TF-1884 Support RTL mode for TextField

(cherry picked from commit 3f8445141bea9dbf276a6a336114e4e2b549936f)
This commit is contained in:
dab246
2023-06-14 11:47:13 +07:00
committed by Dat H. Pham
parent 0cc2a2f0cc
commit df19b979a2
28 changed files with 500 additions and 485 deletions
-1
View File
@@ -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';
@@ -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<T, R> extends State<TypeAheadFieldQuickSea
FocusNode? _focusNode;
TextEditingController? _textEditingController;
_SuggestionsBox? _suggestionsBox;
late TextDirection _textDirection;
TextEditingController? get _effectiveController =>
widget.textFieldConfiguration.controller ?? _textEditingController;
@@ -622,6 +624,8 @@ class _TypeAheadFieldQuickSearchState<T, R> extends State<TypeAheadFieldQuickSea
super.initState();
WidgetsBinding.instance.addObserver(this);
_textDirection = widget.textFieldConfiguration.textDirection ?? TextDirection.ltr;
if (widget.textFieldConfiguration.controller == null) {
_textEditingController = TextEditingController();
}
@@ -840,7 +844,17 @@ class _TypeAheadFieldQuickSearchState<T, R> extends State<TypeAheadFieldQuickSea
maxLength: widget.textFieldConfiguration.maxLength,
maxLengthEnforcement: widget.textFieldConfiguration.maxLengthEnforcement,
obscureText: widget.textFieldConfiguration.obscureText,
onChanged: widget.textFieldConfiguration.onChanged,
onChanged: (input) {
widget.textFieldConfiguration.onChanged?.call(input);
if (input.isNotEmpty) {
final directionByText = DirectionUtils.getDirectionByEndsText(input);
if (directionByText != _textDirection) {
setState(() {
_textDirection = directionByText;
});
}
}
},
onSubmitted: widget.textFieldConfiguration.onSubmitted,
onEditingComplete: widget.textFieldConfiguration.onEditingComplete,
onTap: widget.textFieldConfiguration.onTap,
@@ -851,9 +865,8 @@ class _TypeAheadFieldQuickSearchState<T, R> extends State<TypeAheadFieldQuickSea
cursorWidth: widget.textFieldConfiguration.cursorWidth,
cursorRadius: widget.textFieldConfiguration.cursorRadius,
cursorColor: widget.textFieldConfiguration.cursorColor,
textDirection: widget.textFieldConfiguration.textDirection,
enableInteractiveSelection:
widget.textFieldConfiguration.enableInteractiveSelection,
textDirection: _textDirection,
enableInteractiveSelection: widget.textFieldConfiguration.enableInteractiveSelection,
readOnly: widget.hideKeyboard,
),
),
@@ -1,40 +0,0 @@
import 'package:core/presentation/utils/style_utils.dart';
import 'package:flutter/material.dart';
class TextBuilder {
String? _text;
TextStyle? _textStyle;
TextAlign? _textAlign;
Key? _key;
TextBuilder key(Key key) {
_key = key;
return this;
}
TextBuilder text(String text) {
_text = text;
return this;
}
TextBuilder textStyle(TextStyle textStyle) {
_textStyle = textStyle;
return this;
}
TextBuilder textAlign(TextAlign textAlign) {
_textAlign = textAlign;
return this;
}
Text build() {
return Text(_text ?? '', key: _key ?? const Key('TextBuilder'), style: _textStyle ?? CommonTextStyle.textStyleNormal, textAlign: _textAlign ?? TextAlign.center);
}
}
class CenterTextBuilder extends TextBuilder {
@override
Text build() {
return Text(_text ?? '', key: _key ?? const Key('TextBuilder'), style: _textStyle, textAlign: TextAlign.center);
}
}
@@ -1,100 +1,117 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/utils/direction_utils.dart';
import 'package:flutter/material.dart';
class TextFieldBuilder {
Key? _key;
ValueChanged<String>? _onTextChange;
ValueChanged<String>? _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<String>? onTextChange;
final ValueChanged<String>? 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<TextFieldBuilder> createState() => _TextFieldBuilderState();
}
class _TextFieldBuilderState extends State<TextFieldBuilder> {
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<String> onChange) {
_onTextChange = onChange;
}
void onSubmitted(ValueChanged<String> 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();
}
}
+14
View File
@@ -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;
}
+1 -1
View File
@@ -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;
+8
View File
@@ -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:
+3
View File
@@ -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