diff --git a/super_editor/lib/src/default_editor/document_scrollable.dart b/super_editor/lib/src/default_editor/document_scrollable.dart index 96f6b59a02..1585c73512 100644 --- a/super_editor/lib/src/default_editor/document_scrollable.dart +++ b/super_editor/lib/src/default_editor/document_scrollable.dart @@ -373,6 +373,11 @@ class AutoScrollController with ChangeNotifier { } final scrollPosition = _getScrollPosition!(); + + if (scrollPosition.maxScrollExtent == 0) { + return; + } + scrollPosition.jumpTo( (scrollPosition.pixels + delta).clamp(0.0, scrollPosition.maxScrollExtent), ); @@ -388,7 +393,9 @@ class AutoScrollController with ChangeNotifier { } if (pos is ScrollPositionWithSingleContext) { - pos.goBallistic(pixelsPerSecond); + if (pos.maxScrollExtent > 0) { + pos.goBallistic(pixelsPerSecond); + } pos.context.setIgnorePointer(false); } } diff --git a/super_editor/test/super_editor/supereditor_scrolling_test.dart b/super_editor/test/super_editor/supereditor_scrolling_test.dart index 05b521616d..ece7e73991 100644 --- a/super_editor/test/super_editor/supereditor_scrolling_test.dart +++ b/super_editor/test/super_editor/supereditor_scrolling_test.dart @@ -9,6 +9,7 @@ import 'package:super_editor/super_editor.dart'; import 'package:super_editor/super_editor_test.dart'; import 'supereditor_test_tools.dart'; +import 'test_documents.dart'; void main() { group("SuperEditor scrolling", () { @@ -682,11 +683,101 @@ void main() { // Ensure SuperEditor has scrolled expect(editorScrollController.offset, greaterThan(0)); - - // Ensure that scrolling didn't scroll the ListView - expect(listScrollController.position.pixels, equals(0)); }); }); + + group("when all content fits in the viewport", () { + testWidgetsOnDesktop( + "trackpad doesn't scroll content", + (tester) async { + tester.view.physicalSize = const Size(800, 600); + + final isScrollingUp = _scrollDirectionVariant.currentValue == _ScrollDirection.up; + + await tester // + .createDocument() + .withCustomContent( + paragraphThenHrThenParagraphDoc() + ..insertNodeAt( + 0, + ParagraphNode( + id: Editor.createNodeId(), + text: AttributedText('Document #1'), + metadata: { + 'blockType': header1Attribution, + }, + ), + ), + ) + .pump(); + + final scrollState = tester.state(find.byType(Scrollable)); + + // Perform a fling on the editor to attemp scrolling. + await tester.trackpadFling( + find.byType(SuperEditor), + Offset(0.0, isScrollingUp ? 100 : -100), + 300, + ); + + await tester.pump(); + + // Ensure SuperEditor is not scrolling. + expect(scrollState.position.activity?.isScrolling, false); + }, + variant: _scrollDirectionVariant, + ); + + testWidgetsOnDesktop( + "mouse scroll wheel doesn't scroll content", + (tester) async { + tester.view.physicalSize = const Size(800, 600); + + final isScrollUp = _scrollDirectionVariant.currentValue == _ScrollDirection.up; + + await tester // + .createDocument() + .withCustomContent( + paragraphThenHrThenParagraphDoc() + ..insertNodeAt( + 0, + ParagraphNode( + id: Editor.createNodeId(), + text: AttributedText('Document #1'), + metadata: { + 'blockType': header1Attribution, + }, + ), + ), + ) + .pump(); + + final scrollState = tester.state(find.byType(Scrollable)); + + final Offset scrollEventLocation = tester.getCenter(find.byType(SuperEditor)); + final TestPointer testPointer = TestPointer(1, PointerDeviceKind.mouse); + + // Send initial pointer event to set the location for subsequent pointer scroll events. + await tester.sendEventToBinding(testPointer.hover(scrollEventLocation)); + + // Send pointer scroll event to start scrolling. + await tester.sendEventToBinding( + testPointer.scroll( + Offset( + 0.0, + isScrollUp ? 100 : -100.0, + ), + ), + ); + + await tester.pump(); + + // Ensure SuperReader is not scrolling. + expect(scrollState.position.activity!.isScrolling, false); + }, + variant: _scrollDirectionVariant, + ); + }); }); }); } @@ -850,3 +941,13 @@ MutableDocument _createExampleDocumentForScrolling() { ], ); } + +final _scrollDirectionVariant = ValueVariant<_ScrollDirection>({ + _ScrollDirection.up, + _ScrollDirection.down, +}); + +enum _ScrollDirection { + up, + down; +} diff --git a/super_editor/test/super_reader/super_reader_scrolling_test.dart b/super_editor/test/super_reader/super_reader_scrolling_test.dart index aded3271dd..623511e127 100644 --- a/super_editor/test/super_reader/super_reader_scrolling_test.dart +++ b/super_editor/test/super_reader/super_reader_scrolling_test.dart @@ -6,6 +6,7 @@ import 'package:super_editor/super_editor.dart'; import 'package:super_editor/super_reader_test.dart'; import 'reader_test_tools.dart'; +import 'test_documents.dart'; void main() { group("SuperReader scrolling", () { @@ -218,5 +219,108 @@ void main() { isTrue, ); }); + + group("when all content fits in the viewport", () { + testWidgetsOnDesktop( + "trackpad doesn't scroll content", + (tester) async { + tester.view.physicalSize = const Size(800, 600); + + final isScrollUp = _scrollDirectionVariant.currentValue == _ScrollDirection.up; + + await tester // + .createDocument() + .withCustomContent( + paragraphThenHrThenParagraphDoc() + ..insertNodeAt( + 0, + ParagraphNode( + id: Editor.createNodeId(), + text: AttributedText('Document #1'), + metadata: { + 'blockType': header1Attribution, + }, + ), + ), + ) + .pump(); + + final scrollState = tester.state(find.byType(Scrollable)); + + // Perform a fling on the reader to attemp scrolling. + await tester.trackpadFling( + find.byType(SuperReader), + Offset(0.0, isScrollUp ? 100 : -100), + 300, + ); + + await tester.pump(); + + // Ensure SuperReader is not scrolling. + expect(scrollState.position.activity?.isScrolling, false); + }, + variant: _scrollDirectionVariant, + ); + + testWidgetsOnDesktop( + "mouse scroll wheel doesn't scroll content", + (tester) async { + tester.view.physicalSize = const Size(800, 600); + + final isScrollUp = _scrollDirectionVariant.currentValue == _ScrollDirection.up; + + await tester // + .createDocument() + .withCustomContent( + paragraphThenHrThenParagraphDoc() + ..insertNodeAt( + 0, + ParagraphNode( + id: Editor.createNodeId(), + text: AttributedText('Document #1'), + metadata: { + 'blockType': header1Attribution, + }, + ), + ), + ) + .pump(); + + final scrollState = tester.state(find.byType(Scrollable)); + + final Offset scrollEventLocation = tester.getCenter(find.byType(SuperReader)); + final TestPointer testPointer = TestPointer(1, PointerDeviceKind.mouse); + + // Send initial pointer event to set the location for subsequent pointer scroll events. + await tester.sendEventToBinding(testPointer.hover(scrollEventLocation)); + + // Send pointer scroll event to start scrolling. + await tester.sendEventToBinding( + testPointer.scroll( + Offset( + 0.0, + isScrollUp ? 100 : -100.0, + ), + ), + ); + + await tester.pump(); + + // Ensure SuperReader is not scrolling. + expect(scrollState.position.activity!.isScrolling, false); + }, + variant: _scrollDirectionVariant, + ); + }); }); } + +final _scrollDirectionVariant = ValueVariant<_ScrollDirection>({ + _ScrollDirection.up, + _ScrollDirection.down, +}); + +enum _ScrollDirection { + up, + down; +}