TF-381 Apply new UI EmailView for browser

This commit is contained in:
dab246
2022-03-22 13:34:03 +07:00
committed by Dat H. Pham
parent dc35d5e5a0
commit c2f6434686
22 changed files with 300 additions and 256 deletions
@@ -33,7 +33,7 @@ class ResponsiveUtils {
bool isMobile(BuildContext context) => getDeviceWidth(context) < minTabletWidth;
bool isTablet(BuildContext context) => getDeviceWidth(context) >= minTabletWidth && getDeviceWidth(context) < minDesktopWidth;
bool isTablet(BuildContext context) => getDeviceWidth(context) >= minTabletWidth && getDeviceWidth(context) < minTabletLargeWidth;
bool isDesktop(BuildContext context) => getDeviceWidth(context) >= minDesktopWidth;
@@ -105,7 +105,7 @@ class ButtonBuilder {
_onPressActionWithPositionClick?.call(position);
}
},
borderRadius: BorderRadius.all(Radius.circular(_radiusSplash ?? 0)),
borderRadius: BorderRadius.all(Radius.circular(_radiusSplash ?? 20)),
child: Container(
key: _key,
alignment: Alignment.center,
@@ -10,6 +10,7 @@ Widget buildIconWeb({
IconWebCallback? onTap,
EdgeInsets? iconPadding,
double? iconSize,
double? splashRadius,
}) {
return Material(
color: Colors.transparent,
@@ -18,7 +19,7 @@ Widget buildIconWeb({
icon: icon,
iconSize: iconSize,
padding: iconPadding ?? EdgeInsets.all(8.0),
splashRadius: 20,
splashRadius: splashRadius ?? 20,
tooltip: tooltip,
onPressed: onTap)
);
@@ -27,9 +28,10 @@ Widget buildIconWeb({
Widget buildIconWebHasPosition(BuildContext context, {
required Widget icon,
String? tooltip,
IconWebHasPositionCallback? onTap
IconWebHasPositionCallback? onTapDown,
IconWebCallback? onTap,
}) {
return GestureDetector(
return InkWell(
onTapDown: (detail) {
final screenSize = MediaQuery.of(context).size;
final offset = detail.globalPosition;
@@ -39,10 +41,12 @@ Widget buildIconWebHasPosition(BuildContext context, {
screenSize.width - offset.dx,
screenSize.height - offset.dy,
);
onTap?.call(position);
onTapDown?.call(position);
},
onTap: () => onTap?.call(),
borderRadius: BorderRadius.all(Radius.circular(35)),
child: Tooltip(
message: tooltip,
message: tooltip ?? '',
child: icon,
)
);
@@ -200,27 +200,18 @@ class DestinationPickerView extends GetWidget<DestinationPickerController> {
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
color: Colors.white),
margin: EdgeInsets.only(left: 16, right: 16, top: _getTopPaddingListMailbox(context, actions)),
margin: EdgeInsets.only(left: 16, right: 16, top: 10),
child: _buildDefaultMailbox(context)),
SizedBox(height: 20),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
color: Colors.white),
margin: EdgeInsets.only(left: 16, right: 16, top: 4, bottom: 30),
margin: EdgeInsets.only(left: 16, right: 16, top: 10, bottom: 20),
child: _buildFolderMailbox(context)),
]
);
}
double _getTopPaddingListMailbox(BuildContext context, MailboxActions? actions) {
if (actions == MailboxActions.create) {
return (_responsiveUtils.isMobile(context) || _responsiveUtils.isMobileDevice(context)) ? 20.0 : 5.0;
} else {
return (_responsiveUtils.isMobile(context) || _responsiveUtils.isMobileDevice(context)) ? 16.0 : 10.0;
}
}
Widget _buildDefaultMailbox(BuildContext context) {
return Obx(() => controller.defaultMailboxTree.value.root.childrenItems?.isNotEmpty ?? false
? Transform(
@@ -36,7 +36,6 @@ class AppBarDestinationPickerBuilder {
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
_buildBackButton(),
@@ -48,16 +47,27 @@ class AppBarDestinationPickerBuilder {
}
Widget _buildBackButton() {
return Material(
borderRadius: BorderRadius.circular(12),
color: Colors.transparent,
child: _responsiveUtils.isMobile(_context)
? IconButton(
color: _mailboxAction == MailboxActions.create ? AppColor.colorTextButton : AppColor.baseTextColor,
icon: _getBackIcon(),
onPressed: () => _onCloseActionClick?.call())
: SizedBox(width: 40, height: 40)
);
if (_mailboxAction == MailboxActions.create) {
if (_responsiveUtils.isMobile(_context)) {
return Material(
color: Colors.transparent,
shape: CircleBorder(),
child: IconButton(
splashRadius: 20,
icon: SvgPicture.asset(_imagePaths.icBack, color: AppColor.colorTextButton, fit: BoxFit.fill),
onPressed: () => _onCloseActionClick?.call()));
} else {
return SizedBox(width: 40, height: 40);
}
} else {
return Material(
color: Colors.transparent,
shape: CircleBorder(),
child: IconButton(
splashRadius: 20,
icon: SvgPicture.asset(_imagePaths.icComposerClose, color: AppColor.baseTextColor, fit: BoxFit.fill),
onPressed: () => _onCloseActionClick?.call()));
}
}
Widget _buildTitle() {
@@ -80,12 +90,4 @@ class AppBarDestinationPickerBuilder {
return _responsiveUtils.isMobile(_context) ? TextAlign.start : TextAlign.center;
}
}
Widget _getBackIcon() {
if (_mailboxAction == MailboxActions.create) {
return SvgPicture.asset(_imagePaths.icBack, fit: BoxFit.fill);
} else {
return SvgPicture.asset(_imagePaths.icComposerClose, fit: BoxFit.fill);
}
}
}
+72 -24
View File
@@ -17,10 +17,11 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/bottom_bar_mai
import 'package:tmail_ui_user/features/email/presentation/widgets/email_action_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_content_item_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_content_place_holder_loading_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/user_setting_popup_menu_mixin.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:filesize/filesize.dart';
class EmailView extends GetView {
class EmailView extends GetView with UserSettingPopupMenuMixin {
final emailController = Get.find<EmailController>();
final responsiveUtils = Get.find<ResponsiveUtils>();
@@ -31,11 +32,11 @@ class EmailView extends GetView {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
backgroundColor: responsiveUtils.isDesktop(context) ? AppColor.colorBgDesktop : Colors.white,
body: Container(
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
decoration: !(responsiveUtils.isMobile(context) && responsiveUtils.isMobileDevice(context))
decoration: responsiveUtils.isTabletLarge(context)
? BoxDecoration(border: Border(left: BorderSide(color: AppColor.colorLineLeftEmailView, width: 1.0)))
: null,
child: SafeArea(
@@ -44,15 +45,12 @@ class EmailView extends GetView {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildAppBar(context),
Obx(() => emailController.currentEmail != null
? _buildDivider()
: SizedBox.shrink()),
Expanded(child: _buildEmailBody(context)),
Obx(() => emailController.currentEmail != null
? Divider(color: AppColor.colorDividerEmailView, height: 1)
: SizedBox.shrink()),
_buildBottomBar(context),
if (responsiveUtils.isDesktop(context))
Container(
color: Colors.white,
padding: EdgeInsets.only(right: 10, top: 16, bottom: 10),
child: _buildHeader(context)),
Expanded(child: _buildBody(context)),
]
)
),
@@ -60,6 +58,52 @@ class EmailView extends GetView {
);
}
Widget _buildHeader(BuildContext context) {
return Row(children: [
Spacer(),
Padding(
padding: EdgeInsets.only(right: 16),
child: (AvatarBuilder()
..text(emailController.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? '')
..backgroundColor(Colors.white)
..textColor(Colors.black)
..context(context)
..addOnTapAvatarActionWithPositionClick((position) => openUserSettingAction(
context,
position,
popupMenuUserSettingActionTile(context, () => emailController.mailboxDashBoardController.logoutAction())))
..addBoxShadows([BoxShadow(
color: AppColor.colorShadowBgContentEmail,
spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5))])
..size(48))
.build()),
]);
}
Widget _buildBody(BuildContext context) {
return Container(
decoration: responsiveUtils.isDesktop(context)
? BoxDecoration(
borderRadius: BorderRadius.circular(20),
border: Border.all(color: AppColor.colorBorderBodyThread, width: 1),
color: Colors.white)
: null,
margin: responsiveUtils.isDesktop(context) ? EdgeInsets.all(16) : EdgeInsets.zero,
padding: responsiveUtils.isDesktop(context) ? EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 3) : EdgeInsets.zero,
child: Column(children: [
_buildAppBar(context),
if (responsiveUtils.isDesktop(context)) SizedBox(height: 5),
Obx(() => emailController.currentEmail != null && !responsiveUtils.isDesktop(context)
? _buildDivider() : SizedBox.shrink()),
Expanded(child: _buildEmailBody(context)),
Obx(() => emailController.currentEmail != null
? Divider(color: AppColor.colorDividerEmailView, height: 1)
: SizedBox.shrink()),
_buildBottomBar(context),
])
);
}
Widget _buildDivider({EdgeInsets? edgeInsets}){
return Padding(
padding: edgeInsets ?? EdgeInsets.symmetric(horizontal: 16),
@@ -129,12 +173,15 @@ class EmailView extends GetView {
style: TextStyle(fontSize: 25, color: AppColor.mailboxTextColor, fontWeight: FontWeight.bold));
}
Widget _buildEmailSubject() {
Widget _buildEmailSubject(BuildContext context) {
return Padding(
padding: EdgeInsets.only(right: 16),
child: Text(
'${emailController.mailboxDashBoardController.selectedEmail.value?.getEmailTitle()}',
style: TextStyle(fontSize: 20, color: AppColor.colorNameEmail)
style: TextStyle(
fontSize: 20,
color: AppColor.colorNameEmail,
fontWeight: responsiveUtils.isDesktop(context) ? FontWeight.w500 : FontWeight.normal)
));
}
@@ -153,18 +200,19 @@ class EmailView extends GetView {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(child: _buildEmailSubject()),
Expanded(child: _buildEmailSubject(context)),
_buildEmailTime(context),
]),
_buildDivider(edgeInsets: EdgeInsets.only(top: 16)),
if (responsiveUtils.isDesktop(context)) SizedBox(height: 20),
if (!responsiveUtils.isDesktop(context)) _buildDivider(edgeInsets: EdgeInsets.only(top: 16)),
Obx(() => emailController.currentEmail != null
? _buildEmailAddress(
context,
emailController.currentEmail!,
emailController.emailAddressExpandMode.value,
emailController.isDisplayFullEmailAddress.value)
context,
emailController.currentEmail!,
emailController.emailAddressExpandMode.value,
emailController.isDisplayFullEmailAddress.value)
: SizedBox.shrink()),
_buildDivider(edgeInsets: EdgeInsets.only(top: 4)),
_buildDivider(edgeInsets: EdgeInsets.only(top: 8)),
_buildAttachments(context),
_buildListEmailContent(context, constraints),
],
@@ -193,15 +241,15 @@ class EmailView extends GetView {
if (email.from.numberEmailAddress() > 0)
_buildEmailAddressByPrefix(context, email, PrefixEmailAddress.from, isDisplayFull),
if (email.to.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND)
_buildDivider(edgeInsets: EdgeInsets.only(top: 4)),
_buildDivider(edgeInsets: EdgeInsets.only(top: 8, bottom: 4)),
if (email.to.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND)
_buildEmailAddressByPrefix(context, email, PrefixEmailAddress.to, isDisplayFull),
if (email.cc.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND && isDisplayFull)
_buildDivider(edgeInsets: EdgeInsets.only(top: 4)),
_buildDivider(edgeInsets: EdgeInsets.only(top: 8, bottom: 4)),
if (email.cc.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND && isDisplayFull)
_buildEmailAddressByPrefix(context, email, PrefixEmailAddress.cc, isDisplayFull),
if (email.bcc.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND && isDisplayFull)
_buildDivider(edgeInsets: EdgeInsets.only(top: 4)),
_buildDivider(edgeInsets: EdgeInsets.only(top: 8, bottom: 4)),
if (email.bcc.numberEmailAddress() > 0 && expandMode == ExpandMode.EXPAND && isDisplayFull)
_buildEmailAddressByPrefix(context, email, PrefixEmailAddress.bcc, isDisplayFull),
],
@@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:model/model.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/main/localizations/app_localizations.dart';
typedef OnBackActionClick = void Function();
typedef OnEmailActionClick = void Function(PresentationEmail, EmailActionType);
@@ -50,7 +51,6 @@ class AppBarMailWidgetBuilder {
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (_conditionShow(_context))
@@ -74,9 +74,10 @@ class AppBarMailWidgetBuilder {
}
Widget _buildBackButton() {
return IconButton(
icon: SvgPicture.asset(_imagePaths.icBack, width: 20, height: 20, color: AppColor.colorTextButton, fit: BoxFit.fill),
onPressed: () => _onBackActionClick?.call()
return buildIconWeb(
icon: SvgPicture.asset(_imagePaths.icBack, width: 18, height: 18, color: AppColor.colorTextButton, fit: BoxFit.fill),
tooltip: AppLocalizations.of(_context).back,
onTap: () => _onBackActionClick?.call()
);
}
@@ -93,71 +94,42 @@ class AppBarMailWidgetBuilder {
Widget _buildListOptionButton() {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
key: Key('button_move_to_mailbox_email'),
icon: SvgPicture.asset(_imagePaths.icMoveEmail, color: AppColor.colorButton, fit: BoxFit.fill),
onPressed: () {
buildIconWeb(
icon: SvgPicture.asset(_imagePaths.icMoveEmail, fit: BoxFit.fill),
tooltip: AppLocalizations.of(_context).move_to_mailbox,
onTap: () {
if (_presentationEmail != null) {
_onEmailActionClick?.call(_presentationEmail!, EmailActionType.move);
}
}),
IconButton(
key: Key('button_mark_as_star_email'),
icon: SvgPicture.asset(
(_presentationEmail != null && _presentationEmail!.isFlaggedEmail())
? _imagePaths.icStar
: _imagePaths.icUnStar,
fit: BoxFit.fill),
onPressed: () {
buildIconWeb(
icon: SvgPicture.asset((_presentationEmail != null && _presentationEmail!.isFlaggedEmail()) ? _imagePaths.icStar : _imagePaths.icUnStar, fit: BoxFit.fill),
tooltip: (_presentationEmail != null && _presentationEmail!.isFlaggedEmail())
? AppLocalizations.of(_context).mark_as_unstar
: AppLocalizations.of(_context).mark_as_star,
onTap: () {
if (_presentationEmail != null) {
_onEmailActionClick?.call(_presentationEmail!,
_presentationEmail!.isFlaggedEmail() ? EmailActionType.markAsUnStar : EmailActionType.markAsStar);
_onEmailActionClick?.call(_presentationEmail!, _presentationEmail!.isFlaggedEmail() ? EmailActionType.markAsUnStar : EmailActionType.markAsStar);
}
}),
IconButton(
key: Key('button_delete_email'),
icon: SvgPicture.asset(_imagePaths.icDeleteEmail, color: AppColor.colorButton, fit: BoxFit.fill),
onPressed: () {
if (_presentationEmail != null) {
_onEmailActionClick?.call(_presentationEmail!, EmailActionType.delete);
}
}),
_buildMoreButton(),
Padding(
padding: EdgeInsets.only(left: 10, right: 16),
child: buildIconWebHasPosition(
_context,
tooltip: AppLocalizations.of(_context).more,
icon: SvgPicture.asset(_imagePaths.icMore, fit: BoxFit.fill),
onTap: () {
if (_presentationEmail != null && _responsiveUtils.isMobile(_context)) {
_onMoreActionClick?.call(_presentationEmail!, null);
}
},
onTapDown: (position) {
if (_presentationEmail != null && !_responsiveUtils.isMobile(_context)) {
_onMoreActionClick?.call(_presentationEmail!, position);
}
})),
]
);
}
Widget _buildMoreButton() {
return Material(
key: Key('button_more_email'),
borderRadius: BorderRadius.circular(12),
color: Colors.transparent,
child: Padding(
padding: EdgeInsets.only(left: 10, right: 16),
child: GestureDetector(
onTap: () {
if (_presentationEmail != null && _responsiveUtils.isMobileDevice(_context)) {
_onMoreActionClick?.call(_presentationEmail!, null);
}
},
child: SvgPicture.asset(_imagePaths.icMore, color: AppColor.colorButton, fit: BoxFit.fill),
onTapDown: (detail) {
if (_presentationEmail != null && !_responsiveUtils.isMobileDevice(_context)) {
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,
);
_onMoreActionClick?.call(_presentationEmail!, position);
}
})
)
);
}
}
@@ -91,22 +91,23 @@ class BottomBarMailWidgetBuilder {
}})
..text(AppLocalizations.of(_context).forward, isVertical: _responsiveUtils.isMobile(_context)))
.build(),
(ButtonBuilder(_imagePaths.icNewMessage)
..key(Key('button_new_message'))
..size(20)
..paddingIcon(EdgeInsets.only(
top: _responsiveUtils.isMobileDevice(_context) ? 10 : 16,
bottom: _responsiveUtils.isMobileDevice(_context) ? 8 : 16,
right: 5))
..textStyle(TextStyle(
fontSize: _responsiveUtils.isMobileDevice(_context) ? 12 : 16,
color: AppColor.colorTextButton))
..onPressActionClick(() {
if (_onPressEmailActionClick != null) {
_onPressEmailActionClick!(EmailActionType.compose);
}})
..text(AppLocalizations.of(_context).new_message, isVertical: _responsiveUtils.isMobile(_context)))
.build()
if (!_responsiveUtils.isDesktop(_context))
(ButtonBuilder(_imagePaths.icNewMessage)
..key(Key('button_new_message'))
..size(20)
..paddingIcon(EdgeInsets.only(
top: _responsiveUtils.isMobileDevice(_context) ? 10 : 16,
bottom: _responsiveUtils.isMobileDevice(_context) ? 8 : 16,
right: 5))
..textStyle(TextStyle(
fontSize: _responsiveUtils.isMobileDevice(_context) ? 12 : 16,
color: AppColor.colorTextButton))
..onPressActionClick(() {
if (_onPressEmailActionClick != null) {
_onPressEmailActionClick!(EmailActionType.compose);
}})
..text(AppLocalizations.of(_context).new_message, isVertical: _responsiveUtils.isMobile(_context)))
.build()
]
);
}
@@ -54,10 +54,10 @@ class EmailContentItemBuilder {
}
case EmailContentType.textPlain:
return Padding(
padding: EdgeInsets.zero,
padding: EdgeInsets.only(top: 20),
child: Text(
_emailContent.content,
style: TextStyle(fontSize: 14, color: AppColor.colorNameEmail)));
style: TextStyle(fontSize: 14, color: AppColor.colorNameEmail, fontWeight: FontWeight.normal)));
case EmailContentType.other:
return SizedBox.shrink();
}
@@ -2,11 +2,9 @@ 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/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/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/state_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart';
@@ -44,7 +42,6 @@ class MailboxBindings extends BaseBindings {
void bindingsController() {
Get.put(MailboxController(
Get.find<GetAllMailboxInteractor>(),
Get.find<DeleteCredentialInteractor>(),
Get.find<RefreshAllMailboxInteractor>(),
Get.find<CreateNewMailboxInteractor>(),
Get.find<SearchMailboxInteractor>(),
@@ -56,7 +53,6 @@ class MailboxBindings extends BaseBindings {
Get.find<AppToast>(),
Get.find<ImagePaths>(),
Get.find<ResponsiveUtils>(),
Get.find<CachingManager>(),
));
}
@@ -75,7 +71,6 @@ class MailboxBindings extends BaseBindings {
@override
void bindingsInteractor() {
Get.lazyPut(() => DeleteCredentialInteractor(Get.find<CredentialRepository>()));
Get.lazyPut(() => GetAllMailboxInteractor(Get.find<MailboxRepository>()));
Get.lazyPut(() => RefreshAllMailboxInteractor(Get.find<MailboxRepository>()));
Get.lazyPut(() => CreateNewMailboxInteractor(Get.find<MailboxRepository>()));
@@ -12,12 +12,10 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:rxdart/transformers.dart';
import 'package:tmail_ui_user/features/base/base_mailbox_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';
import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/create_new_mailbox_state.dart';
@@ -59,7 +57,6 @@ class MailboxController extends BaseMailboxController {
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
final GetAllMailboxInteractor _getAllMailboxInteractor;
final DeleteCredentialInteractor _deleteCredentialInteractor;
final RefreshAllMailboxInteractor _refreshAllMailboxInteractor;
final CreateNewMailboxInteractor _createNewMailboxInteractor;
final SearchMailboxInteractor _searchMailboxInteractor;
@@ -70,7 +67,6 @@ class MailboxController extends BaseMailboxController {
final AppToast _appToast;
final ImagePaths _imagePaths;
final ResponsiveUtils responsiveUtils;
final CachingManager _cachingManager;
final listMailboxSearched = <PresentationMailbox>[].obs;
final searchState = SearchState.initial().obs;
@@ -87,7 +83,6 @@ class MailboxController extends BaseMailboxController {
MailboxController(
this._getAllMailboxInteractor,
this._deleteCredentialInteractor,
this._refreshAllMailboxInteractor,
this._createNewMailboxInteractor,
this._searchMailboxInteractor,
@@ -99,7 +94,6 @@ class MailboxController extends BaseMailboxController {
this._appToast,
this._imagePaths,
this.responsiveUtils,
this._cachingManager,
) : super(treeBuilder);
@override
@@ -283,14 +277,6 @@ class MailboxController extends BaseMailboxController {
_openMailboxEventController.add(OpenMailboxViewEvent(context, presentationMailboxSelected));
}
void _deleteCredential() async {
await _deleteCredentialInteractor.execute();
}
void _clearAllCache() async {
await _cachingManager.clearAll();
}
void goToCreateNewMailboxView() async {
final accountId = mailboxDashBoardController.accountId.value;
if (accountId != null) {
@@ -612,12 +598,6 @@ class MailboxController extends BaseMailboxController {
mailboxDashBoardController.closeDrawer();
}
void logoutAction() {
_deleteCredential();
_clearAllCache();
pushAndPopAll(AppRoutes.LOGIN);
}
@override
void dispose() {
_openMailboxEventController.close();
@@ -198,7 +198,7 @@ class MailboxView extends GetWidget<MailboxController> {
_imagePaths,
context,
controller.mailboxDashBoardController.userProfile.value)
..addOnLogoutAction(() => controller.logoutAction()))
..addOnLogoutAction(() => controller.mailboxDashBoardController.logoutAction()))
.build()));
}
@@ -71,15 +71,14 @@ class MailBoxFolderTileBuilder {
trailing: _mailboxNode.hasChildren()
? Padding(
padding: EdgeInsets.only(right: 0, left: 16),
child: IconButton(
padding: EdgeInsets.zero,
color: AppColor.primaryColor,
child: buildIconWeb(
icon: SvgPicture.asset(
_mailboxNode.expandMode == ExpandMode.EXPAND ? _imagePaths.icExpandFolder : _imagePaths.icFolderArrow,
color: AppColor.colorArrowUserMailbox,
fit: BoxFit.fill),
onPressed: () => _onExpandFolderActionClick?.call(_mailboxNode)
))
splashRadius: 15,
tooltip: _mailboxNode.expandMode == ExpandMode.EXPAND ? AppLocalizations.of(_context).collapse : AppLocalizations.of(_context).expand,
onTap: () => _onExpandFolderActionClick?.call(_mailboxNode)))
: null
),
Padding(
@@ -9,12 +9,14 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/base/reloadable/reloadable_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';
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/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.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';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_user_profile_interactor.dart';
@@ -35,6 +37,8 @@ class MailboxDashBoardController extends ReloadableController {
final AppToast _appToast = Get.find<AppToast>();
final ImagePaths _imagePaths = Get.find<ImagePaths>();
final RemoveEmailDraftsInteractor _removeEmailDraftsInteractor = Get.find<RemoveEmailDraftsInteractor>();
final DeleteCredentialInteractor _deleteCredentialInteractor = Get.find<DeleteCredentialInteractor>();
final CachingManager _cachingManager = Get.find<CachingManager>();
final scaffoldKey = GlobalKey<ScaffoldState>();
final selectedMailbox = Rxn<PresentationMailbox>();
@@ -179,6 +183,8 @@ class MailboxDashBoardController extends ReloadableController {
scaffoldKey.currentState?.openEndDrawer();
}
bool get isDrawerOpen => scaffoldKey.currentState?.isDrawerOpen == true;
bool isSearchActive() {
return searchState.value.searchStatus == SearchStatus.ACTIVE;
}
@@ -273,6 +279,20 @@ class MailboxDashBoardController extends ReloadableController {
}
}
void _deleteCredential() async {
await _deleteCredentialInteractor.execute();
}
void _clearAllCache() async {
await _cachingManager.clearAll();
}
void logoutAction() {
_deleteCredential();
if (!kIsWeb) _clearAllCache();
pushAndPopAll(AppRoutes.LOGIN);
}
@override
void onClose() {
searchInputController.dispose();
@@ -22,32 +22,18 @@ class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> {
key: controller.scaffoldKey,
drawer: ResponsiveWidget(
responsiveUtils: _responsiveUtils,
mobile: Container(child: MailboxView(), width: _responsiveUtils.getSizeScreenWidth(context)),
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: Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(flex: 1, child: MailboxView()),
Expanded(flex: 3, child: _buildThreadAndEmailContainer(context)),
],
),
),
tabletLarge: Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(flex: 2, child: MailboxView()),
Expanded(flex: 4, child: _buildThreadAndEmailContainer(context)),
],
),
),
desktop: _buildDesktopView(context),
tabletLarge: _buildTabletLargeView(context),
tablet: ThreadView(),
mobile: ThreadView()
),
@@ -93,4 +79,40 @@ class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> {
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)),
],
),
);
}
}
@@ -0,0 +1,37 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/app_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
mixin UserSettingPopupMenuMixin {
final _imagePaths = Get.find<ImagePaths>();
void openUserSettingAction(BuildContext context, RelativeRect? position, List<PopupMenuEntry> 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);
}
List<PopupMenuEntry> popupMenuUserSettingActionTile(BuildContext context, Function? onCallBack) {
return [
PopupMenuItem(padding: EdgeInsets.symmetric(horizontal: 8), child: logoutAction(context, onCallBack)),
];
}
Widget logoutAction(BuildContext context, Function? onCallBack) {
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) => onCallBack?.call()))
.build();
}
}
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/caching/caching_manager.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
@@ -40,7 +41,7 @@ class SessionController extends GetxController {
void _goToLogin() {
_deleteCredential();
_clearAllCache();
if (!kIsWeb) _clearAllCache();
pushAndPop(AppRoutes.LOGIN);
}
@@ -1,8 +1,6 @@
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';
@@ -15,9 +13,6 @@ 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';
@@ -58,8 +53,6 @@ class ThreadBindings extends BaseBindings {
Get.find<LoadMoreEmailsInMailboxInteractor>(),
Get.find<SearchEmailInteractor>(),
Get.find<SearchMoreEmailInteractor>(),
Get.find<DeleteCredentialInteractor>(),
Get.find<CachingManager>(),
));
}
@@ -97,19 +90,16 @@ class ThreadBindings extends BaseBindings {
Get.lazyPut(() => LoadMoreEmailsInMailboxInteractor(Get.find<ThreadRepository>()));
Get.lazyPut(() => SearchEmailInteractor(Get.find<ThreadRepository>()));
Get.lazyPut(() => SearchMoreEmailInteractor(Get.find<ThreadRepository>()));
Get.lazyPut(() => DeleteCredentialInteractor(Get.find<CredentialRepository>()));
}
@override
void bindingsRepository() {
Get.lazyPut<CredentialRepository>(() => Get.find<CredentialRepositoryImpl>());
Get.lazyPut<ThreadRepository>(() => Get.find<ThreadRepositoryImpl>());
Get.lazyPut<EmailRepository>(() => Get.find<EmailRepositoryImpl>());
}
@override
void bindingsRepositoryImpl() {
Get.lazyPut(() => CredentialRepositoryImpl(Get.find<SharedPreferences>()));
Get.lazyPut(() => ThreadRepositoryImpl(
{
DataSourceType.network: Get.find<ThreadDataSource>(),
@@ -15,7 +15,6 @@ 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';
@@ -26,7 +25,6 @@ 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';
@@ -72,8 +70,6 @@ class ThreadController extends BaseController {
final LoadMoreEmailsInMailboxInteractor _loadMoreEmailsInMailboxInteractor;
final SearchEmailInteractor _searchEmailInteractor;
final SearchMoreEmailInteractor _searchMoreEmailInteractor;
final DeleteCredentialInteractor _deleteCredentialInteractor;
final CachingManager _cachingManager;
final emailList = <PresentationEmail>[].obs;
final emailListSearch = <PresentationEmail>[].obs;
@@ -107,8 +103,6 @@ class ThreadController extends BaseController {
this._loadMoreEmailsInMailboxInteractor,
this._searchEmailInteractor,
this._searchMoreEmailInteractor,
this._deleteCredentialInteractor,
this._cachingManager,
);
@override
@@ -752,30 +746,6 @@ class ThreadController extends BaseController {
}
}
void openUserSettingAction(BuildContext context, RelativeRect? position, List<PopupMenuEntry> 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();
}
@@ -4,11 +4,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/user_setting_popup_menu_mixin.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
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';
@@ -17,7 +17,7 @@ import 'package:tmail_ui_user/features/thread/presentation/widgets/search_app_ba
import 'package:tmail_ui_user/features/thread/presentation/widgets/suggestion_box_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ThreadView extends GetWidget<ThreadController> {
class ThreadView extends GetWidget<ThreadController> with UserSettingPopupMenuMixin {
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
@@ -92,8 +92,10 @@ class ThreadView extends GetWidget<ThreadController> {
..backgroundColor(Colors.white)
..textColor(Colors.black)
..context(context)
..addOnTapAvatarActionWithPositionClick((position) =>
controller.openUserSettingAction(context, position, _popupMenuUserSettingActionTile(context)))
..addOnTapAvatarActionWithPositionClick((position) => openUserSettingAction(
context,
position,
popupMenuUserSettingActionTile(context, () => controller.mailboxDashBoardController.logoutAction())))
..addBoxShadows([BoxShadow(
color: AppColor.colorShadowBgContentEmail,
spreadRadius: 1, blurRadius: 1, offset: Offset(0, 0.5))])
@@ -631,20 +633,4 @@ class ThreadView extends GetWidget<ThreadController> {
}
});
}
List<PopupMenuEntry> _popupMenuUserSettingActionTile(BuildContext context) {
return [
PopupMenuItem(padding: EdgeInsets.symmetric(horizontal: 8), child: _logoutAction(context)),
];
}
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();
}
}
@@ -178,9 +178,9 @@ class AppBarThreadWidgetBuilder {
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () => !_responsiveUtils.isDesktop(_context) ? _onOpenListMailboxActionClick?.call() : null,
onTap: () => !_responsiveUtils.isTabletLarge(_context) ? _onOpenListMailboxActionClick?.call() : null,
child: Padding(
padding: !_responsiveUtils.isDesktop(_context) ? EdgeInsets.zero : EdgeInsets.only(bottom: 8, top: 8),
padding: !_responsiveUtils.isTabletLarge(_context) ? EdgeInsets.zero : EdgeInsets.only(bottom: 8, top: 8),
child: Container(
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
@@ -191,14 +191,14 @@ class AppBarThreadWidgetBuilder {
overflow: GetPlatform.isWeb ? TextOverflow.clip : TextOverflow.ellipsis,
style: TextStyle(fontSize: 21, color: AppColor.colorNameEmail, fontWeight: FontWeight.w700))
))),
if (!_responsiveUtils.isDesktop(_context))
if (!_responsiveUtils.isTabletLarge(_context))
Transform(
transform: Matrix4.translationValues(-8.0, 0.0, 0.0),
child: IconButton(
padding: EdgeInsets.zero,
color: AppColor.baseTextColor,
icon: SvgPicture.asset(_imagePaths.icChevronDown, width: 20, height: 16, fit: BoxFit.fill),
onPressed: () => !_responsiveUtils.isDesktop(_context) ? _onOpenListMailboxActionClick?.call() : null))
onPressed: () => !_responsiveUtils.isTabletLarge(_context) ? _onOpenListMailboxActionClick?.call() : null))
]
);
}
@@ -208,9 +208,9 @@ class AppBarThreadWidgetBuilder {
var widthSiblingsWidget = 220;
if (_responsiveUtils.isTablet(_context)) {
width = width * 0.7;
widthSiblingsWidget = 300;
widthSiblingsWidget = 250;
} else if (_responsiveUtils.isTabletLarge(_context)) {
width = width * 0.35;
width = width * 0.6;
widthSiblingsWidget = 250;
} else if (_responsiveUtils.isDesktop(_context)) {
width = width * 0.25;
@@ -862,4 +862,30 @@ class AppLocalizations {
name: 'select',
);
}
String get more {
return Intl.message(
'More',
name: 'more',
);
}
String get back {
return Intl.message(
'Back',
name: 'back',
);
}
String get expand {
return Intl.message(
'Expand',
name: 'expand');
}
String get collapse {
return Intl.message(
'Collapse',
name: 'collapse');
}
}