TF-2196 Update controller with 'From'
(cherry picked from commit 4f0854a762631ded27cc197a9cce18c5de0ed97a)
This commit is contained in:
@@ -7,6 +7,7 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:core/core.dart';
|
import 'package:core/core.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:device_info_plus/device_info_plus.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:file_picker/file_picker.dart';
|
||||||
import 'package:filesize/filesize.dart';
|
import 'package:filesize/filesize.dart';
|
||||||
import 'package:fk_user_agent/fk_user_agent.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/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/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/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/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/get_email_content_state.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/state/transform_html_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 bccAddressExpandMode = ExpandMode.EXPAND.obs;
|
||||||
final emailContentsViewState = Rxn<Either<Failure, Success>>();
|
final emailContentsViewState = Rxn<Either<Failure, Success>>();
|
||||||
final hasRequestReadReceipt = false.obs;
|
final hasRequestReadReceipt = false.obs;
|
||||||
|
final fromRecipientState = PrefixRecipientState.disabled.obs;
|
||||||
final ccRecipientState = PrefixRecipientState.disabled.obs;
|
final ccRecipientState = PrefixRecipientState.disabled.obs;
|
||||||
final bccRecipientState = PrefixRecipientState.disabled.obs;
|
final bccRecipientState = PrefixRecipientState.disabled.obs;
|
||||||
final isSendEmailLoading = false.obs;
|
final isSendEmailLoading = false.obs;
|
||||||
|
final identitySelected = Rxn<Identity>();
|
||||||
|
final listFromIdentities = RxList<Identity>();
|
||||||
|
|
||||||
final LocalFilePickerInteractor _localFilePickerInteractor;
|
final LocalFilePickerInteractor _localFilePickerInteractor;
|
||||||
final DeviceInfoPlugin _deviceInfoPlugin;
|
final DeviceInfoPlugin _deviceInfoPlugin;
|
||||||
@@ -136,23 +141,27 @@ class ComposerController extends BaseController {
|
|||||||
final toEmailAddressController = TextEditingController();
|
final toEmailAddressController = TextEditingController();
|
||||||
final ccEmailAddressController = TextEditingController();
|
final ccEmailAddressController = TextEditingController();
|
||||||
final bccEmailAddressController = TextEditingController();
|
final bccEmailAddressController = TextEditingController();
|
||||||
|
final searchIdentitiesInputController = TextEditingController();
|
||||||
|
|
||||||
final GlobalKey<TagsEditorState> keyToEmailTagEditor = GlobalKey<TagsEditorState>();
|
final GlobalKey<TagsEditorState> keyToEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||||
final GlobalKey<TagsEditorState> keyCcEmailTagEditor = GlobalKey<TagsEditorState>();
|
final GlobalKey<TagsEditorState> keyCcEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||||
final GlobalKey<TagsEditorState> keyBccEmailTagEditor = GlobalKey<TagsEditorState>();
|
final GlobalKey<TagsEditorState> keyBccEmailTagEditor = GlobalKey<TagsEditorState>();
|
||||||
final GlobalKey headerEditorMobileWidgetKey = GlobalKey();
|
final GlobalKey headerEditorMobileWidgetKey = GlobalKey();
|
||||||
|
final GlobalKey<DropdownButton2State> identityDropdownKey = GlobalKey<DropdownButton2State>();
|
||||||
final double defaultPaddingCoordinateYCursorEditor = 8;
|
final double defaultPaddingCoordinateYCursorEditor = 8;
|
||||||
|
|
||||||
FocusNode? subjectEmailInputFocusNode;
|
FocusNode? subjectEmailInputFocusNode;
|
||||||
FocusNode? toAddressFocusNode;
|
FocusNode? toAddressFocusNode;
|
||||||
FocusNode? ccAddressFocusNode;
|
FocusNode? ccAddressFocusNode;
|
||||||
FocusNode? bccAddressFocusNode;
|
FocusNode? bccAddressFocusNode;
|
||||||
|
FocusNode? searchIdentitiesFocusNode;
|
||||||
|
|
||||||
final RichTextController keyboardRichTextController = RichTextController();
|
final RichTextController keyboardRichTextController = RichTextController();
|
||||||
|
|
||||||
final ScrollController scrollController = ScrollController();
|
final ScrollController scrollController = ScrollController();
|
||||||
final ScrollController scrollControllerEmailAddress = ScrollController();
|
final ScrollController scrollControllerEmailAddress = ScrollController();
|
||||||
final ScrollController scrollControllerAttachment = ScrollController();
|
final ScrollController scrollControllerAttachment = ScrollController();
|
||||||
|
final ScrollController scrollControllerIdentities = ScrollController();
|
||||||
|
|
||||||
final _saveToDraftEventController = StreamController<SaveToDraftViewEvent>();
|
final _saveToDraftEventController = StreamController<SaveToDraftViewEvent>();
|
||||||
Stream<SaveToDraftViewEvent> get _saveToDraftEventStream => _saveToDraftEventController.stream;
|
Stream<SaveToDraftViewEvent> get _saveToDraftEventStream => _saveToDraftEventController.stream;
|
||||||
@@ -164,7 +173,6 @@ class ComposerController extends BaseController {
|
|||||||
double? maxWithEditor;
|
double? maxWithEditor;
|
||||||
EmailId? _emailIdEditing;
|
EmailId? _emailIdEditing;
|
||||||
bool isAttachmentCollapsed = false;
|
bool isAttachmentCollapsed = false;
|
||||||
Identity? identitySelected;
|
|
||||||
|
|
||||||
late Worker uploadInlineImageWorker;
|
late Worker uploadInlineImageWorker;
|
||||||
late Worker dashboardViewStateWorker;
|
late Worker dashboardViewStateWorker;
|
||||||
@@ -227,6 +235,8 @@ class ComposerController extends BaseController {
|
|||||||
ccAddressFocusNode = null;
|
ccAddressFocusNode = null;
|
||||||
bccAddressFocusNode?.dispose();
|
bccAddressFocusNode?.dispose();
|
||||||
bccAddressFocusNode = null;
|
bccAddressFocusNode = null;
|
||||||
|
searchIdentitiesFocusNode?.dispose();
|
||||||
|
searchIdentitiesFocusNode = null;
|
||||||
subjectEmailInputController.dispose();
|
subjectEmailInputController.dispose();
|
||||||
toEmailAddressController.dispose();
|
toEmailAddressController.dispose();
|
||||||
ccEmailAddressController.dispose();
|
ccEmailAddressController.dispose();
|
||||||
@@ -238,6 +248,7 @@ class ComposerController extends BaseController {
|
|||||||
scrollControllerEmailAddress.removeListener(_scrollControllerEmailAddressListener);
|
scrollControllerEmailAddress.removeListener(_scrollControllerEmailAddressListener);
|
||||||
scrollControllerEmailAddress.dispose();
|
scrollControllerEmailAddress.dispose();
|
||||||
scrollControllerAttachment.dispose();
|
scrollControllerAttachment.dispose();
|
||||||
|
scrollControllerIdentities.dispose();
|
||||||
_saveToDraftStreamSubscription.cancel();
|
_saveToDraftStreamSubscription.cancel();
|
||||||
_saveToDraftEventController.close();
|
_saveToDraftEventController.close();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@@ -366,6 +377,7 @@ class ComposerController extends BaseController {
|
|||||||
);
|
);
|
||||||
ccAddressFocusNode = FocusNode();
|
ccAddressFocusNode = FocusNode();
|
||||||
bccAddressFocusNode = FocusNode();
|
bccAddressFocusNode = FocusNode();
|
||||||
|
searchIdentitiesFocusNode = FocusNode();
|
||||||
|
|
||||||
subjectEmailInputFocusNode?.addListener(() {
|
subjectEmailInputFocusNode?.addListener(() {
|
||||||
log('ComposerController::createFocusNodeInput():subjectEmailInputFocusNode: ${subjectEmailInputFocusNode?.hasFocus}');
|
log('ComposerController::createFocusNodeInput():subjectEmailInputFocusNode: ${subjectEmailInputFocusNode?.hasFocus}');
|
||||||
@@ -414,7 +426,7 @@ class ComposerController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onLoadCompletedMobileEditorAction(HtmlEditorApi editorApi, WebUri? url) {
|
void onLoadCompletedMobileEditorAction(HtmlEditorApi editorApi, WebUri? url) {
|
||||||
if (identitySelected == null) {
|
if (identitySelected.value == null) {
|
||||||
_getAllIdentities();
|
_getAllIdentities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -552,10 +564,13 @@ class ComposerController extends BaseController {
|
|||||||
void _handleGetAllIdentitiesSuccess(GetAllIdentitiesSuccess success) async {
|
void _handleGetAllIdentitiesSuccess(GetAllIdentitiesSuccess success) async {
|
||||||
final listIdentitiesMayDeleted = success.identities?.toListMayDeleted() ?? [];
|
final listIdentitiesMayDeleted = success.identities?.toListMayDeleted() ?? [];
|
||||||
if (listIdentitiesMayDeleted.isNotEmpty) {
|
if (listIdentitiesMayDeleted.isNotEmpty) {
|
||||||
|
listFromIdentities.value = listIdentitiesMayDeleted;
|
||||||
await _selectIdentity(listIdentitiesMayDeleted.first);
|
await _selectIdentity(listIdentitiesMayDeleted.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
_autoFocusFieldWhenLauncher();
|
if (fromRecipientState.value == PrefixRecipientState.disabled) {
|
||||||
|
_autoFocusFieldWhenLauncher();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initEmailAddress({
|
void _initEmailAddress({
|
||||||
@@ -663,17 +678,17 @@ class ComposerController extends BaseController {
|
|||||||
}
|
}
|
||||||
) async {
|
) async {
|
||||||
Set<EmailAddress> listFromEmailAddress = {EmailAddress(null, userProfile.email)};
|
Set<EmailAddress> listFromEmailAddress = {EmailAddress(null, userProfile.email)};
|
||||||
if (identitySelected?.email?.isNotEmpty == true) {
|
if (identitySelected.value?.email?.isNotEmpty == true) {
|
||||||
listFromEmailAddress = {
|
listFromEmailAddress = {
|
||||||
EmailAddress(
|
EmailAddress(
|
||||||
identitySelected?.name,
|
identitySelected.value?.name,
|
||||||
identitySelected?.email
|
identitySelected.value?.email
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Set<EmailAddress> listReplyToEmailAddress = {EmailAddress(null, userProfile.email)};
|
Set<EmailAddress> listReplyToEmailAddress = {EmailAddress(null, userProfile.email)};
|
||||||
if (identitySelected?.replyTo?.isNotEmpty == true) {
|
if (identitySelected.value?.replyTo?.isNotEmpty == true) {
|
||||||
listReplyToEmailAddress = identitySelected!.replyTo!;
|
listReplyToEmailAddress = identitySelected.value!.replyTo!;
|
||||||
}
|
}
|
||||||
|
|
||||||
final attachments = <EmailBodyPart>{};
|
final attachments = <EmailBodyPart>{};
|
||||||
@@ -931,7 +946,7 @@ class ComposerController extends BaseController {
|
|||||||
: EmailRequest(
|
: EmailRequest(
|
||||||
email: createdEmail,
|
email: createdEmail,
|
||||||
sentMailboxId: mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleSent],
|
sentMailboxId: mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleSent],
|
||||||
identityId: identitySelected?.id,
|
identityId: identitySelected.value?.id,
|
||||||
emailIdDestroyed: arguments.emailActionType == EmailActionType.editDraft
|
emailIdDestroyed: arguments.emailActionType == EmailActionType.editDraft
|
||||||
? arguments.presentationEmail?.id
|
? arguments.presentationEmail?.id
|
||||||
: null,
|
: null,
|
||||||
@@ -1502,6 +1517,9 @@ class ComposerController extends BaseController {
|
|||||||
|
|
||||||
void addEmailAddressType(PrefixEmailAddress prefixEmailAddress) {
|
void addEmailAddressType(PrefixEmailAddress prefixEmailAddress) {
|
||||||
switch(prefixEmailAddress) {
|
switch(prefixEmailAddress) {
|
||||||
|
case PrefixEmailAddress.from:
|
||||||
|
fromRecipientState.value = PrefixRecipientState.enabled;
|
||||||
|
break;
|
||||||
case PrefixEmailAddress.cc:
|
case PrefixEmailAddress.cc:
|
||||||
ccRecipientState.value = PrefixRecipientState.enabled;
|
ccRecipientState.value = PrefixRecipientState.enabled;
|
||||||
break;
|
break;
|
||||||
@@ -1672,8 +1690,8 @@ class ComposerController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _selectIdentity(Identity? newIdentity) async {
|
Future<void> _selectIdentity(Identity? newIdentity) async {
|
||||||
final formerIdentity = identitySelected;
|
final formerIdentity = identitySelected.value;
|
||||||
identitySelected = newIdentity;
|
identitySelected.value = newIdentity;
|
||||||
if (newIdentity != null) {
|
if (newIdentity != null) {
|
||||||
await _applyIdentityForAllFieldComposer(formerIdentity, newIdentity);
|
await _applyIdentityForAllFieldComposer(formerIdentity, newIdentity);
|
||||||
}
|
}
|
||||||
@@ -1927,7 +1945,7 @@ class ComposerController extends BaseController {
|
|||||||
richTextWebController.editorController.setFullScreen();
|
richTextWebController.editorController.setFullScreen();
|
||||||
onChangeTextEditorWeb(initContent);
|
onChangeTextEditorWeb(initContent);
|
||||||
richTextWebController.setEnableCodeView();
|
richTextWebController.setEnableCodeView();
|
||||||
if (identitySelected == null) {
|
if (identitySelected.value == null) {
|
||||||
_getAllIdentities();
|
_getAllIdentities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2135,4 +2153,36 @@ class ComposerController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+4
-4
@@ -4,13 +4,11 @@ import 'package:flutter/material.dart';
|
|||||||
class FromComposerMobileWidgetStyle {
|
class FromComposerMobileWidgetStyle {
|
||||||
static const double space = 8.0;
|
static const double space = 8.0;
|
||||||
static const double identityButtonHeight = 32.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 identityButtonInkWellPadding = EdgeInsets.symmetric(vertical: 8.0);
|
||||||
static const EdgeInsetsGeometry identityButtonPadding = EdgeInsets.only(
|
static const EdgeInsetsGeometry identityButtonPadding = EdgeInsets.only(
|
||||||
top: 4,
|
top: 4,
|
||||||
bottom: 4,
|
bottom: 4,
|
||||||
right: 4,
|
|
||||||
left: 8,
|
left: 8,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -34,11 +32,13 @@ class FromComposerMobileWidgetStyle {
|
|||||||
static const TextStyle buttonTitleTextStyle = TextStyle(
|
static const TextStyle buttonTitleTextStyle = TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: AppColor.colorCalendarEventUnread
|
color: AppColor.colorCalendarEventUnread,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
);
|
||||||
static const TextStyle buttonSubTitleTextStyle = TextStyle(
|
static const TextStyle buttonSubTitleTextStyle = TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: AppColor.colorLabelComposer
|
color: AppColor.colorLabelComposer,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -46,26 +46,24 @@ class FromComposerMobileWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: FromComposerMobileWidgetStyle.space),
|
const SizedBox(width: FromComposerMobileWidgetStyle.space),
|
||||||
Expanded(
|
Flexible(
|
||||||
child: Container(
|
child: Padding(
|
||||||
padding: FromComposerMobileWidgetStyle.identityButtonInkWellPadding,
|
padding: FromComposerMobileWidgetStyle.identityButtonInkWellPadding,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: FromComposerMobileWidgetStyle.identityButtonInkWellBorderRadius,
|
borderRadius: FromComposerMobileWidgetStyle.identityButtonInkWellBorderRadius,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: FromComposerMobileWidgetStyle.identityButtonHeight,
|
height: FromComposerMobileWidgetStyle.identityButtonHeight,
|
||||||
width: responsiveUtils.isLandscapeMobile(context)
|
|
||||||
? FromComposerMobileWidgetStyle.identityButtonWidthMobileLandscape
|
|
||||||
: 0,
|
|
||||||
padding: FromComposerMobileWidgetStyle.identityButtonPadding,
|
padding: FromComposerMobileWidgetStyle.identityButtonPadding,
|
||||||
decoration: FromComposerMobileWidgetStyle.identityButtonDecoration,
|
decoration: FromComposerMobileWidgetStyle.identityButtonDecoration,
|
||||||
child: Row(
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (selectedIdentity != null)
|
if (selectedIdentity != null)
|
||||||
Expanded(
|
Flexible(
|
||||||
child: RichText(
|
child: RichText(
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
softWrap: false,
|
||||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
children: [
|
children: [
|
||||||
@@ -82,11 +80,11 @@ class FromComposerMobileWidget extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
const SizedBox.shrink(),
|
const SizedBox.shrink(),
|
||||||
SvgPicture.asset(imagePaths.icDropDown)
|
SvgPicture.asset(imagePaths.icDropDown),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user