TF-675 Implement upload attachment on presentation layer
This commit is contained in:
@@ -3,11 +3,8 @@ import 'package:core/core.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_bindings.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/datasource/composer_datasource.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/datasource/contact_datasource.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/datasource_impl/composer_datasource_impl.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/datasource_impl/contact_datasource_impl.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/network/composer_api.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/repository/auto_complete_repository_impl.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/repository/composer_repository_impl.dart';
|
||||
import 'package:tmail_ui_user/features/composer/data/repository/contact_repository_impl.dart';
|
||||
@@ -21,7 +18,6 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/update_email_dra
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/upload_attachment_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/upload_mutiple_attachment_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/session_extension.dart';
|
||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||
@@ -41,9 +37,13 @@ import 'package:tmail_ui_user/features/manage_account/data/network/manage_accoun
|
||||
import 'package:tmail_ui_user/features/manage_account/data/repository/manage_account_repository_impl.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/upload/data/datasource/attachment_upload_datasource.dart';
|
||||
import 'package:tmail_ui_user/features/upload/data/datasource_impl/attachment_upload_datasource_impl.dart';
|
||||
import 'package:tmail_ui_user/features/upload/data/network/file_uploader.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/usecases/local_file_picker_interactor.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/controller/upload_controller.dart';
|
||||
import 'package:jmap_dart_client/http/http_client.dart' as jmap_http_client;
|
||||
import 'package:worker_manager/worker_manager.dart';
|
||||
|
||||
class ComposerBindings extends BaseBindings {
|
||||
|
||||
@@ -57,7 +57,7 @@ class ComposerBindings extends BaseBindings {
|
||||
}
|
||||
|
||||
void _bindingsUtils() {
|
||||
Get.lazyPut(() => const Uuid());
|
||||
Get.lazyPut(() => FileUploader(Get.find<DioClient>(), Get.find<Executor>()));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -68,7 +68,7 @@ class ComposerBindings extends BaseBindings {
|
||||
dataSources.add(Get.find<TMailContactDataSourceImpl>());
|
||||
}
|
||||
|
||||
Get.lazyPut(() => ComposerDataSourceImpl(Get.find<ComposerAPI>()));
|
||||
Get.lazyPut(() => AttachmentUploadDataSourceImpl(Get.find<FileUploader>()));
|
||||
Get.lazyPut(() => ContactDataSourceImpl());
|
||||
Get.lazyPut(() => EmailDataSourceImpl(Get.find<EmailAPI>()));
|
||||
Get.lazyPut(() => HtmlDataSourceImpl(
|
||||
@@ -82,7 +82,7 @@ class ComposerBindings extends BaseBindings {
|
||||
|
||||
@override
|
||||
void bindingsDataSource() {
|
||||
Get.lazyPut<ComposerDataSource>(() => Get.find<ComposerDataSourceImpl>());
|
||||
Get.lazyPut<AttachmentUploadDataSource>(() => Get.find<AttachmentUploadDataSourceImpl>());
|
||||
Get.lazyPut<ContactDataSource>(() => Get.find<ContactDataSourceImpl>());
|
||||
Get.lazyPut<EmailDataSource>(() => Get.find<EmailDataSourceImpl>());
|
||||
Get.lazyPut<HtmlDataSource>(() => Get.find<HtmlDataSourceImpl>());
|
||||
@@ -91,7 +91,7 @@ class ComposerBindings extends BaseBindings {
|
||||
|
||||
@override
|
||||
void bindingsRepositoryImpl() {
|
||||
Get.lazyPut(() => ComposerRepositoryImpl(Get.find<ComposerDataSource>()));
|
||||
Get.lazyPut(() => ComposerRepositoryImpl(Get.find<AttachmentUploadDataSource>()));
|
||||
Get.lazyPut(() => AutoCompleteRepositoryImpl(dataSources));
|
||||
Get.lazyPut(() => ContactRepositoryImpl(Get.find<ContactDataSource>()));
|
||||
Get.lazyPut(() => EmailRepositoryImpl(
|
||||
@@ -120,7 +120,6 @@ class ComposerBindings extends BaseBindings {
|
||||
));
|
||||
Get.lazyPut(() => LocalFilePickerInteractor());
|
||||
Get.lazyPut(() => UploadAttachmentInteractor(Get.find<ComposerRepository>()));
|
||||
Get.lazyPut(() => UploadMultipleAttachmentInteractor(Get.find<UploadAttachmentInteractor>()));
|
||||
Get.lazyPut(() => SendEmailInteractor(Get.find<EmailRepository>()));
|
||||
Get.lazyPut(() => SaveEmailAsDraftsInteractor(Get.find<EmailRepository>()));
|
||||
Get.lazyPut(() => GetEmailContentInteractor(Get.find<EmailRepository>()));
|
||||
@@ -130,18 +129,23 @@ class ComposerBindings extends BaseBindings {
|
||||
|
||||
@override
|
||||
void bindingsController() {
|
||||
Get.lazyPut(() => UploadController(Get.find<UploadAttachmentInteractor>()));
|
||||
Get.lazyPut(() => ComposerController(
|
||||
Get.find<SendEmailInteractor>(),
|
||||
Get.find<GetAutoCompleteInteractor>(),
|
||||
Get.find<GetAutoCompleteWithDeviceContactInteractor>(),
|
||||
Get.find<Uuid>(),
|
||||
Get.find<DeviceInfoPlugin>(),
|
||||
Get.find<LocalFilePickerInteractor>(),
|
||||
Get.find<UploadMultipleAttachmentInteractor>(),
|
||||
Get.find<SaveEmailAsDraftsInteractor>(),
|
||||
Get.find<GetEmailContentInteractor>(),
|
||||
Get.find<UpdateEmailDraftsInteractor>(),
|
||||
Get.find<GetAllIdentitiesInteractor>(),
|
||||
Get.find<UploadController>(),
|
||||
));
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
Get.delete<UploadController>();
|
||||
Get.delete<ComposerController>();
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,9 @@ import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/get_autocomplete_state.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_with_device_contact_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/upload_attachment_state.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/save_email_as_drafts_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/update_email_drafts_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/usecases/upload_mutiple_attachment_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
|
||||
@@ -44,8 +42,10 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/model/upload_task_id.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/state/local_file_picker_state.dart';
|
||||
import 'package:tmail_ui_user/features/upload/domain/usecases/local_file_picker_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/controller/upload_controller.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
@@ -56,12 +56,12 @@ class ComposerController extends BaseController {
|
||||
final _appToast = Get.find<AppToast>();
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
final _uuid = Get.find<Uuid>();
|
||||
|
||||
final expandModeAttachments = ExpandMode.COLLAPSE.obs;
|
||||
final composerArguments = Rxn<ComposerArguments>();
|
||||
final isEnableEmailSendButton = false.obs;
|
||||
final isInitialRecipient = false.obs;
|
||||
final attachments = <Attachment>[].obs;
|
||||
final emailContents = Rxn<List<EmailContent>>();
|
||||
final listEmailAddressType = <PrefixEmailAddress>[].obs;
|
||||
final subjectEmail = Rxn<String>();
|
||||
@@ -75,14 +75,13 @@ class ComposerController extends BaseController {
|
||||
final SendEmailInteractor _sendEmailInteractor;
|
||||
final GetAutoCompleteInteractor _getAutoCompleteInteractor;
|
||||
final GetAutoCompleteWithDeviceContactInteractor _getAutoCompleteWithDeviceContactInteractor;
|
||||
final Uuid _uuid;
|
||||
final LocalFilePickerInteractor _localFilePickerInteractor;
|
||||
final UploadMultipleAttachmentInteractor _uploadMultipleAttachmentInteractor;
|
||||
final DeviceInfoPlugin _deviceInfoPlugin;
|
||||
final SaveEmailAsDraftsInteractor _saveEmailAsDraftsInteractor;
|
||||
final GetEmailContentInteractor _getEmailContentInteractor;
|
||||
final UpdateEmailDraftsInteractor _updateEmailDraftsInteractor;
|
||||
final GetAllIdentitiesInteractor _getAllIdentitiesInteractor;
|
||||
final UploadController uploadController;
|
||||
|
||||
List<EmailAddress> listToEmailAddress = <EmailAddress>[];
|
||||
List<EmailAddress> listCcEmailAddress = <EmailAddress>[];
|
||||
@@ -129,14 +128,13 @@ class ComposerController extends BaseController {
|
||||
this._sendEmailInteractor,
|
||||
this._getAutoCompleteInteractor,
|
||||
this._getAutoCompleteWithDeviceContactInteractor,
|
||||
this._uuid,
|
||||
this._deviceInfoPlugin,
|
||||
this._localFilePickerInteractor,
|
||||
this._uploadMultipleAttachmentInteractor,
|
||||
this._saveEmailAsDraftsInteractor,
|
||||
this._getEmailContentInteractor,
|
||||
this._updateEmailDraftsInteractor,
|
||||
this._getAllIdentitiesInteractor,
|
||||
this.uploadController,
|
||||
);
|
||||
|
||||
@override
|
||||
@@ -183,18 +181,11 @@ class ComposerController extends BaseController {
|
||||
(failure) {
|
||||
if (failure is LocalFilePickerFailure || failure is LocalFilePickerCancel) {
|
||||
_pickFileFailure(failure);
|
||||
} else if (failure is UploadAttachmentFailure
|
||||
|| failure is UploadMultipleAttachmentAllFailure) {
|
||||
_uploadAttachmentsFailure(failure);
|
||||
}
|
||||
},
|
||||
(success) {
|
||||
if (success is LocalFilePickerSuccess) {
|
||||
_pickFileSuccess(success);
|
||||
} else if (success is UploadAttachmentSuccess
|
||||
|| success is UploadMultipleAttachmentAllSuccess
|
||||
|| success is UploadMultipleAttachmentHasSomeFailure) {
|
||||
_uploadAttachmentsSuccess(success);
|
||||
} else if (success is GetEmailContentSuccess) {
|
||||
_getEmailContentSuccess(success);
|
||||
} if (success is GetAllIdentitiesSuccess) {
|
||||
@@ -219,7 +210,7 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
popBack();
|
||||
}
|
||||
|
||||
|
||||
void _initEmail() {
|
||||
final arguments = kIsWeb ? mailboxDashBoardController.routerArguments : Get.arguments;
|
||||
if (arguments is ComposerArguments) {
|
||||
@@ -243,8 +234,13 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
|
||||
void _initAttachments(ComposerArguments arguments) {
|
||||
attachments.value = arguments.attachments ?? [];
|
||||
initialAttachments = arguments.attachments ?? [];
|
||||
if (arguments.attachments?.isNotEmpty == true) {
|
||||
initialAttachments = arguments.attachments!;
|
||||
uploadController.initializeUploadAttachments(arguments.attachments!);
|
||||
}
|
||||
if (BuildUtils.isWeb) {
|
||||
expandModeAttachments.value = ExpandMode.EXPAND;
|
||||
}
|
||||
}
|
||||
|
||||
void _getAllIdentities() {
|
||||
@@ -466,7 +462,7 @@ class ComposerController extends BaseController {
|
||||
generatePartId: EmailBodyValue(emailBodyText, false, false)
|
||||
},
|
||||
headerUserAgent: {IndividualHeaderIdentifier.headerUserAgent : userAgent},
|
||||
attachments: attachments.isNotEmpty ? _generateAttachments() : null,
|
||||
attachments: uploadController.generateAttachments(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -485,11 +481,6 @@ class ComposerController extends BaseController {
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
Set<EmailBodyPart> _generateAttachments() {
|
||||
return attachments.map((attachment) =>
|
||||
attachment.toEmailBodyPart(ContentDisposition.attachment.value)).toSet();
|
||||
}
|
||||
|
||||
void sendEmailAction(BuildContext context) async {
|
||||
clearFocusEditor(context);
|
||||
|
||||
@@ -534,7 +525,19 @@ class ComposerController extends BaseController {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_validateAttachmentsSize()) {
|
||||
if (!uploadController.allUploadAttachmentsCompleted) {
|
||||
showConfirmDialogAction(
|
||||
context,
|
||||
AppLocalizations.of(context).messageDialogSendEmailUploadingAttachment,
|
||||
AppLocalizations.of(context).got_it,
|
||||
() => {},
|
||||
title: AppLocalizations.of(context).sending_failed,
|
||||
icon: SvgPicture.asset(_imagePaths.icSendToastError, fit: BoxFit.fill),
|
||||
hasCancelButton: false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uploadController.hasEnoughMaxAttachmentSize()) {
|
||||
showConfirmDialogAction(
|
||||
context,
|
||||
AppLocalizations.of(context).message_dialog_send_email_exceeds_maximum_size(
|
||||
@@ -561,7 +564,7 @@ class ComposerController extends BaseController {
|
||||
final email = await _generateEmail(mapDefaultMailboxId, userProfile);
|
||||
final accountId = session.accounts.keys.first;
|
||||
final sentMailboxId = mapDefaultMailboxId[PresentationMailbox.roleSent];
|
||||
final submissionCreateId = Id(_uuid.v1());
|
||||
final submissionCreateId = Id(const Uuid().v1());
|
||||
|
||||
mailboxDashBoardController.consumeState(_sendEmailInteractor.execute(
|
||||
accountId,
|
||||
@@ -633,88 +636,34 @@ class ComposerController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
void _pickFileSuccess(Success success) {
|
||||
if (success is LocalFilePickerSuccess) {
|
||||
if (_validateAttachmentsSize(listFiles: success.pickedFiles)) {
|
||||
_uploadAttachmentsAction(success.pickedFiles);
|
||||
} else {
|
||||
if (currentContext != null) {
|
||||
showConfirmDialogAction(
|
||||
currentContext!,
|
||||
AppLocalizations.of(currentContext!).message_dialog_upload_attachments_exceeds_maximum_size(
|
||||
filesize(mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0)),
|
||||
AppLocalizations.of(currentContext!).got_it,
|
||||
() => {},
|
||||
title: AppLocalizations.of(currentContext!).maximum_files_size,
|
||||
hasCancelButton: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 totalSizeReadyToUpload = currentTotalAttachmentsSize + uploadedTotalSize;
|
||||
log('ComposerController::_validateAttachmentsSize(): totalSizeReadyToUpload: $totalSizeReadyToUpload');
|
||||
|
||||
final maxSizeAttachmentsPerEmail = mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value;
|
||||
if (maxSizeAttachmentsPerEmail != null) {
|
||||
return totalSizeReadyToUpload <= maxSizeAttachmentsPerEmail;
|
||||
void _pickFileSuccess(LocalFilePickerSuccess success) {
|
||||
if (uploadController.hasEnoughMaxAttachmentSize(listFiles: success.pickedFiles)) {
|
||||
_uploadAttachmentsAction(success.pickedFiles);
|
||||
} else {
|
||||
return false;
|
||||
if (currentContext != null) {
|
||||
showConfirmDialogAction(
|
||||
currentContext!,
|
||||
AppLocalizations.of(currentContext!).message_dialog_upload_attachments_exceeds_maximum_size(
|
||||
filesize(mailboxDashBoardController.maxSizeAttachmentsPerEmail?.value ?? 0, 0)),
|
||||
AppLocalizations.of(currentContext!).got_it,
|
||||
() => {},
|
||||
title: AppLocalizations.of(currentContext!).maximum_files_size,
|
||||
hasCancelButton: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _uploadAttachmentsAction(List<FileInfo> pickedFiles) async {
|
||||
final session = mailboxDashBoardController.sessionCurrent;
|
||||
if (session != null) {
|
||||
final accountId = session.accounts.keys.first;
|
||||
final uploadUrl = session.getUploadUrl(accountId);
|
||||
consumeState(_uploadMultipleAttachmentInteractor.execute(pickedFiles, accountId, uploadUrl));
|
||||
final accountId = mailboxDashBoardController.accountId.value;
|
||||
if (session != null && accountId != null) {
|
||||
final uploadUri = session.getUploadUri(accountId);
|
||||
uploadController.justUploadAttachmentsAction(pickedFiles, uploadUri);
|
||||
}
|
||||
}
|
||||
|
||||
void _uploadAttachmentsFailure(Failure failure) {
|
||||
if (currentContext != null) {
|
||||
_appToast.showErrorToast(AppLocalizations.of(currentContext!).can_not_upload_this_file_as_attachments);
|
||||
}
|
||||
}
|
||||
|
||||
void _uploadAttachmentsSuccess(Success success) {
|
||||
if (success is UploadAttachmentSuccess) {
|
||||
attachments.add(success.attachment);
|
||||
} else if (success is UploadMultipleAttachmentAllSuccess) {
|
||||
final listAttachment = success.listResults.where((either) => either.isRight())
|
||||
.map((either) => either
|
||||
.map((result) => (result as UploadAttachmentSuccess).attachment)
|
||||
.toIterable().first)
|
||||
.toList();
|
||||
|
||||
attachments.addAll(listAttachment);
|
||||
} else if (success is UploadMultipleAttachmentHasSomeFailure) {
|
||||
final listAttachment = success.listResults
|
||||
.map((either) => either
|
||||
.map((result) => (result as UploadAttachmentSuccess).attachment)
|
||||
.toIterable().first)
|
||||
.toList();
|
||||
|
||||
attachments.addAll(listAttachment);
|
||||
}
|
||||
if (currentContext != null) {
|
||||
_appToast.showSuccessToast(AppLocalizations.of(currentContext!).attachments_uploaded_successfully);
|
||||
}
|
||||
}
|
||||
|
||||
void removeAttachmentAction(Attachment attachmentRemoved) {
|
||||
attachments.removeWhere((attachment) => attachment == attachmentRemoved);
|
||||
void deleteAttachmentUploaded(UploadTaskId uploadId) {
|
||||
uploadController.deleteFileUploaded(uploadId);
|
||||
}
|
||||
|
||||
Future<bool> _isEmailChanged(BuildContext context, ComposerArguments arguments) async {
|
||||
@@ -759,7 +708,7 @@ class ComposerController extends BaseController {
|
||||
final oldBccEmailAddress = recipients.value1;
|
||||
final isBccEmailAddressChanged = !oldBccEmailAddress.isSame(newBccEmailAddress);
|
||||
|
||||
final isAttachmentsChanged = !initialAttachments.isSame(attachments.toList());
|
||||
final isAttachmentsChanged = !initialAttachments.isSame(uploadController.attachmentsUploaded.toList());
|
||||
|
||||
if (isEmailBodyChanged || isEmailSubjectChanged
|
||||
|| isToEmailAddressChanged || isCcEmailAddressChanged
|
||||
@@ -816,8 +765,10 @@ class ComposerController extends BaseController {
|
||||
|
||||
void _getEmailContentSuccess(GetEmailContentSuccess success) {
|
||||
emailContents.value = success.emailContents;
|
||||
attachments.value = success.attachments;
|
||||
initialAttachments = success.attachments;
|
||||
if (success.attachments.isNotEmpty) {
|
||||
initialAttachments = success.attachments;
|
||||
uploadController.initializeUploadAttachments(success.attachments);
|
||||
}
|
||||
}
|
||||
|
||||
String? getEmailContentDraftsAsHtml() {
|
||||
|
||||
@@ -14,6 +14,8 @@ import 'package:tmail_ui_user/features/composer/domain/state/upload_attachment_s
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/email_address_input_builder.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/extensions/list_upload_file_state_extension.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class ComposerView extends GetWidget<ComposerController> {
|
||||
@@ -29,10 +31,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
return ResponsiveWidget(
|
||||
responsiveUtils: responsiveUtils,
|
||||
mobile: _buildComposerViewForMobile(context),
|
||||
landscapeMobile: _buildComposerViewForMobile(context),
|
||||
tablet: _buildComposerViewForTablet(context),
|
||||
tabletLarge: _buildComposerViewForTablet(context),
|
||||
desktop: _buildComposerViewForTablet(context),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -398,19 +397,26 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 16), child: _buildListButton(context)),
|
||||
const Divider(color: AppColor.colorDividerComposer, height: 1),
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildAttachmentsTitle(context, controller.attachments, controller.expandModeAttachments.value))
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isEmpty
|
||||
? _buildAttachmentsLoadingView()
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||
child: _buildAttachmentsList(context, controller.attachments, controller.expandModeAttachments.value))
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() {
|
||||
final uploadAttachments = controller.uploadController.listUploadAttachments;
|
||||
if (uploadAttachments.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
} else {
|
||||
return Column(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildAttachmentsTitle(context,
|
||||
uploadAttachments,
|
||||
controller.expandModeAttachments.value)),
|
||||
_buildAttachmentsLoadingView(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||
child: _buildAttachmentsList(context,
|
||||
uploadAttachments,
|
||||
controller.expandModeAttachments.value))
|
||||
]);
|
||||
}
|
||||
}),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20),
|
||||
child: _buildComposerEditor(context)),
|
||||
@@ -453,19 +459,26 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 60, right: 25),
|
||||
child: Column(children: [
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildAttachmentsTitle(context, controller.attachments, controller.expandModeAttachments.value))
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isEmpty
|
||||
? _buildAttachmentsLoadingView()
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||
child: _buildAttachmentsList(context, controller.attachments, controller.expandModeAttachments.value))
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() {
|
||||
final uploadAttachments = controller.uploadController.listUploadAttachments;
|
||||
if (uploadAttachments.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
} else {
|
||||
return Column(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: _buildAttachmentsTitle(context,
|
||||
uploadAttachments,
|
||||
controller.expandModeAttachments.value)),
|
||||
_buildAttachmentsLoadingView(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, left: 16, right: 16),
|
||||
child: _buildAttachmentsList(context,
|
||||
uploadAttachments,
|
||||
controller.expandModeAttachments.value))
|
||||
]);
|
||||
}
|
||||
}),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20, top: 10),
|
||||
child: _buildComposerEditor(context)),
|
||||
@@ -509,11 +522,15 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
: const SizedBox.shrink()));
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsTitle(BuildContext context, List<Attachment> attachments, ExpandMode expandModeAttachment) {
|
||||
Widget _buildAttachmentsTitle(
|
||||
BuildContext context,
|
||||
List<UploadFileState> uploadFilesState,
|
||||
ExpandMode expandModeAttachment
|
||||
) {
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
'${AppLocalizations.of(context).attachments} (${filesize(attachments.totalSize(), 0)}):',
|
||||
'${AppLocalizations.of(context).attachments} (${filesize(uploadFilesState.totalSize, 0)}):',
|
||||
style: const TextStyle(fontSize: 12, color: AppColor.colorHintEmailAddressInput, fontWeight: FontWeight.normal)),
|
||||
_buildAttachmentsLoadingView(padding: const EdgeInsets.only(left: 16), size: 16),
|
||||
const Spacer(),
|
||||
@@ -524,7 +541,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
child: Text(
|
||||
expandModeAttachment == ExpandMode.EXPAND
|
||||
? AppLocalizations.of(context).hide
|
||||
: '${AppLocalizations.of(context).show_all} (${attachments.length})',
|
||||
: '${AppLocalizations.of(context).show_all} (${uploadFilesState.length})',
|
||||
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: AppColor.colorTextButton)),
|
||||
onPressed: () => controller.toggleDisplayAttachments()
|
||||
)
|
||||
@@ -533,23 +550,28 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsList(BuildContext context, List<Attachment> attachments, ExpandMode expandMode) {
|
||||
Widget _buildAttachmentsList(
|
||||
BuildContext context,
|
||||
List<UploadFileState> uploadFilesState,
|
||||
ExpandMode expandMode
|
||||
) {
|
||||
const double maxHeightItem = 60;
|
||||
if (expandMode == ExpandMode.EXPAND) {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return GridView.builder(
|
||||
key: const Key('list_attachment_full'),
|
||||
primary: false,
|
||||
shrinkWrap: true,
|
||||
itemCount: attachments.length,
|
||||
itemCount: uploadFilesState.length,
|
||||
gridDelegate: SliverGridDelegateFixedHeight(
|
||||
height: 60,
|
||||
height: maxHeightItem,
|
||||
crossAxisCount: _getMaxItemRowListAttachment(context, constraints),
|
||||
crossAxisSpacing: 8.0,
|
||||
mainAxisSpacing: 8.0),
|
||||
itemBuilder: (context, index) =>
|
||||
(AttachmentFileComposerBuilder(context, imagePaths, attachments[index])
|
||||
..addOnDeleteAttachmentAction((attachment) => controller.removeAttachmentAction(attachment)))
|
||||
.build()
|
||||
itemBuilder: (context, index) => AttachmentFileComposerBuilder(
|
||||
uploadFilesState[index],
|
||||
onDeleteAttachmentAction: (attachment) =>
|
||||
controller.deleteAttachmentUploaded(attachment.uploadTaskId))
|
||||
);
|
||||
});
|
||||
} else {
|
||||
@@ -557,20 +579,19 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
height: maxHeightItem,
|
||||
child: ListView.builder(
|
||||
key: const Key('list_attachment_minimize'),
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: attachments.length,
|
||||
itemBuilder: (context, index) =>
|
||||
(AttachmentFileComposerBuilder(context, imagePaths, attachments[index],
|
||||
itemMargin: const EdgeInsets.only(right: 8),
|
||||
maxWidth: _getMaxWidthItemListAttachment(context, constraints),
|
||||
maxHeight: 60)
|
||||
..addOnDeleteAttachmentAction((attachment) => controller.removeAttachmentAction(attachment)))
|
||||
.build()
|
||||
itemCount: uploadFilesState.length,
|
||||
itemBuilder: (context, index) => AttachmentFileComposerBuilder(
|
||||
uploadFilesState[index],
|
||||
itemMargin: const EdgeInsets.only(right: 8),
|
||||
maxWidth: _getMaxWidthItemListAttachment(context, constraints),
|
||||
onDeleteAttachmentAction: (attachment) =>
|
||||
controller.deleteAttachmentUploaded(attachment.uploadTaskId))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -15,6 +15,8 @@ import 'package:tmail_ui_user/features/composer/presentation/composer_controller
|
||||
import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/attachment_file_composer_builder.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/email_address_input_builder.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/extensions/list_upload_file_state_extension.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class ComposerView extends GetWidget<ComposerController> {
|
||||
@@ -488,54 +490,65 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
}
|
||||
|
||||
Widget _buildEditorAndAttachments(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
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))
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isEmpty
|
||||
? _buildAttachmentsLoadingView()
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() => controller.attachments.isNotEmpty
|
||||
? Padding(
|
||||
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))
|
||||
: const SizedBox.shrink()),
|
||||
Obx(() {
|
||||
if (controller.composerArguments.value != null) {
|
||||
if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) {
|
||||
final initContent = controller.textEditorWeb ?? ''.addEditorDefaultSpace();
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
} else if (controller.composerArguments.value?.emailActionType == EmailActionType.edit) {
|
||||
final initContent = controller.textEditorWeb ?? controller.getEmailContentDraftsAsHtml();
|
||||
if (initContent != null) {
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
} else {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: CupertinoActivityIndicator(color: AppColor.colorLoading)));
|
||||
}
|
||||
} else {
|
||||
final initContent = controller.textEditorWeb ?? controller.getEmailContentQuotedAsHtml(context, controller.composerArguments.value!);
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
}
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}),
|
||||
]
|
||||
);
|
||||
return Obx(() {
|
||||
final uploadAttachments = controller.uploadController.listUploadAttachments;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
if (uploadAttachments.isNotEmpty)
|
||||
...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 4,
|
||||
bottom: 4,
|
||||
left: responsiveUtils.isMobile(context) ? 16 : 20,
|
||||
right: responsiveUtils.isMobile(context) ? 16: 0),
|
||||
child: _buildAttachmentsTitle(context,
|
||||
uploadAttachments,
|
||||
controller.expandModeAttachments.value)),
|
||||
_buildAttachmentsLoadingView(),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 8,
|
||||
left: responsiveUtils.isMobile(context) ? 16 : 10,
|
||||
right: responsiveUtils.isMobile(context) ? 16 : 10),
|
||||
child: _buildAttachmentsList(context,
|
||||
uploadAttachments,
|
||||
controller.expandModeAttachments.value))
|
||||
],
|
||||
if (controller.composerArguments.value != null)
|
||||
_buildComposeEditor(context)
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildComposeEditor(BuildContext context) {
|
||||
if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) {
|
||||
final initContent = controller.textEditorWeb ?? ''.addEditorDefaultSpace();
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
} else if (controller.composerArguments.value?.emailActionType == EmailActionType.edit) {
|
||||
final initContent = controller.textEditorWeb ?? controller.getEmailContentDraftsAsHtml();
|
||||
if (initContent != null) {
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
} else {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: CupertinoActivityIndicator(color: AppColor.colorLoading)));
|
||||
}
|
||||
} else {
|
||||
final initContent = controller.textEditorWeb ?? controller.getEmailContentQuotedAsHtml(context, controller.composerArguments.value!);
|
||||
return Expanded(child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: responsiveUtils.isMobile(context) ? 8 : 10),
|
||||
child: _buildEditor(context, initContent)));
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildEditor(BuildContext context, String initContent) {
|
||||
@@ -590,11 +603,14 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
: const SizedBox.shrink()));
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsTitle(BuildContext context, List<Attachment> attachments, ExpandMode expandModeAttachment) {
|
||||
Widget _buildAttachmentsTitle(
|
||||
BuildContext context,
|
||||
List<UploadFileState> uploadFilesState,
|
||||
ExpandMode expandModeAttachment) {
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
'${AppLocalizations.of(context).attachments} (${filesize(attachments.totalSize(), 0)}):',
|
||||
'${AppLocalizations.of(context).attachments} (${filesize(uploadFilesState.totalSize, 0)}):',
|
||||
style: const TextStyle(fontSize: 12, color: AppColor.colorHintEmailAddressInput, fontWeight: FontWeight.normal)),
|
||||
_buildAttachmentsLoadingView(padding: const EdgeInsets.only(left: 16), size: 16),
|
||||
const Spacer(),
|
||||
@@ -605,7 +621,7 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
child: Text(
|
||||
expandModeAttachment == ExpandMode.EXPAND
|
||||
? AppLocalizations.of(context).hide
|
||||
: '${AppLocalizations.of(context).show_all} (${attachments.length})',
|
||||
: '${AppLocalizations.of(context).show_all} (${uploadFilesState.length})',
|
||||
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: AppColor.colorTextButton)),
|
||||
onPressed: () => controller.toggleDisplayAttachments()
|
||||
)
|
||||
@@ -614,7 +630,10 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAttachmentsList(BuildContext context, List<Attachment> attachments, ExpandMode expandMode) {
|
||||
Widget _buildAttachmentsList(
|
||||
BuildContext context,
|
||||
List<UploadFileState> uploadFilesState,
|
||||
ExpandMode expandMode) {
|
||||
if (expandMode == ExpandMode.COLLAPSE) {
|
||||
return const SizedBox.shrink();
|
||||
} else {
|
||||
@@ -628,14 +647,13 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: attachments.length,
|
||||
itemBuilder: (context, index) =>
|
||||
(AttachmentFileComposerBuilder(context, imagePaths, attachments[index],
|
||||
itemMargin: const EdgeInsets.only(right: 8),
|
||||
maxWidth: _getMaxWidthItemListAttachment(context, constraints),
|
||||
maxHeight: 60)
|
||||
..addOnDeleteAttachmentAction((attachment) => controller.removeAttachmentAction(attachment)))
|
||||
.build()
|
||||
itemCount: uploadFilesState.length,
|
||||
itemBuilder: (context, index) => AttachmentFileComposerBuilder(
|
||||
uploadFilesState[index],
|
||||
itemMargin: const EdgeInsets.only(right: 8),
|
||||
maxWidth: _getMaxWidthItemListAttachment(context, constraints),
|
||||
onDeleteAttachmentAction: (attachment) =>
|
||||
controller.deleteAttachmentUploaded(attachment.uploadTaskId))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,88 +1,131 @@
|
||||
|
||||
import 'package:core/core.dart';
|
||||
import 'package:filesize/filesize.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart';
|
||||
import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_status.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
typedef OnDeleteAttachmentAction = void Function(Attachment attachment);
|
||||
typedef OnDeleteAttachmentAction = void Function(UploadFileState fileState);
|
||||
|
||||
class AttachmentFileComposerBuilder {
|
||||
class AttachmentFileComposerBuilder extends StatelessWidget with AppLoaderMixin {
|
||||
|
||||
final BuildContext context;
|
||||
final ImagePaths imagePaths;
|
||||
final Attachment attachment;
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
final UploadFileState fileState;
|
||||
final double? maxWidth;
|
||||
final double? maxHeight;
|
||||
final EdgeInsets? itemMargin;
|
||||
final OnDeleteAttachmentAction? onDeleteAttachmentAction;
|
||||
final Widget? buttonAction;
|
||||
|
||||
OnDeleteAttachmentAction? _onDeleteAttachmentAction;
|
||||
AttachmentFileComposerBuilder(this.fileState, {
|
||||
super.key,
|
||||
this.maxWidth,
|
||||
this.itemMargin,
|
||||
this.buttonAction,
|
||||
this.onDeleteAttachmentAction,
|
||||
});
|
||||
|
||||
Widget? buttonAction;
|
||||
|
||||
AttachmentFileComposerBuilder(
|
||||
this.context,
|
||||
this.imagePaths,
|
||||
this.attachment,
|
||||
{
|
||||
this.maxWidth,
|
||||
this.maxHeight,
|
||||
this.itemMargin,
|
||||
}
|
||||
);
|
||||
|
||||
void addOnDeleteAttachmentAction(OnDeleteAttachmentAction onDeleteAttachmentAction) {
|
||||
_onDeleteAttachmentAction = onDeleteAttachmentAction;
|
||||
}
|
||||
|
||||
Widget build() {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Theme(
|
||||
data: ThemeData(
|
||||
splashColor: Colors.transparent ,
|
||||
highlightColor: Colors.transparent),
|
||||
child: Container(
|
||||
margin: itemMargin ?? EdgeInsets.zero,
|
||||
padding: EdgeInsets.zero,
|
||||
alignment: Alignment.center,
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: AppColor.colorInputBorderCreateMailbox),
|
||||
color: Colors.white),
|
||||
child: Stack(children: [
|
||||
ListTile(
|
||||
contentPadding: const EdgeInsets.only(right: kIsWeb ? 16 : 18),
|
||||
data: ThemeData(
|
||||
splashColor: Colors.transparent ,
|
||||
highlightColor: Colors.transparent),
|
||||
child: Container(
|
||||
margin: itemMargin ?? EdgeInsets.zero,
|
||||
padding: EdgeInsets.zero,
|
||||
alignment: Alignment.center,
|
||||
width: maxWidth,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: AppColor.colorInputBorderCreateMailbox),
|
||||
color: Colors.white),
|
||||
child: Stack(children: [
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
focusColor: AppColor.primaryColor,
|
||||
hoverColor: AppColor.primaryColor,
|
||||
onTap: () {},
|
||||
leading: Transform(
|
||||
transform: Matrix4.translationValues(8.0, kIsWeb ? -3.0 : -5.0, 0.0),
|
||||
child: SvgPicture.asset(imagePaths.icFileAttachment, fit: BoxFit.fill)),
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 8,
|
||||
bottom: BuildUtils.isWeb ? 6 : 14),
|
||||
child: SvgPicture.asset(
|
||||
fileState.getIcon(_imagePaths),
|
||||
width: 40,
|
||||
height: 40,
|
||||
fit: BoxFit.fill),
|
||||
),
|
||||
title: Transform(
|
||||
transform: Matrix4.translationValues(kIsWeb ? -4.0 : -10.0, kIsWeb ? -6.0 : -9.0, 0.0),
|
||||
child: Text(
|
||||
attachment.name ?? '',
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 12, color: AppColor.colorNameEmail, fontWeight: FontWeight.w500),
|
||||
)),
|
||||
subtitle: attachment.size != null && attachment.size?.value != 0
|
||||
transform: Matrix4.translationValues(
|
||||
BuildUtils.isWeb ? 0.0 : -8.0,
|
||||
BuildUtils.isWeb ? -8.0 : -10.0,
|
||||
0.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: BuildUtils.isWeb ? 20 : 16),
|
||||
child: Text(
|
||||
fileState.fileName,
|
||||
maxLines: 1,
|
||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500),
|
||||
),
|
||||
)
|
||||
),
|
||||
subtitle: fileState.fileSize != 0
|
||||
? Transform(
|
||||
transform: Matrix4.translationValues(kIsWeb ? -4.0 : -10.0, kIsWeb ? -5.0 : -8.0, 0.0),
|
||||
transform: Matrix4.translationValues(
|
||||
BuildUtils.isWeb ? 0.0 : -8.0,
|
||||
BuildUtils.isWeb ? -8.0 : -10.0,
|
||||
0.0),
|
||||
child: Text(
|
||||
filesize(attachment.size?.value, 0),
|
||||
filesize(fileState.fileSize),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 10, color: AppColor.colorContentEmail, fontWeight: FontWeight.normal)))
|
||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColor.colorContentEmail)))
|
||||
: null,
|
||||
),
|
||||
Positioned(right: kIsWeb ? -5 : -12, top: kIsWeb ? -5 : -12, child: buildIconWeb(
|
||||
icon: SvgPicture.asset(imagePaths.icDeleteAttachment, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).delete,
|
||||
onTap: () => _onDeleteAttachmentAction?.call(attachment)))
|
||||
]),
|
||||
)
|
||||
),
|
||||
Positioned(
|
||||
right: BuildUtils.isWeb ? -5 : -12,
|
||||
top: BuildUtils.isWeb ? -5 : -12,
|
||||
child: buildIconWeb(
|
||||
icon: SvgPicture.asset(_imagePaths.icDeleteAttachment, fit: BoxFit.fill),
|
||||
tooltip: AppLocalizations.of(context).delete,
|
||||
onTap: () {
|
||||
if (onDeleteAttachmentAction != null) {
|
||||
onDeleteAttachmentAction!.call(fileState);
|
||||
}
|
||||
}
|
||||
)
|
||||
),
|
||||
Align(alignment: Alignment.bottomCenter, child: _progressLoading),
|
||||
]),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _progressLoading {
|
||||
switch(fileState.uploadStatus) {
|
||||
case UploadFileStatus.waiting:
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 50),
|
||||
child: horizontalLoadingWidget);
|
||||
case UploadFileStatus.uploading:
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 50),
|
||||
child: horizontalPercentLoadingWidget(fileState.percentUploading));
|
||||
case UploadFileStatus.uploadFailed:
|
||||
case UploadFileStatus.succeed:
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -406,9 +406,11 @@ class EmailView extends GetWidget<EmailController> with NetworkConnectionMixin {
|
||||
}
|
||||
|
||||
int _getAttachmentLimitDisplayed(BuildContext context) {
|
||||
if (responsiveUtils.isScreenWithShortestSide(context)) {
|
||||
if (responsiveUtils.isMobile(context)
|
||||
|| responsiveUtils.isLandscapeMobile(context)) {
|
||||
return 2;
|
||||
} else if (responsiveUtils.isTablet(context)) {
|
||||
} else if (responsiveUtils.isTablet(context) ||
|
||||
responsiveUtils.isLandscapeTablet(context)) {
|
||||
return 3;
|
||||
} else {
|
||||
return 4;
|
||||
|
||||
@@ -82,8 +82,8 @@ class AttachmentFileTileBuilder {
|
||||
padding: const EdgeInsets.only(left: 8, bottom: BuildUtils.isWeb ? 6 : 14),
|
||||
child: SvgPicture.asset(
|
||||
_attachment.getIcon(_imagePaths),
|
||||
width: 44,
|
||||
height: 44,
|
||||
width: 40,
|
||||
height: 40,
|
||||
fit: BoxFit.fill),
|
||||
),
|
||||
title: Transform(
|
||||
|
||||
@@ -31,7 +31,6 @@ import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_na
|
||||
import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart';
|
||||
import 'package:tmail_ui_user/features/thread/data/datasource_impl/thread_datasource_impl.dart';
|
||||
import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class MailboxBindings extends BaseBindings {
|
||||
|
||||
@@ -43,7 +42,6 @@ class MailboxBindings extends BaseBindings {
|
||||
|
||||
void _bindingsUtils() {
|
||||
Get.lazyPut(() => TreeBuilder());
|
||||
Get.lazyPut(() => const Uuid());
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -57,7 +55,6 @@ class MailboxBindings extends BaseBindings {
|
||||
Get.find<VerifyNameInteractor>(),
|
||||
Get.find<RenameMailboxInteractor>(),
|
||||
Get.find<MoveMailboxInteractor>(),
|
||||
Get.find<Uuid>(),
|
||||
Get.find<TreeBuilder>(),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ class MailboxController extends BaseMailboxController {
|
||||
final _appToast = Get.find<AppToast>();
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
final _uuid = Get.find<Uuid>();
|
||||
|
||||
final GetAllMailboxInteractor _getAllMailboxInteractor;
|
||||
final RefreshAllMailboxInteractor _refreshAllMailboxInteractor;
|
||||
@@ -83,7 +84,6 @@ class MailboxController extends BaseMailboxController {
|
||||
final VerifyNameInteractor _verifyNameInteractor;
|
||||
final RenameMailboxInteractor _renameMailboxInteractor;
|
||||
final MoveMailboxInteractor _moveMailboxInteractor;
|
||||
final Uuid _uuid;
|
||||
|
||||
final listMailboxSearched = <PresentationMailbox>[].obs;
|
||||
final searchState = SearchState.initial().obs;
|
||||
@@ -110,7 +110,6 @@ class MailboxController extends BaseMailboxController {
|
||||
this._verifyNameInteractor,
|
||||
this._renameMailboxInteractor,
|
||||
this._moveMailboxInteractor,
|
||||
this._uuid,
|
||||
treeBuilder,
|
||||
) : super(treeBuilder);
|
||||
|
||||
|
||||
+1
-2
@@ -21,7 +21,6 @@ import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_draft
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart';
|
||||
@@ -384,7 +383,7 @@ class MailboxDashBoardController extends ReloadableController {
|
||||
|
||||
void closeComposerOverlay() {
|
||||
routerArguments = null;
|
||||
Get.delete<ComposerController>();
|
||||
ComposerBindings().dispose();
|
||||
composerOverlayState.value = ComposerOverlayState.inActive;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,23 +6,15 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/delete_ide
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/edit_identity_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class IdentitiesBindings extends BaseBindings {
|
||||
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => const Uuid());
|
||||
super.dependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
void bindingsController() {
|
||||
Get.lazyPut(() => IdentitiesController(
|
||||
Get.find<GetAllIdentitiesInteractor>(),
|
||||
Get.find<DeleteIdentityInteractor>(),
|
||||
Get.find<CreateNewIdentityInteractor>(),
|
||||
Get.find<Uuid>(),
|
||||
Get.find<EditIdentityInteractor>(),
|
||||
));
|
||||
}
|
||||
|
||||
+1
-2
@@ -32,10 +32,10 @@ class IdentitiesController extends BaseController {
|
||||
final _appToast = Get.find<AppToast>();
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
final _responsiveUtils = Get.find<ResponsiveUtils>();
|
||||
final _uuid = Get.find<Uuid>();
|
||||
|
||||
final GetAllIdentitiesInteractor _getAllIdentitiesInteractor;
|
||||
final CreateNewIdentityInteractor _createNewIdentityInteractor;
|
||||
final Uuid _uuid;
|
||||
final DeleteIdentityInteractor _deleteIdentityInteractor;
|
||||
final EditIdentityInteractor _editIdentityInteractor;
|
||||
|
||||
@@ -51,7 +51,6 @@ class IdentitiesController extends BaseController {
|
||||
this._getAllIdentitiesInteractor,
|
||||
this._deleteIdentityInteractor,
|
||||
this._createNewIdentityInteractor,
|
||||
this._uuid,
|
||||
this._editIdentityInteractor,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2022-07-08T15:25:15.196374",
|
||||
"@@last_modified": "2022-07-05T19:24:56.876056",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -1561,5 +1561,11 @@
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"messageDialogSendEmailUploadingAttachment": "Your message could not be sent because it uploading attachment",
|
||||
"@messageDialogSendEmailUploadingAttachment": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import 'package:get/get.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
|
||||
import 'package:tmail_ui_user/main/utils/email_receive_manager.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class CoreBindings extends Bindings {
|
||||
|
||||
@@ -18,6 +19,7 @@ class CoreBindings extends Bindings {
|
||||
_bindingToast();
|
||||
_bindingDeviceManager();
|
||||
_bindingReceivingSharingStream();
|
||||
_bindingUtils();
|
||||
}
|
||||
|
||||
void _bindingAppImagePaths() {
|
||||
@@ -53,4 +55,8 @@ class CoreBindings extends Bindings {
|
||||
void _bindingReceivingSharingStream() {
|
||||
Get.put(EmailReceiveManager());
|
||||
}
|
||||
|
||||
void _bindingUtils() {
|
||||
Get.put(const Uuid());
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_appauth/flutter_appauth.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:jmap_dart_client/http/http_client.dart' as JmapHttpClient;
|
||||
import 'package:tmail_ui_user/features/composer/data/network/composer_api.dart';
|
||||
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/local/account_cache_manager.dart';
|
||||
import 'package:tmail_ui_user/features/login/data/local/token_oidc_cache_manager.dart';
|
||||
@@ -77,7 +76,6 @@ class NetworkBindings extends Bindings {
|
||||
Get.put(EmailAPI(
|
||||
Get.find<JmapHttpClient.HttpClient>(),
|
||||
Get.find<DownloadManager>()));
|
||||
Get.put(ComposerAPI(Get.find<DioClient>()));
|
||||
Get.put(ManageAccountAPI(Get.find<JmapHttpClient.HttpClient>()));
|
||||
}
|
||||
|
||||
|
||||
@@ -1601,4 +1601,11 @@ class AppLocalizations {
|
||||
'Russian',
|
||||
name: 'languageRussian');
|
||||
}
|
||||
|
||||
String get messageDialogSendEmailUploadingAttachment {
|
||||
return Intl.message(
|
||||
'Your message could not be sent because it uploading attachment',
|
||||
name: 'messageDialogSendEmailUploadingAttachment'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,13 @@ extension SessionExtension on Session {
|
||||
return downloadUrlDecode;
|
||||
}
|
||||
|
||||
Uri getUploadUrl(AccountId accountId) {
|
||||
Uri getUploadUri(AccountId accountId) {
|
||||
final baseUrl = '${uploadUrl.origin}${uploadUrl.path}';
|
||||
final uploadUriTemplate = UriTemplate('${Uri.decodeFull(baseUrl)}');
|
||||
final uploadUri = uploadUriTemplate.expand({
|
||||
'accountId' : '${accountId.id.value}'
|
||||
});
|
||||
log('SessionExtension::getUploadUri(): uploadUri: $uploadUri');
|
||||
return Uri.parse(uploadUri);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ class UploadResponse with EquatableMixin {
|
||||
}
|
||||
|
||||
extension UploadResponseExtension on UploadResponse {
|
||||
Attachment toAttachmentFile(String nameFile, {MediaType? mediaType}) {
|
||||
return Attachment(blobId: blobId, size: UnsignedInt(size), name: nameFile, type: mediaType ?? type);
|
||||
Attachment toAttachment(String nameFile) {
|
||||
return Attachment(blobId: blobId, size: UnsignedInt(size), name: nameFile, type: type);
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,8 @@ dependencies:
|
||||
# Isolate
|
||||
worker_manager: 4.4.0
|
||||
|
||||
async: 2.8.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
Reference in New Issue
Block a user