Unverified Commit 95eed876 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Add enableInteractiveSelection to CupertinoTextField and test it (#32823)

Adds a field that already exists in Material's TextField.
parent 4aaeb4e1
......@@ -186,6 +186,7 @@ class CupertinoTextField extends StatefulWidget {
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection,
this.scrollPhysics,
}) : assert(textAlign != null),
assert(autofocus != null),
......@@ -423,12 +424,20 @@ class CupertinoTextField extends StatefulWidget {
/// {@macro flutter.widgets.editableText.scrollPadding}
final EdgeInsets scrollPadding;
/// {@macro flutter.widgets.editableText.enableInteractiveSelection}
final bool enableInteractiveSelection;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// {@macro flutter.widgets.edtiableText.scrollPhysics}
final ScrollPhysics scrollPhysics;
/// {@macro flutter.rendering.editable.selectionEnabled}
bool get selectionEnabled {
return enableInteractiveSelection ?? !obscureText;
}
@override
_CupertinoTextFieldState createState() => _CupertinoTextFieldState();
......@@ -456,6 +465,7 @@ class CupertinoTextField extends StatefulWidget {
properties.add(IntProperty('maxLength', maxLength, defaultValue: null));
properties.add(FlagProperty('maxLengthEnforced', value: maxLengthEnforced, ifTrue: 'max length enforced'));
properties.add(DiagnosticsProperty<Color>('cursorColor', cursorColor, defaultValue: null));
properties.add(FlagProperty('selectionEnabled', value: selectionEnabled, defaultValue: true, ifFalse: 'selection disabled'));
properties.add(DiagnosticsProperty<ScrollPhysics>('scrollPhysics', scrollPhysics, defaultValue: null));
}
}
......@@ -530,10 +540,12 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
}
void _handleForcePressStarted(ForcePressDetails details) {
_renderEditable.selectWordsInRange(
from: details.globalPosition,
cause: SelectionChangedCause.forcePress,
);
if (widget.selectionEnabled) {
_renderEditable.selectWordsInRange(
from: details.globalPosition,
cause: SelectionChangedCause.forcePress,
);
}
}
void _handleForcePressEnded(ForcePressDetails details) {
......@@ -546,22 +558,28 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
}
void _handleSingleTapUp(TapUpDetails details) {
_renderEditable.selectWordEdge(cause: SelectionChangedCause.tap);
if (widget.selectionEnabled) {
_renderEditable.selectWordEdge(cause: SelectionChangedCause.tap);
}
_requestKeyboard();
}
void _handleSingleLongTapStart(LongPressStartDetails details) {
_renderEditable.selectPositionAt(
from: details.globalPosition,
cause: SelectionChangedCause.longPress,
);
if (widget.selectionEnabled) {
_renderEditable.selectPositionAt(
from: details.globalPosition,
cause: SelectionChangedCause.longPress,
);
}
}
void _handleSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) {
_renderEditable.selectPositionAt(
from: details.globalPosition,
cause: SelectionChangedCause.longPress,
);
if (widget.selectionEnabled) {
_renderEditable.selectPositionAt(
from: details.globalPosition,
cause: SelectionChangedCause.longPress,
);
}
}
void _handleSingleLongTapEnd(LongPressEndDetails details) {
......@@ -570,9 +588,11 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
}
void _handleDoubleTapDown(TapDownDetails details) {
_renderEditable.selectWord(cause: SelectionChangedCause.tap);
if (_shouldShowSelectionToolbar)
_editableText.showToolbar();
if (widget.selectionEnabled) {
_renderEditable.selectWord(cause: SelectionChangedCause.tap);
if (_shouldShowSelectionToolbar)
_editableText.showToolbar();
}
}
bool _shouldShowSelectionHandles(SelectionChangedCause cause) {
......@@ -782,7 +802,8 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
minLines: widget.minLines,
expands: widget.expands,
selectionColor: _kSelectionHighlightColor,
selectionControls: cupertinoTextSelectionControls,
selectionControls: widget.selectionEnabled
? cupertinoTextSelectionControls : null,
onChanged: widget.onChanged,
onSelectionChanged: _handleSelectionChanged,
onEditingComplete: widget.onEditingComplete,
......@@ -800,6 +821,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
keyboardAppearance: keyboardAppearance,
dragStartBehavior: widget.dragStartBehavior,
scrollPhysics: widget.scrollPhysics,
enableInteractiveSelection: widget.enableInteractiveSelection,
),
),
);
......
......@@ -1399,6 +1399,102 @@ void main() {
},
);
testWidgets(
'An obscured CupertinoTextField is not selectable by default',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextField(
controller: controller,
obscureText: true,
),
),
),
);
final Offset textfieldStart = tester.getTopLeft(find.byType(CupertinoTextField));
await tester.tapAt(textfieldStart + const Offset(150.0, 5.0));
await tester.pump(const Duration(milliseconds: 50));
final TestGesture gesture =
await tester.startGesture(textfieldStart + const Offset(150.0, 5.0));
// Hold the press.
await tester.pump(const Duration(milliseconds: 500));
// Nothing is selected despite the double tap long press gesture.
expect(
controller.selection,
const TextSelection(baseOffset: 35, extentOffset: 35),
);
// The selection menu is not present.
expect(find.byType(CupertinoButton), findsNWidgets(0));
await gesture.up();
await tester.pump();
// Still nothing selected and no selection menu.
expect(
controller.selection,
const TextSelection(baseOffset: 35, extentOffset: 35),
);
expect(find.byType(CupertinoButton), findsNWidgets(0));
},
);
testWidgets(
'An obscured CupertinoTextField is selectable when enabled',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextField(
controller: controller,
obscureText: true,
enableInteractiveSelection: true,
),
),
),
);
final Offset textfieldStart = tester.getTopLeft(find.byType(CupertinoTextField));
await tester.tapAt(textfieldStart + const Offset(150.0, 5.0));
await tester.pump(const Duration(milliseconds: 50));
final TestGesture gesture =
await tester.startGesture(textfieldStart + const Offset(150.0, 5.0));
// Hold the press.
await tester.pump(const Duration(milliseconds: 500));
// The obscured text is not broken into words, so only one letter is
// selected at a time.
expect(
controller.selection,
const TextSelection(baseOffset: 9, extentOffset: 10),
);
// Selected text shows 3 toolbar buttons.
expect(find.byType(CupertinoButton), findsNWidgets(3));
await gesture.up();
await tester.pump();
// Still selected.
expect(
controller.selection,
const TextSelection(baseOffset: 9, extentOffset: 10),
);
expect(find.byType(CupertinoButton), findsNWidgets(3));
},
);
testWidgets(
'long press moves cursor to the exact long press position and shows toolbar',
(WidgetTester tester) async {
......
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