TF-1884 Support RTL mode for TextField
(cherry picked from commit 3f8445141bea9dbf276a6a336114e4e2b549936f)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user