TF-83 Fix show message constraints when sending a message
This commit is contained in:
@@ -20,23 +20,23 @@ class AppToast {
|
||||
gravity: ToastGravity.BOTTOM);
|
||||
}
|
||||
|
||||
void showSuccessToast(String message) {
|
||||
void showSuccessToast(String message, {bool isToastLengthLong = false}) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
fontSize: 16,
|
||||
textColor: Colors.white,
|
||||
backgroundColor: AppColor.toastSuccessBackgroundColor,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
toastLength: isToastLengthLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.BOTTOM);
|
||||
}
|
||||
|
||||
void showErrorToast(String message) {
|
||||
void showErrorToast(String message, {bool isToastLengthLong = false}) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
fontSize: 16,
|
||||
textColor: Colors.white,
|
||||
backgroundColor: AppColor.toastErrorBackgroundColor,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
toastLength: isToastLengthLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.BOTTOM);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class AppToast {
|
||||
void showToastWithIcon(BuildContext context, {
|
||||
String? message, String? icon, Color? bgColor,
|
||||
Color? textColor, double? radius, EdgeInsets? padding,
|
||||
TextStyle? textStyle, double? widthToast}) {
|
||||
TextStyle? textStyle, double? widthToast, Duration? toastLength}) {
|
||||
double sizeWidth = context.width > 360 ? 360 : context.width - 40;
|
||||
final toast = Material(
|
||||
color: bgColor ?? Colors.white,
|
||||
@@ -82,7 +82,7 @@ class AppToast {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (icon != null) SvgPicture.asset(icon, width: 24, height: 24, fit: BoxFit.fill),
|
||||
SizedBox(width: 10.0),
|
||||
if (icon != null) SizedBox(width: 10.0),
|
||||
Expanded(child: Text(
|
||||
message ?? '',
|
||||
style: textStyle ?? TextStyle(fontSize: 15, color: textColor ?? Colors.black))),
|
||||
@@ -94,7 +94,7 @@ class AppToast {
|
||||
fToast.showToast(
|
||||
child: toast,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
toastDuration: Duration(seconds: 2),
|
||||
toastDuration: toastLength ?? Duration(seconds: 2),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:core/core.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart';
|
||||
|
||||
abstract class BaseController extends GetxController {
|
||||
abstract class BaseController extends GetxController with MessageDialogActionMixin {
|
||||
final viewState = Rx<Either<Failure, Success>>(Right(UIState.idle));
|
||||
final connectivityResult = Rxn<ConnectivityResult>();
|
||||
|
||||
void consumeState(Stream<Either<Failure, Success>> newStateStream) async {
|
||||
log('BaseController::consumeState():');
|
||||
newStateStream.listen(
|
||||
(state) => onData(state),
|
||||
onError: (error) => onError(error),
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
import 'package:core/core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
mixin MessageDialogActionMixin {
|
||||
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
void showConfirmDialogAction(
|
||||
BuildContext context,
|
||||
String message,
|
||||
String actionName,
|
||||
Function onConfirmAction,
|
||||
{bool hasCancelButton = true, Widget? icon}
|
||||
) {
|
||||
if (_responsiveUtils.isMobile(context)) {
|
||||
(ConfirmationDialogActionSheetBuilder(context)
|
||||
..messageText(message)
|
||||
..styleConfirmButton(TextStyle(fontSize: 20, fontWeight: FontWeight.normal, color: Colors.black))
|
||||
..onCancelAction(AppLocalizations.of(context).cancel, () => popBack())
|
||||
..onConfirmAction(actionName, () {
|
||||
popBack();
|
||||
onConfirmAction.call();
|
||||
})).show();
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||
builder: (BuildContext context) => PointerInterceptor(child: (ConfirmDialogBuilder(_imagePaths)
|
||||
..key(Key('confirm_dialog_action'))
|
||||
..title(AppLocalizations.of(context).sending_failed)
|
||||
..content(message)
|
||||
..addIcon(icon)
|
||||
..colorConfirmButton(AppColor.colorTextButton)
|
||||
..colorCancelButton(AppColor.colorCancelButton)
|
||||
..paddingTitle(icon != null ? EdgeInsets.only(top: 34) : EdgeInsets.only(top: 10))
|
||||
..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(actionName, () {
|
||||
popBack();
|
||||
onConfirmAction.call();
|
||||
})
|
||||
..onCancelButtonAction(hasCancelButton ? AppLocalizations.of(context).cancel : '', () => popBack())
|
||||
..onCloseButtonAction(() => popBack()))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import 'package:dartz/dartz.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:enough_html_editor/enough_html_editor.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:fk_user_agent/fk_user_agent.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -23,7 +24,6 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package: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';
|
||||
@@ -55,7 +55,6 @@ 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 expandModeAttachments = ExpandMode.EXPAND.obs;
|
||||
final composerArguments = Rxn<ComposerArguments>();
|
||||
@@ -386,11 +385,11 @@ class ComposerController extends BaseController {
|
||||
clearFocusEditor(context);
|
||||
|
||||
if (!isEnableEmailSendButton.value) {
|
||||
_showConfirmDialogSendEmailFailed(
|
||||
context,
|
||||
showConfirmDialogAction(context,
|
||||
AppLocalizations.of(context).message_dialog_send_email_without_recipient,
|
||||
AppLocalizations.of(context).add_recipients,
|
||||
() => {},
|
||||
icon: SvgPicture.asset(_imagePaths.icSendToastError, fit: BoxFit.fill),
|
||||
hasCancelButton: false);
|
||||
return;
|
||||
}
|
||||
@@ -399,10 +398,8 @@ class ComposerController extends BaseController {
|
||||
final listEmailAddressInvalid = allListEmailAddress
|
||||
.where((emailAddress) => !GetUtils.isEmail(emailAddress.emailAddress))
|
||||
.toList();
|
||||
|
||||
if (listEmailAddressInvalid.isNotEmpty) {
|
||||
_showConfirmDialogSendEmailFailed(
|
||||
context,
|
||||
showConfirmDialogAction(context,
|
||||
AppLocalizations.of(context).message_dialog_send_email_with_email_address_invalid,
|
||||
AppLocalizations.of(context).fix_email_addresses,
|
||||
() {
|
||||
@@ -410,16 +407,30 @@ class ComposerController extends BaseController {
|
||||
ccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
bccAddressExpandMode.value = ExpandMode.EXPAND;
|
||||
},
|
||||
icon: SvgPicture.asset(_imagePaths.icSendToastError, fit: BoxFit.fill),
|
||||
hasCancelButton: false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (subjectEmail.value == null || subjectEmail.isEmpty == true) {
|
||||
_showConfirmDialogSendEmailFailed(
|
||||
context,
|
||||
showConfirmDialogAction(context,
|
||||
AppLocalizations.of(context).message_dialog_send_email_without_a_subject,
|
||||
AppLocalizations.of(context).send_anyway,
|
||||
() => _handleSendMessages(context));
|
||||
() => _handleSendMessages(context),
|
||||
icon: SvgPicture.asset(_imagePaths.icEmpty, fit: BoxFit.fill),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_validateAttachmentsSize()) {
|
||||
showConfirmDialogAction(
|
||||
context,
|
||||
AppLocalizations.of(context).message_dialog_send_email_exceeds_maximum_size('${
|
||||
filesize(mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0)}'),
|
||||
AppLocalizations.of(context).got_it,
|
||||
() => {},
|
||||
icon: SvgPicture.asset(_imagePaths.icSendToastError, fit: BoxFit.fill),
|
||||
hasCancelButton: false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -512,6 +523,10 @@ class ComposerController extends BaseController {
|
||||
consumeState(_localFilePickerInteractor.execute(fileType: fileType));
|
||||
}
|
||||
|
||||
void openFilePickerByTypeOnWeb(BuildContext context, FileType fileType) async {
|
||||
consumeState(_localFilePickerInteractor.execute(fileType: fileType));
|
||||
}
|
||||
|
||||
void _pickFileFailure(Failure failure) {
|
||||
if (failure is LocalFilePickerFailure) {
|
||||
if (currentContext != null) {
|
||||
@@ -522,32 +537,34 @@ class ComposerController extends BaseController {
|
||||
|
||||
void _pickFileSuccess(Success success) {
|
||||
if (success is LocalFilePickerSuccess) {
|
||||
if (_validateAttachmentsSize(success.pickedFiles)) {
|
||||
if (_validateAttachmentsSize(listFiles: success.pickedFiles)) {
|
||||
_uploadAttachmentsAction(success.pickedFiles);
|
||||
} else {
|
||||
if (currentContext != null) {
|
||||
_appToast.showErrorToast(AppLocalizations.of(currentContext!).the_total_size_of_attachments_in_an_email_exceeds_the_limit);
|
||||
showConfirmDialogAction(
|
||||
currentContext!,
|
||||
AppLocalizations.of(currentContext!).message_dialog_upload_attachments_exceeds_maximum_size('${
|
||||
filesize(mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0)}'),
|
||||
AppLocalizations.of(currentContext!).got_it,
|
||||
() => {},
|
||||
hasCancelButton: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool _validateAttachmentsSize(List<FileInfo> listFiles) {
|
||||
num currentTotalSize = 0;
|
||||
if (attachments.isNotEmpty) {
|
||||
final currentListSize = attachments
|
||||
.map((attachment) => attachment.size?.value ?? 0)
|
||||
.toList();
|
||||
currentTotalSize = currentListSize.reduce((sum, size) => sum + size);
|
||||
log('ComposerController::checkingAttachmentsLimit(): currentTotalSize: $currentTotalSize');
|
||||
bool _validateAttachmentsSize({List<FileInfo>? listFiles}) {
|
||||
final currentTotalAttachmentsSize = attachments.totalSize();
|
||||
log('ComposerController::_validateAttachmentsSize(): $currentTotalAttachmentsSize');
|
||||
num uploadedTotalSize = 0;
|
||||
if (listFiles != null && listFiles.isNotEmpty) {
|
||||
final uploadedListSize = listFiles.map((file) => file.fileSize).toList();
|
||||
uploadedTotalSize = uploadedListSize.reduce((sum, size) => sum + size);
|
||||
log('ComposerController::_validateAttachmentsSize(): uploadedTotalSize: $uploadedTotalSize');
|
||||
}
|
||||
|
||||
final uploadedListSize = listFiles.map((file) => file.fileSize).toList();
|
||||
final uploadedTotalSize = uploadedListSize.reduce((sum, size) => sum + size);
|
||||
log('ComposerController::checkingAttachmentsLimit(): uploadedTotalSize: $uploadedTotalSize');
|
||||
|
||||
final totalSizeReadyToUpload = currentTotalSize + uploadedTotalSize;
|
||||
log('ComposerController::checkingAttachmentsLimit(): totalSizeReadyToUpload: $totalSizeReadyToUpload');
|
||||
final totalSizeReadyToUpload = currentTotalAttachmentsSize + uploadedTotalSize;
|
||||
log('ComposerController::_validateAttachmentsSize(): totalSizeReadyToUpload: $totalSizeReadyToUpload');
|
||||
|
||||
final maxSizeAttachmentsPerEmail = mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value;
|
||||
if (maxSizeAttachmentsPerEmail != null) {
|
||||
@@ -743,46 +760,6 @@ class ComposerController extends BaseController {
|
||||
expandModeAttachments.value = newExpandMode;
|
||||
}
|
||||
|
||||
void _showConfirmDialogSendEmailFailed(BuildContext context, String message,
|
||||
String actionName, Function? onConfirmAction, {bool hasCancelButton = true}) {
|
||||
if (_responsiveUtils.isMobile(context)) {
|
||||
(ConfirmationDialogActionSheetBuilder(context)
|
||||
..messageText(message)
|
||||
..styleConfirmButton(TextStyle(fontSize: 20, fontWeight: FontWeight.normal, color: Colors.black))
|
||||
..onCancelAction(AppLocalizations.of(context).cancel, () => popBack())
|
||||
..onConfirmAction(actionName, () {
|
||||
popBack();
|
||||
onConfirmAction?.call();
|
||||
})).show();
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
|
||||
builder: (BuildContext context) => PointerInterceptor(child: (ConfirmDialogBuilder(_imagePaths)
|
||||
..key(Key('confirm_dialog_send_message'))
|
||||
..title(AppLocalizations.of(context).sending_failed)
|
||||
..content(message)
|
||||
..addIcon(SvgPicture.asset(_imagePaths.icSendToastError, fit: BoxFit.fill))
|
||||
..colorConfirmButton(AppColor.colorTextButton)
|
||||
..colorCancelButton(AppColor.colorCancelButton)
|
||||
..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(actionName, () {
|
||||
popBack();
|
||||
onConfirmAction?.call();
|
||||
})
|
||||
..onCancelButtonAction(hasCancelButton ? AppLocalizations.of(context).cancel : '', () => popBack())
|
||||
..onCloseButtonAction(() => popBack()))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
void addEmailAddressType(PrefixEmailAddress prefixEmailAddress) {
|
||||
listEmailAddressType.add(prefixEmailAddress);
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icAttachmentsComposer, color: AppColor.colorTextButton, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).attach_file,
|
||||
onTap: () => controller.openFilePickerByType(context, FileType.any)),
|
||||
onTap: () => controller.openFilePickerByTypeOnWeb(context, FileType.any)),
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2022-04-05T16:47:07.723009",
|
||||
"@@last_modified": "2022-04-07T14:40:38.896425",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -894,12 +894,6 @@
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"the_total_size_of_attachments_in_an_email_exceeds_the_limit": "The total size of attachments in an email exceeds the limit.",
|
||||
"@the_total_size_of_attachments_in_an_email_exceeds_the_limit": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"your_download_has_started": "Your download has started",
|
||||
"@your_download_has_started": {
|
||||
"type": "text",
|
||||
@@ -1015,5 +1009,31 @@
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"message_dialog_send_email_exceeds_maximum_size": "Your message could not be sent because it exceeds the maximum size of {maxSize}",
|
||||
"@message_dialog_send_email_exceeds_maximum_size": {
|
||||
"type": "text",
|
||||
"placeholders_order": [
|
||||
"maxSize"
|
||||
],
|
||||
"placeholders": {
|
||||
"maxSize": {}
|
||||
}
|
||||
},
|
||||
"message_dialog_upload_attachments_exceeds_maximum_size": "You have reached the maximum file size. Please upload files that total size is less than {maxSize}",
|
||||
"@message_dialog_upload_attachments_exceeds_maximum_size": {
|
||||
"type": "text",
|
||||
"placeholders_order": [
|
||||
"maxSize"
|
||||
],
|
||||
"placeholders": {
|
||||
"maxSize": {}
|
||||
}
|
||||
},
|
||||
"got_it": "Got it",
|
||||
"@got_it": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@@ -950,13 +950,6 @@ class AppLocalizations {
|
||||
name: 'fix_email_addresses');
|
||||
}
|
||||
|
||||
String get the_total_size_of_attachments_in_an_email_exceeds_the_limit {
|
||||
return Intl.message(
|
||||
'The total size of attachments in an email exceeds the limit.',
|
||||
name: 'the_total_size_of_attachments_in_an_email_exceeds_the_limit'
|
||||
);
|
||||
}
|
||||
|
||||
String get your_download_has_started {
|
||||
return Intl.message(
|
||||
'Your download has started',
|
||||
@@ -1069,4 +1062,26 @@ class AppLocalizations {
|
||||
'Version',
|
||||
name: 'version');
|
||||
}
|
||||
|
||||
String message_dialog_send_email_exceeds_maximum_size(String maxSize) {
|
||||
return Intl.message(
|
||||
'Your message could not be sent because it exceeds the maximum size of $maxSize',
|
||||
name: 'message_dialog_send_email_exceeds_maximum_size',
|
||||
args: [maxSize]
|
||||
);
|
||||
}
|
||||
|
||||
String message_dialog_upload_attachments_exceeds_maximum_size(String maxSize) {
|
||||
return Intl.message(
|
||||
'You have reached the maximum file size. Please upload files that total size is less than $maxSize',
|
||||
name: 'message_dialog_upload_attachments_exceeds_maximum_size',
|
||||
args: [maxSize]
|
||||
);
|
||||
}
|
||||
|
||||
String get got_it {
|
||||
return Intl.message(
|
||||
'Got it',
|
||||
name: 'got_it');
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,8 @@ import 'package:model/model.dart';
|
||||
extension ListAttachmentExtension on List<Attachment> {
|
||||
|
||||
num totalSize() {
|
||||
num totalSize = 0;
|
||||
forEach((attachment) {
|
||||
if (attachment.size != null) {
|
||||
totalSize += attachment.size!.value;
|
||||
}
|
||||
});
|
||||
final currentListSize = map((attachment) => attachment.size?.value ?? 0).toList();
|
||||
final totalSize = currentListSize.reduce((sum, size) => sum + size);
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user