TF-1152 Make better manage initial cursor position in composer
This commit is contained in:
@@ -5,7 +5,6 @@ import 'dart:io';
|
|||||||
import 'package:core/core.dart';
|
import 'package:core/core.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:enough_html_editor/enough_html_editor.dart';
|
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:filesize/filesize.dart';
|
import 'package:filesize/filesize.dart';
|
||||||
import 'package:fk_user_agent/fk_user_agent.dart';
|
import 'package:fk_user_agent/fk_user_agent.dart';
|
||||||
@@ -115,6 +114,9 @@ class ComposerController extends BaseController {
|
|||||||
final ccEmailAddressController = TextEditingController();
|
final ccEmailAddressController = TextEditingController();
|
||||||
final bccEmailAddressController = TextEditingController();
|
final bccEmailAddressController = TextEditingController();
|
||||||
|
|
||||||
|
FocusNode? subjectEmailInputFocusNode;
|
||||||
|
FocusNode? toAddressFocusNode;
|
||||||
|
|
||||||
final RichTextController keyboardRichTextController = RichTextController();
|
final RichTextController keyboardRichTextController = RichTextController();
|
||||||
|
|
||||||
final ScrollController scrollController = ScrollController();
|
final ScrollController scrollController = ScrollController();
|
||||||
@@ -183,6 +185,7 @@ class ComposerController extends BaseController {
|
|||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
createFocusNodeInput();
|
||||||
_listenWorker();
|
_listenWorker();
|
||||||
if (!BuildUtils.isWeb) {
|
if (!BuildUtils.isWeb) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
@@ -216,6 +219,10 @@ class ComposerController extends BaseController {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
subjectEmailInputFocusNode?.dispose();
|
||||||
|
subjectEmailInputFocusNode = null;
|
||||||
|
toAddressFocusNode?.dispose();
|
||||||
|
toAddressFocusNode = null;
|
||||||
subjectEmailInputController.dispose();
|
subjectEmailInputController.dispose();
|
||||||
toEmailAddressController.dispose();
|
toEmailAddressController.dispose();
|
||||||
ccEmailAddressController.dispose();
|
ccEmailAddressController.dispose();
|
||||||
@@ -252,14 +259,7 @@ class ComposerController extends BaseController {
|
|||||||
} else if (success is GetEmailContentSuccess) {
|
} else if (success is GetEmailContentSuccess) {
|
||||||
_getEmailContentSuccess(success);
|
_getEmailContentSuccess(success);
|
||||||
} else if (success is GetAllIdentitiesSuccess) {
|
} else if (success is GetAllIdentitiesSuccess) {
|
||||||
if (success.identities?.isNotEmpty == true) {
|
_handleGetAllIdentitiesSuccess(success);
|
||||||
listIdentities.value = success.identities!
|
|
||||||
.where((identity) => identity.mayDelete == true)
|
|
||||||
.toList();
|
|
||||||
if (listIdentities.isNotEmpty) {
|
|
||||||
selectIdentity(listIdentities.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (success is DownloadImageAsBase64Success) {
|
} else if (success is DownloadImageAsBase64Success) {
|
||||||
if(kIsWeb) {
|
if(kIsWeb) {
|
||||||
richTextWebController.insertImage(
|
richTextWebController.insertImage(
|
||||||
@@ -305,6 +305,11 @@ class ComposerController extends BaseController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void createFocusNodeInput() {
|
||||||
|
toAddressFocusNode = FocusNode();
|
||||||
|
subjectEmailInputFocusNode = FocusNode();
|
||||||
|
}
|
||||||
|
|
||||||
void _initEmail() {
|
void _initEmail() {
|
||||||
final arguments = kIsWeb ? mailboxDashBoardController.routerArguments : Get.arguments;
|
final arguments = kIsWeb ? mailboxDashBoardController.routerArguments : Get.arguments;
|
||||||
if (arguments is ComposerArguments) {
|
if (arguments is ComposerArguments) {
|
||||||
@@ -321,6 +326,8 @@ class ComposerController extends BaseController {
|
|||||||
_initSubjectEmail(arguments);
|
_initSubjectEmail(arguments);
|
||||||
_initAttachments(arguments);
|
_initAttachments(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_autoFocusFieldWhenLauncher();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initSubjectEmail(ComposerArguments arguments) {
|
void _initSubjectEmail(ComposerArguments arguments) {
|
||||||
@@ -350,6 +357,20 @@ class ComposerController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleGetAllIdentitiesSuccess(GetAllIdentitiesSuccess success) async {
|
||||||
|
if (success.identities?.isNotEmpty == true) {
|
||||||
|
listIdentities.value = success.identities!
|
||||||
|
.where((identity) => identity.mayDelete == true)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (listIdentities.isNotEmpty) {
|
||||||
|
await selectIdentity(listIdentities.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_autoFocusFieldWhenLauncher();
|
||||||
|
}
|
||||||
|
|
||||||
String? getContentEmail(BuildContext context) {
|
String? getContentEmail(BuildContext context) {
|
||||||
if (composerArguments.value != null) {
|
if (composerArguments.value != null) {
|
||||||
switch(composerArguments.value!.emailActionType) {
|
switch(composerArguments.value!.emailActionType) {
|
||||||
@@ -1076,8 +1097,10 @@ class ComposerController extends BaseController {
|
|||||||
|
|
||||||
void displayScreenTypeComposerAction(ScreenDisplayMode displayMode) {
|
void displayScreenTypeComposerAction(ScreenDisplayMode displayMode) {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
createFocusNodeInput();
|
||||||
_updateTextForEditor();
|
_updateTextForEditor();
|
||||||
screenDisplayMode.value = displayMode;
|
screenDisplayMode.value = displayMode;
|
||||||
|
_autoFocusFieldWhenLauncher();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateTextForEditor() async {
|
void _updateTextForEditor() async {
|
||||||
@@ -1174,13 +1197,13 @@ class ComposerController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectIdentity(Identity? newIdentity) {
|
Future<void> selectIdentity(Identity? newIdentity) async {
|
||||||
final formerIdentity = identitySelected.value;
|
final formerIdentity = identitySelected.value;
|
||||||
identitySelected.value = newIdentity;
|
identitySelected.value = newIdentity;
|
||||||
if (newIdentity != null) {
|
if (newIdentity != null) {
|
||||||
_applyIdentityForAllFieldComposer(formerIdentity, newIdentity);
|
await _applyIdentityForAllFieldComposer(formerIdentity, newIdentity);
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
|
||||||
}
|
}
|
||||||
|
return Future.value(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get _isMobileApp {
|
bool get _isMobileApp {
|
||||||
@@ -1189,7 +1212,10 @@ class ComposerController extends BaseController {
|
|||||||
&& _responsiveUtils.isMobile(currentContext!);
|
&& _responsiveUtils.isMobile(currentContext!);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _applyIdentityForAllFieldComposer(Identity? formerIdentity, Identity newIdentity) {
|
Future<void> _applyIdentityForAllFieldComposer(
|
||||||
|
Identity? formerIdentity,
|
||||||
|
Identity newIdentity
|
||||||
|
) async {
|
||||||
if (formerIdentity != null) {
|
if (formerIdentity != null) {
|
||||||
// Remove former identity
|
// Remove former identity
|
||||||
if (formerIdentity.bcc?.isNotEmpty == true) {
|
if (formerIdentity.bcc?.isNotEmpty == true) {
|
||||||
@@ -1203,7 +1229,7 @@ class ComposerController extends BaseController {
|
|||||||
|
|
||||||
// Add new identity
|
// Add new identity
|
||||||
if (newIdentity.bcc?.isNotEmpty == true) {
|
if (newIdentity.bcc?.isNotEmpty == true) {
|
||||||
_applyBccEmailAddressFromIdentity(newIdentity.bcc!);
|
await _applyBccEmailAddressFromIdentity(newIdentity.bcc!);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_isMobileApp) {
|
if (!_isMobileApp) {
|
||||||
@@ -1213,9 +1239,11 @@ class ComposerController extends BaseController {
|
|||||||
_applySignature(newIdentity.textSignature!);
|
_applySignature(newIdentity.textSignature!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Future.value(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _applyBccEmailAddressFromIdentity(Set<EmailAddress> listEmailAddress) {
|
Future<void> _applyBccEmailAddressFromIdentity(Set<EmailAddress> listEmailAddress) {
|
||||||
if (!listEmailAddressType.contains(PrefixEmailAddress.bcc)) {
|
if (!listEmailAddressType.contains(PrefixEmailAddress.bcc)) {
|
||||||
listEmailAddressType.add(PrefixEmailAddress.bcc);
|
listEmailAddressType.add(PrefixEmailAddress.bcc);
|
||||||
}
|
}
|
||||||
@@ -1224,6 +1252,8 @@ class ComposerController extends BaseController {
|
|||||||
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
_updateStatusEmailSendButton();
|
_updateStatusEmailSendButton();
|
||||||
|
|
||||||
|
return Future.value(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _removeBccEmailAddressFromFormerIdentity(Set<EmailAddress> listEmailAddress) {
|
void _removeBccEmailAddressFromFormerIdentity(Set<EmailAddress> listEmailAddress) {
|
||||||
@@ -1368,4 +1398,18 @@ class ComposerController extends BaseController {
|
|||||||
hasRequestReadReceipt.toggle();
|
hasRequestReadReceipt.toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _autoFocusFieldWhenLauncher() {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
if (listToEmailAddress.isEmpty) {
|
||||||
|
toAddressFocusNode?.requestFocus();
|
||||||
|
} else if (subjectEmailInputController.text.isEmpty) {
|
||||||
|
subjectEmailInputFocusNode?.requestFocus();
|
||||||
|
} else if (BuildUtils.isWeb) {
|
||||||
|
Future.delayed(
|
||||||
|
const Duration(milliseconds: 500),
|
||||||
|
richTextWebController.editorController.setFocus
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -354,6 +354,8 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
controller.listEmailAddressType,
|
controller.listEmailAddressType,
|
||||||
expandMode: controller.toAddressExpandMode.value,
|
expandMode: controller.toAddressExpandMode.value,
|
||||||
controller: controller.toEmailAddressController,
|
controller: controller.toEmailAddressController,
|
||||||
|
focusNode: controller.toAddressFocusNode,
|
||||||
|
autoDisposeFocusNode: false,
|
||||||
isInitial: controller.isInitialRecipient.value)
|
isInitial: controller.isInitialRecipient.value)
|
||||||
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
|
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
|
||||||
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
|
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
|
||||||
@@ -431,6 +433,7 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
..key(const Key('subject_email_input'))
|
..key(const Key('subject_email_input'))
|
||||||
..cursorColor(AppColor.colorTextButton)
|
..cursorColor(AppColor.colorTextButton)
|
||||||
..maxLines(responsiveUtils.isMobile(context) ? null : 1)
|
..maxLines(responsiveUtils.isMobile(context) ? null : 1)
|
||||||
|
..addFocusNode(controller.subjectEmailInputFocusNode)
|
||||||
..onChange((value) => controller.setSubjectEmail(value))
|
..onChange((value) => controller.setSubjectEmail(value))
|
||||||
..textStyle(const TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal))
|
..textStyle(const TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal))
|
||||||
..textDecoration(const InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none))
|
..textDecoration(const InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none))
|
||||||
|
|||||||
@@ -473,6 +473,8 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
controller.listEmailAddressType,
|
controller.listEmailAddressType,
|
||||||
expandMode: controller.toAddressExpandMode.value,
|
expandMode: controller.toAddressExpandMode.value,
|
||||||
controller: controller.toEmailAddressController,
|
controller: controller.toEmailAddressController,
|
||||||
|
focusNode: controller.toAddressFocusNode,
|
||||||
|
autoDisposeFocusNode: false,
|
||||||
isInitial: controller.isInitialRecipient.value)
|
isInitial: controller.isInitialRecipient.value)
|
||||||
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
|
..addOnFocusEmailAddressChangeAction((prefixEmailAddress, focus) => controller.onEmailAddressFocusChange(prefixEmailAddress, focus))
|
||||||
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
|
..addOnShowFullListEmailAddressAction((prefixEmailAddress) => controller.showFullEmailAddress(prefixEmailAddress))
|
||||||
@@ -544,6 +546,7 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
child: (TextFieldBuilder()
|
child: (TextFieldBuilder()
|
||||||
..key(const Key('subject_email_input'))
|
..key(const Key('subject_email_input'))
|
||||||
..cursorColor(AppColor.colorTextButton)
|
..cursorColor(AppColor.colorTextButton)
|
||||||
|
..addFocusNode(controller.subjectEmailInputFocusNode)
|
||||||
..onChange((value) => controller.setSubjectEmail(value))
|
..onChange((value) => controller.setSubjectEmail(value))
|
||||||
..textStyle(const TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal))
|
..textStyle(const TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal))
|
||||||
..textDecoration(const InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none))
|
..textDecoration(const InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none))
|
||||||
@@ -671,7 +674,7 @@ class ComposerView extends GetWidget<ComposerController>
|
|||||||
child: HtmlEditor(
|
child: HtmlEditor(
|
||||||
key: const Key('composer_editor_web'),
|
key: const Key('composer_editor_web'),
|
||||||
controller: controller.richTextWebController.editorController,
|
controller: controller.richTextWebController.editorController,
|
||||||
htmlEditorOptions: HtmlEditorOptions(
|
htmlEditorOptions: const HtmlEditorOptions(
|
||||||
hint: '',
|
hint: '',
|
||||||
darkMode: false,
|
darkMode: false,
|
||||||
customBodyCssStyle: bodyCssStyleForEditor),
|
customBodyCssStyle: bodyCssStyleForEditor),
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ class EmailAddressInputBuilder {
|
|||||||
final List<PrefixEmailAddress> _listEmailAddressType;
|
final List<PrefixEmailAddress> _listEmailAddressType;
|
||||||
final TextEditingController? controller;
|
final TextEditingController? controller;
|
||||||
final bool? isInitial;
|
final bool? isInitial;
|
||||||
|
final FocusNode? focusNode;
|
||||||
|
final bool autoDisposeFocusNode;
|
||||||
|
|
||||||
List<EmailAddress> listEmailAddress = <EmailAddress>[];
|
List<EmailAddress> listEmailAddress = <EmailAddress>[];
|
||||||
|
|
||||||
@@ -76,6 +78,8 @@ class EmailAddressInputBuilder {
|
|||||||
{
|
{
|
||||||
this.isInitial,
|
this.isInitial,
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.focusNode,
|
||||||
|
this.autoDisposeFocusNode = true,
|
||||||
this.expandMode = ExpandMode.EXPAND,
|
this.expandMode = ExpandMode.EXPAND,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -127,12 +131,14 @@ class EmailAddressInputBuilder {
|
|||||||
child: TagEditor<SuggestionEmailAddress>(
|
child: TagEditor<SuggestionEmailAddress>(
|
||||||
length: newListEmailAddress.length,
|
length: newListEmailAddress.length,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
focusNode: focusNode,
|
||||||
|
autoDisposeFocusNode: autoDisposeFocusNode,
|
||||||
keyboardType: TextInputType.emailAddress,
|
keyboardType: TextInputType.emailAddress,
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
hasAddButton: false,
|
hasAddButton: false,
|
||||||
tagSpacing: 8,
|
tagSpacing: 8,
|
||||||
delimiters: const [' '],
|
delimiters: const [' '],
|
||||||
autofocus: _prefixEmailAddress != PrefixEmailAddress.to,
|
autofocus: _prefixEmailAddress != PrefixEmailAddress.to && listEmailAddress.isEmpty,
|
||||||
minTextFieldWidth: 20,
|
minTextFieldWidth: 20,
|
||||||
resetTextOnSubmitted: true,
|
resetTextOnSubmitted: true,
|
||||||
suggestionsBoxElevation: _suggestionBoxRadius,
|
suggestionsBoxElevation: _suggestionBoxRadius,
|
||||||
|
|||||||
+3
-3
@@ -473,7 +473,7 @@ packages:
|
|||||||
name: firebase_core_web
|
name: firebase_core_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.2"
|
||||||
firebase_messaging:
|
firebase_messaging:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1366,14 +1366,14 @@ packages:
|
|||||||
name: super_tag_editor
|
name: super_tag_editor
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.3+2"
|
version: "0.0.3+3"
|
||||||
syncfusion_flutter_core:
|
syncfusion_flutter_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: syncfusion_flutter_core
|
name: syncfusion_flutter_core
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "20.3.58"
|
version: "20.3.60"
|
||||||
syncfusion_flutter_datepicker:
|
syncfusion_flutter_datepicker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
+1
-1
@@ -99,7 +99,7 @@ dependencies:
|
|||||||
filesize: 2.0.1
|
filesize: 2.0.1
|
||||||
|
|
||||||
# super_tag_editor
|
# super_tag_editor
|
||||||
super_tag_editor: 0.0.3+2
|
super_tag_editor: 0.0.3+3
|
||||||
|
|
||||||
# uuid
|
# uuid
|
||||||
uuid: 3.0.4
|
uuid: 3.0.4
|
||||||
|
|||||||
Reference in New Issue
Block a user