TF-2475 Add onSubjectTextListener for subject focus node

This commit is contained in:
dab246
2024-07-01 14:59:30 +07:00
committed by Dat H. Pham
parent e3822734a6
commit fc4ca58d4e
9 changed files with 66 additions and 62 deletions
@@ -430,8 +430,10 @@ class ComposerController extends BaseController with DragDropFileMixin {
void _subjectEmailInputFocusListener() { void _subjectEmailInputFocusListener() {
if (subjectEmailInputFocusNode?.hasFocus == true) { if (subjectEmailInputFocusNode?.hasFocus == true) {
if (PlatformInfo.isMobile) { if (PlatformInfo.isMobile
htmlEditorApi?.unfocus(); && currentContext != null
&& !responsiveUtils.isScreenWithShortestSide(currentContext!)) {
richTextMobileTabletController?.richTextController.hideRichTextView();
} }
_collapseAllRecipient(); _collapseAllRecipient();
_autoCreateEmailTag(); _autoCreateEmailTag();
@@ -454,17 +456,13 @@ class ComposerController extends BaseController with DragDropFileMixin {
richTextMobileTabletController?.richTextController.onCreateHTMLEditor( richTextMobileTabletController?.richTextController.onCreateHTMLEditor(
editorApi, editorApi,
onEnterKeyDown: _onEnterKeyDown, onEnterKeyDown: _onEnterKeyDown,
onFocus: () => _onEditorFocusOnMobile(context), onFocus: _onEditorFocusOnMobile,
onChangeCursor: (coordinates) { onChangeCursor: (coordinates) {
_onChangeCursorOnMobile(coordinates, context); _onChangeCursorOnMobile(coordinates, context);
}, },
); );
} }
void onTapOutsideSubject(PointerDownEvent event) {
subjectEmailInputFocusNode?.unfocus();
}
void onLoadCompletedMobileEditorAction(HtmlEditorApi editorApi, WebUri? url) async { void onLoadCompletedMobileEditorAction(HtmlEditorApi editorApi, WebUri? url) async {
_isEmailBodyLoaded = true; _isEmailBodyLoaded = true;
if (identitySelected.value == null) { if (identitySelected.value == null) {
@@ -1379,13 +1377,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
} }
} }
void onEditorFocusChange(bool isFocus) {
if (isFocus) {
_collapseAllRecipient();
_autoCreateEmailTag();
}
}
void _collapseAllRecipient() { void _collapseAllRecipient() {
toAddressExpandMode.value = ExpandMode.COLLAPSE; toAddressExpandMode.value = ExpandMode.COLLAPSE;
ccAddressExpandMode.value = ExpandMode.COLLAPSE; ccAddressExpandMode.value = ExpandMode.COLLAPSE;
@@ -1505,7 +1496,9 @@ class ComposerController extends BaseController with DragDropFileMixin {
break; break;
} }
_closeSuggestionBox(); _closeSuggestionBox();
if (PlatformInfo.isMobile) { if (PlatformInfo.isMobile
&& currentContext != null
&& !responsiveUtils.isScreenWithShortestSide(currentContext!)) {
richTextMobileTabletController?.richTextController.hideRichTextView(); richTextMobileTabletController?.richTextController.hideRichTextView();
} }
} else { } else {
@@ -1645,9 +1638,11 @@ class ComposerController extends BaseController with DragDropFileMixin {
_closeComposerAction(); _closeComposerAction();
} }
Future<void> _onEditorFocusOnMobile(BuildContext context) async { Future<void> _onEditorFocusOnMobile() async {
if (PlatformInfo.isAndroid) { if (PlatformInfo.isAndroid) {
FocusScope.of(context).unfocus(); if (FocusManager.instance.primaryFocus?.hasFocus == true) {
FocusManager.instance.primaryFocus?.unfocus();
}
await Future.delayed( await Future.delayed(
const Duration(milliseconds: 300), const Duration(milliseconds: 300),
richTextMobileTabletController?.richTextController.showDeviceKeyboard); richTextMobileTabletController?.richTextController.showDeviceKeyboard);
@@ -1709,8 +1704,8 @@ class ComposerController extends BaseController with DragDropFileMixin {
hasRequestReadReceipt.toggle(); hasRequestReadReceipt.toggle();
} }
void _autoFocusFieldWhenLauncher() { Future<void> _autoFocusFieldWhenLauncher() async {
if (_hasInputFieldFocused) { if (await _hasInputFieldFocused()) {
log('ComposerController::_autoFocusFieldWhenLauncher: INPUT_FIELD_FOCUS = true'); log('ComposerController::_autoFocusFieldWhenLauncher: INPUT_FIELD_FOCUS = true');
return; return;
} }
@@ -1725,14 +1720,28 @@ class ComposerController extends BaseController with DragDropFileMixin {
subjectEmailInputFocusNode?.requestFocus(); subjectEmailInputFocusNode?.requestFocus();
} else if (PlatformInfo.isWeb) { } else if (PlatformInfo.isWeb) {
richTextWebController?.editorController.setFocus(); richTextWebController?.editorController.setFocus();
} else if (PlatformInfo.isIOS) {
await richTextMobileTabletController?.htmlEditorApi?.requestFocus();
} }
} }
bool get _hasInputFieldFocused => Future<bool> _hasInputFieldFocused() async {
toAddressFocusNode?.hasFocus == true || if (PlatformInfo.isWeb) {
ccAddressFocusNode?.hasFocus == true || return toAddressFocusNode?.hasFocus == true ||
bccAddressFocusNode?.hasFocus == true || ccAddressFocusNode?.hasFocus == true ||
subjectEmailInputFocusNode?.hasFocus == true; bccAddressFocusNode?.hasFocus == true ||
subjectEmailInputFocusNode?.hasFocus == true;
} else if (PlatformInfo.isMobile) {
final isEditorFocused = (await richTextMobileTabletController?.isEditorFocused) ?? false;
return toAddressFocusNode?.hasFocus == true ||
ccAddressFocusNode?.hasFocus == true ||
bccAddressFocusNode?.hasFocus == true ||
subjectEmailInputFocusNode?.hasFocus == true ||
isEditorFocused;
}
return false;
}
void handleInitHtmlEditorWeb(String initContent) async { void handleInitHtmlEditorWeb(String initContent) async {
log('ComposerController::handleInitHtmlEditorWeb:'); log('ComposerController::handleInitHtmlEditorWeb:');
@@ -1755,14 +1764,11 @@ class ComposerController extends BaseController with DragDropFileMixin {
richTextWebController?.closeAllMenuPopup(); richTextWebController?.closeAllMenuPopup();
} }
void handleOnUnFocusHtmlEditorWeb() {
onEditorFocusChange(false);
}
void handleOnMouseDownHtmlEditorWeb(BuildContext context) { void handleOnMouseDownHtmlEditorWeb(BuildContext context) {
Navigator.maybePop(context); Navigator.maybePop(context);
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
onEditorFocusChange(true); _collapseAllRecipient();
_autoCreateEmailTag();
} }
FocusNode? getNextFocusOfToEmailAddress() { FocusNode? getNextFocusOfToEmailAddress() {
@@ -201,7 +201,6 @@ class ComposerView extends GetWidget<ComposerController> {
onTextChange: controller.setSubjectEmail, onTextChange: controller.setSubjectEmail,
padding: ComposerStyle.mobileSubjectPadding, padding: ComposerStyle.mobileSubjectPadding,
margin: ComposerStyle.mobileSubjectMargin, margin: ComposerStyle.mobileSubjectMargin,
onTapOutside: controller.onTapOutsideSubject,
), ),
Obx(() { Obx(() {
if (controller.uploadController.listUploadAttachments.isNotEmpty) { if (controller.uploadController.listUploadAttachments.isNotEmpty) {
@@ -350,7 +349,6 @@ class ComposerView extends GetWidget<ComposerController> {
onTextChange: controller.setSubjectEmail, onTextChange: controller.setSubjectEmail,
padding: ComposerStyle.mobileSubjectPadding, padding: ComposerStyle.mobileSubjectPadding,
margin: ComposerStyle.mobileSubjectMargin, margin: ComposerStyle.mobileSubjectMargin,
onTapOutside: controller.onTapOutsideSubject,
), ),
Obx(() { Obx(() {
if (controller.uploadController.listUploadAttachments.isNotEmpty) { if (controller.uploadController.listUploadAttachments.isNotEmpty) {
@@ -184,7 +184,6 @@ class ComposerView extends GetWidget<ComposerController> {
onInitial: controller.handleInitHtmlEditorWeb, onInitial: controller.handleInitHtmlEditorWeb,
onChangeContent: controller.onChangeTextEditorWeb, onChangeContent: controller.onChangeTextEditorWeb,
onFocus: controller.handleOnFocusHtmlEditorWeb, onFocus: controller.handleOnFocusHtmlEditorWeb,
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
onEditorSettings: controller.richTextWebController!.onEditorSettingsChange, onEditorSettings: controller.richTextWebController!.onEditorSettingsChange,
onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged, onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged,
@@ -425,7 +424,6 @@ class ComposerView extends GetWidget<ComposerController> {
onInitial: controller.handleInitHtmlEditorWeb, onInitial: controller.handleInitHtmlEditorWeb,
onChangeContent: controller.onChangeTextEditorWeb, onChangeContent: controller.onChangeTextEditorWeb,
onFocus: controller.handleOnFocusHtmlEditorWeb, onFocus: controller.handleOnFocusHtmlEditorWeb,
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
onEditorSettings: controller.richTextWebController?.onEditorSettingsChange, onEditorSettings: controller.richTextWebController?.onEditorSettingsChange,
onEditorTextSizeChanged: controller.richTextWebController?.onEditorTextSizeChanged, onEditorTextSizeChanged: controller.richTextWebController?.onEditorTextSizeChanged,
@@ -687,7 +685,6 @@ class ComposerView extends GetWidget<ComposerController> {
onInitial: controller.handleInitHtmlEditorWeb, onInitial: controller.handleInitHtmlEditorWeb,
onChangeContent: controller.onChangeTextEditorWeb, onChangeContent: controller.onChangeTextEditorWeb,
onFocus: controller.handleOnFocusHtmlEditorWeb, onFocus: controller.handleOnFocusHtmlEditorWeb,
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb,
onMouseDown: controller.handleOnMouseDownHtmlEditorWeb, onMouseDown: controller.handleOnMouseDownHtmlEditorWeb,
onEditorSettings: controller.richTextWebController!.onEditorSettingsChange, onEditorSettings: controller.richTextWebController!.onEditorSettingsChange,
onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged, onEditorTextSizeChanged: controller.richTextWebController!.onEditorTextSizeChanged,
@@ -1,8 +1,8 @@
import 'dart:io'; import 'dart:io';
import 'package:core/presentation/utils/keyboard_utils.dart';
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:core/utils/html/html_utils.dart'; import 'package:core/utils/html/html_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:rich_text_composer/rich_text_composer.dart'; import 'package:rich_text_composer/rich_text_composer.dart';
@@ -16,10 +16,12 @@ class RichTextMobileTabletController extends BaseRichTextController {
final RichTextController richTextController = RichTextController(); final RichTextController richTextController = RichTextController();
Future<bool> get isEditorFocused async => await htmlEditorApi?.hasFocus() ?? false;
void insertImage(InlineImage inlineImage) async { void insertImage(InlineImage inlineImage) async {
bool isEditorFocused = await htmlEditorApi?.hasFocus() ?? false; final isFocused = await isEditorFocused;
log('RichTextMobileTabletController::insertImage: isEditorFocused = $isEditorFocused'); log('RichTextMobileTabletController::insertImage: isEditorFocused = $isFocused');
if (!isEditorFocused) { if (!isFocused) {
await htmlEditorApi?.requestFocusLastChild(); await htmlEditorApi?.requestFocusLastChild();
} }
if (inlineImage.base64Uri?.isNotEmpty == true) { if (inlineImage.base64Uri?.isNotEmpty == true) {
@@ -53,10 +55,9 @@ class RichTextMobileTabletController extends BaseRichTextController {
required BuildContext context, required BuildContext context,
required RichTextController? richTextController required RichTextController? richTextController
}) async { }) async {
if (Platform.isAndroid) { if (PlatformInfo.isAndroid) {
await htmlEditorApi?.storeSelectionRange(); await htmlEditorApi?.hideKeyboard();
KeyboardUtils.hideSystemKeyboardMobile(); } else if (PlatformInfo.isIOS) {
} else {
await htmlEditorApi?.unfocus(); await htmlEditorApi?.unfocus();
} }
@@ -11,7 +11,6 @@ class SubjectComposerWidget extends StatelessWidget {
final ValueChanged<String>? onTextChange; final ValueChanged<String>? onTextChange;
final EdgeInsetsGeometry? margin; final EdgeInsetsGeometry? margin;
final EdgeInsetsGeometry? padding; final EdgeInsetsGeometry? padding;
final TapRegionCallback? onTapOutside;
const SubjectComposerWidget({ const SubjectComposerWidget({
super.key, super.key,
@@ -20,7 +19,6 @@ class SubjectComposerWidget extends StatelessWidget {
required this.onTextChange, required this.onTextChange,
this.margin, this.margin,
this.padding, this.padding,
this.onTapOutside,
}); });
@override @override
@@ -52,7 +50,6 @@ class SubjectComposerWidget extends StatelessWidget {
textDirection: DirectionUtils.getDirectionByLanguage(context), textDirection: DirectionUtils.getDirectionByLanguage(context),
textStyle: SubjectComposerWidgetStyle.inputTextStyle, textStyle: SubjectComposerWidgetStyle.inputTextStyle,
controller: textController, controller: textController,
onTapOutside: onTapOutside,
) )
) )
] ]
@@ -236,7 +236,9 @@ class SettingsView extends GetWidget<SettingsController> {
} }
case AccountMenuItem.alwaysReadReceipt: case AccountMenuItem.alwaysReadReceipt:
if (controller.manageAccountDashboardController.isServerSettingsCapabilitySupported) { if (controller.manageAccountDashboardController.isServerSettingsCapabilitySupported) {
return const AlwaysReadReceiptView(); return const SafeArea(
top: false,
child: AlwaysReadReceiptView());
} else { } else {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
@@ -259,7 +261,9 @@ class SettingsView extends GetWidget<SettingsController> {
top: false, top: false,
child: MailboxVisibilityView()); child: MailboxVisibilityView());
case AccountMenuItem.notification: case AccountMenuItem.notification:
return const NotificationView(); return const SafeArea(
top: false,
child: NotificationView());
default: default:
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
@@ -95,13 +95,13 @@ class VacationController extends BaseController {
} }
void _initFocusListener() { void _initFocusListener() {
subjectTextFocusNode.addListener(() { subjectTextFocusNode.addListener(_onSubjectTextListener);
if (subjectTextFocusNode.hasFocus == true) { }
if (PlatformInfo.isMobile) {
richTextControllerForMobile.hideRichTextView(); void _onSubjectTextListener() {
} if (subjectTextFocusNode.hasFocus && PlatformInfo.isMobile) {
} richTextControllerForMobile.hideRichTextView();
}); }
} }
void _getAllVacation() { void _getAllVacation() {
@@ -410,6 +410,7 @@ class VacationController extends BaseController {
@override @override
void onClose() { void onClose() {
subjectTextFocusNode.removeListener(_onSubjectTextListener);
subjectTextFocusNode.dispose(); subjectTextFocusNode.dispose();
subjectTextController.dispose(); subjectTextController.dispose();
richTextControllerForMobile.dispose(); richTextControllerForMobile.dispose();
+6 -6
View File
@@ -436,8 +436,8 @@ packages:
dependency: transitive dependency: transitive
description: description:
path: "." path: "."
ref: cherry-pick-fix-rich-text-format-style ref: cnb_supported
resolved-ref: "7041e5822707ab57fcf36964c38556e2d27b06e2" resolved-ref: "8301d67b4c30bb2234bbe96de4ae135b88a6af40"
url: "https://github.com/linagora/enough_html_editor.git" url: "https://github.com/linagora/enough_html_editor.git"
source: git source: git
version: "0.0.5" version: "0.0.5"
@@ -1106,8 +1106,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: cherry-pick-fix-rich-text-format-style ref: cnb_supported
resolved-ref: "2ce34bf07bc0239a6b2502d9ddf0acd8cd2f28e3" resolved-ref: ddcfb76517161f63d63470526fe54bf74deac955
url: "https://github.com/linagora/html-editor-enhanced.git" url: "https://github.com/linagora/html-editor-enhanced.git"
source: git source: git
version: "2.5.1" version: "2.5.1"
@@ -1621,8 +1621,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: cherry-pick-fix-rich-text-format-style ref: cnb_supported
resolved-ref: "88dc2d55dabe254c0932410582ae049f4b0c7e54" resolved-ref: "955d70b3e57ddeed2b709ee8822c7a8a620e1aaa"
url: "https://github.com/linagora/rich-text-composer.git" url: "https://github.com/linagora/rich-text-composer.git"
source: git source: git
version: "0.0.2" version: "0.0.2"
+2 -2
View File
@@ -55,12 +55,12 @@ dependencies:
rich_text_composer: rich_text_composer:
git: git:
url: https://github.com/linagora/rich-text-composer.git url: https://github.com/linagora/rich-text-composer.git
ref: cherry-pick-fix-rich-text-format-style ref: cnb_supported
html_editor_enhanced: html_editor_enhanced:
git: git:
url: https://github.com/linagora/html-editor-enhanced.git url: https://github.com/linagora/html-editor-enhanced.git
ref: cherry-pick-fix-rich-text-format-style ref: cnb_supported
# TODO: We will change it when the PR in upstream repository will be merged # TODO: We will change it when the PR in upstream repository will be merged
# https://github.com/linagora/jmap-dart-client/pull/87 # https://github.com/linagora/jmap-dart-client/pull/87