Unverified Commit 24f0d285 authored by Tomasz Gucio's avatar Tomasz Gucio Committed by GitHub

Adjust selection drag start position for viewport offset changes (#80047)

parent 884fdf2e
...@@ -952,7 +952,7 @@ class TextSelectionGestureDetectorBuilder { ...@@ -952,7 +952,7 @@ class TextSelectionGestureDetectorBuilder {
@protected @protected
final TextSelectionGestureDetectorBuilderDelegate delegate; final TextSelectionGestureDetectorBuilderDelegate delegate;
/// Returns true iff lastSecondaryTapDownPosition was on selection. /// Returns true if lastSecondaryTapDownPosition was on selection.
bool get _lastSecondaryTapWasOnSelection { bool get _lastSecondaryTapWasOnSelection {
assert(renderEditable.lastSecondaryTapDownPosition != null); assert(renderEditable.lastSecondaryTapDownPosition != null);
if (renderEditable.selection == null) { if (renderEditable.selection == null) {
...@@ -985,6 +985,9 @@ class TextSelectionGestureDetectorBuilder { ...@@ -985,6 +985,9 @@ class TextSelectionGestureDetectorBuilder {
@protected @protected
RenderEditable get renderEditable => editableText.renderEditable; RenderEditable get renderEditable => editableText.renderEditable;
/// The viewport offset pixels of the [RenderEditable] at the last drag start.
double _dragStartViewportOffset = 0.0;
/// Handler for [TextSelectionGestureDetector.onTapDown]. /// Handler for [TextSelectionGestureDetector.onTapDown].
/// ///
/// By default, it forwards the tap to [RenderEditable.handleTapDown] and sets /// By default, it forwards the tap to [RenderEditable.handleTapDown] and sets
...@@ -1197,6 +1200,8 @@ class TextSelectionGestureDetectorBuilder { ...@@ -1197,6 +1200,8 @@ class TextSelectionGestureDetectorBuilder {
from: details.globalPosition, from: details.globalPosition,
cause: SelectionChangedCause.drag, cause: SelectionChangedCause.drag,
); );
_dragStartViewportOffset = renderEditable.offset.pixels;
} }
/// Handler for [TextSelectionGestureDetector.onDragSelectionUpdate]. /// Handler for [TextSelectionGestureDetector.onDragSelectionUpdate].
...@@ -1212,8 +1217,14 @@ class TextSelectionGestureDetectorBuilder { ...@@ -1212,8 +1217,14 @@ class TextSelectionGestureDetectorBuilder {
void onDragSelectionUpdate(DragStartDetails startDetails, DragUpdateDetails updateDetails) { void onDragSelectionUpdate(DragStartDetails startDetails, DragUpdateDetails updateDetails) {
if (!delegate.selectionEnabled) if (!delegate.selectionEnabled)
return; return;
// Adjust the drag start offset for possible viewport offset changes.
final Offset startOffset = renderEditable.maxLines == 1
? Offset(renderEditable.offset.pixels - _dragStartViewportOffset, 0.0)
: Offset(0.0, renderEditable.offset.pixels - _dragStartViewportOffset);
renderEditable.selectPositionAt( renderEditable.selectPositionAt(
from: startDetails.globalPosition, from: startDetails.globalPosition - startOffset,
to: updateDetails.globalPosition, to: updateDetails.globalPosition,
cause: SelectionChangedCause.drag, cause: SelectionChangedCause.drag,
); );
...@@ -1618,7 +1629,7 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget ...@@ -1618,7 +1629,7 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget
}) : super(value); }) : super(value);
bool _disposed = false; bool _disposed = false;
/// True iff this instance has been disposed. /// True if this instance has been disposed.
bool get disposed => _disposed; bool get disposed => _disposed;
/// Check the [Clipboard] and update [value] if needed. /// Check the [Clipboard] and update [value] if needed.
......
...@@ -624,6 +624,44 @@ void main() { ...@@ -624,6 +624,44 @@ void main() {
expect(editableText.selectionOverlay!.toolbarIsVisible, isFalse); expect(editableText.selectionOverlay!.toolbarIsVisible, isFalse);
}); });
testWidgets('test TextSelectionGestureDetectorBuilder drag with RenderEditable viewport offset change', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester);
final FakeRenderEditable renderEditable = tester.renderObject(find.byType(FakeEditable));
// Reconfigure the RenderEditable for multi-line.
renderEditable.maxLines = null;
renderEditable.offset = ViewportOffset.fixed(20.0);
renderEditable.layout(const BoxConstraints.tightFor(width: 400, height: 300.0));
await tester.pumpAndSettle();
final TestGesture gesture = await tester.startGesture(
const Offset(200.0, 200.0),
kind: PointerDeviceKind.mouse,
);
addTearDown(gesture.removePointer);
await tester.pumpAndSettle();
expect(renderEditable.selectPositionAtCalled, isFalse);
await gesture.moveTo(const Offset(300.0, 200.0));
await tester.pumpAndSettle();
expect(renderEditable.selectPositionAtCalled, isTrue);
expect(renderEditable.selectPositionAtFrom, const Offset(200.0, 200.0));
expect(renderEditable.selectPositionAtTo, const Offset(300.0, 200.0));
// Move the viewport offset (scroll).
renderEditable.offset = ViewportOffset.fixed(150.0);
renderEditable.layout(const BoxConstraints.tightFor(width: 400, height: 300.0));
await tester.pumpAndSettle();
await gesture.moveTo(const Offset(300.0, 400.0));
await tester.pumpAndSettle();
await gesture.up();
await tester.pumpAndSettle();
expect(renderEditable.selectPositionAtCalled, isTrue);
expect(renderEditable.selectPositionAtFrom, const Offset(200.0, 70.0));
expect(renderEditable.selectPositionAtTo, const Offset(300.0, 400.0));
});
testWidgets('test TextSelectionGestureDetectorBuilder selection disabled', (WidgetTester tester) async { testWidgets('test TextSelectionGestureDetectorBuilder selection disabled', (WidgetTester tester) async {
await pumpTextSelectionGestureDetectorBuilder(tester, selectionEnabled: false); await pumpTextSelectionGestureDetectorBuilder(tester, selectionEnabled: false);
final TestGesture gesture = await tester.startGesture( final TestGesture gesture = await tester.startGesture(
...@@ -863,9 +901,13 @@ class FakeRenderEditable extends RenderEditable { ...@@ -863,9 +901,13 @@ class FakeRenderEditable extends RenderEditable {
} }
bool selectPositionAtCalled = false; bool selectPositionAtCalled = false;
Offset? selectPositionAtFrom;
Offset? selectPositionAtTo;
@override @override
void selectPositionAt({ required Offset from, Offset? to, required SelectionChangedCause cause }) { void selectPositionAt({ required Offset from, Offset? to, required SelectionChangedCause cause }) {
selectPositionAtCalled = true; selectPositionAtCalled = true;
selectPositionAtFrom = from;
selectPositionAtTo = to;
} }
bool selectWordCalled = false; bool selectWordCalled = false;
......
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