Skip to content
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

[SuperEditor][SuperReader] - Lock scrolling when content fits within available space (Resolves #1409) #1421

Merged
merged 13 commits into from
Sep 30, 2023
9 changes: 8 additions & 1 deletion super_editor/lib/src/default_editor/document_scrollable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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),
);
Expand All @@ -388,7 +393,9 @@ class AutoScrollController with ChangeNotifier {
}

if (pos is ScrollPositionWithSingleContext) {
pos.goBallistic(pixelsPerSecond);
if (pos.maxScrollExtent > 0) {
matthew-carroll marked this conversation as resolved.
Show resolved Hide resolved
pos.goBallistic(pixelsPerSecond);
}
pos.context.setIgnorePointer(false);
}
}
Expand Down
107 changes: 104 additions & 3 deletions super_editor/test/super_editor/supereditor_scrolling_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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", () {
Expand Down Expand Up @@ -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(
rutvik110 marked this conversation as resolved.
Show resolved Hide resolved
"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<ScrollableState>(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<ScrollableState>(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,
);
});
});
});
}
Expand Down Expand Up @@ -850,3 +941,13 @@ MutableDocument _createExampleDocumentForScrolling() {
],
);
}

final _scrollDirectionVariant = ValueVariant<_ScrollDirection>({
_ScrollDirection.up,
_ScrollDirection.down,
});

enum _ScrollDirection {
up,
down;
}
104 changes: 104 additions & 0 deletions super_editor/test/super_reader/super_reader_scrolling_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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", () {
Expand Down Expand Up @@ -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<ScrollableState>(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<ScrollableState>(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;
}
Loading