From 64171603bb092fa0370c56b8c2dad0463e421dec Mon Sep 17 00:00:00 2001 From: hieubt Date: Fri, 3 Nov 2023 16:08:36 +0700 Subject: [PATCH] TF-2196 Update controller with 'From' (cherry picked from commit 4f0854a762631ded27cc197a9cce18c5de0ed97a) --- .../presentation/composer_controller.dart | 74 ++++++++++++++++--- .../from_composer_mobile_widget_style.dart | 8 +- .../mobile/from_composer_mobile_widget.dart | 16 ++-- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 66efbaaee..cc270b7da 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -7,6 +7,7 @@ import 'package:collection/collection.dart'; import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:device_info_plus/device_info_plus.dart'; +import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:file_picker/file_picker.dart'; import 'package:filesize/filesize.dart'; import 'package:fk_user_agent/fk_user_agent.dart'; @@ -58,6 +59,7 @@ import 'package:tmail_ui_user/features/composer/presentation/model/save_to_draft import 'package:tmail_ui_user/features/composer/presentation/model/save_to_draft_view_event.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/composer_style.dart'; +import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/from_composer_bottom_sheet_builder.dart'; import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/transform_html_email_content_state.dart'; @@ -109,9 +111,12 @@ class ComposerController extends BaseController { final bccAddressExpandMode = ExpandMode.EXPAND.obs; final emailContentsViewState = Rxn>(); final hasRequestReadReceipt = false.obs; + final fromRecipientState = PrefixRecipientState.disabled.obs; final ccRecipientState = PrefixRecipientState.disabled.obs; final bccRecipientState = PrefixRecipientState.disabled.obs; final isSendEmailLoading = false.obs; + final identitySelected = Rxn(); + final listFromIdentities = RxList(); final LocalFilePickerInteractor _localFilePickerInteractor; final DeviceInfoPlugin _deviceInfoPlugin; @@ -136,23 +141,27 @@ class ComposerController extends BaseController { final toEmailAddressController = TextEditingController(); final ccEmailAddressController = TextEditingController(); final bccEmailAddressController = TextEditingController(); + final searchIdentitiesInputController = TextEditingController(); final GlobalKey keyToEmailTagEditor = GlobalKey(); final GlobalKey keyCcEmailTagEditor = GlobalKey(); final GlobalKey keyBccEmailTagEditor = GlobalKey(); final GlobalKey headerEditorMobileWidgetKey = GlobalKey(); + final GlobalKey identityDropdownKey = GlobalKey(); final double defaultPaddingCoordinateYCursorEditor = 8; FocusNode? subjectEmailInputFocusNode; FocusNode? toAddressFocusNode; FocusNode? ccAddressFocusNode; FocusNode? bccAddressFocusNode; + FocusNode? searchIdentitiesFocusNode; final RichTextController keyboardRichTextController = RichTextController(); final ScrollController scrollController = ScrollController(); final ScrollController scrollControllerEmailAddress = ScrollController(); final ScrollController scrollControllerAttachment = ScrollController(); + final ScrollController scrollControllerIdentities = ScrollController(); final _saveToDraftEventController = StreamController(); Stream get _saveToDraftEventStream => _saveToDraftEventController.stream; @@ -164,7 +173,6 @@ class ComposerController extends BaseController { double? maxWithEditor; EmailId? _emailIdEditing; bool isAttachmentCollapsed = false; - Identity? identitySelected; late Worker uploadInlineImageWorker; late Worker dashboardViewStateWorker; @@ -227,6 +235,8 @@ class ComposerController extends BaseController { ccAddressFocusNode = null; bccAddressFocusNode?.dispose(); bccAddressFocusNode = null; + searchIdentitiesFocusNode?.dispose(); + searchIdentitiesFocusNode = null; subjectEmailInputController.dispose(); toEmailAddressController.dispose(); ccEmailAddressController.dispose(); @@ -238,6 +248,7 @@ class ComposerController extends BaseController { scrollControllerEmailAddress.removeListener(_scrollControllerEmailAddressListener); scrollControllerEmailAddress.dispose(); scrollControllerAttachment.dispose(); + scrollControllerIdentities.dispose(); _saveToDraftStreamSubscription.cancel(); _saveToDraftEventController.close(); super.dispose(); @@ -366,6 +377,7 @@ class ComposerController extends BaseController { ); ccAddressFocusNode = FocusNode(); bccAddressFocusNode = FocusNode(); + searchIdentitiesFocusNode = FocusNode(); subjectEmailInputFocusNode?.addListener(() { log('ComposerController::createFocusNodeInput():subjectEmailInputFocusNode: ${subjectEmailInputFocusNode?.hasFocus}'); @@ -414,7 +426,7 @@ class ComposerController extends BaseController { } void onLoadCompletedMobileEditorAction(HtmlEditorApi editorApi, WebUri? url) { - if (identitySelected == null) { + if (identitySelected.value == null) { _getAllIdentities(); } } @@ -552,10 +564,13 @@ class ComposerController extends BaseController { void _handleGetAllIdentitiesSuccess(GetAllIdentitiesSuccess success) async { final listIdentitiesMayDeleted = success.identities?.toListMayDeleted() ?? []; if (listIdentitiesMayDeleted.isNotEmpty) { + listFromIdentities.value = listIdentitiesMayDeleted; await _selectIdentity(listIdentitiesMayDeleted.first); } - _autoFocusFieldWhenLauncher(); + if (fromRecipientState.value == PrefixRecipientState.disabled) { + _autoFocusFieldWhenLauncher(); + } } void _initEmailAddress({ @@ -663,17 +678,17 @@ class ComposerController extends BaseController { } ) async { Set listFromEmailAddress = {EmailAddress(null, userProfile.email)}; - if (identitySelected?.email?.isNotEmpty == true) { + if (identitySelected.value?.email?.isNotEmpty == true) { listFromEmailAddress = { EmailAddress( - identitySelected?.name, - identitySelected?.email + identitySelected.value?.name, + identitySelected.value?.email ) }; } Set listReplyToEmailAddress = {EmailAddress(null, userProfile.email)}; - if (identitySelected?.replyTo?.isNotEmpty == true) { - listReplyToEmailAddress = identitySelected!.replyTo!; + if (identitySelected.value?.replyTo?.isNotEmpty == true) { + listReplyToEmailAddress = identitySelected.value!.replyTo!; } final attachments = {}; @@ -931,7 +946,7 @@ class ComposerController extends BaseController { : EmailRequest( email: createdEmail, sentMailboxId: mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleSent], - identityId: identitySelected?.id, + identityId: identitySelected.value?.id, emailIdDestroyed: arguments.emailActionType == EmailActionType.editDraft ? arguments.presentationEmail?.id : null, @@ -1502,6 +1517,9 @@ class ComposerController extends BaseController { void addEmailAddressType(PrefixEmailAddress prefixEmailAddress) { switch(prefixEmailAddress) { + case PrefixEmailAddress.from: + fromRecipientState.value = PrefixRecipientState.enabled; + break; case PrefixEmailAddress.cc: ccRecipientState.value = PrefixRecipientState.enabled; break; @@ -1672,8 +1690,8 @@ class ComposerController extends BaseController { } Future _selectIdentity(Identity? newIdentity) async { - final formerIdentity = identitySelected; - identitySelected = newIdentity; + final formerIdentity = identitySelected.value; + identitySelected.value = newIdentity; if (newIdentity != null) { await _applyIdentityForAllFieldComposer(formerIdentity, newIdentity); } @@ -1927,7 +1945,7 @@ class ComposerController extends BaseController { richTextWebController.editorController.setFullScreen(); onChangeTextEditorWeb(initContent); richTextWebController.setEnableCodeView(); - if (identitySelected == null) { + if (identitySelected.value == null) { _getAllIdentities(); } } @@ -2135,4 +2153,36 @@ class ComposerController extends BaseController { } } } + + Future onChangeIdentity(Identity? newIdentity) async { + await _selectIdentity(newIdentity); + } + + void _searchIdentities(String searchText) { + if (searchText.isEmpty) { + _getAllIdentities(); + } else { + listFromIdentities.value = listFromIdentities + .where((identity) => identity.name?.toLowerCase().contains(searchText.toLowerCase()) == true) + .toList(); + } + } + + void openSelectIdentityBottomSheet(BuildContext context) { + ( + FromComposerBottomSheetBuilder( + context, + _imagePaths, + listFromIdentities, + scrollControllerIdentities, + searchIdentitiesInputController + ) + ..onCloseAction(() => popBack()) + ..onChangeIdentityAction((identity) { + onChangeIdentity(identity); + popBack(); + }) + ..onTextSearchChangedAction((searchText) => _searchIdentities(searchText)) + ).build(); + } } \ No newline at end of file diff --git a/lib/features/composer/presentation/styles/mobile/from_composer_mobile_widget_style.dart b/lib/features/composer/presentation/styles/mobile/from_composer_mobile_widget_style.dart index 941658d0d..0f53b1db3 100644 --- a/lib/features/composer/presentation/styles/mobile/from_composer_mobile_widget_style.dart +++ b/lib/features/composer/presentation/styles/mobile/from_composer_mobile_widget_style.dart @@ -4,13 +4,11 @@ import 'package:flutter/material.dart'; class FromComposerMobileWidgetStyle { static const double space = 8.0; static const double identityButtonHeight = 32.0; - static const double identityButtonWidthMobileLandscape = 421.0; static const EdgeInsetsGeometry identityButtonInkWellPadding = EdgeInsets.symmetric(vertical: 8.0); static const EdgeInsetsGeometry identityButtonPadding = EdgeInsets.only( top: 4, bottom: 4, - right: 4, left: 8, ); @@ -34,11 +32,13 @@ class FromComposerMobileWidgetStyle { static const TextStyle buttonTitleTextStyle = TextStyle( fontSize: 16, fontWeight: FontWeight.w500, - color: AppColor.colorCalendarEventUnread + color: AppColor.colorCalendarEventUnread, + overflow: TextOverflow.ellipsis, ); static const TextStyle buttonSubTitleTextStyle = TextStyle( fontSize: 16, fontWeight: FontWeight.w500, - color: AppColor.colorLabelComposer + color: AppColor.colorLabelComposer, + overflow: TextOverflow.ellipsis, ); } \ No newline at end of file diff --git a/lib/features/composer/presentation/widgets/mobile/from_composer_mobile_widget.dart b/lib/features/composer/presentation/widgets/mobile/from_composer_mobile_widget.dart index b46d365e3..98705e8d9 100644 --- a/lib/features/composer/presentation/widgets/mobile/from_composer_mobile_widget.dart +++ b/lib/features/composer/presentation/widgets/mobile/from_composer_mobile_widget.dart @@ -46,26 +46,24 @@ class FromComposerMobileWidget extends StatelessWidget { ), ), const SizedBox(width: FromComposerMobileWidgetStyle.space), - Expanded( - child: Container( + Flexible( + child: Padding( padding: FromComposerMobileWidgetStyle.identityButtonInkWellPadding, child: InkWell( borderRadius: FromComposerMobileWidgetStyle.identityButtonInkWellBorderRadius, onTap: onTap, child: Container( height: FromComposerMobileWidgetStyle.identityButtonHeight, - width: responsiveUtils.isLandscapeMobile(context) - ? FromComposerMobileWidgetStyle.identityButtonWidthMobileLandscape - : 0, padding: FromComposerMobileWidgetStyle.identityButtonPadding, decoration: FromComposerMobileWidgetStyle.identityButtonDecoration, child: Row( + mainAxisSize: MainAxisSize.min, children: [ if (selectedIdentity != null) - Expanded( + Flexible( child: RichText( maxLines: 1, - softWrap: CommonTextStyle.defaultSoftWrap, + softWrap: false, overflow: CommonTextStyle.defaultTextOverFlow, text: TextSpan( children: [ @@ -82,11 +80,11 @@ class FromComposerMobileWidget extends StatelessWidget { ) ] ), - ) + ), ) else const SizedBox.shrink(), - SvgPicture.asset(imagePaths.icDropDown) + SvgPicture.asset(imagePaths.icDropDown), ], ), ),