mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
SelectableText long press on iOS (#63994)
This commit is contained in:
parent
2ae25cc2d7
commit
8f370dff65
|
@ -72,25 +72,11 @@ class _SelectableTextSelectionGestureDetectorBuilder extends TextSelectionGestur
|
|||
@override
|
||||
void onSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) {
|
||||
if (delegate.selectionEnabled) {
|
||||
switch (Theme.of(_state.context).platform) {
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
renderEditable.selectPositionAt(
|
||||
from: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
break;
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.linux:
|
||||
case TargetPlatform.windows:
|
||||
renderEditable.selectWordsInRange(
|
||||
from: details.globalPosition - details.offsetFromOrigin,
|
||||
to: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
break;
|
||||
}
|
||||
renderEditable.selectWordsInRange(
|
||||
from: details.globalPosition - details.offsetFromOrigin,
|
||||
to: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,22 +104,8 @@ class _SelectableTextSelectionGestureDetectorBuilder extends TextSelectionGestur
|
|||
@override
|
||||
void onSingleLongTapStart(LongPressStartDetails details) {
|
||||
if (delegate.selectionEnabled) {
|
||||
switch (Theme.of(_state.context).platform) {
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
renderEditable.selectPositionAt(
|
||||
from: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
break;
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.linux:
|
||||
case TargetPlatform.windows:
|
||||
renderEditable.selectWord(cause: SelectionChangedCause.longPress);
|
||||
Feedback.forLongPress(_state.context);
|
||||
break;
|
||||
}
|
||||
renderEditable.selectWord(cause: SelectionChangedCause.longPress);
|
||||
Feedback.forLongPress(_state.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2710,7 +2710,7 @@ void main() {
|
|||
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
|
||||
|
||||
testWidgets(
|
||||
'long press moves cursor to the exact long press position and shows toolbar',
|
||||
'long press selects word and shows toolbar (iOS)',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
|
@ -2730,13 +2730,16 @@ void main() {
|
|||
final EditableText editableTextWidget = tester.widget(find.byType(EditableText).first);
|
||||
final TextEditingController controller = editableTextWidget.controller;
|
||||
|
||||
// Collapsed cursor for iOS long press.
|
||||
// The longpressed word is selected.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 4, affinity: TextAffinity.upstream),
|
||||
const TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: 7,
|
||||
),
|
||||
);
|
||||
|
||||
// Collapsed toolbar shows 2 buttons.
|
||||
// Toolbar shows one button.
|
||||
expect(find.byType(CupertinoButton), findsNWidgets(1));
|
||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
|
||||
|
||||
|
@ -2828,10 +2831,14 @@ void main() {
|
|||
final EditableText editableTextWidget = tester.widget(find.byType(EditableText).first);
|
||||
final TextEditingController controller = editableTextWidget.controller;
|
||||
|
||||
// Long press on iOS shows collapsed selection cursor.
|
||||
// The longpressed word is selected.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 4, affinity: TextAffinity.upstream),
|
||||
const TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: 7,
|
||||
affinity: TextAffinity.downstream,
|
||||
),
|
||||
);
|
||||
// Cursor move doesn't trigger a toolbar initially.
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
@ -2842,7 +2849,11 @@ void main() {
|
|||
// The selection position is now moved with the drag.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 7, affinity: TextAffinity.downstream),
|
||||
const TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: 8,
|
||||
affinity: TextAffinity.downstream,
|
||||
),
|
||||
);
|
||||
// Still no toolbar.
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
@ -2853,7 +2864,11 @@ void main() {
|
|||
// The selection position is now moved with the drag.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 11, affinity: TextAffinity.upstream),
|
||||
const TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: 12,
|
||||
affinity: TextAffinity.downstream,
|
||||
),
|
||||
);
|
||||
// Still no toolbar.
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
@ -2864,7 +2879,11 @@ void main() {
|
|||
// The selection isn't affected by the gesture lift.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 11, affinity: TextAffinity.upstream),
|
||||
const TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: 12,
|
||||
affinity: TextAffinity.downstream,
|
||||
),
|
||||
);
|
||||
// The toolbar now shows up.
|
||||
expect(find.byType(CupertinoButton), findsNWidgets(1));
|
||||
|
@ -2906,7 +2925,7 @@ void main() {
|
|||
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 21),
|
||||
const TextSelection(baseOffset: 13, extentOffset: 23),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
|
@ -2915,21 +2934,33 @@ void main() {
|
|||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 64, affinity: TextAffinity.downstream),
|
||||
const TextSelection(
|
||||
baseOffset: 13,
|
||||
extentOffset: 66,
|
||||
affinity: TextAffinity.downstream,
|
||||
),
|
||||
);
|
||||
// Keep moving out.
|
||||
await gesture.moveBy(const Offset(1, 0));
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 66, affinity: TextAffinity.upstream),
|
||||
const TextSelection(
|
||||
baseOffset: 13,
|
||||
extentOffset: 66,
|
||||
affinity: TextAffinity.downstream,
|
||||
),
|
||||
);
|
||||
await gesture.moveBy(const Offset(1, 0));
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 66, affinity: TextAffinity.upstream),
|
||||
); // We're at the edge now.
|
||||
const TextSelection(
|
||||
baseOffset: 13,
|
||||
extentOffset: 66,
|
||||
affinity: TextAffinity.downstream,
|
||||
),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.up();
|
||||
|
@ -2938,7 +2969,11 @@ void main() {
|
|||
// The selection isn't affected by the gesture lift.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 66, affinity: TextAffinity.upstream),
|
||||
const TextSelection(
|
||||
baseOffset: 13,
|
||||
extentOffset: 66,
|
||||
affinity: TextAffinity.downstream,
|
||||
),
|
||||
);
|
||||
// The toolbar now shows up.
|
||||
expect(find.byType(CupertinoButton), findsNWidgets(1));
|
||||
|
@ -2957,10 +2992,13 @@ void main() {
|
|||
expect(firstCharEndpoint.length, 1);
|
||||
// The first character is now offscreen to the left.
|
||||
expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-125, epsilon: 1));
|
||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
|
||||
},
|
||||
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }),
|
||||
skip: true, // https://github.com/flutter/flutter/issues/64059
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'long tap after a double tap select is not affected',
|
||||
'long tap still selects after a double tap select',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
|
@ -2991,10 +3029,10 @@ void main() {
|
|||
await tester.longPressAt(selectableTextStart + const Offset(100.0, 5.0));
|
||||
await tester.pump();
|
||||
|
||||
// Plain collapsed selection at the exact tap position.
|
||||
// Selected the "word" where the tap happened, which is the first space.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 7),
|
||||
const TextSelection(baseOffset: 7, extentOffset: 8),
|
||||
);
|
||||
|
||||
// Long press toolbar.
|
||||
|
@ -3933,38 +3971,4 @@ void main() {
|
|||
TargetPlatform.windows,
|
||||
}),
|
||||
);
|
||||
|
||||
testWidgets('The handles show after pressing Select All (iOS and Mac)', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
child: SelectableText('abc def ghi'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Long press at 'e' in 'def'.
|
||||
final Offset ePos = textOffsetToPosition(tester, 5);
|
||||
await tester.longPressAt(ePos);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Select All'), findsOneWidget);
|
||||
expect(find.text('Copy'), findsNothing);
|
||||
expect(find.text('Paste'), findsNothing);
|
||||
expect(find.text('Cut'), findsNothing);
|
||||
EditableTextState editableText = tester.state(find.byType(EditableText));
|
||||
expect(editableText.selectionOverlay.handlesAreVisible, isFalse);
|
||||
expect(editableText.selectionOverlay.toolbarIsVisible, isTrue);
|
||||
|
||||
await tester.tap(find.text('Select All'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Copy'), findsOneWidget);
|
||||
expect(find.text('Select All'), findsNothing);
|
||||
expect(find.text('Paste'), findsNothing);
|
||||
expect(find.text('Cut'), findsNothing);
|
||||
editableText = tester.state(find.byType(EditableText));
|
||||
expect(editableText.selectionOverlay.handlesAreVisible, isTrue);
|
||||
},
|
||||
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }),
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue