From e74e2013709f07e5182d079c6d7c37d1c0cc847a Mon Sep 17 00:00:00 2001 From: DatDang Date: Thu, 29 Aug 2024 14:07:00 +0700 Subject: [PATCH] Add sample Semantics identifiers --- .../confirmation_dialog_key_values.dart | 7 + .../constants/search_key_values.dart | 10 + .../dialog/confirmation_dialog_builder.dart | 127 +- .../quick_search/quick_search_input_form.dart | 102 +- .../login_basic_auth_key_values.dart | 6 + .../presentation/composer_view_web.dart | 1138 +++++++++-------- .../view/web/web_editor_view.dart | 183 +-- .../widgets/recipient_composer_widget.dart | 5 +- .../widgets/subject_composer_widget.dart | 3 +- .../web/bottom_bar_composer_widget.dart | 26 +- ...le_responsive_app_bar_composer_widget.dart | 22 +- .../login/presentation/base_login_view.dart | 11 +- .../login/presentation/login_view_web.dart | 12 +- .../mailbox_dashboard_view_web.dart | 48 +- 14 files changed, 907 insertions(+), 793 deletions(-) create mode 100644 core/lib/presentation/constants/confirmation_dialog_key_values.dart create mode 100644 core/lib/presentation/constants/search_key_values.dart create mode 100644 lib/features/base/key_values/login_basic_auth_key_values.dart diff --git a/core/lib/presentation/constants/confirmation_dialog_key_values.dart b/core/lib/presentation/constants/confirmation_dialog_key_values.dart new file mode 100644 index 0000000000..77ec4f5ed5 --- /dev/null +++ b/core/lib/presentation/constants/confirmation_dialog_key_values.dart @@ -0,0 +1,7 @@ +class ConfirmationDialogKeyValues { + static const String title = 'tmail_confirmation_dialog_title'; + static const String content = 'tmail_confirmation_dialog_content'; + static const String confirmButton = 'tmail_confirmation_dialog_confirm_button'; + static const String cancelButton = 'tmail_confirmation_dialog_cancel_button'; + static const String closeButton = 'tmail_confirmation_dialog_close_button'; +} \ No newline at end of file diff --git a/core/lib/presentation/constants/search_key_values.dart b/core/lib/presentation/constants/search_key_values.dart new file mode 100644 index 0000000000..bf0d03e965 --- /dev/null +++ b/core/lib/presentation/constants/search_key_values.dart @@ -0,0 +1,10 @@ +class SearchKeyValues { + static const String searchInputField = 'tmail_search_input_field'; + static const String searchUserResult = 'tmail_search_user_result'; + static const String searchEmailResult = 'tmail_search_email_result'; +} + +// When search input field is focused +// And search input field is not empty +// Then user result should be shown with maximum 2 results +// And email result should be shown with maximum 5 results \ No newline at end of file diff --git a/core/lib/presentation/views/dialog/confirmation_dialog_builder.dart b/core/lib/presentation/views/dialog/confirmation_dialog_builder.dart index 8cb4d41c75..d4d3de87bf 100644 --- a/core/lib/presentation/views/dialog/confirmation_dialog_builder.dart +++ b/core/lib/presentation/views/dialog/confirmation_dialog_builder.dart @@ -1,5 +1,6 @@ import 'package:core/core.dart'; +import 'package:core/presentation/constants/confirmation_dialog_key_values.dart'; import 'package:core/presentation/views/dialog/confirm_dialog_button.dart'; import 'package:flutter/material.dart'; @@ -184,13 +185,16 @@ class ConfirmDialogBuilder { if (_onCloseButtonAction != null) Align( alignment: AlignmentDirectional.centerEnd, - child: TMailButtonWidget.fromIcon( - icon: _imagePath.icCircleClose, - iconSize: 30, - padding: const EdgeInsets.all(3), - backgroundColor: Colors.transparent, - margin: const EdgeInsetsDirectional.only(top: 16, end: 16), - onTapActionCallback: _onCloseButtonAction + child: Semantics( + label: ConfirmationDialogKeyValues.closeButton, + child: TMailButtonWidget.fromIcon( + icon: _imagePath.icCircleClose, + iconSize: 30, + padding: const EdgeInsets.all(3), + backgroundColor: Colors.transparent, + margin: const EdgeInsetsDirectional.only(top: 16, end: 16), + onTapActionCallback: _onCloseButtonAction + ), ) ), if (_iconWidget != null) @@ -203,10 +207,13 @@ class ConfirmDialogBuilder { Padding( padding: _paddingTitle ?? const EdgeInsetsDirectional.only(top: 12, start: 24, end: 24), child: Center( - child: Text( - _title, - textAlign: TextAlign.center, - style: _styleTitle ?? const TextStyle(fontSize: 20.0, color: AppColor.colorActionDeleteConfirmDialog, fontWeight: FontWeight.w500) + child: Semantics( + identifier: ConfirmationDialogKeyValues.title, + child: Text( + _title, + textAlign: TextAlign.center, + style: _styleTitle ?? const TextStyle(fontSize: 20.0, color: AppColor.colorActionDeleteConfirmDialog, fontWeight: FontWeight.w500) + ), ) ) ), @@ -214,9 +221,12 @@ class ConfirmDialogBuilder { Padding( padding: _paddingContent ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: Center( - child: Text(_content, - textAlign: TextAlign.center, - style: _styleContent ?? const TextStyle(fontSize: 17.0, color: AppColor.colorMessageDialog) + child: Semantics( + identifier: ConfirmationDialogKeyValues.content, + child: Text(_content, + textAlign: TextAlign.center, + style: _styleContent ?? const TextStyle(fontSize: 17.0, color: AppColor.colorMessageDialog) + ), ), ), ) @@ -224,11 +234,14 @@ class ConfirmDialogBuilder { Padding( padding: _paddingContent ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: Center( - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: _styleContent ?? const TextStyle(fontSize: 17.0, color: AppColor.colorMessageDialog), - children: listTextSpan + child: Semantics( + identifier: ConfirmationDialogKeyValues.content, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: _styleContent ?? const TextStyle(fontSize: 17.0, color: AppColor.colorMessageDialog), + children: listTextSpan + ), ), ), ), @@ -238,26 +251,32 @@ class ConfirmDialogBuilder { if (_cancelText.isNotEmpty) Padding( padding: const EdgeInsetsDirectional.only(top: 8, start: 16, end: 16), - child: ConfirmDialogButton( - label: _cancelText, - backgroundColor: _colorCancelButton, - borderRadius: _radiusButton, - textStyle: _styleTextCancelButton, - padding: _paddingButton, - maxLines: titleActionButtonMaxLines, - onTapAction: _onCancelButtonAction), + child: Semantics( + identifier: ConfirmationDialogKeyValues.cancelButton, + child: ConfirmDialogButton( + label: _cancelText, + backgroundColor: _colorCancelButton, + borderRadius: _radiusButton, + textStyle: _styleTextCancelButton, + padding: _paddingButton, + maxLines: titleActionButtonMaxLines, + onTapAction: _onCancelButtonAction), + ), ), if (_confirmText.isNotEmpty) Padding( padding: const EdgeInsetsDirectional.only(top: 8, start: 16, end: 16), - child: ConfirmDialogButton( - label: _confirmText, - backgroundColor: _colorConfirmButton, - borderRadius: _radiusButton, - textStyle: _styleTextConfirmButton, - padding: _paddingButton, - maxLines: titleActionButtonMaxLines, - onTapAction: _onConfirmButtonAction), + child: Semantics( + identifier: ConfirmationDialogKeyValues.confirmButton, + child: ConfirmDialogButton( + label: _confirmText, + backgroundColor: _colorConfirmButton, + borderRadius: _radiusButton, + textStyle: _styleTextConfirmButton, + padding: _paddingButton, + maxLines: titleActionButtonMaxLines, + onTapAction: _onConfirmButtonAction), + ), ), const SizedBox(height: 16), ] @@ -267,24 +286,30 @@ class ConfirmDialogBuilder { child: Row( children: [ if (_cancelText.isNotEmpty) - Expanded(child: ConfirmDialogButton( - label: _cancelText, - backgroundColor: _colorCancelButton, - borderRadius: _radiusButton, - textStyle: _styleTextCancelButton, - padding: _paddingButton, - maxLines: titleActionButtonMaxLines, - onTapAction: _onCancelButtonAction)), + Expanded(child: Semantics( + identifier: ConfirmationDialogKeyValues.cancelButton, + child: ConfirmDialogButton( + label: _cancelText, + backgroundColor: _colorCancelButton, + borderRadius: _radiusButton, + textStyle: _styleTextCancelButton, + padding: _paddingButton, + maxLines: titleActionButtonMaxLines, + onTapAction: _onCancelButtonAction), + )), if (_confirmText.isNotEmpty && _cancelText.isNotEmpty) const SizedBox(width: 8), if (_confirmText.isNotEmpty) - Expanded(child: ConfirmDialogButton( - label: _confirmText, - backgroundColor: _colorConfirmButton, - borderRadius: _radiusButton, - textStyle: _styleTextConfirmButton, - padding: _paddingButton, - maxLines: titleActionButtonMaxLines, - onTapAction: _onConfirmButtonAction,)) + Expanded(child: Semantics( + identifier: ConfirmationDialogKeyValues.confirmButton, + child: ConfirmDialogButton( + label: _confirmText, + backgroundColor: _colorConfirmButton, + borderRadius: _radiusButton, + textStyle: _styleTextConfirmButton, + padding: _paddingButton, + maxLines: titleActionButtonMaxLines, + onTapAction: _onConfirmButtonAction,), + )) ] )) ] diff --git a/core/lib/presentation/views/quick_search/quick_search_input_form.dart b/core/lib/presentation/views/quick_search/quick_search_input_form.dart index a5d5c2ec9d..43e99d932a 100644 --- a/core/lib/presentation/views/quick_search/quick_search_input_form.dart +++ b/core/lib/presentation/views/quick_search/quick_search_input_form.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:math'; +import 'package:core/presentation/constants/search_key_values.dart'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/direction_utils.dart'; @@ -850,47 +851,50 @@ class _TypeAheadFieldQuickSearchState extends State extends State<_SuggestionsList> Widget createSuggestionsWidget() { final listItemSuggestionWidget = _suggestions?.map((T suggestion) { if (widget.itemBuilder != null) { - return InkWell( - child: widget.itemBuilder!(context, suggestion), - onTap: () => widget.onSuggestionSelected?.call(suggestion), + return Semantics( + identifier: SearchKeyValues.searchEmailResult, + child: InkWell( + child: widget.itemBuilder!(context, suggestion), + onTap: () => widget.onSuggestionSelected?.call(suggestion), + ), ); } else { return const SizedBox.shrink(); @@ -1251,9 +1258,12 @@ class _SuggestionsListState extends State<_SuggestionsList> if (widget.contactSuggestionBuilder != null) { return Material( type: MaterialType.transparency, - child: InkWell( - child: widget.contactSuggestionBuilder!(context, contact), - onTap: () => widget.onContactSuggestionSelected?.call(contact), + child: Semantics( + identifier: SearchKeyValues.searchUserResult, + child: InkWell( + child: widget.contactSuggestionBuilder!(context, contact), + onTap: () => widget.onContactSuggestionSelected?.call(contact), + ), ), ); } else { diff --git a/lib/features/base/key_values/login_basic_auth_key_values.dart b/lib/features/base/key_values/login_basic_auth_key_values.dart new file mode 100644 index 0000000000..6be566b110 --- /dev/null +++ b/lib/features/base/key_values/login_basic_auth_key_values.dart @@ -0,0 +1,6 @@ +class LoginBasicAuthKeyValues { + static const String loginView = 'tmail_login_view'; + static const String loginEmailField = 'tmail_login_email_field'; + static const String loginPasswordField = 'tmail_login_password_field'; + static const String loginSubmitButton = 'tmail_login_submit_button'; +} \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 77bba5e670..d1df5c2194 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:model/email/prefix_email_address.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:tmail_ui_user/features/base/key_values/composer_key_values.dart'; import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart'; @@ -40,26 +41,261 @@ class ComposerView extends GetWidget { return GestureDetector( onTap: () => controller.clearFocus(context), excludeFromSemantics: true, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Obx(() => MobileResponsiveAppBarComposerWidget( - isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled, - isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled, - openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, - isSendButtonEnabled: controller.isEnableEmailSendButton.value, + child: Semantics( + identifier: ComposerKeyValues.composerView, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Obx(() => MobileResponsiveAppBarComposerWidget( + isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled, + isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled, + openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, + isSendButtonEnabled: controller.isEnableEmailSendButton.value, + onCloseViewAction: () => controller.handleClickCloseComposer(context), + attachFileAction: () => controller.openFilePickerByType(context, FileType.any), + insertImageAction: () => controller.insertImage(context, constraints.maxWidth), + sendMessageAction: () => controller.handleClickSendButton(context), + openContextMenuAction: (position) { + controller.openPopupMenuAction( + context, + position, + _createMoreOptionPopupItems(context), + radius: ComposerStyle.popupMenuRadius + ); + }, + )), + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: ComposerStyle.getMaxHeightEmailAddressWidget( + context, + constraints, + controller.responsiveUtils + ) + ), + child: SingleChildScrollView( + controller: controller.scrollControllerEmailAddress, + child: Obx(() => Column( + children: [ + if (controller.fromRecipientState.value == PrefixRecipientState.enabled) + Tooltip( + message: controller.identitySelected.value?.email ?? '', + child: FromComposerMobileWidget( + selectedIdentity: controller.identitySelected.value, + imagePaths: controller.imagePaths, + responsiveUtils: controller.responsiveUtils, + margin: ComposerStyle.mobileRecipientMargin, + padding: ComposerStyle.mobileRecipientPadding, + onTap: () => controller.openSelectIdentityBottomSheet(context) + ), + ), + RecipientComposerWidget( + prefix: PrefixEmailAddress.to, + listEmailAddress: controller.listToEmailAddress, + imagePaths: controller.imagePaths, + maxWidth: constraints.maxWidth, + fromState: controller.fromRecipientState.value, + ccState: controller.ccRecipientState.value, + bccState: controller.bccRecipientState.value, + expandMode: controller.toAddressExpandMode.value, + controller: controller.toEmailAddressController, + focusNode: controller.toAddressFocusNode, + focusNodeKeyboard: controller.toAddressFocusNodeKeyboard, + keyTagEditor: controller.keyToEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + padding: ComposerStyle.mobileRecipientPadding, + margin: ComposerStyle.mobileRecipientMargin, + nextFocusNode: controller.getNextFocusOfToEmailAddress(), + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onAddEmailAddressTypeAction: controller.addEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, + ), + if (controller.ccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.cc, + listEmailAddress: controller.listCcEmailAddress, + imagePaths: controller.imagePaths, + maxWidth: constraints.maxWidth, + expandMode: controller.ccAddressExpandMode.value, + controller: controller.ccEmailAddressController, + focusNode: controller.ccAddressFocusNode, + focusNodeKeyboard: controller.ccAddressFocusNodeKeyboard, + keyTagEditor: controller.keyCcEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.getNextFocusOfCcEmailAddress(), + padding: ComposerStyle.mobileRecipientPadding, + margin: ComposerStyle.mobileRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, + ), + if (controller.bccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.bcc, + listEmailAddress: controller.listBccEmailAddress, + imagePaths: controller.imagePaths, + maxWidth: constraints.maxWidth, + expandMode: controller.bccAddressExpandMode.value, + controller: controller.bccEmailAddressController, + focusNode: controller.bccAddressFocusNode, + focusNodeKeyboard: controller.bccAddressFocusNodeKeyboard, + keyTagEditor: controller.keyBccEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.subjectEmailInputFocusNode, + padding: ComposerStyle.mobileRecipientPadding, + margin: ComposerStyle.mobileRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, + ), + ], + )), + ) + ), + SubjectComposerWidget( + focusNode: controller.subjectEmailInputFocusNode, + textController: controller.subjectEmailInputController, + onTextChange: controller.setSubjectEmail, + padding: ComposerStyle.mobileSubjectPadding, + margin: ComposerStyle.mobileSubjectMargin, + ), + Expanded( + child: LayoutBuilder( + builder: (context, constraintsEditor) { + return Stack( + children: [ + Column( + children: [ + Expanded( + child: Padding( + padding: ComposerStyle.mobileEditorPadding, + child: Obx(() => WebEditorView( + editorController: controller.richTextWebController!.editorController, + arguments: controller.composerArguments.value, + contentViewState: controller.emailContentsViewState.value, + currentWebContent: controller.textEditorWeb, + onInitial: controller.handleInitHtmlEditorWeb, + onChangeContent: controller.onChangeTextEditorWeb, + onFocus: controller.handleOnFocusHtmlEditorWeb, + onUnFocus: controller.handleOnUnFocusEditorWeb, + onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, + onEditorSettings: controller.richTextWebController!.onEditorSettingsChange, + onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged, + width: constraints.maxWidth, + height: constraints.maxHeight, + onDragEnter: controller.handleOnDragEnterHtmlEditorWeb, + )), + ), + ), + Obx(() { + if (controller.uploadController.listUploadAttachments.isNotEmpty) { + return AttachmentComposerWidget( + listFileUploaded: controller.uploadController.listUploadAttachments, + isCollapsed: controller.isAttachmentCollapsed, + onDeleteAttachmentAction: controller.deleteAttachmentUploaded, + onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed, + ); + } else { + return const SizedBox.shrink(); + } + }), + Obx(() { + if (controller.richTextWebController!.isFormattingOptionsEnabled) { + return ToolbarRichTextWebBuilder( + richTextWebController: controller.richTextWebController!, + padding: ComposerStyle.richToolbarPadding, + decoration: const BoxDecoration( + color: ComposerStyle.richToolbarColor, + boxShadow: ComposerStyle.richToolbarShadow + ), + ); + } else { + return const SizedBox.shrink(); + } + }) + ], + ), + Align( + alignment: AlignmentDirectional.topCenter, + child: Obx(() => InsertImageLoadingBarWidget( + uploadInlineViewState: controller.uploadController.uploadInlineViewState.value, + viewState: controller.viewState.value, + padding: ComposerStyle.insertImageLoadingBarPadding, + )), + ), + Obx(() { + if (controller.mailboxDashBoardController.isAttachmentDraggableAppActive) { + return Positioned.fill( + child: PointerInterceptor( + child: AttachmentDropZoneWidget( + imagePaths: controller.imagePaths, + width: constraintsEditor.maxWidth, + height: constraintsEditor.maxHeight, + onAttachmentDropZoneListener: controller.onAttachmentDropZoneListener, + ) + ), + ); + } else { + return const SizedBox.shrink(); + } + }), + Obx(() { + if (controller.mailboxDashBoardController.isLocalFileDraggableAppActive) { + return Positioned.fill( + child: PointerInterceptor( + child: LocalFileDropZoneWidget( + imagePaths: controller.imagePaths, + width: constraintsEditor.maxWidth, + height: constraintsEditor.maxHeight, + onLocalFileDropZoneListener: (details) => + controller.onLocalFileDropZoneListener( + context: context, + details: details, + maxWidth: constraintsEditor.maxWidth, + ), + ) + ), + ); + } else { + return const SizedBox.shrink(); + } + }), + ], + ); + } + ), + ), + ] + ), + ), + ); + } + ), + desktop: Obx(() => DesktopResponsiveContainerView( + childBuilder: (context, constraints) { + return GestureDetector( + onTap: () => controller.clearFocus(context), + excludeFromSemantics: true, + child: Semantics( + identifier: ComposerKeyValues.composerView, + child: Column(children: [ + Obx(() => DesktopAppBarComposerWidget( + emailSubject: controller.subjectEmail.value ?? '', + displayMode: controller.screenDisplayMode.value, onCloseViewAction: () => controller.handleClickCloseComposer(context), - attachFileAction: () => controller.openFilePickerByType(context, FileType.any), - insertImageAction: () => controller.insertImage(context, constraints.maxWidth), - sendMessageAction: () => controller.handleClickSendButton(context), - openContextMenuAction: (position) { - controller.openPopupMenuAction( - context, - position, - _createMoreOptionPopupItems(context), - radius: ComposerStyle.popupMenuRadius - ); - }, + onChangeDisplayModeAction: controller.displayScreenTypeComposerAction, + constraints: constraints, )), ConstrainedBox( constraints: BoxConstraints( @@ -74,16 +310,14 @@ class ComposerView extends GetWidget { child: Obx(() => Column( children: [ if (controller.fromRecipientState.value == PrefixRecipientState.enabled) - Tooltip( - message: controller.identitySelected.value?.email ?? '', - child: FromComposerMobileWidget( - selectedIdentity: controller.identitySelected.value, - imagePaths: controller.imagePaths, - responsiveUtils: controller.responsiveUtils, - margin: ComposerStyle.mobileRecipientMargin, - padding: ComposerStyle.mobileRecipientPadding, - onTap: () => controller.openSelectIdentityBottomSheet(context) - ), + FromComposerDropDownWidget( + items: controller.listFromIdentities, + itemSelected: controller.identitySelected.value, + dropdownKey: controller.identityDropdownKey, + imagePaths: controller.imagePaths, + padding: ComposerStyle.desktopRecipientPadding, + margin: ComposerStyle.desktopRecipientMargin, + onChangeIdentity: controller.onChangeIdentity, ), RecipientComposerWidget( prefix: PrefixEmailAddress.to, @@ -99,8 +333,8 @@ class ComposerView extends GetWidget { focusNodeKeyboard: controller.toAddressFocusNodeKeyboard, keyTagEditor: controller.keyToEmailTagEditor, isInitial: controller.isInitialRecipient.value, - padding: ComposerStyle.mobileRecipientPadding, - margin: ComposerStyle.mobileRecipientMargin, + padding: ComposerStyle.desktopRecipientPadding, + margin: ComposerStyle.desktopRecipientMargin, nextFocusNode: controller.getNextFocusOfToEmailAddress(), onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, onShowFullListEmailAddressAction: controller.showFullEmailAddress, @@ -123,8 +357,8 @@ class ComposerView extends GetWidget { keyTagEditor: controller.keyCcEmailTagEditor, isInitial: controller.isInitialRecipient.value, nextFocusNode: controller.getNextFocusOfCcEmailAddress(), - padding: ComposerStyle.mobileRecipientPadding, - margin: ComposerStyle.mobileRecipientMargin, + padding: ComposerStyle.desktopRecipientPadding, + margin: ComposerStyle.desktopRecipientMargin, onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, onShowFullListEmailAddressAction: controller.showFullEmailAddress, onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, @@ -146,8 +380,8 @@ class ComposerView extends GetWidget { keyTagEditor: controller.keyBccEmailTagEditor, isInitial: controller.isInitialRecipient.value, nextFocusNode: controller.subjectEmailInputFocusNode, - padding: ComposerStyle.mobileRecipientPadding, - margin: ComposerStyle.mobileRecipientMargin, + padding: ComposerStyle.desktopRecipientPadding, + margin: ComposerStyle.desktopRecipientMargin, onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, onShowFullListEmailAddressAction: controller.showFullEmailAddress, onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, @@ -164,8 +398,8 @@ class ComposerView extends GetWidget { focusNode: controller.subjectEmailInputFocusNode, textController: controller.subjectEmailInputController, onTextChange: controller.setSubjectEmail, - padding: ComposerStyle.mobileSubjectPadding, - margin: ComposerStyle.mobileSubjectMargin, + padding: ComposerStyle.desktopSubjectPadding, + margin: ComposerStyle.desktopSubjectMargin, ), Expanded( child: LayoutBuilder( @@ -175,52 +409,84 @@ class ComposerView extends GetWidget { Column( children: [ Expanded( - child: Padding( - padding: ComposerStyle.mobileEditorPadding, - child: Obx(() => WebEditorView( - editorController: controller.richTextWebController!.editorController, - arguments: controller.composerArguments.value, - contentViewState: controller.emailContentsViewState.value, - currentWebContent: controller.textEditorWeb, - onInitial: controller.handleInitHtmlEditorWeb, - onChangeContent: controller.onChangeTextEditorWeb, - onFocus: controller.handleOnFocusHtmlEditorWeb, - onUnFocus: controller.handleOnUnFocusEditorWeb, - onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, - onEditorSettings: controller.richTextWebController!.onEditorSettingsChange, - onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged, - width: constraints.maxWidth, - height: constraints.maxHeight, - onDragEnter: controller.handleOnDragEnterHtmlEditorWeb, - )), + child: Container( + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: ComposerStyle.borderColor, + width: 1 + ) + ), + color: ComposerStyle.backgroundEditorColor + ), + child: Column( + children: [ + Expanded( + child: Padding( + padding: ComposerStyle.desktopEditorPadding, + child: Obx(() { + return WebEditorView( + editorController: controller.richTextWebController!.editorController, + arguments: controller.composerArguments.value, + contentViewState: controller.emailContentsViewState.value, + currentWebContent: controller.textEditorWeb, + onInitial: controller.handleInitHtmlEditorWeb, + onChangeContent: controller.onChangeTextEditorWeb, + onFocus: controller.handleOnFocusHtmlEditorWeb, + onUnFocus: controller.handleOnUnFocusEditorWeb, + onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, + onEditorSettings: controller.richTextWebController?.onEditorSettingsChange, + onEditorTextSizeChanged: controller.richTextWebController?.onEditorTextSizeChanged, + width: constraints.maxWidth, + height: constraints.maxHeight, + onDragEnter: controller.handleOnDragEnterHtmlEditorWeb, + ); + }), + ), + ), + Obx(() { + if (controller.uploadController.listUploadAttachments.isNotEmpty) { + return AttachmentComposerWidget( + listFileUploaded: controller.uploadController.listUploadAttachments, + isCollapsed: controller.isAttachmentCollapsed, + onDeleteAttachmentAction: controller.deleteAttachmentUploaded, + onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed, + ); + } else { + return const SizedBox.shrink(); + } + }), + Obx(() { + if (controller.richTextWebController!.isFormattingOptionsEnabled) { + return ToolbarRichTextWebBuilder( + richTextWebController: controller.richTextWebController!, + padding: ComposerStyle.richToolbarPadding, + decoration: const BoxDecoration( + color: ComposerStyle.richToolbarColor, + boxShadow: ComposerStyle.richToolbarShadow + ), + ); + } else { + return const SizedBox.shrink(); + } + }) + ], + ), ), ), - Obx(() { - if (controller.uploadController.listUploadAttachments.isNotEmpty) { - return AttachmentComposerWidget( - listFileUploaded: controller.uploadController.listUploadAttachments, - isCollapsed: controller.isAttachmentCollapsed, - onDeleteAttachmentAction: controller.deleteAttachmentUploaded, - onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed, - ); - } else { - return const SizedBox.shrink(); - } - }), - Obx(() { - if (controller.richTextWebController!.isFormattingOptionsEnabled) { - return ToolbarRichTextWebBuilder( - richTextWebController: controller.richTextWebController!, - padding: ComposerStyle.richToolbarPadding, - decoration: const BoxDecoration( - color: ComposerStyle.richToolbarColor, - boxShadow: ComposerStyle.richToolbarShadow - ), - ); - } else { - return const SizedBox.shrink(); - } - }) + Obx(() => BottomBarComposerWidget( + isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled, + isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled, + hasReadReceipt: controller.hasRequestReadReceipt.value, + openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, + attachFileAction: () => controller.openFilePickerByType(context, FileType.any), + insertImageAction: () => controller.insertImage(context, constraints.maxWidth), + showCodeViewAction: controller.richTextWebController!.toggleCodeView, + deleteComposerAction: () => controller.handleClickDeleteComposer(context), + saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context), + sendMessageAction: () => controller.handleClickSendButton(context), + requestReadReceiptAction: () => controller.toggleRequestReadReceipt(context), + )), ], ), Align( @@ -273,153 +539,156 @@ class ComposerView extends GetWidget { } ), ), - ] + ]), ), ); - } - ), - desktop: Obx(() => DesktopResponsiveContainerView( + }, + displayMode: controller.screenDisplayMode.value, + emailSubject: controller.subjectEmail.value ?? '', + onCloseViewAction: () => controller.handleClickCloseComposer(context), + onChangeDisplayModeAction: controller.displayScreenTypeComposerAction, + )), + tablet: TabletResponsiveContainerView( childBuilder: (context, constraints) { return GestureDetector( onTap: () => controller.clearFocus(context), excludeFromSemantics: true, - child: Column(children: [ - Obx(() => DesktopAppBarComposerWidget( - emailSubject: controller.subjectEmail.value ?? '', - displayMode: controller.screenDisplayMode.value, - onCloseViewAction: () => controller.handleClickCloseComposer(context), - onChangeDisplayModeAction: controller.displayScreenTypeComposerAction, - constraints: constraints, - )), - ConstrainedBox( - constraints: BoxConstraints( - maxHeight: ComposerStyle.getMaxHeightEmailAddressWidget( - context, - constraints, - controller.responsiveUtils - ) - ), - child: SingleChildScrollView( - controller: controller.scrollControllerEmailAddress, - child: Obx(() => Column( - children: [ - if (controller.fromRecipientState.value == PrefixRecipientState.enabled) - FromComposerDropDownWidget( - items: controller.listFromIdentities, - itemSelected: controller.identitySelected.value, - dropdownKey: controller.identityDropdownKey, - imagePaths: controller.imagePaths, - padding: ComposerStyle.desktopRecipientPadding, - margin: ComposerStyle.desktopRecipientMargin, - onChangeIdentity: controller.onChangeIdentity, - ), - RecipientComposerWidget( - prefix: PrefixEmailAddress.to, - listEmailAddress: controller.listToEmailAddress, - imagePaths: controller.imagePaths, - maxWidth: constraints.maxWidth, - fromState: controller.fromRecipientState.value, - ccState: controller.ccRecipientState.value, - bccState: controller.bccRecipientState.value, - expandMode: controller.toAddressExpandMode.value, - controller: controller.toEmailAddressController, - focusNode: controller.toAddressFocusNode, - focusNodeKeyboard: controller.toAddressFocusNodeKeyboard, - keyTagEditor: controller.keyToEmailTagEditor, - isInitial: controller.isInitialRecipient.value, - padding: ComposerStyle.desktopRecipientPadding, - margin: ComposerStyle.desktopRecipientMargin, - nextFocusNode: controller.getNextFocusOfToEmailAddress(), - onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, - onShowFullListEmailAddressAction: controller.showFullEmailAddress, - onAddEmailAddressTypeAction: controller.addEmailAddressType, - onUpdateListEmailAddressAction: controller.updateListEmailAddress, - onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, - onFocusNextAddressAction: controller.handleFocusNextAddressAction, - onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, - ), - if (controller.ccRecipientState.value == PrefixRecipientState.enabled) - RecipientComposerWidget( - prefix: PrefixEmailAddress.cc, - listEmailAddress: controller.listCcEmailAddress, - imagePaths: controller.imagePaths, - maxWidth: constraints.maxWidth, - expandMode: controller.ccAddressExpandMode.value, - controller: controller.ccEmailAddressController, - focusNode: controller.ccAddressFocusNode, - focusNodeKeyboard: controller.ccAddressFocusNodeKeyboard, - keyTagEditor: controller.keyCcEmailTagEditor, - isInitial: controller.isInitialRecipient.value, - nextFocusNode: controller.getNextFocusOfCcEmailAddress(), - padding: ComposerStyle.desktopRecipientPadding, - margin: ComposerStyle.desktopRecipientMargin, - onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, - onShowFullListEmailAddressAction: controller.showFullEmailAddress, - onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, - onUpdateListEmailAddressAction: controller.updateListEmailAddress, - onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, - onFocusNextAddressAction: controller.handleFocusNextAddressAction, - onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, - ), - if (controller.bccRecipientState.value == PrefixRecipientState.enabled) + child: Semantics( + identifier: ComposerKeyValues.composerView, + child: Column(children: [ + Obx(() => DesktopAppBarComposerWidget( + emailSubject: controller.subjectEmail.value ?? '', + onCloseViewAction: () => controller.handleClickCloseComposer(context), + constraints: constraints, + )), + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: ComposerStyle.getMaxHeightEmailAddressWidget( + context, + constraints, + controller.responsiveUtils + ) + ), + child: SingleChildScrollView( + controller: controller.scrollControllerEmailAddress, + child: Obx(() => Column( + children: [ + if (controller.fromRecipientState.value == PrefixRecipientState.enabled) + FromComposerDropDownWidget( + items: controller.listFromIdentities, + itemSelected: controller.identitySelected.value, + dropdownKey: controller.identityDropdownKey, + imagePaths: controller.imagePaths, + padding: ComposerStyle.tabletRecipientPadding, + margin: ComposerStyle.tabletRecipientMargin, + onChangeIdentity: controller.onChangeIdentity, + ), RecipientComposerWidget( - prefix: PrefixEmailAddress.bcc, - listEmailAddress: controller.listBccEmailAddress, + prefix: PrefixEmailAddress.to, + listEmailAddress: controller.listToEmailAddress, imagePaths: controller.imagePaths, maxWidth: constraints.maxWidth, - expandMode: controller.bccAddressExpandMode.value, - controller: controller.bccEmailAddressController, - focusNode: controller.bccAddressFocusNode, - focusNodeKeyboard: controller.bccAddressFocusNodeKeyboard, - keyTagEditor: controller.keyBccEmailTagEditor, + fromState: controller.fromRecipientState.value, + ccState: controller.ccRecipientState.value, + bccState: controller.bccRecipientState.value, + expandMode: controller.toAddressExpandMode.value, + controller: controller.toEmailAddressController, + focusNode: controller.toAddressFocusNode, + focusNodeKeyboard: controller.toAddressFocusNodeKeyboard, + keyTagEditor: controller.keyToEmailTagEditor, isInitial: controller.isInitialRecipient.value, - nextFocusNode: controller.subjectEmailInputFocusNode, - padding: ComposerStyle.desktopRecipientPadding, - margin: ComposerStyle.desktopRecipientMargin, + padding: ComposerStyle.tabletRecipientPadding, + margin: ComposerStyle.tabletRecipientMargin, + nextFocusNode: controller.getNextFocusOfToEmailAddress(), onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, onShowFullListEmailAddressAction: controller.showFullEmailAddress, - onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onAddEmailAddressTypeAction: controller.addEmailAddressType, onUpdateListEmailAddressAction: controller.updateListEmailAddress, onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, onFocusNextAddressAction: controller.handleFocusNextAddressAction, onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, ), - ], - )), - ) - ), - SubjectComposerWidget( - focusNode: controller.subjectEmailInputFocusNode, - textController: controller.subjectEmailInputController, - onTextChange: controller.setSubjectEmail, - padding: ComposerStyle.desktopSubjectPadding, - margin: ComposerStyle.desktopSubjectMargin, - ), - Expanded( - child: LayoutBuilder( - builder: (context, constraintsEditor) { - return Stack( - children: [ - Column( - children: [ - Expanded( - child: Container( - decoration: const BoxDecoration( - border: Border( - bottom: BorderSide( - color: ComposerStyle.borderColor, - width: 1 - ) + if (controller.ccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.cc, + listEmailAddress: controller.listCcEmailAddress, + imagePaths: controller.imagePaths, + maxWidth: constraints.maxWidth, + expandMode: controller.ccAddressExpandMode.value, + controller: controller.ccEmailAddressController, + focusNode: controller.ccAddressFocusNode, + focusNodeKeyboard: controller.ccAddressFocusNodeKeyboard, + keyTagEditor: controller.keyCcEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.getNextFocusOfCcEmailAddress(), + padding: ComposerStyle.tabletRecipientPadding, + margin: ComposerStyle.tabletRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, + ), + if (controller.bccRecipientState.value == PrefixRecipientState.enabled) + RecipientComposerWidget( + prefix: PrefixEmailAddress.bcc, + listEmailAddress: controller.listBccEmailAddress, + imagePaths: controller.imagePaths, + maxWidth: constraints.maxWidth, + expandMode: controller.bccAddressExpandMode.value, + controller: controller.bccEmailAddressController, + focusNode: controller.bccAddressFocusNode, + focusNodeKeyboard: controller.bccAddressFocusNodeKeyboard, + keyTagEditor: controller.keyBccEmailTagEditor, + isInitial: controller.isInitialRecipient.value, + nextFocusNode: controller.subjectEmailInputFocusNode, + padding: ComposerStyle.tabletRecipientPadding, + margin: ComposerStyle.tabletRecipientMargin, + onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, + onShowFullListEmailAddressAction: controller.showFullEmailAddress, + onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, + onUpdateListEmailAddressAction: controller.updateListEmailAddress, + onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, + onFocusNextAddressAction: controller.handleFocusNextAddressAction, + onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, + ), + ], + )), + ) + ), + SubjectComposerWidget( + focusNode: controller.subjectEmailInputFocusNode, + textController: controller.subjectEmailInputController, + onTextChange: controller.setSubjectEmail, + padding: ComposerStyle.tabletSubjectPadding, + margin: ComposerStyle.tabletSubjectMargin, + ), + Expanded( + child: LayoutBuilder( + builder: (context, constraintsBody) { + return Stack( + children: [ + Column( + children: [ + Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: ComposerStyle.borderColor, + width: 1 + ) + ), + color: ComposerStyle.backgroundEditorColor ), - color: ComposerStyle.backgroundEditorColor - ), - child: Column( - children: [ - Expanded( - child: Padding( - padding: ComposerStyle.desktopEditorPadding, - child: Obx(() { - return WebEditorView( + child: Column( + children: [ + Expanded( + child: Padding( + padding: ComposerStyle.tabletEditorPadding, + child: Obx(() => WebEditorView( editorController: controller.richTextWebController!.editorController, arguments: controller.composerArguments.value, contentViewState: controller.emailContentsViewState.value, @@ -429,370 +698,111 @@ class ComposerView extends GetWidget { onFocus: controller.handleOnFocusHtmlEditorWeb, onUnFocus: controller.handleOnUnFocusEditorWeb, onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, - onEditorSettings: controller.richTextWebController?.onEditorSettingsChange, - onEditorTextSizeChanged: controller.richTextWebController?.onEditorTextSizeChanged, + onEditorSettings: controller.richTextWebController!.onEditorSettingsChange, + onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged, width: constraints.maxWidth, height: constraints.maxHeight, onDragEnter: controller.handleOnDragEnterHtmlEditorWeb, - ); - }), + )), + ), ), - ), - Obx(() { - if (controller.uploadController.listUploadAttachments.isNotEmpty) { - return AttachmentComposerWidget( - listFileUploaded: controller.uploadController.listUploadAttachments, - isCollapsed: controller.isAttachmentCollapsed, - onDeleteAttachmentAction: controller.deleteAttachmentUploaded, - onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed, - ); - } else { - return const SizedBox.shrink(); - } - }), - Obx(() { - if (controller.richTextWebController!.isFormattingOptionsEnabled) { - return ToolbarRichTextWebBuilder( - richTextWebController: controller.richTextWebController!, - padding: ComposerStyle.richToolbarPadding, - decoration: const BoxDecoration( - color: ComposerStyle.richToolbarColor, - boxShadow: ComposerStyle.richToolbarShadow - ), - ); - } else { - return const SizedBox.shrink(); - } - }) - ], + Obx(() { + if (controller.uploadController.listUploadAttachments.isNotEmpty) { + return AttachmentComposerWidget( + listFileUploaded: controller.uploadController.listUploadAttachments, + isCollapsed: controller.isAttachmentCollapsed, + onDeleteAttachmentAction: controller.deleteAttachmentUploaded, + onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed, + ); + } else { + return const SizedBox.shrink(); + } + }), + Obx(() { + if (controller.richTextWebController!.isFormattingOptionsEnabled) { + return ToolbarRichTextWebBuilder( + richTextWebController: controller.richTextWebController!, + padding: ComposerStyle.richToolbarPadding, + decoration: const BoxDecoration( + color: ComposerStyle.richToolbarColor, + boxShadow: ComposerStyle.richToolbarShadow + ), + ); + } else { + return const SizedBox.shrink(); + } + }) + ], + ), ), ), - ), - Obx(() => BottomBarComposerWidget( - isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled, - isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled, - hasReadReceipt: controller.hasRequestReadReceipt.value, - openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, - attachFileAction: () => controller.openFilePickerByType(context, FileType.any), - insertImageAction: () => controller.insertImage(context, constraints.maxWidth), - showCodeViewAction: controller.richTextWebController!.toggleCodeView, - deleteComposerAction: () => controller.handleClickDeleteComposer(context), - saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context), - sendMessageAction: () => controller.handleClickSendButton(context), - requestReadReceiptAction: () => controller.toggleRequestReadReceipt(context), + Obx(() => BottomBarComposerWidget( + isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled, + isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled, + hasReadReceipt: controller.hasRequestReadReceipt.value, + openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, + attachFileAction: () => controller.openFilePickerByType(context, FileType.any), + insertImageAction: () => controller.insertImage(context, constraints.maxWidth), + showCodeViewAction: controller.richTextWebController!.toggleCodeView, + deleteComposerAction: () => controller.handleClickDeleteComposer(context), + saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context), + sendMessageAction: () => controller.handleClickSendButton(context), + requestReadReceiptAction: () => controller.toggleRequestReadReceipt(context), + )), + ], + ), + Align( + alignment: AlignmentDirectional.topCenter, + child: Obx(() => InsertImageLoadingBarWidget( + uploadInlineViewState: controller.uploadController.uploadInlineViewState.value, + viewState: controller.viewState.value, + padding: ComposerStyle.insertImageLoadingBarPadding, )), - ], - ), - Align( - alignment: AlignmentDirectional.topCenter, - child: Obx(() => InsertImageLoadingBarWidget( - uploadInlineViewState: controller.uploadController.uploadInlineViewState.value, - viewState: controller.viewState.value, - padding: ComposerStyle.insertImageLoadingBarPadding, - )), - ), - Obx(() { - if (controller.mailboxDashBoardController.isAttachmentDraggableAppActive) { - return Positioned.fill( - child: PointerInterceptor( - child: AttachmentDropZoneWidget( - imagePaths: controller.imagePaths, - width: constraintsEditor.maxWidth, - height: constraintsEditor.maxHeight, - onAttachmentDropZoneListener: controller.onAttachmentDropZoneListener, - ) - ), - ); - } else { - return const SizedBox.shrink(); - } - }), - Obx(() { - if (controller.mailboxDashBoardController.isLocalFileDraggableAppActive) { - return Positioned.fill( - child: PointerInterceptor( - child: LocalFileDropZoneWidget( - imagePaths: controller.imagePaths, - width: constraintsEditor.maxWidth, - height: constraintsEditor.maxHeight, - onLocalFileDropZoneListener: (details) => - controller.onLocalFileDropZoneListener( - context: context, - details: details, - maxWidth: constraintsEditor.maxWidth, - ), - ) - ), - ); - } else { - return const SizedBox.shrink(); - } - }), - ], - ); - } - ), - ), - ]), - ); - }, - displayMode: controller.screenDisplayMode.value, - emailSubject: controller.subjectEmail.value ?? '', - onCloseViewAction: () => controller.handleClickCloseComposer(context), - onChangeDisplayModeAction: controller.displayScreenTypeComposerAction, - )), - tablet: TabletResponsiveContainerView( - childBuilder: (context, constraints) { - return GestureDetector( - onTap: () => controller.clearFocus(context), - excludeFromSemantics: true, - child: Column(children: [ - Obx(() => DesktopAppBarComposerWidget( - emailSubject: controller.subjectEmail.value ?? '', - onCloseViewAction: () => controller.handleClickCloseComposer(context), - constraints: constraints, - )), - ConstrainedBox( - constraints: BoxConstraints( - maxHeight: ComposerStyle.getMaxHeightEmailAddressWidget( - context, - constraints, - controller.responsiveUtils - ) - ), - child: SingleChildScrollView( - controller: controller.scrollControllerEmailAddress, - child: Obx(() => Column( - children: [ - if (controller.fromRecipientState.value == PrefixRecipientState.enabled) - FromComposerDropDownWidget( - items: controller.listFromIdentities, - itemSelected: controller.identitySelected.value, - dropdownKey: controller.identityDropdownKey, - imagePaths: controller.imagePaths, - padding: ComposerStyle.tabletRecipientPadding, - margin: ComposerStyle.tabletRecipientMargin, - onChangeIdentity: controller.onChangeIdentity, - ), - RecipientComposerWidget( - prefix: PrefixEmailAddress.to, - listEmailAddress: controller.listToEmailAddress, - imagePaths: controller.imagePaths, - maxWidth: constraints.maxWidth, - fromState: controller.fromRecipientState.value, - ccState: controller.ccRecipientState.value, - bccState: controller.bccRecipientState.value, - expandMode: controller.toAddressExpandMode.value, - controller: controller.toEmailAddressController, - focusNode: controller.toAddressFocusNode, - focusNodeKeyboard: controller.toAddressFocusNodeKeyboard, - keyTagEditor: controller.keyToEmailTagEditor, - isInitial: controller.isInitialRecipient.value, - padding: ComposerStyle.tabletRecipientPadding, - margin: ComposerStyle.tabletRecipientMargin, - nextFocusNode: controller.getNextFocusOfToEmailAddress(), - onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, - onShowFullListEmailAddressAction: controller.showFullEmailAddress, - onAddEmailAddressTypeAction: controller.addEmailAddressType, - onUpdateListEmailAddressAction: controller.updateListEmailAddress, - onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, - onFocusNextAddressAction: controller.handleFocusNextAddressAction, - onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, - ), - if (controller.ccRecipientState.value == PrefixRecipientState.enabled) - RecipientComposerWidget( - prefix: PrefixEmailAddress.cc, - listEmailAddress: controller.listCcEmailAddress, - imagePaths: controller.imagePaths, - maxWidth: constraints.maxWidth, - expandMode: controller.ccAddressExpandMode.value, - controller: controller.ccEmailAddressController, - focusNode: controller.ccAddressFocusNode, - focusNodeKeyboard: controller.ccAddressFocusNodeKeyboard, - keyTagEditor: controller.keyCcEmailTagEditor, - isInitial: controller.isInitialRecipient.value, - nextFocusNode: controller.getNextFocusOfCcEmailAddress(), - padding: ComposerStyle.tabletRecipientPadding, - margin: ComposerStyle.tabletRecipientMargin, - onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, - onShowFullListEmailAddressAction: controller.showFullEmailAddress, - onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, - onUpdateListEmailAddressAction: controller.updateListEmailAddress, - onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, - onFocusNextAddressAction: controller.handleFocusNextAddressAction, - onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, - ), - if (controller.bccRecipientState.value == PrefixRecipientState.enabled) - RecipientComposerWidget( - prefix: PrefixEmailAddress.bcc, - listEmailAddress: controller.listBccEmailAddress, - imagePaths: controller.imagePaths, - maxWidth: constraints.maxWidth, - expandMode: controller.bccAddressExpandMode.value, - controller: controller.bccEmailAddressController, - focusNode: controller.bccAddressFocusNode, - focusNodeKeyboard: controller.bccAddressFocusNodeKeyboard, - keyTagEditor: controller.keyBccEmailTagEditor, - isInitial: controller.isInitialRecipient.value, - nextFocusNode: controller.subjectEmailInputFocusNode, - padding: ComposerStyle.tabletRecipientPadding, - margin: ComposerStyle.tabletRecipientMargin, - onFocusEmailAddressChangeAction: controller.onEmailAddressFocusChange, - onShowFullListEmailAddressAction: controller.showFullEmailAddress, - onDeleteEmailAddressTypeAction: controller.deleteEmailAddressType, - onUpdateListEmailAddressAction: controller.updateListEmailAddress, - onSuggestionEmailAddress: controller.getAutoCompleteSuggestion, - onFocusNextAddressAction: controller.handleFocusNextAddressAction, - onRemoveDraggableEmailAddressAction: controller.removeDraggableEmailAddress, - ), - ], - )), - ) - ), - SubjectComposerWidget( - focusNode: controller.subjectEmailInputFocusNode, - textController: controller.subjectEmailInputController, - onTextChange: controller.setSubjectEmail, - padding: ComposerStyle.tabletSubjectPadding, - margin: ComposerStyle.tabletSubjectMargin, - ), - Expanded( - child: LayoutBuilder( - builder: (context, constraintsBody) { - return Stack( - children: [ - Column( - children: [ - Expanded( - child: Container( - decoration: const BoxDecoration( - border: Border( - bottom: BorderSide( - color: ComposerStyle.borderColor, - width: 1 - ) - ), - color: ComposerStyle.backgroundEditorColor + ), + Obx(() { + if (controller.mailboxDashBoardController.isAttachmentDraggableAppActive) { + return Positioned.fill( + child: PointerInterceptor( + child: AttachmentDropZoneWidget( + imagePaths: controller.imagePaths, + width: constraintsBody.maxWidth, + height: constraintsBody.maxHeight, + onAttachmentDropZoneListener: controller.onAttachmentDropZoneListener, + ) ), - child: Column( - children: [ - Expanded( - child: Padding( - padding: ComposerStyle.tabletEditorPadding, - child: Obx(() => WebEditorView( - editorController: controller.richTextWebController!.editorController, - arguments: controller.composerArguments.value, - contentViewState: controller.emailContentsViewState.value, - currentWebContent: controller.textEditorWeb, - onInitial: controller.handleInitHtmlEditorWeb, - onChangeContent: controller.onChangeTextEditorWeb, - onFocus: controller.handleOnFocusHtmlEditorWeb, - onUnFocus: controller.handleOnUnFocusEditorWeb, - onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, - onEditorSettings: controller.richTextWebController!.onEditorSettingsChange, - onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged, - width: constraints.maxWidth, - height: constraints.maxHeight, - onDragEnter: controller.handleOnDragEnterHtmlEditorWeb, - )), + ); + } else { + return const SizedBox.shrink(); + } + }), + Obx(() { + if (controller.mailboxDashBoardController.isLocalFileDraggableAppActive) { + return Positioned.fill( + child: PointerInterceptor( + child: LocalFileDropZoneWidget( + imagePaths: controller.imagePaths, + width: constraintsBody.maxWidth, + height: constraintsBody.maxHeight, + onLocalFileDropZoneListener: (details) => + controller.onLocalFileDropZoneListener( + context: context, + details: details, + maxWidth: constraintsBody.maxWidth, ), - ), - Obx(() { - if (controller.uploadController.listUploadAttachments.isNotEmpty) { - return AttachmentComposerWidget( - listFileUploaded: controller.uploadController.listUploadAttachments, - isCollapsed: controller.isAttachmentCollapsed, - onDeleteAttachmentAction: controller.deleteAttachmentUploaded, - onToggleExpandAttachmentAction: (isCollapsed) => controller.isAttachmentCollapsed = isCollapsed, - ); - } else { - return const SizedBox.shrink(); - } - }), - Obx(() { - if (controller.richTextWebController!.isFormattingOptionsEnabled) { - return ToolbarRichTextWebBuilder( - richTextWebController: controller.richTextWebController!, - padding: ComposerStyle.richToolbarPadding, - decoration: const BoxDecoration( - color: ComposerStyle.richToolbarColor, - boxShadow: ComposerStyle.richToolbarShadow - ), - ); - } else { - return const SizedBox.shrink(); - } - }) - ], + ) ), - ), - ), - Obx(() => BottomBarComposerWidget( - isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled, - isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled, - hasReadReceipt: controller.hasRequestReadReceipt.value, - openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions, - attachFileAction: () => controller.openFilePickerByType(context, FileType.any), - insertImageAction: () => controller.insertImage(context, constraints.maxWidth), - showCodeViewAction: controller.richTextWebController!.toggleCodeView, - deleteComposerAction: () => controller.handleClickDeleteComposer(context), - saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context), - sendMessageAction: () => controller.handleClickSendButton(context), - requestReadReceiptAction: () => controller.toggleRequestReadReceipt(context), - )), - ], - ), - Align( - alignment: AlignmentDirectional.topCenter, - child: Obx(() => InsertImageLoadingBarWidget( - uploadInlineViewState: controller.uploadController.uploadInlineViewState.value, - viewState: controller.viewState.value, - padding: ComposerStyle.insertImageLoadingBarPadding, - )), - ), - Obx(() { - if (controller.mailboxDashBoardController.isAttachmentDraggableAppActive) { - return Positioned.fill( - child: PointerInterceptor( - child: AttachmentDropZoneWidget( - imagePaths: controller.imagePaths, - width: constraintsBody.maxWidth, - height: constraintsBody.maxHeight, - onAttachmentDropZoneListener: controller.onAttachmentDropZoneListener, - ) - ), - ); - } else { - return const SizedBox.shrink(); - } - }), - Obx(() { - if (controller.mailboxDashBoardController.isLocalFileDraggableAppActive) { - return Positioned.fill( - child: PointerInterceptor( - child: LocalFileDropZoneWidget( - imagePaths: controller.imagePaths, - width: constraintsBody.maxWidth, - height: constraintsBody.maxHeight, - onLocalFileDropZoneListener: (details) => - controller.onLocalFileDropZoneListener( - context: context, - details: details, - maxWidth: constraintsBody.maxWidth, - ), - ) - ), - ); - } else { - return const SizedBox.shrink(); - } - }), - ], - ); - }, - ), - ) - ]), + ); + } else { + return const SizedBox.shrink(); + } + }), + ], + ); + }, + ), + ) + ]), + ), ); }, ) diff --git a/lib/features/composer/presentation/view/web/web_editor_view.dart b/lib/features/composer/presentation/view/web/web_editor_view.dart index 1e99380a33..933e4be7c6 100644 --- a/lib/features/composer/presentation/view/web/web_editor_view.dart +++ b/lib/features/composer/presentation/view/web/web_editor_view.dart @@ -7,6 +7,7 @@ import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; import 'package:html_editor_enhanced/html_editor.dart'; import 'package:model/email/email_action_type.dart'; +import 'package:tmail_ui_user/features/base/key_values/composer_key_values.dart'; import 'package:tmail_ui_user/features/composer/domain/state/restore_email_inline_images_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/view/editor_view_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/widgets/web/web_editor_widget.dart'; @@ -62,32 +63,9 @@ class WebEditorView extends StatelessWidget with EditorViewMixin { case EmailActionType.compose: case EmailActionType.composeFromEmailAddress: case EmailActionType.composeFromFileShared: - return WebEditorWidget( - editorController: editorController, - content: currentWebContent ?? HtmlExtension.editorStartTags, - direction: AppUtils.getCurrentDirection(context), - onInitial: onInitial, - onChangeContent: onChangeContent, - onFocus: onFocus, - onUnFocus: onUnFocus, - onMouseDown: onMouseDown, - onEditorSettings: onEditorSettings, - onEditorTextSizeChanged: onEditorTextSizeChanged, - width: width, - height: height, - onDragEnter: onDragEnter, - ); - case EmailActionType.editDraft: - case EmailActionType.editSendingEmail: - case EmailActionType.composeFromContentShared: - case EmailActionType.reopenComposerBrowser: - case EmailActionType.composeFromUnsubscribeMailtoLink: - case EmailActionType.composeFromMailtoUri: - if (contentViewState == null) { - return const SizedBox.shrink(); - } - return contentViewState!.fold( - (failure) => WebEditorWidget( + return Semantics( + identifier: ComposerKeyValues.composerContentField, + child: WebEditorWidget( editorController: editorController, content: currentWebContent ?? HtmlExtension.editorStartTags, direction: AppUtils.getCurrentDirection(context), @@ -102,6 +80,35 @@ class WebEditorView extends StatelessWidget with EditorViewMixin { height: height, onDragEnter: onDragEnter, ), + ); + case EmailActionType.editDraft: + case EmailActionType.editSendingEmail: + case EmailActionType.composeFromContentShared: + case EmailActionType.reopenComposerBrowser: + case EmailActionType.composeFromUnsubscribeMailtoLink: + case EmailActionType.composeFromMailtoUri: + if (contentViewState == null) { + return const SizedBox.shrink(); + } + return contentViewState!.fold( + (failure) => Semantics( + identifier: ComposerKeyValues.composerContentField, + child: WebEditorWidget( + editorController: editorController, + content: currentWebContent ?? HtmlExtension.editorStartTags, + direction: AppUtils.getCurrentDirection(context), + onInitial: onInitial, + onChangeContent: onChangeContent, + onFocus: onFocus, + onUnFocus: onUnFocus, + onMouseDown: onMouseDown, + onEditorSettings: onEditorSettings, + onEditorTextSizeChanged: onEditorTextSizeChanged, + width: width, + height: height, + onDragEnter: onDragEnter, + ), + ), (success) { if (success is GetEmailContentLoading || success is RestoringEmailInlineImages) { return const CupertinoLoadingWidget(padding: EdgeInsets.all(16.0)); @@ -112,20 +119,23 @@ class WebEditorView extends StatelessWidget with EditorViewMixin { if (newContent.isEmpty) { newContent = HtmlExtension.editorStartTags; } - return WebEditorWidget( - editorController: editorController, - content: currentWebContent ?? newContent, - direction: AppUtils.getCurrentDirection(context), - onInitial: onInitial, - onChangeContent: onChangeContent, - onFocus: onFocus, - onUnFocus: onUnFocus, - onMouseDown: onMouseDown, - onEditorSettings: onEditorSettings, - onEditorTextSizeChanged: onEditorTextSizeChanged, - width: width, - height: height, - onDragEnter: onDragEnter, + return Semantics( + identifier: ComposerKeyValues.composerContentField, + child: WebEditorWidget( + editorController: editorController, + content: currentWebContent ?? newContent, + direction: AppUtils.getCurrentDirection(context), + onInitial: onInitial, + onChangeContent: onChangeContent, + onFocus: onFocus, + onUnFocus: onUnFocus, + onMouseDown: onMouseDown, + onEditorSettings: onEditorSettings, + onEditorTextSizeChanged: onEditorTextSizeChanged, + width: width, + height: height, + onDragEnter: onDragEnter, + ), ); } } @@ -144,20 +154,23 @@ class WebEditorView extends StatelessWidget with EditorViewMixin { emailActionType: arguments!.emailActionType, presentationEmail: arguments!.presentationEmail! ); - return WebEditorWidget( - editorController: editorController, - content: currentWebContent ?? emailContentQuoted, - direction: AppUtils.getCurrentDirection(context), - onInitial: onInitial, - onChangeContent: onChangeContent, - onFocus: onFocus, - onUnFocus: onUnFocus, - onMouseDown: onMouseDown, - onEditorSettings: onEditorSettings, - onEditorTextSizeChanged: onEditorTextSizeChanged, - width: width, - height: height, - onDragEnter: onDragEnter, + return Semantics( + identifier: ComposerKeyValues.composerContentField, + child: WebEditorWidget( + editorController: editorController, + content: currentWebContent ?? emailContentQuoted, + direction: AppUtils.getCurrentDirection(context), + onInitial: onInitial, + onChangeContent: onChangeContent, + onFocus: onFocus, + onUnFocus: onUnFocus, + onMouseDown: onMouseDown, + onEditorSettings: onEditorSettings, + onEditorTextSizeChanged: onEditorTextSizeChanged, + width: width, + height: height, + onDragEnter: onDragEnter, + ), ); }, (success) { @@ -172,39 +185,45 @@ class WebEditorView extends StatelessWidget with EditorViewMixin { emailActionType: arguments!.emailActionType, presentationEmail: arguments!.presentationEmail! ); - return WebEditorWidget( - editorController: editorController, - content: currentWebContent ?? emailContentQuoted, - direction: AppUtils.getCurrentDirection(context), - onInitial: onInitial, - onChangeContent: onChangeContent, - onFocus: onFocus, - onUnFocus: onUnFocus, - onMouseDown: onMouseDown, - onEditorSettings: onEditorSettings, - onEditorTextSizeChanged: onEditorTextSizeChanged, - width: width, - height: height, - onDragEnter: onDragEnter, + return Semantics( + identifier: ComposerKeyValues.composerContentField, + child: WebEditorWidget( + editorController: editorController, + content: currentWebContent ?? emailContentQuoted, + direction: AppUtils.getCurrentDirection(context), + onInitial: onInitial, + onChangeContent: onChangeContent, + onFocus: onFocus, + onUnFocus: onUnFocus, + onMouseDown: onMouseDown, + onEditorSettings: onEditorSettings, + onEditorTextSizeChanged: onEditorTextSizeChanged, + width: width, + height: height, + onDragEnter: onDragEnter, + ), ); } } ); default: - return WebEditorWidget( - editorController: editorController, - content: currentWebContent ?? HtmlExtension.editorStartTags, - direction: AppUtils.getCurrentDirection(context), - onInitial: onInitial, - onChangeContent: onChangeContent, - onFocus: onFocus, - onUnFocus: onUnFocus, - onMouseDown: onMouseDown, - onEditorSettings: onEditorSettings, - onEditorTextSizeChanged: onEditorTextSizeChanged, - width: width, - height: height, - onDragEnter: onDragEnter, + return Semantics( + identifier: ComposerKeyValues.composerContentField, + child: WebEditorWidget( + editorController: editorController, + content: currentWebContent ?? HtmlExtension.editorStartTags, + direction: AppUtils.getCurrentDirection(context), + onInitial: onInitial, + onChangeContent: onChangeContent, + onFocus: onFocus, + onUnFocus: onUnFocus, + onMouseDown: onMouseDown, + onEditorSettings: onEditorSettings, + onEditorTextSizeChanged: onEditorTextSizeChanged, + width: width, + height: height, + onDragEnter: onDragEnter, + ), ); } } diff --git a/lib/features/composer/presentation/widgets/recipient_composer_widget.dart b/lib/features/composer/presentation/widgets/recipient_composer_widget.dart index 78001a39df..88772089ae 100644 --- a/lib/features/composer/presentation/widgets/recipient_composer_widget.dart +++ b/lib/features/composer/presentation/widgets/recipient_composer_widget.dart @@ -16,6 +16,7 @@ import 'package:model/email/prefix_email_address.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:model/mailbox/expand_mode.dart'; import 'package:super_tag_editor/tag_editor.dart'; +import 'package:tmail_ui_user/features/base/key_values/composer_key_values.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/prefix_recipient_state.dart'; @@ -123,7 +124,9 @@ class _RecipientComposerWidgetState extends State { @override Widget build(BuildContext context) { return Semantics( - value: 'Composer:${widget.prefix.name}', + identifier: widget.prefix == PrefixEmailAddress.to + ? ComposerKeyValues.composerToField + : null, child: Container( decoration: const BoxDecoration( border: Border( diff --git a/lib/features/composer/presentation/widgets/subject_composer_widget.dart b/lib/features/composer/presentation/widgets/subject_composer_widget.dart index b164453aff..9fa3420213 100644 --- a/lib/features/composer/presentation/widgets/subject_composer_widget.dart +++ b/lib/features/composer/presentation/widgets/subject_composer_widget.dart @@ -1,6 +1,7 @@ import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/base/key_values/composer_key_values.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/subject_composer_widget_style.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -24,7 +25,7 @@ class SubjectComposerWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Semantics( - label: 'Composer:subject', + identifier: ComposerKeyValues.composerSubjectField, child: Container( decoration: const BoxDecoration( border: Border( diff --git a/lib/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart b/lib/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart index 6687d43927..4d50951fd6 100644 --- a/lib/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart +++ b/lib/features/composer/presentation/widgets/web/bottom_bar_composer_widget.dart @@ -2,6 +2,7 @@ import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/key_values/composer_key_values.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/web/bottom_bar_composer_widget_style.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -131,17 +132,20 @@ class BottomBarComposerWidget extends StatelessWidget { onTapActionCallback: saveToDraftAction, ), const SizedBox(width: BottomBarComposerWidgetStyle.sendButtonSpace), - TMailButtonWidget( - text: AppLocalizations.of(context).send, - icon: _imagePaths.icSend, - iconAlignment: TextDirection.rtl, - padding: BottomBarComposerWidgetStyle.sendButtonPadding, - iconSize: BottomBarComposerWidgetStyle.iconSize, - iconSpace: BottomBarComposerWidgetStyle.sendButtonIconSpace, - textStyle: BottomBarComposerWidgetStyle.sendButtonTextStyle, - backgroundColor: BottomBarComposerWidgetStyle.sendButtonBackgroundColor, - borderRadius: BottomBarComposerWidgetStyle.sendButtonRadius, - onTapActionCallback: sendMessageAction, + Semantics( + identifier: ComposerKeyValues.composerSendButton, + child: TMailButtonWidget( + text: AppLocalizations.of(context).send, + icon: _imagePaths.icSend, + iconAlignment: TextDirection.rtl, + padding: BottomBarComposerWidgetStyle.sendButtonPadding, + iconSize: BottomBarComposerWidgetStyle.iconSize, + iconSpace: BottomBarComposerWidgetStyle.sendButtonIconSpace, + textStyle: BottomBarComposerWidgetStyle.sendButtonTextStyle, + backgroundColor: BottomBarComposerWidgetStyle.sendButtonBackgroundColor, + borderRadius: BottomBarComposerWidgetStyle.sendButtonRadius, + onTapActionCallback: sendMessageAction, + ), ) ] ), diff --git a/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart b/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart index 5c7b0790e3..f627e82565 100644 --- a/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart +++ b/lib/features/composer/presentation/widgets/web/mobile_responsive_app_bar_composer_widget.dart @@ -2,6 +2,7 @@ import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/key_values/composer_key_values.dart'; import 'package:tmail_ui_user/features/composer/presentation/styles/mobile_app_bar_composer_widget_style.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -84,15 +85,18 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget { onTapActionCallback: insertImageAction, ), const SizedBox(width: MobileAppBarComposerWidgetStyle.space), - TMailButtonWidget.fromIcon( - icon: isSendButtonEnabled - ? _imagePaths.icSendMobile - : _imagePaths.icSendDisable, - backgroundColor: Colors.transparent, - padding: MobileAppBarComposerWidgetStyle.iconPadding, - iconSize: MobileAppBarComposerWidgetStyle.sendButtonIconSize, - tooltipMessage: AppLocalizations.of(context).send, - onTapActionCallback: sendMessageAction, + Semantics( + identifier: ComposerKeyValues.composerSendButton, + child: TMailButtonWidget.fromIcon( + icon: isSendButtonEnabled + ? _imagePaths.icSendMobile + : _imagePaths.icSendDisable, + backgroundColor: Colors.transparent, + padding: MobileAppBarComposerWidgetStyle.iconPadding, + iconSize: MobileAppBarComposerWidgetStyle.sendButtonIconSize, + tooltipMessage: AppLocalizations.of(context).send, + onTapActionCallback: sendMessageAction, + ), ), const SizedBox(width: MobileAppBarComposerWidgetStyle.space), TMailButtonWidget.fromIcon( diff --git a/lib/features/login/presentation/base_login_view.dart b/lib/features/login/presentation/base_login_view.dart index 9c1b75591d..c56e172c09 100644 --- a/lib/features/login/presentation/base_login_view.dart +++ b/lib/features/login/presentation/base_login_view.dart @@ -2,6 +2,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/views/text/type_ahead_form_field_builder.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/key_values/login_basic_auth_key_values.dart'; import 'package:tmail_ui_user/features/base/widget/recent_item_tile_widget.dart'; import 'package:tmail_ui_user/features/login/domain/model/recent_login_username.dart'; import 'package:tmail_ui_user/features/login/presentation/login_controller.dart'; @@ -42,9 +43,15 @@ abstract class BaseLoginView extends GetWidget { padding: const EdgeInsetsDirectional.symmetric(horizontal: 24), child: Column( children: [ - buildUserNameInput(context), + Semantics( + identifier: LoginBasicAuthKeyValues.loginEmailField, + child: buildUserNameInput(context), + ), const SizedBox(height: 24), - buildPasswordInput(context), + Semantics( + identifier: LoginBasicAuthKeyValues.loginPasswordField, + child: buildPasswordInput(context), + ), const SizedBox(height: 40), ], ), diff --git a/lib/features/login/presentation/login_view_web.dart b/lib/features/login/presentation/login_view_web.dart index 5bd119f68c..f5e9b691ec 100644 --- a/lib/features/login/presentation/login_view_web.dart +++ b/lib/features/login/presentation/login_view_web.dart @@ -5,6 +5,7 @@ import 'package:core/presentation/views/text/slogan_builder.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart'; +import 'package:tmail_ui_user/features/base/key_values/login_basic_auth_key_values.dart'; import 'package:tmail_ui_user/features/base/widget/application_logo_with_text_widget.dart'; import 'package:tmail_ui_user/features/login/presentation/base_login_view.dart'; import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart'; @@ -21,10 +22,13 @@ class LoginView extends BaseLoginView { return Scaffold( backgroundColor: AppColor.primaryLightColor, body: Center(child: SingleChildScrollView( - child: ResponsiveWidget( - responsiveUtils: controller.responsiveUtils, - mobile: _buildMobileForm(context), - desktop: _buildWebForm(context), + child: Semantics( + identifier: LoginBasicAuthKeyValues.loginView, + child: ResponsiveWidget( + responsiveUtils: controller.responsiveUtils, + mobile: _buildMobileForm(context), + desktop: _buildWebForm(context), + ), ))), ); } diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart index 676ce71d48..971a0f435a 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/extensions/username_extension.dart'; +import 'package:tmail_ui_user/features/base/key_values/composer_key_values.dart'; import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; import 'package:tmail_ui_user/features/email/presentation/email_view.dart'; @@ -192,8 +193,8 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { }), ), Obx(() => controller.composerOverlayState.value == ComposerOverlayState.active - ? const ComposerView() - : const SizedBox.shrink() + ? const ComposerView() + : const SizedBox.shrink() ), Obx(() => controller.searchMailboxActivated.value == true && !controller.responsiveUtils.isWebDesktop(context) ? const SearchMailboxView() @@ -657,27 +658,30 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { ), width: ResponsiveUtils.defaultSizeMenu, alignment: Alignment.centerLeft, - child: TMailButtonWidget( - key: const Key('compose_email_button'), - text: AppLocalizations.of(context).compose, - icon: controller.imagePaths.icComposeWeb, - borderRadius: 10, - iconSize: 24, - iconColor: Colors.white, - padding: const EdgeInsetsDirectional.symmetric(vertical: 8), - backgroundColor: AppColor.colorTextButton, - boxShadow: const [ - BoxShadow( - blurRadius: 12.0, - color: AppColor.colorShadowComposerButton - ) - ], - textStyle: const TextStyle( - fontSize: 15, - color: Colors.white, - fontWeight: FontWeight.w500 + child: Semantics( + identifier: ComposerKeyValues.openComposerButton, + child: TMailButtonWidget( + key: const Key('compose_email_button'), + text: AppLocalizations.of(context).compose, + icon: controller.imagePaths.icComposeWeb, + borderRadius: 10, + iconSize: 24, + iconColor: Colors.white, + padding: const EdgeInsetsDirectional.symmetric(vertical: 8), + backgroundColor: AppColor.colorTextButton, + boxShadow: const [ + BoxShadow( + blurRadius: 12.0, + color: AppColor.colorShadowComposerButton + ) + ], + textStyle: const TextStyle( + fontSize: 15, + color: Colors.white, + fontWeight: FontWeight.w500 + ), + onTapActionCallback: () => controller.goToComposer(ComposerArguments()), ), - onTapActionCallback: () => controller.goToComposer(ComposerArguments()), ), ); }