diff --git a/flutter_client/lib/player/now_playing_screen.dart b/flutter_client/lib/player/now_playing_screen.dart index 804c4ef3..e7547b7e 100644 --- a/flutter_client/lib/player/now_playing_screen.dart +++ b/flutter_client/lib/player/now_playing_screen.dart @@ -397,6 +397,12 @@ class _SecondaryControls extends StatelessWidget { streamUrl: '', ), hideQueueActions: true, + // /now-playing lives outside the ShellRoute. Pushing + // /artists/:id or /albums/:id (both shell-children) on top + // of it would make go_router try to mount a duplicate + // ShellRoute. Pop ourselves first so the destination route + // mounts cleanly inside the existing shell. + onBeforeNavigate: () => Navigator.of(context).maybePop(), ), ], ); diff --git a/flutter_client/lib/shared/widgets/track_actions/track_actions_button.dart b/flutter_client/lib/shared/widgets/track_actions/track_actions_button.dart index cd293209..61b67575 100644 --- a/flutter_client/lib/shared/widgets/track_actions/track_actions_button.dart +++ b/flutter_client/lib/shared/widgets/track_actions/track_actions_button.dart @@ -11,6 +11,7 @@ class TrackActionsButton extends StatelessWidget { super.key, required this.track, this.hideQueueActions = false, + this.onBeforeNavigate, }); final TrackRef track; @@ -19,6 +20,11 @@ class TrackActionsButton extends StatelessWidget { /// screen where the menu's track IS the currently-playing one. final bool hideQueueActions; + /// Forwarded to TrackActionsSheet.onBeforeNavigate. Use to dismiss + /// the host route before "Go to album" / "Go to artist" pushes the + /// detail screen. + final void Function()? onBeforeNavigate; + @override Widget build(BuildContext context) { final fs = Theme.of(context).extension()!; @@ -29,6 +35,7 @@ class TrackActionsButton extends StatelessWidget { context, track, hideQueueActions: hideQueueActions, + onBeforeNavigate: onBeforeNavigate, ), ); } diff --git a/flutter_client/lib/shared/widgets/track_actions/track_actions_sheet.dart b/flutter_client/lib/shared/widgets/track_actions/track_actions_sheet.dart index c3adaf7e..b689f70d 100644 --- a/flutter_client/lib/shared/widgets/track_actions/track_actions_sheet.dart +++ b/flutter_client/lib/shared/widgets/track_actions/track_actions_sheet.dart @@ -21,15 +21,25 @@ class TrackActionsSheet extends ConsumerWidget { super.key, required this.track, required this.hideQueueActions, + this.onBeforeNavigate, }); final TrackRef track; final bool hideQueueActions; + /// Optional hook invoked just before "Go to album" / "Go to artist" + /// pushes the destination route. Lets callers that live OUTSIDE the + /// ShellRoute (e.g. the full player at /now-playing) pop themselves + /// first, so go_router doesn't try to mount a second ShellRoute on + /// top of the active top-level route — the same duplicate-page-key + /// failure mode we hit when /queue lived inside the shell. + final void Function()? onBeforeNavigate; + static Future show( BuildContext context, TrackRef track, { bool hideQueueActions = false, + void Function()? onBeforeNavigate, }) { return showModalBottomSheet( context: context, @@ -37,6 +47,7 @@ class TrackActionsSheet extends ConsumerWidget { builder: (_) => TrackActionsSheet( track: track, hideQueueActions: hideQueueActions, + onBeforeNavigate: onBeforeNavigate, ), ); } @@ -141,6 +152,7 @@ class TrackActionsSheet extends ConsumerWidget { label: 'Go to album', onTap: () { Navigator.pop(context); + onBeforeNavigate?.call(); context.push('/albums/${track.albumId}'); }, ), @@ -150,6 +162,7 @@ class TrackActionsSheet extends ConsumerWidget { label: 'Go to artist', onTap: () { Navigator.pop(context); + onBeforeNavigate?.call(); context.push('/artists/${track.artistId}'); }, ),