diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 009172819..cf320a165 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -145,6 +145,7 @@ extension AppColor on Color { static const colorBackgroundNotificationVacationSetting= Color(0xFFFFF5C2); static const colorDivider = Color(0xFFE7E8EC); static const colorDividerVertical = Color(0xFF99A2AD); + static const colorCloseButton = Color(0xFF818C99); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/lib/features/contact/presentation/contact_bindings.dart b/lib/features/contact/presentation/contact_bindings.dart new file mode 100644 index 000000000..d73545e6a --- /dev/null +++ b/lib/features/contact/presentation/contact_bindings.dart @@ -0,0 +1,11 @@ + +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/contact/presentation/contact_controller.dart'; + +class ContactBindings extends Bindings { + + @override + void dependencies() { + Get.lazyPut(() => ContactController()); + } +} \ No newline at end of file diff --git a/lib/features/contact/presentation/contact_controller.dart b/lib/features/contact/presentation/contact_controller.dart new file mode 100644 index 000000000..79f899536 --- /dev/null +++ b/lib/features/contact/presentation/contact_controller.dart @@ -0,0 +1,150 @@ + +import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/build_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; +import 'package:model/autocomplete/auto_complete_pattern.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:debounce_throttle/debounce_throttle.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/contact_suggestion_source.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/get_autocomplete_state.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_with_device_contact_interactor.dart'; +import 'package:tmail_ui_user/features/composer/presentation/extensions/session_extension.dart'; +import 'package:tmail_ui_user/features/contact/presentation/model/contact_arguments.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/autocomplete_bindings.dart'; +import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; +import 'package:tmail_ui_user/main/routes/route_navigation.dart'; + +class ContactController extends GetxController { + + final textInputSearchController = TextEditingController(); + final textInputSearchFocus = FocusNode(); + ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.tMailContact; + + final searchQuery = SearchQuery.initial().obs; + final listContactSearched = RxList(); + + late GetAutoCompleteWithDeviceContactInteractor _getAutoCompleteWithDeviceContactInteractor; + late GetAutoCompleteInteractor _getAutoCompleteInteractor; + + late Debouncer _deBouncerTime; + late AccountId _accountId; + late Session _session; + + EmailAddress? contactSelected; + + @override + void onInit() { + super.onInit(); + _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; + if (listContactSelected.isNotEmpty) { + contactSelected = EmailAddress(listContactSelected.first, listContactSelected.first); + } + } + if (!BuildUtils.isWeb) { + Future.delayed( + const Duration(milliseconds: 500), + () => _checkContactPermission()); + } + super.onReady(); + } + + @override + void onClose() { + textInputSearchController.dispose(); + _deBouncerTime.cancel(); + super.onClose(); + } + + void _initializeDebounceTimeTextSearchChange() { + _deBouncerTime = Debouncer( + const Duration(milliseconds: 500), + initialValue: ''); + _deBouncerTime.values.listen((value) async { + searchQuery.value = SearchQuery(value); + _searchContactByNameOrEmail(searchQuery.value.value); + }); + } + + void onTextSearchChange(String text) { + _deBouncerTime.value = text; + } + + void clearAllTextInputSearchForm() { + textInputSearchController.clear(); + searchQuery.value = SearchQuery.initial(); + textInputSearchFocus.requestFocus(); + } + + void _checkContactPermission() async { + final permissionStatus = await Permission.contacts.status; + if (permissionStatus.isGranted) { + _contactSuggestionSource = ContactSuggestionSource.all; + } else if (!permissionStatus.isPermanentlyDenied) { + final requestedPermission = await Permission.contacts.request(); + _contactSuggestionSource = requestedPermission == PermissionStatus.granted + ? ContactSuggestionSource.all + : _contactSuggestionSource; + } + } + + void _searchContactByNameOrEmail(String query) async { + log('ContactController::_searchContactByNameOrEmail(): query: $query'); + final listContact = await _getAutoCompleteSuggestion(query); + listContactSearched.value = listContact; + } + + Future> _getAutoCompleteSuggestion(String query) async { + if(_session.hasSupportTmailAutoComplete != true) return []; + + if (!Get.isRegistered() || + !Get.isRegistered()) { + AutoCompleteBindings().dependencies(); + } + + _getAutoCompleteWithDeviceContactInteractor = Get.find(); + _getAutoCompleteInteractor = Get.find(); + + if (_contactSuggestionSource == ContactSuggestionSource.all) { + return await _getAutoCompleteWithDeviceContactInteractor + .execute(AutoCompletePattern(word: query, limit: 30, accountId: _accountId)) + .then((value) => value.fold( + (failure) => [], + (success) => success is GetAutoCompleteSuccess + ? success.listEmailAddress + : [])); + } + return await _getAutoCompleteInteractor + .execute(AutoCompletePattern(word: query, limit: 30, accountId: _accountId)) + .then((value) => value.fold( + (failure) => [], + (success) => success is GetAutoCompleteSuccess + ? success.listEmailAddress + : [])); + } + + void selectContact(BuildContext context, EmailAddress emailAddress) { + FocusScope.of(context).unfocus(); + popBack(result: emailAddress); + } + + void closeContactView(BuildContext context) { + clearAllTextInputSearchForm(); + FocusScope.of(context).unfocus(); + popBack(); + } +} \ No newline at end of file diff --git a/lib/features/contact/presentation/contact_view.dart b/lib/features/contact/presentation/contact_view.dart new file mode 100644 index 000000000..d466a0d59 --- /dev/null +++ b/lib/features/contact/presentation/contact_view.dart @@ -0,0 +1,190 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/presentation/utils/style_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +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/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'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class ContactView extends GetWidget { + + final _responsiveUtils = Get.find(); + final _imagePaths = Get.find(); + + ContactView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + if (_responsiveUtils.isWebDesktop(context)) { + WidgetsBinding.instance.addPostFrameCallback((_) { + controller.closeContactView(context); + }); + } + + return Scaffold( + backgroundColor: Colors.black38, + body: GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: SafeArea( + bottom: false, + left: false, + right: false, + top: ContactUtils.supportAppBarTopBorder(context, _responsiveUtils), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(ContactUtils.getRadiusBorderAppBarTop( + context, + _responsiveUtils)), + topRight: Radius.circular(ContactUtils.getRadiusBorderAppBarTop( + context, + _responsiveUtils))), + color: Colors.white), + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(ContactUtils.getRadiusBorderAppBarTop( + context, + _responsiveUtils)), + topRight: Radius.circular(ContactUtils.getRadiusBorderAppBarTop( + context, + _responsiveUtils))), + child: SafeArea(child: Container( + color: Colors.white, + child: Column(children: [ + Container( + height: 52, + color: Colors.white, + padding: ContactUtils.getPaddingAppBar(context, _responsiveUtils), + child: AppBarContactWidget( + onCloseContactView: () => controller.closeContactView(context)) + ), + const Divider(color: AppColor.colorDividerComposer, height: 1), + (SearchAppBarWidget( + _imagePaths, + controller.searchQuery.value, + controller.textInputSearchFocus, + controller.textInputSearchController, + hasBackButton: false, + hasSearchButton: true) + ..addPadding(EdgeInsets.zero) + ..setHeightSearchBar(44) + ..setMargin(ContactUtils.getPaddingSearchInputForm(context, _responsiveUtils)) + ..addDecoration(BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: AppColor.colorBgSearchBar)) + ..addIconClearText(SvgPicture.asset( + _imagePaths.icClearTextSearch, + width: 18, + height: 18, + fit: BoxFit.fill)) + ..setHintText(AppLocalizations.of(context).hintSearchInputContact) + ..addOnClearTextSearchAction(() => controller.clearAllTextInputSearchForm()) + ..addOnTextChangeSearchAction(controller.onTextSearchChange) + ..addOnSearchTextAction((query) => {})) + .build(), + Expanded(child: Obx(() { + if (controller.listContactSearched.isNotEmpty) { + return Container( + color: Colors.white, + child: ListView.separated( + itemCount: controller.listContactSearched.length, + separatorBuilder: (context, index) { + return Padding( + padding: ContactUtils.getPaddingDividerSearchResultList(context, _responsiveUtils), + child: const Divider( + height: 1, + color: AppColor.colorDivider), + ); + }, + itemBuilder: (context, index) { + final emailAddress = controller.listContactSearched[index]; + return _buildItemSearchContact(context, emailAddress); + } + ) + ); + } else { + return const SizedBox.shrink(); + } + })), + ]), + )) + ) + ), + ), + ) + ); + } + + Widget _buildItemSearchContact(BuildContext context, EmailAddress emailAddress) { + return Material( + color: Colors.transparent, + child: ListTile( + onTap: () => controller.selectContact(context, emailAddress), + contentPadding: ContactUtils.getPaddingSearchInputForm(context, _responsiveUtils), + leading: Container( + width: 44, + height: 44, + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(44) * 0.5, + border: Border.all(color: Colors.transparent), + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + stops: const [0.0, 1.0], + colors: emailAddress.avatarColors), + color: AppColor.avatarColor + ), + child: Text( + emailAddress.asString().isNotEmpty + ? emailAddress.asString()[0].toUpperCase() + : '', + style: const TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w600))), + title: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + emailAddress.asString(), + maxLines: 1, + overflow: CommonTextStyle.defaultTextOverFlow, + softWrap: CommonTextStyle.defaultSoftWrap, + style: const TextStyle( + color: Colors.black, + fontSize: 15, + fontWeight: FontWeight.normal)), + if (emailAddress.displayName.isNotEmpty && emailAddress.emailAddress.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + emailAddress.emailAddress, + maxLines: 1, + overflow: CommonTextStyle.defaultTextOverFlow, + softWrap: CommonTextStyle.defaultSoftWrap, + style: const TextStyle( + color: AppColor.colorContentEmail, + fontSize: 13, + fontWeight: FontWeight.normal))) + ] + ), + trailing: controller.contactSelected?.email == emailAddress.email + ? SvgPicture.asset(_imagePaths.icFilterSelected, + width: 24, + height: 24, + fit: BoxFit.fill) + : null, + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/contact/presentation/model/contact_arguments.dart b/lib/features/contact/presentation/model/contact_arguments.dart new file mode 100644 index 000000000..9dc5c8e51 --- /dev/null +++ b/lib/features/contact/presentation/model/contact_arguments.dart @@ -0,0 +1,15 @@ + +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; + +class ContactArguments with EquatableMixin { + final AccountId accountId; + final Session session; + final Set listContactSelected; + + ContactArguments(this.accountId, this.session, this.listContactSelected); + + @override + List get props => [accountId, session, listContactSelected]; +} \ No newline at end of file diff --git a/lib/features/contact/presentation/utils/contact_utils.dart b/lib/features/contact/presentation/utils/contact_utils.dart new file mode 100644 index 000000000..d44ab9eb5 --- /dev/null +++ b/lib/features/contact/presentation/utils/contact_utils.dart @@ -0,0 +1,69 @@ + +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/utils/build_utils.dart'; +import 'package:flutter/material.dart'; + +class ContactUtils { + static EdgeInsets getPaddingAppBar(BuildContext context, ResponsiveUtils responsiveUtils) { + if (BuildUtils.isWeb) { + return const EdgeInsets.symmetric(horizontal: 16); + } else { + if (responsiveUtils.isScreenWithShortestSide(context)) { + return const EdgeInsets.symmetric(horizontal: 10); + } else { + return const EdgeInsets.symmetric(horizontal: 32); + } + } + } + + static EdgeInsets getPaddingSearchInputForm(BuildContext context, ResponsiveUtils responsiveUtils) { + if (BuildUtils.isWeb) { + return const EdgeInsets.symmetric(horizontal: 16, vertical: 10); + } else { + if (responsiveUtils.isScreenWithShortestSide(context)) { + return const EdgeInsets.symmetric(horizontal: 16, vertical: 10); + } else { + return const EdgeInsets.symmetric(horizontal: 32, vertical: 10); + } + } + } + + static EdgeInsets getPaddingSearchResultList(BuildContext context, ResponsiveUtils responsiveUtils) { + if (BuildUtils.isWeb) { + return const EdgeInsets.symmetric(horizontal: 16, vertical: 10); + } else { + if (responsiveUtils.isScreenWithShortestSide(context)) { + return const EdgeInsets.symmetric(horizontal: 16, vertical: 10); + } else { + return const EdgeInsets.symmetric(horizontal: 32, vertical: 10); + } + } + } + + static EdgeInsets getPaddingDividerSearchResultList(BuildContext context, ResponsiveUtils responsiveUtils) { + if (BuildUtils.isWeb) { + return const EdgeInsets.symmetric(horizontal: 16); + } else { + if (responsiveUtils.isScreenWithShortestSide(context)) { + return const EdgeInsets.symmetric(horizontal: 16); + } else { + return const EdgeInsets.symmetric(horizontal: 32); + } + } + } + + static bool supportAppBarTopBorder(BuildContext context, ResponsiveUtils responsiveUtils) { + if (BuildUtils.isWeb || responsiveUtils.isLandscapeMobile(context)) { + return false; + } + return true; + } + + static double getRadiusBorderAppBarTop(BuildContext context, ResponsiveUtils responsiveUtils) { + if (supportAppBarTopBorder(context, responsiveUtils)) { + return 16; + } else { + return 0; + } + } +} \ No newline at end of file diff --git a/lib/features/contact/presentation/widgets/app_bar_contact_widget.dart b/lib/features/contact/presentation/widgets/app_bar_contact_widget.dart new file mode 100644 index 000000000..396d89917 --- /dev/null +++ b/lib/features/contact/presentation/widgets/app_bar_contact_widget.dart @@ -0,0 +1,47 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/views/button/icon_button_web.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class AppBarContactWidget extends StatelessWidget { + + final _imagePaths = Get.find(); + + final Function()? onCloseContactView; + + AppBarContactWidget({ + Key? key, + this.onCloseContactView, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Stack(alignment: Alignment.center, children: [ + Positioned( + left: 0, + child: buildIconWeb( + icon: SvgPicture.asset(_imagePaths.icCloseComposer, + color: AppColor.colorCloseButton, + width: 24, + height: 24, + fit: BoxFit.fill), + minSize: 25, + iconSize: 25, + iconPadding: const EdgeInsets.all(5), + splashRadius: 15, + tooltip: AppLocalizations.of(context).close, + onTap: onCloseContactView), + ), + Center(child: Text( + AppLocalizations.of(context).contains, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black))), + ]); + } +} \ No newline at end of file diff --git a/lib/features/search/presentation/model/simple_search_filter.dart b/lib/features/search/presentation/model/simple_search_filter.dart index 9b82b7655..af7d9c9d4 100644 --- a/lib/features/search/presentation/model/simple_search_filter.dart +++ b/lib/features/search/presentation/model/simple_search_filter.dart @@ -138,12 +138,12 @@ extension SearchEmailFilterExtension on SimpleSearchFilter { } } - String getNameContactApplied(PrefixEmailAddress prefixEmailAddress) { + String getNameContactApplied(BuildContext context, PrefixEmailAddress prefixEmailAddress) { switch(prefixEmailAddress) { case PrefixEmailAddress.from: - return from.first; + return '${AppLocalizations.of(context).from_email_address_prefix} ${from.first}'; case PrefixEmailAddress.to: - return to.first; + return '${AppLocalizations.of(context).to_email_address_prefix} ${to.first}'; default: return ''; } diff --git a/lib/features/search/presentation/search_email_controller.dart b/lib/features/search/presentation/search_email_controller.dart index 4a6886412..fcc163cce 100644 --- a/lib/features/search/presentation/search_email_controller.dart +++ b/lib/features/search/presentation/search_email_controller.dart @@ -7,13 +7,16 @@ import 'package:debounce_throttle/debounce_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_comparator.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_comparator_property.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/contact/presentation/model/contact_arguments.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_email_permanently_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_emails_permanently_state.dart'; @@ -81,6 +84,8 @@ class SearchEmailController extends BaseController AccountId? get accountId => mailboxDashBoardController.accountId.value; + Session? get session => mailboxDashBoardController.sessionCurrent; + UserProfile? get userProfile => mailboxDashBoardController.userProfile.value; SearchQuery? get searchQuery => simpleSearchFilter.value.text; @@ -355,9 +360,6 @@ class SearchEmailController extends BaseController } bool checkQuickSearchFilterSelected(QuickSearchFilter filter) { - log('SearchEmailController::checkQuickSearchFilterSelected(): filter: $filter'); - log('SearchEmailController::checkQuickSearchFilterSelected(): simpleSearchFilter: ${simpleSearchFilter.value.from}'); - log('SearchEmailController::checkQuickSearchFilterSelected(): userProfile: ${userProfile!.email}'); switch (filter) { case QuickSearchFilter.hasAttachment: return simpleSearchFilter.value.hasAttachment == true; @@ -366,16 +368,13 @@ class SearchEmailController extends BaseController return true; } return simpleSearchFilter.value.emailReceiveTimeType == EmailReceiveTimeType.last7Days; - case QuickSearchFilter.fromMe: - return userProfile != null && - simpleSearchFilter.value.from.contains(userProfile!.email) && - simpleSearchFilter.value.from.length == 1; + default: + return false; } } void _selectQuickSearchFilter(QuickSearchFilter filter) { final filterSelected = checkQuickSearchFilterSelected(filter); - log('SearchEmailController::_selectQuickSearchFilter(): filterSelected: $filterSelected'); switch (filter) { case QuickSearchFilter.hasAttachment: _updateSimpleSearchFilter(hasAttachment: !filterSelected); @@ -389,14 +388,7 @@ class SearchEmailController extends BaseController _updateSimpleSearchFilter(emailReceiveTimeType: EmailReceiveTimeType.last7Days); } break; - case QuickSearchFilter.fromMe: - if (userProfile != null) { - filterSelected - ? simpleSearchFilter.value.from.removeWhere((e) => e == userProfile!.email) - : simpleSearchFilter.value.from.add(userProfile!.email); - log('SearchEmailController::_selectQuickSearchFilter(): from: ${simpleSearchFilter.value.from}'); - _updateSimpleSearchFilter(from: simpleSearchFilter.value.from); - } + default: break; } } @@ -445,11 +437,60 @@ class SearchEmailController extends BaseController BuildContext context, PrefixEmailAddress prefixEmailAddress ) async { + if (accountId != null && session != null) { + final listContactSelected = simpleSearchFilter.value.getContactApplied(prefixEmailAddress); + final newContact = await push( + AppRoutes.CONTACT, + 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; + } + } + + 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, SearchQuery? text, PresentationMailbox? mailbox, EmailReceiveTimeType? emailReceiveTimeType, @@ -458,6 +499,7 @@ class SearchEmailController extends BaseController }) { simpleSearchFilter.value = simpleSearchFilter.value.copyWith( from: from, + to: to, text: text, mailbox: mailbox, emailReceiveTimeType: emailReceiveTimeType, diff --git a/lib/features/search/presentation/search_email_view.dart b/lib/features/search/presentation/search_email_view.dart index 26c594c24..513ce866f 100644 --- a/lib/features/search/presentation/search_email_view.dart +++ b/lib/features/search/presentation/search_email_view.dart @@ -42,6 +42,12 @@ class SearchEmailView extends GetWidget @override Widget build(BuildContext context) { + if (_responsiveUtils.isWebDesktop(context)) { + WidgetsBinding.instance.addPostFrameCallback((_) { + controller.closeSearchView(context); + }); + } + return Scaffold( body: GestureDetector( onTap: () => FocusScope.of(context).unfocus(), @@ -129,7 +135,6 @@ class SearchEmailView extends GetWidget ..textDecoration(InputDecoration( contentPadding: const EdgeInsets.all(12), hintText: AppLocalizations.of(context).search_emails, - fillColor: Colors.redAccent, hintStyle: const TextStyle( color: AppColor.loginTextFieldHintColor, fontSize: 16), @@ -590,7 +595,7 @@ class SearchEmailView extends GetWidget const SizedBox(width: 4), Text( filterSelected - ? controller.simpleSearchFilter.value.getNameContactApplied(prefixEmailAddress) + ? controller.simpleSearchFilter.value.getNameContactApplied(context, prefixEmailAddress) : controller.simpleSearchFilter.value.getNameContactDefault(context, prefixEmailAddress), maxLines: 1, overflow: CommonTextStyle.defaultTextOverFlow, diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index ef03cc03e..cad239eaa 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-09-16T03:16:09.866930", + "@@last_modified": "2022-09-20T13:44:48.613115", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -2185,5 +2185,17 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "contact": "Contact", + "@contact": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "hintSearchInputContact": "Enter name or email", + "@hintSearchInputContact": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index cdf6e08eb..5a065142a 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2252,11 +2252,23 @@ class AppLocalizations { ); } - String get clearAll { return Intl.message( 'Clear all', name: 'clearAll', ); } + + String get contact { + return Intl.message( + 'Contact', + name: 'contact'); + } + + String get hintSearchInputContact { + return Intl.message( + 'Enter name or email', + name: 'hintSearchInputContact' + ); + } } \ No newline at end of file diff --git a/lib/main/pages/app_pages.dart b/lib/main/pages/app_pages.dart index f6a9aa82c..534671a67 100644 --- a/lib/main/pages/app_pages.dart +++ b/lib/main/pages/app_pages.dart @@ -2,6 +2,7 @@ import 'package:get/get.dart'; import 'package:get/get_navigation/src/routes/get_route.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart' deferred as composer; +import 'package:tmail_ui_user/features/contact/presentation/contact_bindings.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' deferred as destination_picker; import 'package:tmail_ui_user/features/email/presentation/email_view.dart' deferred as email; @@ -11,6 +12,7 @@ import 'package:tmail_ui_user/features/identity_creator/presentation/identity_cr import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_view.dart' deferred as identity_creator; import 'package:tmail_ui_user/features/emails_forward_creator/presentation/emails_forward_creator_binding.dart'; import 'package:tmail_ui_user/features/emails_forward_creator/presentation/emails_forward_creator_view.dart' deferred as emails_forward_creator; +import 'package:tmail_ui_user/features/contact/presentation/contact_view.dart' deferred as contact_view; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/rules_filter_creator_bindings.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/rules_filter_creator_view.dart' deferred as rules_filter_creator; import 'package:tmail_ui_user/features/login/presentation/login_bindings.dart'; @@ -89,5 +91,12 @@ class AppPages { 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()), ]; } diff --git a/lib/main/routes/app_routes.dart b/lib/main/routes/app_routes.dart index 572c36334..2b3d4d0df 100644 --- a/lib/main/routes/app_routes.dart +++ b/lib/main/routes/app_routes.dart @@ -14,4 +14,5 @@ abstract class AppRoutes { static const RULES_FILTER_CREATOR = '$MANAGE_ACCOUNT/rules_filter_creator'; static const EMAILS_FORWARD_CREATOR = '$MANAGE_ACCOUNT/emails_forward_creator'; static const SEARCH_EMAIL = '$MAILBOX_DASHBOARD/search_email'; + static const CONTACT = '$MAILBOX_DASHBOARD/contact'; } \ No newline at end of file