From c33c1178ab3d2517ae2af890dbdcb44d10fffbf2 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sun, 24 May 2026 13:26:55 -0400 Subject: [PATCH] fix(android): split MinstrelNavGraph into NavGraphBuilder extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit detekt LongMethod (97/60 lines). Body had no actual logic — just 13 sequential composable() route declarations. Split by route category (matches the existing comment headers): - inShellTopLevel(navController, expandPlayer) — 8 in-shell tabs - inShellDetail(expandPlayer) — 6 push-on-top detail screens - outsideShell() — NowPlaying (with slide-up transitions), Queue, ServerUrl, Login `MinstrelNavGraph` itself is now 15 lines (NavHost shell that delegates to the three groups), and each helper sits well under the 60-line cap. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../minstrel/nav/MinstrelNavGraph.kt | 211 +++++++++--------- 1 file changed, 102 insertions(+), 109 deletions(-) diff --git a/android/app/src/main/java/com/fabledsword/minstrel/nav/MinstrelNavGraph.kt b/android/app/src/main/java/com/fabledsword/minstrel/nav/MinstrelNavGraph.kt index c1d0a917..7070e03e 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/nav/MinstrelNavGraph.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/nav/MinstrelNavGraph.kt @@ -5,6 +5,7 @@ import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -28,123 +29,115 @@ fun MinstrelNavGraph( modifier: Modifier = Modifier, ) { val expandPlayer = { navController.navigate(NowPlaying) } - NavHost( navController = navController, startDestination = Library, modifier = modifier.fillMaxSize(), ) { - // ── In-shell top-level destinations ─────────────────────────── + inShellTopLevel(navController, expandPlayer) + inShellDetail(expandPlayer) + outsideShell() + } +} - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Home", "Lands in the next design-drift sub-task.") - } - } - - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - LibraryScreen(navController = navController) - } - } - - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Search", "Lands in a later phase.") - } - } - - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Discover", "Lands in Phase 10 (Lidarr requests).") - } - } - - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Playlists", "Lands in Phase 7.") - } - } - - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Settings", "Lands in Phase 11.") - } - } - - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Admin", "Admin landing — lands in a later phase.") - } - } - - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Requests", "Your Lidarr requests — Phase 10.") - } - } - - // ── In-shell detail screens (push-on-top) ───────────────────── - - composable { backStackEntry -> - val route: AlbumDetail = backStackEntry.toRoute() - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Album", "Album detail for ${route.id} — later 5.x slice.") - } - } - - composable { backStackEntry -> - val route: ArtistDetail = backStackEntry.toRoute() - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Artist", "Artist detail for ${route.id} — later 5.x slice.") - } - } - - composable { backStackEntry -> - val route: PlaylistDetail = backStackEntry.toRoute() - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Playlist", "Playlist detail for ${route.id} — Phase 7.") - } - } - - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Admin · Requests", "Lands with admin slice.") - } - } - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Admin · Quarantine", "Lands with admin slice.") - } - } - composable { - ShellScaffold(onExpandPlayer = expandPlayer) { - ComingSoon("Admin · Users", "Lands with admin slice.") - } - } - - // ── Outside-shell full-screen routes ────────────────────────── - - composable( - // Slide up from the bottom on enter; back down on dismiss. - // Mirrors the Flutter CustomTransitionPage (280ms easeOutCubic). - enterTransition = { slideInVertically(initialOffsetY = { it }) }, - exitTransition = { slideOutVertically(targetOffsetY = { it }) }, - popEnterTransition = { slideInVertically(initialOffsetY = { it }) }, - popExitTransition = { slideOutVertically(targetOffsetY = { it }) }, - ) { - NowPlayingScreen() - } - - composable { ComingSoon("Queue", "Lands in a later 6.x slice.") } - - composable { - ComingSoon("Connect to your Minstrel", "Server-URL entry — Phase 11.") - } - composable { - ComingSoon("Sign in", "Login flow — Phase 11.") +private fun NavGraphBuilder.inShellTopLevel( + navController: NavHostController, + expandPlayer: () -> Unit, +) { + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Home", "Lands in the next design-drift sub-task.") } } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + LibraryScreen(navController = navController) + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Search", "Lands in a later phase.") + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Discover", "Lands in Phase 10 (Lidarr requests).") + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Playlists", "Lands in Phase 7.") + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Settings", "Lands in Phase 11.") + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Admin", "Admin landing — lands in a later phase.") + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Requests", "Your Lidarr requests — Phase 10.") + } + } +} + +private fun NavGraphBuilder.inShellDetail(expandPlayer: () -> Unit) { + composable { backStackEntry -> + val route: AlbumDetail = backStackEntry.toRoute() + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Album", "Album detail for ${route.id} — later 5.x slice.") + } + } + composable { backStackEntry -> + val route: ArtistDetail = backStackEntry.toRoute() + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Artist", "Artist detail for ${route.id} — later 5.x slice.") + } + } + composable { backStackEntry -> + val route: PlaylistDetail = backStackEntry.toRoute() + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Playlist", "Playlist detail for ${route.id} — Phase 7.") + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Admin · Requests", "Lands with admin slice.") + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Admin · Quarantine", "Lands with admin slice.") + } + } + composable { + ShellScaffold(onExpandPlayer = expandPlayer) { + ComingSoon("Admin · Users", "Lands with admin slice.") + } + } +} + +private fun NavGraphBuilder.outsideShell() { + composable( + // Slide up from the bottom on enter; back down on dismiss. + // Mirrors the Flutter CustomTransitionPage (280ms easeOutCubic). + enterTransition = { slideInVertically(initialOffsetY = { it }) }, + exitTransition = { slideOutVertically(targetOffsetY = { it }) }, + popEnterTransition = { slideInVertically(initialOffsetY = { it }) }, + popExitTransition = { slideOutVertically(targetOffsetY = { it }) }, + ) { + NowPlayingScreen() + } + composable { ComingSoon("Queue", "Lands in a later 6.x slice.") } + composable { + ComingSoon("Connect to your Minstrel", "Server-URL entry — Phase 11.") + } + composable { ComingSoon("Sign in", "Login flow — Phase 11.") } } @Composable