From dc35d5e5a0ec88096cb809bf67f15e7527041e57 Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 22 Mar 2022 11:50:09 +0700 Subject: [PATCH] TF-381 Apply new UI search emails --- .../presentation/mailbox_controller.dart | 6 +- .../mailbox/presentation/mailbox_view.dart | 2 + .../presentation/thread_controller.dart | 8 + .../thread/presentation/thread_view.dart | 313 +++++++++++------- .../widgets/search_app_bar_widget.dart | 20 +- 5 files changed, 218 insertions(+), 131 deletions(-) diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 69e2118ee..be4b00631 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -267,7 +267,11 @@ class MailboxController extends BaseMailboxController { mailboxDashBoardController.setSelectedMailbox(presentationMailboxSelected); mailboxDashBoardController.clearSelectedEmail(); - if (!responsiveUtils.isDesktop(context)) { + if (mailboxDashBoardController.isSearchActive()) { + mailboxDashBoardController.disableSearch(); + } + + if (!responsiveUtils.isDesktop(context) && !responsiveUtils.isTabletLarge(context)) { mailboxDashBoardController.closeDrawer(); } } diff --git a/lib/features/mailbox/presentation/mailbox_view.dart b/lib/features/mailbox/presentation/mailbox_view.dart index d527e74ef..6b2e11b99 100644 --- a/lib/features/mailbox/presentation/mailbox_view.dart +++ b/lib/features/mailbox/presentation/mailbox_view.dart @@ -342,7 +342,9 @@ class MailboxView extends GetWidget { children: [ _buildBackSearchButton(context), Expanded(child: (SearchAppBarWidget( + context, _imagePaths, + _responsiveUtils, controller.searchQuery.value, controller.searchFocus, controller.searchInputController, diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 8c0ad10be..fdffb592f 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -50,6 +50,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/refresh_changes_em import 'package:tmail_ui_user/features/thread/domain/usecases/search_email_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/search_more_email_interactor.dart'; import 'package:tmail_ui_user/features/thread/presentation/extensions/filter_message_option_extension.dart'; +import 'package:tmail_ui_user/features/thread/presentation/model/search_status.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -149,12 +150,19 @@ class ThreadController extends BaseController { } }); }); + + mailboxDashBoardController.searchState.listen((state) { + if (state.searchStatus == SearchStatus.INACTIVE) { + emailListSearch.clear(); + } + }); } @override void onClose() { mailboxDashBoardController.selectedMailbox.close(); mailboxDashBoardController.viewState.close(); + mailboxDashBoardController.searchState.close(); listEmailController.dispose(); super.onClose(); } diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 2be2a17f7..2c8435b8e 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -40,73 +40,35 @@ class ThreadView extends GetWidget { color: Colors.white, padding: EdgeInsets.only(right: 10, top: 16, bottom: 10), child: _buildHeader(context)), - Obx(() => controller.isSearchActive() - ? _buildSearchForm(context) - : _responsiveUtils.isDesktop(context) ? SizedBox.shrink() : _buildAppBarNormal(context)), - Obx(() => !controller.isSearchActive() && !_responsiveUtils.isDesktop(context) - ? Padding( - padding: EdgeInsets.only(left: 16, right: 16, bottom: 10), - child: (SearchBarView(_imagePaths) - ..hintTextSearch(AppLocalizations.of(context).hint_search_emails) - ..addOnOpenSearchViewAction(() => controller.enableSearch(context))) - .build()) - : SizedBox.shrink()), + _buildSearchInputFormForMobile(context), + _buildSearchButtonViewForMobile(context), Expanded(child: Container( color: AppColor.colorBgDesktop, margin: _responsiveUtils.isDesktop(context) ? EdgeInsets.all(16) : EdgeInsets.zero, - child: Stack( - children: [ + child: Stack(children: [ Container( - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: _responsiveUtils.isDesktop(context) ? BorderRadius.circular(20) : null, - border: _responsiveUtils.isDesktop(context) ? Border.all(color: AppColor.colorBorderBodyThread, width: 1) : null, - color: Colors.white), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildStatusResultSearch(context), - _buildLoadingView(), - Expanded(child: _buildListEmail(context)), - _buildLoadingViewLoadMore(), - ] - ) + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: _responsiveUtils.isDesktop(context) ? BorderRadius.circular(20) : null, + border: _responsiveUtils.isDesktop(context) ? Border.all(color: AppColor.colorBorderBodyThread, width: 1) : null, + color: Colors.white), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildStatusResultSearch(context), + _buildLoadingView(), + Expanded(child: _buildListEmail(context)), + _buildLoadingViewLoadMore(), + ] + ) ), _buildSuggestionBox(context) - ], - )) - ), - Obx(() => controller.isSelectionEnabled() && !_responsiveUtils.isDesktop(context) - ? Column(children: [ - Divider(color: AppColor.lineItemListColor, height: 1, thickness: 0.2), - _buildOptionSelectionBottomBar(context) - ]) - : SizedBox.shrink()), + ]))), + _buildListButtonSelectionForMobile(context), ] ) ), - floatingActionButton: Obx(() => !controller.isSearchActive() && !controller.isSelectionEnabled() - ? Container( - padding: EdgeInsets.only(bottom: controller.isSelectionEnabled() - ? 80 - : _responsiveUtils.isMobileDevice(context) ? 0 : 16), - child: Align( - alignment: Alignment.bottomRight, - child: ScrollingFloatingButtonAnimated( - icon: SvgPicture.asset(_imagePaths.icCompose, width: 20, height: 20, fit: BoxFit.fill), - text: Padding( - padding: EdgeInsets.only(right: 10), - child: Text( - AppLocalizations.of(context).compose, - style: TextStyle(color: AppColor.colorTextButton, fontSize: 15.0, fontWeight: FontWeight.w500)) - ), - onPress: () => controller.composeEmailAction(), - scrollController: controller.listEmailController, - color: Colors.white, - elevation: 4.0, - width: 140, - animateIcon: false))) - : SizedBox.shrink()), + floatingActionButton: _buildFloatingButtonCompose(context), ), ); } @@ -114,20 +76,15 @@ class ThreadView extends GetWidget { Widget _buildHeader(BuildContext context) { return Row(children: [ Obx(() => !controller.isSelectionEnabled() && _responsiveUtils.isDesktop(context) - ? _buildOptionTopBar(context) + ? _buildListButtonTopBar(context) : SizedBox.shrink()), Obx(() => controller.isSelectionEnabled() && _responsiveUtils.isDesktop(context) - ? _buildOptionSelectionTopBar(context) + ? _buildListButtonSelectionForDesktop(context) : SizedBox.shrink()), SizedBox(width: 16), - Spacer(), - Padding( - padding: EdgeInsets.only(right: 16), - child: (SearchBarView(_imagePaths) - ..hintTextSearch(AppLocalizations.of(context).search_emails) - ..maxSizeWidth(240) - ..addOnOpenSearchViewAction(() => controller.enableSearch(context))) - .build()), + Obx(() => !controller.isSearchActive() && _responsiveUtils.isDesktop(context) ? Spacer() : SizedBox.shrink()), + Expanded(child: _buildSearchInputFormForDesktop(context)), + _buildSearchButtonViewForDesktop(context), Padding( padding: EdgeInsets.only(right: 16), child: (AvatarBuilder() @@ -136,10 +93,7 @@ class ThreadView extends GetWidget { ..textColor(Colors.black) ..context(context) ..addOnTapAvatarActionWithPositionClick((position) => - controller.openUserSettingAction( - context, - position, - [PopupMenuItem(padding: EdgeInsets.symmetric(horizontal: 8), child: _logoutAction(context))])) + controller.openUserSettingAction(context, position, _popupMenuUserSettingActionTile(context))) ..addBoxShadows([BoxShadow( color: AppColor.colorShadowBgContentEmail, spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5))]) @@ -148,18 +102,19 @@ class ThreadView extends GetWidget { ]); } - Widget _buildOptionTopBar(BuildContext context) { + Widget _buildListButtonTopBar(BuildContext context) { return Row(children: [ - SizedBox(width: 16), - (ButtonBuilder(_imagePaths.icRefresh) - ..key(Key('button_reload_thread')) - ..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread)) - ..paddingIcon(EdgeInsets.zero) - ..size(16) - ..radiusSplash(10) - ..padding(EdgeInsets.symmetric(horizontal: 8, vertical: 8)) - ..onPressActionClick(() => controller.refreshAllEmail())) - .build(), + if (!controller.isSearchActive()) SizedBox(width: 16), + if (!controller.isSearchActive()) + (ButtonBuilder(_imagePaths.icRefresh) + ..key(Key('button_reload_thread')) + ..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread)) + ..paddingIcon(EdgeInsets.zero) + ..size(16) + ..radiusSplash(10) + ..padding(EdgeInsets.symmetric(horizontal: 8, vertical: 8)) + ..onPressActionClick(() => controller.refreshAllEmail())) + .build(), SizedBox(width: 16), (ButtonBuilder(_imagePaths.icSelectAll) ..key(Key('button_select_all')) @@ -192,36 +147,38 @@ class ThreadView extends GetWidget { }) ..text(AppLocalizations.of(context).mark_all_as_read, isVertical: false)) .build(), - SizedBox(width: 16), - (ButtonBuilder(_imagePaths.icFilterWeb) - ..key(Key('button_filter_messages')) - ..context(context) - ..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread)) - ..paddingIcon(EdgeInsets.only(right: 8)) - ..size(16) - ..padding(EdgeInsets.symmetric(horizontal: 12, vertical: 8)) - ..radiusSplash(10) - ..textStyle(TextStyle( - fontSize: 12, - color: controller.filterMessageOption.value == FilterMessageOption.all ? AppColor.colorTextButtonHeaderThread : AppColor.colorNameEmail, - fontWeight: controller.filterMessageOption.value == FilterMessageOption.all ? FontWeight.normal : FontWeight.w500)) - ..addIconAction(Padding( - padding: EdgeInsets.only(left: 8), - child: SvgPicture.asset(_imagePaths.icArrowDown, fit: BoxFit.fill))) - ..addOnPressActionWithPositionClick((position) => - controller.openFilterMessagesForTablet( - context, - position, - _popupMenuEmailActionTile(context, controller.filterMessageOption.value))) - ..text(controller.filterMessageOption.value == FilterMessageOption.all - ? AppLocalizations.of(context).filter_messages - : controller.filterMessageOption.value.getTitle(context), isVertical: false)) - .build(), + if (!controller.isSearchActive()) SizedBox(width: 16), + if (!controller.isSearchActive()) + (ButtonBuilder(_imagePaths.icFilterWeb) + ..key(Key('button_filter_messages')) + ..context(context) + ..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorButtonHeaderThread)) + ..paddingIcon(EdgeInsets.only(right: 8)) + ..size(16) + ..padding(EdgeInsets.symmetric(horizontal: 12, vertical: 8)) + ..radiusSplash(10) + ..textStyle(TextStyle( + fontSize: 12, + color: controller.filterMessageOption.value == FilterMessageOption.all ? AppColor.colorTextButtonHeaderThread : AppColor.colorNameEmail, + fontWeight: controller.filterMessageOption.value == FilterMessageOption.all ? FontWeight.normal : FontWeight.w500)) + ..addIconAction(Padding( + padding: EdgeInsets.only(left: 8), + child: SvgPicture.asset(_imagePaths.icArrowDown, fit: BoxFit.fill))) + ..addOnPressActionWithPositionClick((position) => + controller.openFilterMessagesForTablet( + context, + position, + _popupMenuEmailActionTile(context, controller.filterMessageOption.value))) + ..text(controller.filterMessageOption.value == FilterMessageOption.all + ? AppLocalizations.of(context).filter_messages + : controller.filterMessageOption.value.getTitle(context), isVertical: false)) + .build(), ]); } - Widget _buildOptionSelectionTopBar(BuildContext context) { + Widget _buildListButtonSelectionForDesktop(BuildContext context) { return Row(children: [ + SizedBox(width: 16), buildIconWeb( icon: SvgPicture.asset(_imagePaths.icCloseComposer, color: AppColor.colorTextButton, fit: BoxFit.fill), tooltip: AppLocalizations.of(context).cancel, @@ -251,22 +208,101 @@ class ThreadView extends GetWidget { ]); } - Widget _buildOptionSelectionBottomBar(BuildContext context) { - return Padding( - padding: EdgeInsets.all(10), - child: (BottomBarThreadSelectionWidget( - context, - _imagePaths, - _responsiveUtils, - controller.listEmailSelected) - ..addOnPressEmailSelectionActionClick((actionType, selectionEmail) => - controller.pressEmailSelectionAction(context, actionType, selectionEmail))) - .build()); + Widget _buildListButtonSelectionForMobile(BuildContext context) { + return Obx(() { + if (controller.isSelectionEnabled() && !_responsiveUtils.isDesktop(context)) { + return Column(children: [ + Divider(color: AppColor.lineItemListColor, height: 1, thickness: 0.2), + Padding( + padding: EdgeInsets.all(10), + child: (BottomBarThreadSelectionWidget(context, _imagePaths, _responsiveUtils, controller.listEmailSelected) + ..addOnPressEmailSelectionActionClick((actionType, selectionEmail) => controller.pressEmailSelectionAction(context, actionType, selectionEmail))) + .build()), + ]); + } else { + return SizedBox.shrink(); + } + }); + } + + Widget _buildSearchButtonViewForMobile(BuildContext context) { + return Obx(() { + if (!controller.isSearchActive() && !_responsiveUtils.isDesktop(context)) { + return Padding( + padding: EdgeInsets.only(left: 16, right: 16, bottom: 10), + child: (SearchBarView(_imagePaths) + ..hintTextSearch(AppLocalizations.of(context).hint_search_emails) + ..addOnOpenSearchViewAction(() => controller.enableSearch(context))) + .build()); + } else { + return SizedBox.shrink(); + } + }); + } + + Widget _buildSearchInputFormForMobile(BuildContext context) { + return Obx(() { + if (controller.isSearchActive() && !_responsiveUtils.isDesktop(context)) { + return _buildSearchForm(context); + } else { + return _responsiveUtils.isDesktop(context) ? SizedBox.shrink() : _buildAppBarNormal(context); + } + }); + } + + Widget _buildSearchButtonViewForDesktop(BuildContext context) { + return Obx(() { + if (!controller.isSearchActive() && _responsiveUtils.isDesktop(context)) { + return Padding( + padding: EdgeInsets.only(right: 16), + child: (SearchBarView(_imagePaths) + ..hintTextSearch(AppLocalizations.of(context).search_emails) + ..maxSizeWidth(240) + ..addOnOpenSearchViewAction(() => controller.enableSearch(context))) + .build()); + } else { + return SizedBox.shrink(); + } + }); + } + + Widget _buildSearchInputFormForDesktop(BuildContext context) { + return Obx(() { + if (controller.isSearchActive() && _responsiveUtils.isDesktop(context)) { + return _buildSearchFormForDesktop(context); + } else { + return SizedBox.shrink(); + } + }); + } + + Widget _buildSearchFormForDesktop(BuildContext context) { + return (SearchAppBarWidget( + context, + _imagePaths, + _responsiveUtils, + controller.searchQuery, + controller.mailboxDashBoardController.searchFocus, + controller.mailboxDashBoardController.searchInputController, + suggestionSearch: controller.mailboxDashBoardController.suggestionSearch,) + ..addDecoration(BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10)), + color: AppColor.colorBgSearchBar)) + ..setMargin(EdgeInsets.only(right: 10)) + ..setHeightSearchBar(45) + ..setHintText(AppLocalizations.of(context).search_mail) + ..addOnCancelSearchPressed(() => controller.disableSearch()) + ..addOnClearTextSearchAction(() => controller.mailboxDashBoardController.clearSearchText()) + ..addOnTextChangeSearchAction((query) => controller.mailboxDashBoardController.addSuggestionSearch(query)) + ..addOnSearchTextAction((query) => controller.mailboxDashBoardController.searchEmail(context, query))) + .build(); } Widget _buildSearchForm(BuildContext context) { return (SearchAppBarWidget( + context, _imagePaths, + _responsiveUtils, controller.searchQuery, controller.mailboxDashBoardController.searchFocus, controller.mailboxDashBoardController.searchInputController, @@ -306,6 +342,33 @@ class ThreadView extends GetWidget { .build(); } + Widget _buildFloatingButtonCompose(BuildContext context) { + return Obx(() { + if (!controller.isSearchActive() && !controller.isSelectionEnabled() && !_responsiveUtils.isDesktop(context)) { + return Container( + padding: EdgeInsets.only(bottom: controller.isSelectionEnabled() ? 80 : _responsiveUtils.isMobileDevice(context) ? 0 : 16), + child: Align( + alignment: Alignment.bottomRight, + child: ScrollingFloatingButtonAnimated( + icon: SvgPicture.asset(_imagePaths.icCompose, width: 20, height: 20, fit: BoxFit.fill), + text: Padding(padding: EdgeInsets.only(right: 10), + child: Text(AppLocalizations.of(context).compose, + style: TextStyle(color: AppColor.colorTextButton, fontSize: 15.0, fontWeight: FontWeight.w500))), + onPress: () => controller.composeEmailAction(), + scrollController: controller.listEmailController, + color: Colors.white, + elevation: 4.0, + width: 140, + animateIcon: false + ) + ) + ); + } else { + return SizedBox.shrink(); + } + }); + } + List _filterMessagesCupertinoActionTile(BuildContext context, FilterMessageOption optionCurrent) { return [ _filterMessageWithAttachmentsAction(context, optionCurrent), @@ -462,11 +525,11 @@ class ThreadView extends GetWidget { if (controller.currentSelectMode.value == SelectMode.INACTIVE) { return listPresentationEmail.isNotEmpty ? RefreshIndicator( - color: AppColor.primaryColor, + color: AppColor.colorTextButton, onRefresh: () async => controller.refreshAllEmail(), child: _buildListEmailBody(context, listPresentationEmail)) : RefreshIndicator( - color: AppColor.primaryColor, + color: AppColor.colorTextButton, onRefresh: () async => controller.refreshAllEmail(), child: _buildEmptyEmail(context)); } else { @@ -569,6 +632,12 @@ class ThreadView extends GetWidget { }); } + List _popupMenuUserSettingActionTile(BuildContext context) { + return [ + PopupMenuItem(padding: EdgeInsets.symmetric(horizontal: 8), child: _logoutAction(context)), + ]; + } + Widget _logoutAction(BuildContext context) { return (AppActionSheetActionBuilder( Key('logout_action'), diff --git a/lib/features/thread/presentation/widgets/search_app_bar_widget.dart b/lib/features/thread/presentation/widgets/search_app_bar_widget.dart index be0a69af8..3fa27b8ac 100644 --- a/lib/features/thread/presentation/widgets/search_app_bar_widget.dart +++ b/lib/features/thread/presentation/widgets/search_app_bar_widget.dart @@ -15,7 +15,9 @@ class SearchAppBarWidget { OnClearTextSearchAction? _onClearTextSearchAction; OnSearchTextAction? _onSearchTextAction; + final BuildContext _context; final ImagePaths _imagePaths; + final ResponsiveUtils _responsiveUtils; final SearchQuery? _searchQuery; final TextEditingController? _searchInputController; final FocusNode? _searchFocusNode; @@ -31,7 +33,9 @@ class SearchAppBarWidget { Widget? _iconClearText; SearchAppBarWidget( + this._context, this._imagePaths, + this._responsiveUtils, this._searchQuery, this._searchFocusNode, this._searchInputController, @@ -85,19 +89,20 @@ class SearchAppBarWidget { Widget build() { return Container( key: Key('search_app_bar_widget'), - alignment: Alignment.topCenter, height: _heightSearchBar, decoration: _decoration, - padding: _padding ?? EdgeInsets.symmetric(vertical: 8), + padding: _padding ?? EdgeInsets.zero, margin: _margin, child: MediaQuery( data: MediaQueryData(padding: EdgeInsets.zero), child: Row( - mainAxisAlignment: MainAxisAlignment.center, children: [ if (hasBackButton) _buildBackButton(), if (hasSearchButton) _buildSearchButton(), - Expanded(child: _buildSearchInputForm()), + Expanded(child: Transform( + transform: Matrix4.translationValues(0.0, _responsiveUtils.isDesktop(_context) ? -2.0 : 0.0, 0.0), + child: _buildSearchInputForm(), + )), if (suggestionSearch?.isNotEmpty == true || (_searchQuery != null && _searchQuery!.value.isNotEmpty)) _buildClearTextSearchButton(), ] @@ -111,11 +116,10 @@ class SearchAppBarWidget { shape: CircleBorder(), color: Colors.transparent, child: Padding( - padding: EdgeInsets.only(left: 8), + padding: EdgeInsets.only(left: _responsiveUtils.isDesktop(_context) ? 0 : 8), child: IconButton( splashRadius: 20, - color: AppColor.appColor, - icon: SvgPicture.asset(_imagePaths.icBack, color: AppColor.appColor, fit: BoxFit.fill), + icon: SvgPicture.asset(_imagePaths.icBack, color: AppColor.colorTextButton, fit: BoxFit.fill), onPressed: () { _searchInputController?.clear(); if (_onCancelSearchPressed != null) { @@ -155,7 +159,7 @@ class SearchAppBarWidget { border: InputBorder.none, focusedBorder: InputBorder.none, enabledBorder: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 7), + contentPadding: EdgeInsets.zero, hintText: _hintText, hintStyle: TextStyle(color: AppColor.colorHintSearchBar, fontSize: 17.0), labelStyle: TextStyle(color: AppColor.colorHintSearchBar, fontSize: 17.0)))