diff --git a/lib/features/composer/domain/model/email_request.dart b/lib/features/composer/domain/model/email_request.dart new file mode 100644 index 000000000..dece59e3d --- /dev/null +++ b/lib/features/composer/domain/model/email_request.dart @@ -0,0 +1,17 @@ + +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; + +class EmailRequest with EquatableMixin { + + final Email email; + final Id submissionCreateId; + final MailboxId? mailboxIdSaved; + + EmailRequest(this.email, this.submissionCreateId, {this.mailboxIdSaved}); + + @override + List get props => [email, submissionCreateId, mailboxIdSaved]; +} \ No newline at end of file diff --git a/lib/features/composer/domain/state/send_email_state.dart b/lib/features/composer/domain/state/send_email_state.dart new file mode 100644 index 000000000..d1b19abed --- /dev/null +++ b/lib/features/composer/domain/state/send_email_state.dart @@ -0,0 +1,18 @@ +import 'package:core/core.dart'; + +class SendEmailSuccess extends UIState { + + SendEmailSuccess(); + + @override + List get props => []; +} + +class SendEmailFailure extends FeatureFailure { + final exception; + + SendEmailFailure(this.exception); + + @override + List get props => [exception]; +} \ No newline at end of file diff --git a/lib/features/composer/domain/usecases/send_email_interactor.dart b/lib/features/composer/domain/usecases/send_email_interactor.dart new file mode 100644 index 000000000..3123d24f8 --- /dev/null +++ b/lib/features/composer/domain/usecases/send_email_interactor.dart @@ -0,0 +1,26 @@ +import 'package:core/core.dart'; +import 'package:dartz/dartz.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart'; +import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; + +class SendEmailInteractor { + final EmailRepository emailRepository; + + SendEmailInteractor(this.emailRepository); + + Stream> execute(AccountId accountId, EmailRequest emailRequest) async* { + try { + yield Right(UIState.loading); + final result = await emailRepository.sendEmail(accountId, emailRequest); + if (result) { + yield Right(SendEmailSuccess()); + } else { + yield Left(SendEmailFailure(result)); + } + } catch (e) { + yield Left(SendEmailFailure(e)); + } + } +} \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_bindings.dart b/lib/features/composer/presentation/composer_bindings.dart index fa4a9ca60..6484c797b 100644 --- a/lib/features/composer/presentation/composer_bindings.dart +++ b/lib/features/composer/presentation/composer_bindings.dart @@ -1,9 +1,56 @@ +import 'package:core/core.dart'; +import 'package:core/presentation/utils/app_toast.dart'; import 'package:get/get.dart'; +import 'package:html_editor_enhanced/html_editor.dart'; +import 'package:tmail_ui_user/features/composer/data/datasource/autocomplete_datasource.dart'; +import 'package:tmail_ui_user/features/composer/data/datasource/composer_datasource.dart'; +import 'package:tmail_ui_user/features/composer/data/datasource_impl/autocomplete_datasource_impl.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/local_autocomplete_datasource_impl.dart'; +import 'package:tmail_ui_user/features/composer/data/datasource_impl/local_composer_datasource_impl.dart'; +import 'package:tmail_ui_user/features/composer/data/local/email_address_database_manager.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/domain/repository/auto_complete_repository.dart'; +import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/save_email_addresses_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/search_email_address_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; +import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; +import 'package:uuid/uuid.dart'; class ComposerBindings extends Bindings { @override void dependencies() { - Get.lazyPut(() => ComposerController()); + Get.lazyPut(() => EmailAddressDatabaseManager(Get.find())); + Get.lazyPut(() => ComposerDataSourceImpl()); + Get.lazyPut(() => LocalComposerDataSourceImpl(Get.find())); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => ComposerRepositoryImpl({ + DataSourceType.network: Get.find(), + DataSourceType.local: Get.find(), + })); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => SendEmailInteractor(Get.find())); + Get.lazyPut(() => SaveEmailAddressesInteractor(Get.find())); + Get.lazyPut(() => AutoCompleteDataSourceImpl()); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => LocalAutoCompleteDataSourceImpl(Get.find())); + Get.lazyPut(() => AutoCompleteRepositoryImpl({ + DataSourceType.network: Get.find(), + DataSourceType.local: Get.find(), + })); + Get.lazyPut(() => Get.find()); + Get.lazyPut(() => SearchEmailAddressInteractor(Get.find())); + Get.lazyPut(() => Uuid()); + Get.lazyPut(() => HtmlEditorController()); + Get.lazyPut(() => ComposerController( + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find(), + Get.find())); } } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 4c2ba7aa7..4232d15fd 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -1,46 +1,93 @@ +import 'dart:async'; + import 'package:core/core.dart'; +import 'package:core/presentation/utils/app_toast.dart'; import 'package:dartz/dartz.dart'; import 'package:flutter/cupertino.dart'; import 'package:get/get.dart'; import 'package:html_editor_enhanced/html_editor.dart'; +import 'package:http_parser/http_parser.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_body_value.dart'; import 'package:model/model.dart'; +import 'package:tmail_ui_user/features/base/base_controller.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/auto_complete_pattern.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; +import 'package:tmail_ui_user/features/composer/domain/state/search_email_address_state.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/save_email_addresses_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/search_email_address_interactor.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart'; +import 'package:tmail_ui_user/features/email/presentation/constants/email_constants.dart'; import 'package:tmail_ui_user/features/email/presentation/model/attachment_file.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/email_content_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/model/message_content.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:uuid/uuid.dart'; -class ComposerController extends GetxController { +class ComposerController extends BaseController { final expandMode = ExpandMode.COLLAPSE.obs; final composerArguments = Rxn(); final isEnableEmailSendButton = false.obs; final listReplyToEmailAddress = [].obs; - final htmlEditorController = HtmlEditorController(); - final listEmailAddressSuggestion = [ - EmailAddress('Mike Jones', 'user1@linagora.com'), - EmailAddress('Mike Smith', 'user2@linagora.com'), - EmailAddress('Jane Smith', 'user3@linagora.com'), - EmailAddress('User4', 'user4@linagora.com'), - EmailAddress('User5', 'user5@linagora.com') - ]; + final SendEmailInteractor _sendEmailInteractor; + final SaveEmailAddressesInteractor _saveEmailAddressInteractor; + final SearchEmailAddressInteractor _searchEmailAddressInteractor; + final AppToast _appToast; + final Uuid _uuid; + final HtmlEditorController htmlEditorController; + List listToEmailAddress = []; List listCcEmailAddress = []; List listBccEmailAddress = []; + String? _subjectEmail; - ComposerController(); + void setSubjectEmail(String subject) => _subjectEmail = subject; + + ComposerController( + this._sendEmailInteractor, + this._saveEmailAddressInteractor, + this._searchEmailAddressInteractor, + this._appToast, + this._uuid, + this.htmlEditorController, + ); @override - void onReady() { + void onReady() async { super.onReady(); _getSelectedEmail(); + await searchEmailAddressSuggestion(''); } + @override + void onDone() { + viewState.value.fold( + (failure) { + _appToast.showErrorToast(AppLocalizations.of(Get.context!).error_message_sent); + Get.back(); + }, + (success) { + _saveEmailAddress(); + _appToast.showSuccessToast(AppLocalizations.of(Get.context!).message_sent); + Get.back(); + }); + } + + @override + void onError(error) { + _appToast.showErrorToast(AppLocalizations.of(Get.context!).error_message_sent); + Get.back(); + } + void _getSelectedEmail() { final arguments = Get.arguments; if (arguments is ComposerArguments) { @@ -166,6 +213,67 @@ class ComposerController extends GetxController { return emailQuotedHtml; } + Future generateEmail() async { + final generateEmailId = EmailId(Id(_uuid.v1())); + final outboxMailboxId = composerArguments.value!.mapMailboxId[PresentationMailbox.roleOutbox]; + final listFromEmailAddress = { + EmailAddress( + composerArguments.value!.userProfile.getNameDisplay(), + composerArguments.value!.userProfile.getEmailAddress()) + }; + final generatePartId = PartId(_uuid.v1()); + final generateBlobId = Id(_uuid.v1()); + + final emailBodyText = await htmlEditorController.getText(); + + return Email( + generateEmailId, + mailboxIds: {outboxMailboxId!: true}, + from: listFromEmailAddress, + to: listToEmailAddress.toSet(), + cc: listCcEmailAddress.toSet(), + bcc: listBccEmailAddress.toSet(), + subject: _subjectEmail, + htmlBody: { + EmailBodyPart( + partId: generatePartId, + blobId: generateBlobId, + type: MediaType.parse(EmailConstants.HTML_TEXT) + )}, + bodyValues: { + generatePartId: EmailBodyValue(emailBodyText, false, false) + } + ); + } + + void sendEmailAction(BuildContext context) async { + if (isEnableEmailSendButton.value) { + _appToast.showToast(AppLocalizations.of(context).your_email_being_sent); + + final email = await generateEmail(); + final accountId = composerArguments.value!.session.accounts.keys.first; + final sentMailboxId = composerArguments.value!.mapMailboxId[PresentationMailbox.roleSent]; + final submissionCreateId = Id(_uuid.v1()); + + consumeState(_sendEmailInteractor.execute(accountId, EmailRequest(email, submissionCreateId, mailboxIdSaved: sentMailboxId))); + } else { + _appToast.showErrorToast(AppLocalizations.of(context).your_email_should_have_at_least_one_recipient); + } + } + + void _saveEmailAddress() { + final listEmailAddressCanSave = Set(); + listEmailAddressCanSave.addAll(listToEmailAddress + listCcEmailAddress + listBccEmailAddress); + _saveEmailAddressInteractor.execute(listEmailAddressCanSave.toList()); + } + + Future> searchEmailAddressSuggestion(String word) async { + return await _searchEmailAddressInteractor.execute(AutoCompletePattern(word: word)) + .then((value) => value.fold( + (failure) => [], + (success) => success is SearchEmailAddressSuccess ? success.listEmailAddress : [])); + } + void backToEmailViewAction() { Get.back(); } diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart index eb2980aca..96e1f7ba4 100644 --- a/lib/features/composer/presentation/composer_view.dart +++ b/lib/features/composer/presentation/composer_view.dart @@ -51,6 +51,7 @@ class ComposerView extends GetWidget { return Padding( padding: EdgeInsets.only(left: 20, right: 24, top: 12, bottom: 12), child: Obx(() => (TopBarComposerWidgetBuilder(imagePaths, controller.isEnableEmailSendButton.value) + ..addSendEmailActionClick(() => controller.sendEmailAction(context)) ..addBackActionClick(() => controller.backToEmailViewAction())) .build()), ); @@ -66,20 +67,7 @@ class ComposerView extends GetWidget { children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 24), - child: Obx(() { - return (EmailAddressComposerWidgetBuilder( - context, - imagePaths, - controller.expandMode.value, - controller.listEmailAddressSuggestion, - controller.listReplyToEmailAddress.isNotEmpty ? controller.listReplyToEmailAddress : controller.listToEmailAddress, - controller.listCcEmailAddress, - controller.listBccEmailAddress, - controller.composerArguments.value?.userProfile) - ..addExpandAddressActionClick(() => controller.expandEmailAddressAction()) - ..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress))) - .build(); - })), + child: _buildEmailAddress(context)), _buildSubjectEmail(context), Container( margin: EdgeInsets.zero, @@ -91,6 +79,22 @@ class ComposerView extends GetWidget { ), ); } + + Widget _buildEmailAddress(BuildContext context) { + return Obx(() => (EmailAddressComposerWidgetBuilder( + context, + imagePaths, + controller.expandMode.value, + controller.listReplyToEmailAddress.isNotEmpty ? controller.listReplyToEmailAddress : controller.listToEmailAddress, + controller.listCcEmailAddress, + controller.listBccEmailAddress, + controller.composerArguments.value?.userProfile) + ..addExpandAddressActionClick(() => controller.expandEmailAddressAction()) + ..addOnUpdateListEmailAddressAction((prefixEmailAddress, listEmailAddress) => controller.updateListEmailAddress(prefixEmailAddress, listEmailAddress)) + ..addOnSuggestionEmailAddress((word) => controller.searchEmailAddressSuggestion(word))) + .build() + ); + } Widget _buildSubjectEmail(BuildContext context) { return Padding( @@ -99,6 +103,7 @@ class ComposerView extends GetWidget { .key(Key('subject_email_input')) .textInputAction(TextInputAction.newline) .maxLines(null) + .onChange((value) => controller.setSubjectEmail(value)) .textStyle(TextStyle(color: AppColor.nameUserColor, fontSize: 14, fontWeight: FontWeight.w500)) .textDecoration(InputDecoration( hintText: AppLocalizations.of(context).subject_email, @@ -118,7 +123,9 @@ class ComposerView extends GetWidget { child: Container( margin: EdgeInsets.zero, color: AppColor.bgComposer, - padding: EdgeInsets.only(bottom: 30), + padding: controller.getEmailActionType() != EmailActionType.compose + ? EdgeInsets.only(bottom: 30, left: 16, right: 16) + : EdgeInsets.only(bottom: 30), alignment: Alignment.topCenter, child: _buildEmailBodyEditorQuoted(context) ) diff --git a/lib/features/composer/presentation/widgets/email_address_composer_widget_builder.dart b/lib/features/composer/presentation/widgets/email_address_composer_widget_builder.dart index ffa0d2233..75934fec5 100644 --- a/lib/features/composer/presentation/widgets/email_address_composer_widget_builder.dart +++ b/lib/features/composer/presentation/widgets/email_address_composer_widget_builder.dart @@ -1,16 +1,19 @@ +import 'dart:async'; + import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_chips_input/flutter_chips_input.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart'; typedef OnOpenExpandAddressActionClick = void Function(); - +typedef OnSuggestionEmailAddress = Future> Function(String word); typedef OnUpdateListEmailAddressAction = void Function( PrefixEmailAddress prefixEmailAddress, List listEmailAddress @@ -21,7 +24,6 @@ class EmailAddressComposerWidgetBuilder { final ImagePaths _imagePaths; final BuildContext _context; final ExpandMode _expandMode; - final List _listEmailAddressSuggestion; final List _listToEmailAddress; final List _listCcEmailAddress; final List _listBccEmailAddress; @@ -31,12 +33,12 @@ class EmailAddressComposerWidgetBuilder { OnOpenExpandAddressActionClick? _onOpenExpandAddressActionClick; OnUpdateListEmailAddressAction? _onUpdateListEmailAddressAction; + OnSuggestionEmailAddress? _onSuggestionEmailAddress; EmailAddressComposerWidgetBuilder( this._context, this._imagePaths, this._expandMode, - this._listEmailAddressSuggestion, this._listToEmailAddress, this._listCcEmailAddress, this._listBccEmailAddress, @@ -51,6 +53,10 @@ class EmailAddressComposerWidgetBuilder { _onUpdateListEmailAddressAction = onUpdateListEmailAddressAction; } + void addOnSuggestionEmailAddress(OnSuggestionEmailAddress onSuggestionEmailAddress) { + _onSuggestionEmailAddress = onSuggestionEmailAddress; + } + Widget build() { keyToEmailAddress.currentState?.selectSuggestion(_listToEmailAddress); @@ -115,29 +121,33 @@ class EmailAddressComposerWidgetBuilder { : Key('${prefixEmailAddress.toString()}_email_address_input'), initialValue: _getListEmailAddressCurrent(prefixEmailAddress), textStyle: TextStyle(color: AppColor.nameUserColor, fontSize: 14, fontWeight: FontWeight.w500), + cursorColor: AppColor.primaryColor, decoration: InputDecoration( border: InputBorder.none, hintText: AppLocalizations.of(_context).hint_text_email_address, hintMaxLines: 1, hintStyle: TextStyle(color: AppColor.baseTextColor, fontSize: 14, fontWeight: FontWeight.w500)), - initialSuggestions: _listEmailAddressSuggestion, findSuggestions: (query) { - if (query.isNotEmpty) { - final lowercaseQuery = query.toLowerCase(); - return _listEmailAddressSuggestion - .where((emailAddress) => emailAddress.getName().toLowerCase().contains(query.toLowerCase()) - || emailAddress.getEmail().toLowerCase().contains(query.toLowerCase())) - .toList(growable: false) - ..sort((email1, email2) => email1.asString().toLowerCase().indexOf(lowercaseQuery).compareTo(email2.asString().toLowerCase().indexOf(lowercaseQuery))); + if (query.isNotEmpty && _onSuggestionEmailAddress != null) { + return _onSuggestionEmailAddress!(query); } return []; }, onChanged: (data) { - print('data: $data'); if (_onUpdateListEmailAddressAction != null) { _onUpdateListEmailAddressAction!(prefixEmailAddress, data); } }, + onChipInputActionDone: (state, value) { + if (GetUtils.isEmail(value)) { + state.selectSuggestion(EmailAddress(value, value)); + } + }, + onChipInputChangeFocusAction: (state, value) { + if (GetUtils.isEmail(value)) { + state.selectSuggestion(EmailAddress(value, value)); + } + }, chipBuilder: (context, state, emailAddress) { return InputChip( key: ObjectKey(emailAddress), diff --git a/lib/features/composer/presentation/widgets/top_bar_composer_widget_builder.dart b/lib/features/composer/presentation/widgets/top_bar_composer_widget_builder.dart index de23c4846..6bfb15171 100644 --- a/lib/features/composer/presentation/widgets/top_bar_composer_widget_builder.dart +++ b/lib/features/composer/presentation/widgets/top_bar_composer_widget_builder.dart @@ -11,9 +11,9 @@ class TopBarComposerWidgetBuilder { OnSendEmailActionClick? _onSendEmailActionClick; final ImagePaths _imagePaths; - bool isEnableEmailSendButton; + final bool _isEnableEmailSendButton; - TopBarComposerWidgetBuilder(this._imagePaths, this.isEnableEmailSendButton); + TopBarComposerWidgetBuilder(this._imagePaths, this._isEnableEmailSendButton); void addBackActionClick(OnBackActionClick onBackActionClick) { _onBackActionClick = onBackActionClick; @@ -68,12 +68,11 @@ class TopBarComposerWidgetBuilder { SizedBox(width: 10), ButtonBuilder(_imagePaths.icComposerSend) .key(Key('button_send_email')) - .color(isEnableEmailSendButton ? AppColor.enableSendEmailButtonColor : AppColor.disableSendEmailButtonColor) + .color(_isEnableEmailSendButton ? AppColor.enableSendEmailButtonColor : AppColor.disableSendEmailButtonColor) .onPressActionClick(() { - if (_onSendEmailActionClick != null && isEnableEmailSendButton) { + if (_onSendEmailActionClick != null && _isEnableEmailSendButton) { _onSendEmailActionClick!(); - } - }) + }}) .build(), SizedBox(width: 10), ButtonBuilder(_imagePaths.icComposerMenu).key(Key('button_menu_composer')).build(), diff --git a/lib/features/email/data/datasource/email_datasource.dart b/lib/features/email/data/datasource/email_datasource.dart index 9aa8967a9..70478c27a 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -1,6 +1,9 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; abstract class EmailDataSource { Future getEmailContent(AccountId accountId, EmailId emailId); + + Future sendEmail(AccountId accountId, EmailRequest emailRequest); } \ No newline at end of file diff --git a/lib/features/email/data/datasource_impl/email_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_datasource_impl.dart index e792145be..1b70de051 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -1,5 +1,6 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; import 'package:tmail_ui_user/features/email/data/network/email_api.dart'; @@ -17,4 +18,13 @@ class EmailDataSourceImpl extends EmailDataSource { throw error; }); } + + @override + Future sendEmail(AccountId accountId, EmailRequest emailRequest) { + return Future.sync(() async { + return await emailAPI.sendEmail(accountId, emailRequest); + }).catchError((error) { + throw error; + }); + } } \ No newline at end of file diff --git a/lib/features/email/data/network/email_api.dart b/lib/features/email/data/network/email_api.dart index 72e3aeb95..a6ebc3d96 100644 --- a/lib/features/email/data/network/email_api.dart +++ b/lib/features/email/data/network/email_api.dart @@ -2,11 +2,23 @@ import 'dart:async'; import 'package:jmap_dart_client/http/http_client.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/patch_object.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; +import 'package:jmap_dart_client/jmap/core/reference_id.dart'; +import 'package:jmap_dart_client/jmap/core/reference_prefix.dart'; import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/get/get_email_method.dart'; import 'package:jmap_dart_client/jmap/mail/email/get/get_email_response.dart'; +import 'package:jmap_dart_client/jmap/mail/email/set/set_email_method.dart'; +import 'package:jmap_dart_client/jmap/mail/email/set/set_email_response.dart'; +import 'package:jmap_dart_client/jmap/mail/email/submission/address.dart'; +import 'package:jmap_dart_client/jmap/mail/email/submission/email_submission.dart'; +import 'package:jmap_dart_client/jmap/mail/email/submission/email_submission_id.dart'; +import 'package:jmap_dart_client/jmap/mail/email/submission/envelope.dart'; +import 'package:jmap_dart_client/jmap/mail/email/submission/set/set_email_submission_method.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; +import 'package:model/model.dart'; class EmailAPI { @@ -40,4 +52,55 @@ class EmailAPI { throw error; }); } + + Future sendEmail(AccountId accountId, EmailRequest emailRequest) async { + final mailboxIdSaved = emailRequest.mailboxIdSaved ?? emailRequest.email.mailboxIds?.keys.first; + + final setEmailMethod = SetEmailMethod(accountId) + ..addCreate(emailRequest.email.id.id, emailRequest.email); + + final setEmailSubmissionMethod = SetEmailSubmissionMethod(accountId) + ..addCreate( + emailRequest.submissionCreateId, + EmailSubmission( + emailId: EmailId(ReferenceId(ReferencePrefix.defaultPrefix, emailRequest.email.id.id)), + envelope: Envelope( + Address(emailRequest.email.from?.first.email ?? ''), + emailRequest.email.getRecipientEmailAddressList().map((emailAddress) => Address(emailAddress)).toSet() + ) + )) + ..addOnSuccessUpdateEmail({ + EmailSubmissionId(ReferenceId(ReferencePrefix.defaultPrefix, emailRequest.submissionCreateId)): PatchObject({ + PatchObject.mailboxIdsProperty: { + mailboxIdSaved?.id.value: true + } + }) + }); + + final requestBuilder = JmapRequestBuilder(httpClient, ProcessingInvocation()); + + final setEmailInvocation = requestBuilder.invocation(setEmailMethod); + final setEmailSubmissionInvocation = requestBuilder.invocation(setEmailSubmissionMethod); + + final response = await (requestBuilder + ..usings(setEmailSubmissionMethod.requiredCapabilities)) + .build() + .execute(); + + final setEmailResponse = response.parse( + setEmailInvocation.methodCallId, + SetEmailResponse.deserialize); + + final setEmailSubmissionResponse = response.parse( + setEmailSubmissionInvocation.methodCallId, + SetEmailResponse.deserialize, + methodName: setEmailInvocation.methodName); + + return Future.sync(() async { + final emailCreated = setEmailResponse!.created![emailRequest.email.id.id]; + return setEmailSubmissionResponse!.updated![emailCreated!.id.id] == null; + }).catchError((error) { + throw error; + }); + } } \ No newline at end of file diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index 108ab0cb9..c40a9800c 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -1,6 +1,7 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; @@ -14,4 +15,9 @@ class EmailRepositoryImpl extends EmailRepository { Future getEmailContent(AccountId accountId, EmailId emailId) { return emailDataSource.getEmailContent(accountId, emailId); } + + @override + Future sendEmail(AccountId accountId, EmailRequest emailRequest) { + return emailDataSource.sendEmail(accountId, emailRequest); + } } \ No newline at end of file diff --git a/lib/features/email/domain/extensions/email_extension.dart b/lib/features/email/domain/extensions/email_extension.dart deleted file mode 100644 index 21ed08794..000000000 --- a/lib/features/email/domain/extensions/email_extension.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:model/email/email_content.dart'; - -extension EmailExtension on Email { - - EmailContent toEmailContent() { - return EmailContent( - id, - htmlBody: htmlBody, - attachments: attachments, - bodyValues: bodyValues - ); - } -} \ No newline at end of file diff --git a/lib/features/email/domain/extensions/presentation_email_extension.dart b/lib/features/email/domain/extensions/presentation_email_extension.dart deleted file mode 100644 index 15575cc48..000000000 --- a/lib/features/email/domain/extensions/presentation_email_extension.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:model/model.dart'; -import 'package:core/core.dart'; - -extension PresentationEmailExtension on PresentationEmail { - - String getTimeSentEmail(String newLocale) { - final dateTime = sentAt?.value; - return sentAt.formatDate(pattern: dateTime.toPattern(), locale: newLocale); - } -} \ No newline at end of file diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart index 458e27c6b..a0d55049d 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -1,6 +1,9 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; abstract class EmailRepository { Future getEmailContent(AccountId accountId, EmailId emailId); + + Future sendEmail(AccountId accountId, EmailRequest emailRequest); } \ No newline at end of file diff --git a/lib/features/email/domain/usecases/get_email_content_interactor.dart b/lib/features/email/domain/usecases/get_email_content_interactor.dart index f073b034d..8ddb9a8e5 100644 --- a/lib/features/email/domain/usecases/get_email_content_interactor.dart +++ b/lib/features/email/domain/usecases/get_email_content_interactor.dart @@ -1,10 +1,10 @@ import 'package:core/core.dart'; +import 'package:model/model.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart'; -import 'package:tmail_ui_user/features/email/domain/extensions/email_extension.dart'; class GetEmailContentInteractor { final EmailRepository emailRepository; diff --git a/lib/features/email/presentation/constants/email_contants.dart b/lib/features/email/presentation/constants/email_constants.dart similarity index 100% rename from lib/features/email/presentation/constants/email_contants.dart rename to lib/features/email/presentation/constants/email_constants.dart diff --git a/lib/features/email/presentation/email_controller.dart b/lib/features/email/presentation/email_controller.dart index 9f84ecc1e..ca5e88093 100644 --- a/lib/features/email/presentation/email_controller.dart +++ b/lib/features/email/presentation/email_controller.dart @@ -67,14 +67,17 @@ class EmailController extends BaseController { emailAddressExpandMode.value = expandMode; } + bool canComposeEmail() => mailboxDashBoardController.sessionCurrent != null + && mailboxDashBoardController.userProfile.value != null + && mailboxDashBoardController.mapMailboxId.containsKey(PresentationMailbox.roleOutbox) + && mailboxDashBoardController.selectedEmail.value != null; + void goToThreadView(BuildContext context) { Get.back(); } void pressEmailAction(EmailActionType emailActionType) { - if (mailboxDashBoardController.selectedEmail.value != null - && mailboxDashBoardController.sessionCurrent != null - && mailboxDashBoardController.userProfile.value != null) { + if (canComposeEmail()) { Get.toNamed( AppRoutes.COMPOSER, arguments: ComposerArguments( @@ -82,7 +85,8 @@ class EmailController extends BaseController { presentationEmail: mailboxDashBoardController.selectedEmail.value!, emailContent: emailContent, session: mailboxDashBoardController.sessionCurrent!, - userProfile: mailboxDashBoardController.userProfile.value!)); + userProfile: mailboxDashBoardController.userProfile.value!, + mapMailboxId: mailboxDashBoardController.mapMailboxId)); } } } \ No newline at end of file diff --git a/lib/features/email/presentation/extensions/email_content_extension.dart b/lib/features/email/presentation/extensions/email_content_extension.dart index e33aa1643..c60e55a80 100644 --- a/lib/features/email/presentation/extensions/email_content_extension.dart +++ b/lib/features/email/presentation/extensions/email_content_extension.dart @@ -1,6 +1,6 @@ import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart'; import 'package:model/email/email_content.dart'; -import 'package:tmail_ui_user/features/email/presentation/constants/email_contants.dart'; +import 'package:tmail_ui_user/features/email/presentation/constants/email_constants.dart'; import 'package:tmail_ui_user/features/email/presentation/model/attachment_file.dart'; import 'package:tmail_ui_user/features/email/presentation/model/message_content.dart'; import 'package:tmail_ui_user/features/email/presentation/model/text_format.dart'; diff --git a/lib/features/email/presentation/extensions/presentation_email_extension.dart b/lib/features/email/presentation/extensions/presentation_email_extension.dart deleted file mode 100644 index e2d9b47f7..000000000 --- a/lib/features/email/presentation/extensions/presentation_email_extension.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:model/model.dart'; - -extension PresentationEmailExtension on PresentationEmail { - - int numberOfAllEmailAddress() => to.numberEmailAddress() + cc.numberEmailAddress() + bcc.numberEmailAddress(); - - String getSentTime(String locale) => sentAt.formatDate(pattern: 'dd/MM/yyyy h:mm a', locale: locale); -} \ No newline at end of file diff --git a/lib/features/email/presentation/model/composer_arguments.dart b/lib/features/email/presentation/model/composer_arguments.dart index 60f308ef9..fb5199be8 100644 --- a/lib/features/email/presentation/model/composer_arguments.dart +++ b/lib/features/email/presentation/model/composer_arguments.dart @@ -1,6 +1,7 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; class ComposerArguments with EquatableMixin { @@ -9,15 +10,24 @@ class ComposerArguments with EquatableMixin { final EmailContent? emailContent; final Session session; final UserProfile userProfile; + final Map mapMailboxId; ComposerArguments({ this.emailActionType = EmailActionType.compose, this.presentationEmail, this.emailContent, required this.session, - required this.userProfile + required this.userProfile, + required this.mapMailboxId, }); @override - List get props => [emailActionType, presentationEmail, emailContent, session, userProfile]; + List get props => [ + emailActionType, + presentationEmail, + emailContent, + session, + userProfile, + mapMailboxId, + ]; } \ No newline at end of file diff --git a/lib/features/email/presentation/widgets/sender_and_receiver_information_tile_builder.dart b/lib/features/email/presentation/widgets/sender_and_receiver_information_tile_builder.dart index 7b104875f..5e21ebdef 100644 --- a/lib/features/email/presentation/widgets/sender_and_receiver_information_tile_builder.dart +++ b/lib/features/email/presentation/widgets/sender_and_receiver_information_tile_builder.dart @@ -5,7 +5,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:model/email/presentation_email.dart'; import 'package:model/model.dart'; -import 'package:tmail_ui_user/features/email/presentation/extensions/presentation_email_extension.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; typedef OnOpenExpandAddressReceiverActionClick = void Function(); @@ -69,7 +68,7 @@ class SenderAndReceiverInformationTileBuilder { Padding( padding: EdgeInsets.only(top: 6), child: Text( - '${_presentationEmail!.getSentTime(Localizations.localeOf(_context).toLanguageTag())}', + '${_presentationEmail!.getEmailDateTime(Localizations.localeOf(_context).toLanguageTag(), pattern: 'dd/MM/yyyy h:mm a')}', style: TextStyle(fontSize: 12, color: AppColor.baseTextColor), )) ], diff --git a/lib/features/login/data/datasource/atuthentitcation_datasource.dart b/lib/features/login/data/datasource/authentication_datasource.dart similarity index 100% rename from lib/features/login/data/datasource/atuthentitcation_datasource.dart rename to lib/features/login/data/datasource/authentication_datasource.dart diff --git a/lib/features/login/data/datasource_impl/authentication_datasource_impl.dart b/lib/features/login/data/datasource_impl/authentication_datasource_impl.dart index 0f82f6719..bc40f8e1e 100644 --- a/lib/features/login/data/datasource_impl/authentication_datasource_impl.dart +++ b/lib/features/login/data/datasource_impl/authentication_datasource_impl.dart @@ -1,7 +1,5 @@ import 'package:model/model.dart'; -import 'package:tmail_ui_user/features/login/data/datasource/atuthentitcation_datasource.dart'; -import 'package:tmail_ui_user/features/login/data/model/request/account_request.dart'; -import 'package:tmail_ui_user/features/login/data/model/response/user_profile_response.dart'; +import 'package:tmail_ui_user/features/login/data/datasource/authentication_datasource.dart'; import 'package:tmail_ui_user/features/login/data/network/login_api.dart'; class AuthenticationDataSourceImpl extends AuthenticationDataSource { diff --git a/lib/features/login/data/network/login_api.dart b/lib/features/login/data/network/login_api.dart index 0a58c7be7..9282a5b0e 100644 --- a/lib/features/login/data/network/login_api.dart +++ b/lib/features/login/data/network/login_api.dart @@ -4,8 +4,7 @@ import 'dart:io'; import 'package:core/core.dart'; import 'package:dio/dio.dart'; -import 'package:tmail_ui_user/features/login/data/model/request/account_request.dart'; -import 'package:tmail_ui_user/features/login/data/model/response/user_profile_response.dart'; +import 'package:model/model.dart'; class LoginAPI { final DioClient _dioClient; diff --git a/lib/features/login/data/repository/authentication_repository_impl.dart b/lib/features/login/data/repository/authentication_repository_impl.dart index 298239da8..69350c974 100644 --- a/lib/features/login/data/repository/authentication_repository_impl.dart +++ b/lib/features/login/data/repository/authentication_repository_impl.dart @@ -1,5 +1,5 @@ import 'package:model/model.dart'; -import 'package:tmail_ui_user/features/login/data/datasource/atuthentitcation_datasource.dart'; +import 'package:tmail_ui_user/features/login/data/datasource/authentication_datasource.dart'; import 'package:tmail_ui_user/features/login/domain/repository/authentication_repository.dart'; class AuthenticationRepositoryImpl extends AuthenticationRepository { diff --git a/lib/features/login/data/repository/credential_repository_impl.dart b/lib/features/login/data/repository/credential_repository_impl.dart index 4d16634af..52adc3c7d 100644 --- a/lib/features/login/data/repository/credential_repository_impl.dart +++ b/lib/features/login/data/repository/credential_repository_impl.dart @@ -2,9 +2,7 @@ import 'dart:convert'; import 'package:model/model.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:tmail_ui_user/features/login/data/model/response/user_profile_response.dart'; import 'package:tmail_ui_user/features/login/data/utils/login_constant.dart'; -import 'package:tmail_ui_user/features/login/data/extensions/user_profile_extension.dart'; import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; class CredentialRepositoryImpl extends CredentialRepository { diff --git a/lib/features/login/domain/extensions/uri_extension.dart b/lib/features/login/domain/extensions/uri_extension.dart index 145609682..ea9f10443 100644 --- a/lib/features/login/domain/extensions/uri_extension.dart +++ b/lib/features/login/domain/extensions/uri_extension.dart @@ -1,4 +1,3 @@ -// extension UriExtension on Uri { bool isBaseUrlValid() => origin.isNotEmpty; diff --git a/lib/features/login/presentation/login_bindings.dart b/lib/features/login/presentation/login_bindings.dart index 74dec5811..c0006e5bf 100644 --- a/lib/features/login/presentation/login_bindings.dart +++ b/lib/features/login/presentation/login_bindings.dart @@ -1,7 +1,7 @@ import 'package:core/core.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:tmail_ui_user/features/login/data/datasource/atuthentitcation_datasource.dart'; +import 'package:tmail_ui_user/features/login/data/datasource/authentication_datasource.dart'; import 'package:tmail_ui_user/features/login/data/datasource_impl/authentication_datasource_impl.dart'; import 'package:tmail_ui_user/features/login/data/network/login_api.dart'; import 'package:tmail_ui_user/features/login/data/repository/authentication_repository_impl.dart'; diff --git a/lib/features/mailbox/domain/constants/mailbox_constants.dart b/lib/features/mailbox/domain/constants/mailbox_constants.dart index df9393275..052a32b4a 100644 --- a/lib/features/mailbox/domain/constants/mailbox_constants.dart +++ b/lib/features/mailbox/domain/constants/mailbox_constants.dart @@ -1,4 +1,3 @@ class MailboxConstants { static const MAILBOX_LEVEL_SEPARATOR = "/"; - static const ROLE_DEFAULT = "inbox"; } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index b8b129144..3bdfbe136 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -6,7 +6,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; -import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/select_mode.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; @@ -78,7 +77,7 @@ class MailboxController extends BaseController { void onDone() { viewState.value.map((success) { if (success is GetAllMailboxSuccess) { - _setUpMailboxDefault(success.defaultMailboxList); + _setUpMapMailboxIdDefault(success.defaultMailboxList); } }); } @@ -90,12 +89,13 @@ class MailboxController extends BaseController { folderMailboxTree.value = await _treeBuilder.generateMailboxTree(folderMailboxList); } - void _setUpMailboxDefault(List defaultMailboxList) { - try { - final mailboxDefault = defaultMailboxList - .firstWhere((presentationMailbox) => presentationMailbox.role == Role(MailboxConstants.ROLE_DEFAULT)); - mailboxDashBoardController.setSelectedMailbox(mailboxDefault); - } catch (e) {} + void _setUpMapMailboxIdDefault(List defaultMailboxList) { + defaultMailboxList.forEach((presentationMailbox) { + if (presentationMailbox.role == PresentationMailbox.roleInbox) { + mailboxDashBoardController.setSelectedMailbox(presentationMailbox); + } + mailboxDashBoardController.addMailboxIdToMap(presentationMailbox.role!, presentationMailbox.id); + }); } SelectMode getSelectMode(PresentationMailbox presentationMailbox, PresentationMailbox? selectedMailbox) { diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart index 76ac5a03d..cfb4fef5a 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart @@ -3,6 +3,7 @@ import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/email_controller.dart'; @@ -20,6 +21,7 @@ class MailboxDashBoardController extends BaseController { final userProfile = Rxn(); Session? sessionCurrent; + Map mapMailboxId = Map(); MailboxDashBoardController(this._getUserProfileInteractor); @@ -57,6 +59,10 @@ class MailboxDashBoardController extends BaseController { }); } + void addMailboxIdToMap(Role role, MailboxId mailboxId) { + mapMailboxId[role] = mailboxId; + } + void setSelectedMailbox(PresentationMailbox? newPresentationMailbox) { selectedMailbox.value = newPresentationMailbox; } diff --git a/lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart b/lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart index f3218af4e..6fd906395 100644 --- a/lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart +++ b/lib/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart @@ -1,4 +1,5 @@ import 'package:core/core.dart'; +import 'package:model/model.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; @@ -7,7 +8,6 @@ import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart'; -import 'package:tmail_ui_user/features/thread/domain/extensions/email_extension.dart'; class GetEmailsInMailboxInteractor { final ThreadRepository threadRepository; diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index cead585dd..29570a001 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -170,6 +170,10 @@ class ThreadController extends BaseController { } } + bool canComposeEmail() => mailboxDashBoardController.sessionCurrent != null + && mailboxDashBoardController.userProfile.value != null + && mailboxDashBoardController.mapMailboxId.containsKey([PresentationMailbox.roleOutbox]); + void openMailboxLeftMenu() { mailboxDashBoardController.openDrawer(); } @@ -179,12 +183,13 @@ class ThreadController extends BaseController { } void composeEmailAction() { - if (mailboxDashBoardController.sessionCurrent != null && mailboxDashBoardController.userProfile.value != null) { + if (canComposeEmail()) { Get.toNamed( AppRoutes.COMPOSER, arguments: ComposerArguments( session: mailboxDashBoardController.sessionCurrent!, - userProfile: mailboxDashBoardController.userProfile.value!)); + userProfile: mailboxDashBoardController.userProfile.value!, + mapMailboxId: mailboxDashBoardController.mapMailboxId)); } } } \ No newline at end of file diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index d93488c58..76e2b92ec 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -43,7 +43,7 @@ class ThreadView extends GetWidget { ) ), floatingActionButton: FloatingActionButton( - elevation: 0.0, + elevation: 4.0, child: new Icon(Icons.add), backgroundColor: AppColor.appColor, onPressed: () => controller.composeEmailAction() diff --git a/lib/features/thread/presentation/widgets/email_tile_builder.dart b/lib/features/thread/presentation/widgets/email_tile_builder.dart index a916b355d..0ef744701 100644 --- a/lib/features/thread/presentation/widgets/email_tile_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_builder.dart @@ -4,7 +4,6 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:model/model.dart'; -import 'package:tmail_ui_user/features/email/domain/extensions/presentation_email_extension.dart'; typedef OnOpenMailActionClick = void Function(); @@ -82,7 +81,7 @@ class EmailTileBuilder { Padding( padding: EdgeInsets.only(right: 4), child: Text( - '${_presentationEmail.getTimeSentEmail(Localizations.localeOf(_context).toLanguageTag())}', + '${_presentationEmail.getEmailDateTime(Localizations.localeOf(_context).toLanguageTag())}', maxLines: 1, overflow:TextOverflow.ellipsis, style: TextStyle( diff --git a/lib/main/bindings/core/core_bindings.dart b/lib/main/bindings/core/core_bindings.dart index 02bdf5868..6171d4ca2 100644 --- a/lib/main/bindings/core/core_bindings.dart +++ b/lib/main/bindings/core/core_bindings.dart @@ -1,4 +1,5 @@ import 'package:core/core.dart'; +import 'package:core/presentation/utils/app_toast.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -10,7 +11,8 @@ class CoreBindings extends Bindings { _bindingAppImagePaths(); _bindingResponsiveManager(); _bindingKeyboardManager(); - _bindingValiadtor(); + _bindingValidator(); + _bindingToast(); } void _bindingAppImagePaths() { @@ -29,7 +31,11 @@ class CoreBindings extends Bindings { Get.put(KeyboardUtils()); } - void _bindingValiadtor() { + void _bindingValidator() { Get.put(HtmlMessagePurifier()); } + + void _bindingToast() { + Get.put(AppToast()); + } } \ No newline at end of file diff --git a/lib/main/bindings/local/local_bindings.dart b/lib/main/bindings/local/local_bindings.dart new file mode 100644 index 000000000..4b3baed5d --- /dev/null +++ b/lib/main/bindings/local/local_bindings.dart @@ -0,0 +1,15 @@ + +import 'package:core/core.dart'; +import 'package:get/get.dart'; + +class LocalBindings extends Bindings { + + @override + void dependencies() { + _bindingDatabase(); + } + + void _bindingDatabase() { + Get.put(DatabaseClient()); + } +} \ No newline at end of file diff --git a/lib/main/bindings/main_bindings.dart b/lib/main/bindings/main_bindings.dart index b5e4c3056..1b225f8c5 100644 --- a/lib/main/bindings/main_bindings.dart +++ b/lib/main/bindings/main_bindings.dart @@ -1,5 +1,6 @@ import 'package:get/get.dart'; import 'package:tmail_ui_user/main/bindings/core/core_bindings.dart'; +import 'package:tmail_ui_user/main/bindings/local/local_bindings.dart'; import 'package:tmail_ui_user/main/bindings/network/network_bindings.dart'; class MainBindings extends Bindings { @@ -7,5 +8,6 @@ class MainBindings extends Bindings { Future dependencies() async { await CoreBindings().dependencies(); NetworkBindings().dependencies(); + LocalBindings().dependencies(); } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 5e528e506..e0f6136e1 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -199,5 +199,33 @@ class AppLocalizations { name: 'prefix_forward_email', ); } + + String get your_email_being_sent { + return Intl.message( + 'Your email being sent...', + name: 'your_email_being_sent', + ); + } + + String get your_email_should_have_at_least_one_recipient { + return Intl.message( + 'Your email should have at least one recipient', + name: 'your_email_should_have_at_least_one_recipient', + ); + } + + String get message_sent { + return Intl.message( + 'Message sent', + name: 'message_sent', + ); + } + + String get error_message_sent { + return Intl.message( + 'Error message sent', + name: 'error_message_sent', + ); + } }