refactor checkpoint

This commit is contained in:
Christien Rioux 2024-01-29 22:38:19 -05:00
parent 7bd426ce98
commit 1e6b9f4a43
12 changed files with 145 additions and 136 deletions

View File

@ -1,22 +1,25 @@
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../theme/theme.dart';
import '../../tools/tools.dart';
import '../cubit/cubit.dart';
class ProfileWidget extends StatelessWidget {
const ProfileWidget({
required this.name,
this.pronouns,
super.key,
});
final String name;
final String? pronouns;
@override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) {
final accountData = context.watch<AccountRecordCubit>().state.data;
if (accountData == null) {
return waitingPage(context);
}
final account = accountData.value;
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final textTheme = theme.textTheme;
@ -28,21 +31,14 @@ class ProfileWidget extends StatelessWidget {
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))),
child: Column(children: [
Text(
name,
account.profile.name,
style: textTheme.headlineSmall,
textAlign: TextAlign.left,
).paddingAll(4),
if (pronouns != null && pronouns!.isNotEmpty)
Text(pronouns!, style: textTheme.bodyMedium).paddingLTRB(4, 0, 4, 4),
if (account.profile.pronouns.isNotEmpty)
Text(account.profile.pronouns, style: textTheme.bodyMedium)
.paddingLTRB(4, 0, 4, 4),
]),
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(StringProperty('name', name))
..add(StringProperty('pronouns', pronouns));
}
}

View File

