Skip to content

Revert "Hide text selection toolbar when dragging handles on mobile" #105247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 5 additions & 65 deletions packages/flutter/lib/src/widgets/text_selection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ export 'package:flutter/services.dart' show TextSelectionDelegate;
/// called.
const Duration _kDragSelectionUpdateThrottle = Duration(milliseconds: 50);

/// A duration that determines the delay before showing the text selection
/// toolbar again after dragging either selection handle on Android. Eyeballed
/// on a Pixel 5 Android API 31 emulator.
const Duration _kAndroidPostDragShowDelay = Duration(milliseconds: 300);

/// Signature for when a pointer that's dragging to select text has moved again.
///
/// The first argument [startDetails] contains the details of the event that
Expand Down Expand Up @@ -787,8 +782,6 @@ class SelectionOverlay {
/// Controls the fade-in and fade-out animations for the toolbar and handles.
static const Duration fadeDuration = Duration(milliseconds: 150);

Timer? _androidPostDragShowTimer;

/// A pair of handles. If this is non-null, there are always 2, though the
/// second is hidden when the selection is collapsed.
List<OverlayEntry>? _handles;
Expand Down Expand Up @@ -828,7 +821,7 @@ class SelectionOverlay {
/// Shows the toolbar by inserting it into the [context]'s overlay.
/// {@endtemplate}
void showToolbar() {
if (_toolbar != null || (_hideToolbarWhenDraggingHandles && _isDraggingHandles)) {
if (_toolbar != null) {
return;
}
_toolbar = OverlayEntry(builder: _buildToolbar);
Expand Down Expand Up @@ -895,62 +888,9 @@ class SelectionOverlay {
/// Disposes this object and release resources.
/// {@endtemplate}
void dispose() {
_androidPostDragShowTimer?.cancel();
_androidPostDragShowTimer = null;
hide();
}

final bool _hideToolbarWhenDraggingHandles =
<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android }.contains(defaultTargetPlatform);

bool _isDraggingStartHandle = false;
bool _isDraggingEndHandle = false;
bool get _isDraggingHandles => _isDraggingStartHandle || _isDraggingEndHandle;

Future<void> _handleDragging() async {
// Hide toolbar while dragging either handle on Android and iOS.
if (!_hideToolbarWhenDraggingHandles)
return;

if (_isDraggingHandles) {
if (defaultTargetPlatform == TargetPlatform.android) {
_androidPostDragShowTimer?.cancel();
_androidPostDragShowTimer = null;
}
hideToolbar();
} else {
if (defaultTargetPlatform == TargetPlatform.android) {
_androidPostDragShowTimer = Timer(_kAndroidPostDragShowDelay, showToolbar);
} else {
showToolbar();
}
}
}

void _onStartHandleDragStart(DragStartDetails details) {
_isDraggingStartHandle = true;
_handleDragging();
onStartHandleDragStart?.call(details);
}

void _onStartHandleDragEnd(DragEndDetails details) {
_isDraggingStartHandle = false;
_handleDragging();
onStartHandleDragEnd?.call(details);
}

void _onEndHandleDragStart(DragStartDetails details) {
_isDraggingEndHandle = true;
_handleDragging();
onEndHandleDragStart?.call(details);
}

void _onEndHandleDragEnd(DragEndDetails details) {
_isDraggingEndHandle = false;
_handleDragging();
onEndHandleDragEnd?.call(details);
}

Widget _buildStartHandle(BuildContext context) {
final Widget handle;
final TextSelectionControls? selectionControls = this.selectionControls;
Expand All @@ -961,9 +901,9 @@ class SelectionOverlay {
type: _startHandleType,
handleLayerLink: startHandleLayerLink,
onSelectionHandleTapped: onSelectionHandleTapped,
onSelectionHandleDragStart: _onStartHandleDragStart,
onSelectionHandleDragStart: onStartHandleDragStart,
onSelectionHandleDragUpdate: onStartHandleDragUpdate,
onSelectionHandleDragEnd: _onStartHandleDragEnd,
onSelectionHandleDragEnd: onStartHandleDragEnd,
selectionControls: selectionControls,
visibility: startHandlesVisible,
preferredLineHeight: _lineHeightAtStart,
Expand All @@ -986,9 +926,9 @@ class SelectionOverlay {
type: _endHandleType,
handleLayerLink: endHandleLayerLink,
onSelectionHandleTapped: onSelectionHandleTapped,
onSelectionHandleDragStart: _onEndHandleDragStart,
onSelectionHandleDragStart: onEndHandleDragStart,
onSelectionHandleDragUpdate: onEndHandleDragUpdate,
onSelectionHandleDragEnd: _onEndHandleDragEnd,
onSelectionHandleDragEnd: onEndHandleDragEnd,
selectionControls: selectionControls,
visibility: endHandlesVisible,
preferredLineHeight: _lineHeightAtEnd,
Expand Down
5 changes: 0 additions & 5 deletions packages/flutter/test/material/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3179,11 +3179,6 @@ void main() {
expect(controller.selection.extentOffset, 50);

if (!isContextMenuProvidedByPlatform) {
if (defaultTargetPlatform == TargetPlatform.android) {
// There should be a delay before the toolbar is shown again on Android.
expect(find.text('Cut'), findsNothing);
await tester.pump(const Duration(milliseconds: 300));
}
await tester.tap(find.text('Cut'));
await tester.pump();
expect(controller.selection.isCollapsed, true);
Expand Down
63 changes: 0 additions & 63 deletions packages/flutter/test/widgets/editable_text_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1553,69 +1553,6 @@ void main() {
// toolbar. Until we change that, this test should remain skipped.
}, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android })); // [intended]

testWidgets('dragging handles hides toolbar on mobile', (WidgetTester tester) async {
controller.text = 'blah blah blah';

await tester.pumpWidget(
MaterialApp(
home: EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
selectionControls: materialTextSelectionControls,
),
),
);

final EditableTextState state =
tester.state<EditableTextState>(find.byType(EditableText));

// Show the toolbar
state.renderEditable.selectWordsInRange(
from: Offset.zero,
cause: SelectionChangedCause.tap,
);
await tester.pump();

expect(state.showToolbar(), true);
await tester.pumpAndSettle();
expect(find.text('Paste'), findsOneWidget);

final List<TextSelectionPoint> endpoints = globalize(
state.renderEditable.getEndpointsForSelection(state.textEditingValue.selection),
state.renderEditable,
);
expect(endpoints.length, 2);

// We use a small offset because the endpoint is on the very corner of the
// handle.
final Offset endHandlePosition = endpoints[1].point + const Offset(1.0, 1.0);

// Select 2 more characters by dragging end handle.
final TestGesture gesture = await tester.startGesture(endHandlePosition);
await gesture.moveTo(textOffsetToPosition(tester, 6));
await tester.pumpAndSettle();
expect(find.text('Paste'), findsNothing);

// End drag gesture and expect toolbar to show again.
await gesture.up();
if (defaultTargetPlatform == TargetPlatform.android) {
// There should be a delay before the toolbar is shown again on Android.
expect(find.text('Paste'), findsNothing);
await tester.pump(const Duration(milliseconds: 300));
}
await tester.pumpAndSettle();
expect(find.text('Paste'), findsOneWidget);

// On web, we don't show the Flutter toolbar and instead rely on the browser
// toolbar. Until we change that, this test should remain skipped.
},
skip: kIsWeb, // [intended]
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android }),
);

testWidgets('Paste is shown only when there is something to paste', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
Expand Down
7 changes: 1 addition & 6 deletions packages/flutter/test/widgets/selectable_text_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1132,12 +1132,7 @@ void main() {
await gesture.moveTo(newHandlePos);
await tester.pump();
await gesture.up();
if (defaultTargetPlatform == TargetPlatform.android) {
// There should be a delay before the toolbar is shown again on Android.
expect(find.text('Cut'), findsNothing);
await tester.pump(const Duration(milliseconds: 300));
}
await tester.pumpAndSettle();
await tester.pump();

expect(controller.selection.baseOffset, 5);
expect(controller.selection.extentOffset, 50);
Expand Down
2 changes: 0 additions & 2 deletions packages/flutter/test/widgets/text_selection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1246,8 +1246,6 @@ void main() {
await gesture2.up();
await tester.pump(const Duration(milliseconds: 20));
expect(endDragEndDetails, isNotNull);

selectionOverlay.dispose();
});
});

Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy