refactor: extract MainScaffold for better separation of navigation chrome logic
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
package bzh.ajaury.chombev
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.saveable.rememberSerializable
|
||||
@@ -13,8 +11,7 @@ import androidx.savedstate.compose.serialization.serializers.SnapshotStateListSe
|
||||
import bzh.ajaury.chombev.core.coroutines.di.coroutinesModule
|
||||
import bzh.ajaury.chombev.core.logging.di.loggingModule
|
||||
import bzh.ajaury.chombev.di.sharedModule
|
||||
import bzh.ajaury.chombev.navigation.MainBottomBar
|
||||
import bzh.ajaury.chombev.navigation.MainTopBar
|
||||
import bzh.ajaury.chombev.navigation.MainScaffold
|
||||
import bzh.ajaury.chombev.navigation.Route
|
||||
import bzh.ajaury.chombev.navigation.WebPages
|
||||
import bzh.ajaury.chombev.player.ui.PlayerScreen
|
||||
@@ -49,38 +46,21 @@ fun App() {
|
||||
|
||||
val darkTheme = isSystemInDarkTheme()
|
||||
|
||||
// The current top destination drives the shared chrome: the top and bottom bars are shown
|
||||
// only on the main screens (Records and the web pages), not on the Player detail screen.
|
||||
val currentRoute = backStack.lastOrNull()
|
||||
val selectedPage = (currentRoute as? Route.Web)?.page
|
||||
val isMainScreen = currentRoute is Route.Records || currentRoute is Route.Web
|
||||
|
||||
ChomBevTheme(darkTheme = darkTheme) {
|
||||
Scaffold(
|
||||
// Let each screen's bars/insets apply; keeps the Player's own scaffold from double-padding.
|
||||
contentWindowInsets = WindowInsets(0, 0, 0, 0),
|
||||
topBar = {
|
||||
if (isMainScreen) {
|
||||
MainTopBar()
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
if (isMainScreen) {
|
||||
MainBottomBar(
|
||||
selectedPage = selectedPage,
|
||||
onRecordsClick = { backStack.selectMainTab(null) },
|
||||
onDeepenClick = { backStack.selectMainTab(WebPages.DEEPEN) },
|
||||
onAboutClick = { backStack.selectMainTab(WebPages.ABOUT) },
|
||||
)
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
NavDisplay(
|
||||
backStack = backStack,
|
||||
onBack = { backStack.removeLastOrNull() },
|
||||
entryProvider = { key ->
|
||||
when (key) {
|
||||
is Route.Records -> NavEntry(key) {
|
||||
// Each destination owns its chrome (see MainScaffold) so navigating to the full-screen
|
||||
// player animates as a whole scene without the main bars reflowing the outgoing screen.
|
||||
NavDisplay(
|
||||
backStack = backStack,
|
||||
onBack = { backStack.removeLastOrNull() },
|
||||
entryProvider = { key ->
|
||||
when (key) {
|
||||
is Route.Records -> NavEntry(key) {
|
||||
MainScaffold(
|
||||
selectedPage = null,
|
||||
onRecordsClick = { backStack.selectMainTab(null) },
|
||||
onDeepenClick = { backStack.selectMainTab(WebPages.DEEPEN) },
|
||||
onAboutClick = { backStack.selectMainTab(WebPages.ABOUT) },
|
||||
) { innerPadding ->
|
||||
RecordsScreen(
|
||||
contentPadding = innerPadding,
|
||||
onRecordClick = { record ->
|
||||
@@ -88,15 +68,22 @@ fun App() {
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is Route.Player -> NavEntry(key) {
|
||||
PlayerScreen(
|
||||
recordId = key.recordId,
|
||||
onBackClicked = { backStack.removeLastOrNull() },
|
||||
)
|
||||
}
|
||||
is Route.Player -> NavEntry(key) {
|
||||
PlayerScreen(
|
||||
recordId = key.recordId,
|
||||
onBackClicked = { backStack.removeLastOrNull() },
|
||||
)
|
||||
}
|
||||
|
||||
is Route.Web -> NavEntry(key) {
|
||||
is Route.Web -> NavEntry(key) {
|
||||
MainScaffold(
|
||||
selectedPage = key.page,
|
||||
onRecordsClick = { backStack.selectMainTab(null) },
|
||||
onDeepenClick = { backStack.selectMainTab(WebPages.DEEPEN) },
|
||||
onAboutClick = { backStack.selectMainTab(WebPages.ABOUT) },
|
||||
) { innerPadding ->
|
||||
WebViewScreen(
|
||||
page = key.page,
|
||||
contentPadding = innerPadding,
|
||||
@@ -104,9 +91,9 @@ fun App() {
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package bzh.ajaury.chombev.navigation
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import bzh.ajaury.chombev.web.model.WebPage
|
||||
|
||||
/**
|
||||
* Scaffold shared by the main destinations (Records, Deepen, About): the app [MainTopBar] and the
|
||||
* [MainBottomBar].
|
||||
*
|
||||
* Each main destination wraps its own content in a [MainScaffold] rather than sitting inside one
|
||||
* shared outer scaffold. This keeps the chrome part of the destination, so it animates with it and
|
||||
* its content padding stays stable during navigation — avoiding the layout jump that happened when
|
||||
* pushing a full-screen detail (the player) instantly removed the shared bars.
|
||||
*/
|
||||
@Composable
|
||||
fun MainScaffold(
|
||||
selectedPage: WebPage?,
|
||||
onRecordsClick: () -> Unit = {},
|
||||
onDeepenClick: () -> Unit = {},
|
||||
onAboutClick: () -> Unit = {},
|
||||
content: @Composable (PaddingValues) -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
// Let each bar apply its own insets; matches the player's standalone scaffold.
|
||||
contentWindowInsets = WindowInsets(0, 0, 0, 0),
|
||||
topBar = { MainTopBar() },
|
||||
bottomBar = {
|
||||
MainBottomBar(
|
||||
selectedPage = selectedPage,
|
||||
onRecordsClick = onRecordsClick,
|
||||
onDeepenClick = onDeepenClick,
|
||||
onAboutClick = onAboutClick,
|
||||
)
|
||||
},
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user