TF-295 Apply new UI for composer web browser
This commit is contained in:
@@ -127,6 +127,7 @@ class ComposerBindings extends BaseBindings {
|
||||
Get.find<GetAutoCompleteWithDeviceContactInteractor>(),
|
||||
Get.find<AppToast>(),
|
||||
Get.find<ImagePaths>(),
|
||||
Get.find<ResponsiveUtils>(),
|
||||
Get.find<Uuid>(),
|
||||
Get.find<DeviceInfoPlugin>(),
|
||||
Get.find<LocalFilePickerInteractor>(),
|
||||
|
||||
@@ -19,8 +19,10 @@ import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email_body_value.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart';
|
||||
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:permission_handler/permission_handler.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/auto_complete_pattern.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/contact_suggestion_source.dart';
|
||||
@@ -35,15 +37,16 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_inter
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/update_email_drafts_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/upload_mutiple_attachment_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/state/local_file_picker_state.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/usecases/local_file_picker_interactor.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class ComposerController extends BaseController {
|
||||
@@ -51,11 +54,14 @@ class ComposerController extends BaseController {
|
||||
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
||||
|
||||
final expandMode = ExpandMode.COLLAPSE.obs;
|
||||
final expandModeAttachments = ExpandMode.EXPAND.obs;
|
||||
final composerArguments = Rxn<ComposerArguments>();
|
||||
final isEnableEmailSendButton = false.obs;
|
||||
final isInitialRecipient = false.obs;
|
||||
final attachments = <Attachment>[].obs;
|
||||
final emailContents = <EmailContent>[].obs;
|
||||
final subjectEmail = Rxn<String>();
|
||||
final screenDisplayMode = ScreenDisplayMode.normal.obs;
|
||||
|
||||
final SendEmailInteractor _sendEmailInteractor;
|
||||
final SaveEmailAddressesInteractor _saveEmailAddressInteractor;
|
||||
@@ -63,6 +69,7 @@ class ComposerController extends BaseController {
|
||||
final GetAutoCompleteWithDeviceContactInteractor _getAutoCompleteWithDeviceContactInteractor;
|
||||
final AppToast _appToast;
|
||||
final ImagePaths _imagePaths;
|
||||
final ResponsiveUtils responsiveUtils;
|
||||
final Uuid _uuid;
|
||||
final LocalFilePickerInteractor _localFilePickerInteractor;
|
||||
final UploadMultipleAttachmentInteractor _uploadMultipleAttachmentInteractor;
|
||||
@@ -74,7 +81,6 @@ class ComposerController extends BaseController {
|
||||
List<EmailAddress> listToEmailAddress = <EmailAddress>[];
|
||||
List<EmailAddress> listCcEmailAddress = <EmailAddress>[];
|
||||
List<EmailAddress> listBccEmailAddress = <EmailAddress>[];
|
||||
String? _subjectEmail;
|
||||
ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.localContact;
|
||||
HtmlEditorApi? htmlEditorApi;
|
||||
final HtmlEditorBrowser.HtmlEditorController htmlControllerBrowser = HtmlEditorBrowser.HtmlEditorController();
|
||||
@@ -85,8 +91,13 @@ class ComposerController extends BaseController {
|
||||
final bccEmailAddressController = TextEditingController();
|
||||
|
||||
List<Attachment> initialAttachments = <Attachment>[];
|
||||
String? _textEditor;
|
||||
|
||||
void setSubjectEmail(String subject) => _subjectEmail = subject;
|
||||
void setTextEditor(String? text) => _textEditor = text;
|
||||
|
||||
String? get textEditor => _textEditor;
|
||||
|
||||
void setSubjectEmail(String subject) => subjectEmail.value = subject;
|
||||
|
||||
Future<String> _getEmailBodyText({bool onlyText = false}) async {
|
||||
if (kIsWeb) {
|
||||
@@ -107,6 +118,7 @@ class ComposerController extends BaseController {
|
||||
this._getAutoCompleteWithDeviceContactInteractor,
|
||||
this._appToast,
|
||||
this._imagePaths,
|
||||
this.responsiveUtils,
|
||||
this._uuid,
|
||||
this._deviceInfoPlugin,
|
||||
this._localFilePickerInteractor,
|
||||
@@ -178,7 +190,7 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
|
||||
void _initEmail() {
|
||||
final arguments = Get.arguments;
|
||||
final arguments = kIsWeb ? mailboxDashBoardController.routerArguments : Get.arguments;
|
||||
if (arguments is ComposerArguments) {
|
||||
composerArguments.value = arguments;
|
||||
if (arguments.emailActionType == EmailActionType.edit) {
|
||||
@@ -211,6 +223,14 @@ class ComposerController extends BaseController {
|
||||
return '';
|
||||
}
|
||||
|
||||
String? get initTextEditorComposer {
|
||||
if (composerArguments.value?.emailActionType == EmailActionType.compose) {
|
||||
return textEditor;
|
||||
} else {
|
||||
return textEditor ?? getContentEmail();
|
||||
}
|
||||
}
|
||||
|
||||
Tuple2<String, String>? _getHeaderEmailQuoted(String locale, ComposerArguments arguments) {
|
||||
if (arguments.presentationEmail != null) {
|
||||
final sentDate = arguments.presentationEmail?.sentAt;
|
||||
@@ -226,8 +246,9 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
|
||||
void _initToEmailAddress(ComposerArguments arguments) {
|
||||
if (arguments.presentationEmail != null) {
|
||||
final userEmailAddress = EmailAddress(null, arguments.userProfile.email);
|
||||
final userProfile = mailboxDashBoardController.userProfile.value;
|
||||
if (arguments.presentationEmail != null && userProfile != null) {
|
||||
final userEmailAddress = EmailAddress(null, userProfile.email);
|
||||
|
||||
final recipients = arguments.presentationEmail!.generateRecipientsEmailAddressForComposer(arguments.emailActionType, arguments.mailboxRole);
|
||||
|
||||
@@ -302,12 +323,12 @@ class ComposerController extends BaseController {
|
||||
return emailQuotedHtml;
|
||||
}
|
||||
|
||||
Future<Email> _generateEmail(ComposerArguments arguments, {bool asDrafts = false}) async {
|
||||
Future<Email> _generateEmail(Map<Role, MailboxId> mapDefaultMailboxId, UserProfile userProfile, {bool asDrafts = false}) async {
|
||||
final generateEmailId = EmailId(Id(_uuid.v1()));
|
||||
final outboxMailboxId = arguments.mapMailboxId[PresentationMailbox.roleOutbox];
|
||||
final draftMailboxId = arguments.mapMailboxId[PresentationMailbox.roleDrafts];
|
||||
final outboxMailboxId = mapDefaultMailboxId[PresentationMailbox.roleOutbox];
|
||||
final draftMailboxId = mapDefaultMailboxId[PresentationMailbox.roleDrafts];
|
||||
final listFromEmailAddress = {
|
||||
EmailAddress(null, arguments.userProfile.email)
|
||||
EmailAddress(null, userProfile.email)
|
||||
};
|
||||
final generatePartId = PartId(_uuid.v1());
|
||||
final generateBlobId = Id(_uuid.v1());
|
||||
@@ -323,7 +344,7 @@ class ComposerController extends BaseController {
|
||||
cc: listCcEmailAddress.toSet(),
|
||||
bcc: listBccEmailAddress.toSet(),
|
||||
keywords: asDrafts ? {KeyWordIdentifier.emailDraft : true} : null,
|
||||
subject: _subjectEmail,
|
||||
subject: subjectEmail.value,
|
||||
htmlBody: {
|
||||
EmailBodyPart(
|
||||
partId: generatePartId,
|
||||
@@ -363,30 +384,44 @@ class ComposerController extends BaseController {
|
||||
clearFocusEditor(context);
|
||||
|
||||
if (isEnableEmailSendButton.value) {
|
||||
final arguments = composerArguments.value;
|
||||
if (arguments != null) {
|
||||
_saveEmailAddress();
|
||||
|
||||
final email = await _generateEmail(arguments);
|
||||
final accountId = arguments.session.accounts.keys.first;
|
||||
final sentMailboxId = arguments.mapMailboxId[PresentationMailbox.roleSent];
|
||||
final submissionCreateId = Id(_uuid.v1());
|
||||
|
||||
mailboxDashBoardController.consumeState(_sendEmailInteractor.execute(
|
||||
accountId,
|
||||
EmailRequest(
|
||||
email,
|
||||
submissionCreateId,
|
||||
mailboxIdSaved: sentMailboxId,
|
||||
emailIdDestroyed: arguments.emailActionType == EmailActionType.edit ? arguments.presentationEmail?.id : null)));
|
||||
if (subjectEmail.value?.isNotEmpty == true) {
|
||||
_handleSendMessages(context);
|
||||
} else {
|
||||
_showConfirmDialogSendEmail(context);
|
||||
}
|
||||
|
||||
popBack();
|
||||
} else {
|
||||
_appToast.showErrorToast(AppLocalizations.of(context).your_email_should_have_at_least_one_recipient);
|
||||
}
|
||||
}
|
||||
|
||||
void _handleSendMessages(BuildContext context) async {
|
||||
final arguments = composerArguments.value;
|
||||
final session = mailboxDashBoardController.sessionCurrent;
|
||||
final mapDefaultMailboxId = mailboxDashBoardController.mapDefaultMailboxId;
|
||||
final userProfile = mailboxDashBoardController.userProfile.value;
|
||||
if (arguments != null && session != null && mapDefaultMailboxId.isNotEmpty && userProfile != null) {
|
||||
_saveEmailAddress();
|
||||
|
||||
final email = await _generateEmail(mapDefaultMailboxId, userProfile);
|
||||
final accountId = session.accounts.keys.first;
|
||||
final sentMailboxId = mapDefaultMailboxId[PresentationMailbox.roleSent];
|
||||
final submissionCreateId = Id(_uuid.v1());
|
||||
|
||||
mailboxDashBoardController.consumeState(_sendEmailInteractor.execute(
|
||||
accountId,
|
||||
EmailRequest(email, submissionCreateId, mailboxIdSaved: sentMailboxId,
|
||||
emailIdDestroyed: arguments.emailActionType == EmailActionType.edit
|
||||
? arguments.presentationEmail?.id
|
||||
: null)));
|
||||
}
|
||||
|
||||
if (kIsWeb) {
|
||||
closeComposerWeb();
|
||||
} else {
|
||||
popBack();
|
||||
}
|
||||
}
|
||||
|
||||
void _saveEmailAddress() async {
|
||||
final listEmailAddressCanSave = Set<EmailAddress>();
|
||||
listEmailAddressCanSave.addAll(listToEmailAddress + listCcEmailAddress + listBccEmailAddress);
|
||||
@@ -460,10 +495,10 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
|
||||
void _uploadAttachmentsAction(List<FileInfo> pickedFiles) async {
|
||||
if (composerArguments.value != null) {
|
||||
final accountId = composerArguments.value!.session.accounts.keys.first;
|
||||
final uploadUrl = composerArguments.value!.session.getUploadUrl(accountId);
|
||||
|
||||
final session = mailboxDashBoardController.sessionCurrent;
|
||||
if (session != null) {
|
||||
final accountId = session.accounts.keys.first;
|
||||
final uploadUrl = session.getUploadUrl(accountId);
|
||||
consumeState(_uploadMultipleAttachmentInteractor.execute(pickedFiles, accountId, uploadUrl));
|
||||
}
|
||||
}
|
||||
@@ -508,9 +543,9 @@ class ComposerController extends BaseController {
|
||||
final oldEmailBody = kIsWeb ? getContentEmail() : '\n${getContentEmail()}\n';
|
||||
final isEmailBodyChanged = !oldEmailBody.isSame(newEmailBody);
|
||||
|
||||
final newEmailSubject = _subjectEmail;
|
||||
final subjectEmail = arguments.presentationEmail?.getEmailTitle().trim() ?? '';
|
||||
final oldEmailSubject = arguments.emailActionType.getSubjectComposer(Get.context!, subjectEmail);
|
||||
final newEmailSubject = subjectEmail.value;
|
||||
final titleEmail = arguments.presentationEmail?.getEmailTitle().trim() ?? '';
|
||||
final oldEmailSubject = arguments.emailActionType.getSubjectComposer(Get.context!, titleEmail);
|
||||
final isEmailSubjectChanged = !oldEmailSubject.isSame(newEmailSubject);
|
||||
|
||||
final recipients = arguments.presentationEmail
|
||||
@@ -544,13 +579,18 @@ class ComposerController extends BaseController {
|
||||
clearFocusEditor(context);
|
||||
|
||||
final arguments = composerArguments.value;
|
||||
if (arguments != null && Get.context != null) {
|
||||
final mapDefaultMailboxId = mailboxDashBoardController.mapDefaultMailboxId;
|
||||
final userProfile = mailboxDashBoardController.userProfile.value;
|
||||
final session = mailboxDashBoardController.sessionCurrent;
|
||||
|
||||
if (arguments != null && Get.context != null && mapDefaultMailboxId.isNotEmpty
|
||||
&& userProfile != null && session != null) {
|
||||
final isChanged = await _isEmailChanged(arguments);
|
||||
if (isChanged) {
|
||||
_saveEmailAddress();
|
||||
|
||||
final newEmail = await _generateEmail(arguments, asDrafts: true);
|
||||
final accountId = arguments.session.accounts.keys.first;
|
||||
final newEmail = await _generateEmail(mapDefaultMailboxId, userProfile, asDrafts: true);
|
||||
final accountId = session.accounts.keys.first;
|
||||
final oldEmail = arguments.presentationEmail;
|
||||
|
||||
if (arguments.emailActionType == EmailActionType.edit && oldEmail != null) {
|
||||
@@ -563,10 +603,10 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
|
||||
void _getEmailContentAction(ComposerArguments arguments) async {
|
||||
final baseDownloadUrl = arguments.session.getDownloadUrl();
|
||||
final accountId = arguments.session.accounts.keys.first;
|
||||
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl();
|
||||
final accountId = mailboxDashBoardController.sessionCurrent?.accounts.keys.first;
|
||||
final emailId = arguments.presentationEmail?.id;
|
||||
if (emailId != null) {
|
||||
if (emailId != null && baseDownloadUrl != null && accountId != null) {
|
||||
consumeState(_getEmailContentInteractor.execute(accountId, emailId, baseDownloadUrl));
|
||||
}
|
||||
}
|
||||
@@ -594,7 +634,7 @@ class ComposerController extends BaseController {
|
||||
if (arguments.emailActionType == EmailActionType.edit) {
|
||||
return arguments.presentationEmail?.from?.first.emailAddress ?? '';
|
||||
} else {
|
||||
return arguments.userProfile.email;
|
||||
return mailboxDashBoardController.userProfile.value?.email ?? '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
@@ -603,6 +643,69 @@ class ComposerController extends BaseController {
|
||||
void clearFocusEditor(BuildContext context) {
|
||||
if (!kIsWeb) {
|
||||
htmlEditorApi?.unfocus(context);
|
||||
htmlControllerBrowser.clearFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void closeComposerWeb() {
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.none);
|
||||
}
|
||||
|
||||
void minimizeComposer() {
|
||||
_updateTextForEditor();
|
||||
final newDisplayMode = screenDisplayMode.value == ScreenDisplayMode.minimize ? ScreenDisplayMode.normal : ScreenDisplayMode.minimize;
|
||||
screenDisplayMode.value = newDisplayMode;
|
||||
}
|
||||
|
||||
void setFullScreenComposer() {
|
||||
_updateTextForEditor();
|
||||
final newDisplayMode = screenDisplayMode.value == ScreenDisplayMode.fullScreen ? ScreenDisplayMode.normal : ScreenDisplayMode.fullScreen;
|
||||
screenDisplayMode.value = newDisplayMode;
|
||||
}
|
||||
|
||||
void _updateTextForEditor() async {
|
||||
final textCurrent = await htmlControllerBrowser.getText();
|
||||
log('_updateTextForEditor() | textCurrent: $textCurrent');
|
||||
htmlControllerBrowser.insertHtml(textCurrent);
|
||||
}
|
||||
|
||||
void deleteComposer() {
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.none);
|
||||
}
|
||||
|
||||
void toggleDisplayAttachments() {
|
||||
final newExpandMode = expandModeAttachments.value == ExpandMode.COLLAPSE ? ExpandMode.EXPAND : ExpandMode.COLLAPSE;
|
||||
expandModeAttachments.value = newExpandMode;
|
||||
}
|
||||
|
||||
void _showConfirmDialogSendEmail(BuildContext context) {
|
||||
if (responsiveUtils.isMobileDevice(context)) {
|
||||
(ConfirmationDialogActionSheetBuilder(context)
|
||||
..messageText(AppLocalizations.of(context).message_confirm_send_email)
|
||||
..styleConfirmButton(TextStyle(fontSize: 20, fontWeight: FontWeight.normal, color: Colors.black))
|
||||
..onCancelAction(AppLocalizations.of(context).cancel, () => popBack())
|
||||
..onConfirmAction(AppLocalizations.of(context).send, () {
|
||||
popBack();
|
||||
_handleSendMessages(context);
|
||||
})).show();
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||
builder: (BuildContext context) => PointerInterceptor(child: (ConfirmDialogBuilder(_imagePaths)
|
||||
..key(Key('confirm_dialog_send_message'))
|
||||
..content(AppLocalizations.of(context).message_confirm_send_email)
|
||||
..colorConfirmButton(AppColor.colorTextButton)
|
||||
..colorCancelButton(AppColor.colorCancelButton)
|
||||
..styleContent(TextStyle(fontSize: 15, fontWeight: FontWeight.normal, color: AppColor.colorMessageDialog))
|
||||
..styleTextCancelButton(TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorTextButton))
|
||||
..styleTextConfirmButton(TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: Colors.white))
|
||||
..onConfirmButtonAction(AppLocalizations.of(context).send, () {
|
||||
popBack();
|
||||
_handleSendMessages(context);
|
||||
})
|
||||
..onCancelButtonAction(AppLocalizations.of(context).cancel, () => popBack()))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,529 @@
|
||||
import 'package:core/core.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:html_editor_enhanced/html_editor.dart' as HtmlEditorBrowser;
|
||||
import 'package:model/model.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/upload_attachment_state.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/email_address_input_builder.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class ComposerView extends GetWidget<ComposerController> {
|
||||
|
||||
final responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
final imagePaths = Get.find<ImagePaths>();
|
||||
final appToast = Get.find<AppToast>();
|
||||
final keyboardUtils = Get.find<KeyboardUtils>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveWidget(
|
||||
responsiveUtils: responsiveUtils,
|
||||
mobile: Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: Align(alignment: Alignment.center, child: Card(
|
||||
color: Colors.transparent,
|
||||
child: Container(
|
||||
color: Colors.white,
|
||||
child: PointerInterceptor(child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Obx(() => _buildAppBarForMobile(context, controller.isEnableEmailSendButton.value)),
|
||||
SizedBox(height: 16),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildEmailAddress(context)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildSubjectEmail(context)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Expanded(child: Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: _buildEditorAndAttachments(context))),
|
||||
]
|
||||
))
|
||||
)
|
||||
))
|
||||
),
|
||||
desktop: Obx(() {
|
||||
return Stack(children: [
|
||||
if (controller.screenDisplayMode == ScreenDisplayMode.normal)
|
||||
Positioned(right: 10, bottom: 10, child: Card(
|
||||
elevation: 20,
|
||||
color: Colors.transparent,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
width: responsiveUtils.getSizeWidthScreen(context) * 0.5,
|
||||
height: responsiveUtils.getSizeHeightScreen(context) * 0.65,
|
||||
child: PointerInterceptor(child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 5),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildAppBar(context)),
|
||||
SizedBox(height: 10),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildTitleComposer(context)),
|
||||
SizedBox(height: 16),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildEmailAddress(context)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildSubjectEmail(context)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Expanded(child: Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: _buildEditorAndAttachments(context))),
|
||||
Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)),
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
)),
|
||||
if (controller.screenDisplayMode == ScreenDisplayMode.minimize)
|
||||
Positioned(right: 10, bottom: 10, child: Card(
|
||||
elevation: 20,
|
||||
color: Colors.transparent,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: AppColor.colorTextButton, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
width: 500,
|
||||
height: 50,
|
||||
child: PointerInterceptor(child: Row(
|
||||
children: [
|
||||
Expanded(child: Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 16),
|
||||
child: _buildTitleComposer(context),
|
||||
)),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icMinimizeComposer, color: Colors.white, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).minimize,
|
||||
onTap: () => controller.minimizeComposer()),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icFullScreenComposer, color: Colors.white, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).fullscreen,
|
||||
onTap: () => controller.setFullScreenComposer()),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
child: buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icCloseComposer, color: Colors.white, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).close,
|
||||
onTap: () => controller.closeComposerWeb())),
|
||||
]
|
||||
))
|
||||
)
|
||||
)),
|
||||
if (controller.screenDisplayMode == ScreenDisplayMode.fullScreen)
|
||||
Scaffold(
|
||||
backgroundColor: Colors.black38,
|
||||
body: Align(alignment: Alignment.center, child: Card(
|
||||
color: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
width: responsiveUtils.getSizeWidthScreen(context) * 0.8,
|
||||
height: responsiveUtils.getSizeHeightScreen(context) * 0.85,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
child: PointerInterceptor(child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 5),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildAppBar(context)),
|
||||
SizedBox(height: 10),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildTitleComposer(context)),
|
||||
SizedBox(height: 16),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildEmailAddress(context)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildSubjectEmail(context)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Expanded(child: Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: _buildEditorAndAttachments(context))),
|
||||
Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)),
|
||||
]
|
||||
))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
]);
|
||||
}),
|
||||
tablet: Scaffold(
|
||||
backgroundColor: Colors.black38,
|
||||
body: Align(alignment: Alignment.center, child: Card(
|
||||
color: Colors.transparent,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 20),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
child: PointerInterceptor(child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 5),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildAppBar(context)),
|
||||
SizedBox(height: 10),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildTitleComposer(context)),
|
||||
SizedBox(height: 16),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildEmailAddress(context)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: _buildSubjectEmail(context)),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Expanded(child: Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: _buildEditorAndAttachments(context))),
|
||||
Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)),
|
||||
]
|
||||
))
|
||||
)
|
||||
)
|
||||
))
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAppBar(BuildContext context) {
|
||||
return Transform(
|
||||
transform: Matrix4.translationValues(15.0, 0.0, 0.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Spacer(),
|
||||
if (responsiveUtils.isDesktop(context))
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icMinimizeComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).minimize,
|
||||
onTap: () => controller.minimizeComposer()),
|
||||
if (responsiveUtils.isDesktop(context))
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icFullScreenComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).fullscreen,
|
||||
onTap: () => controller.setFullScreenComposer()),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icCloseComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).close,
|
||||
onTap: () => controller.closeComposerWeb()),
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAppBarForMobile(BuildContext context, bool isEnableSendButton) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
|
||||
color: Colors.white,
|
||||
child: Row(
|
||||
children: [
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icCloseComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).close,
|
||||
onTap: () => controller.closeComposerWeb()),
|
||||
Spacer(),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icAttachmentsComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).pick_attachments,
|
||||
onTap: () => controller.openFilePickerByType(context, FileType.any)),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(
|
||||
imagePaths.icSendComposer,
|
||||
color: isEnableSendButton ? AppColor.colorTextButton : AppColor.colorDisableMailboxCreateButton,
|
||||
fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).send,
|
||||
onTap: () => controller.sendEmailAction(context)),
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomBar(BuildContext context, bool isEnableSendButton) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 10, right: 20, top: 18, bottom: 18),
|
||||
color: AppColor.colorBottomBarComposer,
|
||||
child: Row(
|
||||
children: [
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icDeleteComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).delete,
|
||||
onTap: () => controller.deleteComposer()),
|
||||
Spacer(),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icAttachmentsComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).pick_attachments,
|
||||
onTap: () => controller.openFilePickerByType(context, FileType.any)),
|
||||
SizedBox(width: 16),
|
||||
SizedBox(
|
||||
width: 102,
|
||||
height: 36,
|
||||
child: ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.resolveWith(
|
||||
(states) => isEnableSendButton ? AppColor.colorTextButton : AppColor.colorDisableMailboxCreateButton),
|
||||
padding: MaterialStateProperty.resolveWith((states) => EdgeInsets.symmetric(horizontal: 16, vertical: 10)),
|
||||
elevation: MaterialStateProperty.resolveWith((states) => 0),
|
||||
shape: MaterialStateProperty.all(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
side: BorderSide(width: 0, color: isEnableSendButton ? AppColor.colorTextButton : AppColor.colorDisableMailboxCreateButton)))),
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
Text(AppLocalizations.of(context).send.toUpperCase(), style: TextStyle(fontSize: 17, color: Colors.white, fontWeight: FontWeight.w500)),
|
||||
SizedBox(width: 5),
|
||||
SvgPicture.asset(imagePaths.icSendComposer, width: 18, height: 18, fit: BoxFit.fill),
|
||||
]),
|
||||
onPressed: () => controller.sendEmailAction(context)
|
||||
),
|
||||
)
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTitleComposer(BuildContext context) {
|
||||
return Obx(() => Text(
|
||||
controller.subjectEmail.isNotEmpty == true
|
||||
? controller.subjectEmail.value ?? ''
|
||||
: AppLocalizations.of(context).new_message.capitalizeFirstEach,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w500,
|
||||
color: controller.screenDisplayMode == ScreenDisplayMode.minimize ? Colors.white : Colors.black),
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildEmailAddress(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
child: Text(
|
||||
'${AppLocalizations.of(context).from_email_address_prefix}:',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(fontSize: 15, color: AppColor.colorHintEmailAddressInput))),
|
||||
Expanded(
|
||||
child: Obx(() => controller.composerArguments.value != null
|
||||
? Text(
|
||||
'<${controller.getEmailAddressSender()}>',
|
||||
style: TextStyle(fontSize: 16, color: AppColor.colorContentEmail, fontWeight: FontWeight.normal))
|
||||
: SizedBox.shrink()
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Obx(() => (EmailAddressInputBuilder(
|
||||
context,
|
||||
imagePaths,
|
||||
appToast,
|
||||
PrefixEmailAddress.to,
|
||||
controller.listToEmailAddress,
|
||||
controller: controller.toEmailAddressController,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
expandMode: controller.expandMode.value)
|
||||
..addExpandAddressActionClick(() => controller.expandEmailAddressAction())
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
|
||||
.build()
|
||||
),
|
||||
Obx(() => controller.expandMode.value == ExpandMode.EXPAND
|
||||
? Divider(color: AppColor.colorDividerComposer, height: 1)
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.expandMode.value == ExpandMode.EXPAND
|
||||
? (EmailAddressInputBuilder(
|
||||
context,
|
||||
imagePaths,
|
||||
appToast,
|
||||
PrefixEmailAddress.cc,
|
||||
controller.listCcEmailAddress,
|
||||
controller: controller.ccEmailAddressController,
|
||||
isInitial: controller.isInitialRecipient.value,)
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
|
||||
.build()
|
||||
: SizedBox.shrink()
|
||||
),
|
||||
Obx(() => controller.expandMode.value == ExpandMode.EXPAND
|
||||
? Divider(color: AppColor.colorDividerComposer, height: 1)
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.expandMode.value == ExpandMode.EXPAND
|
||||
? (EmailAddressInputBuilder(
|
||||
context,
|
||||
imagePaths,
|
||||
appToast,
|
||||
PrefixEmailAddress.bcc,
|
||||
controller.listBccEmailAddress,
|
||||
controller: controller.bccEmailAddressController,
|
||||
isInitial: controller.isInitialRecipient.value,)
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
|
||||
.build()
|
||||
: SizedBox.shrink()
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSubjectEmail(BuildContext context) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 8, top: 16),
|
||||
child: Text(
|
||||
'${AppLocalizations.of(context).subject_email}:',
|
||||
style: TextStyle(fontSize: 15, color: AppColor.colorHintEmailAddressInput))),
|
||||
Expanded(child: (TextFieldBuilder()
|
||||
..key(Key('subject_email_input'))
|
||||
..cursorColor(AppColor.colorTextButton)
|
||||
..onChange((value) => controller.setSubjectEmail(value))
|
||||
..textStyle(TextStyle(color: AppColor.colorEmailAddress, fontSize: 15))
|
||||
..textDecoration(InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none))
|
||||
..addController(controller.subjectEmailInputController))
|
||||
.build()
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEditorAndAttachments(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
physics: ClampingScrollPhysics(),
|
||||
child: Column(
|
||||
children: [
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 10),
|
||||
child: _buildAttachmentsTitle(context, controller.attachments, controller.expandModeAttachments.value))
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isEmpty
|
||||
? _buildAttachmentsLoadingView()
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(bottom: 8, left: 10, right: 10),
|
||||
child: _buildAttachmentsList(context, controller.attachments, controller.expandModeAttachments.value))
|
||||
: SizedBox.shrink()),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
child: _buildComposerEditor(context)),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildComposerEditor(BuildContext context) {
|
||||
return Obx(() => HtmlEditorBrowser.HtmlEditor(
|
||||
key: Key('composer_editor_web'),
|
||||
controller: controller.htmlControllerBrowser,
|
||||
htmlEditorOptions: HtmlEditorBrowser.HtmlEditorOptions(
|
||||
hint: '',
|
||||
initialText: controller.initTextEditorComposer,
|
||||
autoAdjustHeight: true,
|
||||
darkMode: false,
|
||||
disableScrollbarEditor: true,
|
||||
),
|
||||
htmlToolbarOptions: HtmlEditorBrowser.HtmlToolbarOptions(
|
||||
toolbarPosition: HtmlEditorBrowser.ToolbarPosition.custom
|
||||
),
|
||||
otherOptions: HtmlEditorBrowser.OtherOptions(height: 550),
|
||||
callbacks: HtmlEditorBrowser.Callbacks(onBeforeCommand: (String? currentHtml) {
|
||||
controller.setTextEditor(currentHtml);
|
||||
}, onChangeContent: (String? changed) {
|
||||
controller.setTextEditor(changed);
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsLoadingView({EdgeInsets? padding, double? size}) {
|
||||
return Obx(() => controller.viewState.value.fold(
|
||||
(failure) => SizedBox.shrink(),
|
||||
(success) => success is UploadingAttachmentState
|
||||
? Center(child: Padding(
|
||||
padding: padding ?? EdgeInsets.all(10),
|
||||
child: SizedBox(
|
||||
width: size ?? 20,
|
||||
height: size ?? 20,
|
||||
child: CupertinoActivityIndicator(color: AppColor.colorTextButton))))
|
||||
: SizedBox.shrink()));
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsTitle(BuildContext context, List<Attachment> attachments, ExpandMode expandModeAttachment) {
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
'${AppLocalizations.of(context).attachments} (${filesize(attachments.totalSize(), 0)}):',
|
||||
style: TextStyle(fontSize: 12, color: AppColor.colorHintEmailAddressInput, fontWeight: FontWeight.normal)),
|
||||
_buildAttachmentsLoadingView(padding: EdgeInsets.only(left: 16), size: 16),
|
||||
Spacer(),
|
||||
Material(
|
||||
type: MaterialType.circle,
|
||||
color: Colors.transparent,
|
||||
child: TextButton(
|
||||
child: Text(
|
||||
expandModeAttachment == ExpandMode.EXPAND
|
||||
? AppLocalizations.of(context).hide
|
||||
: '${AppLocalizations.of(context).show_all} (${attachments.length})',
|
||||
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: AppColor.colorTextButton)),
|
||||
onPressed: () => controller.toggleDisplayAttachments()
|
||||
)
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsList(BuildContext context, List<Attachment> attachments, ExpandMode expandMode) {
|
||||
if (expandMode == ExpandMode.EXPAND) {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return GridView.builder(
|
||||
key: Key('list_attachment_full'),
|
||||
primary: false,
|
||||
shrinkWrap: true,
|
||||
itemCount: attachments.length,
|
||||
gridDelegate: SliverGridDelegateFixedHeight(
|
||||
height: 60,
|
||||
crossAxisCount: _getMaxItemRowListAttachment(context, constraints),
|
||||
crossAxisSpacing: 8.0,
|
||||
mainAxisSpacing: 8.0),
|
||||
itemBuilder: (context, index) =>
|
||||
(AttachmentFileComposerBuilder(context, imagePaths, attachments[index])
|
||||
..addOnDeleteAttachmentAction((attachment) => controller.removeAttachmentAction(attachment)))
|
||||
.build()
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
child: ListView.builder(
|
||||
key: Key('list_attachment_minimize'),
|
||||
shrinkWrap: true,
|
||||
physics: ClampingScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: attachments.length,
|
||||
itemBuilder: (context, index) =>
|
||||
(AttachmentFileComposerBuilder(context, imagePaths, attachments[index],
|
||||
itemMargin: EdgeInsets.only(right: 8),
|
||||
maxWidth: _getMaxWidthItemListAttachment(context, constraints),
|
||||
maxHeight: 60)
|
||||
..addOnDeleteAttachmentAction((attachment) => controller.removeAttachmentAction(attachment)))
|
||||
.build()
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int _getMaxItemRowListAttachment(BuildContext context, BoxConstraints constraints) {
|
||||
if (constraints.maxWidth < ResponsiveUtils.minTabletWidth) {
|
||||
return 2;
|
||||
} else if (constraints.maxWidth < ResponsiveUtils.minTabletLargeWidth) {
|
||||
return 3;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
double _getMaxWidthItemListAttachment(BuildContext context, BoxConstraints constraints) {
|
||||
final currentWidth = constraints.maxWidth - 40;
|
||||
return currentWidth / _getMaxItemRowListAttachment(context, constraints);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
enum ScreenDisplayMode {
|
||||
fullScreen,
|
||||
minimize,
|
||||
normal
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
import 'package:core/core.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
typedef OnDeleteAttachmentAction = void Function(Attachment attachment);
|
||||
|
||||
class AttachmentFileComposerBuilder {
|
||||
|
||||
final BuildContext context;
|
||||
final ImagePaths imagePaths;
|
||||
final Attachment attachment;
|
||||
final double? maxWidth;
|
||||
final double? maxHeight;
|
||||
final EdgeInsets? itemMargin;
|
||||
|
||||
OnDeleteAttachmentAction? _onDeleteAttachmentAction;
|
||||
|
||||
Widget? buttonAction;
|
||||
|
||||
AttachmentFileComposerBuilder(
|
||||
this.context,
|
||||
this.imagePaths,
|
||||
this.attachment,
|
||||
{
|
||||
this.maxWidth,
|
||||
this.maxHeight,
|
||||
this.itemMargin,
|
||||
}
|
||||
);
|
||||
|
||||
void addOnDeleteAttachmentAction(OnDeleteAttachmentAction onDeleteAttachmentAction) {
|
||||
_onDeleteAttachmentAction = onDeleteAttachmentAction;
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
return Theme(
|
||||
data: ThemeData(
|
||||
splashColor: Colors.transparent ,
|
||||
highlightColor: Colors.transparent),
|
||||
child: Container(
|
||||
margin: itemMargin ?? EdgeInsets.zero,
|
||||
padding: EdgeInsets.zero,
|
||||
alignment: Alignment.center,
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: AppColor.colorInputBorderCreateMailbox),
|
||||
color: Colors.white),
|
||||
child: Stack(children: [
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.only(right: 16),
|
||||
onTap: () {},
|
||||
leading: Transform(
|
||||
transform: Matrix4.translationValues(8.0, -3.0, 0.0),
|
||||
child: SvgPicture.asset(imagePaths.icFileAttachment, fit: BoxFit.fill)),
|
||||
title: Transform(
|
||||
transform: Matrix4.translationValues(-4.0, -6.0, 0.0),
|
||||
child: Text(
|
||||
attachment.name ?? '',
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: 12, color: AppColor.colorNameEmail, fontWeight: FontWeight.w500),
|
||||
)),
|
||||
subtitle: attachment.size != null && attachment.size?.value != 0
|
||||
? Transform(
|
||||
transform: Matrix4.translationValues(-4.0, -5.0, 0.0),
|
||||
child: Text(
|
||||
filesize(attachment.size?.value, 0),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: 10, color: AppColor.colorContentEmail, fontWeight: FontWeight.normal)))
|
||||
: null,
|
||||
),
|
||||
Positioned(right: -5, top: -5, child: buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icDeleteAttachment, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).delete,
|
||||
onTap: () => _onDeleteAttachmentAction?.call(attachment)))
|
||||
]),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ class EmailAddressInputBuilder {
|
||||
final List<EmailAddress> _listEmailAddress;
|
||||
final TextEditingController? controller;
|
||||
final bool? isInitial;
|
||||
final bool hasAvatar;
|
||||
|
||||
OnOpenExpandAddressActionClick? _onOpenExpandAddressActionClick;
|
||||
OnUpdateListEmailAddressAction? _onUpdateListEmailAddressAction;
|
||||
@@ -51,6 +52,7 @@ class EmailAddressInputBuilder {
|
||||
this._listEmailAddress,
|
||||
{
|
||||
this.isInitial,
|
||||
this.hasAvatar = false,
|
||||
this.controller,
|
||||
this.expandMode = ExpandMode.COLLAPSE,
|
||||
}
|
||||
@@ -69,7 +71,7 @@ class EmailAddressInputBuilder {
|
||||
Expanded(child: _buildTagEditor()),
|
||||
if (_prefixEmailAddress == PrefixEmailAddress.to)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 4),
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
child: _buildButtonExpandAddress())
|
||||
]
|
||||
);
|
||||
@@ -79,12 +81,10 @@ class EmailAddressInputBuilder {
|
||||
return Material(
|
||||
type: MaterialType.circle,
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
icon: SvgPicture.asset(
|
||||
expandMode == ExpandMode.EXPAND ? _imagePaths.icExpandAddress : _imagePaths.icMoreReceiver,
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.fill),
|
||||
child: TextButton(
|
||||
child: Text(
|
||||
expandMode == ExpandMode.EXPAND ? AppLocalizations.of(_context).hide : AppLocalizations.of(_context).details,
|
||||
style: TextStyle(fontWeight: FontWeight.normal, fontSize: 16, color: AppColor.colorTextButton)),
|
||||
onPressed: () => _onOpenExpandAddressActionClick?.call()
|
||||
)
|
||||
);
|
||||
@@ -98,6 +98,7 @@ class EmailAddressInputBuilder {
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
textInputAction: TextInputAction.done,
|
||||
hasAddButton: false,
|
||||
tagSpacing: 8,
|
||||
resetTextOnSubmitted: true,
|
||||
textStyle: TextStyle(color: AppColor.colorEmailAddress, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
onSubmitted: (value) {
|
||||
@@ -117,16 +118,22 @@ class EmailAddressInputBuilder {
|
||||
tagBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.only(top: kIsWeb ? 8 : 0),
|
||||
child: Chip(
|
||||
labelPadding: EdgeInsets.only(left: 8, right: 8, bottom: 2),
|
||||
labelPadding: EdgeInsets.only(left: 12, right: 12, bottom: 2),
|
||||
label: Text(_listEmail[index], maxLines: 1, overflow: TextOverflow.ellipsis),
|
||||
deleteIcon: SvgPicture.asset(_imagePaths.icDeleteEmailAddress, fit: BoxFit.fill),
|
||||
labelStyle: TextStyle(color: AppColor.colorEmailAddress, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
backgroundColor: AppColor.emailAddressChipColor,
|
||||
avatar: CircleAvatar(
|
||||
backgroundColor: AppColor.colorTextButton,
|
||||
child: Text(
|
||||
_listEmail[index].isNotEmpty ? _listEmail[index][0].toUpperCase() : '',
|
||||
style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500))),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(width: 0, color: AppColor.emailAddressChipColor),
|
||||
),
|
||||
avatar: hasAvatar == true
|
||||
? CircleAvatar(
|
||||
backgroundColor: AppColor.colorTextButton,
|
||||
child: Text(
|
||||
_listEmail[index].isNotEmpty ? _listEmail[index][0].toUpperCase() : '',
|
||||
style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500)))
|
||||
: null,
|
||||
onDeleted: () {
|
||||
setState(() => _listEmailAddress.removeAt(index));
|
||||
_onUpdateListEmailAddressAction?.call(_prefixEmailAddress, _listEmailAddress);
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:core/core.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -33,6 +34,7 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_
|
||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_dialog_builder.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
@@ -480,16 +482,16 @@ class EmailController extends BaseController {
|
||||
void composeEmailFromEmailAddress(EmailAddress emailAddress) {
|
||||
popBack();
|
||||
|
||||
if (canComposeEmail()) {
|
||||
push(
|
||||
AppRoutes.COMPOSER,
|
||||
arguments: ComposerArguments(
|
||||
emailActionType: EmailActionType.composeFromEmailAddress,
|
||||
emailAddress: emailAddress,
|
||||
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role,
|
||||
session: mailboxDashBoardController.sessionCurrent!,
|
||||
userProfile: mailboxDashBoardController.userProfile.value!,
|
||||
mapMailboxId: mailboxDashBoardController.mapDefaultMailboxId));
|
||||
final arguments = ComposerArguments(
|
||||
emailActionType: EmailActionType.composeFromEmailAddress,
|
||||
emailAddress: emailAddress,
|
||||
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
|
||||
if (kIsWeb) {
|
||||
if (mailboxDashBoardController.dashBoardAction != DashBoardAction.compose) {
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: arguments);
|
||||
}
|
||||
} else {
|
||||
push(AppRoutes.COMPOSER, arguments: arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,11 +499,6 @@ class EmailController extends BaseController {
|
||||
popBack();
|
||||
}
|
||||
|
||||
bool canComposeEmail() => mailboxDashBoardController.sessionCurrent != null
|
||||
&& mailboxDashBoardController.userProfile.value != null
|
||||
&& mailboxDashBoardController.mapDefaultMailboxId.isNotEmpty
|
||||
&& mailboxDashBoardController.selectedEmail.value != null;
|
||||
|
||||
void backToThreadView() {
|
||||
attachmentsExpandMode.value = ExpandMode.COLLAPSE;
|
||||
emailAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
@@ -513,30 +510,36 @@ class EmailController extends BaseController {
|
||||
if (emailActionType == EmailActionType.compose) {
|
||||
composeEmailAction();
|
||||
} else {
|
||||
if (canComposeEmail()) {
|
||||
push(
|
||||
AppRoutes.COMPOSER,
|
||||
arguments: ComposerArguments(
|
||||
emailActionType: emailActionType,
|
||||
presentationEmail: mailboxDashBoardController.selectedEmail.value!,
|
||||
emailContents: emailContents,
|
||||
attachments: attachments,
|
||||
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role,
|
||||
session: mailboxDashBoardController.sessionCurrent!,
|
||||
userProfile: mailboxDashBoardController.userProfile.value!,
|
||||
mapMailboxId: mailboxDashBoardController.mapDefaultMailboxId));
|
||||
final arguments = ComposerArguments(
|
||||
emailActionType: emailActionType,
|
||||
presentationEmail: mailboxDashBoardController.selectedEmail.value!,
|
||||
emailContents: emailContents,
|
||||
attachments: attachments,
|
||||
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
|
||||
|
||||
if (kIsWeb) {
|
||||
if (mailboxDashBoardController.dashBoardAction != DashBoardAction.compose) {
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: arguments);
|
||||
}
|
||||
if (Get.currentRoute == AppRoutes.EMAIL) {
|
||||
popBack();
|
||||
}
|
||||
} else {
|
||||
push(AppRoutes.COMPOSER, arguments: arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void composeEmailAction() {
|
||||
if (canComposeEmail()) {
|
||||
push(
|
||||
AppRoutes.COMPOSER,
|
||||
arguments: ComposerArguments(
|
||||
session: mailboxDashBoardController.sessionCurrent!,
|
||||
userProfile: mailboxDashBoardController.userProfile.value!,
|
||||
mapMailboxId: mailboxDashBoardController.mapDefaultMailboxId));
|
||||
if (kIsWeb) {
|
||||
if (mailboxDashBoardController.dashBoardAction != DashBoardAction.compose) {
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: ComposerArguments());
|
||||
}
|
||||
if (Get.currentRoute == AppRoutes.EMAIL) {
|
||||
popBack();
|
||||
}
|
||||
} else {
|
||||
push(AppRoutes.COMPOSER, arguments: ComposerArguments());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,7 +216,7 @@ class EmailView extends GetView {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
padding: EdgeInsets.only(top: kIsWeb ? 10: 20),
|
||||
child: Text(
|
||||
'${prefixEmailAddress.asName(context)}:',
|
||||
style: TextStyle(fontSize: 14, color: AppColor.colorEmailAddressPrefix))),
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/main/routes/router_arguments.dart';
|
||||
|
||||
class ComposerArguments with EquatableMixin {
|
||||
class ComposerArguments extends RouterArguments {
|
||||
final EmailActionType emailActionType;
|
||||
final PresentationEmail? presentationEmail;
|
||||
final List<EmailContent>? emailContents;
|
||||
final EmailAddress? emailAddress;
|
||||
final List<Attachment>? attachments;
|
||||
final Session session;
|
||||
final UserProfile userProfile;
|
||||
final Map<Role, MailboxId> mapMailboxId;
|
||||
final Role? mailboxRole;
|
||||
|
||||
ComposerArguments({
|
||||
@@ -23,9 +19,6 @@ class ComposerArguments with EquatableMixin {
|
||||
this.attachments,
|
||||
this.mailboxRole,
|
||||
this.emailAddress,
|
||||
required this.session,
|
||||
required this.userProfile,
|
||||
required this.mapMailboxId,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -35,8 +28,5 @@ class ComposerArguments with EquatableMixin {
|
||||
attachments,
|
||||
mailboxRole,
|
||||
emailAddress,
|
||||
session,
|
||||
userProfile,
|
||||
mapMailboxId,
|
||||
];
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
import 'package:core/core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/main/routes/app_routes.dart';
|
||||
|
||||
typedef OnBackActionClick = void Function();
|
||||
typedef OnEmailActionClick = void Function(PresentationEmail, EmailActionType);
|
||||
@@ -51,9 +53,9 @@ class AppBarMailWidgetBuilder {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if ((!_responsiveUtils.isDesktop(_context) && !_responsiveUtils.isTabletLarge(_context)))
|
||||
if (_conditionShowBackButton())
|
||||
_buildBackButton(),
|
||||
if ((!_responsiveUtils.isDesktop(_context) && !_responsiveUtils.isTabletLarge(_context)))
|
||||
if (_conditionShowBackButton())
|
||||
Expanded(child: _buildMailboxName()),
|
||||
if (_presentationEmail != null) _buildListOptionButton(),
|
||||
]
|
||||
@@ -62,6 +64,16 @@ class AppBarMailWidgetBuilder {
|
||||
);
|
||||
}
|
||||
|
||||
bool _conditionShowBackButton() {
|
||||
if (Get.currentRoute == AppRoutes.MAILBOX_DASHBOARD) {
|
||||
return !_responsiveUtils.isDesktop(_context) && !_responsiveUtils.isTabletLarge(_context);
|
||||
} else if (Get.currentRoute == AppRoutes.EMAIL) {
|
||||
return _responsiveUtils.isMobileDevice(_context) || _responsiveUtils.isTablet(_context);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildBackButton() {
|
||||
return IconButton(
|
||||
icon: SvgPicture.asset(_imagePaths.icBack, width: 20, height: 20, color: AppColor.colorTextButton, fit: BoxFit.fill),
|
||||
|
||||
@@ -78,7 +78,7 @@ class AttachmentFileTileBuilder {
|
||||
}},
|
||||
leading: Transform(
|
||||
transform: Matrix4.translationValues(14.0, 2.0, 0.0),
|
||||
child: SvgPicture.asset(_imagePaths.icAttachmentFile, width: 24, height: 24, fit: BoxFit.fill)),
|
||||
child: SvgPicture.asset(_imagePaths.icFileAttachment, width: 24, height: 24, fit: BoxFit.fill)),
|
||||
title: Transform(
|
||||
transform: Matrix4.translationValues(-8.0, -8.0, 0.0),
|
||||
child: Text(
|
||||
|
||||
@@ -453,6 +453,8 @@ class MailboxController extends BaseMailboxController {
|
||||
..title(AppLocalizations.of(context).delete_mailboxes)
|
||||
..content(AppLocalizations.of(context).message_confirmation_dialog_delete_mailbox(presentationMailbox.name?.name ?? ''))
|
||||
..addIcon(SvgPicture.asset(_imagePaths.icRemoveDialog, fit: BoxFit.fill))
|
||||
..colorConfirmButton(AppColor.colorConfirmActionDialog)
|
||||
..styleTextConfirmButton(TextStyle(fontSize: 17, fontWeight: FontWeight.w500, color: AppColor.colorActionDeleteConfirmDialog))
|
||||
..onCloseButtonAction(() => popBack())
|
||||
..onConfirmButtonAction(AppLocalizations.of(context).delete, () => _deleteMailboxAction(presentationMailbox))
|
||||
..onCancelButtonAction(AppLocalizations.of(context).cancel, () => popBack()))
|
||||
|
||||
@@ -11,16 +11,20 @@ import 'package:tmail_ui_user/features/base/base_controller.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/email_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/state/remove_email_drafts_state.dart';
|
||||
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/model/dashboard_action.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';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/model/search_status.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/router_arguments.dart';
|
||||
|
||||
class MailboxDashBoardController extends BaseController {
|
||||
|
||||
@@ -36,6 +40,7 @@ class MailboxDashBoardController extends BaseController {
|
||||
final userProfile = Rxn<UserProfile>();
|
||||
final searchState = SearchState.initial().obs;
|
||||
final suggestionSearch = <String>[].obs;
|
||||
final dashBoardAction = DashBoardAction.none.obs;
|
||||
|
||||
SearchQuery? searchQuery;
|
||||
Session? sessionCurrent;
|
||||
@@ -43,6 +48,7 @@ class MailboxDashBoardController extends BaseController {
|
||||
Map<MailboxId, PresentationMailbox> mapMailbox = Map();
|
||||
TextEditingController searchInputController = TextEditingController();
|
||||
FocusNode searchFocus = FocusNode();
|
||||
RouterArguments? routerArguments;
|
||||
|
||||
MailboxDashBoardController(
|
||||
this._getUserProfileInteractor,
|
||||
@@ -225,6 +231,20 @@ class MailboxDashBoardController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
void dispatchDashBoardAction(DashBoardAction action, {RouterArguments? arguments}) {
|
||||
switch(action) {
|
||||
case DashBoardAction.none:
|
||||
routerArguments = null;
|
||||
Get.delete<ComposerController>();
|
||||
break;
|
||||
case DashBoardAction.compose:
|
||||
routerArguments = arguments;
|
||||
ComposerBindings().dependencies();
|
||||
break;
|
||||
}
|
||||
dashBoardAction.value = action;
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
searchInputController.dispose();
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import 'package:core/core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart'
|
||||
if (dart.library.html) 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart';
|
||||
|
||||
class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> {
|
||||
@@ -30,35 +33,40 @@ class MailboxDashBoardView extends GetWidget<MailboxDashBoardController> {
|
||||
desktop: SizedBox.shrink()
|
||||
),
|
||||
drawerEnableOpenDragGesture: !responsiveUtils.isDesktop(context),
|
||||
body: ResponsiveWidget(
|
||||
responsiveUtils: responsiveUtils,
|
||||
desktop: Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(flex: 1, child: MailboxView()),
|
||||
Expanded(flex: 1, child: ThreadView()),
|
||||
Expanded(flex: 2, child: EmailView()),
|
||||
],
|
||||
),
|
||||
),
|
||||
tabletLarge: Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: responsiveUtils.getSizeWidthScreen(context) * 0.35,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: ThreadView()
|
||||
body: Stack(children: [
|
||||
ResponsiveWidget(
|
||||
responsiveUtils: responsiveUtils,
|
||||
desktop: Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(flex: 1, child: MailboxView()),
|
||||
Expanded(flex: 1, child: ThreadView()),
|
||||
Expanded(flex: 2, child: EmailView()),
|
||||
],
|
||||
),
|
||||
Expanded(child: EmailView()),
|
||||
],
|
||||
),
|
||||
),
|
||||
tablet: ThreadView(),
|
||||
mobile: ThreadView()),
|
||||
),
|
||||
tabletLarge: Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: responsiveUtils.getSizeWidthScreen(context) * 0.35,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: ThreadView()
|
||||
),
|
||||
Expanded(child: EmailView()),
|
||||
],
|
||||
),
|
||||
),
|
||||
tablet: ThreadView(),
|
||||
mobile: ThreadView()),
|
||||
Obx(() => controller.dashBoardAction == DashBoardAction.compose
|
||||
? ComposerView()
|
||||
: SizedBox.shrink()),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
enum DashBoardAction {
|
||||
none,
|
||||
compose
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:core/core.dart';
|
||||
import 'package:dartz/dartz.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';
|
||||
@@ -28,6 +27,7 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen
|
||||
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';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_action.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart';
|
||||
@@ -675,10 +675,6 @@ class ThreadController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
bool canComposeEmail() => mailboxDashBoardController.sessionCurrent != null
|
||||
&& mailboxDashBoardController.userProfile.value != null
|
||||
&& mailboxDashBoardController.mapDefaultMailboxId.isNotEmpty;
|
||||
|
||||
bool isSelectionEnabled() => currentSelectMode.value == SelectMode.ACTIVE;
|
||||
|
||||
void pressEmailSelectionAction(BuildContext context, EmailActionType actionType, List<PresentationEmail> selectionEmail) {
|
||||
@@ -709,27 +705,25 @@ class ThreadController extends BaseController {
|
||||
}
|
||||
|
||||
void editEmail(PresentationEmail presentationEmail) {
|
||||
if (canComposeEmail()) {
|
||||
push(
|
||||
AppRoutes.COMPOSER,
|
||||
arguments: ComposerArguments(
|
||||
emailActionType: EmailActionType.edit,
|
||||
presentationEmail: presentationEmail,
|
||||
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role,
|
||||
session: mailboxDashBoardController.sessionCurrent!,
|
||||
userProfile: mailboxDashBoardController.userProfile.value!,
|
||||
mapMailboxId: mailboxDashBoardController.mapDefaultMailboxId));
|
||||
final arguments = ComposerArguments(
|
||||
emailActionType: EmailActionType.edit,
|
||||
presentationEmail: presentationEmail,
|
||||
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role);
|
||||
|
||||
if (kIsWeb) {
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: arguments);
|
||||
} else {
|
||||
push(AppRoutes.COMPOSER, arguments: arguments);
|
||||
}
|
||||
}
|
||||
|
||||
void composeEmailAction() {
|
||||
if (canComposeEmail()) {
|
||||
push(
|
||||
AppRoutes.COMPOSER,
|
||||
arguments: ComposerArguments(
|
||||
session: mailboxDashBoardController.sessionCurrent!,
|
||||
userProfile: mailboxDashBoardController.userProfile.value!,
|
||||
mapMailboxId: mailboxDashBoardController.mapDefaultMailboxId));
|
||||
if (kIsWeb) {
|
||||
if (mailboxDashBoardController.dashBoardAction != DashBoardAction.compose) {
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.compose, arguments: ComposerArguments());
|
||||
}
|
||||
} else {
|
||||
push(AppRoutes.COMPOSER, arguments: ComposerArguments());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user