This commit is contained in:
Christien Rioux 2024-01-30 14:14:11 -05:00
parent 1e6b9f4a43
commit 4a8958a868
7 changed files with 104 additions and 138 deletions

View file

@ -10,7 +10,6 @@ import '../../../layout/default_app_bar.dart';
import '../../../tools/tools.dart'; import '../../../tools/tools.dart';
import '../../../veilid_processor/veilid_processor.dart'; import '../../../veilid_processor/veilid_processor.dart';
import '../../account_manager.dart'; import '../../account_manager.dart';
import '../../models/models.dart';
class NewAccountPage extends StatefulWidget { class NewAccountPage extends StatefulWidget {
const NewAccountPage({super.key}); const NewAccountPage({super.key});

View file

@ -1,25 +1,24 @@
import 'package:awesome_extensions/awesome_extensions.dart'; import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../proto/proto.dart' as proto;
import '../../theme/theme.dart'; import '../../theme/theme.dart';
import '../../tools/tools.dart';
import '../cubit/cubit.dart';
class ProfileWidget extends StatelessWidget { class ProfileWidget extends StatelessWidget {
const ProfileWidget({ const ProfileWidget({
required proto.Profile profile,
super.key, super.key,
}); }) : _profile = profile;
//
final proto.Profile _profile;
//
@override @override
// ignore: prefer_expression_function_bodies // ignore: prefer_expression_function_bodies
Widget build(BuildContext context) { 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 theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
@ -31,12 +30,12 @@ class ProfileWidget extends StatelessWidget {
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))), RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))),
child: Column(children: [ child: Column(children: [
Text( Text(
account.profile.name, _profile.name,
style: textTheme.headlineSmall, style: textTheme.headlineSmall,
textAlign: TextAlign.left, textAlign: TextAlign.left,
).paddingAll(4), ).paddingAll(4),
if (account.profile.pronouns.isNotEmpty) if (_profile.pronouns.isNotEmpty)
Text(account.profile.pronouns, style: textTheme.bodyMedium) Text(_profile.pronouns, style: textTheme.bodyMedium)
.paddingLTRB(4, 0, 4, 4), .paddingLTRB(4, 0, 4, 4),
]), ]),
); );

View file

@ -10,7 +10,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../old_to_refactor/proto/proto.dart' as proto; import '../../old_to_refactor/proto/proto.dart' as proto;
import '../../old_to_refactor/providers/account.dart'; import '../../old_to_refactor/providers/account.dart';
import '../../old_to_refactor/providers/chat.dart'; import '../../old_to_refactor/providers/chat.dart';
import '../../old_to_refactor/providers/conversation.dart'; import '../../contacts/models/conversation.dart';
import '../../old_to_refactor/tools/tools.dart'; import '../../old_to_refactor/tools/tools.dart';
import '../../old_to_refactor/veilid_init.dart'; import '../../old_to_refactor/veilid_init.dart';
import '../../old_to_refactor/veilid_support/veilid_support.dart'; import '../../old_to_refactor/veilid_support/veilid_support.dart';

View file

