diff --git a/assets/images/ic_add_identity.svg b/assets/images/ic_add_identity.svg new file mode 100644 index 000000000..c9aa064e1 --- /dev/null +++ b/assets/images/ic_add_identity.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_dropdown.svg b/assets/images/ic_dropdown.svg new file mode 100644 index 000000000..03b459774 --- /dev/null +++ b/assets/images/ic_dropdown.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_email.svg b/assets/images/ic_email.svg new file mode 100644 index 000000000..44f59957e --- /dev/null +++ b/assets/images/ic_email.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_more_vertical.svg b/assets/images/ic_more_vertical.svg new file mode 100644 index 000000000..44e3006ca --- /dev/null +++ b/assets/images/ic_more_vertical.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ic_reply_to.svg b/assets/images/ic_reply_to.svg new file mode 100644 index 000000000..52cfb2ed5 --- /dev/null +++ b/assets/images/ic_reply_to.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index d61619efa..aba28abd4 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -107,6 +107,7 @@ extension AppColor on Color { static const colorAvatar = Color(0xFFDE5E5E); static const colorFocusButton = Color(0x14818C99); static const colorBorderEmailAddressInvalid = Color(0xFFFF3347); + static const colorBorderIdentityInfo = Color(0xFFE7E8EC); static const colorBgMailboxSelected = Color(0xFF99E4E8EC); static const colorLoading = Color(0x2999A2AD); static const colorActionButtonHover = Color(0xFFA2AAB3); diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index e2525419a..b992c096c 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -95,6 +95,11 @@ class ImagePaths { String get icLogout => _getImagePath('ic_logout.svg'); String get icSetting => _getImagePath('ic_setting.svg'); String get icProfiles => _getImagePath('ic_profiles.svg'); + String get icAddIdentity => _getImagePath('ic_add_identity.svg'); + String get icDropDown => _getImagePath('ic_dropdown.svg'); + String get icMoreVertical => _getImagePath('ic_more_vertical.svg'); + String get icEmail => _getImagePath('ic_email.svg'); + String get icReplyTo => _getImagePath('ic_reply_to.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/base/reloadable/reloadable_controller.dart b/lib/features/base/reloadable/reloadable_controller.dart index adbbd8ecd..efb3a0a67 100644 --- a/lib/features/base/reloadable/reloadable_controller.dart +++ b/lib/features/base/reloadable/reloadable_controller.dart @@ -102,8 +102,4 @@ abstract class ReloadableController extends BaseController { _clearAllCacheAction(); goToLogin(); } - - void goToSettings() { - push(AppRoutes.MANAGE_ACCOUNT); - } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart index e588ca0ce..e64d61972 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart @@ -35,6 +35,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_ema import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_user_profile_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_email_drafts_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/search_state.dart'; @@ -422,6 +423,11 @@ class MailboxDashBoardController extends ReloadableController { dashBoardAction.value = DashBoardAction.idle; } + void goToSettings() { + push(AppRoutes.MANAGE_ACCOUNT, + arguments: ManageAccountArguments(accountId.value, userProfile.value)); + } + @override void onClose() { _emailReceiveManager.closeEmailReceiveManagerStream(); diff --git a/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart b/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart index b66b602af..a5ea0a517 100644 --- a/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart +++ b/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart @@ -15,11 +15,11 @@ mixin UserSettingPopupMenuMixin { enabled: false, padding: EdgeInsets.zero, child: _userInformation(context, userProfile)), - PopupMenuDivider(height: 0.5), + const PopupMenuDivider(height: 0.5), PopupMenuItem( padding: EdgeInsets.zero, child: _settingAction(context, onSettingAction)), - PopupMenuDivider(height: 0.5), + const PopupMenuDivider(height: 0.5), PopupMenuItem( padding: EdgeInsets.zero, child: _logoutAction(context, onLogoutAction)), @@ -31,14 +31,14 @@ mixin UserSettingPopupMenuMixin { return SizedBox( width: 300, child: ListTile( - contentPadding: EdgeInsets.symmetric(horizontal: 20), - title: Text(userProfile.email, maxLines: 1, style: TextStyle( + contentPadding: const EdgeInsets.symmetric(horizontal: 20), + title: Text(userProfile.email, maxLines: 1, style: const TextStyle( fontSize: 15, color: AppColor.colorHintSearchBar, fontWeight: FontWeight.normal))), ); } - return SizedBox.shrink(); + return const SizedBox.shrink(); } Widget _settingAction(BuildContext context, Function? onCallBack) { diff --git a/lib/features/manage_account/presentation/account_properties/profiles/identities/identities_bindings.dart b/lib/features/manage_account/presentation/account_properties/profiles/identities/identities_bindings.dart deleted file mode 100644 index a7ee750be..000000000 --- a/lib/features/manage_account/presentation/account_properties/profiles/identities/identities_bindings.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/base/base_bindings.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/account_properties/profiles/identities/identities_controller.dart'; - -class IdentitiesBindings extends BaseBindings { - - @override - void bindingsController() { - Get.lazyPut(() => IdentitiesController()); - } - - @override - void bindingsDataSource() { - } - - @override - void bindingsDataSourceImpl() { - } - - @override - void bindingsInteractor() { - } - - @override - void bindingsRepository() { - } - - @override - void bindingsRepositoryImpl() { - } -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/account_properties/profiles/identities/identities_view.dart b/lib/features/manage_account/presentation/account_properties/profiles/identities/identities_view.dart deleted file mode 100644 index 8ab722a35..000000000 --- a/lib/features/manage_account/presentation/account_properties/profiles/identities/identities_view.dart +++ /dev/null @@ -1,17 +0,0 @@ - -import 'package:core/core.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/account_properties/profiles/identities/identities_controller.dart'; - -class IdentitiesView extends GetWidget { - - final _responsiveUtils = Get.find(); - - IdentitiesView({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container(color: Colors.green); - } -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/account_properties/profiles/profiles_controller.dart b/lib/features/manage_account/presentation/account_properties/profiles/profiles_controller.dart deleted file mode 100644 index 2f5761408..000000000 --- a/lib/features/manage_account/presentation/account_properties/profiles/profiles_controller.dart +++ /dev/null @@ -1,17 +0,0 @@ - -import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/base/base_controller.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/profiles_tab_type.dart'; - -class ProfilesController extends BaseController { - - final tabTypeSelected = ProfilesTabType.identities.obs; - - @override - void onDone() { - } - - @override - void onError(error) { - } -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/dashboard/manage_account_dashboard_controller.dart b/lib/features/manage_account/presentation/dashboard/manage_account_dashboard_controller.dart deleted file mode 100644 index 678a91556..000000000 --- a/lib/features/manage_account/presentation/dashboard/manage_account_dashboard_controller.dart +++ /dev/null @@ -1,60 +0,0 @@ - -import 'package:flutter/material.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/base/reloadable/reloadable_controller.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_user_profile_state.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_user_profile_interactor.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/account_property.dart'; - -class ManageAccountDashBoardController extends ReloadableController { - - final GetUserProfileInteractor _getUserProfileInteractor; - - final menuDrawerKey = GlobalKey(); - - final appInformation = Rxn(); - final userProfile = Rxn(); - final accountPropertySelected = AccountProperty.profiles.obs; - - ManageAccountDashBoardController( - this._getUserProfileInteractor, - ); - - @override - void onReady() { - _getUserProfile(); - super.onReady(); - } - - @override - void onDone() { - viewState.value.fold( - (failure) {}, - (success) { - if (success is GetUserProfileSuccess) { - userProfile.value = success.userProfile; - } - } - ); - } - - @override - void onError(error) { - } - - void _getUserProfile() async { - consumeState(_getUserProfileInteractor.execute()); - } - - void openMenuDrawer() { - menuDrawerKey.currentState?.openDrawer(); - } - - void closeMenuDrawer() { - menuDrawerKey.currentState?.openEndDrawer(); - } - - bool get isMenuDrawerOpen => menuDrawerKey.currentState?.isDrawerOpen == true; -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/dashboard/manage_account_dashboard_bindings.dart b/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart similarity index 91% rename from lib/features/manage_account/presentation/dashboard/manage_account_dashboard_bindings.dart rename to lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart index 1e96bfe10..370058554 100644 --- a/lib/features/manage_account/presentation/dashboard/manage_account_dashboard_bindings.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart @@ -2,9 +2,9 @@ import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_user_profile_interactor.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/account_properties/profiles/profiles_bindings.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/dashboard/manage_account_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/manage_account_menu_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/profiles_bindings.dart'; class ManageAccountDashBoardBindings extends BaseBindings { diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart new file mode 100644 index 000000000..da31a7399 --- /dev/null +++ b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart @@ -0,0 +1,101 @@ + +import 'package:core/core.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:model/model.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:tmail_ui_user/features/base/reloadable/reloadable_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_user_profile_state.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_user_profile_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart'; +import 'package:tmail_ui_user/main/routes/app_routes.dart'; +import 'package:tmail_ui_user/main/routes/route_navigation.dart'; + +class ManageAccountDashBoardController extends ReloadableController { + + final _responsiveUtils = Get.find(); + + final GetUserProfileInteractor _getUserProfileInteractor; + + final menuDrawerKey = GlobalKey(); + + final appInformation = Rxn(); + final userProfile = Rxn(); + final accountId = Rxn(); + final accountMenuItemSelected = AccountMenuItem.profiles.obs; + + ManageAccountDashBoardController( + this._getUserProfileInteractor, + ); + + @override + void onReady() { + _getArguments(); + super.onReady(); + } + + @override + void onDone() { + viewState.value.fold( + (failure) {}, + (success) { + if (success is GetUserProfileSuccess) { + userProfile.value = success.userProfile; + } + } + ); + } + + @override + void onError(error) { + } + + @override + void handleReloaded(Session session) { + accountId.value = session.accounts.keys.first; + _getUserProfile(); + } + + void _getArguments() { + final arguments = Get.arguments; + log('ManageAccountDashBoardController::_getAccountIdAndUserProfile(): $arguments'); + if (arguments is ManageAccountArguments) { + accountId.value = arguments.accountId; + userProfile.value = arguments.userProfile; + } else { + if (kIsWeb) { + reload(); + } + } + } + + void _getUserProfile() async { + consumeState(_getUserProfileInteractor.execute()); + } + + void openMenuDrawer() { + menuDrawerKey.currentState?.openDrawer(); + } + + void closeMenuDrawer() { + menuDrawerKey.currentState?.openEndDrawer(); + } + + bool get isMenuDrawerOpen => menuDrawerKey.currentState?.isDrawerOpen == true; + + void selectAccountMenuItem(AccountMenuItem newAccountMenuItem) { + accountMenuItemSelected.value = newAccountMenuItem; + if (currentContext != null && !_responsiveUtils.isDesktop(currentContext!)) { + closeMenuDrawer(); + } + } + + void goToSettings() { + pushAndPop(AppRoutes.MANAGE_ACCOUNT, + arguments: ManageAccountArguments(accountId.value, userProfile.value)); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/dashboard/manage_account_dashboard_view.dart b/lib/features/manage_account/presentation/manage_account_dashboard_view.dart similarity index 93% rename from lib/features/manage_account/presentation/dashboard/manage_account_dashboard_view.dart rename to lib/features/manage_account/presentation/manage_account_dashboard_view.dart index 0debeae8f..6587d3a33 100644 --- a/lib/features/manage_account/presentation/dashboard/manage_account_dashboard_view.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_view.dart @@ -4,10 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/account_properties/profiles/profiles_view.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/dashboard/manage_account_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/manage_account_menu_view.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/account_property.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/profiles_view.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -73,7 +73,7 @@ class ManageAccountDashBoardView extends GetWidget {})) .build(), const SizedBox(width: 16), - (AvatarBuilder() + Obx(() => (AvatarBuilder() ..text(controller.userProfile.value?.getAvatarText() ?? '') ..backgroundColor(Colors.white) ..textColor(Colors.black) @@ -121,7 +121,7 @@ class ManageAccountDashBoardView extends GetWidget(); - final listAccountProperties = [ - AccountProperty.profiles + final listAccountMenuItem = [ + AccountMenuItem.profiles ]; @override @@ -19,4 +19,8 @@ class ManageAccountMenuController extends BaseController { @override void onError(error) { } + + void selectAccountMenuItem(AccountMenuItem newAccountMenuItem) { + dashBoardController.selectAccountMenuItem(newAccountMenuItem); + } } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart b/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart index ba867636d..59ec21467 100644 --- a/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart +++ b/lib/features/manage_account/presentation/menu/manage_account_menu_view.dart @@ -65,23 +65,29 @@ class ManageAccountMenuView extends GetWidget { padding: const EdgeInsets.only(left: 16, right: 8), key: const Key('list_manage_account_property'), shrinkWrap: true, - itemCount: controller.listAccountProperties.length, - itemBuilder: (context, index) => Obx(() => AccountPropertyTileBuilder( + itemCount: controller.listAccountMenuItem.length, + itemBuilder: (context, index) => Obx(() => AccountMenuItemTileBuilder( context, _imagePaths, _responsiveUtils, - controller.listAccountProperties[index], - controller.dashBoardController.accountPropertySelected.value))), + controller.listAccountMenuItem[index], + controller.dashBoardController.accountMenuItemSelected.value, + onSelectAccountMenuItemAction: (newAccountMenuItem) => + controller.selectAccountMenuItem(newAccountMenuItem)))), const Padding( padding: EdgeInsets.symmetric(vertical: 16), child: Divider(color: AppColor.lineItemListColor, height: 0.5, thickness: 0.2)), Padding(padding: const EdgeInsets.only(left: 32), - child: InkWell(child: Row(children: [ - SvgPicture.asset(_imagePaths.icLogout, fit: BoxFit.fill), - const SizedBox(width: 12), - Expanded(child: Text(AppLocalizations.of(context).sign_out, - style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.black))) - ]))), + child: InkWell( + onTap: () => controller.dashBoardController.logoutAction(), + child: Row(children: [ + SvgPicture.asset(_imagePaths.icLogout, fit: BoxFit.fill), + const SizedBox(width: 12), + Expanded(child: Text(AppLocalizations.of(context).sign_out, + style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.black))) + ]) + ) + ), ]), )), ] diff --git a/lib/features/manage_account/presentation/menu/widgets/account_property_tile_builder.dart b/lib/features/manage_account/presentation/menu/widgets/account_property_tile_builder.dart index 4174576b2..400ed74d1 100644 --- a/lib/features/manage_account/presentation/menu/widgets/account_property_tile_builder.dart +++ b/lib/features/manage_account/presentation/menu/widgets/account_property_tile_builder.dart @@ -1,54 +1,59 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/account_property.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart'; -class AccountPropertyTileBuilder extends StatelessWidget { +typedef OnSelectAccountMenuItemAction = void Function(AccountMenuItem); + +class AccountMenuItemTileBuilder extends StatelessWidget { final BuildContext _context; final ImagePaths _imagePaths; final ResponsiveUtils _responsiveUtils; - final AccountProperty _accountProperty; - final AccountProperty _accountPropertySelected; + final AccountMenuItem _menuItem; + final AccountMenuItem _menuItemSelected; + final OnSelectAccountMenuItemAction? onSelectAccountMenuItemAction; - const AccountPropertyTileBuilder( + const AccountMenuItemTileBuilder( this._context, this._imagePaths, this._responsiveUtils, - this._accountProperty, - this._accountPropertySelected, {Key? key} + this._menuItem, + this._menuItemSelected, + {Key? key, this.onSelectAccountMenuItemAction} ) : super(key: key); @override Widget build(BuildContext context) { - return Theme( + return InkWell( + onTap: () => onSelectAccountMenuItemAction?.call(_menuItem), + child: Theme( data: ThemeData( splashColor: Colors.transparent, highlightColor: Colors.transparent), child: Container( - key: const Key('account_property_tile'), + key: const Key('account_menu_item_tile'), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: backgroundColorItem - ), + color: backgroundColorItem), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), child: MediaQuery( data: const MediaQueryData(padding: EdgeInsets.zero), child: Column(children: [ Row(children: [ - SvgPicture.asset(_accountProperty.getIcon(_imagePaths), width: 28, height: 28, fit: BoxFit.fill), + SvgPicture.asset(_menuItem.getIcon(_imagePaths), width: 28, height: 28, fit: BoxFit.fill), const SizedBox(width: 12), - Expanded(child: Text(_accountProperty.getName(context), - style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.black))) + Expanded(child: Text(_menuItem.getName(context), + style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.black))) ]), ]) ) ) - ); + )); } Color get backgroundColorItem { - if (_accountPropertySelected == _accountProperty) { + if (_menuItemSelected == _menuItem) { return AppColor.colorBgMailboxSelected; } return _responsiveUtils.isDesktop(_context) ? AppColor.colorBgDesktop : Colors.white; diff --git a/lib/features/manage_account/presentation/model/account_property.dart b/lib/features/manage_account/presentation/model/account_menu_item.dart similarity index 72% rename from lib/features/manage_account/presentation/model/account_property.dart rename to lib/features/manage_account/presentation/model/account_menu_item.dart index c4dc3f893..1c384bbbc 100644 --- a/lib/features/manage_account/presentation/model/account_property.dart +++ b/lib/features/manage_account/presentation/model/account_menu_item.dart @@ -3,22 +3,22 @@ import 'package:core/core.dart'; import 'package:flutter/cupertino.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -enum AccountProperty { +enum AccountMenuItem { profiles } -extension AccountPropertyExtension on AccountProperty { +extension AccountMenuItemExtension on AccountMenuItem { String getIcon(ImagePaths imagePaths) { switch(this) { - case AccountProperty.profiles: + case AccountMenuItem.profiles: return imagePaths.icProfiles; } } String getName(BuildContext context) { switch(this) { - case AccountProperty.profiles: + case AccountMenuItem.profiles: return AppLocalizations.of(context).profiles; } } diff --git a/lib/features/manage_account/presentation/model/manage_account_arguments.dart b/lib/features/manage_account/presentation/model/manage_account_arguments.dart new file mode 100644 index 000000000..9c71cbd74 --- /dev/null +++ b/lib/features/manage_account/presentation/model/manage_account_arguments.dart @@ -0,0 +1,15 @@ + +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:model/model.dart'; + +class ManageAccountArguments with EquatableMixin { + + final AccountId? accountId; + final UserProfile? userProfile; + + ManageAccountArguments(this.accountId, this.userProfile); + + @override + List get props => [accountId, userProfile]; +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/profiles_tab_type.dart b/lib/features/manage_account/presentation/model/profiles_tab_type.dart index 60270292c..4a27d7d49 100644 --- a/lib/features/manage_account/presentation/model/profiles_tab_type.dart +++ b/lib/features/manage_account/presentation/model/profiles_tab_type.dart @@ -4,21 +4,15 @@ import 'package:flutter/material.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; enum ProfilesTabType { - personalInfo, identities, - follower, } extension ProfilesTabTypeExtension on ProfilesTabType { String getName(BuildContext context) { switch(this) { - case ProfilesTabType.personalInfo: - return AppLocalizations.of(context).identities; case ProfilesTabType.identities: return AppLocalizations.of(context).identities; - case ProfilesTabType.follower: - return AppLocalizations.of(context).identities; } } } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/profiles/identities/identities_bindings.dart b/lib/features/manage_account/presentation/profiles/identities/identities_bindings.dart new file mode 100644 index 000000000..76e1291b6 --- /dev/null +++ b/lib/features/manage_account/presentation/profiles/identities/identities_bindings.dart @@ -0,0 +1,49 @@ +import 'package:get/get.dart'; +import 'package:jmap_dart_client/http/http_client.dart' as jmap_http_client; +import 'package:tmail_ui_user/features/base/base_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/data/datasource/manage_account_datasource.dart'; +import 'package:tmail_ui_user/features/manage_account/data/datasource_impl/manage_account_datasource_impl.dart'; +import 'package:tmail_ui_user/features/manage_account/data/network/manage_account_api.dart'; +import 'package:tmail_ui_user/features/manage_account/data/repository/manage_account_repository_impl.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart'; + +class IdentitiesBindings extends BaseBindings { + + @override + void dependencies() { + Get.lazyPut(() => ManageAccountAPI(Get.find())); + super.dependencies(); + } + + @override + void bindingsController() { + Get.lazyPut(() => IdentitiesController(Get.find())); + } + + @override + void bindingsDataSource() { + Get.lazyPut(() => Get.find()); + } + + @override + void bindingsDataSourceImpl() { + Get.lazyPut(() => ManageAccountDataSourceImpl(Get.find())); + } + + @override + void bindingsInteractor() { + Get.lazyPut(() => GetAllIdentitiesInteractor(Get.find())); + } + + @override + void bindingsRepository() { + Get.lazyPut(() => Get.find()); + } + + @override + void bindingsRepositoryImpl() { + Get.lazyPut(() => ManageAccountRepositoryImpl(Get.find())); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/profiles/identities/identities_controller.dart b/lib/features/manage_account/presentation/profiles/identities/identities_controller.dart new file mode 100644 index 000000000..d58bb83c1 --- /dev/null +++ b/lib/features/manage_account/presentation/profiles/identities/identities_controller.dart @@ -0,0 +1,63 @@ + +import 'package:core/core.dart'; +import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/identities/identity.dart'; +import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; + +class IdentitiesController extends BaseController { + + final _accountDashBoardController = Get.find(); + + final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; + + final identitySelected = Rxn(); + final listIdentities = [].obs; + + IdentitiesController(this._getAllIdentitiesInteractor); + + @override + void onInit() { + _onAccountDashBoardListener(); + super.onInit(); + } + + @override + void onDone() { + viewState.value.fold( + (failure) {}, + (success) { + if (success is GetAllIdentitiesSuccess) { + if (success.identities?.isNotEmpty == true) { + listIdentities.value = success.identities ?? []; + selectIdentity(listIdentities.first); + } + } + } + ); + } + + @override + void onError(error) { + } + + void _onAccountDashBoardListener() { + _accountDashBoardController.accountId.listen((accountId) { + log('IdentitiesController::_onAccountDashBoardListener(): accountId: $accountId'); + if (accountId != null) { + _getAllIdentities(accountId); + } + }); + } + + void _getAllIdentities(AccountId accountId) { + consumeState(_getAllIdentitiesInteractor.execute(accountId)); + } + + void selectIdentity(Identity? newIdentity) { + identitySelected.value = newIdentity; + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/profiles/identities/identities_view.dart b/lib/features/manage_account/presentation/profiles/identities/identities_view.dart new file mode 100644 index 000000000..4d9587f69 --- /dev/null +++ b/lib/features/manage_account/presentation/profiles/identities/identities_view.dart @@ -0,0 +1,119 @@ + +import 'package:core/core.dart'; +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/identities/identity.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class IdentitiesView extends GetWidget { + + final _responsiveUtils = Get.find(); + final _imagePaths = Get.find(); + + IdentitiesView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final buttonSelectIdentity = Row(children: [ + Expanded(child: Obx(() => DropdownButtonHideUnderline( + child: DropdownButton2( + isExpanded: true, + hint: Row( + children: [ + Expanded(child: Text( + controller.identitySelected.value?.name ?? '', + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.normal, color: Colors.black), + maxLines: 1, + overflow: TextOverflow.ellipsis, + )), + ], + ), + items: controller.listIdentities.map((item) => DropdownMenuItem( + value: item, + child: Text( + item.name ?? '', + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.normal, color: Colors.black), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + )).toList(), + value: controller.identitySelected.value, + onChanged: (newIdentity) => controller.selectIdentity(newIdentity), + icon: SvgPicture.asset(_imagePaths.icDropDown), + buttonPadding: const EdgeInsets.symmetric(horizontal: 12), + buttonDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all(color: AppColor.colorInputBorderCreateMailbox, width: 0.5), + color: AppColor.colorInputBackgroundCreateMailbox), + itemHeight: 44, + buttonHeight: 44, + itemPadding: const EdgeInsets.symmetric(horizontal: 12), + dropdownMaxHeight: 200, + dropdownDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.white), + dropdownElevation: 4, + scrollbarRadius: const Radius.circular(40), + scrollbarThickness: 6, + ), + ))), + if (!_responsiveUtils.isMobile(context)) const SizedBox(width: 12), + if (!_responsiveUtils.isMobile(context)) + (ButtonBuilder(_imagePaths.icAddIdentity) + ..key(const Key('button_new_identity')) + ..decoration(BoxDecoration(borderRadius: BorderRadius.circular(10), color: AppColor.colorTextButton)) + ..paddingIcon(const EdgeInsets.only(right: 8)) + ..iconColor(Colors.white) + ..maxWidth(170) + ..size(20) + ..radiusSplash(10) + ..padding(const EdgeInsets.symmetric(vertical: 12)) + ..textStyle(const TextStyle(fontSize: 17, color: Colors.white, fontWeight: FontWeight.w500)) + ..onPressActionClick(() => {}) + ..text(AppLocalizations.of(context).new_identity, isVertical: false)) + .build() + ]); + + return LayoutBuilder(builder: (context, constraints) => ResponsiveWidget( + responsiveUtils: _responsiveUtils, + mobile: Scaffold( + body: Container( + margin: const EdgeInsets.symmetric(vertical: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buttonSelectIdentity, + Obx(() => IdentityInfoTileBuilder(context, + _imagePaths, + controller.identitySelected.value)), + ] + )), + floatingActionButton: _responsiveUtils.isMobile(context) + ? FloatingActionButton( + key: const Key('add_new_identity'), + onPressed: () => {}, + backgroundColor: AppColor.primaryColor, + child: SvgPicture.asset(_imagePaths.icAddIdentity, width: 24, height: 24)) + : null), + desktop: Container( + margin: const EdgeInsets.symmetric(vertical: 24, horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: constraints.maxWidth / 2, + child: buttonSelectIdentity), + Obx(() => IdentityInfoTileBuilder(context, + _imagePaths, + controller.identitySelected.value, + maxWidth: constraints.maxWidth / 2)), + ] + ) + ) + )); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart b/lib/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart new file mode 100644 index 000000000..4927c07df --- /dev/null +++ b/lib/features/manage_account/presentation/profiles/identities/widgets/identity_info_tile_builder.dart @@ -0,0 +1,117 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:jmap_dart_client/jmap/identities/identity.dart'; +import 'package:model/model.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class IdentityInfoTileBuilder extends StatelessWidget { + + final BuildContext _context; + final ImagePaths _imagePaths; + final Identity? _identity; + final double? maxWidth; + + const IdentityInfoTileBuilder( + this._context, + this._imagePaths, + this._identity, + {Key? key, this.maxWidth} + ) : super(key: key); + + @override + Widget build(BuildContext context) { + if (_identity == null) { + return const SizedBox.shrink(); + } + + return Container( + key: const Key('identity_info_tile'), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + border: Border.all(color: AppColor.colorBorderIdentityInfo, width: 1), + color: Colors.white), + padding: const EdgeInsets.only(top: 12, bottom: 12), + margin: const EdgeInsets.only(top: 12), + width: maxWidth, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row(children: [ + Expanded(child: Text(_identity?.name ?? '', + style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 17, color: Colors.black))), + buildIconWeb( + icon: SvgPicture.asset(_imagePaths.icMoreVertical, fit: BoxFit.fill), + onTap: () => {}) + ])), + const SizedBox(height: 10), + const Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2), + const SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text(_identity?.name ?? '', + style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 17, color: Colors.black))), + if (_identity?.email != null) const SizedBox(height: 10), + if (_identity?.email != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row(children: [ + SizedBox( + width: 40, + child: SvgPicture.asset(_imagePaths.icEmail, width: 15, height: 15)), + const SizedBox(width: 4), + Expanded(child: Text(_identity?.email ?? '', + style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: AppColor.colorHintSearchBar))) + ])), + if (_identity?.replyTo != null) const SizedBox(height: 10), + if (_identity?.replyTo != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row(children: [ + SizedBox( + width: 40, + child: SvgPicture.asset(_imagePaths.icReplyTo, width: 15, height: 15)), + const SizedBox(width: 4), + Expanded(child: Text(_identity?.replyTo?.listEmailAddressToString(isFullEmailAddress: true) ?? '', + style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: AppColor.colorHintSearchBar))) + ])), + if (_identity?.cc != null) const SizedBox(height: 6), + if (_identity?.cc != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row(children: [ + Container( + width: 40, + padding: const EdgeInsets.only(left: 10), + child: Text(AppLocalizations.of(_context).cc_email_address_prefix, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + decoration: TextDecoration.underline, + color: AppColor.colorTextButton))), + const SizedBox(width: 4), + Expanded(child: Text(_identity?.cc?.listEmailAddressToString(isFullEmailAddress: true) ?? '', + style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: AppColor.colorHintSearchBar))) + ])), + if (_identity?.bcc != null) const SizedBox(height: 6), + if (_identity?.bcc != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row(children: [ + Container( + padding: const EdgeInsets.only(left: 6), + width: 40, + child: Text(AppLocalizations.of(_context).bcc_email_address_prefix, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.normal, + decoration: TextDecoration.underline, + color: AppColor.colorTextButton))), + const SizedBox(width: 4), + Expanded(child: Text(_identity?.bcc?.listEmailAddressToString(isFullEmailAddress: true) ?? '', + style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: AppColor.colorHintSearchBar))) + ])), + ]) + ); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/account_properties/profiles/profiles_bindings.dart b/lib/features/manage_account/presentation/profiles/profiles_bindings.dart similarity index 81% rename from lib/features/manage_account/presentation/account_properties/profiles/profiles_bindings.dart rename to lib/features/manage_account/presentation/profiles/profiles_bindings.dart index dea8ddd3b..95d4381c7 100644 --- a/lib/features/manage_account/presentation/account_properties/profiles/profiles_bindings.dart +++ b/lib/features/manage_account/presentation/profiles/profiles_bindings.dart @@ -1,14 +1,14 @@ import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/account_properties/profiles/identities/identities_bindings.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/account_properties/profiles/profiles_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/profiles_controller.dart'; class ProfileBindings extends BaseBindings { @override void dependencies() { super.dependencies(); - IdentitiesBindings(); + IdentitiesBindings().dependencies(); } @override diff --git a/lib/features/manage_account/presentation/account_properties/profiles/identities/identities_controller.dart b/lib/features/manage_account/presentation/profiles/profiles_controller.dart similarity index 73% rename from lib/features/manage_account/presentation/account_properties/profiles/identities/identities_controller.dart rename to lib/features/manage_account/presentation/profiles/profiles_controller.dart index de1a0edad..935d49912 100644 --- a/lib/features/manage_account/presentation/account_properties/profiles/identities/identities_controller.dart +++ b/lib/features/manage_account/presentation/profiles/profiles_controller.dart @@ -1,7 +1,7 @@ import 'package:tmail_ui_user/features/base/base_controller.dart'; -class IdentitiesController extends BaseController { +class ProfilesController extends BaseController { @override void onDone() { diff --git a/lib/features/manage_account/presentation/account_properties/profiles/profiles_view.dart b/lib/features/manage_account/presentation/profiles/profiles_view.dart similarity index 77% rename from lib/features/manage_account/presentation/account_properties/profiles/profiles_view.dart rename to lib/features/manage_account/presentation/profiles/profiles_view.dart index 011ccdc6b..72f8db481 100644 --- a/lib/features/manage_account/presentation/account_properties/profiles/profiles_view.dart +++ b/lib/features/manage_account/presentation/profiles/profiles_view.dart @@ -2,9 +2,9 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/account_properties/profiles/identities/identities_view.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/account_properties/profiles/profiles_controller.dart'; -import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/profiles_tab_type.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_view.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/profiles/profiles_controller.dart'; class ProfilesView extends GetWidget { @@ -37,7 +37,7 @@ class ProfilesView extends GetWidget { color: AppColor.colorTextButtonHeaderThread), labelStyle: const TextStyle( fontSize: 15, - fontWeight: FontWeight.normal, + fontWeight: FontWeight.w500, color: AppColor.primaryColor), labelColor: AppColor.primaryColor, indicatorSize: TabBarIndicatorSize.label, @@ -48,13 +48,16 @@ class ProfilesView extends GetWidget { indicatorSize: CustomIndicatorSize.full), onTap: (index) {}, tabs: [ - Tab(text: AppLocalizations.of(context).identities), + Tab(text: ProfilesTabType.identities.getName(context)), ]), - body: TabBarView( - children: [ - IdentitiesView(), - ], - ), + body: Column(children: [ + const Divider(color: AppColor.colorDividerMailbox, height: 0.5, thickness: 0.2), + Expanded(child: TabBarView( + children: [ + IdentitiesView(), + ], + )) + ]), ) ), ), diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 4d9c2dd48..77ddd7388 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-04-25T19:06:15.088714", + "@@last_modified": "2022-04-26T09:31:06.288489", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -1119,5 +1119,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "new_identity": "New Identity", + "@new_identity": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index ab6576c63..2d44dd108 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1173,4 +1173,9 @@ class AppLocalizations { return Intl.message('Identities', name: 'identities'); } + + String get new_identity { + return Intl.message('New Identity', + name: 'new_identity'); + } } \ No newline at end of file diff --git a/lib/main/pages/app_pages.dart b/lib/main/pages/app_pages.dart index d1be36c48..77f57dd7a 100644 --- a/lib/main/pages/app_pages.dart +++ b/lib/main/pages/app_pages.dart @@ -14,10 +14,10 @@ import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_crea 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' 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/manage_account/presentation/dashboard/manage_account_dashboard_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_bindings.dart'; 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/features/manage_account/presentation/dashboard/manage_account_dashboard_view.dart' deferred as manage_account_dashboard; +import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_view.dart' deferred as manage_account_dashboard; import 'package:tmail_ui_user/main/pages/deferred_widget.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; diff --git a/lib/main/routes/app_routes.dart b/lib/main/routes/app_routes.dart index 957c6f98e..8aeef8e95 100644 --- a/lib/main/routes/app_routes.dart +++ b/lib/main/routes/app_routes.dart @@ -9,5 +9,5 @@ abstract class AppRoutes { static const COMPOSER = '/composer'; static const DESTINATION_PICKER = '/destinationPicker'; static const MAILBOX_CREATOR = '/mailboxCreator'; - static const MANAGE_ACCOUNT = '/manage_account'; + static const MANAGE_ACCOUNT = '$MAILBOX_DASHBOARD/manage_account'; } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index b6a6df2ed..fabfbbf0a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -143,6 +143,8 @@ dependencies: receive_sharing_intent: 1.4.5 + dropdown_button2: 1.4.0 + dev_dependencies: flutter_test: sdk: flutter