TF-390 Apply new ui composer for browser
This commit is contained in:
@@ -125,9 +125,6 @@ class ComposerBindings extends BaseBindings {
|
||||
Get.find<SaveEmailAddressesInteractor>(),
|
||||
Get.find<GetAutoCompleteInteractor>(),
|
||||
Get.find<GetAutoCompleteWithDeviceContactInteractor>(),
|
||||
Get.find<AppToast>(),
|
||||
Get.find<ImagePaths>(),
|
||||
Get.find<ResponsiveUtils>(),
|
||||
Get.find<Uuid>(),
|
||||
Get.find<DeviceInfoPlugin>(),
|
||||
Get.find<LocalFilePickerInteractor>(),
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:file_picker/file_picker.dart';
|
||||
import 'package:fk_user_agent/fk_user_agent.dart';
|
||||
import 'package:flutter/foundation.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:http_parser/http_parser.dart';
|
||||
@@ -52,7 +53,10 @@ import 'package:uuid/uuid.dart';
|
||||
class ComposerController extends BaseController {
|
||||
|
||||
final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
||||
|
||||
final _appToast = Get.find<AppToast>();
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
|
||||
final expandMode = ExpandMode.COLLAPSE.obs;
|
||||
final expandModeMobile = ExpandMode.EXPAND.obs;
|
||||
final expandModeAttachments = ExpandMode.EXPAND.obs;
|
||||
@@ -61,16 +65,17 @@ class ComposerController extends BaseController {
|
||||
final isInitialRecipient = false.obs;
|
||||
final attachments = <Attachment>[].obs;
|
||||
final emailContents = Rxn<List<EmailContent>>();
|
||||
final listEmailAddressType = <PrefixEmailAddress>[].obs;
|
||||
final subjectEmail = Rxn<String>();
|
||||
final screenDisplayMode = ScreenDisplayMode.normal.obs;
|
||||
final toAddressExpandMode = ExpandMode.EXPAND.obs;
|
||||
final ccAddressExpandMode = ExpandMode.EXPAND.obs;
|
||||
final bccAddressExpandMode = ExpandMode.EXPAND.obs;
|
||||
|
||||
final SendEmailInteractor _sendEmailInteractor;
|
||||
final SaveEmailAddressesInteractor _saveEmailAddressInteractor;
|
||||
final GetAutoCompleteInteractor _getAutoCompleteInteractor;
|
||||
final GetAutoCompleteWithDeviceContactInteractor _getAutoCompleteWithDeviceContactInteractor;
|
||||
final AppToast _appToast;
|
||||
final ImagePaths _imagePaths;
|
||||
final ResponsiveUtils responsiveUtils;
|
||||
final Uuid _uuid;
|
||||
final LocalFilePickerInteractor _localFilePickerInteractor;
|
||||
final UploadMultipleAttachmentInteractor _uploadMultipleAttachmentInteractor;
|
||||
@@ -90,6 +95,7 @@ class ComposerController extends BaseController {
|
||||
final toEmailAddressController = TextEditingController();
|
||||
final ccEmailAddressController = TextEditingController();
|
||||
final bccEmailAddressController = TextEditingController();
|
||||
final toEmailAddressFocusNode = FocusNode();
|
||||
|
||||
List<Attachment> initialAttachments = <Attachment>[];
|
||||
String? _textEditorWeb;
|
||||
@@ -117,9 +123,6 @@ class ComposerController extends BaseController {
|
||||
this._saveEmailAddressInteractor,
|
||||
this._getAutoCompleteInteractor,
|
||||
this._getAutoCompleteWithDeviceContactInteractor,
|
||||
this._appToast,
|
||||
this._imagePaths,
|
||||
this.responsiveUtils,
|
||||
this._uuid,
|
||||
this._deviceInfoPlugin,
|
||||
this._localFilePickerInteractor,
|
||||
@@ -151,6 +154,7 @@ class ComposerController extends BaseController {
|
||||
toEmailAddressController.dispose();
|
||||
ccEmailAddressController.dispose();
|
||||
bccEmailAddressController.dispose();
|
||||
toEmailAddressFocusNode.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@@ -241,11 +245,6 @@ class ComposerController extends BaseController {
|
||||
return null;
|
||||
}
|
||||
|
||||
void expandEmailAddressAction() {
|
||||
final newExpandMode = expandMode.value == ExpandMode.COLLAPSE ? ExpandMode.EXPAND : ExpandMode.COLLAPSE;
|
||||
expandMode.value = newExpandMode;
|
||||
}
|
||||
|
||||
void _initToEmailAddress(ComposerArguments arguments) {
|
||||
final userProfile = mailboxDashBoardController.userProfile.value;
|
||||
if (arguments.presentationEmail != null && userProfile != null) {
|
||||
@@ -266,6 +265,14 @@ class ComposerController extends BaseController {
|
||||
if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty) {
|
||||
isInitialRecipient.value = true;
|
||||
}
|
||||
|
||||
if (listCcEmailAddress.isNotEmpty) {
|
||||
listEmailAddressType.add(PrefixEmailAddress.cc);
|
||||
}
|
||||
|
||||
if (listBccEmailAddress.isNotEmpty) {
|
||||
listEmailAddressType.add(PrefixEmailAddress.bcc);
|
||||
}
|
||||
} else if (arguments.emailAddress != null) {
|
||||
listToEmailAddress.add(arguments.emailAddress!);
|
||||
isInitialRecipient.value = true;
|
||||
@@ -377,15 +384,45 @@ class ComposerController extends BaseController {
|
||||
void sendEmailAction(BuildContext context) async {
|
||||
clearFocusEditor(context);
|
||||
|
||||
if (isEnableEmailSendButton.value) {
|
||||
if (subjectEmail.value?.isNotEmpty == true) {
|
||||
_handleSendMessages(context);
|
||||
} else {
|
||||
_showConfirmDialogSendEmail(context);
|
||||
}
|
||||
} else {
|
||||
_appToast.showErrorToast(AppLocalizations.of(context).your_email_should_have_at_least_one_recipient);
|
||||
if (!isEnableEmailSendButton.value) {
|
||||
_showConfirmDialogSendEmailFailed(
|
||||
context,
|
||||
AppLocalizations.of(context).message_dialog_send_email_without_recipient,
|
||||
AppLocalizations.of(context).add_recipients,
|
||||
() => toEmailAddressFocusNode.requestFocus(),
|
||||
hasCancelButton: false);
|
||||
return;
|
||||
}
|
||||
|
||||
final allListEmailAddress = listToEmailAddress + listCcEmailAddress + listBccEmailAddress;
|
||||
final listEmailAddressInvalid = allListEmailAddress
|
||||
.where((emailAddress) => !GetUtils.isEmail(emailAddress.emailAddress))
|
||||
.toList();
|
||||
|
||||
if (listEmailAddressInvalid.isNotEmpty) {
|
||||
_showConfirmDialogSendEmailFailed(
|
||||
context,
|
||||
AppLocalizations.of(context).message_dialog_send_email_with_email_address_invalid,
|
||||
AppLocalizations.of(context).fix_email_addresses,
|
||||
() {
|
||||
toAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
ccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
bccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
},
|
||||
hasCancelButton: false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (subjectEmail.value == null || subjectEmail.isEmpty == true) {
|
||||
_showConfirmDialogSendEmailFailed(
|
||||
context,
|
||||
AppLocalizations.of(context).message_dialog_send_email_without_a_subject,
|
||||
AppLocalizations.of(context).send_anyway,
|
||||
() => _handleSendMessages(context));
|
||||
return;
|
||||
}
|
||||
|
||||
_handleSendMessages(context);
|
||||
}
|
||||
|
||||
void _handleSendMessages(BuildContext context) async {
|
||||
@@ -646,23 +683,20 @@ class ComposerController extends BaseController {
|
||||
if (!kIsWeb) {
|
||||
htmlEditorApi?.unfocus(context);
|
||||
htmlControllerBrowser.clearFocus();
|
||||
} else {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
}
|
||||
}
|
||||
|
||||
void closeComposerWeb() {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.none);
|
||||
}
|
||||
|
||||
void minimizeComposer() {
|
||||
void displayScreenTypeComposerAction(ScreenDisplayMode displayMode) {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
_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;
|
||||
screenDisplayMode.value = displayMode;
|
||||
}
|
||||
|
||||
void _updateTextForEditor() async {
|
||||
@@ -671,6 +705,7 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
|
||||
void deleteComposer() {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
mailboxDashBoardController.dispatchDashBoardAction(DashBoardAction.none);
|
||||
}
|
||||
|
||||
@@ -679,15 +714,16 @@ class ComposerController extends BaseController {
|
||||
expandModeAttachments.value = newExpandMode;
|
||||
}
|
||||
|
||||
void _showConfirmDialogSendEmail(BuildContext context) {
|
||||
if (responsiveUtils.isMobileDevice(context)) {
|
||||
void _showConfirmDialogSendEmailFailed(BuildContext context, String message,
|
||||
String actionName, Function? onConfirmAction, {bool hasCancelButton = true}) {
|
||||
if (_responsiveUtils.isMobile(context)) {
|
||||
(ConfirmationDialogActionSheetBuilder(context)
|
||||
..messageText(AppLocalizations.of(context).message_confirm_send_email)
|
||||
..messageText(message)
|
||||
..styleConfirmButton(TextStyle(fontSize: 20, fontWeight: FontWeight.normal, color: Colors.black))
|
||||
..onCancelAction(AppLocalizations.of(context).cancel, () => popBack())
|
||||
..onConfirmAction(AppLocalizations.of(context).send, () {
|
||||
..onConfirmAction(actionName, () {
|
||||
popBack();
|
||||
_handleSendMessages(context);
|
||||
onConfirmAction?.call();
|
||||
})).show();
|
||||
} else {
|
||||
showDialog(
|
||||
@@ -695,17 +731,25 @@ class ComposerController extends BaseController {
|
||||
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||
builder: (BuildContext context) => PointerInterceptor(child: (ConfirmDialogBuilder(_imagePaths)
|
||||
..key(Key('confirm_dialog_send_message'))
|
||||
..content(AppLocalizations.of(context).message_confirm_send_email)
|
||||
..title(AppLocalizations.of(context).sending_failed)
|
||||
..content(message)
|
||||
..addIcon(SvgPicture.asset(_imagePaths.icSendToastError, fit: BoxFit.fill))
|
||||
..colorConfirmButton(AppColor.colorTextButton)
|
||||
..colorCancelButton(AppColor.colorCancelButton)
|
||||
..styleContent(TextStyle(fontSize: 15, fontWeight: FontWeight.normal, color: AppColor.colorMessageDialog))
|
||||
..paddingTitle(EdgeInsets.only(top: 34))
|
||||
..marginIcon(EdgeInsets.zero)
|
||||
..paddingContent(EdgeInsets.only(left: 44, right: 44, bottom: 24, top: 8))
|
||||
..paddingButton(hasCancelButton ? null : EdgeInsets.only(bottom: 16, left: 44, right: 44))
|
||||
..styleTitle(TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black))
|
||||
..styleContent(TextStyle(fontSize: 14, fontWeight: FontWeight.normal, color: AppColor.colorContentEmail))
|
||||
..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, () {
|
||||
..onConfirmButtonAction(actionName, () {
|
||||
popBack();
|
||||
_handleSendMessages(context);
|
||||
onConfirmAction?.call();
|
||||
})
|
||||
..onCancelButtonAction(AppLocalizations.of(context).cancel, () => popBack()))
|
||||
..onCancelButtonAction(hasCancelButton ? AppLocalizations.of(context).cancel : '', () => popBack())
|
||||
..onCloseButtonAction(() => popBack()))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
@@ -714,6 +758,73 @@ class ComposerController extends BaseController {
|
||||
expandModeMobile.value = expandMode;
|
||||
}
|
||||
|
||||
void addEmailAddressType(PrefixEmailAddress prefixEmailAddress) {
|
||||
listEmailAddressType.add(prefixEmailAddress);
|
||||
}
|
||||
|
||||
void deleteEmailAddressType(PrefixEmailAddress prefixEmailAddress) {
|
||||
listEmailAddressType.remove(prefixEmailAddress);
|
||||
updateListEmailAddress(prefixEmailAddress, List.empty());
|
||||
}
|
||||
|
||||
void onSubjectEmailFocusChange(bool isFocus) {
|
||||
log('ComposerController::onSubjectEmailFocusChange(): Focus: $isFocus');
|
||||
if (isFocus) {
|
||||
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
}
|
||||
}
|
||||
|
||||
void onEditorFocusChange(bool isFocus) {
|
||||
log('ComposerController::onEditorFocusChange(): Focus: $isFocus');
|
||||
if (isFocus) {
|
||||
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
}
|
||||
}
|
||||
|
||||
void showFullEmailAddress(PrefixEmailAddress prefixEmailAddress) {
|
||||
switch(prefixEmailAddress) {
|
||||
case PrefixEmailAddress.to:
|
||||
toAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
break;
|
||||
case PrefixEmailAddress.cc:
|
||||
ccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
break;
|
||||
case PrefixEmailAddress.bcc:
|
||||
bccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onEmailAddressFocusChange(PrefixEmailAddress prefixEmailAddress, bool isFocus) {
|
||||
if (isFocus) {
|
||||
switch(prefixEmailAddress) {
|
||||
case PrefixEmailAddress.to:
|
||||
toAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
break;
|
||||
case PrefixEmailAddress.cc:
|
||||
ccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
break;
|
||||
case PrefixEmailAddress.bcc:
|
||||
bccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void closeComposer(BuildContext context) {
|
||||
popBack();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ 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
|
||||
@@ -128,7 +127,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
onTap: () => controller.openPickAttachmentMenu(context, _pickAttachmentsActionTiles(context))),
|
||||
if (expandModeMobile == ExpandMode.COLLAPSE)
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(isEnableSendButton ? imagePaths.icSendMobile : imagePaths.icSendMobileDisable, fit: BoxFit.fill),
|
||||
icon: SvgPicture.asset(isEnableSendButton ? imagePaths.icSendMobile : imagePaths.icSendDisable, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).send,
|
||||
onTap: () => controller.sendEmailAction(context)),
|
||||
]);
|
||||
@@ -145,7 +144,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
buildIconWeb(
|
||||
iconSize: 36,
|
||||
iconPadding: EdgeInsets.zero,
|
||||
icon: SvgPicture.asset(isEnableSendButton ? imagePaths.icSendMobile : imagePaths.icSendMobileDisable, width: 36, height: 36, fit: BoxFit.fill),
|
||||
icon: SvgPicture.asset(isEnableSendButton ? imagePaths.icSendMobile : imagePaths.icSendDisable, width: 36, height: 36, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).send,
|
||||
onTap: () => controller.sendEmailAction(context)),
|
||||
]);
|
||||
@@ -182,13 +181,11 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
Obx(() => (EmailAddressInputBuilder(
|
||||
context,
|
||||
imagePaths,
|
||||
_appToast,
|
||||
PrefixEmailAddress.to,
|
||||
controller.listToEmailAddress,
|
||||
controller.listEmailAddressType,
|
||||
controller: controller.toEmailAddressController,
|
||||
isInitial: controller.isInitialRecipient.value,
|
||||
expandMode: controller.expandMode.value)
|
||||
..addExpandAddressActionClick(() => controller.expandEmailAddressAction())
|
||||
isInitial: controller.isInitialRecipient.value)
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
|
||||
.build()
|
||||
@@ -200,9 +197,9 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
? (EmailAddressInputBuilder(
|
||||
context,
|
||||
imagePaths,
|
||||
_appToast,
|
||||
PrefixEmailAddress.cc,
|
||||
controller.listCcEmailAddress,
|
||||
controller.listEmailAddressType,
|
||||
controller: controller.ccEmailAddressController,
|
||||
isInitial: controller.isInitialRecipient.value,)
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
@@ -217,9 +214,9 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
? (EmailAddressInputBuilder(
|
||||
context,
|
||||
imagePaths,
|
||||
_appToast,
|
||||
PrefixEmailAddress.bcc,
|
||||
controller.listBccEmailAddress,
|
||||
controller.listEmailAddressType,
|
||||
controller: controller.bccEmailAddressController,
|
||||
isInitial: controller.isInitialRecipient.value,)
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
|
||||
@@ -2,6 +2,7 @@ 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/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -28,87 +29,78 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
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))),
|
||||
]
|
||||
))
|
||||
)
|
||||
))
|
||||
body: Container(
|
||||
color: Colors.white,
|
||||
child: LayoutBuilder(builder: (context, constraints) => PointerInterceptor(child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Obx(() => _buildAppBarForMobile(context, controller.isEnableEmailSendButton.value)),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
_buildEmailAddress(context, constraints),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 16), child: _buildSubjectEmail(context)),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 16), child: _buildListButton(context)),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Expanded(child: _buildEditorAndAttachments(context)),
|
||||
]
|
||||
)))
|
||||
)
|
||||
),
|
||||
desktop: Obx(() {
|
||||
return Stack(children: [
|
||||
if (controller.screenDisplayMode == ScreenDisplayMode.normal)
|
||||
Positioned(right: 10, bottom: 10, child: Card(
|
||||
Positioned(right: 5, bottom: 5, child: Card(
|
||||
elevation: 20,
|
||||
color: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(24))),
|
||||
width: responsiveUtils.getSizeScreenWidth(context) * 0.55,
|
||||
height: responsiveUtils.getSizeScreenHeight(context) * 0.75,
|
||||
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)),
|
||||
]
|
||||
)
|
||||
height: responsiveUtils.getSizeScreenHeight(context) * 0.7,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
||||
child: LayoutBuilder(builder: (context, constraints) =>
|
||||
PointerInterceptor(child: _buildBodyForDesktop(context, constraints)))
|
||||
)
|
||||
)
|
||||
)),
|
||||
if (controller.screenDisplayMode == ScreenDisplayMode.minimize)
|
||||
Positioned(right: 10, bottom: 10, child: Card(
|
||||
Positioned(right: 5, bottom: 5, child: Card(
|
||||
elevation: 20,
|
||||
color: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: AppColor.colorTextButton, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||
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.saveEmailAsDrafts(context);
|
||||
controller.closeComposerWeb();
|
||||
})),
|
||||
]
|
||||
))
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
child: PointerInterceptor(child: Row(children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).close,
|
||||
onTap: () {
|
||||
controller.saveEmailAsDrafts(context);
|
||||
controller.closeComposerWeb();
|
||||
}
|
||||
)),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icFullScreenComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).fullscreen,
|
||||
onTap: () => controller.displayScreenTypeComposerAction(ScreenDisplayMode.fullScreen)),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icChevronUp, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).show,
|
||||
onTap: () => controller.displayScreenTypeComposerAction(ScreenDisplayMode.normal)),
|
||||
Expanded(child: Padding(
|
||||
padding: EdgeInsets.only(left: 16, right: 80),
|
||||
child: _buildTitleComposer(context),
|
||||
)),
|
||||
]))
|
||||
)
|
||||
)
|
||||
)),
|
||||
if (controller.screenDisplayMode == ScreenDisplayMode.fullScreen)
|
||||
@@ -116,29 +108,15 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
backgroundColor: Colors.black38,
|
||||
body: Align(alignment: Alignment.center, child: Card(
|
||||
color: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(24))),
|
||||
width: responsiveUtils.getSizeScreenWidth(context) * 0.85,
|
||||
height: responsiveUtils.getSizeScreenHeight(context) * 0.9,
|
||||
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)),
|
||||
]
|
||||
))
|
||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
||||
child: LayoutBuilder(builder: (context, constraints) =>
|
||||
PointerInterceptor(child: _buildBodyForDesktop(context, constraints)))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -150,27 +128,30 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
backgroundColor: Colors.black38,
|
||||
body: Align(alignment: Alignment.center, child: Card(
|
||||
color: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(24))),
|
||||
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)),
|
||||
]
|
||||
))
|
||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
||||
child: LayoutBuilder(builder: (context, constraints) =>
|
||||
PointerInterceptor(child: _buildBodyForDesktop(context, constraints)))
|
||||
)
|
||||
)
|
||||
))
|
||||
),
|
||||
tabletLarge: Scaffold(
|
||||
backgroundColor: Colors.black38,
|
||||
body: Align(alignment: Alignment.center, child: Card(
|
||||
color: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(24))),
|
||||
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 20),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
||||
child: LayoutBuilder(builder: (context, constraints) =>
|
||||
PointerInterceptor(child: _buildBodyForDesktop(context, constraints)))
|
||||
)
|
||||
)
|
||||
))
|
||||
@@ -179,55 +160,55 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
}
|
||||
|
||||
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.saveEmailAsDrafts(context);
|
||||
controller.closeComposerWeb();
|
||||
}),
|
||||
]
|
||||
),
|
||||
return Row(
|
||||
children: [
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icCloseMailbox, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).close,
|
||||
onTap: () {
|
||||
controller.saveEmailAsDrafts(context);
|
||||
controller.closeComposerWeb();
|
||||
}),
|
||||
if (responsiveUtils.isDesktop(context))
|
||||
Obx(() => buildIconWeb(
|
||||
icon: SvgPicture.asset(
|
||||
controller.screenDisplayMode == ScreenDisplayMode.fullScreen
|
||||
? imagePaths.icFullScreenExit
|
||||
: imagePaths.icFullScreenComposer,
|
||||
fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).fullscreen,
|
||||
onTap: () => controller.displayScreenTypeComposerAction(controller.screenDisplayMode == ScreenDisplayMode.fullScreen
|
||||
? ScreenDisplayMode.normal
|
||||
: ScreenDisplayMode.fullScreen))),
|
||||
if (responsiveUtils.isDesktop(context))
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icMinimize, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).minimize,
|
||||
onTap: () => controller.displayScreenTypeComposerAction(ScreenDisplayMode.minimize)),
|
||||
Expanded(child: _buildTitleComposer(context)),
|
||||
SizedBox(width: 100),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAppBarForMobile(BuildContext context, bool isEnableSendButton) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
|
||||
padding: EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 10),
|
||||
color: Colors.white,
|
||||
child: Row(
|
||||
children: [
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icCloseComposer, fit: BoxFit.fill),
|
||||
icon: SvgPicture.asset(imagePaths.icClose, width: 30, height: 30, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).close,
|
||||
iconPadding: EdgeInsets.zero,
|
||||
onTap: () {
|
||||
controller.saveEmailAsDrafts(context);
|
||||
controller.closeComposerWeb();
|
||||
}),
|
||||
Spacer(),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icAttachmentsComposer, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).pick_attachments,
|
||||
onTap: () => controller.openFilePickerByType(context, FileType.any)),
|
||||
Expanded(child: _buildTitleComposer(context)),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(
|
||||
imagePaths.icSendComposer,
|
||||
color: isEnableSendButton ? AppColor.colorTextButton : AppColor.colorDisableMailboxCreateButton,
|
||||
isEnableSendButton ? imagePaths.icSendMobile : imagePaths.icSendDisable,
|
||||
fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).send,
|
||||
onTap: () => controller.sendEmailAction(context)),
|
||||
@@ -238,133 +219,157 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
|
||||
Widget _buildBottomBar(BuildContext context, bool isEnableSendButton) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 10, right: 20, top: 18, bottom: 18),
|
||||
color: AppColor.colorBottomBarComposer,
|
||||
child: Row(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
color: Colors.white,
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center,
|
||||
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)
|
||||
),
|
||||
)
|
||||
buildTextButton(
|
||||
AppLocalizations.of(context).cancel,
|
||||
textStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 17, color: AppColor.lineItemListColor),
|
||||
backgroundColor: AppColor.emailAddressChipColor,
|
||||
width: 150,
|
||||
height: 44,
|
||||
radius: 10,
|
||||
onTap: () => controller.closeComposerWeb()),
|
||||
SizedBox(width: 12),
|
||||
buildTextButton(
|
||||
AppLocalizations.of(context).save_to_drafts,
|
||||
textStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 17, color: AppColor.colorTextButton),
|
||||
backgroundColor: AppColor.emailAddressChipColor,
|
||||
width: 150,
|
||||
height: 44,
|
||||
radius: 10,
|
||||
onTap: () {
|
||||
controller.saveEmailAsDrafts(context);
|
||||
controller.closeComposerWeb();
|
||||
}),
|
||||
SizedBox(width: 12),
|
||||
buildTextButton(
|
||||
AppLocalizations.of(context).send,
|
||||
width: 150,
|
||||
height: 44,
|
||||
radius: 10,
|
||||
onTap: () => controller.sendEmailAction(context)),
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBodyForDesktop(BuildContext context, BoxConstraints constraints) {
|
||||
return Column(children: [
|
||||
Padding(padding: EdgeInsets.only(left: 20, right: 20, top: 8), child: _buildAppBar(context)),
|
||||
Padding(padding: EdgeInsets.only(top: 8), child: Divider(color: AppColor.colorDividerComposer, height: 1)),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 16),
|
||||
child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Padding(padding: EdgeInsets.only(top: 20),
|
||||
child: (AvatarBuilder()
|
||||
..text('${controller.mailboxDashBoardController.userProfile.value?.getAvatarText() ?? ''}')
|
||||
..size(56)
|
||||
..addTextStyle(TextStyle(fontWeight: FontWeight.w600, fontSize: 28, color: Colors.white))
|
||||
..backgroundColor(AppColor.colorAvatar))
|
||||
.build()),
|
||||
Expanded(child: Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: Column(children: [
|
||||
_buildEmailAddress(context, constraints),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Padding(padding: EdgeInsets.only(right: 16), child: _buildSubjectEmail(context)),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
_buildListButton(context),
|
||||
]),
|
||||
))
|
||||
])),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Expanded(child: Padding(
|
||||
padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 60, right: responsiveUtils.isMobile(context) ? 16 : 25),
|
||||
child: _buildEditorAndAttachments(context))),
|
||||
Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Obx(() => _buildBottomBar(context, controller.isEnableEmailSendButton.value)),
|
||||
]);
|
||||
}
|
||||
|
||||
Widget _buildTitleComposer(BuildContext context) {
|
||||
return Obx(() => Text(
|
||||
controller.subjectEmail.isNotEmpty == true
|
||||
? controller.subjectEmail.value ?? ''
|
||||
: AppLocalizations.of(context).new_message.capitalizeFirstEach,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
overflow: kIsWeb ? null : TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w500,
|
||||
color: controller.screenDisplayMode == ScreenDisplayMode.minimize ? Colors.white : Colors.black),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black),
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildEmailAddress(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
Widget _buildEmailAddress(BuildContext context, BoxConstraints constraints) {
|
||||
log('ComposerView::_buildEmailAddress(): height: ${constraints.maxHeight}');
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: _getMaxHeightEmailAddressWidget(context, constraints)),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
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()
|
||||
),
|
||||
],
|
||||
Obx(() => Padding(
|
||||
padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0),
|
||||
child: (EmailAddressInputBuilder(context, imagePaths,
|
||||
PrefixEmailAddress.to,
|
||||
controller.listToEmailAddress,
|
||||
controller.listEmailAddressType,
|
||||
expandMode: controller.toAddressExpandMode.value,
|
||||
controller: controller.toEmailAddressController,
|
||||
focusNode: controller.toEmailAddressFocusNode,
|
||||
isInitial: controller.isInitialRecipient.value)
|
||||
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
|
||||
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
|
||||
..addOnAddEmailAddressTypeAction((prefixEmailAddress) => controller.addEmailAddressType(prefixEmailAddress))
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
|
||||
.build()
|
||||
)),
|
||||
Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true
|
||||
? Divider(color: AppColor.colorDividerComposer, height: 1)
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.cc) == true
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0),
|
||||
child: (EmailAddressInputBuilder(context, imagePaths,
|
||||
PrefixEmailAddress.cc,
|
||||
controller.listCcEmailAddress,
|
||||
controller.listEmailAddressType,
|
||||
expandMode: controller.ccAddressExpandMode.value,
|
||||
controller: controller.ccEmailAddressController,
|
||||
isInitial: controller.isInitialRecipient.value,)
|
||||
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
|
||||
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
|
||||
..addOnDeleteEmailAddressTypeAction((prefixEmailAddress) => controller.deleteEmailAddressType(prefixEmailAddress))
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
|
||||
.build())
|
||||
: SizedBox.shrink()
|
||||
),
|
||||
Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true
|
||||
? Divider(color: AppColor.colorDividerComposer, height: 1)
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.listEmailAddressType.contains(PrefixEmailAddress.bcc) == true
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(left: responsiveUtils.isMobile(context) ? 16 : 0),
|
||||
child: (EmailAddressInputBuilder(context, imagePaths,
|
||||
PrefixEmailAddress.bcc,
|
||||
controller.listBccEmailAddress,
|
||||
controller.listEmailAddressType,
|
||||
expandMode: controller.bccAddressExpandMode.value,
|
||||
controller: controller.bccEmailAddressController,
|
||||
isInitial: controller.isInitialRecipient.value,)
|
||||
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
|
||||
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
|
||||
..addOnDeleteEmailAddressTypeAction((prefixEmailAddress) => controller.deleteEmailAddressType(prefixEmailAddress))
|
||||
..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))
|
||||
..addOnSuggestionEmailAddress((word) => controller.getAutoCompleteSuggestion(word)))
|
||||
.build())
|
||||
: SizedBox.shrink()
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -377,61 +382,74 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
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()
|
||||
Expanded(
|
||||
child: FocusScope(child: Focus(
|
||||
onFocusChange: (focus) => controller.onSubjectEmailFocusChange(focus),
|
||||
child: (TextFieldBuilder()
|
||||
..key(Key('subject_email_input'))
|
||||
..cursorColor(AppColor.colorTextButton)
|
||||
..onChange((value) => controller.setSubjectEmail(value))
|
||||
..textStyle(TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal))
|
||||
..textDecoration(InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none))
|
||||
..addController(controller.subjectEmailInputController))
|
||||
.build(),
|
||||
))
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildListButton(BuildContext context) {
|
||||
return Transform(
|
||||
transform: Matrix4.translationValues(-10.0, 0.0, 0.0),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 5),
|
||||
child: Row(children: [
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icAttachmentsComposer, color: AppColor.colorTextButton, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).attach_file,
|
||||
onTap: () => controller.openFilePickerByType(context, FileType.any)),
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEditorAndAttachments(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 10),
|
||||
padding: EdgeInsets.only(top: 4, bottom: 4, left: responsiveUtils.isMobile(context) ? 16 : 20, right: responsiveUtils.isMobile(context) ? 16: 0),
|
||||
child: _buildAttachmentsTitle(context, controller.attachments, controller.expandModeAttachments.value))
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isEmpty
|
||||
? _buildAttachmentsLoadingView()
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isNotEmpty && controller.expandModeAttachments.value == ExpandMode.COLLAPSE
|
||||
? Padding(padding: EdgeInsets.symmetric(horizontal: 10), child: Divider(color: AppColor.colorDividerComposer, height: 1))
|
||||
: SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(bottom: 8, left: 10, right: 10),
|
||||
padding: EdgeInsets.only(bottom: 8, left: responsiveUtils.isMobile(context) ? 16 : 10, right: responsiveUtils.isMobile(context) ? 16 : 10),
|
||||
child: _buildAttachmentsList(context, controller.attachments, controller.expandModeAttachments.value))
|
||||
: SizedBox.shrink()),
|
||||
Obx(() {
|
||||
if (controller.composerArguments.value != null) {
|
||||
if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) {
|
||||
final initContent = controller.textEditorWeb ?? '';
|
||||
log('ComposerView::_buildEditorAndAttachments(): initContent: $initContent');
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
} else if (controller.composerArguments.value?.emailActionType == EmailActionType.edit) {
|
||||
final initContent = controller.getEmailContentDraftsAsHtml();
|
||||
log('ComposerView::_buildEditorAndAttachments(): initContent: $initContent');
|
||||
final initContent = controller.textEditorWeb ?? controller.getEmailContentDraftsAsHtml();
|
||||
if (initContent != null) {
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
} else {
|
||||
return SizedBox.shrink();
|
||||
}
|
||||
} else {
|
||||
final initContent = controller.getEmailContentQuotedAsHtml(context, controller.composerArguments.value!);
|
||||
log('ComposerView::_buildEditorAndAttachments(): initContent: $initContent');
|
||||
final initContent = controller.textEditorWeb ?? controller.getEmailContentQuotedAsHtml(context, controller.composerArguments.value!);
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
}
|
||||
} else {
|
||||
@@ -443,11 +461,13 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
}
|
||||
|
||||
Widget _buildEditor(BuildContext context, String initContent) {
|
||||
log('ComposerView::_buildEditor(): initContent: $initContent');
|
||||
|
||||
return HtmlEditorBrowser.HtmlEditor(
|
||||
key: Key('composer_editor_web'),
|
||||
controller: controller.htmlControllerBrowser,
|
||||
htmlEditorOptions: HtmlEditorBrowser.HtmlEditorOptions(
|
||||
hint: '<p></p>',
|
||||
hint: '${AppLocalizations.of(context).hint_compose_email}',
|
||||
initialText: initContent,
|
||||
darkMode: false,
|
||||
),
|
||||
@@ -460,7 +480,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
log('ComposerView::_buildComposerEditor(): onBeforeCommand');
|
||||
controller.setTextEditorWeb(currentHtml);
|
||||
}, onChangeContent: (String? changed) {
|
||||
log('ComposerView::_buildComposerEditor(): onChangeContent');
|
||||
log('ComposerView::_buildComposerEditor(): onChangeContent : $changed');
|
||||
controller.setTextEditorWeb(changed);
|
||||
}, onInit: () {
|
||||
log('ComposerView::_buildComposerEditor(): onInit');
|
||||
@@ -470,6 +490,10 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
controller.htmlControllerBrowser.setFocus();
|
||||
});
|
||||
}, onBlur: () {
|
||||
controller.onEditorFocusChange(false);
|
||||
}, onMouseDown: () {
|
||||
controller.onEditorFocusChange(true);
|
||||
}
|
||||
),
|
||||
);
|
||||
@@ -555,4 +579,16 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
final currentWidth = constraints.maxWidth - 40;
|
||||
return currentWidth / _getMaxItemRowListAttachment(context, constraints);
|
||||
}
|
||||
|
||||
double _getMaxHeightEmailAddressWidget(BuildContext context, BoxConstraints constraints) {
|
||||
if (responsiveUtils.isDesktop(context)) {
|
||||
if (controller.screenDisplayMode == ScreenDisplayMode.normal) {
|
||||
return constraints.maxHeight > 0 ? constraints.maxHeight * 0.25 : 150.0;
|
||||
} else {
|
||||
return constraints.maxHeight > 0 ? constraints.maxHeight * 0.3 : 150.0;
|
||||
}
|
||||
} else {
|
||||
return constraints.maxHeight > 0 ? constraints.maxHeight * 0.4 : 150.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,29 +12,32 @@ import 'package:model/model.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
typedef OnOpenExpandAddressActionClick = void Function();
|
||||
typedef OnSuggestionEmailAddress = Future<List<EmailAddress>> Function(String word);
|
||||
typedef OnUpdateListEmailAddressAction = void Function(PrefixEmailAddress, List<EmailAddress>);
|
||||
typedef OnAddEmailAddressTypeAction = void Function(PrefixEmailAddress);
|
||||
typedef OnDeleteEmailAddressTypeAction = void Function(PrefixEmailAddress);
|
||||
typedef OnShowFullListEmailAddressAction = void Function(PrefixEmailAddress);
|
||||
typedef OnFocusEmailAddressChangeAction = void Function(PrefixEmailAddress, bool);
|
||||
|
||||
class EmailAddressInputBuilder {
|
||||
|
||||
final BuildContext _context;
|
||||
final ImagePaths _imagePaths;
|
||||
final AppToast _appToast;
|
||||
final ExpandMode expandMode;
|
||||
final PrefixEmailAddress _prefixEmailAddress;
|
||||
List<EmailAddress> _listEmailAddress;
|
||||
final List<PrefixEmailAddress> _listEmailAddressType;
|
||||
final TextEditingController? controller;
|
||||
final FocusNode? focusNode;
|
||||
final bool? isInitial;
|
||||
final bool hasAvatar;
|
||||
|
||||
OnOpenExpandAddressActionClick? _onOpenExpandAddressActionClick;
|
||||
List<EmailAddress> _listEmailAddress;
|
||||
|
||||
OnUpdateListEmailAddressAction? _onUpdateListEmailAddressAction;
|
||||
OnSuggestionEmailAddress? _onSuggestionEmailAddress;
|
||||
|
||||
void addExpandAddressActionClick(OnOpenExpandAddressActionClick onOpenExpandAddressActionClick) {
|
||||
_onOpenExpandAddressActionClick = onOpenExpandAddressActionClick;
|
||||
}
|
||||
OnAddEmailAddressTypeAction? _onAddEmailAddressTypeAction;
|
||||
OnDeleteEmailAddressTypeAction? _onDeleteEmailAddressTypeAction;
|
||||
OnShowFullListEmailAddressAction? _onShowFullListEmailAddressAction;
|
||||
OnFocusEmailAddressChangeAction? _onFocusEmailAddressChangeAction;
|
||||
|
||||
void addOnUpdateListEmailAddressAction(OnUpdateListEmailAddressAction onUpdateListEmailAddressAction) {
|
||||
_onUpdateListEmailAddressAction = onUpdateListEmailAddressAction;
|
||||
@@ -44,124 +47,174 @@ class EmailAddressInputBuilder {
|
||||
_onSuggestionEmailAddress = onSuggestionEmailAddress;
|
||||
}
|
||||
|
||||
void addOnAddEmailAddressTypeAction(OnAddEmailAddressTypeAction onAddEmailAddressTypeAction) {
|
||||
_onAddEmailAddressTypeAction = onAddEmailAddressTypeAction;
|
||||
}
|
||||
|
||||
void addOnDeleteEmailAddressTypeAction(OnDeleteEmailAddressTypeAction onDeleteEmailAddressTypeAction) {
|
||||
_onDeleteEmailAddressTypeAction = onDeleteEmailAddressTypeAction;
|
||||
}
|
||||
|
||||
void addOnShowFullListEmailAddressAction(OnShowFullListEmailAddressAction onShowFullListEmailAddressAction) {
|
||||
_onShowFullListEmailAddressAction = onShowFullListEmailAddressAction;
|
||||
}
|
||||
|
||||
void addOnFocusEmailAddressChangeAction(OnFocusEmailAddressChangeAction onFocusEmailAddressChangeAction) {
|
||||
_onFocusEmailAddressChangeAction = onFocusEmailAddressChangeAction;
|
||||
}
|
||||
|
||||
EmailAddressInputBuilder(
|
||||
this._context,
|
||||
this._imagePaths,
|
||||
this._appToast,
|
||||
this._prefixEmailAddress,
|
||||
this._listEmailAddress,
|
||||
this._listEmailAddressType,
|
||||
{
|
||||
this.isInitial,
|
||||
this.hasAvatar = false,
|
||||
this.controller,
|
||||
this.expandMode = ExpandMode.COLLAPSE,
|
||||
this.focusNode,
|
||||
this.expandMode = ExpandMode.EXPAND,
|
||||
}
|
||||
);
|
||||
|
||||
Widget build() {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 8, top: 15),
|
||||
child: Text(
|
||||
'${_prefixEmailAddress.asName(_context)}:',
|
||||
style: TextStyle(fontSize: 15, color: AppColor.colorHintEmailAddressInput))),
|
||||
Expanded(child: _buildTagEditor()),
|
||||
Text('${_prefixEmailAddress.asName(_context)}:',
|
||||
style: TextStyle(fontSize: 15, color: AppColor.colorHintEmailAddressInput)),
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(_imagePaths.icAddEmailAddress, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(_context).email_address_suggestion,
|
||||
onTap: () => {}),
|
||||
Expanded(child: Padding(
|
||||
padding: EdgeInsets.only(right: _listEmailAddressType.isNotEmpty ? 16 : 0),
|
||||
child: _buildTagEditor())),
|
||||
if (_prefixEmailAddress == PrefixEmailAddress.to)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: kIsWeb ? 8 : 0),
|
||||
child: _buildButtonExpandAddress())
|
||||
Row(children: [
|
||||
if (!_listEmailAddressType.contains(PrefixEmailAddress.cc))
|
||||
Transform(
|
||||
transform: Matrix4.translationValues(
|
||||
_listEmailAddressType.contains(PrefixEmailAddress.bcc) ? 0.0 : 16.0,
|
||||
0.0, 0.0),
|
||||
child: buildTextCircleButton(AppLocalizations.of(_context).cc_email_address_prefix,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline,
|
||||
color: AppColor.lineItemListColor),
|
||||
onTap: () => _onAddEmailAddressTypeAction?.call(PrefixEmailAddress.cc))),
|
||||
if (!_listEmailAddressType.contains(PrefixEmailAddress.bcc))
|
||||
buildTextCircleButton(AppLocalizations.of(_context).bcc_email_address_prefix,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline,
|
||||
color: AppColor.lineItemListColor),
|
||||
onTap: () => _onAddEmailAddressTypeAction?.call(PrefixEmailAddress.bcc)),
|
||||
]),
|
||||
if (_prefixEmailAddress != PrefixEmailAddress.to)
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(_imagePaths.icCloseComposer, fit: BoxFit.fill),
|
||||
onTap: () => _onDeleteEmailAddressTypeAction?.call(_prefixEmailAddress))
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildButtonExpandAddress() {
|
||||
return Material(
|
||||
type: MaterialType.circle,
|
||||
color: Colors.transparent,
|
||||
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()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTagEditor() {
|
||||
return StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
return TagEditor<EmailAddress>(
|
||||
length: _listEmail.length,
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
textInputAction: TextInputAction.done,
|
||||
hasAddButton: false,
|
||||
tagSpacing: 8,
|
||||
delimiters: [' '],
|
||||
resetTextOnSubmitted: true,
|
||||
textStyle: TextStyle(color: AppColor.colorEmailAddress, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
onSubmitted: (value) {
|
||||
if (GetUtils.isEmail(value)) {
|
||||
setState(() => _listEmailAddress.add(EmailAddress(value, value)));
|
||||
_onUpdateListEmailAddressAction?.call(_prefixEmailAddress, _listEmailAddress);
|
||||
} else {
|
||||
_appToast.showErrorToast(AppLocalizations.of(context).email_address_is_not_in_the_correct_format);
|
||||
}
|
||||
},
|
||||
inputDecoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: AppLocalizations.of(_context).hint_text_email_address,
|
||||
hintMaxLines: 1,
|
||||
hintStyle: TextStyle(color: AppColor.colorHintEmailAddressInput, fontSize: 14, fontWeight: FontWeight.w500)
|
||||
),
|
||||
tagBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.only(top: kIsWeb ? 8 : 0),
|
||||
child: Chip(
|
||||
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,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(width: 0, color: AppColor.emailAddressChipColor),
|
||||
final newListEmailAddress = _isCollapse ? _listEmailAddress.sublist(0, 1) : _listEmailAddress;
|
||||
return FocusScope(child: Focus(
|
||||
onFocusChange: (focus) => _onFocusEmailAddressChangeAction?.call(_prefixEmailAddress, focus),
|
||||
child: TagEditor<EmailAddress>(
|
||||
length: newListEmailAddress.length,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
textInputAction: TextInputAction.done,
|
||||
hasAddButton: false,
|
||||
tagSpacing: 8,
|
||||
delimiters: [' '],
|
||||
minTextFieldWidth: 20,
|
||||
resetTextOnSubmitted: true,
|
||||
textStyle: TextStyle(color: AppColor.colorEmailAddress, fontSize: 14, fontWeight: FontWeight.w500),
|
||||
onSubmitted: (value) {
|
||||
setState(() => _listEmailAddress.add(EmailAddress(null, value)));
|
||||
_onUpdateListEmailAddressAction?.call(_prefixEmailAddress, _listEmailAddress);
|
||||
},
|
||||
inputDecoration: InputDecoration(border: InputBorder.none),
|
||||
tagBuilder: (context, index) => Stack(alignment: Alignment.centerRight, children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: kIsWeb ? 8 : 0, right: _isCollapse ? 50 : 0),
|
||||
child: InkWell(
|
||||
onTap: () => _isCollapse ? _onShowFullListEmailAddressAction?.call(_prefixEmailAddress) : null,
|
||||
child: Chip(
|
||||
labelPadding: EdgeInsets.only(left: 12, right: 12, bottom: 2),
|
||||
label: Text(newListEmailAddress[index].asString(), maxLines: 1, overflow: kIsWeb ? null : TextOverflow.ellipsis),
|
||||
deleteIcon: SvgPicture.asset(_imagePaths.icClose, fit: BoxFit.fill),
|
||||
labelStyle: TextStyle(color: Colors.black, fontSize: 17, fontWeight: FontWeight.normal),
|
||||
backgroundColor: _isEmailAddressValid(_listEmailAddress[index].emailAddress) ? AppColor.colorEmailAddressTag : Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(
|
||||
width: _isEmailAddressValid(_listEmailAddress[index].emailAddress) ? 0 : 1,
|
||||
color: _isEmailAddressValid(_listEmailAddress[index].emailAddress) ? AppColor.colorEmailAddressTag : AppColor.colorBorderEmailAddressInvalid),
|
||||
),
|
||||
avatar: newListEmailAddress[index].displayName.isNotEmpty
|
||||
? CircleAvatar(
|
||||
backgroundColor: AppColor.colorTextButton,
|
||||
child: Text(
|
||||
_listEmailAddress[index].displayName[0].toUpperCase(),
|
||||
style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500)))
|
||||
: null,
|
||||
onDeleted: () {
|
||||
setState(() => _listEmailAddress.removeAt(index));
|
||||
_onUpdateListEmailAddressAction?.call(_prefixEmailAddress, _listEmailAddress);
|
||||
},
|
||||
)
|
||||
)
|
||||
),
|
||||
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);
|
||||
},
|
||||
)),
|
||||
onTagChanged: (String value) {
|
||||
if (GetUtils.isEmail(value)) {
|
||||
setState(() => _listEmailAddress.add(EmailAddress(value, value)));
|
||||
_onUpdateListEmailAddressAction?.call(_prefixEmailAddress, _listEmailAddress);
|
||||
} else {
|
||||
_appToast.showErrorToast(AppLocalizations.of(context).email_address_is_not_in_the_correct_format);
|
||||
}
|
||||
},
|
||||
findSuggestions: (String query) {
|
||||
if (query.isNotEmpty && _onSuggestionEmailAddress != null) {
|
||||
return _onSuggestionEmailAddress!(query);
|
||||
}
|
||||
return [];
|
||||
},
|
||||
suggestionBuilder: (context, tagEditorState, emailAddress) {
|
||||
return _buildSuggestionItem(setState, context, tagEditorState, emailAddress);
|
||||
},
|
||||
);
|
||||
if (_isCollapse) _buildCounter(context, _listEmailAddress.length - newListEmailAddress.length),
|
||||
]),
|
||||
onTagChanged: (String value) {
|
||||
setState(() => _listEmailAddress.add(EmailAddress(null, value)));
|
||||
_onUpdateListEmailAddressAction?.call(_prefixEmailAddress, _listEmailAddress);
|
||||
},
|
||||
findSuggestions: (String query) {
|
||||
if (query.isNotEmpty && _onSuggestionEmailAddress != null) {
|
||||
return _onSuggestionEmailAddress!(query);
|
||||
}
|
||||
return [];
|
||||
},
|
||||
suggestionBuilder: (context, tagEditorState, emailAddress) {
|
||||
return _buildSuggestionItem(setState, context, tagEditorState, emailAddress);
|
||||
},
|
||||
)
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
List<String> get _listEmail => _listEmailAddress.map((emailAddress) => emailAddress.asString()).toList();
|
||||
Widget _buildCounter(BuildContext context, int count) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 8, top: kIsWeb ? 8 : 0),
|
||||
child: InkWell(
|
||||
onTap: () => _onShowFullListEmailAddressAction?.call(_prefixEmailAddress),
|
||||
child: Chip(
|
||||
labelPadding: EdgeInsets.symmetric(horizontal: 8),
|
||||
label: Text('+$count', maxLines: 1, overflow: kIsWeb ? null : TextOverflow.ellipsis),
|
||||
labelStyle: TextStyle(color: Colors.black, fontSize: 17, fontWeight: FontWeight.normal),
|
||||
backgroundColor: AppColor.colorEmailAddressTag,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(width: 0, color: AppColor.colorEmailAddressTag),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool get _isCollapse {
|
||||
return _listEmailAddress.length > 1 && expandMode == ExpandMode.COLLAPSE;
|
||||
}
|
||||
|
||||
Widget _buildSuggestionItem(StateSetter setState, BuildContext context, TagsEditorState<EmailAddress> tagEditorState, EmailAddress emailAddress) {
|
||||
return Container(
|
||||
@@ -175,14 +228,14 @@ class EmailAddressInputBuilder {
|
||||
backgroundColor: AppColor.avatarColor,
|
||||
child: Text(
|
||||
emailAddress.asString().isNotEmpty ? emailAddress.asString()[0].toUpperCase() : '',
|
||||
style: TextStyle(color: AppColor.appColor, fontSize: 16, fontWeight: FontWeight.w500))),
|
||||
style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w600))),
|
||||
title: Text(
|
||||
emailAddress.asString(),
|
||||
style: TextStyle(color: AppColor.nameUserColor, fontSize: 14, fontWeight: FontWeight.w500)),
|
||||
style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.normal)),
|
||||
subtitle: emailAddress.displayName.isNotEmpty && emailAddress.emailAddress.isNotEmpty
|
||||
? Text(
|
||||
emailAddress.emailAddress,
|
||||
style: TextStyle(color: AppColor.baseTextColor, fontSize: 12, fontWeight: FontWeight.w500))
|
||||
emailAddress.emailAddress,
|
||||
style: TextStyle(color: AppColor.colorHintSearchBar, fontSize: 13, fontWeight: FontWeight.normal))
|
||||
: null,
|
||||
onTap: () {
|
||||
setState(() => _listEmailAddress.add(emailAddress));
|
||||
@@ -192,4 +245,6 @@ class EmailAddressInputBuilder {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool _isEmailAddressValid(String emailAddress) => GetUtils.isEmail(emailAddress);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SuggestionsBoxController {
|
||||
final BuildContext context;
|
||||
|
||||
OverlayEntry? overlayEntry;
|
||||
|
||||
bool _isOpened = false;
|
||||
|
||||
bool get isOpened => _isOpened;
|
||||
|
||||
SuggestionsBoxController(this.context);
|
||||
|
||||
void open() {
|
||||
if (_isOpened) return;
|
||||
assert(overlayEntry != null);
|
||||
Overlay.of(context)?.insert(overlayEntry!);
|
||||
_isOpened = true;
|
||||
}
|
||||
|
||||
void close() {
|
||||
if (!_isOpened) return;
|
||||
assert(overlayEntry != null);
|
||||
overlayEntry!.remove();
|
||||
_isOpened = false;
|
||||
}
|
||||
|
||||
void toggle() {
|
||||
if (_isOpened) {
|
||||
close();
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/state.dart' as jmapState;
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:rxdart/transformers.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart';
|
||||
@@ -457,7 +458,7 @@ class MailboxController extends BaseMailboxController {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||
builder: (BuildContext context) => (ConfirmDialogBuilder(_imagePaths)
|
||||
builder: (BuildContext context) => PointerInterceptor(child: (ConfirmDialogBuilder(_imagePaths)
|
||||
..key(Key('confirm_dialog_delete_mailbox'))
|
||||
..title(AppLocalizations.of(context).delete_mailboxes)
|
||||
..content(AppLocalizations.of(context).message_confirmation_dialog_delete_mailbox(presentationMailbox.name?.name ?? ''))
|
||||
@@ -467,7 +468,7 @@ class MailboxController extends BaseMailboxController {
|
||||
..onCloseButtonAction(() => popBack())
|
||||
..onConfirmButtonAction(AppLocalizations.of(context).delete, () => _deleteMailboxAction(presentationMailbox))
|
||||
..onCancelButtonAction(AppLocalizations.of(context).cancel, () => popBack()))
|
||||
.build());
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -207,10 +207,10 @@ class AppLocalizations {
|
||||
);
|
||||
}
|
||||
|
||||
String get your_email_should_have_at_least_one_recipient {
|
||||
String get message_dialog_send_email_without_recipient {
|
||||
return Intl.message(
|
||||
'Your email should have at least one recipient',
|
||||
name: 'your_email_should_have_at_least_one_recipient',
|
||||
name: 'message_dialog_send_email_without_recipient',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -810,10 +810,10 @@ class AppLocalizations {
|
||||
name: 'show_all');
|
||||
}
|
||||
|
||||
String get message_confirm_send_email {
|
||||
String get message_dialog_send_email_without_a_subject {
|
||||
return Intl.message(
|
||||
'Are you sure to send messages without a subject?',
|
||||
name: 'message_confirm_send_email');
|
||||
name: 'message_dialog_send_email_without_a_subject');
|
||||
}
|
||||
|
||||
String get app_name {
|
||||
@@ -888,4 +888,72 @@ class AppLocalizations {
|
||||
'Collapse',
|
||||
name: 'collapse');
|
||||
}
|
||||
|
||||
String get save_to_drafts {
|
||||
return Intl.message(
|
||||
'Save to drafts',
|
||||
name: 'save_to_drafts',
|
||||
);
|
||||
}
|
||||
|
||||
String get hint_compose_email {
|
||||
return Intl.message(
|
||||
'Start composing a letter...',
|
||||
name: 'hint_compose_email');
|
||||
}
|
||||
|
||||
String get email_address_suggestion {
|
||||
return Intl.message(
|
||||
'Email address suggestion',
|
||||
name: 'email_address_suggestion',
|
||||
);
|
||||
}
|
||||
|
||||
String get attach_file {
|
||||
return Intl.message(
|
||||
'Attach file',
|
||||
name: 'attach_file');
|
||||
}
|
||||
|
||||
String get show {
|
||||
return Intl.message(
|
||||
'Show',
|
||||
name: 'show');
|
||||
}
|
||||
|
||||
String get add_recipients {
|
||||
return Intl.message(
|
||||
'Add recipients',
|
||||
name: 'add_recipients');
|
||||
}
|
||||
|
||||
String get sending_failed {
|
||||
return Intl.message(
|
||||
'Sending failed',
|
||||
name: 'sending_failed');
|
||||
}
|
||||
|
||||
String get send_anyway {
|
||||
return Intl.message(
|
||||
'Send anyway',
|
||||
name: 'send_anyway');
|
||||
}
|
||||
|
||||
String get empty_subject {
|
||||
return Intl.message(
|
||||
'Empty subject',
|
||||
name: 'empty_subject');
|
||||
}
|
||||
|
||||
String get message_dialog_send_email_with_email_address_invalid {
|
||||
return Intl.message(
|
||||
'Check the correctness of email addresses and try again',
|
||||
name: 'message_dialog_send_email_with_email_address_invalid');
|
||||
}
|
||||
|
||||
String get fix_email_addresses {
|
||||
return Intl.message(
|
||||
'Fix email addresses',
|
||||
name: 'fix_email_addresses');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user