diff --git a/lib/widgets/image_viewer.dart b/lib/widgets/image_viewer.dart index 12317a4..81ca4a8 100644 --- a/lib/widgets/image_viewer.dart +++ b/lib/widgets/image_viewer.dart @@ -31,9 +31,20 @@ class ImageViewer extends StatefulWidget { // an indicator like "5/3". Clamp instead of trusting the caller. final index = initialIndex.clamp(0, images.length - 1); Navigator.of(context, rootNavigator: true).push( - MaterialPageRoute( - builder: (context) => ImageViewer(images: images, initialIndex: index), + PageRouteBuilder( fullscreenDialog: true, + // Not a MaterialPageRoute: Android's M3 zoom transition scale-fades + // the incoming route, which on a black page holding one image reads + // as a ghost of the image growing into place. A quick plain fade + // fits a lightbox. + transitionDuration: const Duration(milliseconds: 150), + reverseTransitionDuration: const Duration(milliseconds: 150), + pageBuilder: + (context, animation, secondaryAnimation) => + ImageViewer(images: images, initialIndex: index), + transitionsBuilder: + (context, animation, secondaryAnimation, child) => + FadeTransition(opacity: animation, child: child), ), ); } diff --git a/test/widgets/detailed_post_view_media_test.dart b/test/widgets/detailed_post_view_media_test.dart index 53fa113..6035603 100644 --- a/test/widgets/detailed_post_view_media_test.dart +++ b/test/widgets/detailed_post_view_media_test.dart @@ -49,10 +49,12 @@ class _RecordingObserver extends NavigatorObserver { /// /// MaterialApp's own initial `/` route is a `MaterialPageRoute`, /// and Dart treats `dynamic` and `void` as mutual subtypes — so a plain - /// `whereType>()` would count it too. Callers - /// clear the log after pumping, and this getter is what they assert on. - List> get pushedPages => - pushed.whereType>().toList(); + /// `whereType>()` would count it too. Callers clear the + /// log after pumping, and this getter is what they assert on. PageRoute + /// rather than MaterialPageRoute: the image viewer pushes a + /// PageRouteBuilder to opt out of the M3 zoom transition. + List> get pushedPages => + pushed.whereType>().toList(); /// Forgets routes recorded during setup, so only taps are counted. void reset() => pushed.clear(); @@ -903,7 +905,7 @@ void main() { expect( observer.pushedPages, hasLength(1), - reason: 'image tap pushes exactly one MaterialPageRoute', + reason: 'image tap pushes exactly one page route', ); await tester.pumpAndSettle(); @@ -1264,7 +1266,9 @@ void main() { final videoRoutes = observer.pushedPages; expect(videoRoutes, hasLength(1)); - final page = videoRoutes.single.builder( + // The video player still pushes a MaterialPageRoute; the cast is what + // exposes `builder` for building the page without mounting it. + final page = (videoRoutes.single as MaterialPageRoute).builder( tester.element(find.byKey(_videoKey)), ); expect(page, isA());