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

Customizable obscuringCharacter (#55415)

parent 4552af15
......@@ -241,6 +241,7 @@ class CupertinoTextField extends StatefulWidget {
ToolbarOptions toolbarOptions,
this.showCursor,
this.autofocus = false,
this.obscuringCharacter = '•',
this.obscureText = false,
this.autocorrect = true,
SmartDashesType smartDashesType,
......@@ -272,6 +273,7 @@ class CupertinoTextField extends StatefulWidget {
}) : assert(textAlign != null),
assert(readOnly != null),
assert(autofocus != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1),
assert(obscureText != null),
assert(autocorrect != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
......@@ -428,6 +430,9 @@ class CupertinoTextField extends StatefulWidget {
/// {@macro flutter.widgets.editableText.autofocus}
final bool autofocus;
/// {@macro flutter.widgets.editableText.obscuringCharacter}
final String obscuringCharacter;
/// {@macro flutter.widgets.editableText.obscureText}
final bool obscureText;
......@@ -601,6 +606,7 @@ class CupertinoTextField extends StatefulWidget {
properties.add(DiagnosticsProperty<TextInputType>('keyboardType', keyboardType, defaultValue: TextInputType.text));
properties.add(DiagnosticsProperty<TextStyle>('style', style, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false));
properties.add(DiagnosticsProperty<String>('obscuringCharacter', obscuringCharacter, defaultValue: '•'));
properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true));
properties.add(EnumProperty<SmartDashesType>('smartDashesType', smartDashesType, defaultValue: obscureText ? SmartDashesType.disabled : SmartDashesType.enabled));
......@@ -921,6 +927,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
strutStyle: widget.strutStyle,
textAlign: widget.textAlign,
autofocus: widget.autofocus,
obscuringCharacter: widget.obscuringCharacter,
obscureText: widget.obscureText,
autocorrect: widget.autocorrect,
smartDashesType: widget.smartDashesType,
......
......@@ -318,6 +318,7 @@ class TextField extends StatefulWidget {
ToolbarOptions toolbarOptions,
this.showCursor,
this.autofocus = false,
this.obscuringCharacter = '•',
this.obscureText = false,
this.autocorrect = true,
SmartDashesType smartDashesType,
......@@ -350,6 +351,7 @@ class TextField extends StatefulWidget {
}) : assert(textAlign != null),
assert(readOnly != null),
assert(autofocus != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1),
assert(obscureText != null),
assert(autocorrect != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
......@@ -476,6 +478,9 @@ class TextField extends StatefulWidget {
/// {@macro flutter.widgets.editableText.autofocus}
final bool autofocus;
/// {@macro flutter.widgets.editableText.obscuringCharacter}
final String obscuringCharacter;
/// {@macro flutter.widgets.editableText.obscureText}
final bool obscureText;
......@@ -727,6 +732,7 @@ class TextField extends StatefulWidget {
properties.add(DiagnosticsProperty<TextInputType>('keyboardType', keyboardType, defaultValue: TextInputType.text));
properties.add(DiagnosticsProperty<TextStyle>('style', style, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false));
properties.add(DiagnosticsProperty<String>('obscuringCharacter', obscuringCharacter, defaultValue: '•'));
properties.add(DiagnosticsProperty<bool>('obscureText', obscureText, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true));
properties.add(EnumProperty<SmartDashesType>('smartDashesType', smartDashesType, defaultValue: obscureText ? SmartDashesType.disabled : SmartDashesType.enabled));
......@@ -1021,6 +1027,7 @@ class _TextFieldState extends State<TextField> implements TextSelectionGestureDe
textAlign: widget.textAlign,
textDirection: widget.textDirection,
autofocus: widget.autofocus,
obscuringCharacter: widget.obscuringCharacter,
obscureText: widget.obscureText,
autocorrect: widget.autocorrect,
smartDashesType: widget.smartDashesType,
......
......@@ -146,6 +146,7 @@ class TextFormField extends FormField<String> {
bool readOnly = false,
ToolbarOptions toolbarOptions,
bool showCursor,
String obscuringCharacter = '•',
bool obscureText = false,
bool autocorrect = true,
SmartDashesType smartDashesType,
......@@ -177,6 +178,7 @@ class TextFormField extends FormField<String> {
assert(textAlign != null),
assert(autofocus != null),
assert(readOnly != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1),
assert(obscureText != null),
assert(autocorrect != null),
assert(enableSuggestions != null),
......@@ -230,6 +232,7 @@ class TextFormField extends FormField<String> {
toolbarOptions: toolbarOptions,
readOnly: readOnly,
showCursor: showCursor,
obscuringCharacter: obscuringCharacter,
obscureText: obscureText,
autocorrect: autocorrect,
smartDashesType: smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
......
......@@ -213,6 +213,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
bool readOnly = false,
bool forceLine = true,
TextWidthBasis textWidthBasis = TextWidthBasis.parent,
String obscuringCharacter = '•',
bool obscureText = false,
Locale locale,
double cursorWidth = 1.0,
......@@ -247,6 +248,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
assert(ignorePointer != null),
assert(textWidthBasis != null),
assert(paintCursorAboveText != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1),
assert(obscureText != null),
assert(textSelectionDelegate != null),
assert(cursorWidth != null && cursorWidth >= 0.0),
......@@ -284,6 +286,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
_selectionWidthStyle = selectionWidthStyle,
_startHandleLayerLink = startHandleLayerLink,
_endHandleLayerLink = endHandleLayerLink,
_obscuringCharacter = obscuringCharacter,
_obscureText = obscureText,
_readOnly = readOnly,
_forceLine = forceLine,
......@@ -295,9 +298,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
_promptRectPaint.color = promptRectColor;
}
/// Character used to obscure text if [obscureText] is true.
static const String obscuringCharacter = '•';
/// Called when the selection changes.
///
/// If this is null, then selection changes will be ignored.
......@@ -344,6 +344,20 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
markNeedsTextLayout();
}
/// Character used for obscuring text if [obscureText] is true.
///
/// Cannot be null, and must have a length of exactly one.
String get obscuringCharacter => _obscuringCharacter;
String _obscuringCharacter;
set obscuringCharacter(String value) {
if (_obscuringCharacter == value) {
return;
}
assert(value != null && value.length == 1);
_obscuringCharacter = value;
markNeedsLayout();
}
/// Whether to hide the text being edited (e.g., for passwords).
bool get obscureText => _obscureText;
bool _obscureText;
......
......@@ -357,6 +357,7 @@ class EditableText extends StatefulWidget {
@required this.controller,
@required this.focusNode,
this.readOnly = false,
this.obscuringCharacter = '•',
this.obscureText = false,
this.autocorrect = true,
SmartDashesType smartDashesType,
......@@ -413,6 +414,7 @@ class EditableText extends StatefulWidget {
this.autofillHints,
}) : assert(controller != null),
assert(focusNode != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1),
assert(obscureText != null),
assert(autocorrect != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
......@@ -464,11 +466,20 @@ class EditableText extends StatefulWidget {
/// Controls whether this widget has keyboard focus.
final FocusNode focusNode;
/// {@template flutter.widgets.editableText.obscuringCharacter}
/// Character used for obscuring text if [obscureText] is true.
///
/// Must be only a single character.
///
/// Defaults to the character U+2022 BULLET (•).
/// {@endtemplate}
final String obscuringCharacter;
/// {@template flutter.widgets.editableText.obscureText}
/// Whether to hide the text being edited (e.g., for passwords).
///
/// When this is set to true, all the characters in the text field are
/// replaced by U+2022 BULLET characters (•).
/// replaced by [obscuringCharacter].
///
/// Defaults to false. Cannot be null.
/// {@endtemplate}
......@@ -2029,6 +2040,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
textDirection: _textDirection,
locale: widget.locale,
textWidthBasis: widget.textWidthBasis,
obscuringCharacter: widget.obscuringCharacter,
obscureText: widget.obscureText,
autocorrect: widget.autocorrect,
smartDashesType: widget.smartDashesType,
......@@ -2063,7 +2075,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
TextSpan buildTextSpan() {
if (widget.obscureText) {
String text = _value.text;
text = RenderEditable.obscuringCharacter * text.length;
text = widget.obscuringCharacter * text.length;
final int o =
_obscureShowCharTicksPending > 0 ? _obscureLatestCharIndex : null;
if (o != null && o >= 0 && o < text.length)
......@@ -2101,6 +2113,7 @@ class _Editable extends LeafRenderObjectWidget {
this.textAlign,
@required this.textDirection,
this.locale,
this.obscuringCharacter,
this.obscureText,
this.autocorrect,
this.smartDashesType,
......@@ -2144,6 +2157,7 @@ class _Editable extends LeafRenderObjectWidget {
final TextAlign textAlign;
final TextDirection textDirection;
final Locale locale;
final String obscuringCharacter;
final bool obscureText;
final TextWidthBasis textWidthBasis;
final bool autocorrect;
......@@ -2192,6 +2206,7 @@ class _Editable extends LeafRenderObjectWidget {
onSelectionChanged: onSelectionChanged,
onCaretChanged: onCaretChanged,
ignorePointer: rendererIgnoresPointer,
obscuringCharacter: obscuringCharacter,
obscureText: obscureText,
textWidthBasis: textWidthBasis,
cursorWidth: cursorWidth,
......@@ -2234,6 +2249,7 @@ class _Editable extends LeafRenderObjectWidget {
..onCaretChanged = onCaretChanged
..ignorePointer = rendererIgnoresPointer
..textWidthBasis = textWidthBasis
..obscuringCharacter = obscuringCharacter
..obscureText = obscureText
..cursorWidth = cursorWidth
..cursorRadius = cursorRadius
......
......@@ -2281,7 +2281,7 @@ void main() {
),
));
const String expectedValue = '••••••••••••••••••••••••';
final String expectedValue = '•' * originalText.length;
expect(
semantics,
......@@ -2368,6 +2368,27 @@ void main() {
semantics.dispose();
});
testWidgets('password fields can have their obscuring character customized', (WidgetTester tester) async {
const String originalText = 'super-secret-password!!1';
controller.text = originalText;
const String obscuringCharacter = '#';
await tester.pumpWidget(MaterialApp(
home: EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
obscuringCharacter: obscuringCharacter,
obscureText: true,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
),
));
final String expectedValue = obscuringCharacter * originalText.length;
expect(findRenderEditable(tester).text.text, expectedValue);
});
group('a11y copy/cut/paste', () {
Future<void> _buildApp(MockTextSelectionControls controls, WidgetTester tester) {
return tester.pumpWidget(MaterialApp(
......
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