Only create and use the correct rich text controller for each platform

This commit is contained in:
dab246
2024-04-23 23:26:17 +07:00
committed by Dat H. Pham
parent a2e6b78576
commit 36ab6b1ccc
8 changed files with 139 additions and 111 deletions
@@ -214,9 +214,12 @@ class ComposerBindings extends BaseBindings {
@override @override
void bindingsController() { void bindingsController() {
Get.lazyPut(() => RichTextMobileTabletController()); if (PlatformInfo.isWeb) {
Get.lazyPut(() => RichTextWebController());
} else {
Get.lazyPut(() => RichTextMobileTabletController());
}
Get.lazyPut(() => UploadController(Get.find<UploadAttachmentInteractor>())); Get.lazyPut(() => UploadController(Get.find<UploadAttachmentInteractor>()));
Get.lazyPut(() => RichTextWebController());
Get.lazyPut(() => ComposerController( Get.lazyPut(() => ComposerController(
Get.find<LocalFilePickerInteractor>(), Get.find<LocalFilePickerInteractor>(),
Get.find<LocalImagePickerInteractor>(), Get.find<LocalImagePickerInteractor>(),
@@ -225,7 +228,6 @@ class ComposerBindings extends BaseBindings {
Get.find<UploadController>(), Get.find<UploadController>(),
Get.find<RemoveComposerCacheOnWebInteractor>(), Get.find<RemoveComposerCacheOnWebInteractor>(),
Get.find<SaveComposerCacheOnWebInteractor>(), Get.find<SaveComposerCacheOnWebInteractor>(),
Get.find<RichTextWebController>(),
Get.find<DownloadImageAsBase64Interactor>(), Get.find<DownloadImageAsBase64Interactor>(),
Get.find<TransformHtmlEmailContentInteractor>(), Get.find<TransformHtmlEmailContentInteractor>(),
Get.find<GetAlwaysReadReceiptSettingInteractor>(), Get.find<GetAlwaysReadReceiptSettingInteractor>(),
@@ -235,9 +237,12 @@ class ComposerBindings extends BaseBindings {
} }
void dispose() { void dispose() {
if (PlatformInfo.isWeb) {
Get.delete<RichTextWebController>();
} else {
Get.delete<RichTextMobileTabletController>();
}
Get.delete<UploadController>(); Get.delete<UploadController>();
Get.delete<RichTextWebController>();
Get.delete<RichTextMobileTabletController>();
Get.delete<ComposerController>(); Get.delete<ComposerController>();
} }
} }
@@ -94,7 +94,6 @@ import 'package:universal_html/html.dart' as html;
class ComposerController extends BaseController with DragDropFileMixin { class ComposerController extends BaseController with DragDropFileMixin {
final mailboxDashBoardController = Get.find<MailboxDashBoardController>(); final mailboxDashBoardController = Get.find<MailboxDashBoardController>();
final richTextMobileTabletController = Get.find<RichTextMobileTabletController>();
final networkConnectionController = Get.find<NetworkConnectionController>(); final networkConnectionController = Get.find<NetworkConnectionController>();
final _dynamicUrlInterceptors = Get.find<DynamicUrlInterceptors>(); final _dynamicUrlInterceptors = Get.find<DynamicUrlInterceptors>();
@@ -121,7 +120,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
final UploadController uploadController; final UploadController uploadController;
final RemoveComposerCacheOnWebInteractor _removeComposerCacheOnWebInteractor; final RemoveComposerCacheOnWebInteractor _removeComposerCacheOnWebInteractor;
final SaveComposerCacheOnWebInteractor _saveComposerCacheOnWebInteractor; final SaveComposerCacheOnWebInteractor _saveComposerCacheOnWebInteractor;
final RichTextWebController richTextWebController;
final DownloadImageAsBase64Interactor _downloadImageAsBase64Interactor; final DownloadImageAsBase64Interactor _downloadImageAsBase64Interactor;
final TransformHtmlEmailContentInteractor _transformHtmlEmailContentInteractor; final TransformHtmlEmailContentInteractor _transformHtmlEmailContentInteractor;
final GetAlwaysReadReceiptSettingInteractor _getAlwaysReadReceiptSettingInteractor; final GetAlwaysReadReceiptSettingInteractor _getAlwaysReadReceiptSettingInteractor;
@@ -165,7 +163,8 @@ class ComposerController extends BaseController with DragDropFileMixin {
StreamSubscription<html.Event>? _subscriptionOnDragLeave; StreamSubscription<html.Event>? _subscriptionOnDragLeave;
StreamSubscription<html.Event>? _subscriptionOnDrop; StreamSubscription<html.Event>? _subscriptionOnDrop;
final RichTextController keyboardRichTextController = RichTextController(); RichTextMobileTabletController? richTextMobileTabletController;
RichTextWebController? richTextWebController;
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
final ScrollController scrollControllerEmailAddress = ScrollController(); final ScrollController scrollControllerEmailAddress = ScrollController();
@@ -194,7 +193,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
this.uploadController, this.uploadController,
this._removeComposerCacheOnWebInteractor, this._removeComposerCacheOnWebInteractor,
this._saveComposerCacheOnWebInteractor, this._saveComposerCacheOnWebInteractor,
this.richTextWebController,
this._downloadImageAsBase64Interactor, this._downloadImageAsBase64Interactor,
this._transformHtmlEmailContentInteractor, this._transformHtmlEmailContentInteractor,
this._getAlwaysReadReceiptSettingInteractor, this._getAlwaysReadReceiptSettingInteractor,
@@ -205,14 +203,17 @@ class ComposerController extends BaseController with DragDropFileMixin {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
createFocusNodeInput();
scrollControllerEmailAddress.addListener(_scrollControllerEmailAddressListener);
_listenStreamEvent();
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_listenBrowserTabRefresh(); _listenBrowserTabRefresh();
}); });
richTextWebController = getBinding<RichTextWebController>();
} else {
richTextMobileTabletController = getBinding<RichTextMobileTabletController>();
} }
createFocusNodeInput();
scrollControllerEmailAddress.addListener(_scrollControllerEmailAddressListener);
_listenStreamEvent();
_getAlwaysReadReceiptSetting(); _getAlwaysReadReceiptSetting();
} }
@@ -239,6 +240,7 @@ class ComposerController extends BaseController with DragDropFileMixin {
_subscriptionOnDragOver?.cancel(); _subscriptionOnDragOver?.cancel();
_subscriptionOnDragLeave?.cancel(); _subscriptionOnDragLeave?.cancel();
_subscriptionOnDrop?.cancel(); _subscriptionOnDrop?.cancel();
subjectEmailInputFocusNode?.removeListener(_subjectEmailInputFocusListener);
super.onClose(); super.onClose();
} }
@@ -266,7 +268,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
bccEmailAddressController.dispose(); bccEmailAddressController.dispose();
uploadInlineImageWorker.dispose(); uploadInlineImageWorker.dispose();
dashboardViewStateWorker.dispose(); dashboardViewStateWorker.dispose();
keyboardRichTextController.dispose();
scrollController.dispose(); scrollController.dispose();
scrollControllerEmailAddress.removeListener(_scrollControllerEmailAddressListener); scrollControllerEmailAddress.removeListener(_scrollControllerEmailAddressListener);
scrollControllerEmailAddress.dispose(); scrollControllerEmailAddress.dispose();
@@ -295,9 +296,9 @@ class ComposerController extends BaseController with DragDropFileMixin {
} else if (success is DownloadImageAsBase64Success) { } else if (success is DownloadImageAsBase64Success) {
final inlineImage = InlineImage(fileInfo: success.fileInfo, base64Uri: success.base64Uri); final inlineImage = InlineImage(fileInfo: success.fileInfo, base64Uri: success.base64Uri);
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
richTextWebController.insertImage(inlineImage); richTextWebController?.insertImage(inlineImage);
} else { } else {
richTextMobileTabletController.insertImage(inlineImage); richTextMobileTabletController?.insertImage(inlineImage);
} }
maxWithEditor = null; maxWithEditor = null;
} else if (success is GetAlwaysReadReceiptSettingSuccess) { } else if (success is GetAlwaysReadReceiptSettingSuccess) {
@@ -414,15 +415,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
void createFocusNodeInput() { void createFocusNodeInput() {
toAddressFocusNode = FocusNode(); toAddressFocusNode = FocusNode();
subjectEmailInputFocusNode = FocusNode(
onKey: (focus, event) {
if (event is RawKeyDownEvent && event.logicalKey == LogicalKeyboardKey.tab) {
richTextWebController.editorController.setFocus();
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
}
);
ccAddressFocusNode = FocusNode(); ccAddressFocusNode = FocusNode();
bccAddressFocusNode = FocusNode(); bccAddressFocusNode = FocusNode();
searchIdentitiesFocusNode = FocusNode(); searchIdentitiesFocusNode = FocusNode();
@@ -430,24 +422,36 @@ class ComposerController extends BaseController with DragDropFileMixin {
ccAddressFocusNodeKeyboard = FocusNode(); ccAddressFocusNodeKeyboard = FocusNode();
bccAddressFocusNodeKeyboard = FocusNode(); bccAddressFocusNodeKeyboard = FocusNode();
subjectEmailInputFocusNode?.addListener(() { subjectEmailInputFocusNode = FocusNode(
log('ComposerController::createFocusNodeInput():subjectEmailInputFocusNode: ${subjectEmailInputFocusNode?.hasFocus}'); onKey: PlatformInfo.isWeb ? _subjectEmailInputOnKeyListener : null
if (subjectEmailInputFocusNode?.hasFocus == true) { );
if (PlatformInfo.isMobile) { subjectEmailInputFocusNode?.addListener(_subjectEmailInputFocusListener);
htmlEditorApi?.unfocus(); }
}
_collapseAllRecipient(); void _subjectEmailInputFocusListener() {
_autoCreateEmailTag(); if (subjectEmailInputFocusNode?.hasFocus == true) {
if (PlatformInfo.isMobile) {
htmlEditorApi?.unfocus();
} }
}); _collapseAllRecipient();
_autoCreateEmailTag();
}
}
KeyEventResult _subjectEmailInputOnKeyListener(FocusNode node, RawKeyEvent event) {
if (event is RawKeyDownEvent && event.logicalKey == LogicalKeyboardKey.tab) {
richTextWebController?.editorController.setFocus();
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
} }
void onCreatedMobileEditorAction(BuildContext context, HtmlEditorApi editorApi, String? content) { void onCreatedMobileEditorAction(BuildContext context, HtmlEditorApi editorApi, String? content) {
if (identitySelected.value != null) { if (identitySelected.value != null) {
initTextEditor(content); initTextEditor(content);
} }
richTextMobileTabletController.htmlEditorApi = editorApi; richTextMobileTabletController?.htmlEditorApi = editorApi;
keyboardRichTextController.onCreateHTMLEditor( richTextMobileTabletController?.richTextController.onCreateHTMLEditor(
editorApi, editorApi,
onEnterKeyDown: _onEnterKeyDown, onEnterKeyDown: _onEnterKeyDown,
context: context, context: context,
@@ -1325,7 +1329,10 @@ class ComposerController extends BaseController with DragDropFileMixin {
} }
void displayScreenTypeComposerAction(ScreenDisplayMode displayMode) async { void displayScreenTypeComposerAction(ScreenDisplayMode displayMode) async {
_updateTextForEditor(); if (richTextWebController != null && screenDisplayMode.value != ScreenDisplayMode.minimize) {
final textCurrent = await richTextWebController!.editorController.getText();
richTextWebController!.editorController.setText(textCurrent);
}
screenDisplayMode.value = displayMode; screenDisplayMode.value = displayMode;
await Future.delayed( await Future.delayed(
@@ -1333,11 +1340,6 @@ class ComposerController extends BaseController with DragDropFileMixin {
_autoFocusFieldWhenLauncher); _autoFocusFieldWhenLauncher);
} }
void _updateTextForEditor() async {
final textCurrent = await richTextWebController.editorController.getText();
richTextWebController.editorController.setText(textCurrent);
}
void deleteComposer() { void deleteComposer() {
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
mailboxDashBoardController.closeComposerOverlay(); mailboxDashBoardController.closeComposerOverlay();
@@ -1589,7 +1591,7 @@ class ComposerController extends BaseController with DragDropFileMixin {
Future<void> _applySignature(String signature) async { Future<void> _applySignature(String signature) async {
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
richTextWebController.editorController.insertSignature(signature); richTextWebController?.editorController.insertSignature(signature);
} else { } else {
await htmlEditorApi?.insertSignature(signature, allowCollapsed: false); await htmlEditorApi?.insertSignature(signature, allowCollapsed: false);
} }
@@ -1598,7 +1600,7 @@ class ComposerController extends BaseController with DragDropFileMixin {
Future<void> _removeSignature() async { Future<void> _removeSignature() async {
log('ComposerController::_removeSignature():'); log('ComposerController::_removeSignature():');
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
richTextWebController.editorController.removeSignature(); richTextWebController?.editorController.removeSignature();
} else { } else {
await htmlEditorApi?.removeSignature(); await htmlEditorApi?.removeSignature();
} }
@@ -1712,7 +1714,7 @@ class ComposerController extends BaseController with DragDropFileMixin {
} else if (subjectEmailInputController.text.isEmpty) { } else if (subjectEmailInputController.text.isEmpty) {
subjectEmailInputFocusNode?.requestFocus(); subjectEmailInputFocusNode?.requestFocus();
} else if (PlatformInfo.isWeb) { } else if (PlatformInfo.isWeb) {
richTextWebController.editorController.setFocus(); richTextWebController?.editorController.setFocus();
} }
} }
@@ -1725,10 +1727,10 @@ class ComposerController extends BaseController with DragDropFileMixin {
void handleInitHtmlEditorWeb(String initContent) async { void handleInitHtmlEditorWeb(String initContent) async {
log('ComposerController::handleInitHtmlEditorWeb:'); log('ComposerController::handleInitHtmlEditorWeb:');
_isEmailBodyLoaded = true; _isEmailBodyLoaded = true;
richTextWebController.editorController.setFullScreen(); richTextWebController?.editorController.setFullScreen();
richTextWebController.editorController.setOnDragDropEvent(); richTextWebController?.editorController.setOnDragDropEvent();
onChangeTextEditorWeb(initContent); onChangeTextEditorWeb(initContent);
richTextWebController.setEnableCodeView(); richTextWebController?.setEnableCodeView();
if (identitySelected.value == null) { if (identitySelected.value == null) {
_getAllIdentities(); _getAllIdentities();
} else { } else {
@@ -1739,8 +1741,8 @@ class ComposerController extends BaseController with DragDropFileMixin {
void handleOnFocusHtmlEditorWeb() { void handleOnFocusHtmlEditorWeb() {
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
richTextWebController.editorController.setFocus(); richTextWebController?.editorController.setFocus();
richTextWebController.closeAllMenuPopup(); richTextWebController?.closeAllMenuPopup();
} }
void handleOnUnFocusHtmlEditorWeb() { void handleOnUnFocusHtmlEditorWeb() {
@@ -1779,7 +1781,7 @@ class ComposerController extends BaseController with DragDropFileMixin {
String? get textEditorWeb => _textEditorWeb; String? get textEditorWeb => _textEditorWeb;
HtmlEditorApi? get htmlEditorApi => richTextMobileTabletController.htmlEditorApi; HtmlEditorApi? get htmlEditorApi => richTextMobileTabletController?.htmlEditorApi;
void onChangeTextEditorWeb(String? text) { void onChangeTextEditorWeb(String? text) {
if (identitySelected.value != null) { if (identitySelected.value != null) {
@@ -36,7 +36,7 @@ class ComposerView extends GetWidget<ComposerController> {
return ResponsiveWidget( return ResponsiveWidget(
responsiveUtils: controller.responsiveUtils, responsiveUtils: controller.responsiveUtils,
mobile: MobileContainerView( mobile: MobileContainerView(
keyboardRichTextController: controller.keyboardRichTextController, keyboardRichTextController: controller.richTextMobileTabletController!.richTextController,
onCloseViewAction: () => controller.handleClickCloseComposer(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
onClearFocusAction: () => controller.clearFocus(context), onClearFocusAction: () => controller.clearFocus(context),
onAttachFileAction: () => controller.isNetworkConnectionAvailable onAttachFileAction: () => controller.isNetworkConnectionAvailable
@@ -228,7 +228,7 @@ class ComposerView extends GetWidget<ComposerController> {
), ),
), ),
tablet: TabletContainerView( tablet: TabletContainerView(
keyboardRichTextController: controller.keyboardRichTextController, keyboardRichTextController: controller.richTextMobileTabletController!.richTextController,
onCloseViewAction: () => controller.handleClickCloseComposer(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
onClearFocusAction: () => controller.clearFocus(context), onClearFocusAction: () => controller.clearFocus(context),
onAttachFileAction: () => controller.isNetworkConnectionAvailable onAttachFileAction: () => controller.isNetworkConnectionAvailable
@@ -43,9 +43,9 @@ class ComposerView extends GetWidget<ComposerController> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Obx(() => MobileResponsiveAppBarComposerWidget( Obx(() => MobileResponsiveAppBarComposerWidget(
isCodeViewEnabled: controller.richTextWebController.codeViewEnabled, isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled,
isFormattingOptionsEnabled: controller.richTextWebController.isFormattingOptionsEnabled, isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled,
openRichToolbarAction: controller.richTextWebController.toggleFormattingOptions, openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions,
isSendButtonEnabled: controller.isEnableEmailSendButton.value, isSendButtonEnabled: controller.isEnableEmailSendButton.value,
onCloseViewAction: () => controller.handleClickCloseComposer(context), onCloseViewAction: () => controller.handleClickCloseComposer(context),
attachFileAction: () => controller.openFilePickerByType(context, FileType.any), attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
@@ -177,7 +177,7 @@ class ComposerView extends GetWidget<ComposerController> {
child: Padding( child: Padding(
padding: ComposerStyle.mobileEditorPadding, padding: ComposerStyle.mobileEditorPadding,
child: Obx(() => WebEditorView( child: Obx(() => WebEditorView(
editorController: controller.richTextWebController.editorController, editorController: controller.richTextWebController!.editorController,
arguments: controller.composerArguments.value, arguments: controller.composerArguments.value,
contentViewState: controller.emailContentsViewState.value, contentViewState: controller.emailContentsViewState.value,
currentWebContent: controller.textEditorWeb, currentWebContent: controller.textEditorWeb,
@@ -186,8 +186,8 @@ class ComposerView extends GetWidget<ComposerController> {
onFocus: controller.handleOnFocusHtmlEditorWeb, onFocus: controller.handleOnFocusHtmlEditorWeb,
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb, 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,
width: constraints.maxWidth, width: constraints.maxWidth,
height: constraints.maxHeight, height: constraints.maxHeight,
onDragEnter: controller.handleOnDragEnterHtmlEditorWeb, onDragEnter: controller.handleOnDragEnterHtmlEditorWeb,
@@ -207,9 +207,9 @@ class ComposerView extends GetWidget<ComposerController> {
} }
}), }),
Obx(() { Obx(() {
if (controller.richTextWebController.isFormattingOptionsEnabled) { if (controller.richTextWebController!.isFormattingOptionsEnabled) {
return ToolbarRichTextWebBuilder( return ToolbarRichTextWebBuilder(
richTextWebController: controller.richTextWebController, richTextWebController: controller.richTextWebController!,
padding: ComposerStyle.richToolbarPadding, padding: ComposerStyle.richToolbarPadding,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: ComposerStyle.richToolbarColor, color: ComposerStyle.richToolbarColor,
@@ -418,7 +418,7 @@ class ComposerView extends GetWidget<ComposerController> {
padding: ComposerStyle.desktopEditorPadding, padding: ComposerStyle.desktopEditorPadding,
child: Obx(() { child: Obx(() {
return WebEditorView( return WebEditorView(
editorController: controller.richTextWebController.editorController, editorController: controller.richTextWebController!.editorController,
arguments: controller.composerArguments.value, arguments: controller.composerArguments.value,
contentViewState: controller.emailContentsViewState.value, contentViewState: controller.emailContentsViewState.value,
currentWebContent: controller.textEditorWeb, currentWebContent: controller.textEditorWeb,
@@ -427,8 +427,8 @@ class ComposerView extends GetWidget<ComposerController> {
onFocus: controller.handleOnFocusHtmlEditorWeb, onFocus: controller.handleOnFocusHtmlEditorWeb,
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb, 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,
width: constraints.maxWidth, width: constraints.maxWidth,
height: constraints.maxHeight, height: constraints.maxHeight,
onDragEnter: controller.handleOnDragEnterHtmlEditorWeb, onDragEnter: controller.handleOnDragEnterHtmlEditorWeb,
@@ -449,9 +449,9 @@ class ComposerView extends GetWidget<ComposerController> {
} }
}), }),
Obx(() { Obx(() {
if (controller.richTextWebController.isFormattingOptionsEnabled) { if (controller.richTextWebController!.isFormattingOptionsEnabled) {
return ToolbarRichTextWebBuilder( return ToolbarRichTextWebBuilder(
richTextWebController: controller.richTextWebController, richTextWebController: controller.richTextWebController!,
padding: ComposerStyle.richToolbarPadding, padding: ComposerStyle.richToolbarPadding,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: ComposerStyle.richToolbarColor, color: ComposerStyle.richToolbarColor,
@@ -467,12 +467,12 @@ class ComposerView extends GetWidget<ComposerController> {
), ),
), ),
Obx(() => BottomBarComposerWidget( Obx(() => BottomBarComposerWidget(
isCodeViewEnabled: controller.richTextWebController.codeViewEnabled, isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled,
isFormattingOptionsEnabled: controller.richTextWebController.isFormattingOptionsEnabled, isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled,
openRichToolbarAction: controller.richTextWebController.toggleFormattingOptions, openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions,
attachFileAction: () => controller.openFilePickerByType(context, FileType.any), attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
insertImageAction: () => controller.insertImage(context, constraints.maxWidth), insertImageAction: () => controller.insertImage(context, constraints.maxWidth),
showCodeViewAction: controller.richTextWebController.toggleCodeView, showCodeViewAction: controller.richTextWebController!.toggleCodeView,
deleteComposerAction: () => controller.handleClickDeleteComposer(context), deleteComposerAction: () => controller.handleClickDeleteComposer(context),
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context), saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
sendMessageAction: () => controller.handleClickSendButton(context), sendMessageAction: () => controller.handleClickSendButton(context),
@@ -680,7 +680,7 @@ class ComposerView extends GetWidget<ComposerController> {
child: Padding( child: Padding(
padding: ComposerStyle.tabletEditorPadding, padding: ComposerStyle.tabletEditorPadding,
child: Obx(() => WebEditorView( child: Obx(() => WebEditorView(
editorController: controller.richTextWebController.editorController, editorController: controller.richTextWebController!.editorController,
arguments: controller.composerArguments.value, arguments: controller.composerArguments.value,
contentViewState: controller.emailContentsViewState.value, contentViewState: controller.emailContentsViewState.value,
currentWebContent: controller.textEditorWeb, currentWebContent: controller.textEditorWeb,
@@ -689,8 +689,8 @@ class ComposerView extends GetWidget<ComposerController> {
onFocus: controller.handleOnFocusHtmlEditorWeb, onFocus: controller.handleOnFocusHtmlEditorWeb,
onUnFocus: controller.handleOnUnFocusHtmlEditorWeb, 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,
width: constraints.maxWidth, width: constraints.maxWidth,
height: constraints.maxHeight, height: constraints.maxHeight,
onDragEnter: controller.handleOnDragEnterHtmlEditorWeb, onDragEnter: controller.handleOnDragEnterHtmlEditorWeb,
@@ -710,9 +710,9 @@ class ComposerView extends GetWidget<ComposerController> {
} }
}), }),
Obx(() { Obx(() {
if (controller.richTextWebController.isFormattingOptionsEnabled) { if (controller.richTextWebController!.isFormattingOptionsEnabled) {
return ToolbarRichTextWebBuilder( return ToolbarRichTextWebBuilder(
richTextWebController: controller.richTextWebController, richTextWebController: controller.richTextWebController!,
padding: ComposerStyle.richToolbarPadding, padding: ComposerStyle.richToolbarPadding,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: ComposerStyle.richToolbarColor, color: ComposerStyle.richToolbarColor,
@@ -777,12 +777,12 @@ class ComposerView extends GetWidget<ComposerController> {
), ),
), ),
Obx(() => BottomBarComposerWidget( Obx(() => BottomBarComposerWidget(
isCodeViewEnabled: controller.richTextWebController.codeViewEnabled, isCodeViewEnabled: controller.richTextWebController!.codeViewEnabled,
isFormattingOptionsEnabled: controller.richTextWebController.isFormattingOptionsEnabled, isFormattingOptionsEnabled: controller.richTextWebController!.isFormattingOptionsEnabled,
openRichToolbarAction: controller.richTextWebController.toggleFormattingOptions, openRichToolbarAction: controller.richTextWebController!.toggleFormattingOptions,
attachFileAction: () => controller.openFilePickerByType(context, FileType.any), attachFileAction: () => controller.openFilePickerByType(context, FileType.any),
insertImageAction: () => controller.insertImage(context, constraints.maxWidth), insertImageAction: () => controller.insertImage(context, constraints.maxWidth),
showCodeViewAction: controller.richTextWebController.toggleCodeView, showCodeViewAction: controller.richTextWebController!.toggleCodeView,
deleteComposerAction: () => controller.handleClickDeleteComposer(context), deleteComposerAction: () => controller.handleClickDeleteComposer(context),
saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context), saveToDraftAction: () => controller.handleClickSaveAsDraftsButton(context),
sendMessageAction: () => controller.handleClickSendButton(context), sendMessageAction: () => controller.handleClickSendButton(context),
@@ -833,10 +833,10 @@ class ComposerView extends GetWidget<ComposerController> {
colorIcon: ComposerStyle.popupItemIconColor, colorIcon: ComposerStyle.popupItemIconColor,
padding: ComposerStyle.popupItemPadding, padding: ComposerStyle.popupItemPadding,
selectedIcon: controller.imagePaths.icFilterSelected, selectedIcon: controller.imagePaths.icFilterSelected,
isSelected: controller.richTextWebController.codeViewEnabled, isSelected: controller.richTextWebController?.codeViewEnabled,
onCallbackAction: () { onCallbackAction: () {
popBack(); popBack();
controller.richTextWebController.toggleCodeView(); controller.richTextWebController?.toggleCodeView();
} }
) )
), ),
@@ -11,6 +11,8 @@ import 'package:tmail_ui_user/features/composer/presentation/model/inline_image.
class RichTextMobileTabletController extends BaseRichTextController { class RichTextMobileTabletController extends BaseRichTextController {
HtmlEditorApi? htmlEditorApi; HtmlEditorApi? htmlEditorApi;
final RichTextController richTextController = RichTextController();
void insertImage(InlineImage inlineImage) async { void insertImage(InlineImage inlineImage) async {
if (inlineImage.fileInfo.isShared == true) { if (inlineImage.fileInfo.isShared == true) {
await htmlEditorApi?.moveCursorAtLastNode(); await htmlEditorApi?.moveCursorAtLastNode();
@@ -41,4 +43,11 @@ class RichTextMobileTabletController extends BaseRichTextController {
logError('RichTextMobileTabletController::insertImageData:Exception: $e'); logError('RichTextMobileTabletController::insertImageData:Exception: $e');
} }
} }
@override
void onClose() {
richTextController.dispose();
htmlEditorApi = null;
super.onClose();
}
} }
@@ -149,14 +149,7 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
child: FocusScope( child: FocusScope(
child: Focus( child: Focus(
onFocusChange: (focus) => widget.onFocusEmailAddressChangeAction?.call(widget.prefix, focus), onFocusChange: (focus) => widget.onFocusEmailAddressChangeAction?.call(widget.prefix, focus),
onKey: (focusNode, event) { onKey: PlatformInfo.isWeb ? _recipientInputOnKeyListener : null,
if (event is RawKeyDownEvent && event.logicalKey == LogicalKeyboardKey.tab) {
widget.nextFocusNode?.requestFocus();
widget.onFocusNextAddressAction?.call();
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
},
child: StatefulBuilder( child: StatefulBuilder(
builder: (context, stateSetter) { builder: (context, stateSetter) {
if (PlatformInfo.isWeb || widget.isTestingForWeb) { if (PlatformInfo.isWeb || widget.isTestingForWeb) {
@@ -389,6 +382,15 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
); );
} }
KeyEventResult _recipientInputOnKeyListener(FocusNode node, RawKeyEvent event) {
if (event is RawKeyDownEvent && event.logicalKey == LogicalKeyboardKey.tab) {
widget.nextFocusNode?.requestFocus();
widget.onFocusNextAddressAction?.call();
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
}
bool get _isCollapse => _currentListEmailAddress.length > 1 && widget.expandMode == ExpandMode.COLLAPSE; bool get _isCollapse => _currentListEmailAddress.length > 1 && widget.expandMode == ExpandMode.COLLAPSE;
bool get _isAllRecipientInputEnabled => widget.fromState == PrefixRecipientState.enabled bool get _isAllRecipientInputEnabled => widget.fromState == PrefixRecipientState.enabled
@@ -67,15 +67,15 @@ class IdentityCreatorController extends BaseController {
final isMobileEditorFocus = RxBool(false); final isMobileEditorFocus = RxBool(false);
final isCompressingInlineImage = RxBool(false); final isCompressingInlineImage = RxBool(false);
final RichTextController keyboardRichTextController = RichTextController();
final RichTextMobileTabletController richTextMobileTabletController = RichTextMobileTabletController();
final RichTextWebController richTextWebController = RichTextWebController();
final TextEditingController inputNameIdentityController = TextEditingController(); final TextEditingController inputNameIdentityController = TextEditingController();
final TextEditingController inputBccIdentityController = TextEditingController(); final TextEditingController inputBccIdentityController = TextEditingController();
final FocusNode inputNameIdentityFocusNode = FocusNode(); final FocusNode inputNameIdentityFocusNode = FocusNode();
final FocusNode inputBccIdentityFocusNode = FocusNode(); final FocusNode inputBccIdentityFocusNode = FocusNode();
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
RichTextMobileTabletController? richTextMobileTabletController;
RichTextWebController? richTextWebController;
String? _nameIdentity; String? _nameIdentity;
String? _contentHtmlEditor; String? _contentHtmlEditor;
AccountId? accountId; AccountId? accountId;
@@ -110,6 +110,11 @@ class IdentityCreatorController extends BaseController {
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
if (PlatformInfo.isWeb) {
richTextWebController = RichTextWebController();
} else {
richTextMobileTabletController = RichTextMobileTabletController();
}
log('IdentityCreatorController::onInit():arguments: ${Get.arguments}'); log('IdentityCreatorController::onInit():arguments: ${Get.arguments}');
arguments = Get.arguments; arguments = Get.arguments;
} }
@@ -132,13 +137,18 @@ class IdentityCreatorController extends BaseController {
@override @override
void onClose() { void onClose() {
log('IdentityCreatorController::onClose():'); log('IdentityCreatorController::onClose():');
keyboardRichTextController.dispose();
inputNameIdentityFocusNode.dispose(); inputNameIdentityFocusNode.dispose();
inputBccIdentityFocusNode.dispose(); inputBccIdentityFocusNode.dispose();
inputNameIdentityController.dispose(); inputNameIdentityController.dispose();
inputBccIdentityController.dispose(); inputBccIdentityController.dispose();
scrollController.dispose(); scrollController.dispose();
richTextWebController.onClose(); if (PlatformInfo.isWeb) {
richTextWebController?.onClose();
richTextWebController = null;
} else {
richTextMobileTabletController?.onClose();
richTextMobileTabletController = null;
}
super.onClose(); super.onClose();
} }
@@ -171,7 +181,7 @@ class IdentityCreatorController extends BaseController {
if (identity?.signatureAsString.isNotEmpty == true) { if (identity?.signatureAsString.isNotEmpty == true) {
updateContentHtmlEditor(arguments?.identity?.signatureAsString ?? ''); updateContentHtmlEditor(arguments?.identity?.signatureAsString ?? '');
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
richTextWebController.editorController.setText(arguments?.identity?.signatureAsString ?? ''); richTextWebController?.editorController.setText(arguments?.identity?.signatureAsString ?? '');
} }
} }
} }
@@ -299,9 +309,9 @@ class IdentityCreatorController extends BaseController {
Future<String?> _getSignatureHtmlText() async { Future<String?> _getSignatureHtmlText() async {
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
return richTextWebController.editorController.getText(); return richTextWebController?.editorController.getText();
} else { } else {
return keyboardRichTextController.htmlEditorApi?.getText(); return richTextMobileTabletController?.richTextController.htmlEditorApi?.getText();
} }
} }
@@ -421,7 +431,7 @@ class IdentityCreatorController extends BaseController {
void clearFocusEditor(BuildContext context) { void clearFocusEditor(BuildContext context) {
if (PlatformInfo.isMobile) { if (PlatformInfo.isMobile) {
keyboardRichTextController.htmlEditorApi?.unfocus(); richTextMobileTabletController?.htmlEditorApi?.unfocus();
KeyboardUtils.hideSystemKeyboardMobile(); KeyboardUtils.hideSystemKeyboardMobile();
} }
KeyboardUtils.hideKeyboard(context); KeyboardUtils.hideKeyboard(context);
@@ -434,15 +444,15 @@ class IdentityCreatorController extends BaseController {
} }
void initRichTextForMobile(BuildContext context, HtmlEditorApi editorApi) { void initRichTextForMobile(BuildContext context, HtmlEditorApi editorApi) {
richTextMobileTabletController.htmlEditorApi = editorApi; richTextMobileTabletController?.htmlEditorApi = editorApi;
keyboardRichTextController.onCreateHTMLEditor( richTextMobileTabletController?.richTextController.onCreateHTMLEditor(
editorApi, editorApi,
onEnterKeyDown: _onEnterKeyDownOnMobile, onEnterKeyDown: _onEnterKeyDownOnMobile,
onFocus: _onFocusHTMLEditorOnMobile, onFocus: _onFocusHTMLEditorOnMobile,
context: context context: context
); );
keyboardRichTextController.htmlEditorApi?.onFocusOut = () { richTextMobileTabletController?.htmlEditorApi?.onFocusOut = () {
keyboardRichTextController.hideRichTextView(); richTextMobileTabletController?.richTextController.hideRichTextView();
isMobileEditorFocus.value = false; isMobileEditorFocus.value = false;
}; };
} }
@@ -546,9 +556,9 @@ class IdentityCreatorController extends BaseController {
} }
} else { } else {
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
richTextWebController.insertImageAsBase64(platformFile: file, maxWidth: maxWidth); richTextWebController?.insertImageAsBase64(platformFile: file, maxWidth: maxWidth);
} else if (PlatformInfo.isMobile) { } else if (PlatformInfo.isMobile) {
richTextMobileTabletController.insertImageData(platformFile: file, maxWidth: maxWidth); richTextMobileTabletController?.insertImageData(platformFile: file, maxWidth: maxWidth);
if (file.path != null) { if (file.path != null) {
_deleteCompressedFileOnMobile(file.path!); _deleteCompressedFileOnMobile(file.path!);
} }
@@ -147,14 +147,14 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController>
? AppColor.colorBackgroundKeyboard ? AppColor.colorBackgroundKeyboard
: AppColor.colorBackgroundKeyboardAndroid, : AppColor.colorBackgroundKeyboardAndroid,
isLandScapeMode: controller.responsiveUtils.isLandscapeMobile(context), isLandScapeMode: controller.responsiveUtils.isLandscapeMobile(context),
richTextController: controller.keyboardRichTextController, richTextController: controller.richTextMobileTabletController!.richTextController,
titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles, titleQuickStyleBottomSheet: AppLocalizations.of(context).titleQuickStyles,
titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground, titleBackgroundBottomSheet: AppLocalizations.of(context).titleBackground,
titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground, titleForegroundBottomSheet: AppLocalizations.of(context).titleForeground,
titleFormatBottomSheet: AppLocalizations.of(context).titleFormat, titleFormatBottomSheet: AppLocalizations.of(context).titleFormat,
insertImage: () => controller.pickImage(context), insertImage: () => controller.pickImage(context),
), ),
richTextController: controller.keyboardRichTextController, richTextController: controller.richTextMobileTabletController!.richTextController,
paddingChild: EdgeInsets.zero, paddingChild: EdgeInsets.zero,
child: responsiveWidget child: responsiveWidget
); );
@@ -311,7 +311,7 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController>
children: [ children: [
if (PlatformInfo.isWeb) if (PlatformInfo.isWeb)
ToolbarRichTextWebBuilder( ToolbarRichTextWebBuilder(
richTextWebController: controller.richTextWebController, richTextWebController: controller.richTextWebController!,
padding: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.only(bottom: 12),
extendedOption: [ extendedOption: [
Padding( Padding(
@@ -344,7 +344,7 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController>
Widget _buildHtmlEditorWeb(BuildContext context, String initContent) { Widget _buildHtmlEditorWeb(BuildContext context, String initContent) {
return html_editor_browser.HtmlEditor( return html_editor_browser.HtmlEditor(
key: const Key('identity_create_editor_web'), key: const Key('identity_create_editor_web'),
controller: controller.richTextWebController.editorController, controller: controller.richTextWebController!.editorController,
htmlEditorOptions: html_editor_browser.HtmlEditorOptions( htmlEditorOptions: html_editor_browser.HtmlEditorOptions(
shouldEnsureVisible: true, shouldEnsureVisible: true,
hint: '', hint: '',
@@ -361,16 +361,16 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController>
onBeforeCommand: controller.updateContentHtmlEditor, onBeforeCommand: controller.updateContentHtmlEditor,
onChangeContent: controller.updateContentHtmlEditor, onChangeContent: controller.updateContentHtmlEditor,
onInit: () { onInit: () {
controller.richTextWebController.editorController.setFullScreen(); controller.richTextWebController?.editorController.setFullScreen();
controller.updateContentHtmlEditor(initContent); controller.updateContentHtmlEditor(initContent);
}, onFocus: () { }, onFocus: () {
FocusManager.instance.primaryFocus?.unfocus(); FocusManager.instance.primaryFocus?.unfocus();
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
controller.richTextWebController.editorController.setFocus(); controller.richTextWebController?.editorController.setFocus();
}); });
controller.richTextWebController.closeAllMenuPopup(); controller.richTextWebController?.closeAllMenuPopup();
}, },
onChangeSelection: controller.richTextWebController.onEditorSettingsChange, onChangeSelection: controller.richTextWebController?.onEditorSettingsChange,
onChangeCodeview: controller.updateContentHtmlEditor onChangeCodeview: controller.updateContentHtmlEditor
), ),
); );