@ -26,6 +26,8 @@ class ValidContactInvitation {
_contactIdentityMaster = contactIdentityMaster, _contactIdentityMaster = contactIdentityMaster,
_writer = writer; _writer = writer;
proto.Profile get remoteProfile => _contactRequestPrivate.profile;
Future<AcceptedContact?> accept() async { Future<AcceptedContact?> accept() async {
final pool = DHTRecordPool.instance; final pool = DHTRecordPool.instance;
try { try {

View file

@ -3,10 +3,12 @@ import 'dart:async';
import 'package:awesome_extensions/awesome_extensions.dart'; import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_translate/flutter_translate.dart'; import 'package:flutter_translate/flutter_translate.dart';
import '../../account_manager/account_manager.dart'; import '../../account_manager/account_manager.dart';
import '../../tools/tools.dart'; import '../../tools/tools.dart';
import '../contact_invitation.dart';
class InviteDialog extends StatefulWidget { class InviteDialog extends StatefulWidget {
const InviteDialog( const InviteDialog(
@ -66,22 +68,14 @@ class InviteDialogState extends State<InviteDialog> {
Future<void> _onAccept() async { Future<void> _onAccept() async {
final navigator = Navigator.of(context); final navigator = Navigator.of(context);
final activeAccountInfo = context.read<ActiveAccountInfo>();
setState(() { setState(() {
_isAccepting = true; _isAccepting = true;
}); });
final activeAccountInfo = await ref.read(fetchActiveAccountProvider.future);
if (activeAccountInfo == null) {
setState(() {
_isAccepting = false;
});
navigator.pop();
return;
}
final validInvitation = _validInvitation; final validInvitation = _validInvitation;
if (validInvitation != null) { if (validInvitation != null) {
final acceptedContact = final acceptedContact = await validInvitation.accept();
await acceptContactInvitation(activeAccountInfo, validInvitation);
if (acceptedContact != null) { if (acceptedContact != null) {
// initiator when accept is received will create // initiator when accept is received will create
// contact in the case of a 'note to self' // contact in the case of a 'note to self'
@ -91,7 +85,7 @@ class InviteDialogState extends State<InviteDialog> {
if (!isSelf) { if (!isSelf) {
await createContact( await createContact(
activeAccountInfo: activeAccountInfo, activeAccountInfo: activeAccountInfo,
profile: acceptedContact.profile, profile: acceptedContact.remoteProfile,
remoteIdentity: acceptedContact.remoteIdentity, remoteIdentity: acceptedContact.remoteIdentity,
remoteConversationRecordKey: remoteConversationRecordKey:
acceptedContact.remoteConversationRecordKey, acceptedContact.remoteConversationRecordKey,
@ -99,9 +93,6 @@ class InviteDialogState extends State<InviteDialog> {
acceptedContact.localConversationRecordKey, acceptedContact.localConversationRecordKey,
); );
} }
ref
..invalidate(fetchContactInvitationRecordsProvider)
..invalidate(fetchContactListProvider);
} else { } else {
if (context.mounted) { if (context.mounted) {
showErrorToast(context, 'invite_dialog.failed_to_accept'); showErrorToast(context, 'invite_dialog.failed_to_accept');
@ -120,17 +111,9 @@ class InviteDialogState extends State<InviteDialog> {
setState(() { setState(() {
_isAccepting = true; _isAccepting = true;
}); });
final activeAccountInfo = await ref.read(fetchActiveAccountProvider.future);
if (activeAccountInfo == null) {
setState(() {
_isAccepting = false;
});
navigator.pop();
return;
}
final validInvitation = _validInvitation; final validInvitation = _validInvitation;
if (validInvitation != null) { if (validInvitation != null) {
if (await rejectContactInvitation(activeAccountInfo, validInvitation)) { if (await validInvitation.reject()) {
// do nothing right now // do nothing right now
} else { } else {
if (context.mounted) { if (context.mounted) {
@ -148,67 +131,56 @@ class InviteDialogState extends State<InviteDialog> {
required Uint8List inviteData, required Uint8List inviteData,
}) async { }) async {
try { try {
final activeAccountInfo = final contactInvitationListCubit =
await ref.read(fetchActiveAccountProvider.future); context.read<ContactInvitationListCubit>();
if (activeAccountInfo == null) {
setState(() {
_isValidating = false;
_validInvitation = null;
});
return;
}
final contactInvitationRecords =
await ref.read(fetchContactInvitationRecordsProvider.future);
setState(() { setState(() {
_isValidating = true; _isValidating = true;
_validInvitation = null; _validInvitation = null;
}); });
final validatedContactInvitation = await validateContactInvitation( final validatedContactInvitation =
activeAccountInfo: activeAccountInfo, await contactInvitationListCubit.validateInvitation(
contactInvitationRecords: contactInvitationRecords, inviteData: inviteData,
inviteData: inviteData, getEncryptionKeyCallback:
getEncryptionKeyCallback: (cs, encryptionKeyType, encryptedSecret) async {
(cs, encryptionKeyType, encryptedSecret) async { String encryptionKey;
String encryptionKey; switch (encryptionKeyType) {
switch (encryptionKeyType) { case EncryptionKeyType.none:
case EncryptionKeyType.none: encryptionKey = '';
encryptionKey = ''; case EncryptionKeyType.pin:
case EncryptionKeyType.pin: final description =
final description = translate('invite_dialog.protected_with_pin');
translate('invite_dialog.protected_with_pin'); if (!context.mounted) {
if (!context.mounted) { return null;
return null; }
final pin = await showDialog<String>(
context: context,
builder: (context) => EnterPinDialog(
reenter: false, description: description));
if (pin == null) {
return null;
}
encryptionKey = pin;
case EncryptionKeyType.password:
final description =
translate('invite_dialog.protected_with_password');
if (!context.mounted) {
return null;
}
final password = await showDialog<String>(
context: context,
builder: (context) =>
EnterPasswordDialog(description: description));
if (password == null) {
return null;
}
encryptionKey = password;
} }
final pin = await showDialog<String>( return encryptionKeyType.decryptSecretFromBytes(
context: context, secretBytes: encryptedSecret,
builder: (context) => EnterPinDialog( cryptoKind: cs.kind(),
reenter: false, description: description)); encryptionKey: encryptionKey);
if (pin == null) { });
return null;
}
encryptionKey = pin;
case EncryptionKeyType.password:
final description =
translate('invite_dialog.protected_with_password');
if (!context.mounted) {
return null;
}
final password = await showDialog<String>(
context: context,
builder: (context) =>
EnterPasswordDialog(description: description));
if (password == null) {
return null;
}
encryptionKey = password;
}
return decryptSecretFromBytes(
secretBytes: encryptedSecret,
cryptoKind: cs.kind(),
encryptionKeyType: encryptionKeyType,
encryptionKey: encryptionKey);
});
// Check if validation was cancelled // Check if validation was cancelled
if (validatedContactInvitation == null) { if (validatedContactInvitation == null) {
@ -297,14 +269,11 @@ class InviteDialogState extends State<InviteDialog> {
if (_validInvitation != null && !_isValidating) if (_validInvitation != null && !_isValidating)
Column(children: [ Column(children: [
Container( Container(
constraints: const BoxConstraints(maxHeight: 64), constraints: const BoxConstraints(maxHeight: 64),
width: double.infinity, width: double.infinity,
child: ProfileWidget( child: ProfileWidget(
name: _validInvitation! profile: _validInvitation!.remoteProfile))
.contactRequestPrivate.profile.name, .paddingLTRB(0, 0, 0, 8),
pronouns: _validInvitation!
.contactRequestPrivate.profile.pronouns,
)).paddingLTRB(0, 0, 0, 8),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [

View file

@ -11,7 +11,7 @@ import 'package:veilid_support/veilid_support.dart';
import '../../account_manager/account_manager.dart'; import '../../account_manager/account_manager.dart';
import '../../tools/tools.dart'; import '../../tools/tools.dart';
import 'contact_invitation_display.dart'; import '../contact_invitation.dart';
class SendInviteDialog extends StatefulWidget { class SendInviteDialog extends StatefulWidget {
const SendInviteDialog({super.key}); const SendInviteDialog({super.key});
@ -130,17 +130,11 @@ class SendInviteDialogState extends State<SendInviteDialog> {
Future<void> _onGenerateButtonPressed() async { Future<void> _onGenerateButtonPressed() async {
final navigator = Navigator.of(context); final navigator = Navigator.of(context);
xxx continue here
// Start generation // Start generation
final activeAccountInfo = context.read<ActiveAccountInfo>(); final contactInvitationListCubit =
context.read<ContactInvitationListCubit>();
if (activeAccountInfo == null) { final generator = contactInvitationListCubit.createInvitation(
navigator.pop();
return;
}
final generator = ContactInvitationRespositoryxxx.createContactInvitation(
activeAccountInfo: activeAccountInfo,
encryptionKeyType: _encryptionKeyType, encryptionKeyType: _encryptionKeyType,
encryptionKey: _encryptionKey, encryptionKey: _encryptionKey,
message: _messageTextController.text, message: _messageTextController.text,
@ -152,14 +146,12 @@ xxx continue here
await showDialog<void>( await showDialog<void>(
context: context, context: context,
builder: (context) => ContactInvitationDisplayDialog( builder: (context) => ContactInvitationDisplayDialog(
name: activeAccountInfo.localAccount.name,
message: _messageTextController.text, message: _messageTextController.text,
generator: generator, generator: generator,
)); ));
// if (ret == null) { // if (ret == null) {
// return; // return;
// } // }
ref.invalidate(fetchContactInvitationRecordsProvider);
navigator.pop(); navigator.pop();
} }

View file

@ -34,37 +34,42 @@ class HomeAccountReadyState extends State<HomeAccountReady>
return const Center(child: Text('unlock account')); return const Center(child: Text('unlock account'));
} }
Widget buildUserPanel(BuildContext context) { Widget buildUserPanel() => Builder(builder: (context) {
final theme = Theme.of(context); final account = context.watch<AccountRecordCubit>().state;
final scale = theme.extension<ScaleScheme>()!; final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
return Column(children: <Widget>[ return Column(children: <Widget>[
Row(children: [ Row(children: [
IconButton( IconButton(
icon: const Icon(Icons.settings), icon: const Icon(Icons.settings),
color: scale.secondaryScale.text, color: scale.secondaryScale.text,
constraints: const BoxConstraints.expand(height: 64, width: 64), constraints: const BoxConstraints.expand(height: 64, width: 64),
style: ButtonStyle( style: ButtonStyle(
backgroundColor: backgroundColor:
MaterialStateProperty.all(scale.secondaryScale.border), MaterialStateProperty.all(scale.secondaryScale.border),
shape: MaterialStateProperty.all(const RoundedRectangleBorder( shape: MaterialStateProperty.all(
borderRadius: BorderRadius.all(Radius.circular(16))))), const RoundedRectangleBorder(
tooltip: translate('app_bar.settings_tooltip'), borderRadius:
onPressed: () async { BorderRadius.all(Radius.circular(16))))),
context.go('/home/settings'); tooltip: translate('app_bar.settings_tooltip'),
}).paddingLTRB(0, 0, 8, 0), onPressed: () async {
const ProfileWidget().expanded(), context.go('/home/settings');
]).paddingAll(8), }).paddingLTRB(0, 0, 8, 0),
const MainPager().expanded() asyncValueBuilder(account,
]); (_, account) => ProfileWidget(profile: account.profile))
} .expanded(),
]).paddingAll(8),
const MainPager().expanded()
]);
});
Widget buildPhone(BuildContext context) => Widget buildPhone(BuildContext context) =>
Material(color: Colors.transparent, child: buildUserPanel(context)); Material(color: Colors.transparent, child: buildUserPanel());
Widget buildTabletLeftPane(BuildContext context) => Builder( Widget buildTabletLeftPane(BuildContext context) => Builder(
builder: (context) => builder: (context) =>
Material(color: Colors.transparent, child: buildUserPanel(context))); Material(color: Colors.transparent, child: buildUserPanel()));
Widget buildTabletRightPane(BuildContext context) => buildChatComponent(); Widget buildTabletRightPane(BuildContext context) => buildChatComponent();