Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions lib/screenshot/offscreen_capture.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,24 @@ Widget wrapForOffscreenCapture(
return MaterialApp(
theme: Theme.of(context),
debugShowCheckedModeBanner: false,
home: child,
builder: (context, child) {
// No `home`: with one, the app builds its own navigator, and an
// app's navigator reports its route to the browser. Every capture
// then rewrote the address of the page to `/`, and a reload after
// a screenshot opened the library instead of the strategy. The
// navigator below gives the captured view the route and overlay it
// expects and reports nothing.
builder: (context, _) {
// The captured view paints its own backdrop, or none for a
// transparent screenshot, so the shell paints nothing under it.
return Portal(
child: ShadAppBuilder(
backgroundColor: Colors.transparent,
child: child!,
child: Navigator(
onGenerateRoute: (settings) => MaterialPageRoute<void>(
settings: settings,
builder: (context) => child,
),
),
),
);
},
Expand Down
43 changes: 43 additions & 0 deletions test/offscreen_capture_route_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:icarus/screenshot/offscreen_capture.dart';

void main() {
testWidgets('a capture does not tell the browser the page moved',
(tester) async {
// On web the address is where a reload reopens the editor. The capture
// shell used to be an app with its own navigator, which reported `/` as
// the page's route: after a screenshot, a reload opened the library.
final reported = <String>[];
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.navigation,
(call) async {
if (call.method == 'routeInformationUpdated') {
reported.add((call.arguments as Map)['uri'] as String);
}
return null;
},
);
addTearDown(
() => tester.binding.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.navigation, null),
);

late BuildContext captured;
await tester.pumpWidget(wrapForOffscreenCapture(
Builder(builder: (context) {
captured = context;
return const Text('captured view');
}),
));
await tester.pump();

expect(find.text('captured view'), findsOneWidget);
expect(reported, isEmpty);
// What the captured view still gets from the shell.
expect(Navigator.maybeOf(captured), isNotNull);
expect(Overlay.maybeOf(captured), isNotNull);
expect(ModalRoute.of(captured), isNotNull);
});
}
Loading