fix: optimized swiping and address bar toggle on tap
This commit is contained in:
parent
ac998b394d
commit
0e2027c9e2
5 changed files with 466 additions and 78 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:flutter/gestures.dart' show kLongPressTimeout;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
|
|
@ -21,9 +22,11 @@ SwipeNavigator _navigator({
|
|||
bool canGoBack = true,
|
||||
bool canGoForward = true,
|
||||
double? contentWidth,
|
||||
bool swipesAnywhere = false,
|
||||
}) =>
|
||||
SwipeNavigator(
|
||||
contentWidth: contentWidth,
|
||||
swipesAnywhere: swipesAnywhere,
|
||||
canGoBack: canGoBack,
|
||||
canGoForward: canGoForward,
|
||||
backTitle: 'Previous page',
|
||||
|
|
@ -124,6 +127,50 @@ void main() {
|
|||
expect(back, 1);
|
||||
});
|
||||
|
||||
testWidgets('with swipes anywhere, a drag over the page navigates',
|
||||
(tester) async {
|
||||
var back = 0;
|
||||
await tester.pumpWidget(_wrap(_navigator(
|
||||
onBack: () => back++,
|
||||
onForward: () {},
|
||||
swipesAnywhere: true,
|
||||
)));
|
||||
|
||||
// The middle of the page carries the swipe, where a margin would be.
|
||||
final center = tester.getCenter(find.byType(SwipeNavigator));
|
||||
final gesture = await tester.startGesture(center);
|
||||
await gesture.moveBy(const Offset(300, 0));
|
||||
await tester.pump();
|
||||
expect(find.text('Previous page'), findsOneWidget);
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
expect(back, 1);
|
||||
});
|
||||
|
||||
testWidgets('a finger held long enough to select keeps its drag',
|
||||
(tester) async {
|
||||
var back = 0;
|
||||
await tester.pumpWidget(_wrap(_navigator(
|
||||
onBack: () => back++,
|
||||
onForward: () {},
|
||||
swipesAnywhere: true,
|
||||
)));
|
||||
|
||||
// Sideways travel after the long-press window belongs to a selection,
|
||||
// not to the walk.
|
||||
final center = tester.getCenter(find.byType(SwipeNavigator));
|
||||
final gesture = await tester.startGesture(center);
|
||||
await gesture.moveBy(
|
||||
const Offset(300, 0),
|
||||
timeStamp: kLongPressTimeout + const Duration(milliseconds: 1),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(find.text('Previous page'), findsNothing);
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
expect(back, 0);
|
||||
});
|
||||
|
||||
testWidgets('drags over the content column still belong to selection',
|
||||
(tester) async {
|
||||
var back = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue