diff --git a/core/lib/core.dart b/core/lib/core.dart index 6a91c3387..230e637b9 100644 --- a/core/lib/core.dart +++ b/core/lib/core.dart @@ -47,7 +47,6 @@ export 'utils/platform_info.dart'; export 'presentation/views/text/slogan_builder.dart'; export 'presentation/views/text/text_field_builder.dart'; export 'presentation/views/text/input_decoration_builder.dart'; -export 'presentation/views/text/text_builder.dart'; export 'presentation/views/text/rich_text_builder.dart'; export 'presentation/views/responsive/responsive_widget.dart'; export 'presentation/views/list/tree_view.dart'; diff --git a/core/lib/presentation/views/quick_search/quick_search_input_form.dart b/core/lib/presentation/views/quick_search/quick_search_input_form.dart index dcd788be3..4d0a00f8b 100644 --- a/core/lib/presentation/views/quick_search/quick_search_input_form.dart +++ b/core/lib/presentation/views/quick_search/quick_search_input_form.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -576,6 +577,7 @@ class _TypeAheadFieldQuickSearchState extends State widget.textFieldConfiguration.controller ?? _textEditingController; @@ -622,6 +624,8 @@ class _TypeAheadFieldQuickSearchState extends State extends State extends State? _onTextChange; - ValueChanged? _onTextSubmitted; - TextStyle? _textStyle; - TextInputAction? _textInputAction; - InputDecoration? _inputDecoration; - bool? _obscureText; - int? _maxLines = 1; - int? _minLines; - TextEditingController? _textController; - TextInputType? _keyboardType; - Color? _cursorColor; - bool? _autoFocus; - FocusNode? _focusNode; +class TextFieldBuilder extends StatefulWidget { - void key(Key key) { - _key = key; + final ValueChanged? onTextChange; + final ValueChanged? onTextSubmitted; + final VoidCallback? onTap; + final TextStyle? textStyle; + final TextInputAction? textInputAction; + final InputDecoration? decoration; + final bool obscureText; + final int? maxLines; + final int? minLines; + final TextEditingController? controller; + final TextInputType? keyboardType; + final Color cursorColor; + final bool autoFocus; + final FocusNode? focusNode; + final String? fromValue; + final Brightness? keyboardAppearance; + final bool autocorrect; + final TextDirection textDirection; + final bool readOnly; + final MouseCursor? mouseCursor; + + const TextFieldBuilder({ + super.key, + this.cursorColor = AppColor.primaryColor, + this.autocorrect = false, + this.obscureText = false, + this.autoFocus = false, + this.readOnly = false, + this.textStyle = const TextStyle(color: AppColor.textFieldTextColor), + this.textDirection = TextDirection.ltr, + this.textInputAction, + this.decoration, + this.maxLines, + this.minLines, + this.controller, + this.keyboardType, + this.focusNode, + this.fromValue, + this.keyboardAppearance, + this.mouseCursor, + this.onTap, + this.onTextChange, + this.onTextSubmitted, + }); + + @override + State createState() => _TextFieldBuilderState(); +} + +class _TextFieldBuilderState extends State { + + late TextEditingController _controller; + late TextDirection _textDirection; + + @override + void initState() { + if (widget.fromValue != null) { + _controller = TextEditingController.fromValue(TextEditingValue(text: widget.fromValue!)); + } else if (widget.controller != null) { + _controller = widget.controller!; + } else { + _controller = TextEditingController(); + } + _textDirection = widget.textDirection; + super.initState(); } - void onChange(ValueChanged onChange) { - _onTextChange = onChange; - } - - void onSubmitted(ValueChanged onSubmitted) { - _onTextSubmitted = onSubmitted; - } - - void textStyle(TextStyle style) { - _textStyle = style; - } - - void textInputAction(TextInputAction inputAction) { - _textInputAction = inputAction; - } - - void textDecoration(InputDecoration inputDecoration) { - _inputDecoration = inputDecoration; - } - - void obscureText(bool obscureText) { - _obscureText = obscureText; - } - - void setText(String value) { - _textController = TextEditingController.fromValue(TextEditingValue(text: value)); - } - - void addController(TextEditingController? textEditingController) { - _textController = textEditingController; - } - - void maxLines(int? value) { - _maxLines = value; - } - - void minLines(int? value) { - _minLines = value; - } - - void keyboardType(TextInputType? value) { - _keyboardType = value; - } - - void cursorColor(Color? color) { - _cursorColor = color; - } - - void autoFocus(bool autoFocus) { - _autoFocus = autoFocus; - } - - void addFocusNode(FocusNode? focusNode) { - _focusNode = focusNode; - } - - TextField build() { + @override + Widget build(BuildContext context) { return TextField( - key: _key ?? const Key('TextFieldBuilder'), - onChanged: _onTextChange, - cursorColor: _cursorColor ?? AppColor.primaryColor, - controller: _textController, - autocorrect: false, - textInputAction: _textInputAction, - decoration: _inputDecoration, - maxLines: _maxLines, - minLines: _minLines, - keyboardAppearance: Brightness.light, - style: _textStyle ?? const TextStyle(color: AppColor.textFieldTextColor), - obscureText: _obscureText ?? false, - keyboardType: _keyboardType, - onSubmitted: _onTextSubmitted, - autofocus: _autoFocus ?? false, - focusNode: _focusNode, + key: widget.key, + controller: _controller, + cursorColor: widget.cursorColor, + autocorrect: widget.autocorrect, + textInputAction: widget.textInputAction, + decoration: widget.decoration, + maxLines: widget.maxLines, + minLines: widget.minLines, + keyboardAppearance: widget.keyboardAppearance, + style: widget.textStyle, + obscureText: widget.obscureText, + keyboardType: widget.keyboardType, + autofocus: widget.autoFocus, + focusNode: widget.focusNode, + textDirection: _textDirection, + readOnly: widget.readOnly, + mouseCursor: widget.mouseCursor, + onChanged: (value) { + widget.onTextChange?.call(value); + if (value.isNotEmpty) { + final directionByText = DirectionUtils.getDirectionByEndsText(value); + if (directionByText != _textDirection) { + setState(() { + _textDirection = directionByText; + }); + } + } + }, + onSubmitted: widget.onTextSubmitted, + onTap: widget.onTap, ); } + + @override + void dispose() { + if (widget.fromValue == null && widget.controller == null) { + _controller.dispose(); + } + super.dispose(); + } } \ No newline at end of file diff --git a/core/lib/utils/direction_utils.dart b/core/lib/utils/direction_utils.dart new file mode 100644 index 000000000..56d11ff80 --- /dev/null +++ b/core/lib/utils/direction_utils.dart @@ -0,0 +1,14 @@ + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' as intl; + +abstract class DirectionUtils { + + static bool isDirectionRTLByLanguage(BuildContext context) => intl.Bidi.isRtlLanguage(Localizations.localeOf(context).languageCode); + + static bool isDirectionRTLByEndsText(String text) => intl.Bidi.endsWithRtl(text); + + static TextDirection getDirectionByLanguage(BuildContext context) => isDirectionRTLByLanguage(context) ? TextDirection.rtl : TextDirection.ltr; + + static TextDirection getDirectionByEndsText(String text) => isDirectionRTLByEndsText(text) ? TextDirection.rtl : TextDirection.ltr; +} \ No newline at end of file diff --git a/core/lib/utils/platform_info.dart b/core/lib/utils/platform_info.dart index a1d932762..be125ca08 100644 --- a/core/lib/utils/platform_info.dart +++ b/core/lib/utils/platform_info.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; abstract class PlatformInfo { - static bool get isWeb => kIsWeb; + static const bool isWeb = kIsWeb; static bool get isLinux => !kIsWeb && Platform.isLinux; static bool get isWindows => !kIsWeb && Platform.isWindows; static bool get isMacOS => !kIsWeb && Platform.isMacOS; diff --git a/core/pubspec.lock b/core/pubspec.lock index cee21d210..d8896ee54 100644 --- a/core/pubspec.lock +++ b/core/pubspec.lock @@ -296,6 +296,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" + source: hosted + version: "0.17.0" js: dependency: transitive description: diff --git a/core/pubspec.yaml b/core/pubspec.yaml index b85248303..95047b9ab 100644 --- a/core/pubspec.yaml +++ b/core/pubspec.yaml @@ -70,6 +70,9 @@ dependencies: # flutter_test from sdk depends on collection 1.17.0 collection: 1.17.0 + # flutter_localizations depends on intl 0.17.0 + intl: 0.17.0 + dev_dependencies: flutter_test: sdk: flutter diff --git a/lib/features/base/widget/text_input_field_builder.dart b/lib/features/base/widget/text_input_field_builder.dart index eed04de4a..00d5e5b3d 100644 --- a/lib/features/base/widget/text_input_field_builder.dart +++ b/lib/features/base/widget/text_input_field_builder.dart @@ -1,9 +1,10 @@ import 'package:core/core.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:tmail_ui_user/features/base/widget/text_input_decoration_builder.dart'; -typedef OnChangeInputAction = Function(String? value); +typedef OnChangeInputAction = Function(String value); class TextInputFieldBuilder extends StatelessWidget { @@ -46,24 +47,23 @@ class TextInputFieldBuilder extends StatelessWidget { color: AppColor.colorContentEmail)), const SizedBox(height: 8) ], - (TextFieldBuilder() - ..onChange((value) => onChangeInputAction?.call(value)) - ..textInputAction(TextInputAction.next) - ..addController(editingController ?? TextEditingController()) - ..addFocusNode(focusNode) - ..textStyle(const TextStyle(color: Colors.black, fontSize: 16)) - ..keyboardType(inputType ?? TextInputType.text) - ..minLines(minLines) - ..maxLines(maxLines) - ..textDecoration((TextInputDecorationBuilder() - ..setContentPadding(const EdgeInsets.symmetric( - vertical: BuildUtils.isWeb ? 16 : 12, - horizontal: 12)) - ..setHintText(hint) - ..setFillColor(backgroundColor) - ..setErrorText(error)) - .build())) - .build() + TextFieldBuilder( + onTextChange: onChangeInputAction, + textInputAction: TextInputAction.next, + controller: editingController, + focusNode: focusNode, + textStyle: const TextStyle(color: Colors.black, fontSize: 16), + keyboardType: inputType ?? TextInputType.text, + textDirection: DirectionUtils.getDirectionByLanguage(context), + minLines: minLines, + maxLines: maxLines, + decoration: (TextInputDecorationBuilder() + ..setContentPadding(const EdgeInsets.symmetric(vertical: PlatformInfo.isWeb ? 16 : 12, horizontal: 12)) + ..setHintText(hint) + ..setFillColor(backgroundColor) + ..setErrorText(error)) + .build(), + ) ]); } } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_view.dart b/lib/features/composer/presentation/composer_view.dart index 2f9dea9a7..66a0a162e 100644 --- a/lib/features/composer/presentation/composer_view.dart +++ b/lib/features/composer/presentation/composer_view.dart @@ -13,6 +13,7 @@ import 'package:core/presentation/views/list/sliver_grid_delegate_fixed_height.d import 'package:core/presentation/views/responsive/responsive_widget.dart'; import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:file_picker/file_picker.dart'; import 'package:filesize/filesize.dart'; @@ -490,16 +491,17 @@ class ComposerView extends GetWidget ) ) ), - Expanded(child: (TextFieldBuilder() - ..key(const Key('subject_email_input')) - ..cursorColor(AppColor.colorTextButton) - ..maxLines(responsiveUtils.isMobile(context) ? null : 1) - ..addFocusNode(controller.subjectEmailInputFocusNode) - ..onChange((value) => controller.setSubjectEmail(value)) - ..textStyle(const TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal)) - ..textDecoration(const InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none)) - ..addController(controller.subjectEmailInputController)) - .build()) + Expanded(child: TextFieldBuilder( + key: const Key('subject_email_input'), + cursorColor: AppColor.colorTextButton, + maxLines: responsiveUtils.isMobile(context) ? null : 1, + focusNode: controller.subjectEmailInputFocusNode, + textDirection: DirectionUtils.getDirectionByLanguage(context), + onTextChange: controller.setSubjectEmail, + textStyle: const TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal), + decoration: const InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none), + controller: controller.subjectEmailInputController, + )) ] ); } diff --git a/lib/features/composer/presentation/composer_view_web.dart b/lib/features/composer/presentation/composer_view_web.dart index 5459b61b4..9698a065b 100644 --- a/lib/features/composer/presentation/composer_view_web.dart +++ b/lib/features/composer/presentation/composer_view_web.dart @@ -11,6 +11,7 @@ import 'package:core/presentation/views/image/avatar_builder.dart'; import 'package:core/presentation/views/responsive/responsive_widget.dart'; import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:file_picker/file_picker.dart'; import 'package:filesize/filesize.dart'; @@ -690,16 +691,16 @@ class ComposerView extends GetWidget ) ) ), - Expanded(child: (TextFieldBuilder() - ..key(const Key('subject_email_input')) - ..cursorColor(AppColor.colorTextButton) - ..addFocusNode(controller.subjectEmailInputFocusNode) - ..onChange((value) => controller.setSubjectEmail(value)) - ..textStyle(const TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal)) - ..textDecoration(const InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none)) - ..addController(controller.subjectEmailInputController)) - .build() - ) + Expanded(child: TextFieldBuilder( + key: const Key('subject_email_input'), + cursorColor: AppColor.colorTextButton, + focusNode: controller.subjectEmailInputFocusNode, + onTextChange: controller.setSubjectEmail, + textDirection: DirectionUtils.getDirectionByLanguage(context), + textStyle: const TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.normal), + decoration: const InputDecoration(contentPadding: EdgeInsets.zero, border: InputBorder.none), + controller: controller.subjectEmailInputController, + )) ] ); } diff --git a/lib/features/composer/presentation/widgets/insert_image_dialog_builder.dart b/lib/features/composer/presentation/widgets/insert_image_dialog_builder.dart index 17a5fd3bc..15f7d4ef1 100644 --- a/lib/features/composer/presentation/widgets/insert_image_dialog_builder.dart +++ b/lib/features/composer/presentation/widgets/insert_image_dialog_builder.dart @@ -1,6 +1,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/views/button/icon_button_web.dart'; +import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/utils/build_utils.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; @@ -101,7 +102,7 @@ class InsertImageDialogBuilder { color: Colors.black, fontWeight: FontWeight.w500)), const SizedBox(height: 10), - TextField( + TextFieldBuilder( controller: _inputUrlController, textInputAction: TextInputAction.done, decoration: InputDecoration( @@ -110,7 +111,7 @@ class InsertImageDialogBuilder { errorText: validateFailed, errorMaxLines: 2, ), - ), + ) ]), ), actionsPadding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8), diff --git a/lib/features/contact/presentation/contact_controller.dart b/lib/features/contact/presentation/contact_controller.dart index c8a543ff6..92a777ea4 100644 --- a/lib/features/contact/presentation/contact_controller.dart +++ b/lib/features/contact/presentation/contact_controller.dart @@ -91,6 +91,10 @@ class ContactController extends BaseController { _deBouncerTime.value = text; } + void onSearchTextAction(String text) { + _deBouncerTime.value = text; + } + void clearAllTextInputSearchForm() { textInputSearchController?.clear(); searchQuery.value = SearchQuery.initial(); diff --git a/lib/features/contact/presentation/contact_view.dart b/lib/features/contact/presentation/contact_view.dart index 16867f87b..66b4821f1 100644 --- a/lib/features/contact/presentation/contact_view.dart +++ b/lib/features/contact/presentation/contact_view.dart @@ -78,29 +78,29 @@ class ContactView extends GetWidget { onCloseContactView: () => controller.closeContactView(context)) ), const Divider(color: AppColor.colorDividerComposer, height: 1), - (SearchAppBarWidget( - _imagePaths, - controller.searchQuery.value, - controller.textInputSearchFocus, - controller.textInputSearchController, - hasBackButton: false, - hasSearchButton: true) - ..addPadding(EdgeInsets.zero) - ..setHeightSearchBar(44) - ..setMargin(ContactUtils.getPaddingSearchInputForm(context, _responsiveUtils)) - ..addDecoration(BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: AppColor.colorBgSearchBar)) - ..addIconClearText(SvgPicture.asset( - _imagePaths.icClearTextSearch, - width: 18, - height: 18, - fit: BoxFit.fill)) - ..setHintText(AppLocalizations.of(context).hintSearchInputContact) - ..addOnClearTextSearchAction(() => controller.clearAllTextInputSearchForm()) - ..addOnTextChangeSearchAction(controller.onTextSearchChange) - ..addOnSearchTextAction((query) => {})) - .build(), + SearchAppBarWidget( + imagePaths: _imagePaths, + searchQuery: controller.searchQuery.value, + searchFocusNode: controller.textInputSearchFocus, + searchInputController :controller.textInputSearchController, + hasBackButton: false, + hasSearchButton: true, + padding: EdgeInsets.zero, + heightSearchBar: 44, + margin: ContactUtils.getPaddingSearchInputForm(context, _responsiveUtils), + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10)), + color: AppColor.colorBgSearchBar), + iconClearText: SvgPicture.asset( + _imagePaths.icClearTextSearch, + width: 18, + height: 18, + fit: BoxFit.fill), + hintText: AppLocalizations.of(context).hintSearchInputContact, + onClearTextSearchAction: controller.clearAllTextInputSearchForm, + onTextChangeSearchAction: controller.onTextSearchChange, + onSearchTextAction: controller.onSearchTextAction, + ), Expanded(child: Obx(() { if (controller.listContactSearched.isNotEmpty) { return Container( diff --git a/lib/features/destination_picker/presentation/destination_picker_view.dart b/lib/features/destination_picker/presentation/destination_picker_view.dart index daeca91cb..f97ed040e 100644 --- a/lib/features/destination_picker/presentation/destination_picker_view.dart +++ b/lib/features/destination_picker/presentation/destination_picker_view.dart @@ -8,6 +8,7 @@ import 'package:core/presentation/views/list/tree_view.dart'; import 'package:core/presentation/views/search/search_bar_view.dart'; import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/utils/build_utils.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; @@ -171,23 +172,24 @@ class DestinationPickerView extends GetWidget Widget _buildCreateMailboxNameInput(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), - child: Obx(() => (TextFieldBuilder() - ..key(const Key('create_mailbox_name_input')) - ..onChange((value) => controller.setNewNameMailbox(value)) - ..keyboardType(TextInputType.visiblePassword) - ..cursorColor(AppColor.colorTextButton) - ..addController(controller.nameInputController) - ..maxLines(1) - ..textStyle(const TextStyle( - color: AppColor.colorNameEmail, - fontSize: 16, - overflow: CommonTextStyle.defaultTextOverFlow)) - ..addFocusNode(controller.nameInputFocusNode) - ..textDecoration((CreateMailboxNameInputDecorationBuilder() - ..setHintText(AppLocalizations.of(context).hint_input_create_new_mailbox) - ..setErrorText(controller.getErrorInputNameString(context))) - .build())) - .build()) + child: Obx(() => TextFieldBuilder( + key: const Key('create_mailbox_name_input'), + onTextChange: controller.setNewNameMailbox, + keyboardType: TextInputType.visiblePassword, + cursorColor: AppColor.colorTextButton, + controller: controller.nameInputController, + textDirection: DirectionUtils.getDirectionByLanguage(context), + maxLines: 1, + textStyle: const TextStyle( + color: AppColor.colorNameEmail, + fontSize: 16, + overflow: CommonTextStyle.defaultTextOverFlow), + focusNode: controller.nameInputFocusNode, + decoration: (CreateMailboxNameInputDecorationBuilder() + ..setHintText(AppLocalizations.of(context).hint_input_create_new_mailbox) + ..setErrorText(controller.getErrorInputNameString(context))) + .build(), + )) ); } @@ -554,25 +556,30 @@ class DestinationPickerView extends GetWidget colorFilter: AppColor.colorTextButton.asFilter(), fit: BoxFit.fill), onTap: () => controller.disableSearch(context))), - Expanded(child: (SearchAppBarWidget( - _imagePaths, - controller.searchQuery.value, - controller.searchFocus, - controller.searchInputController, - hasBackButton: false, - hasSearchButton: true) - ..addPadding(EdgeInsets.zero) - ..setMargin(EdgeInsets.only( - right: AppUtils.isDirectionRTL(context) ? 0 : 16, - left: AppUtils.isDirectionRTL(context) ? 16 : 0, - )) - ..addDecoration(BoxDecoration(borderRadius: BorderRadius.circular(12), color: AppColor.colorBgSearchBar)) - ..addIconClearText(SvgPicture.asset(_imagePaths.icClearTextSearch, width: 18, height: 18, fit: BoxFit.fill)) - ..setHintText(AppLocalizations.of(context).hint_search_mailboxes) - ..addOnClearTextSearchAction(() => controller.clearSearchText()) - ..addOnTextChangeSearchAction((query) => controller.searchMailbox(query)) - ..addOnSearchTextAction((query) => controller.searchMailbox(query))) - .build()) + Expanded(child: SearchAppBarWidget( + imagePaths: _imagePaths, + searchQuery: controller.searchQuery.value, + searchFocusNode: controller.searchFocus, + searchInputController: controller.searchInputController, + hasBackButton: false, + hasSearchButton: true, + padding: EdgeInsets.zero, + margin: EdgeInsets.only( + right: DirectionUtils.isDirectionRTLByLanguage(context) ? 0 : 16, + left: DirectionUtils.isDirectionRTLByLanguage(context) ? 16 : 0), + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(12)), + color: AppColor.colorBgSearchBar), + iconClearText: SvgPicture.asset( + _imagePaths.icClearTextSearch, + width: 18, + height: 18, + fit: BoxFit.fill), + hintText: AppLocalizations.of(context).hint_search_mailboxes, + onClearTextSearchAction: controller.clearSearchText, + onTextChangeSearchAction: controller.searchMailbox, + onSearchTextAction: controller.searchMailbox, + )) ] ) ); diff --git a/lib/features/identity_creator/presentation/widgets/identity_input_field_builder.dart b/lib/features/identity_creator/presentation/widgets/identity_input_field_builder.dart index db313e9c7..76e2dab1a 100644 --- a/lib/features/identity_creator/presentation/widgets/identity_input_field_builder.dart +++ b/lib/features/identity_creator/presentation/widgets/identity_input_field_builder.dart @@ -1,7 +1,8 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/views/text/text_field_builder.dart'; -import 'package:core/utils/build_utils.dart'; +import 'package:core/utils/direction_utils.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:tmail_ui_user/features/identity_creator/presentation/widgets/identity_input_decoration_builder.dart'; @@ -41,21 +42,20 @@ class IdentityInputFieldBuilder extends StatelessWidget { fontWeight: FontWeight.w500, color: AppColor.colorContentEmail)), const SizedBox(height: 8), - (TextFieldBuilder() - ..onChange((value) => onChangeInputNameAction?.call(value)) - ..textInputAction(TextInputAction.next) - ..addController(editingController ?? TextEditingController()) - ..autoFocus(true) - ..addFocusNode(focusNode) - ..textStyle(const TextStyle(color: Colors.black, fontSize: 16)) - ..keyboardType(inputType ?? TextInputType.text) - ..textDecoration((IdentityInputDecorationBuilder() - ..setContentPadding(const EdgeInsets.symmetric( - vertical: BuildUtils.isWeb ? 16 : 12, - horizontal: 12)) - ..setErrorText(_error)) - .build())) - .build() + TextFieldBuilder( + onTextChange: onChangeInputNameAction, + textInputAction: TextInputAction.next, + autoFocus: true, + textDirection: DirectionUtils.getDirectionByLanguage(context), + controller: editingController, + focusNode: focusNode, + textStyle: const TextStyle(color: Colors.black, fontSize: 16), + keyboardType: inputType ?? TextInputType.text, + decoration: (IdentityInputDecorationBuilder() + ..setContentPadding(const EdgeInsets.symmetric(vertical: PlatformInfo.isWeb ? 16 : 12,horizontal: 12)) + ..setErrorText(_error)) + .build(), + ) ]); } } \ No newline at end of file diff --git a/lib/features/login/presentation/base_login_view.dart b/lib/features/login/presentation/base_login_view.dart index f91cd79e6..24ec73b39 100644 --- a/lib/features/login/presentation/base_login_view.dart +++ b/lib/features/login/presentation/base_login_view.dart @@ -1,7 +1,6 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; -import 'package:core/presentation/views/text/text_builder.dart'; import 'package:flutter/material.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:get/get.dart'; @@ -30,9 +29,8 @@ abstract class BaseLoginView extends GetWidget { padding: const EdgeInsets.only(top: 11, bottom: 36, left: 58, right: 58), child: SizedBox( width: responsiveUtils.getWidthLoginTextField(context), - child: CenterTextBuilder() - .key(const Key('login_message')) - .text(loginState.viewState.fold( + child: Text( + loginState.viewState.fold( (failure) { if (failure is LoginMissUrlAction) { return AppLocalizations.of(context).requiredUrl; @@ -43,7 +41,7 @@ abstract class BaseLoginView extends GetWidget { } else if (failure is LoginSSONotAvailableAction) { return AppLocalizations.of(context).ssoNotAvailable; } else if (failure is GetOIDCConfigurationFailure - || failure is LoginCanNotVerifySSOConfigurationAction) { + || failure is LoginCanNotVerifySSOConfigurationAction) { return AppLocalizations.of(context).canNotVerifySSOConfiguration; } else if (failure is GetTokenOIDCFailure || failure is LoginCanNotGetTokenAction) { return AppLocalizations.of(context).canNotGetToken; @@ -58,15 +56,16 @@ abstract class BaseLoginView extends GetWidget { return AppLocalizations.of(context).loginInputSSOMessage; } return AppLocalizations.of(context).loginInputUrlMessage; - })) - .textStyle(TextStyle( - fontSize: 15, - fontWeight: FontWeight.w400, - color: loginState.viewState.fold( - (failure) => AppColor.textFieldErrorBorderColor, - (success) => AppColor.colorNameEmail))) - .build() - ) + }), + key: const Key('login_message'), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w400, + color: loginState.viewState.fold( + (failure) => AppColor.textFieldErrorBorderColor, + (success) => AppColor.colorNameEmail)), + )) ); } diff --git a/lib/features/mailbox_creator/presentation/mailbox_creator_view.dart b/lib/features/mailbox_creator/presentation/mailbox_creator_view.dart index 3b939142f..bddcf4f23 100644 --- a/lib/features/mailbox_creator/presentation/mailbox_creator_view.dart +++ b/lib/features/mailbox_creator/presentation/mailbox_creator_view.dart @@ -4,6 +4,7 @@ import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/utils/style_utils.dart'; import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/utils/build_utils.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; @@ -112,23 +113,24 @@ class MailboxCreatorView extends GetWidget { Widget _buildCreateMailboxNameInput(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), - child: Obx(() => (TextFieldBuilder() - ..key(const Key('create_mailbox_name_input')) - ..onChange((value) => controller.setNewNameMailbox(value)) - ..keyboardType(TextInputType.visiblePassword) - ..cursorColor(AppColor.colorTextButton) - ..addController(controller.nameInputController) - ..maxLines(1) - ..textStyle(const TextStyle( - color: AppColor.colorNameEmail, - fontSize: 16, - overflow: CommonTextStyle.defaultTextOverFlow)) - ..addFocusNode(controller.nameInputFocusNode) - ..textDecoration((CreateMailboxNameInputDecorationBuilder() - ..setHintText(AppLocalizations.of(context).hint_input_create_new_mailbox) - ..setErrorText(controller.getErrorInputNameString(context))) - .build())) - .build()) + child: Obx(() => TextFieldBuilder( + key: const Key('create_mailbox_name_input'), + onTextChange: controller.setNewNameMailbox, + keyboardType: TextInputType.visiblePassword, + cursorColor: AppColor.colorTextButton, + controller: controller.nameInputController, + textDirection: DirectionUtils.getDirectionByLanguage(context), + maxLines: 1, + textStyle: const TextStyle( + color: AppColor.colorNameEmail, + fontSize: 16, + overflow: CommonTextStyle.defaultTextOverFlow), + focusNode: controller.nameInputFocusNode, + decoration: (CreateMailboxNameInputDecorationBuilder() + ..setHintText(AppLocalizations.of(context).hint_input_create_new_mailbox) + ..setErrorText(controller.getErrorInputNameString(context))) + .build(), + )) ); } diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart index 0f10f6af1..6c1fa6ac4 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form.dart @@ -356,13 +356,13 @@ class AdvancedSearchInputForm extends GetWidget nextFocusNode?.requestFocus(); } }, - child: TextField( + child: TextFieldBuilder( controller: textEditingController, readOnly: isSelectFormList, mouseCursor: mouseCursor, textInputAction: isSelectFormList ? TextInputAction.done : TextInputAction.next, onTap: onTap, - onSubmitted: (value) { + onTextSubmitted: (value) { if (isSelectFormList) { onTap?.call(); } else { diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart index 739d95fee..492f4c2d0 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart @@ -1,5 +1,11 @@ import 'package:collection/collection.dart'; -import 'package:core/core.dart'; +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/presentation/utils/style_utils.dart'; +import 'package:core/presentation/views/text/text_field_builder.dart'; +import 'package:core/utils/app_logger.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -66,8 +72,8 @@ class _TextFieldAutoCompleteEmailAddressState optionsViewBuilder: (context, onSelected, listEmailAddress) { return Container( margin: const EdgeInsets.only( - top: BuildUtils.isWeb ? 5 : 8, - bottom: 16), + top: PlatformInfo.isWeb ? 5 : 8, + bottom: 16), height: _getHeightSuggestionBox(listEmailAddress.length, 65), width: maxWidthSuggestionBox, alignment: Alignment.topLeft, @@ -134,7 +140,7 @@ class _TextFieldAutoCompleteEmailAddressState widget.nextFocusNode?.requestFocus(); } }, - child: TextField( + child: TextFieldBuilder( controller: tec, focusNode: fn, textInputAction: TextInputAction.next, @@ -180,12 +186,12 @@ class _TextFieldAutoCompleteEmailAddressState ) : null, ), - onChanged: (value) { + onTextChange: (value) { if (value.trim().isNotEmpty) { onChanged?.call(value); } }, - onSubmitted: (tag) { + onTextSubmitted: (tag) { if (tag.trim().isNotEmpty) { onSubmitted?.call(tag); fn.requestFocus(); @@ -334,7 +340,7 @@ class _TextFieldAutoCompleteEmailAddressState double _getHeightSuggestionBox(int countItem, double heightItem) { final maxHeightList = countItem * heightItem; - if (BuildUtils.isWeb) { + if (PlatformInfo.isWeb) { return maxHeightList > 250 ? 250 : maxHeightList; } else { if (_responsiveUtils.isLandscapeMobile(context)) { @@ -346,7 +352,7 @@ class _TextFieldAutoCompleteEmailAddressState } double get maxWidthSuggestionBox { - if (BuildUtils.isWeb) { + if (PlatformInfo.isWeb) { if (_responsiveUtils.isTabletLarge(context)) { return 300; } else { diff --git a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart index bf950732d..6ffd8fdc7 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart @@ -4,6 +4,7 @@ import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/style_utils.dart'; import 'package:core/presentation/views/button/icon_button_web.dart'; import 'package:core/presentation/views/quick_search/quick_search_input_form.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -186,6 +187,7 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { controller: controller.searchInputController, focusNode: controller.searchFocus, textInputAction: TextInputAction.done, + textDirection: DirectionUtils.getDirectionByLanguage(context), onSubmitted: (keyword) => _invokeSearchEmailAction(context, keyword.trim()), decoration: InputDecoration( border: InputBorder.none, diff --git a/lib/features/manage_account/presentation/vacation/vacation_view.dart b/lib/features/manage_account/presentation/vacation/vacation_view.dart index 202befe00..ab185c246 100644 --- a/lib/features/manage_account/presentation/vacation/vacation_view.dart +++ b/lib/features/manage_account/presentation/vacation/vacation_view.dart @@ -1,6 +1,7 @@ import 'package:core/core.dart'; import 'package:core/presentation/utils/html_transformer/html_utils.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; @@ -409,22 +410,21 @@ class VacationView extends GetWidget with RichTextButtonMixi } Widget _buildMessagePlainTextEditor(BuildContext context) { - return (TextFieldBuilder() - ..onChange((value) => controller.updateMessageBody(context, value)) - ..keyboardType(TextInputType.multiline) - ..addController(controller.messageTextController) - ..textStyle(const TextStyle(color: Colors.black, fontSize: 16)) - ..minLines(10) - ..maxLines(null) - ..textDecoration((TextInputDecorationBuilder() + return TextFieldBuilder( + onTextChange: (value) => controller.updateMessageBody(context, value), + keyboardType: TextInputType.multiline, + controller: controller.messageTextController, + textStyle: const TextStyle(color: Colors.black, fontSize: 16), + textDirection: DirectionUtils.getDirectionByLanguage(context), + minLines: 10, + maxLines: null, + decoration: (TextInputDecorationBuilder() ..setContentPadding(const EdgeInsets.all(16)) ..setHintText(AppLocalizations.of(context).hintMessageBodyVacation) ..setFillColor(Colors.white) - ..setErrorText(controller.isVacationDeactivated - ? null - : controller.errorMessageBody.value)) - .build())) - .build(); + ..setErrorText(controller.isVacationDeactivated ? null : controller.errorMessageBody.value)) + .build(), + ); } Widget _buildMessageHtmlTextEditor(BuildContext context) { diff --git a/lib/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart b/lib/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart index 01bbe2d4b..d9634962e 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart @@ -1,6 +1,7 @@ import 'package:core/presentation/views/text/text_field_builder.dart'; -import 'package:core/utils/build_utils.dart'; +import 'package:core/utils/direction_utils.dart'; +import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rules_filter_input_decoration_builder.dart'; @@ -25,20 +26,19 @@ class RulesFilterInputField extends StatelessWidget { @override Widget build(BuildContext context) { - return (TextFieldBuilder() - ..onChange((value) => onChangeAction?.call(value)) - ..textInputAction(TextInputAction.next) - ..addController(editingController ?? TextEditingController()) - ..textStyle(const TextStyle(color: Colors.black, fontSize: 16)) - ..keyboardType(TextInputType.text) - ..addFocusNode(focusNode) - ..textDecoration((RulesFilterInputDecorationBuilder() - ..setContentPadding(const EdgeInsets.symmetric( - vertical: BuildUtils.isWeb ? 16 : 12, - horizontal: 12)) - ..setHintText(hintText) - ..setErrorText(errorText)) - .build())) - .build(); + return TextFieldBuilder( + onTextChange: onChangeAction, + textInputAction: TextInputAction.next, + controller: editingController, + textStyle: const TextStyle(color: Colors.black, fontSize: 16), + textDirection: DirectionUtils.getDirectionByLanguage(context), + keyboardType: TextInputType.text, + focusNode: focusNode, + decoration: (RulesFilterInputDecorationBuilder() + ..setContentPadding(const EdgeInsets.symmetric(vertical: PlatformInfo.isWeb ? 16 : 12, horizontal: 12)) + ..setHintText(hintText) + ..setErrorText(errorText)) + .build(), + ); } } \ No newline at end of file diff --git a/lib/features/search/email/presentation/search_email_controller.dart b/lib/features/search/email/presentation/search_email_controller.dart index 4a092fbef..ce6e276c2 100644 --- a/lib/features/search/email/presentation/search_email_controller.dart +++ b/lib/features/search/email/presentation/search_email_controller.dart @@ -642,6 +642,14 @@ class SearchEmailController extends BaseController _deBouncerTime.value = text; } + void onTextSearchSubmitted(BuildContext context, String text) { + final query = text.trim(); + if (query.isNotEmpty) { + saveRecentSearch(RecentSearch.now(query)); + submitSearchAction(context, query); + } + } + void setTextInputSearchForm(String value) { textInputSearchController.text = value; } diff --git a/lib/features/search/email/presentation/search_email_view.dart b/lib/features/search/email/presentation/search_email_view.dart index 8babdc7a2..08259ad1e 100644 --- a/lib/features/search/email/presentation/search_email_view.dart +++ b/lib/features/search/email/presentation/search_email_view.dart @@ -7,6 +7,7 @@ import 'package:core/presentation/views/background/background_widget_builder.dar import 'package:core/presentation/views/button/icon_button_web.dart'; import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/utils/build_utils.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; @@ -117,29 +118,21 @@ class SearchEmailView extends GetWidget tooltip: AppLocalizations.of(context).back, onTap: () => controller.closeSearchView(context) ), - Expanded(child: (TextFieldBuilder() - ..onChange(controller.onTextSearchChange) - ..textInputAction(TextInputAction.search) - ..addController(controller.textInputSearchController) - ..addFocusNode(controller.textInputSearchFocus) - ..textStyle(const TextStyle(color: Colors.black, fontSize: 16)) - ..keyboardType(TextInputType.text) - ..onSubmitted((value) { - final query = value.trim(); - if (query.isNotEmpty) { - controller.saveRecentSearch(RecentSearch.now(query)); - controller.submitSearchAction(context, query); - } - }) - ..maxLines(1) - ..textDecoration(InputDecoration( - contentPadding: const EdgeInsets.all(12), - hintText: AppLocalizations.of(context).search_emails, - hintStyle: const TextStyle( - color: AppColor.loginTextFieldHintColor, - fontSize: 16), - border: InputBorder.none))) - .build()), + Expanded(child: TextFieldBuilder( + onTextChange: controller.onTextSearchChange, + textInputAction: TextInputAction.search, + controller: controller.textInputSearchController, + focusNode: controller.textInputSearchFocus, + textDirection: DirectionUtils.getDirectionByLanguage(context), + textStyle: const TextStyle(color: Colors.black, fontSize: 16), + keyboardType: TextInputType.text, + onTextSubmitted: (text) => controller.onTextSearchSubmitted(context, text), + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(12), + hintText: AppLocalizations.of(context).search_emails, + hintStyle: const TextStyle(color: AppColor.loginTextFieldHintColor, fontSize: 16), + border: InputBorder.none), + )), Obx(() { if (controller.currentSearchText.isNotEmpty) { return diff --git a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart index aae346434..4935926ec 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart @@ -207,6 +207,13 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa _deBouncerTime.value = text; } + void onTextSearchSubmitted(BuildContext context, String text) { + final query = text.trim(); + if (query.isNotEmpty) { + submitSearchAction(context, query); + } + } + void setTextInputSearchForm(String value) { textInputSearchController.text = value; } diff --git a/lib/features/search/mailbox/presentation/search_mailbox_view.dart b/lib/features/search/mailbox/presentation/search_mailbox_view.dart index be67ba063..dbaa2ffc5 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_view.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_view.dart @@ -3,6 +3,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/views/button/icon_button_web.dart'; import 'package:core/presentation/views/text/text_field_builder.dart'; import 'package:core/utils/build_utils.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:focused_menu_custom/modals.dart'; @@ -138,33 +139,28 @@ class SearchMailboxView extends GetWidget } Widget _buildTextFieldSearchInput(BuildContext context) { - return (TextFieldBuilder() - ..onChange(controller.onTextSearchChange) - ..textInputAction(TextInputAction.search) - ..autoFocus(true) - ..addController(controller.textInputSearchController) - ..textStyle(const TextStyle( - color: Colors.black, + return TextFieldBuilder( + onTextChange: controller.onTextSearchChange, + textInputAction: TextInputAction.search, + autoFocus: true, + controller: controller.textInputSearchController, + textDirection: DirectionUtils.getDirectionByLanguage(context), + textStyle: const TextStyle( + color: Colors.black, + fontSize: 15, + fontWeight: FontWeight.normal), + keyboardType: TextInputType.text, + onTextSubmitted: (text) => controller.onTextSearchSubmitted(context, text), + decoration: InputDecoration( + contentPadding: EdgeInsets.zero, + hintText: AppLocalizations.of(context).searchForMailboxes, + hintStyle: const TextStyle( + color: AppColor.loginTextFieldHintColor, fontSize: 15, - fontWeight: FontWeight.normal)) - ..keyboardType(TextInputType.text) - ..onSubmitted((value) { - final query = value.trim(); - if (query.isNotEmpty) { - controller.submitSearchAction(context, query); - } - }) - ..maxLines(1) - ..textDecoration(InputDecoration( - contentPadding: EdgeInsets.zero, - hintText: AppLocalizations.of(context).searchForMailboxes, - hintStyle: const TextStyle( - color: AppColor.loginTextFieldHintColor, - fontSize: 15, - fontWeight: FontWeight.normal), - border: InputBorder.none - ) - )).build(); + fontWeight: FontWeight.normal), + border: InputBorder.none + ), + ); } Widget _buildMailboxListView(BuildContext context) { diff --git a/lib/features/thread/presentation/widgets/search_app_bar_widget.dart b/lib/features/thread/presentation/widgets/search_app_bar_widget.dart index 8933397d4..510b26edd 100644 --- a/lib/features/thread/presentation/widgets/search_app_bar_widget.dart +++ b/lib/features/thread/presentation/widgets/search_app_bar_widget.dart @@ -1,5 +1,9 @@ -import 'package:core/core.dart'; +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/views/button/icon_button_web.dart'; +import 'package:core/presentation/views/text/text_field_builder.dart'; +import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; @@ -9,93 +13,61 @@ typedef OnClearTextSearchAction = Function(); typedef OnTextChangeSearchAction = Function(String); typedef OnSearchTextAction = Function(String); -class SearchAppBarWidget { - OnCancelSearchPressed? _onCancelSearchPressed; - OnTextChangeSearchAction? _onTextChangeSearchAction; - OnClearTextSearchAction? _onClearTextSearchAction; - OnSearchTextAction? _onSearchTextAction; +class SearchAppBarWidget extends StatelessWidget { - final ImagePaths _imagePaths; - final SearchQuery? _searchQuery; - final TextEditingController? _searchInputController; - final FocusNode? _searchFocusNode; + final ImagePaths imagePaths; + final SearchQuery? searchQuery; + final TextEditingController? searchInputController; + final FocusNode? searchFocusNode; final List? suggestionSearch; final bool hasBackButton; final bool hasSearchButton; + final double? heightSearchBar; + final Decoration? decoration; + final EdgeInsets? padding; + final EdgeInsets? margin; + final String? hintText; + final Widget? iconClearText; + final OnCancelSearchPressed? onCancelSearchPressed; + final OnTextChangeSearchAction? onTextChangeSearchAction; + final OnClearTextSearchAction? onClearTextSearchAction; + final OnSearchTextAction? onSearchTextAction; - double? _heightSearchBar; - Decoration? _decoration; - EdgeInsets? _padding; - EdgeInsets? _margin; - String? _hintText; - Widget? _iconClearText; + const SearchAppBarWidget({ + super.key, + required this.imagePaths, + required this.hasBackButton, + required this.hasSearchButton, + this.searchQuery, + this.searchInputController, + this.searchFocusNode, + this.suggestionSearch, + this.heightSearchBar, + this.decoration, + this.padding, + this.margin, + this.hintText, + this.iconClearText, + this.onCancelSearchPressed, + this.onTextChangeSearchAction, + this.onClearTextSearchAction, + this.onSearchTextAction + }); - SearchAppBarWidget( - this._imagePaths, - this._searchQuery, - this._searchFocusNode, - this._searchInputController, - { - this.hasBackButton = true, - this.suggestionSearch, - this.hasSearchButton = false, - } - ); - - void addOnCancelSearchPressed(OnCancelSearchPressed onCancelSearchPressed) { - _onCancelSearchPressed = onCancelSearchPressed; - } - - void addOnTextChangeSearchAction(OnTextChangeSearchAction onTextChangeSearchAction) { - _onTextChangeSearchAction = onTextChangeSearchAction; - } - - void addOnClearTextSearchAction(OnClearTextSearchAction onClearTextSearchAction) { - _onClearTextSearchAction = onClearTextSearchAction; - } - - void addOnSearchTextAction(OnSearchTextAction onSearchTextAction) { - _onSearchTextAction = onSearchTextAction; - } - - void setHeightSearchBar(double heightSearchBar) { - _heightSearchBar = heightSearchBar; - } - - void addDecoration(Decoration decoration) { - _decoration = decoration; - } - - void addPadding(EdgeInsets padding) { - _padding = padding; - } - - void setMargin(EdgeInsets margin) { - _margin = margin; - } - - void setHintText(String text) { - _hintText = text; - } - - void addIconClearText(Widget? icon) { - _iconClearText = icon; - } - - Widget build() { + @override + Widget build(BuildContext context) { return Container( - key: const Key('search_app_bar_widget'), - height: _heightSearchBar, - decoration: _decoration, - padding: _padding ?? EdgeInsets.zero, - margin: _margin, + key: key ?? const Key('search_app_bar_widget'), + height: heightSearchBar, + decoration: decoration, + padding: padding ?? EdgeInsets.zero, + margin: margin, child: Row( children: [ if (hasBackButton) _buildBackButton(), if (hasSearchButton) _buildSearchButton(), - Expanded(child: _buildSearchInputForm()), - if (suggestionSearch?.isNotEmpty == true - || (_searchQuery != null && _searchQuery!.value.isNotEmpty)) + Expanded(child: _buildSearchInputForm(context)), + if (suggestionSearch?.isNotEmpty == true || (searchQuery != null && searchQuery!.value.isNotEmpty)) _buildClearTextSearchButton(), ] ) @@ -104,47 +76,48 @@ class SearchAppBarWidget { Widget _buildBackButton() { return buildIconWeb( - icon: SvgPicture.asset( - _imagePaths.icBack, - colorFilter: AppColor.colorTextButton.asFilter(), - fit: BoxFit.fill), - onTap: () { - _searchInputController?.clear(); - if (_onCancelSearchPressed != null) { - _onCancelSearchPressed!(); - } - }); + icon: SvgPicture.asset( + imagePaths.icBack, + colorFilter: AppColor.colorTextButton.asFilter(), + fit: BoxFit.fill), + onTap: () { + searchInputController?.clear(); + if (onCancelSearchPressed != null) { + onCancelSearchPressed!(); + } + }); } Widget _buildClearTextSearchButton() { return buildIconWeb( - icon: _iconClearText ?? SvgPicture.asset(_imagePaths.icComposerClose, width: 18, height: 18, fit: BoxFit.fill), - onTap: () { - _searchInputController?.clear(); - _onClearTextSearchAction?.call(); - }); + icon: iconClearText ?? SvgPicture.asset(imagePaths.icComposerClose, width: 18, height: 18, fit: BoxFit.fill), + onTap: () { + searchInputController?.clear(); + onClearTextSearchAction?.call(); + }); } - Widget _buildSearchInputForm() { - return (TextFieldBuilder() - ..key(const Key('search_input_form')) - ..textInputAction(TextInputAction.done) - ..onChange((value) => _onTextChangeSearchAction?.call(value)) - ..onSubmitted((value) => _onSearchTextAction?.call(value)) - ..cursorColor(AppColor.colorTextButton) - ..autoFocus(true) - ..addFocusNode(_searchFocusNode) - ..textStyle(const TextStyle(color: AppColor.colorNameEmail, fontSize: 17)) - ..textDecoration(InputDecoration( - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - contentPadding: EdgeInsets.zero, - hintText: _hintText, - hintStyle: const TextStyle(color: AppColor.colorHintSearchBar, fontSize: 17.0), - labelStyle: const TextStyle(color: AppColor.colorHintSearchBar, fontSize: 17.0))) - ..addController(_searchInputController)) - .build(); + Widget _buildSearchInputForm(BuildContext context) { + return TextFieldBuilder( + key: const Key('search_input_form'), + textInputAction: TextInputAction.done, + onTextChange: onTextChangeSearchAction, + onTextSubmitted: onSearchTextAction, + cursorColor: AppColor.colorTextButton, + textDirection: DirectionUtils.getDirectionByLanguage(context), + autoFocus: true, + focusNode: searchFocusNode, + textStyle: const TextStyle(color: AppColor.colorNameEmail, fontSize: 17), + decoration: InputDecoration( + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + contentPadding: EdgeInsets.zero, + hintText: hintText, + hintStyle: const TextStyle(color: AppColor.colorHintSearchBar, fontSize: 17.0), + labelStyle: const TextStyle(color: AppColor.colorHintSearchBar, fontSize: 17.0)), + controller: searchInputController, + ); } Widget _buildSearchButton() { @@ -154,10 +127,10 @@ class SearchAppBarWidget { minSize: 40, iconPadding: EdgeInsets.zero, icon: SvgPicture.asset( - _imagePaths.icSearchBar, + imagePaths.icSearchBar, fit: BoxFit.fill ), - onTap: () => _onSearchTextAction?.call(_searchInputController?.text ?? '') + onTap: () => onSearchTextAction?.call(searchInputController?.text ?? '') ), ); }