@ -265,6 +265,7 @@ class ContactInvitationListCubit
out = ValidContactInvitation(
activeAccountInfo: _activeAccountInfo,
account: _account,
contactRequestInboxKey: contactRequestInboxKey,
contactRequestPrivate: contactRequestPrivate,
contactIdentityMaster: contactIdentityMaster,
@ -345,12 +346,12 @@ class ContactInvitationListCubit
contactInvitationRecord.localConversationRecordKey);
return conversation.initLocalConversation(
existingConversationRecordKey: localConversationRecordKey,
profile: xxx LOCAL PROFILE HERE NOT REMOTE
profile: _account.profile,
// ignore: prefer_expression_function_bodies
callback: (localConversation) async {
return InvitationStatus(
acceptedContact: AcceptedContact(
profile: remoteConversation.profile,
remoteProfile: remoteConversation.profile,
remoteIdentity: contactIdentityMaster,
remoteConversationRecordKey: remoteConversationRecordKey,
localConversationRecordKey: localConversationRecordKey));

View File

@ -6,13 +6,13 @@ import '../../proto/proto.dart' as proto;
@immutable
class AcceptedContact {
const AcceptedContact({
required this.profile,
required this.remoteProfile,
required this.remoteIdentity,
required this.remoteConversationRecordKey,
required this.localConversationRecordKey,
});
final proto.Profile profile;
final proto.Profile remoteProfile;
final IdentityMaster remoteIdentity;
final TypedKey remoteConversationRecordKey;
final TypedKey localConversationRecordKey;

View File

@ -2,10 +2,10 @@ import 'package:meta/meta.dart';
import 'package:veilid_support/veilid_support.dart';
import '../../account_manager/account_manager.dart';
import '../../contacts/contacts.dart';
import '../../proto/proto.dart' as proto;
import '../../tools/tools.dart';
import 'models.dart';
import '../cubits/contact_invitation_list_cubit.dart';
//////////////////////////////////////////////////
///
@ -14,11 +14,13 @@ class ValidContactInvitation {
@internal
ValidContactInvitation(
{required ActiveAccountInfo activeAccountInfo,
required proto.Account account,
required TypedKey contactRequestInboxKey,
required proto.ContactRequestPrivate contactRequestPrivate,
required IdentityMaster contactIdentityMaster,
required KeyPair writer})
: _activeAccountInfo = activeAccountInfo,
_account = account,
_contactRequestInboxKey = contactRequestInboxKey,
_contactRequestPrivate = contactRequestPrivate,
_contactIdentityMaster = contactIdentityMaster,
@ -38,10 +40,12 @@ class ValidContactInvitation {
.maybeDeleteScope(!isSelf, (contactRequestInbox) async {
// Create local conversation key for this
// contact and send via contact response
return createConversation(
final conversation = ConversationManager(
activeAccountInfo: _activeAccountInfo,
remoteIdentityPublicKey:
_contactIdentityMaster.identityPublicTypedKey(),
_contactIdentityMaster.identityPublicTypedKey());
return conversation.initLocalConversation(
profile: _account.profile,
callback: (localConversation) async {
final contactResponse = proto.ContactResponse()
..accept = true
@ -72,7 +76,7 @@ class ValidContactInvitation {
throw Exception('failed to accept contact invitation');
}
return AcceptedContact(
profile: _contactRequestPrivate.profile,
remoteProfile: _contactRequestPrivate.profile,
remoteIdentity: _contactIdentityMaster,
remoteConversationRecordKey: proto.TypedKeyProto.fromProto(
_contactRequestPrivate.chatRecordKey),
@ -131,6 +135,7 @@ class ValidContactInvitation {
//
final ActiveAccountInfo _activeAccountInfo;
final proto.Account _account;
final TypedKey _contactRequestInboxKey;
final IdentityMaster _contactIdentityMaster;
final KeyPair _writer;

View File

@ -7,20 +7,23 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:provider/provider.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:veilid_support/veilid_support.dart';
import '../../tools/tools.dart';
class InvitationGeneratorCubit extends FutureCubit<Uint8List> {
InvitationGeneratorCubit(super.fut);
}
class ContactInvitationDisplayDialog extends StatefulWidget {
const ContactInvitationDisplayDialog({
required this.name,
required this.message,
required this.generator,
super.key,
});
final String name;
final String message;
final FutureOr<Uint8List> generator;
@ -32,7 +35,6 @@ class ContactInvitationDisplayDialog extends StatefulWidget {
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(StringProperty('name', name))
..add(StringProperty('message', message))
..add(DiagnosticsProperty<FutureOr<Uint8List>?>('generator', generator));
}
@ -42,14 +44,10 @@ class ContactInvitationDisplayDialogState
extends State<ContactInvitationDisplayDialog> {
final focusNode = FocusNode();
final formKey = GlobalKey<FormState>();
late final AutoDisposeFutureProvider<Uint8List?> _generateFutureProvider;
@override
void initState() {
super.initState();
_generateFutureProvider =
AutoDisposeFutureProvider<Uint8List>((ref) async => widget.generator);
}
@override
@ -76,7 +74,9 @@ class ContactInvitationDisplayDialogState
//final scale = theme.extension<ScaleScheme>()!;
final textTheme = theme.textTheme;
final signedContactInvitationBytesV = ref.watch(_generateFutureProvider);
final signedContactInvitationBytesV =
context.watch<InvitationGeneratorCubit>().state;
final cardsize =
min<double>(MediaQuery.of(context).size.shortestSide - 48.0, 400);
@ -90,49 +90,43 @@ class ContactInvitationDisplayDialogState
maxHeight: cardsize),
child: signedContactInvitationBytesV.when(
loading: () => buildProgressIndicator(context),
data: (data) {
if (data == null) {
Navigator.of(context).pop();
return const Text('');
}
return Form(
key: formKey,
child: Column(children: [
FittedBox(
child: Text(
translate(
'send_invite_dialog.contact_invitation'),
style: textTheme.headlineSmall!
.copyWith(color: Colors.black)))
.paddingAll(8),
FittedBox(
child: QrImageView.withQr(
size: 300,
qr: QrCode.fromUint8List(
data: data,
errorCorrectLevel:
QrErrorCorrectLevel.L)))
.expanded(),
Text(widget.message,
softWrap: true,
style: textTheme.labelLarge!
.copyWith(color: Colors.black))
.paddingAll(8),
ElevatedButton.icon(
icon: const Icon(Icons.copy),
label: Text(
translate('send_invite_dialog.copy_invitation')),
onPressed: () async {
showInfoToast(
context,
translate(
'send_invite_dialog.invitation_copied'));
await Clipboard.setData(ClipboardData(
text: makeTextInvite(widget.message, data)));
},
).paddingAll(16),
]));
},
data: (data) => Form(
key: formKey,
child: Column(children: [
FittedBox(
child: Text(
translate(
'send_invite_dialog.contact_invitation'),
style: textTheme.headlineSmall!
.copyWith(color: Colors.black)))
.paddingAll(8),
FittedBox(
child: QrImageView.withQr(
size: 300,
qr: QrCode.fromUint8List(
data: data,
errorCorrectLevel:
QrErrorCorrectLevel.L)))
.expanded(),
Text(widget.message,
softWrap: true,
style: textTheme.labelLarge!
.copyWith(color: Colors.black))
.paddingAll(8),
ElevatedButton.icon(
icon: const Icon(Icons.copy),
label: Text(
translate('send_invite_dialog.copy_invitation')),
onPressed: () async {
showInfoToast(
context,
translate(
'send_invite_dialog.invitation_copied'));
await Clipboard.setData(ClipboardData(
text: makeTextInvite(widget.message, data)));
},
).paddingAll(16),
])),
error: (e, s) {
Navigator.of(context).pop();
showErrorToast(context,

View File

@ -1,10 +1,11 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:flutter_translate/flutter_translate.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart';
import 'contact_invitation_display.dart';
import '../contact_invitation.dart';
class ContactInvitationItemWidget extends StatelessWidget {
const ContactInvitationItemWidget(
@ -48,15 +49,11 @@ class ContactInvitationItemWidget extends StatelessWidget {
// A SlidableAction can have an icon and/or a label.
SlidableAction(
onPressed: (context) async {
final activeAccountInfo =
await ref.read(fetchActiveAccountProvider.future);
if (activeAccountInfo != null) {
await deleteContactInvitation(
accepted: false,
activeAccountInfo: activeAccountInfo,
contactInvitationRecord: contactInvitationRecord);
ref.invalidate(fetchContactInvitationRecordsProvider);
}
final contactInvitationListCubit =
context.read<ContactInvitationListCubit>();
await contactInvitationListCubit.deleteInvitation(
accepted: false,
contactInvitationRecord: contactInvitationRecord);
},
backgroundColor: scale.tertiaryScale.background,
foregroundColor: scale.tertiaryScale.text,
@ -93,22 +90,21 @@ class ContactInvitationItemWidget extends StatelessWidget {
child: ListTile(
//title: Text(translate('contact_list.invitation')),
onTap: () async {
final activeAccountInfo =
await ref.read(fetchActiveAccountProvider.future);
if (activeAccountInfo != null) {
// ignore: use_build_context_synchronously
if (!context.mounted) {
return;
}
await showDialog<void>(
context: context,
builder: (context) => ContactInvitationDisplayDialog(
name: activeAccountInfo.localAccount.name,
message: contactInvitationRecord.message,
generator: Uint8List.fromList(
contactInvitationRecord.invitation),
));
// ignore: use_build_context_synchronously
if (!context.mounted) {
return;
}
await showDialog<void>(
context: context,
builder: (context) => BlocProvider(
create: (context) => InvitationGeneratorCubit(
Future.value(Uint8List.fromList(
contactInvitationRecord.invitation))),
child: ContactInvitationDisplayDialog(
message: contactInvitationRecord.message,
generator: Uint8List.fromList(
contactInvitationRecord.invitation),
)));
},
title: Text(
contactInvitationRecord.message.isEmpty

View File

@ -5,6 +5,7 @@ import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:veilid_support/veilid_support.dart';
@ -129,9 +130,11 @@ class SendInviteDialogState extends State<SendInviteDialog> {
Future<void> _onGenerateButtonPressed() async {
final navigator = Navigator.of(context);
xxx continue here
// Start generation
final activeAccountInfo =
await AccountRepository.instance.fetchActiveAccountInfo();
final activeAccountInfo = context.read<ActiveAccountInfo>();
if (activeAccountInfo == null) {
navigator.pop();
return;

View File

@ -7,10 +7,10 @@ import '../../proto/proto.dart' as proto;
import '../../../packages/veilid_support/veilid_support.dart';
import '../../tools/tools.dart';
import 'account.dart';
import 'chat.dart';
import '../../old_to_refactor/providers/account.dart';
import '../../old_to_refactor/providers/chat.dart';
part 'contact.g.dart';
part '../../old_to_refactor/providers/contact.g.dart';
Future<void> createContact({
required ActiveAccountInfo activeAccountInfo,

View File

@ -1,6 +1,7 @@
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'package:veilid_support/veilid_support.dart';
import '../../account_manager/account_manager.dart';
@ -58,10 +59,12 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
case AccountInfoStatus.accountLocked:
return const HomeAccountLocked();
case AccountInfoStatus.accountReady:
return BlocProvider(
create: (context) => AccountRecordCubit(
record: accountInfo.activeAccountInfo!.accountRecord),
child: HomeAccountReady());
return Provider.value(
value: accountInfo.activeAccountInfo,
child: BlocProvider(
create: (context) => AccountRecordCubit(
record: accountInfo.activeAccountInfo!.accountRecord),
child: HomeAccountReady()));
}
}

View File

@ -1,5 +1,3 @@
import 'dart:async';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/material.dart';
@ -9,21 +7,12 @@ import 'package:go_router/go_router.dart';
import '../../../account_manager/account_manager.dart';
import '../../../contact_invitation/contact_invitation.dart';
import '../../../proto/proto.dart' as proto;
import '../../../theme/theme.dart';
import '../../../tools/tools.dart';
import 'main_pager/main_pager.dart';
class HomeAccountReady extends StatefulWidget {
const HomeAccountReady(
{required ActiveAccountInfo activeAccountInfo,
required proto.Account account,
super.key})
: _activeAccountInfo = activeAccountInfo,
_account = account;
final ActiveAccountInfo _activeAccountInfo;
final proto.Account _account;
const HomeAccountReady({super.key});
@override
HomeAccountReadyState createState() => HomeAccountReadyState();
@ -64,10 +53,7 @@ class HomeAccountReadyState extends State<HomeAccountReady>
onPressed: () async {
context.go('/home/settings');
}).paddingLTRB(0, 0, 8, 0),
ProfileWidget(
name: widget._account.profile.name,
pronouns: widget._account.profile.pronouns,
).expanded(),
const ProfileWidget().expanded(),
]).paddingAll(8),
const MainPager().expanded()
]);
@ -107,14 +93,22 @@ class HomeAccountReadyState extends State<HomeAccountReady>
}
@override
Widget build(BuildContext context) => BlocProvider(
create: (context) => ContactInvitationListCubit(
activeAccountInfo: widget._activeAccountInfo,
account: widget._account),
child: responsiveVisibility(
context: context,
phone: false,
)
? buildTablet(context)
: buildPhone(context));
Widget build(BuildContext context) {
final activeAccountInfo = context.watch<ActiveAccountInfo>();
final accountData = context.watch<AccountRecordCubit>().state.data;
if (accountData == null) {
return waitingPage(context);
}
return BlocProvider(
create: (context) => ContactInvitationListCubit(
activeAccountInfo: activeAccountInfo, account: accountData.value),
child: responsiveVisibility(
context: context,
phone: false,
)
? buildTablet(context)
: buildPhone(context));
}
}

View File

@ -0,0 +1,16 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import '../veilid_support.dart';
abstract class FutureCubit<State> extends Cubit<AsyncValue<State>> {
FutureCubit(Future<State> fut) : super(const AsyncValue.loading()) {
unawaited(fut.then((value) {
emit(AsyncValue.data(value));
// ignore: avoid_types_on_closure_parameters
}, onError: (Object e, StackTrace stackTrace) {
emit(AsyncValue.error(e, stackTrace));
}));
}
}

View File

@ -9,6 +9,7 @@ export 'dht_support/dht_support.dart';
export 'src/async_tag_lock.dart';
export 'src/async_value.dart';
export 'src/config.dart';
export 'src/future_cubit.dart';
export 'src/identity.dart';
export 'src/json_tools.dart';
export 'src/protobuf_tools.dart';