diff --git a/lib/features/base/mixin/view_as_dialog_action_mixin.dart b/lib/features/base/mixin/view_as_dialog_action_mixin.dart index 240eb0129..bdde6e72c 100644 --- a/lib/features/base/mixin/view_as_dialog_action_mixin.dart +++ b/lib/features/base/mixin/view_as_dialog_action_mixin.dart @@ -1,6 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:tmail_ui_user/features/contact/presentation/contact_bindings.dart'; +import 'package:tmail_ui_user/features/contact/presentation/contact_view.dart'; +import 'package:tmail_ui_user/features/contact/presentation/model/contact_arguments.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/destination_picker_bindings.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/destination_picker_view.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; @@ -71,4 +75,32 @@ mixin ViewAsDialogActionMixin { }); }); } + + void showDialogContactView({ + required BuildContext context, + required ContactArguments arguments, + required Function(EmailAddress) onSelectedContact + }) { + ContactBindings().dependencies(); + + showGeneralDialog( + context: context, + barrierDismissible: true, + barrierLabel: '', + barrierColor: Colors.black.withAlpha(24), + pageBuilder: (context, animation, secondaryAnimation) { + return ContactView.fromArguments( + arguments, + onDismissCallback: () { + ContactBindings().dispose(); + popBack(); + }, + onSelectedContactCallback: (emailAddress) { + ContactBindings().dispose(); + popBack(); + + onSelectedContact.call(emailAddress); + }); + }); + } } \ No newline at end of file diff --git a/lib/features/contact/presentation/contact_bindings.dart b/lib/features/contact/presentation/contact_bindings.dart index d73545e6a..433264f2b 100644 --- a/lib/features/contact/presentation/contact_bindings.dart +++ b/lib/features/contact/presentation/contact_bindings.dart @@ -8,4 +8,8 @@ class ContactBindings extends Bindings { void dependencies() { Get.lazyPut(() => ContactController()); } + + void dispose() { + Get.delete(); + } } \ No newline at end of file diff --git a/lib/features/contact/presentation/contact_controller.dart b/lib/features/contact/presentation/contact_controller.dart index a83b022ee..73c6e3dd0 100644 --- a/lib/features/contact/presentation/contact_controller.dart +++ b/lib/features/contact/presentation/contact_controller.dart @@ -18,10 +18,12 @@ import 'package:tmail_ui_user/features/contact/presentation/model/contact_argume import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +typedef OnSelectedContactCallback = Function(EmailAddress emailAddress); + class ContactController extends BaseController { - final textInputSearchController = TextEditingController(); - final textInputSearchFocus = FocusNode(); + TextEditingController? textInputSearchController; + FocusNode? textInputSearchFocus; ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.tMailContact; final searchQuery = SearchQuery.initial().obs; @@ -34,22 +36,28 @@ class ContactController extends BaseController { late AccountId _accountId; late Session _session; + ContactArguments? arguments; EmailAddress? contactSelected; + OnSelectedContactCallback? onSelectedContactCallback; + VoidCallback? onDismissContactView; @override void onInit() { super.onInit(); + textInputSearchController = TextEditingController(); + textInputSearchFocus = FocusNode(); _initializeDebounceTimeTextSearchChange(); } @override void onReady() async { - textInputSearchFocus.requestFocus(); - final arguments = Get.arguments; - if (arguments is ContactArguments) { - _accountId = arguments.accountId; - _session = arguments.session; - final listContactSelected = arguments.listContactSelected; + textInputSearchFocus?.requestFocus(); + if (arguments != null) { + _accountId = arguments!.accountId; + _session = arguments!.session; + final listContactSelected = arguments!.listContactSelected; + log('ContactController::onReady(): arguments: $arguments'); + log('ContactController::onReady(): listContactSelected: $listContactSelected'); if (listContactSelected.isNotEmpty) { contactSelected = EmailAddress(listContactSelected.first, listContactSelected.first); } @@ -65,7 +73,10 @@ class ContactController extends BaseController { @override void onClose() { - textInputSearchController.dispose(); + textInputSearchController?.dispose(); + textInputSearchController = null; + textInputSearchFocus?.dispose(); + textInputSearchFocus = null; _deBouncerTime.cancel(); super.onClose(); } @@ -85,9 +96,9 @@ class ContactController extends BaseController { } void clearAllTextInputSearchForm() { - textInputSearchController.clear(); + textInputSearchController?.clear(); searchQuery.value = SearchQuery.initial(); - textInputSearchFocus.requestFocus(); + textInputSearchFocus?.requestFocus(); } void _checkContactPermission() async { @@ -158,13 +169,35 @@ class ContactController extends BaseController { void selectContact(BuildContext context, EmailAddress emailAddress) { FocusScope.of(context).unfocus(); - popBack(result: emailAddress); + + if (BuildUtils.isWeb) { + textInputSearchFocus?.dispose(); + textInputSearchFocus = null; + textInputSearchController?.dispose(); + textInputSearchController = null; + _deBouncerTime.cancel(); + + onSelectedContactCallback?.call(emailAddress); + } else { + popBack(result: emailAddress); + } } void closeContactView(BuildContext context) { clearAllTextInputSearchForm(); FocusScope.of(context).unfocus(); - popBack(); + + if (BuildUtils.isWeb) { + textInputSearchFocus?.dispose(); + textInputSearchFocus = null; + textInputSearchController?.dispose(); + textInputSearchController = null; + _deBouncerTime.cancel(); + + onDismissContactView?.call(); + } else { + popBack(); + } } @override diff --git a/lib/features/contact/presentation/contact_view.dart b/lib/features/contact/presentation/contact_view.dart index d466a0d59..672fea1f3 100644 --- a/lib/features/contact/presentation/contact_view.dart +++ b/lib/features/contact/presentation/contact_view.dart @@ -9,6 +9,7 @@ import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:tmail_ui_user/features/contact/presentation/contact_controller.dart'; +import 'package:tmail_ui_user/features/contact/presentation/model/contact_arguments.dart'; import 'package:tmail_ui_user/features/contact/presentation/utils/contact_utils.dart'; import 'package:tmail_ui_user/features/contact/presentation/widgets/app_bar_contact_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/search_app_bar_widget.dart'; @@ -19,16 +20,27 @@ class ContactView extends GetWidget { final _responsiveUtils = Get.find(); final _imagePaths = Get.find(); - ContactView({Key? key}) : super(key: key); + @override + final controller = Get.find(); + + ContactView({Key? key}) : super(key: key) { + controller.arguments = Get.arguments; + } + + ContactView.fromArguments( + ContactArguments arguments, { + Key? key, + OnSelectedContactCallback? onSelectedContactCallback, + VoidCallback? onDismissCallback + }) : super(key: key) { + controller.arguments = arguments; + controller.onSelectedContactCallback = onSelectedContactCallback; + controller.onDismissContactView = onDismissCallback; + controller.onInit(); + } @override Widget build(BuildContext context) { - if (_responsiveUtils.isWebDesktop(context)) { - WidgetsBinding.instance.addPostFrameCallback((_) { - controller.closeContactView(context); - }); - } - return Scaffold( backgroundColor: Colors.black38, body: GestureDetector( diff --git a/lib/features/contact/presentation/widgets/app_bar_contact_widget.dart b/lib/features/contact/presentation/widgets/app_bar_contact_widget.dart index 396d89917..0a8b832ea 100644 --- a/lib/features/contact/presentation/widgets/app_bar_contact_widget.dart +++ b/lib/features/contact/presentation/widgets/app_bar_contact_widget.dart @@ -37,7 +37,7 @@ class AppBarContactWidget extends StatelessWidget { onTap: onCloseContactView), ), Center(child: Text( - AppLocalizations.of(context).contains, + AppLocalizations.of(context).contact, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, diff --git a/lib/features/search/presentation/search_email_controller.dart b/lib/features/search/presentation/search_email_controller.dart index db6a9cf93..8245d462a 100644 --- a/lib/features/search/presentation/search_email_controller.dart +++ b/lib/features/search/presentation/search_email_controller.dart @@ -453,55 +453,89 @@ class SearchEmailController extends BaseController ) async { if (accountId != null && session != null) { final listContactSelected = simpleSearchFilter.value.getContactApplied(prefixEmailAddress); - final newContact = await push( - AppRoutes.contact, - arguments: ContactArguments(accountId!, session!, listContactSelected)); + final arguments = ContactArguments(accountId!, session!, listContactSelected); - if (newContact is EmailAddress) { - if (listContactSelected.isNotEmpty) { - switch(prefixEmailAddress) { - case PrefixEmailAddress.from: - listContactSelected.first == newContact.email - ? simpleSearchFilter.value.from.removeWhere((e) => e == newContact.email!) - : simpleSearchFilter.value.from.add(newContact.email!); - break; - case PrefixEmailAddress.to: - listContactSelected.first == newContact.email - ? simpleSearchFilter.value.to.removeWhere((e) => e == newContact.email!) - : simpleSearchFilter.value.to.add(newContact.email!); - break; - default: - break; - } - } else { - switch(prefixEmailAddress) { - case PrefixEmailAddress.from: - simpleSearchFilter.value.from.add(newContact.email!); - break; - case PrefixEmailAddress.to: - simpleSearchFilter.value.to.add(newContact.email!); - break; - default: - break; - } + if (BuildUtils.isWeb) { + showDialogContactView( + context: context, + arguments: arguments, + onSelectedContact: (newContact) { + _dispatchApplyContactAction( + context, + listContactSelected, + prefixEmailAddress, + newContact); + }); + } else { + final newContact = await push( + AppRoutes.contact, + arguments: arguments); + + if (newContact is EmailAddress) { + _dispatchApplyContactAction( + context, + listContactSelected, + prefixEmailAddress, + newContact); } - - switch(prefixEmailAddress) { - case PrefixEmailAddress.from: - _updateSimpleSearchFilter(from: simpleSearchFilter.value.from); - break; - case PrefixEmailAddress.to: - _updateSimpleSearchFilter(to: simpleSearchFilter.value.to); - break; - default: - break; - } - - _searchEmailAction(context); } } } + void _dispatchApplyContactAction( + BuildContext context, + Set listContactSelected, + PrefixEmailAddress prefixEmailAddress, + EmailAddress newContact + ) { + if (listContactSelected.isNotEmpty) { + switch(prefixEmailAddress) { + case PrefixEmailAddress.from: + if (listContactSelected.first == newContact.email) { + simpleSearchFilter.value.from.clear(); + } else { + simpleSearchFilter.value.from.clear(); + simpleSearchFilter.value.from.add(newContact.email!); + } + break; + case PrefixEmailAddress.to: + if (listContactSelected.first == newContact.email) { + simpleSearchFilter.value.to.clear(); + } else { + simpleSearchFilter.value.to.clear(); + simpleSearchFilter.value.to.add(newContact.email!); + } + break; + default: + break; + } + } else { + switch(prefixEmailAddress) { + case PrefixEmailAddress.from: + simpleSearchFilter.value.from.add(newContact.email!); + break; + case PrefixEmailAddress.to: + simpleSearchFilter.value.to.add(newContact.email!); + break; + default: + break; + } + } + + switch(prefixEmailAddress) { + case PrefixEmailAddress.from: + _updateSimpleSearchFilter(from: simpleSearchFilter.value.from); + break; + case PrefixEmailAddress.to: + _updateSimpleSearchFilter(to: simpleSearchFilter.value.to); + break; + default: + break; + } + + _searchEmailAction(context); + } + void _updateSimpleSearchFilter({ Set? from, Set? to, diff --git a/lib/main/pages/app_pages.dart b/lib/main/pages/app_pages.dart index 410abde5c..224a826f0 100644 --- a/lib/main/pages/app_pages.dart +++ b/lib/main/pages/app_pages.dart @@ -47,6 +47,11 @@ class AppPages { opaque: false, page: () => DeferredWidget(mailbox_creator.loadLibrary, () => mailbox_creator.MailboxCreatorView()), binding: MailboxCreatorBindings()), + GetPage( + name: AppRoutes.contact, + opaque: false, + page: () => DeferredWidget(contact_view.loadLibrary, () => contact_view.ContactView()), + binding: ContactBindings()), ]; static final pages = [ @@ -89,11 +94,6 @@ class AppPages { page: () => DeferredWidget(emails_forward_creator.loadLibrary, () => emails_forward_creator.EmailsForwardCreatorView()), binding: EmailsForwardCreatorBindings()), - GetPage( - name: AppRoutes.contact, - opaque: false, - page: () => DeferredWidget(contact_view.loadLibrary, () => contact_view.ContactView()), - binding: ContactBindings()), if (!BuildUtils.isWeb) ...pagesOnlyOnMobile ]; diff --git a/lib/main/routes/app_routes.dart b/lib/main/routes/app_routes.dart index a15f0a98a..c2fa7f4cf 100644 --- a/lib/main/routes/app_routes.dart +++ b/lib/main/routes/app_routes.dart @@ -8,7 +8,7 @@ abstract class AppRoutes { static const composer = '/composer'; static const destinationPicker = '/destination_picker'; static const mailboxCreator = '/mailbox_creator'; - static const contact = '$dashboard/contact'; + static const contact = '/contact'; static const identityCreator = '$settings/identity_creator'; static const rulesFilterCreator = '$settings/rules_filter_creator'; static const emailsForwardCreator = '$settings/emails_forward_creator';