From c3f73a864935c290f1f46ab2023f542983d3308a Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 22 Mar 2022 10:32:38 +0700 Subject: [PATCH] TF-381 Add logout action in browser new UI --- .../views/image/avatar_builder.dart | 32 +++++++++++++--- .../presentation/mailbox_controller.dart | 2 + .../mailbox_dashboard_controller.dart | 2 - .../thread/presentation/thread_bindings.dart | 10 +++++ .../presentation/thread_controller.dart | 30 +++++++++++++++ .../thread/presentation/thread_view.dart | 17 +++++++++ .../app_action_sheet_action_builder.dart | 38 +++++++++++++++++++ 7 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 lib/features/thread/presentation/widgets/app_action_sheet_action_builder.dart diff --git a/core/lib/presentation/views/image/avatar_builder.dart b/core/lib/presentation/views/image/avatar_builder.dart index 01dda7973..c8e160145 100644 --- a/core/lib/presentation/views/image/avatar_builder.dart +++ b/core/lib/presentation/views/image/avatar_builder.dart @@ -2,14 +2,18 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:flutter/material.dart'; typedef OnTapAvatarActionClick = void Function(); +typedef OnTapAvatarActionWithPositionClick = void Function(RelativeRect? position); class AvatarBuilder { + + BuildContext? _context; Key? _key; String? _text; double? _size; Color? _bgColor; Color? _textColor; OnTapAvatarActionClick? _onTapAvatarActionClick; + OnTapAvatarActionWithPositionClick? _onTapAvatarActionWithPositionClick; List? _avatarColors; List? _boxShadows; TextStyle? _textStyle; @@ -18,6 +22,10 @@ class AvatarBuilder { _key = key; } + void context(BuildContext context) { + _context = context; + } + void size(double size) { _size = size; } @@ -50,12 +58,26 @@ class AvatarBuilder { _onTapAvatarActionClick = onTapAvatarActionClick; } + void addOnTapAvatarActionWithPositionClick(OnTapAvatarActionWithPositionClick onTapAvatarActionWithPositionClick) { + _onTapAvatarActionWithPositionClick = onTapAvatarActionWithPositionClick; + } + Widget build() { - return GestureDetector( - onTap: () { - if (_onTapAvatarActionClick != null) { - _onTapAvatarActionClick!(); - }}, + return InkWell( + onTap: () => _onTapAvatarActionClick != null ? _onTapAvatarActionClick?.call() : null, + onTapDown: (detail) { + if (_onTapAvatarActionWithPositionClick != null && _context != null) { + final screenSize = MediaQuery.of(_context!).size; + final offset = detail.globalPosition; + final position = RelativeRect.fromLTRB( + offset.dx, + offset.dy, + screenSize.width - offset.dx, + screenSize.height - offset.dy, + ); + _onTapAvatarActionWithPositionClick?.call(position); + } + }, child: Container( key: _key, width: _size ?? 40, diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index f1ad303ab..69e2118ee 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -106,6 +106,7 @@ class MailboxController extends BaseMailboxController { void onReady() { super.onReady(); mailboxDashBoardController.accountId.listen((accountId) { + log('MailboxController::onReady(): accountId: $accountId'); if (accountId != null) { getAllMailboxAction(accountId); } @@ -148,6 +149,7 @@ class MailboxController extends BaseMailboxController { super.onData(newState); newState.map((success) async { if (success is GetAllMailboxSuccess) { + log('MailboxController::onData(): ${allMailboxes.length}'); allMailboxes = success.mailboxList; currentMailboxState = success.currentMailboxState; await buildTree(allMailboxes); diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart index 7891a5941..cb8009a01 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart @@ -14,7 +14,6 @@ import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.da import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; -import 'package:tmail_ui_user/features/email/presentation/email_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.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/state/remove_email_drafts_state.dart'; @@ -278,7 +277,6 @@ class MailboxDashBoardController extends ReloadableController { void onClose() { searchInputController.dispose(); searchFocus.dispose(); - Get.delete(); super.onClose(); } } \ No newline at end of file diff --git a/lib/features/thread/presentation/thread_bindings.dart b/lib/features/thread/presentation/thread_bindings.dart index ec71a3c0c..e22a972e1 100644 --- a/lib/features/thread/presentation/thread_bindings.dart +++ b/lib/features/thread/presentation/thread_bindings.dart @@ -1,6 +1,8 @@ import 'package:core/core.dart'; import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; +import 'package:tmail_ui_user/features/caching/caching_manager.dart'; import 'package:tmail_ui_user/features/caching/state_cache_client.dart'; import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart'; @@ -13,6 +15,9 @@ import 'package:tmail_ui_user/features/email/domain/repository/email_repository. import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/login/data/repository/credential_repository_impl.dart'; +import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; +import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart'; import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/state_datasource_impl.dart'; import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; @@ -53,6 +58,8 @@ class ThreadBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), + Get.find(), )); } @@ -90,16 +97,19 @@ class ThreadBindings extends BaseBindings { Get.lazyPut(() => LoadMoreEmailsInMailboxInteractor(Get.find())); Get.lazyPut(() => SearchEmailInteractor(Get.find())); Get.lazyPut(() => SearchMoreEmailInteractor(Get.find())); + Get.lazyPut(() => DeleteCredentialInteractor(Get.find())); } @override void bindingsRepository() { + Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); Get.lazyPut(() => Get.find()); } @override void bindingsRepositoryImpl() { + Get.lazyPut(() => CredentialRepositoryImpl(Get.find())); Get.lazyPut(() => ThreadRepositoryImpl( { DataSourceType.network: Get.find(), diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 7459cf57d..8c0ad10be 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -15,6 +15,7 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/caching/caching_manager.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; @@ -25,6 +26,7 @@ import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_sta import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; +import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart'; @@ -69,6 +71,8 @@ class ThreadController extends BaseController { final LoadMoreEmailsInMailboxInteractor _loadMoreEmailsInMailboxInteractor; final SearchEmailInteractor _searchEmailInteractor; final SearchMoreEmailInteractor _searchMoreEmailInteractor; + final DeleteCredentialInteractor _deleteCredentialInteractor; + final CachingManager _cachingManager; final emailList = [].obs; final emailListSearch = [].obs; @@ -102,6 +106,8 @@ class ThreadController extends BaseController { this._loadMoreEmailsInMailboxInteractor, this._searchEmailInteractor, this._searchMoreEmailInteractor, + this._deleteCredentialInteractor, + this._cachingManager, ); @override @@ -738,6 +744,30 @@ class ThreadController extends BaseController { } } + void openUserSettingAction(BuildContext context, RelativeRect? position, List popupMenuItems) async { + await showMenu( + context: context, + position: position ?? RelativeRect.fromLTRB(16, 40, 16, 16), + color: Colors.white, + elevation: 5, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), + items: popupMenuItems); + } + + void _deleteCredential() async { + await _deleteCredentialInteractor.execute(); + } + + void _clearAllCache() async { + await _cachingManager.clearAll(); + } + + void logoutAction() { + _deleteCredential(); + _clearAllCache(); + pushAndPopAll(AppRoutes.LOGIN); + } + void composeEmailAction() { mailboxDashBoardController.composeEmailAction(); } diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 6481356c0..2be2a17f7 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -8,6 +8,7 @@ import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.da import 'package:tmail_ui_user/features/thread/domain/state/search_more_email_state.dart'; import 'package:tmail_ui_user/features/thread/presentation/extensions/filter_message_option_extension.dart'; import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart'; +import 'package:tmail_ui_user/features/thread/presentation/widgets/app_action_sheet_action_builder.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/bottom_bar_thread_selection_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart'; @@ -133,6 +134,12 @@ class ThreadView extends GetWidget { ..text(controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '') ..backgroundColor(Colors.white) ..textColor(Colors.black) + ..context(context) + ..addOnTapAvatarActionWithPositionClick((position) => + controller.openUserSettingAction( + context, + position, + [PopupMenuItem(padding: EdgeInsets.symmetric(horizontal: 8), child: _logoutAction(context))])) ..addBoxShadows([BoxShadow( color: AppColor.colorShadowBgContentEmail, spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5))]) @@ -561,4 +568,14 @@ class ThreadView extends GetWidget { } }); } + + Widget _logoutAction(BuildContext context) { + return (AppActionSheetActionBuilder( + Key('logout_action'), + SvgPicture.asset(_imagePaths.icCloseMailbox, color: AppColor.colorTextButton, fit: BoxFit.fill), + AppLocalizations.of(context).logout, + iconLeftPadding:EdgeInsets.only(right: 12)) + ..onActionClick((option) => controller.logoutAction())) + .build(); + } } \ No newline at end of file diff --git a/lib/features/thread/presentation/widgets/app_action_sheet_action_builder.dart b/lib/features/thread/presentation/widgets/app_action_sheet_action_builder.dart new file mode 100644 index 000000000..8d6d675e8 --- /dev/null +++ b/lib/features/thread/presentation/widgets/app_action_sheet_action_builder.dart @@ -0,0 +1,38 @@ + +import 'package:core/core.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +class AppActionSheetActionBuilder extends CupertinoActionSheetActionBuilder { + + final Color? bgColor; + final EdgeInsets? iconLeftPadding; + + AppActionSheetActionBuilder( + Key key, + SvgPicture actionIcon, + String actionName, + { + this.bgColor, + this.iconLeftPadding, + } + ) : super(key, actionIcon, actionName); + + @override + Widget build() { + return Container( + color: bgColor ?? Colors.white, + child: CupertinoActionSheetAction( + key: key, + child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Padding( + padding: iconLeftPadding ?? EdgeInsets.only(left: 12, right: 16), + child: actionIcon), + Expanded(child: Text(actionName, textAlign: TextAlign.left, style: actionTextStyle())), + ]), + onPressed: () => onCupertinoActionSheetActionClick?.call(null), + ), + ); + } +} \ No newline at end of file