@@ -508,16 +508,11 @@ class EditableText extends StatefulWidget {
508508 this .scrollPadding = const EdgeInsets .all (20.0 ),
509509 this .keyboardAppearance = Brightness .light,
510510 this .dragStartBehavior = DragStartBehavior .start,
511- this .enableInteractiveSelection = true ,
511+ bool ? enableInteractiveSelection ,
512512 this .scrollController,
513513 this .scrollPhysics,
514514 this .autocorrectionTextRectColor,
515- this .toolbarOptions = const ToolbarOptions (
516- copy: true ,
517- cut: true ,
518- paste: true ,
519- selectAll: true ,
520- ),
515+ ToolbarOptions ? toolbarOptions,
521516 this .autofillHints = const < String > [],
522517 this .autofillClient,
523518 this .clipBehavior = Clip .hardEdge,
@@ -533,7 +528,6 @@ class EditableText extends StatefulWidget {
533528 smartQuotesType = smartQuotesType ?? (obscureText ? SmartQuotesType .disabled : SmartQuotesType .enabled),
534529 assert (enableSuggestions != null ),
535530 assert (showSelectionHandles != null ),
536- assert (enableInteractiveSelection != null ),
537531 assert (readOnly != null ),
538532 assert (forceLine != null ),
539533 assert (style != null ),
@@ -560,7 +554,31 @@ class EditableText extends StatefulWidget {
560554 assert (rendererIgnoresPointer != null ),
561555 assert (scrollPadding != null ),
562556 assert (dragStartBehavior != null ),
563- assert (toolbarOptions != null ),
557+ enableInteractiveSelection = enableInteractiveSelection ?? (! readOnly || ! obscureText),
558+ toolbarOptions = toolbarOptions ??
559+ (obscureText
560+ ? (readOnly
561+ // No point in even offering "Select All" in a read-only obscured
562+ // field.
563+ ? const ToolbarOptions ()
564+ // Writable, but obscured.
565+ : const ToolbarOptions (
566+ selectAll: true ,
567+ paste: true ,
568+ ))
569+ : (readOnly
570+ // Read-only, not obscured.
571+ ? const ToolbarOptions (
572+ selectAll: true ,
573+ copy: true ,
574+ )
575+ // Writable, not obscured.
576+ : const ToolbarOptions (
577+ copy: true ,
578+ cut: true ,
579+ selectAll: true ,
580+ paste: true ,
581+ ))),
564582 assert (clipBehavior != null ),
565583 assert (enableIMEPersonalizedLearning != null ),
566584 _strutStyle = strutStyle,
@@ -593,7 +611,9 @@ class EditableText extends StatefulWidget {
593611 /// Whether to hide the text being edited (e.g., for passwords).
594612 ///
595613 /// When this is set to true, all the characters in the text field are
596- /// replaced by [obscuringCharacter] .
614+ /// replaced by [obscuringCharacter] , and the text in the field cannot be
615+ /// copied with copy or cut. If [readOnly] is also true, then the text cannot
616+ /// be selected.
597617 ///
598618 /// Defaults to false. Cannot be null.
599619 /// {@endtemplate}
@@ -629,8 +649,10 @@ class EditableText extends StatefulWidget {
629649
630650 /// Configuration of toolbar options.
631651 ///
632- /// By default, all options are enabled. If [readOnly] is true,
633- /// paste and cut will be disabled regardless.
652+ /// By default, all options are enabled. If [readOnly] is true, paste and cut
653+ /// will be disabled regardless. If [obscureText] is true, cut and copy will
654+ /// be disabled regardless. If [readOnly] and [obscureText] are both true,
655+ /// select all will also be disabled.
634656 final ToolbarOptions toolbarOptions;
635657
636658 /// Whether to show selection handles.
@@ -1492,6 +1514,7 @@ class EditableText extends StatefulWidget {
14921514 properties.add (DiagnosticsProperty <TextEditingController >('controller' , controller));
14931515 properties.add (DiagnosticsProperty <FocusNode >('focusNode' , focusNode));
14941516 properties.add (DiagnosticsProperty <bool >('obscureText' , obscureText, defaultValue: false ));
1517+ properties.add (DiagnosticsProperty <bool >('readOnly' , readOnly, defaultValue: false ));
14951518 properties.add (DiagnosticsProperty <bool >('autocorrect' , autocorrect, defaultValue: true ));
14961519 properties.add (EnumProperty <SmartDashesType >('smartDashesType' , smartDashesType, defaultValue: obscureText ? SmartDashesType .disabled : SmartDashesType .enabled));
14971520 properties.add (EnumProperty <SmartQuotesType >('smartQuotesType' , smartQuotesType, defaultValue: obscureText ? SmartQuotesType .disabled : SmartQuotesType .enabled));
@@ -1511,6 +1534,7 @@ class EditableText extends StatefulWidget {
15111534 properties.add (DiagnosticsProperty <Iterable <String >>('autofillHints' , autofillHints, defaultValue: null ));
15121535 properties.add (DiagnosticsProperty <TextHeightBehavior >('textHeightBehavior' , textHeightBehavior, defaultValue: null ));
15131536 properties.add (DiagnosticsProperty <bool >('enableIMEPersonalizedLearning' , enableIMEPersonalizedLearning, defaultValue: true ));
1537+ properties.add (DiagnosticsProperty <bool >('enableInteractiveSelection' , enableInteractiveSelection, defaultValue: true ));
15141538 }
15151539}
15161540
@@ -1573,16 +1597,16 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
15731597 Color get _cursorColor => widget.cursorColor.withOpacity (_cursorBlinkOpacityController! .value);
15741598
15751599 @override
1576- bool get cutEnabled => widget.toolbarOptions.cut && ! widget.readOnly;
1600+ bool get cutEnabled => widget.toolbarOptions.cut && ! widget.readOnly && ! widget.obscureText ;
15771601
15781602 @override
1579- bool get copyEnabled => widget.toolbarOptions.copy;
1603+ bool get copyEnabled => widget.toolbarOptions.copy && ! widget.obscureText ;
15801604
15811605 @override
15821606 bool get pasteEnabled => widget.toolbarOptions.paste && ! widget.readOnly;
15831607
15841608 @override
1585- bool get selectAllEnabled => widget.toolbarOptions.selectAll;
1609+ bool get selectAllEnabled => widget.toolbarOptions.selectAll && ( ! widget.readOnly || ! widget.obscureText) && widget.enableInteractiveSelection ;
15861610
15871611 void _onChangedClipboardStatus () {
15881612 setState (() {
@@ -1602,11 +1626,11 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
16021626 @override
16031627 void copySelection (SelectionChangedCause cause) {
16041628 final TextSelection selection = textEditingValue.selection;
1605- final String text = textEditingValue.text;
16061629 assert (selection != null );
1607- if (selection.isCollapsed) {
1630+ if (selection.isCollapsed || widget.obscureText ) {
16081631 return ;
16091632 }
1633+ final String text = textEditingValue.text;
16101634 Clipboard .setData (ClipboardData (text: selection.textInside (text)));
16111635 if (cause == SelectionChangedCause .toolbar) {
16121636 bringIntoView (textEditingValue.selection.extent);
@@ -1636,7 +1660,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
16361660 /// Cut current selection to [Clipboard] .
16371661 @override
16381662 void cutSelection (SelectionChangedCause cause) {
1639- if (widget.readOnly) {
1663+ if (widget.readOnly || widget.obscureText ) {
16401664 return ;
16411665 }
16421666 final TextSelection selection = textEditingValue.selection;
@@ -1681,6 +1705,11 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
16811705 /// Select the entire text value.
16821706 @override
16831707 void selectAll (SelectionChangedCause cause) {
1708+ if (widget.readOnly && widget.obscureText) {
1709+ // If we can't modify it, and we can't copy it, there's no point in
1710+ // selecting it.
1711+ return ;
1712+ }
16841713 userUpdateTextEditingValue (
16851714 textEditingValue.copyWith (
16861715 selection: TextSelection (baseOffset: 0 , extentOffset: textEditingValue.text.length),
@@ -3057,7 +3086,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
30573086 selectionHeightStyle: widget.selectionHeightStyle,
30583087 selectionWidthStyle: widget.selectionWidthStyle,
30593088 paintCursorAboveText: widget.paintCursorAboveText,
3060- enableInteractiveSelection: widget.enableInteractiveSelection,
3089+ enableInteractiveSelection: widget.enableInteractiveSelection && ( ! widget.readOnly || ! widget.obscureText) ,
30613090 textSelectionDelegate: this ,
30623091 devicePixelRatio: _devicePixelRatio,
30633092 promptRectRange: _currentPromptRectRange,
@@ -3287,6 +3316,7 @@ class _Editable extends MultiChildRenderObjectWidget {
32873316 ..cursorOffset = cursorOffset
32883317 ..selectionHeightStyle = selectionHeightStyle
32893318 ..selectionWidthStyle = selectionWidthStyle
3319+ ..enableInteractiveSelection = enableInteractiveSelection
32903320 ..textSelectionDelegate = textSelectionDelegate
32913321 ..devicePixelRatio = devicePixelRatio
32923322 ..paintCursorAboveText = paintCursorAboveText
0 commit comments