mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-12-24 07:09:29 -05:00
refactor checkpoint
This commit is contained in:
parent
7bd426ce98
commit
1e6b9f4a43
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
16
packages/veilid_support/lib/src/future_cubit.dart
Normal file
16
packages/veilid_support/lib/src/future_cubit.dart
Normal 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));
|
||||
}));
|
||||
}
|
||||
}
|
@ -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';
|
||||
|
Loading…
Reference in New Issue
Block a user