TF-1512 Show keyboard below editor while type text

This commit is contained in:
dab246
2023-03-01 17:36:40 +07:00
committed by Dat Vu
parent b9ea97baa5
commit 9609e7ee9c
4 changed files with 98 additions and 80 deletions
@@ -18,7 +18,6 @@ import 'package:model/model.dart';
import 'package:rich_text_composer/richtext_controller.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_web_controller.dart';
import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_bindings.dart';
import 'package:tmail_ui_user/features/identity_creator/presentation/model/identity_creator_arguments.dart';
import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification/email_address_validator.dart';
import 'package:tmail_ui_user/features/mailbox_creator/domain/model/verification/empty_name_validator.dart';
@@ -56,8 +55,6 @@ class IdentityCreatorController extends BaseController {
final bccOfIdentity = Rxn<EmailAddress>();
final actionType = IdentityActionType.create.obs;
final isDefaultIdentity = RxBool(false);
final htmlEditorNode = FocusNode(debugLabel: 'html_editor');
final identityCreatorBinding = IdentityCreatorBindings();
late RichTextController keyboardRichTextController;
late RichTextWebController richTextWebController;
@@ -75,8 +72,8 @@ class IdentityCreatorController extends BaseController {
IdentityCreatorArguments? arguments;
OnCreatedIdentityCallback? onCreatedIdentityCallback;
VoidCallback? onDismissIdentityCreator;
ScrollController? scrollController;
final ScrollController scrollController = ScrollController();
final GlobalKey htmlKey = GlobalKey();
final htmlEditorMinHeight = 160;
@@ -110,6 +107,7 @@ class IdentityCreatorController extends BaseController {
inputNameIdentityController = TextEditingController();
inputBccIdentityController = TextEditingController();
inputNameIdentityFocusNode = FocusNode();
scrollController = ScrollController();
}
@override
@@ -128,7 +126,6 @@ class IdentityCreatorController extends BaseController {
@override
void onClose() {
keyboardRichTextController.dispose();
_disposeWidget();
super.onClose();
}
@@ -153,9 +150,11 @@ class IdentityCreatorController extends BaseController {
_nameIdentity = identity?.name ?? '';
inputNameIdentityController?.text = identity?.name ?? '';
if (identity?.htmlSignature?.value.isNotEmpty == true) {
updateContentHtmlEditor(arguments?.identity?.htmlSignature?.value ?? '');
signatureHtmlEditorController.setText(arguments?.identity?.htmlSignature?.value ?? '');
if (identity?.signatureAsString.isNotEmpty == true) {
updateContentHtmlEditor(arguments?.identity?.signatureAsString ?? '');
if (BuildUtils.isWeb) {
signatureHtmlEditorController.setText(arguments?.identity?.signatureAsString ?? '');
}
}
}
@@ -339,14 +338,13 @@ class IdentityCreatorController extends BaseController {
newIdentity,
isDefaultIdentity: isDefaultIdentity.value
);
_disposeWidget();
if (BuildUtils.isWeb) {
_disposeWidget();
onCreatedIdentityCallback?.call(identityRequest);
} else {
popBack(result: identityRequest);
}
} else {
final identityRequest = EditIdentityRequest(
identityId: identity!.id!,
@@ -360,7 +358,6 @@ class IdentityCreatorController extends BaseController {
popBack(result: identityRequest);
}
}
identityCreatorBinding.dispose();
}
void onCheckboxChanged() {
@@ -433,40 +430,42 @@ class IdentityCreatorController extends BaseController {
onDismissIdentityCreator?.call();
} else {
popBack();
identityCreatorBinding.dispose();
}
}
void _disposeWidget() {
keyboardRichTextController.dispose();
inputNameIdentityFocusNode?.dispose();
inputNameIdentityFocusNode = null;
inputNameIdentityController?.dispose();
inputNameIdentityController = null;
inputBccIdentityController?.dispose();
inputBccIdentityController = null;
scrollController.dispose();
scrollController?.dispose();
}
void onFocusHTMLEditorOnMobile() async {
if (htmlKey.currentContext != null) {
await Scrollable.ensureVisible(htmlKey.currentContext!);
if (scrollController != null) {
if (htmlKey.currentContext != null) {
await Scrollable.ensureVisible(htmlKey.currentContext!);
}
await Future.delayed(const Duration(milliseconds: 500), () {
final offset = scrollController!.position.pixels +
defaultKeyboardToolbarHeight +
htmlEditorMinHeight;
scrollController!.animateTo(
offset,
duration: const Duration(milliseconds: 1),
curve: Curves.linear,
);
});
}
await Future.delayed(const Duration(milliseconds: 500), () {
final offset = scrollController.position.pixels +
defaultKeyboardToolbarHeight +
htmlEditorMinHeight;
scrollController.animateTo(
offset,
duration: const Duration(milliseconds: 1),
curve: Curves.linear,
);
});
}
void onEnterKeyDownOnMobile() {
if(scrollController.position.pixels < scrollController.position.maxScrollExtent) {
scrollController.animateTo(
scrollController.position.pixels + 20,
if (scrollController != null && scrollController!.position.pixels < scrollController!.position.maxScrollExtent) {
scrollController!.animateTo(
scrollController!.position.pixels + 20,
duration: const Duration(milliseconds: 1),
curve: Curves.linear,
);
@@ -50,14 +50,47 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController> {
Widget build(BuildContext context) {
return ResponsiveWidget(
responsiveUtils: _responsiveUtils,
mobile: GestureDetector(
onTap: () => controller.clearFocusEditor(context),
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.95,
child: BuildUtils.isWeb
? Scaffold(body: _buildBodyMobile(context))
: _buildBodyMobile(context)
)
mobile: Card(
margin: EdgeInsets.zero,
borderOnForeground: false,
color: Colors.transparent,
child: SafeArea(
top: !BuildUtils.isWeb,
bottom: false,
left: false,
right: false,
child: ClipRRect(
borderRadius: const BorderRadius.only(
topRight: Radius.circular(16),
topLeft: Radius.circular(16)),
child: GestureDetector(
onTap: () => controller.clearFocusEditor(context),
child: Scaffold(
backgroundColor: Colors.white,
body: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(16),
topLeft: Radius.circular(16)),
boxShadow: [
BoxShadow(
color: AppColor.colorShadowLayerBottom,
blurRadius: 96,
spreadRadius: 96,
offset: Offset.zero),
BoxShadow(
color: AppColor.colorShadowLayerTop,
blurRadius: 2,
spreadRadius: 2,
offset: Offset.zero),
]),
child: _buildBodyMobile(context),
),
),
),
),
),
),
landscapeMobile: Scaffold(
backgroundColor: Colors.white,
@@ -163,7 +196,7 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController> {
controller: controller.scrollController,
physics: const ClampingScrollPhysics(),
child: Padding(
padding: const EdgeInsets.all(24.0),
padding: const EdgeInsets.all(24.0),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Obx(() => (IdentityInputFieldBuilder(
AppLocalizations.of(context).name,
@@ -223,27 +256,21 @@ class IdentityCreatorView extends GetWidget<IdentityCreatorController> {
.build()
),
const SizedBox(height: 32),
Row(
children: [
Text(AppLocalizations.of(context).signature,
style: const TextStyle(
fontWeight: FontWeight.normal,
fontSize: 14,
color: AppColor.colorContentEmail,
),
),
],
Text(AppLocalizations.of(context).signature,
style: const TextStyle(
fontWeight: FontWeight.normal,
fontSize: 14,
color: AppColor.colorContentEmail,
),
),
const SizedBox(height: 8),
PointerInterceptor(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.colorInputBorderCreateMailbox),
color: Colors.white,
),
child: _buildSignatureHtmlTemplate(context),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.colorInputBorderCreateMailbox),
color: Colors.white,
),
child: _buildSignatureHtmlTemplate(context),
),
if (_responsiveUtils.isTablet(context) || _responsiveUtils.isMobile(context))...[
Obx(() => Padding(
@@ -11,8 +11,6 @@ import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_bindings.dart';
import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_view.dart';
import 'package:tmail_ui_user/features/identity_creator/presentation/model/identity_creator_arguments.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/create_new_identity_request.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/edit_identity_request.dart';
@@ -32,6 +30,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/model/identit
import 'package:tmail_ui_user/features/manage_account/presentation/model/settings_page_level.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/delete_identity_dialog_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class IdentitiesController extends BaseController {
@@ -40,7 +39,6 @@ class IdentitiesController extends BaseController {
final _appToast = Get.find<AppToast>();
final _imagePaths = Get.find<ImagePaths>();
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _identityCreatorBindings = IdentityCreatorBindings();
final GetAllIdentitiesInteractor _getAllIdentitiesInteractor;
final CreateNewIdentityInteractor _createNewIdentityInteractor;
@@ -165,8 +163,9 @@ class IdentitiesController extends BaseController {
}
});
} else {
final newIdentityArguments =
await _getIdentityRequest(context, arguments);
final newIdentityArguments = await push(
AppRoutes.identityCreator,
arguments: arguments);
if (newIdentityArguments is CreateNewIdentityRequest) {
_createNewIdentityAction(accountId, newIdentityArguments);
@@ -177,25 +176,6 @@ class IdentitiesController extends BaseController {
}
}
Future<dynamic> _getIdentityRequest(
BuildContext context,
dynamic arguments
) async {
return await showModalBottomSheet(
enableDrag: false,
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0)),
),
builder: (context) {
_identityCreatorBindings.dependencies();
return IdentityCreatorView.fromArguments(arguments);
});
}
void _createNewIdentityAction(
AccountId accountId,
CreateNewIdentityRequest identityRequest
@@ -308,7 +288,9 @@ class IdentitiesController extends BaseController {
}
});
} else {
final newIdentityArguments = await _getIdentityRequest(context, arguments);
final newIdentityArguments = await push(
AppRoutes.identityCreator,
arguments: arguments);
if (newIdentityArguments is CreateNewIdentityRequest) {
_createNewIdentityAction(accountId, newIdentityArguments);
+10
View File
@@ -9,6 +9,7 @@ import 'package:tmail_ui_user/features/destination_picker/presentation/destinati
import 'package:tmail_ui_user/features/home/presentation/home_bindings.dart';
import 'package:tmail_ui_user/features/home/presentation/home_view.dart';
import 'package:tmail_ui_user/features/contact/presentation/contact_view.dart' deferred as contact_view;
import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_bindings.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/rules_filter_creator_bindings.dart';
import 'package:tmail_ui_user/features/rules_filter_creator/presentation/rules_filter_creator_view.dart' deferred as rules_filter_creator;
import 'package:tmail_ui_user/features/login/presentation/login_bindings.dart';
@@ -16,6 +17,7 @@ import 'package:tmail_ui_user/features/login/presentation/login_view.dart'
if (dart.library.html) 'package:tmail_ui_user/features/login/presentation/login_view_web.dart' deferred as login;
import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_bindings.dart';
import 'package:tmail_ui_user/features/mailbox_creator/presentation/mailbox_creator_view.dart' deferred as mailbox_creator;
import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_view.dart' deferred as identity_creator;
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view.dart'
if (dart.library.html) 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart' deferred as mailbox_dashboard;
@@ -107,6 +109,14 @@ class AppPages {
() => search_mailbox_view.SearchMailboxView()
),
binding: SearchMailboxBindings()),
GetPage(
name: AppRoutes.identityCreator,
opaque: false,
page: () => DeferredWidget(
identity_creator.loadLibrary,
() => identity_creator.IdentityCreatorView()
),
binding: IdentityCreatorBindings()),
]
];