fix: optimized swiping and address bar toggle on tap

This commit is contained in:
randogoth 2026-10-12 09:52:28 +03:00
parent ac998b394d
commit 0e2027c9e2
5 changed files with 466 additions and 78 deletions

View file

@ -485,6 +485,61 @@ void main() {
expect(find.byType(AddressBar), findsOneWidget);
});
testWidgets('a short tap on the page brings a hidden address bar back',
(tester) async {
await pumpApp(tester);
// A page long enough to scroll.
final tall = pageSource.replaceFirst(
'</body>',
'<p>Padding paragraph to make the page scroll.</p>' * 80 + '</body>');
final page = parseSource(tall, 'https://example.com/index.html');
deps.browser.currentPage.value = page;
await tester.pumpAndSettle();
// Scrolling down hides the address bar.
await tester.drag(find.byType(ListView), const Offset(0, -300));
await tester.pumpAndSettle();
expect(find.byType(AddressBar), findsNothing);
// A short tap on the page text returns it, the way a reader reaches
// for it on a page that has nothing left to scroll.
await tester.tapAt(tester.getCenter(find.byType(ListView)));
await tester.pumpAndSettle();
expect(find.byType(AddressBar), findsOneWidget);
// A short tap hides it again.
await tester.tapAt(tester.getCenter(find.byType(ListView)));
await tester.pumpAndSettle();
expect(find.byType(AddressBar), findsNothing);
});
testWidgets('a tap that opens a link keeps the address bar where it was',
(tester) async {
final sources = {
'https://example.com/index.html': _page(
'Index', '<h1>Index</h1><p><a href="next.html">The next page</a></p>'),
'https://example.com/next.html':
_page('Next', '<h1>Next</h1><p>The second page.</p>'),
};
final stubDeps = AppDependencies(
database: MewsDatabase.test(NativeDatabase.memory()),
fetch: FakeFetch(sources),
strings: strings,
);
await tester.pumpWidget(MewsApp(deps: stubDeps, strings: strings));
await tester.pumpAndSettle();
await stubDeps.browser.open('https://example.com/index.html');
await tester.pumpAndSettle();
// The tap follows a link, so it does not spend itself on the chrome.
await tapRun(tester, 'The next page');
expect(stubDeps.browser.currentPage.value?.url, 'https://example.com/next.html');
expect(find.byType(AddressBar), findsOneWidget);
});
testWidgets('swiping back shows the previous page during the drag',
(tester) async {
final sources = {
@ -528,6 +583,102 @@ void main() {
expect(find.text('https://example.com/a.html'), findsOneWidget);
});
testWidgets('a swipe across the body navigates on a touch host',
(tester) async {
final sources = {
'https://example.com/a.html':
_page('Page A', '<h1>Page A</h1><p>The first pages content.</p>'),
'https://example.com/b.html':
_page('Page B', '<h1>Page B</h1><p>The second pages content.</p>'),
};
final stubDeps = AppDependencies(
database: MewsDatabase.test(NativeDatabase.memory()),
fetch: FakeFetch(sources),
strings: strings,
);
await tester.pumpWidget(MewsApp(deps: stubDeps, strings: strings));
await tester.pumpAndSettle();
await stubDeps.browser.open('https://example.com/a.html');
await stubDeps.browser.open('https://example.com/b.html');
await _pumpUntil(tester, () => stubDeps.browser.backPage.value != null);
// The drag starts over the body text, not in an edge margin; a swipe
// crosses the slop before the long press that starts a selection.
final center = tester.getCenter(find.byType(SwipeNavigator));
final gesture = await tester.startGesture(center);
for (var i = 0; i < 6; i++) {
await gesture.moveBy(const Offset(70, 0));
await tester.pump();
}
await gesture.up();
await tester.pumpAndSettle();
expect(stubDeps.browser.currentPage.value?.url, 'https://example.com/a.html');
});
testWidgets('a long press on body text keeps its drag for selection',
(tester) async {
final sources = {
'https://example.com/a.html':
_page('Page A', '<h1>Page A</h1><p>The first pages content.</p>'),
'https://example.com/b.html':
_page('Page B', '<h1>Page B</h1><p>The second pages content.</p>'),
};
final stubDeps = AppDependencies(
database: MewsDatabase.test(NativeDatabase.memory()),
fetch: FakeFetch(sources),
strings: strings,
);
await tester.pumpWidget(MewsApp(deps: stubDeps, strings: strings));
await tester.pumpAndSettle();
await stubDeps.browser.open('https://example.com/a.html');
await stubDeps.browser.open('https://example.com/b.html');
await _pumpUntil(tester, () => stubDeps.browser.backPage.value != null);
// Hold on the paragraph long enough for the selection to begin, then
// drag sideways: the selection keeps the finger, the page stays put.
final text = tester.getCenter(find.textContaining('The second pages content'));
final gesture = await tester.startGesture(text);
await tester.pump(const Duration(milliseconds: 550));
await gesture.moveBy(
const Offset(300, 0),
timeStamp: const Duration(milliseconds: 600),
);
await tester.pump();
// No neighbor peeks in; the swipe never started.
expect(find.text('Page A'), findsNothing);
await gesture.up();
await tester.pumpAndSettle();
expect(stubDeps.browser.currentPage.value?.url, 'https://example.com/b.html');
});
testWidgets('the chrome starts below the status bar on a phone',
(tester) async {
// View padding arrives in physical pixels; the framework scales it by
// the device pixel ratio to the logical inset the reader sits below.
final previous = tester.view.padding;
tester.view.padding = FakeViewPadding(
left: 0,
right: 0,
top: 44 * tester.view.devicePixelRatio,
bottom: 0,
);
addTearDown(() => tester.view.padding = previous);
final stubDeps = AppDependencies(
database: MewsDatabase.test(NativeDatabase.memory()),
fetch: FakeFetch(const {}),
strings: strings,
);
await tester.pumpWidget(MewsApp(deps: stubDeps, strings: strings));
await tester.pumpAndSettle();
expect(tester.getTopLeft(find.byType(AddressBar)).dy, 44);
});
testWidgets('falls back to the wap subdomain before showing an error',
(tester) async {
final stubDeps = AppDependencies(