From 7b5a2dd8202a79c77d5ccc167efb9789a2c05292 Mon Sep 17 00:00:00 2001 From: dab246 Date: Fri, 8 Apr 2022 12:43:45 +0700 Subject: [PATCH] TF-467 Apply new UI for mailbox mobile --- assets/images/ic_collapse_folder.svg | 3 + assets/images/ic_expand_folder.svg | 4 +- assets/images/ic_folder_arrow.svg | 3 - assets/images/ic_next_arrow.svg | 3 - .../extensions/color_extension.dart | 5 +- .../presentation/resources/image_paths.dart | 3 +- .../presentation/utils/responsive_utils.dart | 3 + .../presentation/views/list/tree_view.dart | 4 +- .../presentation/mailbox_controller.dart | 18 + .../mailbox/presentation/mailbox_view.dart | 481 +++++++++--------- .../presentation/mailbox_view_web.dart | 453 +++++++++++++++++ .../model/mailbox_categories.dart | 40 ++ .../model/mailbox_categories_expand_mode.dart | 17 + .../widgets/mailbox_folder_tile_builder.dart | 88 ++-- ....dart => mailbox_search_tile_builder.dart} | 88 +--- .../user_information_widget_builder.dart | 2 +- .../presentation/mailbox_creator_view.dart | 2 +- .../presentation/mailbox_dashboard_view.dart | 40 +- .../mailbox_dashboard_view_web.dart | 121 +++++ .../thread/presentation/thread_view.dart | 105 ++-- lib/main/localizations/app_localizations.dart | 7 + lib/main/pages/app_pages.dart | 3 +- 22 files changed, 1058 insertions(+), 435 deletions(-) create mode 100644 assets/images/ic_collapse_folder.svg delete mode 100644 assets/images/ic_folder_arrow.svg delete mode 100644 assets/images/ic_next_arrow.svg create mode 100644 lib/features/mailbox/presentation/mailbox_view_web.dart create mode 100644 lib/features/mailbox/presentation/model/mailbox_categories.dart create mode 100644 lib/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart rename lib/features/mailbox/presentation/widgets/{mailbox_tile_builder.dart => mailbox_search_tile_builder.dart} (52%) create mode 100644 lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart diff --git a/assets/images/ic_collapse_folder.svg b/assets/images/ic_collapse_folder.svg new file mode 100644 index 000000000..d65e9848f --- /dev/null +++ b/assets/images/ic_collapse_folder.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_expand_folder.svg b/assets/images/ic_expand_folder.svg index 769cd09c4..e1caa55f3 100644 --- a/assets/images/ic_expand_folder.svg +++ b/assets/images/ic_expand_folder.svg @@ -1,3 +1,3 @@ - - + + diff --git a/assets/images/ic_folder_arrow.svg b/assets/images/ic_folder_arrow.svg deleted file mode 100644 index 5328bf886..000000000 --- a/assets/images/ic_folder_arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/ic_next_arrow.svg b/assets/images/ic_next_arrow.svg deleted file mode 100644 index 54fbf615d..000000000 --- a/assets/images/ic_next_arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 3c44a6be3..daaca6e7d 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -3,7 +3,7 @@ import 'dart:ui' show Color; import 'package:flutter/material.dart'; extension AppColor on Color { - static const primaryColor = Color(0xFF837DFF); + static const primaryColor = Color(0xFF007AFF); static const primaryDarkColor = Color(0xFF1C1C1C); static const primaryLightColor = Color(0xFFFFFFFF); static const baseTextColor = Color(0xFF7E869B); @@ -69,7 +69,8 @@ extension AppColor on Color { static const colorBgSearchBar = Color(0xFFEBEDF0); static const colorShadowBgContentEmail = Color(0x14000000); static const colorDividerMailbox = Color(0xFF99A2AD); - static const colorArrowUserMailbox = Color(0xFFB8C1CC); + static const colorCollapseMailbox = Color(0xFFB8C1CC); + static const colorExpandMailbox = Color(0xFF007AFF); static const colorBgMailbox = Color(0xFFF7F7F7); static const colorFilterMessageDisabled = Color(0xFF99A2AD); static const colorFilterMessageEnabled = Color(0xFF007AFF); diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 1dcd28a5e..71973ffe6 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -2,11 +2,10 @@ import 'package:core/presentation/resources/assets_paths.dart'; class ImagePaths { String get icSearch => _getImagePath('ic_search.svg'); - String get icNextArrow => _getImagePath('ic_next_arrow.svg'); String get icMailboxAllMail => _getImagePath('ic_mailbox_allmail.svg'); String get icMailboxTemplate => _getImagePath('ic_mailbox_template.svg'); - String get icFolderArrow => _getImagePath('ic_folder_arrow.svg'); String get icExpandFolder => _getImagePath('ic_expand_folder.svg'); + String get icCollapseFolder => _getImagePath('ic_collapse_folder.svg'); String get icBack => _getImagePath('ic_back.svg'); String get icEyeDisable => _getImagePath('ic_eye_disable.svg'); String get icShare => _getImagePath('ic_share.svg'); diff --git a/core/lib/presentation/utils/responsive_utils.dart b/core/lib/presentation/utils/responsive_utils.dart index b6e1a3dfd..e631a729b 100644 --- a/core/lib/presentation/utils/responsive_utils.dart +++ b/core/lib/presentation/utils/responsive_utils.dart @@ -8,6 +8,9 @@ class ResponsiveUtils { final int minTabletWidth = 600; final int minTabletLargeWidth = 900; + final double defaultSizeDrawerWidthMobileTablet = 375; + final double defaultSizeDrawerWidthWeb = 320; + final double _loginTextFieldWidthSmallScreen = 280.0; final double _loginTextFieldWidthLargeScreen = 320.0; final double _loginButtonWidth = 240.0; diff --git a/core/lib/presentation/views/list/tree_view.dart b/core/lib/presentation/views/list/tree_view.dart index 4e076c490..2b3344043 100644 --- a/core/lib/presentation/views/list/tree_view.dart +++ b/core/lib/presentation/views/list/tree_view.dart @@ -83,7 +83,9 @@ class TreeViewChild { AnimatedContainer( duration: Duration(milliseconds: 400), child: isExpanded! - ? Column(mainAxisSize: MainAxisSize.min, children: children) + ? Column( + mainAxisSize: MainAxisSize.min, + children: children.map((child) => Padding(padding: EdgeInsets.only(left: 20), child: child)).toList()) : Offstage(), ), ], diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index de95b1c93..5a077552c 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -36,6 +36,8 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailb import 'package:tmail_ui_user/features/mailbox/domain/usecases/rename_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/search_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/open_mailbox_view_event.dart'; @@ -81,6 +83,7 @@ class MailboxController extends BaseMailboxController { final searchState = SearchState.initial().obs; final searchQuery = SearchQuery.initial().obs; final currentSelectMode = SelectMode.INACTIVE.obs; + final mailboxCategoriesExpandMode = MailboxCategoriesExpandMode.initial().obs; final _openMailboxEventController = StreamController(); final searchInputController = TextEditingController(); @@ -672,6 +675,21 @@ class MailboxController extends BaseMailboxController { log('MailboxController::_createListMailboxNameAsStringInMailboxLocation(): $listMailboxNameAsStringExist'); } + void toggleMailboxCategories(MailboxCategories categories) { + switch(categories) { + case MailboxCategories.exchange: + final newExpandMode = mailboxCategoriesExpandMode.value.defaultMailbox == ExpandMode.EXPAND ? ExpandMode.COLLAPSE : ExpandMode.EXPAND; + mailboxCategoriesExpandMode.value.defaultMailbox = newExpandMode; + mailboxCategoriesExpandMode.refresh(); + break; + case MailboxCategories.folders: + final newExpandMode = mailboxCategoriesExpandMode.value.folderMailbox == ExpandMode.EXPAND ? ExpandMode.COLLAPSE : ExpandMode.EXPAND; + mailboxCategoriesExpandMode.value.folderMailbox = newExpandMode; + mailboxCategoriesExpandMode.refresh(); + break; + } + } + void closeMailboxScreen(BuildContext context) { _cancelSelectMailbox(); mailboxDashBoardController.closeDrawer(); diff --git a/lib/features/mailbox/presentation/mailbox_view.dart b/lib/features/mailbox/presentation/mailbox_view.dart index dd02e9050..ffa105fa6 100644 --- a/lib/features/mailbox/presentation/mailbox_view.dart +++ b/lib/features/mailbox/presentation/mailbox_view.dart @@ -6,10 +6,11 @@ import 'package:get/get.dart'; import 'package:model/model.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/bottom_bar_selection_mailbox_widget.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_tile_builder.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/user_information_widget_builder.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'; @@ -25,156 +26,176 @@ class MailboxView extends GetWidget { } Widget _buildBodyMailbox(BuildContext context) { - return SafeArea( - top: _responsiveUtils.isMobile(context) ? true : false, - bottom: false, - left: false, - right: false, + return SafeArea(bottom: false, left: false, right: false, top: _responsiveUtils.isMobile(context), child: ClipRRect( - borderRadius: BorderRadius.only( - topRight: Radius.circular(_responsiveUtils.isMobile(context) ? 14 : 0), - topLeft: Radius.circular(_responsiveUtils.isMobile(context) ? 14 : 0)), + borderRadius: _responsiveUtils.isMobile(context) && _responsiveUtils.isPortrait(context) + ? BorderRadius.only(topRight: Radius.circular(14), topLeft: Radius.circular(14)) + : BorderRadius.all(Radius.zero), child: Drawer( child: Scaffold( backgroundColor: _responsiveUtils.isDesktop(context) ? AppColor.colorBgDesktop : Colors.white, - body: Column( - children: [ - if (_responsiveUtils.isDesktop(context)) - Container( - color: Colors.white, - padding: EdgeInsets.only(left: 20, top: 20, bottom: 24), - child: (SloganBuilder(arrangedByHorizontal: true) - ..setSloganText(AppLocalizations.of(context).app_name) - ..setSloganTextAlign(TextAlign.center) - ..setSloganTextStyle(TextStyle(color: Colors.black, fontSize: 25, fontWeight: FontWeight.bold)) - ..setSizeLogo(28) - ..setLogo(_imagePaths.icLogoTMail)) - .build()), - if (!_responsiveUtils.isDesktop(context)) _buildHeaderMailbox(context), - if (_responsiveUtils.isDesktop(context)) - Row(children: [ - Expanded(child: Container( - padding: EdgeInsets.only(top: 16, left: 20), - color: AppColor.colorBgDesktop, - alignment: Alignment.centerLeft, - child: (ButtonBuilder(_imagePaths.icCompose) - ..key(Key('button_compose_email')) - ..decoration(BoxDecoration(borderRadius: BorderRadius.circular(25), color: AppColor.colorTextButton)) - ..paddingIcon(EdgeInsets.only(right: 8)) - ..iconColor(Colors.white) - ..maxWidth(140) - ..size(20) - ..radiusSplash(10) - ..padding(EdgeInsets.symmetric(vertical: 13)) - ..textStyle(TextStyle(fontSize: 15, color: Colors.white, fontWeight: FontWeight.w500)) - ..onPressActionClick(() => controller.mailboxDashBoardController.composeEmailAction()) - ..text(AppLocalizations.of(context).compose, isVertical: false)) - .build()) - ), - Obx(() { - if (controller.isSearchActive()) { - return controller.listMailboxSearched.isNotEmpty - ? Padding( - padding: EdgeInsets.only(top: 16), - child: _buildEditMailboxButton(context, controller.isSelectionEnabled())) - : SizedBox.shrink(); - } else { - return Padding( - padding: EdgeInsets.only(top: 16), - child: _buildEditMailboxButton(context, controller.isSelectionEnabled())); - } - }) - ]), - Obx(() => !controller.isSearchActive() && _responsiveUtils.isDesktop(context) - ? Row(children: [ - Expanded(child: _buildSearchBarWidget(context)), - buildIconWeb( - icon: SvgPicture.asset(_imagePaths.icAddNewFolder, color: AppColor.colorTextButton, fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).new_mailbox, - onTap: () => controller.goToCreateNewMailboxView()), - ]) - : SizedBox.shrink()), - Obx(() => controller.isSearchActive() ? _buildInputSearchFormWidget(context) : SizedBox.shrink()), - Expanded(child: Obx(() => Container( - color: _responsiveUtils.isDesktop(context) + body: Stack(children: [ + Column(children: [ + if (_responsiveUtils.isDesktop(context)) _buildLogoApp(context), + if (!_responsiveUtils.isDesktop(context)) _buildHeaderMailbox(context), + if (_responsiveUtils.isDesktop(context)) _buildComposerButton(context), + Obx(() => !controller.isSearchActive() && _responsiveUtils.isDesktop(context) + ? Row(children: [ + Expanded(child: _buildSearchBarWidget(context)), + _buildAddNewFolderButton(context), + ]) + : SizedBox.shrink()), + Obx(() => controller.isSearchActive() + ? SafeArea(bottom: false, top: false, right: false, child: _buildInputSearchFormWidget(context)) + : SizedBox.shrink()), + Expanded(child: Obx(() => Container( + color: _responsiveUtils.isDesktop(context) ? Colors.transparent : controller.isSearchActive() ? Colors.white : AppColor.colorBgMailbox, - child: RefreshIndicator( - color: AppColor.primaryColor, - onRefresh: () async => controller.refreshAllMailbox(), - child: controller.isSearchActive() - ? _buildListMailboxSearched(context, controller.listMailboxSearched) - : _buildListMailbox(context)), - ))), - Obx(() => controller.isSelectionEnabled() - ? _buildOptionSelectionMailbox(context) - : SizedBox.shrink()), - ] - ), + child: RefreshIndicator( + color: AppColor.primaryColor, + onRefresh: () async => controller.refreshAllMailbox(), + child:controller.isSearchActive() + ? SafeArea( + bottom: !controller.isSelectionEnabled(), + top: false, + right: false, + child: _buildListMailboxSearched(context)) + : SafeArea( + bottom: !controller.isSelectionEnabled(), + right: false, + child: Padding( + padding: EdgeInsets.only(bottom: (_responsiveUtils.isMobile(context) && _responsiveUtils.isLandscape(context)) || controller.isSelectionEnabled() ? 0 : 55), + child: _buildListMailbox(context))) + ), + ))), + Obx(() => controller.isSelectionEnabled() ? _buildOptionSelectionMailbox(context) : SizedBox.shrink()), + ]), + Obx(() { + if (controller.mailboxDashBoardController.appInformation.value != null + && !controller.isSearchActive() && !controller.isSelectionEnabled()) { + if (_responsiveUtils.isMobile(context) && _responsiveUtils.isLandscape(context)) { + return SizedBox.shrink(); + } + return Align( + alignment: Alignment.bottomCenter, + child: _buildVersionInformation(context, controller.mailboxDashBoardController.appInformation.value!)); + } else { + return SizedBox.shrink(); + } + }) + ]), ) ) ) ); } + Widget _buildLogoApp(BuildContext context) { + return Container( + color: Colors.white, + padding: EdgeInsets.only(left: 32, top: 20, bottom: 24), + child: (SloganBuilder(arrangedByHorizontal: true) + ..setSloganText(AppLocalizations.of(context).app_name) + ..setSloganTextAlign(TextAlign.center) + ..setSloganTextStyle(TextStyle(color: Colors.black, fontSize: 25, fontWeight: FontWeight.bold)) + ..setSizeLogo(24) + ..setLogo(_imagePaths.icLogoTMail)) + .build()); + } + Widget _buildHeaderMailbox(BuildContext context) { return Column( - mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only( - top: _responsiveUtils.isMobile(context) ? 14 : 30, - bottom: 10), - child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - !_responsiveUtils.isDesktop(context) && !_responsiveUtils.isTabletLarge(context) - ? _buildCloseScreenButton(context) - : SizedBox(width: 50), - Obx(() { - if (controller.isSearchActive()) { - return controller.listMailboxSearched.isNotEmpty - ? SizedBox(width: controller.isSelectionEnabled() ? 49 : 40) - : SizedBox.shrink(); - } else { - return SizedBox(width: controller.isSelectionEnabled() ? 49 : 40); - } - }), - Expanded(child: Text( - AppLocalizations.of(context).folders, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 20, color: AppColor.colorNameEmail, fontWeight: FontWeight.w700))), - Obx(() { - if (controller.isSearchActive()) { - return controller.listMailboxSearched.isNotEmpty - ? _buildEditMailboxButton(context, controller.isSelectionEnabled()) - : SizedBox(width: 25); - } else { - return _buildEditMailboxButton(context, controller.isSelectionEnabled()); - } - }), - _buildAddNewFolderButton(context), - ])), - Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2), + padding: EdgeInsets.only(top: _responsiveUtils.isMobile(context) ? 10 : 30, bottom: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _responsiveUtils.isMobile(context) || _responsiveUtils.isTablet(context) + ? Padding(padding: EdgeInsets.only(left: 10), child: _buildCloseScreenButton(context)) + : SizedBox(width: 50), + Obx(() { + if (controller.isSearchActive()) { + return controller.listMailboxSearched.isNotEmpty + ? SizedBox(width: controller.isSelectionEnabled() ? 49 : 40) + : SizedBox.shrink(); + } else { + return SizedBox(width: controller.isSelectionEnabled() ? 49 : 40); + } + }), + Expanded(child: Text( + AppLocalizations.of(context).folders, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 21, color: Colors.black, fontWeight: FontWeight.bold))), + Obx(() { + if (controller.isSearchActive()) { + return controller.listMailboxSearched.isNotEmpty + ? _buildEditMailboxButton(context, controller.isSelectionEnabled()) + : SizedBox(width: 25); + } else { + return _buildEditMailboxButton(context, controller.isSelectionEnabled()); + } + }), + Padding(padding: EdgeInsets.only(right: 5), child: _buildAddNewFolderButton(context)), + ] + ) + ), + if (!_responsiveUtils.isTabletLarge(context)) + Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2), ] ); } + Widget _buildComposerButton(BuildContext context) { + return Row(children: [ + Expanded(child: Container( + padding: EdgeInsets.only(top: 16, left: 20), + color: AppColor.colorBgDesktop, + alignment: Alignment.centerLeft, + child: (ButtonBuilder(_imagePaths.icCompose) + ..key(Key('button_compose_email')) + ..decoration(BoxDecoration(borderRadius: BorderRadius.circular(25), color: AppColor.colorTextButton)) + ..paddingIcon(EdgeInsets.only(right: 8)) + ..iconColor(Colors.white) + ..maxWidth(140) + ..size(20) + ..radiusSplash(10) + ..padding(EdgeInsets.symmetric(vertical: 13)) + ..textStyle(TextStyle(fontSize: 15, color: Colors.white, fontWeight: FontWeight.w500)) + ..onPressActionClick(() => controller.mailboxDashBoardController.composeEmailAction()) + ..text(AppLocalizations.of(context).compose, isVertical: false)) + .build()) + ), + Obx(() { + if (controller.isSearchActive()) { + return controller.listMailboxSearched.isNotEmpty + ? Padding( + padding: EdgeInsets.only(top: 16), + child: _buildEditMailboxButton(context, controller.isSelectionEnabled())) + : SizedBox.shrink(); + } else { + return Padding( + padding: EdgeInsets.only(top: 16), + child: _buildEditMailboxButton(context, controller.isSelectionEnabled())); + } + }) + ]); + } + Widget _buildCloseScreenButton(BuildContext context) { - return Padding( - padding: EdgeInsets.only(left: 16, right: 16), - child: IconButton( - key: Key('mailbox_close_button'), - onPressed: () => controller.closeMailboxScreen(context), - icon: SvgPicture.asset(_imagePaths.icCloseMailbox, width: 30, height: 30, fit: BoxFit.fill))); + return buildIconWeb( + icon: SvgPicture.asset(_imagePaths.icCloseMailbox, width: 28, height: 28, fit: BoxFit.fill), + tooltip: AppLocalizations.of(context).close, + onTap: () => controller.closeMailboxScreen(context)); } Widget _buildAddNewFolderButton(BuildContext context) { - return Padding( - padding: EdgeInsets.only(right: 10), - child: IconButton( - key: Key('create_new_mailbox_button'), - onPressed: () => controller.goToCreateNewMailboxView(), - icon: SvgPicture.asset(_imagePaths.icAddNewFolder, width: 30, height: 30, fit: BoxFit.fill))); + return buildIconWeb( + icon: SvgPicture.asset(_imagePaths.icAddNewFolder, width: 28, height: 24, color: AppColor.colorTextButton, fit: BoxFit.fill), + tooltip: AppLocalizations.of(context).new_mailbox, + onTap: () => controller.goToCreateNewMailboxView()); } Widget _buildEditMailboxButton(BuildContext context, bool isSelectionEnabled) { @@ -184,7 +205,7 @@ class MailboxView extends GetWidget { child: TextButton( child: Text( !isSelectionEnabled ? AppLocalizations.of(context).edit : AppLocalizations.of(context).cancel, - style: TextStyle(fontSize: 17, color: AppColor.colorTextButton)), + style: TextStyle(fontSize: 17, color: AppColor.colorTextButton, fontWeight: FontWeight.normal)), onPressed: () => !isSelectionEnabled ? controller.enableSelectionMailbox() : controller.disableSelectionMailbox() @@ -192,20 +213,28 @@ class MailboxView extends GetWidget { ); } - Widget _buildUserInformationWidget(BuildContext context) { - return Padding( - padding: EdgeInsets.only(left: 16, top: 8.0, right: 16), - child: Obx(() => (UserInformationWidgetBuilder( - _imagePaths, - context, - controller.mailboxDashBoardController.userProfile.value) - ..addOnLogoutAction(() => controller.mailboxDashBoardController.logoutAction())) - .build())); + Widget _buildUserInformation(BuildContext context) { + return Container( + child: Column(children: [ + Padding( + padding: EdgeInsets.only( + left: _responsiveUtils.isMobile(context) && _responsiveUtils.isLandscape(context) ? 0 : 16, + right: 16), + child: (UserInformationWidgetBuilder(_imagePaths, context, controller.mailboxDashBoardController.userProfile.value) + ..addOnLogoutAction(() => controller.mailboxDashBoardController.logoutAction())) + .build()), + Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2) + ]), + ); } Widget _buildSearchBarWidget(BuildContext context) { return Padding( - padding: EdgeInsets.only(top: _responsiveUtils.isDesktop(context) ? 16 : 12, bottom: 16, left: 16, right: 16), + padding: EdgeInsets.only( + top: _responsiveUtils.isDesktop(context) ? 16 : 12, + bottom: 16, + left: _responsiveUtils.isMobile(context) && _responsiveUtils.isLandscape(context) ? 0 : 16, + right: 16), child: (SearchBarView(_imagePaths) ..hintTextSearch(AppLocalizations.of(context).hint_search_mailboxes) ..addOnOpenSearchViewAction(() => controller.enableSearch())) @@ -231,90 +260,80 @@ class MailboxView extends GetWidget { key: PageStorageKey('mailbox_list'), primary: false, shrinkWrap: true, - padding: EdgeInsets.zero, + padding: EdgeInsets.only(bottom: controller.isSelectionEnabled() ? 16 : 0), children: [ - Obx(() => (controller.isSelectionEnabled() && _responsiveUtils.isMobileDevice(context) && _responsiveUtils.isLandscape(context)) - || _responsiveUtils.isDesktop(context) ? SizedBox.shrink() : _buildUserInformationWidget(context)), - Obx(() => (controller.isSelectionEnabled() && _responsiveUtils.isMobileDevice(context) && _responsiveUtils.isLandscape(context)) - || _responsiveUtils.isDesktop(context) ? SizedBox.shrink() : _buildLineSpaceUserInformation()), + Obx(() { + if ((controller.isSelectionEnabled() + && _responsiveUtils.isMobile(context) + && _responsiveUtils.isLandscape(context)) + || _responsiveUtils.isDesktop(context)) { + return SizedBox.shrink(); + } + return _buildUserInformation(context); + }), if (!_responsiveUtils.isDesktop(context)) _buildSearchBarWidget(context), _buildLoadingView(), Obx(() => controller.defaultMailboxTree.value.root.childrenItems?.isNotEmpty ?? false - ? Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(14), - color: Colors.white), - margin: EdgeInsets.only(left: 16, right: 16, top: 4), - child: _buildDefaultMailbox(context)) + ? _buildMailboxCategory(context, MailboxCategories.exchange, controller.defaultMailboxTree.value.root) : SizedBox.shrink()), + SizedBox(height: 12), Obx(() => controller.folderMailboxTree.value.root.childrenItems?.isNotEmpty ?? false - ? Padding( - padding: EdgeInsets.only(left: 25, top: 26, bottom: 12), - child: Text( - AppLocalizations.of(context).folders, - maxLines: 1, - style: TextStyle(fontSize: 20, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600))) + ? _buildMailboxCategory(context, MailboxCategories.folders, controller.folderMailboxTree.value.root) : SizedBox.shrink()), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(14), - color: Colors.white), - margin: EdgeInsets.only(left: 16, right: 16, bottom: 30), - child: _buildFolderMailbox(context), - ), - Obx(() { - if (controller.mailboxDashBoardController.appInformation.value != null) { - return _buildVersionInformation(context, controller.mailboxDashBoardController.appInformation.value!); - } else { - return SizedBox.shrink(); - } - }), ] ); } - Widget _buildLineSpaceUserInformation() { + Widget _buildHeaderMailboxCategory(BuildContext context, MailboxCategories categories) { return Padding( - padding: EdgeInsets.only(top: 16), - child: Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2)); + padding: EdgeInsets.only( + left: _responsiveUtils.isMobile(context) && _responsiveUtils.isLandscape(context) ? 8 : 28, + right: 16), + child: Row(children: [ + Expanded(child: Text(categories.getTitle(context), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 20, color: Colors.black, fontWeight: FontWeight.bold))), + buildIconWeb( + icon: SvgPicture.asset( + categories.getExpandMode(controller.mailboxCategoriesExpandMode.value) == ExpandMode.EXPAND + ? _imagePaths.icExpandFolder + : _imagePaths.icCollapseFolder, + color: AppColor.primaryColor, fit: BoxFit.fill), + tooltip: AppLocalizations.of(context).collapse, + onTap: () => controller.toggleMailboxCategories(categories)) + ])); } - Widget _buildDefaultMailbox(BuildContext context) { - return Obx(() => controller.defaultMailboxTree.value.root.childrenItems?.isNotEmpty ?? false - ? Transform( - transform: Matrix4.translationValues(-4.0, 0.0, 0.0), - child: Padding( - padding: EdgeInsets.only(top: 10, bottom: 10), - child: TreeView( - startExpanded: false, - key: Key('default_mailbox_list'), - children: _buildListChildTileWidget(context, controller.defaultMailboxTree.value.root))) - ) - : SizedBox.shrink() - ); + Widget _buildBodyMailboxCategory(BuildContext context, MailboxCategories categories, MailboxNode mailboxNode) { + final lastNode = mailboxNode.childrenItems?.last; + + return Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(14), color: Colors.white), + margin: EdgeInsets.only( + left: _responsiveUtils.isMobile(context) && _responsiveUtils.isLandscape(context) ? 0 : 16, + right: 16), + padding: EdgeInsets.only(left: 12, right: 8), + child: TreeView( + key: Key('${categories.keyValue}_mailbox_list'), + children: _buildListChildTileWidget(context, mailboxNode, lastNode: lastNode))); } - Widget _buildFolderMailbox(BuildContext context) { - return Obx(() => controller.folderMailboxTree.value.root.childrenItems?.isNotEmpty ?? false - ? Transform( - transform: Matrix4.translationValues(-4.0, 0.0, 0.0), - child: Padding( - padding: EdgeInsets.only(top: 10, bottom: 10), - child: TreeView( - startExpanded: false, - key: Key('folder_mailbox_list'), - children: _buildListChildTileWidget(context, controller.folderMailboxTree.value.root))) - ) - : SizedBox.shrink() - ); + Widget _buildMailboxCategory(BuildContext context, MailboxCategories categories, MailboxNode mailboxNode) { + return Column(children: [ + _buildHeaderMailboxCategory(context, categories), + AnimatedContainer( + duration: Duration(milliseconds: 400), + child: categories.getExpandMode(controller.mailboxCategoriesExpandMode.value) == ExpandMode.EXPAND + ? _buildBodyMailboxCategory(context, categories, mailboxNode) + : Offstage()) + ]); } - List _buildListChildTileWidget(BuildContext context, MailboxNode parentNode) { + List _buildListChildTileWidget(BuildContext context, MailboxNode parentNode, {MailboxNode? lastNode}) { return parentNode.childrenItems ?.map((mailboxNode) => mailboxNode.hasChildren() - ? Padding( - padding: EdgeInsets.only(left: 16), - child: TreeViewChild( + ? TreeViewChild( context, key: Key('children_tree_mailbox_child'), isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND, @@ -322,25 +341,23 @@ class MailboxView extends GetWidget { context, _imagePaths, mailboxNode, + lastNode: lastNode, allSelectMode: controller.currentSelectMode.value) ..addOnOpenMailboxFolderClick((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) ..addOnExpandFolderActionClick((mailboxNode) => controller.toggleMailboxFolder(mailboxNode)) ..addOnSelectMailboxFolderClick((mailboxNode) => controller.selectMailboxNode(mailboxNode))) .build()), children: _buildListChildTileWidget(context, mailboxNode) - ).build()) - : Padding( - padding: EdgeInsets.only(left: 16), - child: Obx(() => (MailBoxFolderTileBuilder( + ).build() + : Obx(() => (MailBoxFolderTileBuilder( context, _imagePaths, mailboxNode, + lastNode: lastNode, allSelectMode: controller.currentSelectMode.value) ..addOnOpenMailboxFolderClick((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) ..addOnSelectMailboxFolderClick((mailboxNode) => controller.selectMailboxNode(mailboxNode))) - .build(), - ) - ) + .build()) ).toList() ?? []; } @@ -388,30 +405,31 @@ class MailboxView extends GetWidget { )); } - Widget _buildListMailboxSearched(BuildContext context, List listMailbox) { - return Container( + Widget _buildListMailboxSearched(BuildContext context) { + return Obx(() => Container( margin: _responsiveUtils.isDesktop(context) ? EdgeInsets.only(left: 16, right: 16) : EdgeInsets.zero, decoration: _responsiveUtils.isDesktop(context) - ? BoxDecoration(borderRadius: BorderRadius.circular(14), color: Colors.white) - : null, + ? BoxDecoration(borderRadius: BorderRadius.circular(14), color: Colors.white) + : null, child: ListView.builder( padding: EdgeInsets.only(left: 16, right: 8), key: Key('list_mailbox_searched'), - itemCount: listMailbox.length, + itemCount: controller.listMailboxSearched.length, shrinkWrap: true, primary: false, - itemBuilder: (context, index) => Obx(() => (MailboxTileBuilder( - _imagePaths, - listMailbox[index], - isSearchActive: controller.isSearchActive(), - allSelectMode: controller.currentSelectMode.value, - isLastElement: index == listMailbox.length - 1) - ..addOnOpenMailboxAction((mailbox) => controller.openMailbox(context, mailbox)) - ..addOnSelectMailboxActionClick((mailbox) => controller.selectMailbox(context, mailbox))) - .build())) - ); + itemBuilder: (context, index) => + Obx(() => (MailboxSearchTileBuilder( + _imagePaths, + controller.listMailboxSearched[index], + allSelectMode: controller.currentSelectMode.value, + lastMailbox: controller.listMailboxSearched.last) + ..addOnOpenMailboxAction((mailbox) => controller.openMailbox(context, mailbox)) + ..addOnSelectMailboxActionClick((mailbox) => controller.selectMailbox(context, mailbox))) + .build()) + ) + )); } Widget _buildOptionSelectionMailbox(BuildContext context) { @@ -430,25 +448,24 @@ class MailboxView extends GetWidget { } else { return Column(children: [ Divider(color: AppColor.lineItemListColor, height: 1, thickness: 0.2), - Padding( - padding: EdgeInsets.only(bottom: 30, top: 5), - child: (BottomBarSelectionMailboxWidget(context, _imagePaths, controller.listMailboxSelected) - ..addOnMailboxActionsClick((actions, listMailboxSelected) => controller.pressMailboxSelectionAction(context, actions, listMailboxSelected))) - .build() - ) + SafeArea( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: (BottomBarSelectionMailboxWidget(context, _imagePaths, controller.listMailboxSelected) + ..addOnMailboxActionsClick((actions, listMailboxSelected) => controller.pressMailboxSelectionAction(context, actions, listMailboxSelected))) + .build())) ]); } } Widget _buildVersionInformation(BuildContext context, PackageInfo packageInfo) { - return Container( + return SafeArea(child: Container( padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16), - margin: EdgeInsets.only(bottom: 30), child: Text( '${AppLocalizations.of(context).version} ${packageInfo.version}', textAlign: TextAlign.center, style: TextStyle(fontSize: 16, color: AppColor.colorContentEmail, fontWeight: FontWeight.w500), ), - ); + )); } } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/mailbox_view_web.dart b/lib/features/mailbox/presentation/mailbox_view_web.dart new file mode 100644 index 000000000..096396df1 --- /dev/null +++ b/lib/features/mailbox/presentation/mailbox_view_web.dart @@ -0,0 +1,453 @@ +import 'package:core/core.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:model/model.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/widgets/bottom_bar_selection_mailbox_widget.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/widgets/user_information_widget_builder.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 MailboxView extends GetWidget { + + final _imagePaths = Get.find(); + final _responsiveUtils = Get.find(); + + @override + Widget build(BuildContext context) { + return _buildBodyMailbox(context); + } + + Widget _buildBodyMailbox(BuildContext context) { + return SafeArea( + top: _responsiveUtils.isMobile(context) ? true : false, + bottom: false, + left: false, + right: false, + child: ClipRRect( + borderRadius: BorderRadius.only( + topRight: Radius.circular(_responsiveUtils.isMobile(context) ? 14 : 0), + topLeft: Radius.circular(_responsiveUtils.isMobile(context) ? 14 : 0)), + child: Drawer( + child: Scaffold( + backgroundColor: _responsiveUtils.isDesktop(context) ? AppColor.colorBgDesktop : Colors.white, + body: Column( + children: [ + if (_responsiveUtils.isDesktop(context)) + Container( + color: Colors.white, + padding: EdgeInsets.only(left: 20, top: 20, bottom: 24), + child: (SloganBuilder(arrangedByHorizontal: true) + ..setSloganText(AppLocalizations.of(context).app_name) + ..setSloganTextAlign(TextAlign.center) + ..setSloganTextStyle(TextStyle(color: Colors.black, fontSize: 25, fontWeight: FontWeight.bold)) + ..setSizeLogo(28) + ..setLogo(_imagePaths.icLogoTMail)) + .build()), + if (!_responsiveUtils.isDesktop(context)) _buildHeaderMailbox(context), + if (_responsiveUtils.isDesktop(context)) + Row(children: [ + Expanded(child: Container( + padding: EdgeInsets.only(top: 16, left: 20), + color: AppColor.colorBgDesktop, + alignment: Alignment.centerLeft, + child: (ButtonBuilder(_imagePaths.icCompose) + ..key(Key('button_compose_email')) + ..decoration(BoxDecoration(borderRadius: BorderRadius.circular(25), color: AppColor.colorTextButton)) + ..paddingIcon(EdgeInsets.only(right: 8)) + ..iconColor(Colors.white) + ..maxWidth(140) + ..size(20) + ..radiusSplash(10) + ..padding(EdgeInsets.symmetric(vertical: 13)) + ..textStyle(TextStyle(fontSize: 15, color: Colors.white, fontWeight: FontWeight.w500)) + ..onPressActionClick(() => controller.mailboxDashBoardController.composeEmailAction()) + ..text(AppLocalizations.of(context).compose, isVertical: false)) + .build()) + ), + Obx(() { + if (controller.isSearchActive()) { + return controller.listMailboxSearched.isNotEmpty + ? Padding( + padding: EdgeInsets.only(top: 16), + child: _buildEditMailboxButton(context, controller.isSelectionEnabled())) + : SizedBox.shrink(); + } else { + return Padding( + padding: EdgeInsets.only(top: 16), + child: _buildEditMailboxButton(context, controller.isSelectionEnabled())); + } + }) + ]), + Obx(() => !controller.isSearchActive() && _responsiveUtils.isDesktop(context) + ? Row(children: [ + Expanded(child: _buildSearchBarWidget(context)), + buildIconWeb( + icon: SvgPicture.asset(_imagePaths.icAddNewFolder, color: AppColor.colorTextButton, fit: BoxFit.fill), + tooltip: AppLocalizations.of(context).new_mailbox, + onTap: () => controller.goToCreateNewMailboxView()), + ]) + : SizedBox.shrink()), + Obx(() => controller.isSearchActive() ? _buildInputSearchFormWidget(context) : SizedBox.shrink()), + Expanded(child: Obx(() => Container( + color: _responsiveUtils.isDesktop(context) + ? Colors.transparent + : controller.isSearchActive() ? Colors.white : AppColor.colorBgMailbox, + child: RefreshIndicator( + color: AppColor.primaryColor, + onRefresh: () async => controller.refreshAllMailbox(), + child: controller.isSearchActive() + ? _buildListMailboxSearched(context, controller.listMailboxSearched) + : _buildListMailbox(context)), + ))), + Obx(() => controller.isSelectionEnabled() + ? _buildOptionSelectionMailbox(context) + : SizedBox.shrink()), + ] + ), + ) + ) + ) + ); + } + + Widget _buildHeaderMailbox(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + top: _responsiveUtils.isMobile(context) ? 14 : 30, + bottom: 10), + child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + !_responsiveUtils.isDesktop(context) && !_responsiveUtils.isTabletLarge(context) + ? _buildCloseScreenButton(context) + : SizedBox(width: 50), + Obx(() { + if (controller.isSearchActive()) { + return controller.listMailboxSearched.isNotEmpty + ? SizedBox(width: controller.isSelectionEnabled() ? 49 : 40) + : SizedBox.shrink(); + } else { + return SizedBox(width: controller.isSelectionEnabled() ? 49 : 40); + } + }), + Expanded(child: Text( + AppLocalizations.of(context).folders, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 20, color: AppColor.colorNameEmail, fontWeight: FontWeight.w700))), + Obx(() { + if (controller.isSearchActive()) { + return controller.listMailboxSearched.isNotEmpty + ? _buildEditMailboxButton(context, controller.isSelectionEnabled()) + : SizedBox(width: 25); + } else { + return _buildEditMailboxButton(context, controller.isSelectionEnabled()); + } + }), + _buildAddNewFolderButton(context), + ])), + Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2), + ] + ); + } + + Widget _buildCloseScreenButton(BuildContext context) { + return Padding( + padding: EdgeInsets.only(left: 16, right: 16), + child: IconButton( + key: Key('mailbox_close_button'), + onPressed: () => controller.closeMailboxScreen(context), + icon: SvgPicture.asset(_imagePaths.icCloseMailbox, width: 30, height: 30, fit: BoxFit.fill))); + } + + Widget _buildAddNewFolderButton(BuildContext context) { + return Padding( + padding: EdgeInsets.only(right: 10), + child: IconButton( + key: Key('create_new_mailbox_button'), + onPressed: () => controller.goToCreateNewMailboxView(), + icon: SvgPicture.asset(_imagePaths.icAddNewFolder, width: 30, height: 30, fit: BoxFit.fill))); + } + + Widget _buildEditMailboxButton(BuildContext context, bool isSelectionEnabled) { + return Material( + shape: CircleBorder(), + color: Colors.transparent, + child: TextButton( + child: Text( + !isSelectionEnabled ? AppLocalizations.of(context).edit : AppLocalizations.of(context).cancel, + style: TextStyle(fontSize: 17, color: AppColor.colorTextButton)), + onPressed: () => !isSelectionEnabled + ? controller.enableSelectionMailbox() + : controller.disableSelectionMailbox() + ) + ); + } + + Widget _buildUserInformationWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.only(left: 16, top: 8.0, right: 16), + child: Obx(() => (UserInformationWidgetBuilder( + _imagePaths, + context, + controller.mailboxDashBoardController.userProfile.value) + ..addOnLogoutAction(() => controller.mailboxDashBoardController.logoutAction())) + .build())); + } + + Widget _buildSearchBarWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.only(top: _responsiveUtils.isDesktop(context) ? 16 : 12, bottom: 16, left: 16, right: 16), + child: (SearchBarView(_imagePaths) + ..hintTextSearch(AppLocalizations.of(context).hint_search_mailboxes) + ..addOnOpenSearchViewAction(() => controller.enableSearch())) + .build()); + } + + Widget _buildLoadingView() { + return Obx(() => controller.viewState.value.fold( + (failure) => SizedBox.shrink(), + (success) => success is LoadingState + ? Center(child: Padding( + padding: EdgeInsets.only(top: 16), + child: SizedBox( + width: 24, + height: 24, + child: CupertinoActivityIndicator(color: AppColor.colorTextButton)))) + : SizedBox.shrink())); + } + + Widget _buildListMailbox(BuildContext context) { + return ListView( + controller: controller.mailboxListScrollController, + key: PageStorageKey('mailbox_list'), + primary: false, + shrinkWrap: true, + padding: EdgeInsets.zero, + children: [ + Obx(() => (controller.isSelectionEnabled() && _responsiveUtils.isMobileDevice(context) && _responsiveUtils.isLandscape(context)) + || _responsiveUtils.isDesktop(context) ? SizedBox.shrink() : _buildUserInformationWidget(context)), + Obx(() => (controller.isSelectionEnabled() && _responsiveUtils.isMobileDevice(context) && _responsiveUtils.isLandscape(context)) + || _responsiveUtils.isDesktop(context) ? SizedBox.shrink() : _buildLineSpaceUserInformation()), + if (!_responsiveUtils.isDesktop(context)) _buildSearchBarWidget(context), + _buildLoadingView(), + Obx(() => controller.defaultMailboxTree.value.root.childrenItems?.isNotEmpty ?? false + ? Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + color: Colors.white), + margin: EdgeInsets.only(left: 16, right: 16, top: 4), + child: _buildDefaultMailbox(context)) + : SizedBox.shrink()), + Obx(() => controller.folderMailboxTree.value.root.childrenItems?.isNotEmpty ?? false + ? Padding( + padding: EdgeInsets.only(left: 25, top: 26, bottom: 12), + child: Text( + AppLocalizations.of(context).folders, + maxLines: 1, + style: TextStyle(fontSize: 20, color: AppColor.colorNameEmail, fontWeight: FontWeight.w600))) + : SizedBox.shrink()), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + color: Colors.white), + margin: EdgeInsets.only(left: 16, right: 16, bottom: 30), + child: _buildFolderMailbox(context), + ), + Obx(() { + if (controller.mailboxDashBoardController.appInformation.value != null) { + return _buildVersionInformation(context, controller.mailboxDashBoardController.appInformation.value!); + } else { + return SizedBox.shrink(); + } + }), + ] + ); + } + + Widget _buildLineSpaceUserInformation() { + return Padding( + padding: EdgeInsets.only(top: 16), + child: Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2)); + } + + Widget _buildDefaultMailbox(BuildContext context) { + return Obx(() => controller.defaultMailboxTree.value.root.childrenItems?.isNotEmpty ?? false + ? Transform( + transform: Matrix4.translationValues(-4.0, 0.0, 0.0), + child: Padding( + padding: EdgeInsets.only(top: 10, bottom: 10), + child: TreeView( + startExpanded: false, + key: Key('default_mailbox_list'), + children: _buildListChildTileWidget(context, controller.defaultMailboxTree.value.root))) + ) + : SizedBox.shrink() + ); + } + + Widget _buildFolderMailbox(BuildContext context) { + return Obx(() => controller.folderMailboxTree.value.root.childrenItems?.isNotEmpty ?? false + ? Transform( + transform: Matrix4.translationValues(-4.0, 0.0, 0.0), + child: Padding( + padding: EdgeInsets.only(top: 10, bottom: 10), + child: TreeView( + startExpanded: false, + key: Key('folder_mailbox_list'), + children: _buildListChildTileWidget(context, controller.folderMailboxTree.value.root))) + ) + : SizedBox.shrink() + ); + } + + List _buildListChildTileWidget(BuildContext context, MailboxNode parentNode) { + return parentNode.childrenItems + ?.map((mailboxNode) => mailboxNode.hasChildren() + ? Padding( + padding: EdgeInsets.only(left: 16), + child: TreeViewChild( + context, + key: Key('children_tree_mailbox_child'), + isExpanded: mailboxNode.expandMode == ExpandMode.EXPAND, + parent: Obx(() => (MailBoxFolderTileBuilder( + context, + _imagePaths, + mailboxNode, + allSelectMode: controller.currentSelectMode.value) + ..addOnOpenMailboxFolderClick((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) + ..addOnExpandFolderActionClick((mailboxNode) => controller.toggleMailboxFolder(mailboxNode)) + ..addOnSelectMailboxFolderClick((mailboxNode) => controller.selectMailboxNode(mailboxNode))) + .build()), + children: _buildListChildTileWidget(context, mailboxNode) + ).build()) + : Padding( + padding: EdgeInsets.only(left: 16), + child: Obx(() => (MailBoxFolderTileBuilder( + context, + _imagePaths, + mailboxNode, + allSelectMode: controller.currentSelectMode.value) + ..addOnOpenMailboxFolderClick((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) + ..addOnSelectMailboxFolderClick((mailboxNode) => controller.selectMailboxNode(mailboxNode))) + .build(), + ) + ) + ).toList() ?? []; + } + + Widget _buildInputSearchFormWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.only(top: 16, bottom: 16), + child: Row( + children: [ + _buildBackSearchButton(context), + Expanded(child: (SearchAppBarWidget( + context, + _imagePaths, + _responsiveUtils, + controller.searchQuery.value, + controller.searchFocus, + controller.searchInputController, + hasBackButton: false, + hasSearchButton: true) + ..addPadding(EdgeInsets.zero) + ..setMargin(EdgeInsets.only(right: 16)) + ..addDecoration(BoxDecoration(borderRadius: BorderRadius.circular(12), color: AppColor.colorBgSearchBar)) + ..addIconClearText(SvgPicture.asset(_imagePaths.icClearTextSearch, width: 20, height: 20, fit: BoxFit.fill)) + ..setHintText(AppLocalizations.of(context).hint_search_mailboxes) + ..addOnClearTextSearchAction(() => controller.clearSearchText()) + ..addOnTextChangeSearchAction((query) => controller.searchMailbox(query)) + ..addOnSearchTextAction((query) => controller.searchMailbox(query))) + .build()) + ] + ) + ); + } + + Widget _buildBackSearchButton(BuildContext context) { + return Padding( + padding: EdgeInsets.only(left: 5), + child: Material( + shape: CircleBorder(), + color: Colors.transparent, + child: IconButton( + splashRadius: 20, + color: AppColor.colorTextButton, + icon: SvgPicture.asset(_imagePaths.icBack, width: 20, height: 20, color: AppColor.colorTextButton, fit: BoxFit.fill), + onPressed: () => controller.disableSearch(context) + ) + )); + } + + Widget _buildListMailboxSearched(BuildContext context, List listMailbox) { + return Container( + margin: _responsiveUtils.isDesktop(context) + ? EdgeInsets.only(left: 16, right: 16) + : EdgeInsets.zero, + decoration: _responsiveUtils.isDesktop(context) + ? BoxDecoration(borderRadius: BorderRadius.circular(14), color: Colors.white) + : null, + child: ListView.builder( + padding: EdgeInsets.only(left: 16, right: 8), + key: Key('list_mailbox_searched'), + itemCount: listMailbox.length, + shrinkWrap: true, + primary: false, + itemBuilder: (context, index) => Obx(() => (MailboxSearchTileBuilder( + _imagePaths, + listMailbox[index], + allSelectMode: controller.currentSelectMode.value, + lastMailbox: controller.listMailboxSearched.last) + ..addOnOpenMailboxAction((mailbox) => controller.openMailbox(context, mailbox)) + ..addOnSelectMailboxActionClick((mailbox) => controller.selectMailbox(context, mailbox))) + .build())) + ); + } + + Widget _buildOptionSelectionMailbox(BuildContext context) { + if (_responsiveUtils.isDesktop(context)) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + boxShadow: [BoxShadow(color: AppColor.colorEmailAddressTag, spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5))], + color: Colors.white), + margin: EdgeInsets.only(left: 10, bottom: 10, right: 10), + padding: EdgeInsets.all(8), + child: (BottomBarSelectionMailboxWidget(context, _imagePaths, controller.listMailboxSelected) + ..addOnMailboxActionsClick((actions, listMailboxSelected) => controller.pressMailboxSelectionAction(context, actions, listMailboxSelected))) + .build(), + ); + } else { + return Column(children: [ + Divider(color: AppColor.lineItemListColor, height: 1, thickness: 0.2), + Padding( + padding: EdgeInsets.only(bottom: 30, top: 5), + child: (BottomBarSelectionMailboxWidget(context, _imagePaths, controller.listMailboxSelected) + ..addOnMailboxActionsClick((actions, listMailboxSelected) => controller.pressMailboxSelectionAction(context, actions, listMailboxSelected))) + .build() + ) + ]); + } + } + + Widget _buildVersionInformation(BuildContext context, PackageInfo packageInfo) { + return Container( + padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16), + margin: EdgeInsets.only(bottom: 30), + child: Text( + '${AppLocalizations.of(context).version} ${packageInfo.version}', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 16, color: AppColor.colorContentEmail, fontWeight: FontWeight.w500), + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/mailbox/presentation/model/mailbox_categories.dart b/lib/features/mailbox/presentation/model/mailbox_categories.dart new file mode 100644 index 000000000..a7a81cf69 --- /dev/null +++ b/lib/features/mailbox/presentation/model/mailbox_categories.dart @@ -0,0 +1,40 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:model/mailbox/expand_mode.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +enum MailboxCategories { + exchange, + folders, +} + +extension MailboxCategoriessExtension on MailboxCategories { + + String get keyValue { + switch(this) { + case MailboxCategories.exchange: + return 'exchange'; + case MailboxCategories.folders: + return 'folders'; + } + } + + String getTitle(BuildContext context) { + switch(this) { + case MailboxCategories.exchange: + return AppLocalizations.of(context).exchange; + case MailboxCategories.folders: + return AppLocalizations.of(context).folders; + } + } + + ExpandMode getExpandMode(MailboxCategoriesExpandMode categoriesExpandMode) { + switch(this) { + case MailboxCategories.exchange: + return categoriesExpandMode.defaultMailbox; + case MailboxCategories.folders: + return categoriesExpandMode.folderMailbox; + } + } +} \ No newline at end of file diff --git a/lib/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart b/lib/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart new file mode 100644 index 000000000..b38c013b1 --- /dev/null +++ b/lib/features/mailbox/presentation/model/mailbox_categories_expand_mode.dart @@ -0,0 +1,17 @@ + +import 'package:equatable/equatable.dart'; +import 'package:model/mailbox/expand_mode.dart'; + +class MailboxCategoriesExpandMode with EquatableMixin { + ExpandMode defaultMailbox; + ExpandMode folderMailbox; + + MailboxCategoriesExpandMode({required this.defaultMailbox, required this.folderMailbox}); + + factory MailboxCategoriesExpandMode.initial() { + return MailboxCategoriesExpandMode(defaultMailbox: ExpandMode.EXPAND, folderMailbox: ExpandMode.EXPAND); + } + + @override + List get props => [defaultMailbox, folderMailbox]; +} \ No newline at end of file diff --git a/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart b/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart index 6e453a396..c98c4e670 100644 --- a/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart +++ b/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart @@ -18,6 +18,7 @@ class MailBoxFolderTileBuilder { final ImagePaths _imagePaths; final SelectMode allSelectMode; final MailboxDisplayed mailboxDisplayed; + final MailboxNode? lastNode; OnExpandFolderActionClick? _onExpandFolderActionClick; OnOpenMailboxFolderClick? _onOpenMailboxFolderClick; @@ -30,6 +31,7 @@ class MailBoxFolderTileBuilder { { this.allSelectMode = SelectMode.INACTIVE, this.mailboxDisplayed = MailboxDisplayed.mailbox, + this.lastNode, } ); @@ -52,7 +54,6 @@ class MailBoxFolderTileBuilder { highlightColor: Colors.transparent), child: Container( key: Key('mailbox_folder_tile'), - alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(0), color: Colors.white @@ -70,21 +71,26 @@ class MailBoxFolderTileBuilder { : _buildMailboxIcon(), title: _buildTitleFolderItem(), trailing: _mailboxNode.hasChildren() - ? Padding( - padding: EdgeInsets.only(right: 0, left: 16), + ? Transform( + transform: Matrix4.translationValues(8.0, 0.0, 0.0), child: buildIconWeb( icon: SvgPicture.asset( - _mailboxNode.expandMode == ExpandMode.EXPAND ? _imagePaths.icExpandFolder : _imagePaths.icFolderArrow, - color: AppColor.colorArrowUserMailbox, + _mailboxNode.expandMode == ExpandMode.EXPAND ? _imagePaths.icExpandFolder : _imagePaths.icCollapseFolder, + color: _mailboxNode.expandMode == ExpandMode.EXPAND ? AppColor.colorExpandMailbox : AppColor.colorCollapseMailbox, fit: BoxFit.fill), splashRadius: 15, tooltip: _mailboxNode.expandMode == ExpandMode.EXPAND ? AppLocalizations.of(_context).collapse : AppLocalizations.of(_context).expand, onTap: () => _onExpandFolderActionClick?.call(_mailboxNode))) - : null + : _mailboxNode.item.getCountUnReadEmails().isNotEmpty + && mailboxDisplayed == MailboxDisplayed.mailbox + && !_mailboxNode.hasChildren() + ? Padding(padding: EdgeInsets.only(right: 12), child: _buildCounter()) + : SizedBox.shrink() ), - Padding( - padding: EdgeInsets.only(left: allSelectMode == SelectMode.ACTIVE ? 50 : 45), - child: Divider(color: AppColor.lineItemListColor, height: 0.5, thickness: 0.2)), + if (lastNode?.item.id != _mailboxNode.item.id) + Padding( + padding: EdgeInsets.only(left: allSelectMode == SelectMode.ACTIVE ? 50 : 35), + child: Divider(color: AppColor.lineItemListColor, height: 0.5, thickness: 0.2)), ]) ) ) @@ -96,70 +102,48 @@ class MailBoxFolderTileBuilder { children: [ if (allSelectMode == SelectMode.ACTIVE) Transform( - transform: Matrix4.translationValues(-16.0, 0.0, 0.0), + transform: Matrix4.translationValues(-24.0, 0.0, 0.0), child: _buildMailboxIcon()), Expanded(child: Transform( - transform: Matrix4.translationValues(-10.0, 0.0, 0.0), + transform: Matrix4.translationValues(allSelectMode == SelectMode.ACTIVE ? -16.0 : -20.0, 0.0, 0.0), child: Text( '${_mailboxNode.item.name?.name ?? ''}', maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 15, - color: AppColor.colorNameEmail), + style: TextStyle(fontSize: 15, color: AppColor.colorNameEmail, fontWeight: FontWeight.normal), ))), - if (_mailboxNode.item.getCountUnReadEmails().isNotEmpty && mailboxDisplayed == MailboxDisplayed.mailbox) - !_mailboxNode.hasChildren() - ? _buildCounter() - : Transform( - transform: Matrix4.translationValues(40.0, 0.0, 0.0), - child: _buildCounter()) + if (_mailboxNode.item.getCountUnReadEmails().isNotEmpty && mailboxDisplayed == MailboxDisplayed.mailbox && _mailboxNode.hasChildren()) + Transform(transform: Matrix4.translationValues(30.0, 0.0, 0.0), child: _buildCounter()) ], ); } Widget _buildCounter() { - return Container( - margin: EdgeInsets.only(left: 8, right: _mailboxNode.hasChildren() ? 0 : 16), - padding: EdgeInsets.only(left: 8, right: 8, top: 2.5, bottom: 2.5), - decoration:BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: AppColor.backgroundCounterMailboxColor), - child: Text( - '${_mailboxNode.item.getCountUnReadEmails()} ${AppLocalizations.of(_context).unread_email_notification}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle(fontSize: 12, color: AppColor.colorNameEmail), - )); + return Text( + '${_mailboxNode.item.getCountUnReadEmails()}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 13, color: Colors.black, fontWeight: FontWeight.normal), + ); } Widget _buildMailboxIcon() { - return Padding( - padding: EdgeInsets.only( - left: allSelectMode == SelectMode.ACTIVE ? 0 : 8, - right: allSelectMode == SelectMode.ACTIVE ? 8 : 0), - child: SvgPicture.asset( - '${_mailboxNode.item.getMailboxIcon(_imagePaths)}', - width: 28, - height: 28, - fit: BoxFit.fill - ) + return SvgPicture.asset( + '${_mailboxNode.item.getMailboxIcon(_imagePaths)}', + width: 28, + height: 28, + fit: BoxFit.fill ); } Widget _buildSelectModeIcon() { - return Material( - borderRadius: BorderRadius.circular(10), - color: Colors.transparent, - child: IconButton( - padding: EdgeInsets.zero, + return Transform( + transform: Matrix4.translationValues(-10.0, 0.0, 0.0), + child: buildIconWeb( icon: SvgPicture.asset( _mailboxNode.selectMode == SelectMode.ACTIVE ? _imagePaths.icSelected : _imagePaths.icUnSelected, - width: 20, - height: 20, fit: BoxFit.fill), - onPressed: () => _onSelectMailboxFolderClick?.call(_mailboxNode) - ) - ); + splashRadius: 15, + onTap: () => _onSelectMailboxFolderClick?.call(_mailboxNode))); } } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/widgets/mailbox_tile_builder.dart b/lib/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart similarity index 52% rename from lib/features/mailbox/presentation/widgets/mailbox_tile_builder.dart rename to lib/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart index 0aef323cc..95a2857b6 100644 --- a/lib/features/mailbox/presentation/widgets/mailbox_tile_builder.dart +++ b/lib/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart @@ -3,31 +3,26 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/mailbox/domain/extensions/presentation_mailbox_extension.dart'; -import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_displayed.dart'; typedef OnOpenMailboxActionClick = void Function(PresentationMailbox); typedef OnSelectMailboxActionClick = void Function(PresentationMailbox); -class MailboxTileBuilder { +class MailboxSearchTileBuilder { final PresentationMailbox _presentationMailbox; + final PresentationMailbox? lastMailbox; final SelectMode allSelectMode; final ImagePaths _imagePaths; - final MailboxDisplayed mailboxDisplayed; - final bool isLastElement; - final bool isSearchActive; OnOpenMailboxActionClick? _onOpenMailboxActionClick; OnSelectMailboxActionClick? _onSelectMailboxActionClick; - MailboxTileBuilder( + MailboxSearchTileBuilder( this._imagePaths, this._presentationMailbox, { this.allSelectMode = SelectMode.INACTIVE, - this.mailboxDisplayed = MailboxDisplayed.mailbox, - this.isLastElement = false, - this.isSearchActive = false, + this.lastMailbox, } ); @@ -62,30 +57,23 @@ class MailboxTileBuilder { leading: allSelectMode == SelectMode.ACTIVE ? _buildSelectModeIcon() : _buildMailboxIcon(), - title: Transform( - transform: Matrix4.translationValues(-10.0, 0.0, 0.0), - child: Row(children: [ + title: Row(children: [ if (allSelectMode == SelectMode.ACTIVE) Transform( - transform: Matrix4.translationValues(-10.0, 0.0, 0.0), + transform: Matrix4.translationValues(-24.0, 0.0, 0.0), child: _buildMailboxIcon()), - Expanded(child: Text( - '${_presentationMailbox.name?.name ?? ''}', - maxLines: 1, - overflow:TextOverflow.ellipsis, - style: TextStyle(fontSize: isSearchActive ? 17 : 15, color: AppColor.colorNameEmail), - )), - if (mailboxDisplayed == MailboxDisplayed.mailbox && !isSearchActive) - Transform( - transform: Matrix4.translationValues(40.0, 0.0, 0.0), - child: Text( - '${_presentationMailbox.getCountUnReadEmails()}', - maxLines: 1, - style: TextStyle(fontSize: 13, color: AppColor.colorNameEmail))) - ])), - subtitle: isSearchActive && _presentationMailbox.mailboxPath?.isNotEmpty == true + Expanded(child: Transform( + transform: Matrix4.translationValues(allSelectMode == SelectMode.ACTIVE ? -16.0 : -20.0, 0.0, 0.0), + child: Text( + '${_presentationMailbox.name?.name ?? ''}', + maxLines: 1, + overflow:TextOverflow.ellipsis, + style: TextStyle(fontSize: 17, color: AppColor.colorNameEmail, fontWeight: FontWeight.normal), + ))), + ]), + subtitle: _presentationMailbox.mailboxPath?.isNotEmpty == true ? Transform( - transform: Matrix4.translationValues(-10.0, 0.0, 0.0), + transform: Matrix4.translationValues(allSelectMode == SelectMode.ACTIVE ? 12.0 : -20.0, 0.0, 0.0), child: Text( _presentationMailbox.mailboxPath ?? '', maxLines: 1, @@ -94,18 +82,8 @@ class MailboxTileBuilder { ), ) : null, - trailing: (mailboxDisplayed == MailboxDisplayed.mailbox && !isSearchActive) - ? Transform( - transform: Matrix4.translationValues(8.0, 0.0, 0.0), - child: IconButton( - color: AppColor.primaryColor, - icon: SvgPicture.asset(_imagePaths.icFolderArrow, color: AppColor.colorArrowUserMailbox, fit: BoxFit.fill), - onPressed: () => _onOpenMailboxActionClick?.call(_presentationMailbox) - ) - ) - : null ), - if (!isLastElement) + if (lastMailbox?.id != _presentationMailbox.id) Padding( padding: EdgeInsets.only(left: allSelectMode == SelectMode.ACTIVE ? 50 : 45), child: Divider(color: AppColor.lineItemListColor, height: 0.5, thickness: 0.2)), @@ -116,32 +94,22 @@ class MailboxTileBuilder { } Widget _buildMailboxIcon() { - return Padding( - padding: EdgeInsets.only( - left: allSelectMode == SelectMode.ACTIVE ? 4 : 8, - right: allSelectMode == SelectMode.ACTIVE ? 4 : 0), - child: SvgPicture.asset( - '${_presentationMailbox.getMailboxIcon(_imagePaths)}', - width: 28, - height: 28, - fit: BoxFit.fill - ) + return SvgPicture.asset( + '${_presentationMailbox.getMailboxIcon(_imagePaths)}', + width: 28, + height: 28, + fit: BoxFit.fill ); } Widget _buildSelectModeIcon() { - return Material( - borderRadius: BorderRadius.circular(10), - color: Colors.transparent, - child: IconButton( - padding: EdgeInsets.zero, + return Transform( + transform: Matrix4.translationValues(-10.0, 0.0, 0.0), + child: buildIconWeb( icon: SvgPicture.asset( _presentationMailbox.selectMode == SelectMode.ACTIVE ? _imagePaths.icSelected : _imagePaths.icUnSelected, - width: 20, - height: 20, fit: BoxFit.fill), - onPressed: () => _onSelectMailboxActionClick?.call(_presentationMailbox) - ) - ); + splashRadius: 15, + onTap: () => _onSelectMailboxActionClick?.call(_presentationMailbox))); } } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/widgets/user_information_widget_builder.dart b/lib/features/mailbox/presentation/widgets/user_information_widget_builder.dart index a9abeca44..d39a104fd 100644 --- a/lib/features/mailbox/presentation/widgets/user_information_widget_builder.dart +++ b/lib/features/mailbox/presentation/widgets/user_information_widget_builder.dart @@ -75,7 +75,7 @@ class UserInformationWidgetBuilder { Transform( transform: Matrix4.translationValues(14.0, 0.0, 0.0), child: IconButton( - icon: SvgPicture.asset(_imagePaths.icNextArrow, width: 7, height: 12, fit: BoxFit.fill, color: AppColor.colorArrowUserMailbox), + icon: SvgPicture.asset(_imagePaths.icCollapseFolder, fit: BoxFit.fill, color: AppColor.colorCollapseMailbox), onPressed: () => {})) ]), ); diff --git a/lib/features/mailbox_creator/presentation/mailbox_creator_view.dart b/lib/features/mailbox_creator/presentation/mailbox_creator_view.dart index 40cbb853e..49ae2d6f7 100644 --- a/lib/features/mailbox_creator/presentation/mailbox_creator_view.dart +++ b/lib/features/mailbox_creator/presentation/mailbox_creator_view.dart @@ -168,7 +168,7 @@ class MailboxCreatorView extends GetWidget { transform: Matrix4.translationValues(4.0, 0.0, 0.0), child: IconButton( color: AppColor.primaryColor, - icon: SvgPicture.asset(_imagePaths.icFolderArrow, color: AppColor.colorArrowUserMailbox, fit: BoxFit.fill), + icon: SvgPicture.asset(_imagePaths.icCollapseFolder, color: AppColor.colorCollapseMailbox, fit: BoxFit.fill), onPressed: () => controller.selectMailboxLocation(context) )) ), diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart index 0f4175c6d..2c0d46273 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart @@ -2,8 +2,7 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/mixin/network_connection_mixin.dart'; -import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart' - if (dart.library.html) 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; +import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart'; import 'package:tmail_ui_user/features/email/presentation/email_view.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart'; @@ -23,9 +22,10 @@ class MailboxDashBoardView extends GetWidget with Ne key: controller.scaffoldKey, drawer: ResponsiveWidget( responsiveUtils: _responsiveUtils, - mobile: Container(child: MailboxView(), - width: _responsiveUtils.isPortrait(context) ? _responsiveUtils.getSizeScreenWidth(context) : _responsiveUtils.getSizeScreenWidth(context) / 2), - tablet: Container(child: MailboxView(), width: _responsiveUtils.getSizeScreenWidth(context) / 2), + mobile: _responsiveUtils.isPortrait(context) + ? SizedBox(child: MailboxView(), width: double.infinity) + : SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthMobileTablet), + tablet: SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthMobileTablet), tabletLarge: SizedBox.shrink(), desktop: SizedBox.shrink() ), @@ -33,8 +33,8 @@ class MailboxDashBoardView extends GetWidget with Ne body: Stack(children: [ ResponsiveWidget( responsiveUtils: _responsiveUtils, - desktop: _buildDesktopView(context), - tabletLarge: _buildTabletLargeView(context), + desktop: _buildLargeScreenView(context), + tabletLarge: _buildLargeScreenView(context), tablet: ThreadView(), mobile: ThreadView() ), @@ -84,8 +84,8 @@ class MailboxDashBoardView extends GetWidget with Ne } } - Widget _buildDesktopView(BuildContext context) { - if (controller.isDrawerOpen && _responsiveUtils.isDesktop(context)) { + Widget _buildLargeScreenView(BuildContext context) { + if (controller.isDrawerOpen && (_responsiveUtils.isDesktop(context) || _responsiveUtils.isTabletLarge(context))) { WidgetsBinding.instance?.addPostFrameCallback((_) { controller.closeDrawer(); }); @@ -95,26 +95,8 @@ class MailboxDashBoardView extends GetWidget with Ne child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded(flex: 1, child: MailboxView()), - Expanded(flex: 3, child: _buildThreadAndEmailContainer(context)), - ], - ), - ); - } - - Widget _buildTabletLargeView(BuildContext context) { - if (controller.isDrawerOpen && _responsiveUtils.isTabletLarge(context)) { - WidgetsBinding.instance?.addPostFrameCallback((_) { - controller.closeDrawer(); - }); - } - - return Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded(flex: 2, child: MailboxView()), - Expanded(flex: 4, child: _buildThreadAndEmailContainer(context)), + SizedBox(child: MailboxView(), width: _responsiveUtils.defaultSizeDrawerWidthMobileTablet), + Expanded(child: _buildThreadAndEmailContainer(context)) ], ), ); diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart new file mode 100644 index 000000000..b14ef95a6 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -0,0 +1,121 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/mixin/network_connection_mixin.dart'; +import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; +import 'package:tmail_ui_user/features/email/presentation/email_view.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view_web.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart'; +import 'package:tmail_ui_user/features/setting/presentation/model/app_setting.dart'; +import 'package:tmail_ui_user/features/setting/presentation/model/reading_pane.dart'; +import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart'; +import 'package:tmail_ui_user/main/routes/app_routes.dart'; + +class MailboxDashBoardView extends GetWidget with NetworkConnectionMixin { + + final _responsiveUtils = Get.find(); + + @override + Widget build(BuildContext context) { + return Scaffold( + key: controller.scaffoldKey, + drawer: ResponsiveWidget( + responsiveUtils: _responsiveUtils, + mobile: Container(child: MailboxView(), + width: _responsiveUtils.isPortrait(context) ? _responsiveUtils.getSizeScreenWidth(context) : _responsiveUtils.getSizeScreenWidth(context) / 2), + tablet: Container(child: MailboxView(), width: _responsiveUtils.getSizeScreenWidth(context) / 2), + tabletLarge: SizedBox.shrink(), + desktop: SizedBox.shrink() + ), + drawerEnableOpenDragGesture: !_responsiveUtils.isDesktop(context), + body: Stack(children: [ + ResponsiveWidget( + responsiveUtils: _responsiveUtils, + desktop: _buildDesktopView(context), + tabletLarge: _buildTabletLargeView(context), + tablet: ThreadView(), + mobile: ThreadView() + ), + Obx(() => controller.dashBoardAction == DashBoardAction.compose + ? ComposerView() + : SizedBox.shrink()), + Obx(() => controller.isNetworkConnectionAvailable() + ? SizedBox.shrink() + : Align(alignment: Alignment.bottomCenter, child: buildNetworkConnectionWidget(context))), + ]), + ); + } + + Widget _buildThreadAndEmailContainer(BuildContext context) { + switch(AppSetting.readingPane) { + case ReadingPane.noSplit: + return Obx(() { + switch(controller.routePath.value) { + case AppRoutes.THREAD: + return ThreadView(); + case AppRoutes.EMAIL: + return EmailView(); + default: + return SizedBox.shrink(); + } + }); + case ReadingPane.rightOfInbox: + if (_responsiveUtils.isDesktop(context)) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(flex: 1, child: ThreadView()), + Expanded(flex: 2, child: EmailView()), + ], + ); + } else { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(flex: 1, child: ThreadView()), + Expanded(flex: 1, child: EmailView()), + ], + ); + } + default: + return SizedBox.shrink(); + } + } + + Widget _buildDesktopView(BuildContext context) { + if (controller.isDrawerOpen && _responsiveUtils.isDesktop(context)) { + WidgetsBinding.instance?.addPostFrameCallback((_) { + controller.closeDrawer(); + }); + } + + return Container( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(flex: 1, child: MailboxView()), + Expanded(flex: 3, child: _buildThreadAndEmailContainer(context)), + ], + ), + ); + } + + Widget _buildTabletLargeView(BuildContext context) { + if (controller.isDrawerOpen && _responsiveUtils.isTabletLarge(context)) { + WidgetsBinding.instance?.addPostFrameCallback((_) { + controller.closeDrawer(); + }); + } + + return Container( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(flex: 2, child: MailboxView()), + Expanded(flex: 4, child: _buildThreadAndEmailContainer(context)), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index dfa179368..d6962c0b3 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -1,5 +1,6 @@ import 'package:core/core.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; @@ -30,48 +31,61 @@ class ThreadView extends GetWidget with UserSettingPopupMenuMi child: Scaffold( resizeToAvoidBottomInset: false, backgroundColor: _responsiveUtils.isDesktop(context) ? AppColor.colorBgDesktop : Colors.white, - body: SafeArea( - right: _responsiveUtils.isMobileDevice(context) && _responsiveUtils.isLandscape(context), - left: _responsiveUtils.isMobileDevice(context) && _responsiveUtils.isLandscape(context), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (_responsiveUtils.isDesktop(context)) - Container( - color: Colors.white, - padding: EdgeInsets.only(right: 10, top: 16, bottom: 10), - child: _buildHeader(context)), - _buildSearchInputFormForMobile(context), - _buildSearchButtonViewForMobile(context), - Obx(() => controller.isMailboxTrash && controller.emailList.isNotEmpty && !controller.isSearchActive() - ? _buildEmptyTrashButton(context) - : SizedBox.shrink()), - Expanded(child: Container( - color: AppColor.colorBgDesktop, - margin: _responsiveUtils.isDesktop(context) ? EdgeInsets.all(16) : EdgeInsets.zero, - 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(), - ] - ) - ), - _buildSuggestionBox(context) - ]))), - _buildListButtonSelectionForMobile(context), - ] - ) - ), + body: Row(children: [ + if (!kIsWeb && !_responsiveUtils.isMobile(context)) + VerticalDivider(color: AppColor.lineItemListColor, width: 1, thickness: 0.2), + Expanded(child: SafeArea( + right: _responsiveUtils.isMobile(context) && _responsiveUtils.isLandscape(context), + left: _responsiveUtils.isMobile(context) && _responsiveUtils.isLandscape(context), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_responsiveUtils.isDesktop(context)) + Container( + color: Colors.white, + padding: EdgeInsets.only(right: 10, top: 16, bottom: 10, left: 32), + child: _buildHeader(context)), + Padding( + padding: EdgeInsets.only( + left: kIsWeb && (_responsiveUtils.isDesktop(context) || _responsiveUtils.isTabletLarge(context)) ? 32 : 0), + child: _buildSearchInputFormForMobile(context)), + Container( + color: kIsWeb ? AppColor.colorBgDesktop : Colors.white, + padding: EdgeInsets.only( + left: kIsWeb && (_responsiveUtils.isDesktop(context) || _responsiveUtils.isTabletLarge(context)) ? 32 : 0), + child: _buildSearchButtonViewForMobile(context)), + Obx(() => controller.isMailboxTrash && controller.emailList.isNotEmpty && !controller.isSearchActive() + ? _buildEmptyTrashButton(context) + : SizedBox.shrink()), + Expanded(child: Container( + padding: EdgeInsets.only( + left: kIsWeb && (_responsiveUtils.isDesktop(context) || _responsiveUtils.isTabletLarge(context)) ? 32 : 0), + color: kIsWeb ? AppColor.colorBgDesktop : Colors.white, + margin: _responsiveUtils.isDesktop(context) ? EdgeInsets.all(16) : EdgeInsets.zero, + 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(), + ] + ) + ), + _buildSuggestionBox(context) + ]))), + _buildListButtonSelectionForMobile(context), + ] + ) + )) + ]), floatingActionButton: _buildFloatingButtonCompose(context), ), ); @@ -247,7 +261,8 @@ class ThreadView extends GetWidget with UserSettingPopupMenuMi Widget _buildSearchButtonViewForMobile(BuildContext context) { return Obx(() { if (!controller.isSearchActive() && !_responsiveUtils.isDesktop(context)) { - return Padding( + return Container( + color: Colors.white, padding: EdgeInsets.only(left: 16, right: 16, bottom: 10), child: (SearchBarView(_imagePaths) ..hintTextSearch(AppLocalizations.of(context).hint_search_emails) @@ -327,7 +342,7 @@ class ThreadView extends GetWidget with UserSettingPopupMenuMi controller.mailboxDashBoardController.searchInputController, suggestionSearch: controller.mailboxDashBoardController.suggestionSearch,) ..addDecoration(BoxDecoration(color: Colors.white)) - ..setMargin(EdgeInsets.only(right: 10)) + ..setMargin(EdgeInsets.only(right: 10, top: _responsiveUtils.isTabletLarge(context) ? 32 : 0)) ..setHintText(AppLocalizations.of(context).search_mail) ..addOnCancelSearchPressed(() => controller.disableSearch()) ..addOnClearTextSearchAction(() => controller.mailboxDashBoardController.clearSearchText()) @@ -515,8 +530,6 @@ class ThreadView extends GetWidget with UserSettingPopupMenuMi margin: _responsiveUtils.isDesktop(context) ? EdgeInsets.only(top: 16, bottom: 16) : EdgeInsets.zero, - width: double.infinity, - height: double.infinity, alignment: Alignment.center, padding: EdgeInsets.zero, color: Colors.white, diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 0ea1af7c3..0e48068ad 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1090,4 +1090,11 @@ class AppLocalizations { 'Maximum files size', name: 'maximum_files_size'); } + + String get exchange { + return Intl.message( + 'Exchange', + name: 'exchange' + ); + } } \ No newline at end of file diff --git a/lib/main/pages/app_pages.dart b/lib/main/pages/app_pages.dart index 5d0bab1d8..583a98ac5 100644 --- a/lib/main/pages/app_pages.dart +++ b/lib/main/pages/app_pages.dart @@ -12,7 +12,8 @@ import 'package:tmail_ui_user/features/login/presentation/login_view.dart' defer import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_bindings.dart'; import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_view.dart' deferred as mailbox_creator; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_bindings.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart' deferred as mailbox_dashBoard; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart' + if (dart.library.html) 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart' deferred as mailbox_dashBoard; import 'package:tmail_ui_user/features/session/presentation/session_page_bindings.dart'; import 'package:tmail_ui_user/features/session/presentation/session_view.dart' deferred as session; import 'package:tmail_ui_user/main/pages/deferred_widget.dart';