TF-675 Implement upload attachment on presentation layer

This commit is contained in:
dab246
2022-07-05 19:33:14 +07:00
committed by Dat H. Pham
parent 91bc3018ea
commit 737555eb14
19 changed files with 358 additions and 313 deletions
@@ -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);
@@ -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>(),
));
}
@@ -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,
);
+7 -1
View File
@@ -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'
);
}
}
+2 -1
View File
@@ -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);
}
}
+2 -2
View File
@@ -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);
}
}
+2
View File
@@ -172,6 +172,8 @@ dependencies:
# Isolate
worker_manager: 4.4.0
async: 2.8.2
dev_dependencies:
flutter_test:
sdk: flutter