From fdb062fa3d859951f5fa2f7108a2aece06a26ef7 Mon Sep 17 00:00:00 2001 From: dab246 Date: Fri, 11 Jul 2025 20:28:29 +0700 Subject: [PATCH] Apply new style for create identity view on mobile Signed-off-by: dab246 --- .../presentation/identity_creator_view.dart | 154 +++--------------- .../identity_creator_form_bottom_view.dart | 24 ++- ...identity_creator_form_desktop_builder.dart | 124 +++++++++----- .../identity_creator_form_mobile_builder.dart | 100 ++++++++---- 4 files changed, 177 insertions(+), 225 deletions(-) diff --git a/lib/features/identity_creator/presentation/identity_creator_view.dart b/lib/features/identity_creator/presentation/identity_creator_view.dart index 1e22c44bd..b9c0a7739 100644 --- a/lib/features/identity_creator/presentation/identity_creator_view.dart +++ b/lib/features/identity_creator/presentation/identity_creator_view.dart @@ -1,4 +1,3 @@ -import 'dart:math' as math; import 'package:core/presentation/extensions/capitalize_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart'; @@ -14,8 +13,6 @@ import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; -import 'package:rich_text_composer/rich_text_composer.dart'; -import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_email_address_drop_down_button.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_horizontal_field_widget.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_label_field_widget.dart'; @@ -68,9 +65,9 @@ class IdentityCreatorView extends GetWidget keyboardType: TextInputType.text, semanticLabel: 'Identity input field', decoration: (IdentityInputDecorationBuilder() - ..setContentPadding(const EdgeInsets.symmetric( + ..setContentPadding(EdgeInsets.symmetric( horizontal: 12, - vertical: 15, + vertical: PlatformInfo.isWeb ? 15 : 12, )) ..setErrorText(controller.errorNameIdentity.value) ..setHintText(appLocalizations.enterName) @@ -115,9 +112,9 @@ class IdentityCreatorView extends GetWidget color: AppColor.m3SurfaceBackground, ), decoration: (IdentityInputDecorationBuilder() - ..setContentPadding(const EdgeInsets.symmetric( + ..setContentPadding(EdgeInsets.symmetric( horizontal: 12, - vertical: 15, + vertical: PlatformInfo.isWeb ? 15 : 12, )) ..setErrorText(controller.errorBccIdentity.value) ..setHintText(appLocalizations.enterEmailAddress) @@ -203,9 +200,9 @@ class IdentityCreatorView extends GetWidget keyboardType: TextInputType.text, semanticLabel: 'Identity input field', decoration: (IdentityInputDecorationBuilder() - ..setContentPadding(const EdgeInsets.symmetric( + ..setContentPadding(EdgeInsets.symmetric( horizontal: 12, - vertical: 15, + vertical: PlatformInfo.isWeb ? 15 : 12, )) ..setErrorText(controller.errorNameIdentity.value) ..setHintText(appLocalizations.enterName) @@ -256,9 +253,9 @@ class IdentityCreatorView extends GetWidget color: AppColor.m3SurfaceBackground, ), decoration: (IdentityInputDecorationBuilder() - ..setContentPadding(const EdgeInsets.symmetric( + ..setContentPadding(EdgeInsets.symmetric( horizontal: 12, - vertical: 15, + vertical: PlatformInfo.isWeb ? 15 : 12, )) ..setErrorText(controller.errorBccIdentity.value) ..setHintText(appLocalizations.enterEmailAddress) @@ -318,132 +315,21 @@ class IdentityCreatorView extends GetWidget ); } - if (PlatformInfo.isWeb) { - bodyCreatorView = NotificationListener( - onNotification: (scrollInfo) { - if (scrollInfo is ScrollEndNotification && - scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { - controller.clearFocusEditor(context); - } - return false; - }, - child: bodyCreatorView, - ); - - return PointerInterceptor( - child: ResponsiveWidget( - responsiveUtils: controller.responsiveUtils, - mobile: IdentityCreatorFormMobileBuilder( - controller: controller, - formView: bodyCreatorView, - ), - tablet: IdentityCreatorFormDesktopBuilder( - controller: controller, - formView: bodyCreatorView, - ) - ), - ); - } else { - return ResponsiveWidget( + return PointerInterceptor( + child: ResponsiveWidget( responsiveUtils: controller.responsiveUtils, - mobile: GestureDetector( - onTap: () => controller.clearFocusEditor(context), - child: Scaffold( - backgroundColor: Colors.black38, - body: SafeArea( - bottom: false, - child: KeyboardRichText( - keyBroadToolbar: RichTextKeyboardToolBar( - rootContext: context, - titleBack: AppLocalizations.of(context).titleFormat, - backgroundKeyboardToolBarColor: PlatformInfo.isIOS - ? AppColor.colorBackgroundKeyboard - : AppColor.colorBackgroundKeyboardAndroid, - richTextController: controller.richTextMobileTabletController!.richTextController, - quickStyleLabel: AppLocalizations.of(context).titleQuickStyles, - backgroundLabel: AppLocalizations.of(context).titleBackground, - foregroundLabel: AppLocalizations.of(context).titleForeground, - formatLabel: AppLocalizations.of(context).titleFormat, - insertImage: () => controller.pickImage(context), - ), - richTextController: controller.richTextMobileTabletController!.richTextController, - child: Card( - margin: EdgeInsets.zero, - elevation: 16, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(16), - topLeft: Radius.circular(16) - ), - ), - clipBehavior: Clip.antiAlias, - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(16), - topLeft: Radius.circular(16) - ), - ), - child: Column(children: [ - Expanded(child: bodyCreatorView) - ]), - ), - ), - ), - ), - ), + mobile: IdentityCreatorFormMobileBuilder( + controller: controller, + formView: bodyCreatorView, + enableRichTextKeyboard: PlatformInfo.isMobile, ), tablet: Portal( - child: GestureDetector( - onTap: () => controller.clearFocusEditor(context), - child: Scaffold( - backgroundColor: Colors.black38, - body: SafeArea( - child: KeyboardRichText( - keyBroadToolbar: RichTextKeyboardToolBar( - rootContext: context, - titleBack: AppLocalizations.of(context).titleFormat, - backgroundKeyboardToolBarColor: PlatformInfo.isIOS - ? AppColor.colorBackgroundKeyboard - : AppColor.colorBackgroundKeyboardAndroid, - richTextController: controller.richTextMobileTabletController!.richTextController, - quickStyleLabel: AppLocalizations.of(context).titleQuickStyles, - backgroundLabel: AppLocalizations.of(context).titleBackground, - foregroundLabel: AppLocalizations.of(context).titleForeground, - formatLabel: AppLocalizations.of(context).titleFormat, - insertImage: () => controller.pickImage(context), - ), - richTextController: controller.richTextMobileTabletController!.richTextController, - child: Center( - child: Padding( - padding: const EdgeInsetsDirectional.symmetric(horizontal: 24), - child: Card( - color: Colors.transparent, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(16)) - ), - clipBehavior: Clip.antiAlias, - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(16)) - ), - width: math.max(controller.responsiveUtils.getSizeScreenWidth(context) * 0.4, 700), - height: controller.responsiveUtils.getSizeScreenHeight(context) * 0.8, - child: Column(children: [ - Expanded(child: bodyCreatorView), - ]) - ) - ), - ) - ), - ), - ), - ), + child: IdentityCreatorFormDesktopBuilder( + controller: controller, + formView: bodyCreatorView, ), - ) - ); - } + ), + ), + ); } } \ No newline at end of file diff --git a/lib/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart b/lib/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart index 398ea7628..8a2954c5a 100644 --- a/lib/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart +++ b/lib/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart @@ -23,18 +23,16 @@ class IdentityCreatorFormBottomView extends StatelessWidget { final checkboxWidget = Obx(() { if (controller.isDefaultIdentitySupported.isTrue) { - return Expanded( - child: Obx(() { - return CustomIconLabeledCheckbox( - label: appLocalizations.setDefaultIdentity, - svgIconPath: controller.imagePaths.icCheckboxUnselected, - selectedSvgIconPath: controller.imagePaths.icCheckboxSelected, - value: controller.isDefaultIdentity.value, - semanticsLabel: 'Set default identity checkbox', - onChanged: (_) => controller.onCheckboxChanged(), - ); - }), - ); + return Obx(() { + return CustomIconLabeledCheckbox( + label: appLocalizations.setDefaultIdentity, + svgIconPath: controller.imagePaths.icCheckboxUnselected, + selectedSvgIconPath: controller.imagePaths.icCheckboxSelected, + value: controller.isDefaultIdentity.value, + semanticsLabel: 'Set default identity checkbox', + onChanged: (_) => controller.onCheckboxChanged(), + ); + }); } else { return const SizedBox.shrink(); } @@ -113,7 +111,7 @@ class IdentityCreatorFormBottomView extends StatelessWidget { ), child: Row( children: [ - checkboxWidget, + Expanded(child: checkboxWidget), Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.end, diff --git a/lib/features/identity_creator/presentation/widgets/identity_creator_form_desktop_builder.dart b/lib/features/identity_creator/presentation/widgets/identity_creator_form_desktop_builder.dart index 3bba327f4..f69c6e026 100644 --- a/lib/features/identity_creator/presentation/widgets/identity_creator_form_desktop_builder.dart +++ b/lib/features/identity_creator/presentation/widgets/identity_creator_form_desktop_builder.dart @@ -1,7 +1,11 @@ import 'dart:math'; +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:rich_text_composer/views/keyboard_rich_text.dart'; +import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_close_button_widget.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_controller.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart'; @@ -11,66 +15,96 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class IdentityCreatorFormDesktopBuilder extends StatelessWidget { final IdentityCreatorController controller; final Widget formView; + final bool enableRichTextKeyboard; const IdentityCreatorFormDesktopBuilder({ super.key, required this.controller, required this.formView, + this.enableRichTextKeyboard = false, }); @override Widget build(BuildContext context) { final appLocalizations = AppLocalizations.of(context); + Widget bodyWidget = Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(16)), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 24, + offset: const Offset(0, 2), + ), + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 2, + ), + ], + ), + width: min( + controller.responsiveUtils.getSizeScreenWidth(context) - 48, + 784, + ), + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Obx(() { + final actionType = controller.actionType.value; + return IdentityCreatorFormTitleWidget( + title: actionType.getTitle(appLocalizations), + ); + }), + Flexible(child: formView), + const SizedBox(height: 24), + IdentityCreatorFormBottomView(controller: controller), + ], + ), + DefaultCloseButtonWidget( + iconClose: controller.imagePaths.icCloseDialog, + onTapActionCallback: () => controller.closeView(context), + ), + ], + ), + ); + + if (enableRichTextKeyboard) { + final richTextController = controller + .richTextMobileTabletController + !.richTextController; + + bodyWidget = KeyboardRichText( + keyBroadToolbar: RichTextKeyboardToolBar( + rootContext: context, + titleBack: appLocalizations.titleFormat, + backgroundKeyboardToolBarColor: PlatformInfo.isIOS + ? AppColor.colorBackgroundKeyboard + : AppColor.colorBackgroundKeyboardAndroid, + richTextController: richTextController, + quickStyleLabel: appLocalizations.titleQuickStyles, + backgroundLabel: appLocalizations.titleBackground, + foregroundLabel: appLocalizations.titleForeground, + formatLabel: appLocalizations.titleFormat, + insertImage: () => controller.pickImage(context), + ), + richTextController: richTextController, + child: bodyWidget, + ); + } + + if (PlatformInfo.isMobile) { + bodyWidget = SafeArea(child: bodyWidget); + } + return Scaffold( backgroundColor: Colors.black.withOpacity(0.2), body: GestureDetector( onTap: () => controller.clearFocusEditor(context), - child: Center( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(16)), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.08), - blurRadius: 24, - offset: const Offset(0, 2), - ), - BoxShadow( - color: Colors.black.withOpacity(0.08), - blurRadius: 2, - ), - ], - ), - width: min( - controller.responsiveUtils.getSizeScreenWidth(context) - 48, - 784, - ), - child: Stack( - children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Obx(() { - final actionType = controller.actionType.value; - return IdentityCreatorFormTitleWidget( - title: actionType.getTitle(appLocalizations), - ); - }), - Flexible(child: formView), - const SizedBox(height: 24), - IdentityCreatorFormBottomView(controller: controller), - ], - ), - DefaultCloseButtonWidget( - iconClose: controller.imagePaths.icCloseDialog, - onTapActionCallback: () => controller.closeView(context), - ), - ], - ), - ), - ), + child: Center(child: bodyWidget), ), ); } diff --git a/lib/features/identity_creator/presentation/widgets/identity_creator_form_mobile_builder.dart b/lib/features/identity_creator/presentation/widgets/identity_creator_form_mobile_builder.dart index 7ace4051b..d2977a778 100644 --- a/lib/features/identity_creator/presentation/widgets/identity_creator_form_mobile_builder.dart +++ b/lib/features/identity_creator/presentation/widgets/identity_creator_form_mobile_builder.dart @@ -1,5 +1,9 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:rich_text_composer/rich_text_composer.dart'; +import 'package:rich_text_composer/views/widgets/rich_text_keyboard_toolbar.dart'; import 'package:tmail_ui_user/features/base/widget/default_field/default_app_bar_widget.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_controller.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart'; @@ -8,54 +12,84 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; class IdentityCreatorFormMobileBuilder extends StatelessWidget { final IdentityCreatorController controller; final Widget formView; + final bool enableRichTextKeyboard; const IdentityCreatorFormMobileBuilder({ super.key, required this.controller, required this.formView, + this.enableRichTextKeyboard = false, }); @override Widget build(BuildContext context) { final appLocalizations = AppLocalizations.of(context); + Widget bodyWidget = ColoredBox( + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Obx(() { + final actionType = controller.actionType.value; + return DefaultAppBarWidget( + title: actionType.getTitle(appLocalizations), + imagePaths: controller.imagePaths, + responsiveUtils: controller.responsiveUtils, + onBackAction: () => controller.closeView(context), + ); + }), + Expanded( + child: SingleChildScrollView( + controller: controller.scrollController, + physics: const ClampingScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: formView), + IdentityCreatorFormBottomView(controller: controller), + ], + ), + ), + ), + ], + ), + ); + + if (enableRichTextKeyboard) { + final richTextController = controller + .richTextMobileTabletController + !.richTextController; + + bodyWidget = KeyboardRichText( + keyBroadToolbar: RichTextKeyboardToolBar( + rootContext: context, + titleBack: appLocalizations.titleFormat, + backgroundKeyboardToolBarColor: PlatformInfo.isIOS + ? AppColor.colorBackgroundKeyboard + : AppColor.colorBackgroundKeyboardAndroid, + richTextController: richTextController, + quickStyleLabel: appLocalizations.titleQuickStyles, + backgroundLabel: appLocalizations.titleBackground, + foregroundLabel: appLocalizations.titleForeground, + formatLabel: appLocalizations.titleFormat, + insertImage: () => controller.pickImage(context), + ), + richTextController: richTextController, + child: bodyWidget, + ); + } + + if (PlatformInfo.isMobile) { + bodyWidget = SafeArea(child: bodyWidget); + } + return Scaffold( backgroundColor: Colors.white, body: GestureDetector( onTap: () => controller.clearFocusEditor(context), - child: SafeArea( - child: ColoredBox( - color: Colors.white, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Obx(() { - final actionType = controller.actionType.value; - return DefaultAppBarWidget( - title: actionType.getTitle(appLocalizations), - imagePaths: controller.imagePaths, - responsiveUtils: controller.responsiveUtils, - onBackAction: () => controller.closeView(context), - ); - }), - Expanded( - child: SingleChildScrollView( - controller: controller.scrollController, - physics: const ClampingScrollPhysics(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible(child: formView), - IdentityCreatorFormBottomView(controller: controller), - ], - ), - ), - ), - ], - ), - ), - ), + child: bodyWidget, ), ); }