Unverified Commit c06bf650 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

iOS smart quote/dash configuration (#44923)

smartDashesType and smartQuotesType params for text fields to control iOS's smart punctuation feature.
parent 1bca434c
...@@ -12,7 +12,7 @@ import 'icons.dart'; ...@@ -12,7 +12,7 @@ import 'icons.dart';
import 'text_selection.dart'; import 'text_selection.dart';
import 'theme.dart'; import 'theme.dart';
export 'package:flutter/services.dart' show TextInputType, TextInputAction, TextCapitalization; export 'package:flutter/services.dart' show TextInputType, TextInputAction, TextCapitalization, SmartQuotesType, SmartDashesType;
// Value inspected from Xcode 11 & iOS 13.0 Simulator. // Value inspected from Xcode 11 & iOS 13.0 Simulator.
const BorderSide _kDefaultRoundedBorderSide = BorderSide( const BorderSide _kDefaultRoundedBorderSide = BorderSide(
...@@ -198,8 +198,8 @@ class CupertinoTextField extends StatefulWidget { ...@@ -198,8 +198,8 @@ class CupertinoTextField extends StatefulWidget {
/// ///
/// The [autocorrect], [autofocus], [clearButtonMode], [dragStartBehavior], /// The [autocorrect], [autofocus], [clearButtonMode], [dragStartBehavior],
/// [expands], [maxLengthEnforced], [obscureText], [prefixMode], [readOnly], /// [expands], [maxLengthEnforced], [obscureText], [prefixMode], [readOnly],
/// [scrollPadding], [suffixMode], [textAlign], and [enableSuggestions] properties /// [scrollPadding], [suffixMode], [textAlign], and [enableSuggestions]
/// must not be null. /// properties must not be null.
/// ///
/// See also: /// See also:
/// ///
...@@ -236,6 +236,8 @@ class CupertinoTextField extends StatefulWidget { ...@@ -236,6 +236,8 @@ class CupertinoTextField extends StatefulWidget {
this.autofocus = false, this.autofocus = false,
this.obscureText = false, this.obscureText = false,
this.autocorrect = true, this.autocorrect = true,
SmartDashesType smartDashesType,
SmartQuotesType smartQuotesType,
this.enableSuggestions = true, this.enableSuggestions = true,
this.maxLines = 1, this.maxLines = 1,
this.minLines, this.minLines,
...@@ -262,6 +264,8 @@ class CupertinoTextField extends StatefulWidget { ...@@ -262,6 +264,8 @@ class CupertinoTextField extends StatefulWidget {
assert(autofocus != null), assert(autofocus != null),
assert(obscureText != null), assert(obscureText != null),
assert(autocorrect != null), assert(autocorrect != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
smartQuotesType = smartQuotesType ?? (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled),
assert(enableSuggestions != null), assert(enableSuggestions != null),
assert(maxLengthEnforced != null), assert(maxLengthEnforced != null),
assert(scrollPadding != null), assert(scrollPadding != null),
...@@ -418,6 +422,12 @@ class CupertinoTextField extends StatefulWidget { ...@@ -418,6 +422,12 @@ class CupertinoTextField extends StatefulWidget {
/// {@macro flutter.widgets.editableText.autocorrect} /// {@macro flutter.widgets.editableText.autocorrect}
final bool autocorrect; final bool autocorrect;
/// {@macro flutter.services.textInput.smartDashesType}
final SmartDashesType smartDashesType;
/// {@macro flutter.services.textInput.smartQuotesType}
final SmartQuotesType smartQuotesType;
/// {@macro flutter.services.textInput.enableSuggestions} /// {@macro flutter.services.textInput.enableSuggestions}
final bool enableSuggestions; final bool enableSuggestions;
...@@ -568,6 +578,8 @@ class CupertinoTextField extends StatefulWidget { ...@@ -568,6 +578,8 @@ class CupertinoTextField extends StatefulWidget {
properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false)); properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false)); properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true)); properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true));
properties.add(EnumProperty<SmartDashesType>('smartDashesType', smartDashesType, defaultValue: obscureText ? SmartDashesType.disabled : SmartDashesType.enabled));
properties.add(EnumProperty<SmartQuotesType>('smartQuotesType', smartQuotesType, defaultValue: obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled));
properties.add(DiagnosticsProperty<bool>('enableSuggestions', enableSuggestions, defaultValue: true)); properties.add(DiagnosticsProperty<bool>('enableSuggestions', enableSuggestions, defaultValue: true));
properties.add(IntProperty('maxLines', maxLines, defaultValue: 1)); properties.add(IntProperty('maxLines', maxLines, defaultValue: 1));
properties.add(IntProperty('minLines', minLines, defaultValue: null)); properties.add(IntProperty('minLines', minLines, defaultValue: null));
...@@ -884,6 +896,8 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK ...@@ -884,6 +896,8 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
autofocus: widget.autofocus, autofocus: widget.autofocus,
obscureText: widget.obscureText, obscureText: widget.obscureText,
autocorrect: widget.autocorrect, autocorrect: widget.autocorrect,
smartDashesType: widget.smartDashesType,
smartQuotesType: widget.smartQuotesType,
enableSuggestions: widget.enableSuggestions, enableSuggestions: widget.enableSuggestions,
maxLines: widget.maxLines, maxLines: widget.maxLines,
minLines: widget.minLines, minLines: widget.minLines,
......
...@@ -238,4 +238,3 @@ class Factory<T> { ...@@ -238,4 +238,3 @@ class Factory<T> {
return 'Factory(type: $type)'; return 'Factory(type: $type)';
} }
} }
...@@ -18,7 +18,7 @@ import 'selectable_text.dart' show iOSHorizontalOffset; ...@@ -18,7 +18,7 @@ import 'selectable_text.dart' show iOSHorizontalOffset;
import 'text_selection.dart'; import 'text_selection.dart';
import 'theme.dart'; import 'theme.dart';
export 'package:flutter/services.dart' show TextInputType, TextInputAction, TextCapitalization; export 'package:flutter/services.dart' show TextInputType, TextInputAction, TextCapitalization, SmartQuotesType, SmartDashesType;
/// Signature for the [TextField.buildCounter] callback. /// Signature for the [TextField.buildCounter] callback.
typedef InputCounterWidgetBuilder = Widget Function( typedef InputCounterWidgetBuilder = Widget Function(
...@@ -280,8 +280,8 @@ class TextField extends StatefulWidget { ...@@ -280,8 +280,8 @@ class TextField extends StatefulWidget {
/// is null (the default) and [readOnly] is true. /// is null (the default) and [readOnly] is true.
/// ///
/// The [textAlign], [autofocus], [obscureText], [readOnly], [autocorrect], /// The [textAlign], [autofocus], [obscureText], [readOnly], [autocorrect],
/// [maxLengthEnforced], [scrollPadding], [maxLines], [maxLength], and /// [maxLengthEnforced], [scrollPadding], [maxLines], [maxLength],
/// [enableSuggestions] arguments must not be null. /// and [enableSuggestions] arguments must not be null.
/// ///
/// See also: /// See also:
/// ///
...@@ -306,6 +306,8 @@ class TextField extends StatefulWidget { ...@@ -306,6 +306,8 @@ class TextField extends StatefulWidget {
this.autofocus = false, this.autofocus = false,
this.obscureText = false, this.obscureText = false,
this.autocorrect = true, this.autocorrect = true,
SmartDashesType smartDashesType,
SmartQuotesType smartQuotesType,
this.enableSuggestions = true, this.enableSuggestions = true,
this.maxLines = 1, this.maxLines = 1,
this.minLines, this.minLines,
...@@ -333,6 +335,8 @@ class TextField extends StatefulWidget { ...@@ -333,6 +335,8 @@ class TextField extends StatefulWidget {
assert(autofocus != null), assert(autofocus != null),
assert(obscureText != null), assert(obscureText != null),
assert(autocorrect != null), assert(autocorrect != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
smartQuotesType = smartQuotesType ?? (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled),
assert(enableSuggestions != null), assert(enableSuggestions != null),
assert(enableInteractiveSelection != null), assert(enableInteractiveSelection != null),
assert(maxLengthEnforced != null), assert(maxLengthEnforced != null),
...@@ -459,6 +463,12 @@ class TextField extends StatefulWidget { ...@@ -459,6 +463,12 @@ class TextField extends StatefulWidget {
/// {@macro flutter.widgets.editableText.autocorrect} /// {@macro flutter.widgets.editableText.autocorrect}
final bool autocorrect; final bool autocorrect;
/// {@macro flutter.services.textInput.smartDashesType}
final SmartDashesType smartDashesType;
/// {@macro flutter.services.textInput.smartQuotesType}
final SmartQuotesType smartQuotesType;
/// {@macro flutter.services.textInput.enableSuggestions} /// {@macro flutter.services.textInput.enableSuggestions}
final bool enableSuggestions; final bool enableSuggestions;
...@@ -684,6 +694,8 @@ class TextField extends StatefulWidget { ...@@ -684,6 +694,8 @@ class TextField extends StatefulWidget {
properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false)); properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false)); properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true)); properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true));
properties.add(EnumProperty<SmartDashesType>('smartDashesType', smartDashesType, defaultValue: obscureText ? SmartDashesType.disabled : SmartDashesType.enabled));
properties.add(EnumProperty<SmartQuotesType>('smartQuotesType', smartQuotesType, defaultValue: obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled));
properties.add(DiagnosticsProperty<bool>('enableSuggestions', enableSuggestions, defaultValue: true)); properties.add(DiagnosticsProperty<bool>('enableSuggestions', enableSuggestions, defaultValue: true));
properties.add(IntProperty('maxLines', maxLines, defaultValue: 1)); properties.add(IntProperty('maxLines', maxLines, defaultValue: 1));
properties.add(IntProperty('minLines', minLines, defaultValue: null)); properties.add(IntProperty('minLines', minLines, defaultValue: null));
...@@ -966,6 +978,8 @@ class _TextFieldState extends State<TextField> implements TextSelectionGestureDe ...@@ -966,6 +978,8 @@ class _TextFieldState extends State<TextField> implements TextSelectionGestureDe
autofocus: widget.autofocus, autofocus: widget.autofocus,
obscureText: widget.obscureText, obscureText: widget.obscureText,
autocorrect: widget.autocorrect, autocorrect: widget.autocorrect,
smartDashesType: widget.smartDashesType,
smartQuotesType: widget.smartQuotesType,
enableSuggestions: widget.enableSuggestions, enableSuggestions: widget.enableSuggestions,
maxLines: widget.maxLines, maxLines: widget.maxLines,
minLines: widget.minLines, minLines: widget.minLines,
......
...@@ -9,6 +9,8 @@ import 'input_decorator.dart'; ...@@ -9,6 +9,8 @@ import 'input_decorator.dart';
import 'text_field.dart'; import 'text_field.dart';
import 'theme.dart'; import 'theme.dart';
export 'package:flutter/services.dart' show SmartQuotesType, SmartDashesType;
/// A [FormField] that contains a [TextField]. /// A [FormField] that contains a [TextField].
/// ///
/// This is a convenience widget that wraps a [TextField] widget in a /// This is a convenience widget that wraps a [TextField] widget in a
...@@ -98,6 +100,8 @@ class TextFormField extends FormField<String> { ...@@ -98,6 +100,8 @@ class TextFormField extends FormField<String> {
bool showCursor, bool showCursor,
bool obscureText = false, bool obscureText = false,
bool autocorrect = true, bool autocorrect = true,
SmartDashesType smartDashesType,
SmartQuotesType smartQuotesType,
bool enableSuggestions = true, bool enableSuggestions = true,
bool autovalidate = false, bool autovalidate = false,
bool maxLengthEnforced = true, bool maxLengthEnforced = true,
...@@ -179,6 +183,8 @@ class TextFormField extends FormField<String> { ...@@ -179,6 +183,8 @@ class TextFormField extends FormField<String> {
showCursor: showCursor, showCursor: showCursor,
obscureText: obscureText, obscureText: obscureText,
autocorrect: autocorrect, autocorrect: autocorrect,
smartDashesType: smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
smartQuotesType: smartQuotesType ?? (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled),
enableSuggestions: enableSuggestions, enableSuggestions: enableSuggestions,
maxLengthEnforced: maxLengthEnforced, maxLengthEnforced: maxLengthEnforced,
maxLines: maxLines, maxLines: maxLines,
......
...@@ -27,6 +27,54 @@ export 'dart:ui' show TextAffinity; ...@@ -27,6 +27,54 @@ export 'dart:ui' show TextAffinity;
// Whether we're compiled to JavaScript in a web browser. // Whether we're compiled to JavaScript in a web browser.
const bool _kIsBrowser = identical(0, 0.0); const bool _kIsBrowser = identical(0, 0.0);
/// Indicates how to handle the intelligent replacement of dashes in text input.
///
/// See also:
///
/// * [TextField.smartDashesType]
/// * [TextFormField.smartDashesType]
/// * [CupertinoTextField.smartDashesType]
/// * [EditableText.smartDashesType]
/// * [SmartQuotesType]
/// * <https://developer.apple.com/documentation/uikit/uitextinputtraits>
enum SmartDashesType {
/// Smart dashes is disabled.
///
/// This corresponds to the
/// ["no" value of UITextSmartDashesType](https://developer.apple.com/documentation/uikit/uitextsmartdashestype/no).
disabled,
/// Smart dashes is enabled.
///
/// This corresponds to the
/// ["yes" value of UITextSmartDashesType](https://developer.apple.com/documentation/uikit/uitextsmartdashestype/yes).
enabled,
}
/// Indicates how to handle the intelligent replacement of quotes in text input.
///
/// See also:
///
/// * [TextField.smartQuotesType]
/// * [TextFormField.smartQuotesType]
/// * [CupertinoTextField.smartQuotesType]
/// * [EditableText.smartQuotesType]
/// * [SmartDashesType]
/// * <https://developer.apple.com/documentation/uikit/uitextinputtraits>
enum SmartQuotesType {
/// Smart quotes is disabled.
///
/// This corresponds to the
/// ["no" value of UITextSmartQuotesType](https://developer.apple.com/documentation/uikit/uitextsmartquotestype/no).
disabled,
/// Smart quotes is enabled.
///
/// This corresponds to the
/// ["yes" value of UITextSmartQuotesType](https://developer.apple.com/documentation/uikit/uitextsmartquotestype/yes).
enabled,
}
/// The type of information for which to optimize the text input control. /// The type of information for which to optimize the text input control.
/// ///
/// On Android, behavior may vary across device and keyboard provider. /// On Android, behavior may vary across device and keyboard provider.
...@@ -385,6 +433,8 @@ class TextInputConfiguration { ...@@ -385,6 +433,8 @@ class TextInputConfiguration {
this.inputType = TextInputType.text, this.inputType = TextInputType.text,
this.obscureText = false, this.obscureText = false,
this.autocorrect = true, this.autocorrect = true,
SmartDashesType smartDashesType,
SmartQuotesType smartQuotesType,
this.enableSuggestions = true, this.enableSuggestions = true,
this.actionLabel, this.actionLabel,
this.inputAction = TextInputAction.done, this.inputAction = TextInputAction.done,
...@@ -392,6 +442,8 @@ class TextInputConfiguration { ...@@ -392,6 +442,8 @@ class TextInputConfiguration {
this.textCapitalization = TextCapitalization.none, this.textCapitalization = TextCapitalization.none,
}) : assert(inputType != null), }) : assert(inputType != null),
assert(obscureText != null), assert(obscureText != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
smartQuotesType = smartQuotesType ?? (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled),
assert(autocorrect != null), assert(autocorrect != null),
assert(enableSuggestions != null), assert(enableSuggestions != null),
assert(keyboardAppearance != null), assert(keyboardAppearance != null),
...@@ -411,6 +463,56 @@ class TextInputConfiguration { ...@@ -411,6 +463,56 @@ class TextInputConfiguration {
/// Defaults to true. /// Defaults to true.
final bool autocorrect; final bool autocorrect;
/// {@template flutter.services.textInput.smartDashesType}
/// Whether to allow the platform to automatically format dashes.
///
/// This flag only affects iOS versions 11 and above. It sets
/// [`UITextSmartDashesType`](https://developer.apple.com/documentation/uikit/uitextsmartdashestype?language=objc)
/// in the engine. When true, it passes
/// [`UITextSmartDashesTypeYes`](https://developer.apple.com/documentation/uikit/uitextsmartdashestype/uitextsmartdashestypeyes?language=objc),
/// and when false, it passes
/// [`UITextSmartDashesTypeNo`](https://developer.apple.com/documentation/uikit/uitextsmartdashestype/uitextsmartdashestypeno?language=objc).
///
/// As an example of what this does, two consecutive hyphen characters will be
/// automatically replaced with one en dash, and three consecutive hyphens
/// will become one em dash.
///
/// Defaults to true, unless [obscureText] is true, when it defaults to false.
/// This is to avoid the problem where password fields receive autoformatted
/// characters.
///
/// See also:
///
/// * [smartQuotesType]
/// * <https://developer.apple.com/documentation/uikit/uitextinputtraits>
/// {@endtemplate}
final SmartDashesType smartDashesType;
/// {@template flutter.services.textInput.smartQuotesType}
/// Whether to allow the platform to automatically format quotes.
///
/// This flag only affects iOS. It sets
/// [`UITextSmartQuotesType`](https://developer.apple.com/documentation/uikit/uitextsmartquotestype?language=objc)
/// in the engine. When true, it passes
/// [`UITextSmartQuotesTypeYes`](https://developer.apple.com/documentation/uikit/uitextsmartquotestype/uitextsmartquotestypeyes?language=objc),
/// and when false, it passes
/// [`UITextSmartQuotesTypeNo`](https://developer.apple.com/documentation/uikit/uitextsmartquotestype/uitextsmartquotestypeno?language=objc).
///
/// As an example of what this does, a standard vertical double quote
/// character will be automatically replaced by a left or right double quote
/// depending on its position in a word.
///
/// Defaults to true, unless [obscureText] is true, when it defaults to false.
/// This is to avoid the problem where password fields receive autoformatted
/// characters.
///
/// See also:
///
/// * [smartDashesType]
/// * <https://developer.apple.com/documentation/uikit/uitextinputtraits>
/// {@endtemplate}
final SmartQuotesType smartQuotesType;
/// {@template flutter.services.textInput.enableSuggestions} /// {@template flutter.services.textInput.enableSuggestions}
/// Whether to show input suggestions as the user types. /// Whether to show input suggestions as the user types.
/// ///
...@@ -455,6 +557,8 @@ class TextInputConfiguration { ...@@ -455,6 +557,8 @@ class TextInputConfiguration {
'inputType': inputType.toJson(), 'inputType': inputType.toJson(),
'obscureText': obscureText, 'obscureText': obscureText,
'autocorrect': autocorrect, 'autocorrect': autocorrect,
'smartDashesType': smartDashesType.index.toString(),
'smartQuotesType': smartQuotesType.index.toString(),
'enableSuggestions': enableSuggestions, 'enableSuggestions': enableSuggestions,
'actionLabel': actionLabel, 'actionLabel': actionLabel,
'inputAction': inputAction.toString(), 'inputAction': inputAction.toString(),
......
...@@ -29,7 +29,7 @@ import 'scrollable.dart'; ...@@ -29,7 +29,7 @@ import 'scrollable.dart';
import 'text_selection.dart'; import 'text_selection.dart';
import 'ticker_provider.dart'; import 'ticker_provider.dart';
export 'package:flutter/services.dart' show TextEditingValue, TextSelection, TextInputType; export 'package:flutter/services.dart' show TextEditingValue, TextSelection, TextInputType, SmartQuotesType, SmartDashesType;
export 'package:flutter/rendering.dart' show SelectionChangedCause; export 'package:flutter/rendering.dart' show SelectionChangedCause;
/// Signature for the callback that reports when the user changes the selection /// Signature for the callback that reports when the user changes the selection
...@@ -342,9 +342,10 @@ class EditableText extends StatefulWidget { ...@@ -342,9 +342,10 @@ class EditableText extends StatefulWidget {
/// The [controller], [focusNode], [obscureText], [autocorrect], [autofocus], /// The [controller], [focusNode], [obscureText], [autocorrect], [autofocus],
/// [showSelectionHandles], [enableInteractiveSelection], [forceLine], /// [showSelectionHandles], [enableInteractiveSelection], [forceLine],
/// [style], [cursorColor], [cursorOpacityAnimates],[backgroundCursorColor], /// [style], [cursorColor], [cursorOpacityAnimates],[backgroundCursorColor],
/// [enableSuggestions], [paintCursorAboveText], [textAlign], [dragStartBehavior], /// [enableSuggestions], [paintCursorAboveText], [textAlign],
/// [scrollPadding], [dragStartBehavior], [toolbarOptions], /// [dragStartBehavior], [scrollPadding], [dragStartBehavior],
/// [rendererIgnoresPointer], and [readOnly] arguments must not be null. /// [toolbarOptions], [rendererIgnoresPointer], and [readOnly] arguments must
/// not be null.
EditableText({ EditableText({
Key key, Key key,
@required this.controller, @required this.controller,
...@@ -352,6 +353,8 @@ class EditableText extends StatefulWidget { ...@@ -352,6 +353,8 @@ class EditableText extends StatefulWidget {
this.readOnly = false, this.readOnly = false,
this.obscureText = false, this.obscureText = false,
this.autocorrect = true, this.autocorrect = true,
SmartDashesType smartDashesType,
SmartQuotesType smartQuotesType,
this.enableSuggestions = true, this.enableSuggestions = true,
@required this.style, @required this.style,
StrutStyle strutStyle, StrutStyle strutStyle,
...@@ -402,6 +405,8 @@ class EditableText extends StatefulWidget { ...@@ -402,6 +405,8 @@ class EditableText extends StatefulWidget {
assert(focusNode != null), assert(focusNode != null),
assert(obscureText != null), assert(obscureText != null),
assert(autocorrect != null), assert(autocorrect != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
smartQuotesType = smartQuotesType ?? (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled),
assert(enableSuggestions != null), assert(enableSuggestions != null),
assert(showSelectionHandles != null), assert(showSelectionHandles != null),
assert(enableInteractiveSelection != null), assert(enableInteractiveSelection != null),
...@@ -517,6 +522,12 @@ class EditableText extends StatefulWidget { ...@@ -517,6 +522,12 @@ class EditableText extends StatefulWidget {
/// {@endtemplate} /// {@endtemplate}
final bool autocorrect; final bool autocorrect;
/// {@macro flutter.services.textInput.smartDashesType}
final SmartDashesType smartDashesType;
/// {@macro flutter.services.textInput.smartQuotesType}
final SmartQuotesType smartQuotesType;
/// {@macro flutter.services.textInput.enableSuggestions} /// {@macro flutter.services.textInput.enableSuggestions}
final bool enableSuggestions; final bool enableSuggestions;
...@@ -1042,6 +1053,8 @@ class EditableText extends StatefulWidget { ...@@ -1042,6 +1053,8 @@ class EditableText extends StatefulWidget {
properties.add(DiagnosticsProperty<FocusNode>('focusNode', focusNode)); properties.add(DiagnosticsProperty<FocusNode>('focusNode', focusNode));
properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false)); properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true)); properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true));
properties.add(EnumProperty<SmartDashesType>('smartDashesType', smartDashesType, defaultValue: obscureText ? SmartDashesType.disabled : SmartDashesType.enabled));
properties.add(EnumProperty<SmartQuotesType>('smartQuotesType', smartQuotesType, defaultValue: obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled));
properties.add(DiagnosticsProperty<bool>('enableSuggestions', enableSuggestions, defaultValue: true)); properties.add(DiagnosticsProperty<bool>('enableSuggestions', enableSuggestions, defaultValue: true));
style?.debugFillProperties(properties); style?.debugFillProperties(properties);
properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null)); properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null));
...@@ -1401,6 +1414,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -1401,6 +1414,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
inputType: widget.keyboardType, inputType: widget.keyboardType,
obscureText: widget.obscureText, obscureText: widget.obscureText,
autocorrect: widget.autocorrect, autocorrect: widget.autocorrect,
smartDashesType: widget.smartDashesType ?? (widget.obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
smartQuotesType: widget.smartQuotesType ?? (widget.obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled),
enableSuggestions: widget.enableSuggestions, enableSuggestions: widget.enableSuggestions,
inputAction: widget.textInputAction ?? (widget.keyboardType == TextInputType.multiline inputAction: widget.textInputAction ?? (widget.keyboardType == TextInputType.multiline
? TextInputAction.newline ? TextInputAction.newline
...@@ -1862,6 +1877,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -1862,6 +1877,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
textWidthBasis: widget.textWidthBasis, textWidthBasis: widget.textWidthBasis,
obscureText: widget.obscureText, obscureText: widget.obscureText,
autocorrect: widget.autocorrect, autocorrect: widget.autocorrect,
smartDashesType: widget.smartDashesType,
smartQuotesType: widget.smartQuotesType,
enableSuggestions: widget.enableSuggestions, enableSuggestions: widget.enableSuggestions,
offset: offset, offset: offset,
onSelectionChanged: _handleSelectionChanged, onSelectionChanged: _handleSelectionChanged,
...@@ -1928,6 +1945,8 @@ class _Editable extends LeafRenderObjectWidget { ...@@ -1928,6 +1945,8 @@ class _Editable extends LeafRenderObjectWidget {
this.locale, this.locale,
this.obscureText, this.obscureText,
this.autocorrect, this.autocorrect,
this.smartDashesType,
this.smartQuotesType,
this.enableSuggestions, this.enableSuggestions,
this.offset, this.offset,
this.onSelectionChanged, this.onSelectionChanged,
...@@ -1966,6 +1985,8 @@ class _Editable extends LeafRenderObjectWidget { ...@@ -1966,6 +1985,8 @@ class _Editable extends LeafRenderObjectWidget {
final bool obscureText; final bool obscureText;
final TextWidthBasis textWidthBasis; final TextWidthBasis textWidthBasis;
final bool autocorrect; final bool autocorrect;
final SmartDashesType smartDashesType;
final SmartQuotesType smartQuotesType;
final bool enableSuggestions; final bool enableSuggestions;
final ViewportOffset offset; final ViewportOffset offset;
final SelectionChangedHandler onSelectionChanged; final SelectionChangedHandler onSelectionChanged;
......
...@@ -6547,6 +6547,8 @@ void main() { ...@@ -6547,6 +6547,8 @@ void main() {
maxLines: 10, maxLines: 10,
maxLength: 100, maxLength: 100,
maxLengthEnforced: false, maxLengthEnforced: false,
smartDashesType: SmartDashesType.disabled,
smartQuotesType: SmartQuotesType.disabled,
enabled: false, enabled: false,
cursorWidth: 1.0, cursorWidth: 1.0,
cursorRadius: Radius.zero, cursorRadius: Radius.zero,
...@@ -6567,6 +6569,8 @@ void main() { ...@@ -6567,6 +6569,8 @@ void main() {
'style: TextStyle(inherit: true, color: Color(0xff00ff00))', 'style: TextStyle(inherit: true, color: Color(0xff00ff00))',
'autofocus: true', 'autofocus: true',
'autocorrect: false', 'autocorrect: false',
'smartDashesType: disabled',
'smartQuotesType: disabled',
'maxLines: 10', 'maxLines: 10',
'maxLength: 100', 'maxLength: 100',
'maxLength not enforced', 'maxLength not enforced',
......
...@@ -358,6 +358,101 @@ void main() { ...@@ -358,6 +358,101 @@ void main() {
expect(tester.testTextInput.setClientArgs['enableSuggestions'], enableSuggestions); expect(tester.testTextInput.setClientArgs['enableSuggestions'], enableSuggestions);
}); });
group('smartDashesType and smartQuotesType', () {
testWidgets('sent to the engine properly', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
const SmartDashesType smartDashesType = SmartDashesType.disabled;
const SmartQuotesType smartQuotesType = SmartQuotesType.disabled;
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: FocusScope(
node: focusScopeNode,
autofocus: true,
child: EditableText(
controller: controller,
backgroundCursorColor: Colors.grey,
focusNode: focusNode,
smartDashesType: smartDashesType,
smartQuotesType: smartQuotesType,
style: textStyle,
cursorColor: cursorColor,
),
),
),
),
);
await tester.tap(find.byType(EditableText));
await tester.showKeyboard(find.byType(EditableText));
await tester.idle();
expect(tester.testTextInput.setClientArgs['smartDashesType'], smartDashesType.index.toString());
expect(tester.testTextInput.setClientArgs['smartQuotesType'], smartQuotesType.index.toString());
});
testWidgets('default to true when obscureText is false', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: FocusScope(
node: focusScopeNode,
autofocus: true,
child: EditableText(
controller: controller,
backgroundCursorColor: Colors.grey,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
obscureText: false,
),
),
),
),
);
await tester.tap(find.byType(EditableText));
await tester.showKeyboard(find.byType(EditableText));
await tester.idle();
expect(tester.testTextInput.setClientArgs['smartDashesType'], '1');
expect(tester.testTextInput.setClientArgs['smartQuotesType'], '1');
});
testWidgets('default to false when obscureText is true', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: FocusScope(
node: focusScopeNode,
autofocus: true,
child: EditableText(
controller: controller,
backgroundCursorColor: Colors.grey,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
obscureText: true,
),
),
),
),
);
await tester.tap(find.byType(EditableText));
await tester.showKeyboard(find.byType(EditableText));
await tester.idle();
expect(tester.testTextInput.setClientArgs['smartDashesType'], '0');
expect(tester.testTextInput.setClientArgs['smartQuotesType'], '0');
});
});
testWidgets('selection overlay will update when text grow bigger', (WidgetTester tester) async { testWidgets('selection overlay will update when text grow bigger', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController.fromValue( final TextEditingController controller = TextEditingController.fromValue(
const TextEditingValue( const TextEditingValue(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment