Skip to content

Commit 23688fe

Browse files
committed
Move window size logic into SceneDecoratorStrategy, simplify scaffolding layouts
1 parent 5b4e395 commit 23688fe

2 files changed

Lines changed: 74 additions & 119 deletions

File tree

app/shared/src/commonMain/kotlin/org/jetbrains/kotlinconf/navigation/NavHost.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import org.jetbrains.kotlinconf.ui.theme.GoldenKodeeColors
5555
import org.jetbrains.kotlinconf.ui.theme.KotlinConfDarkColors
5656
import org.jetbrains.kotlinconf.ui.theme.KotlinConfLightColors
5757
import org.jetbrains.kotlinconf.ui.theme.KotlinConfTheme
58+
import org.jetbrains.kotlinconf.utils.LocalWindowSize
5859
import org.jetbrains.kotlinconf.utils.getStoreUrl
5960

6061
fun navigateByLocalNotificationId(notificationId: String) {
@@ -127,8 +128,14 @@ internal fun NavHost(
127128
val showGoldenKodee by remember { conferenceService.goldenKodeeData.map { it != null } }
128129
.collectAsStateWithLifecycle(false)
129130

130-
val navigationDecorator = remember(navState, navigator, showGoldenKodee) {
131-
NavigationSceneDecoratorStrategy(navState, navigator, showGoldenKodee)
131+
val windowSize = LocalWindowSize.current
132+
val navigationDecorator = remember(navState, navigator, showGoldenKodee, windowSize) {
133+
TopLevelNavStrategy(
134+
navState = navState,
135+
windowSize = windowSize,
136+
showGoldenKodee = showGoldenKodee,
137+
onSelectRoute = { route -> navigator.activate(route) },
138+
)
132139
}
133140

134141
val isGoldenKodee = navState.topLevelRoute is GoldenKodeeScreen

app/shared/src/commonMain/kotlin/org/jetbrains/kotlinconf/navigation/NavScaffold.kt renamed to app/shared/src/commonMain/kotlin/org/jetbrains/kotlinconf/navigation/TopLevelNavStrategy.kt

Lines changed: 65 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,17 @@ package org.jetbrains.kotlinconf.navigation
33
import androidx.compose.animation.AnimatedVisibility
44
import androidx.compose.animation.core.AnimationConstants
55
import androidx.compose.animation.core.tween
6-
import androidx.compose.animation.expandHorizontally
76
import androidx.compose.animation.expandVertically
87
import androidx.compose.animation.fadeOut
9-
import androidx.compose.animation.shrinkHorizontally
108
import androidx.compose.animation.shrinkVertically
11-
import androidx.compose.foundation.background
129
import androidx.compose.foundation.layout.Box
1310
import androidx.compose.foundation.layout.Column
1411
import androidx.compose.foundation.layout.Row
1512
import androidx.compose.foundation.layout.WindowInsets
16-
import androidx.compose.foundation.layout.fillMaxSize
1713
import androidx.compose.foundation.layout.ime
1814
import androidx.compose.foundation.layout.padding
1915
import androidx.compose.runtime.Composable
20-
import androidx.compose.runtime.remember
16+
import androidx.compose.runtime.getValue
2117
import androidx.compose.runtime.rememberUpdatedState
2218
import androidx.compose.ui.Modifier
2319
import androidx.compose.ui.platform.LocalDensity
@@ -48,12 +44,11 @@ import org.jetbrains.kotlinconf.ui.components.MainNavigationBar
4844
import org.jetbrains.kotlinconf.ui.components.MainNavigationRail
4945
import org.jetbrains.kotlinconf.ui.components.VerticalDivider
5046
import org.jetbrains.kotlinconf.ui.theme.KotlinConfTheme
51-
import org.jetbrains.kotlinconf.utils.LocalWindowSize
5247
import org.jetbrains.kotlinconf.utils.WindowSize
5348
import org.jetbrains.kotlinconf.utils.bottomInsetPadding
5449
import org.jetbrains.kotlinconf.utils.topInsetPadding
5550

56-
private val bottomNavDestinations: List<MainNavDestination<TopLevelRoute>> = listOf(
51+
private val topLevelNavDestinations: List<MainNavDestination<TopLevelRoute>> = listOf(
5752
MainNavDestination(
5853
label = Res.string.nav_destination_schedule,
5954
icon = Res.drawable.clock_28,
@@ -86,145 +81,98 @@ private val bottomNavDestinations: List<MainNavDestination<TopLevelRoute>> = lis
8681
),
8782
)
8883

89-
internal class NavigationSceneDecoratorStrategy(
84+
internal class TopLevelNavStrategy(
9085
private val navState: NavState,
91-
private val navigator: Navigator,
86+
private val windowSize: WindowSize,
9287
private val showGoldenKodee: Boolean,
88+
private val onSelectRoute: (TopLevelRoute) -> Unit,
9389
) : SceneDecoratorStrategy<AppRoute> {
9490
override fun SceneDecoratorStrategyScope<AppRoute>.decorateScene(scene: Scene<AppRoute>): Scene<AppRoute> {
95-
return if (navState.topLevelRoute != null) {
96-
NavigationDecoratingScene(scene, navState, navigator, showGoldenKodee)
91+
if (navState.topLevelRoute == null) {
92+
return scene
93+
}
94+
95+
val destinations = if (showGoldenKodee) {
96+
topLevelNavDestinations
9797
} else {
98-
scene
98+
topLevelNavDestinations.filter { it.route !is GoldenKodeeScreen }
99+
}
100+
101+
return when (windowSize) {
102+
WindowSize.Compact -> {
103+
if (navState.currentBackstack.size == 1) {
104+
BottomNavScene(scene, navState, onSelectRoute, destinations)
105+
} else {
106+
scene
107+
}
108+
}
109+
110+
WindowSize.Medium, WindowSize.Large -> {
111+
NavRailScene(scene, navState, onSelectRoute, destinations, windowSize)
112+
}
99113
}
100114
}
101115
}
102116

103-
private class NavigationDecoratingScene(
117+
private class BottomNavScene(
104118
private val scene: Scene<AppRoute>,
105119
private val navState: NavState,
106-
private val navigator: Navigator,
107-
private val showGoldenKodee: Boolean,
120+
private val onSelectRoute: (TopLevelRoute) -> Unit,
121+
private val destinations: List<MainNavDestination<TopLevelRoute>>,
108122
) : Scene<AppRoute> by scene {
109123
override val content: @Composable () -> Unit = {
110-
NavScaffold(navState, navigator, showGoldenKodee, scene)
111-
}
112-
}
113-
114-
@Composable
115-
private fun NavScaffold(
116-
navState: NavState,
117-
navigator: Navigator,
118-
showGoldenKodee: Boolean,
119-
scene: Scene<AppRoute>,
120-
) {
121-
val onSelectRoute: (TopLevelRoute) -> Unit = { route ->
122-
navigator.activate(route)
123-
}
124-
125-
val destinations = remember(showGoldenKodee) {
126-
if (showGoldenKodee) {
127-
bottomNavDestinations
128-
} else {
129-
bottomNavDestinations.filter { it.route !is GoldenKodeeScreen }
130-
}
131-
}
132-
133-
val windowSize = LocalWindowSize.current
134-
135-
val showLargeNavigation = windowSize != WindowSize.Compact &&
136-
navState.topLevelRoute != null
137-
val showCompactNavigation = windowSize == WindowSize.Compact &&
138-
navState.topLevelRoute != null &&
139-
navState.currentBackstack.size == 1 &&
140-
!isKeyboardOpen()
141-
142-
Row(
143-
Modifier.fillMaxSize()
144-
.background(color = KotlinConfTheme.colors.mainBackground)
145-
) {
146-
val enterAnimSpec = tween<IntSize>(delayMillis = AnimationConstants.DefaultDurationMillis)
147-
148-
AnimatedVisibility(
149-
visible = showLargeNavigation,
150-
enter = expandHorizontally(enterAnimSpec),
151-
exit = shrinkHorizontally() + fadeOut(),
152-
) {
153-
SideNavigation(
154-
currentRoute = navState.topLevelRoute,
155-
destinations = destinations,
156-
onSelectRoute = onSelectRoute,
157-
expanded = windowSize == WindowSize.Large,
158-
)
159-
}
160-
161-
Column(Modifier.weight(1f)) {
124+
Column(Modifier.padding(bottomInsetPadding())) {
162125
Box(Modifier.weight(1f)) {
163126
scene.content()
164127
}
165128

129+
val enterAnimSpec =
130+
tween<IntSize>(delayMillis = AnimationConstants.DefaultDurationMillis)
131+
132+
val bottomInset = WindowInsets.ime.getBottom(LocalDensity.current)
133+
val isKeyboardOpen by rememberUpdatedState(bottomInset > 300)
134+
166135
AnimatedVisibility(
167-
visible = showCompactNavigation,
136+
visible = !isKeyboardOpen,
168137
enter = expandVertically(enterAnimSpec),
169138
exit = shrinkVertically() + fadeOut(),
170139
) {
171-
BottomNavigation(
172-
currentRoute = navState.topLevelRoute,
140+
HorizontalDivider(thickness = 1.dp, color = KotlinConfTheme.colors.strokePale)
141+
142+
MainNavigationBar(
143+
currentDestination = destinations.find { it.route == navState.topLevelRoute },
173144
destinations = destinations,
174-
onSelectRoute = onSelectRoute,
145+
onSelect = { selectedDestination ->
146+
onSelectRoute(selectedDestination.route)
147+
},
175148
)
176149
}
177150
}
178151
}
179152
}
180153

181-
@Composable
182-
private fun isKeyboardOpen(): Boolean {
183-
val bottomInset = WindowInsets.ime.getBottom(LocalDensity.current)
184-
return rememberUpdatedState(bottomInset > 300).value
185-
}
186-
187-
@Composable
188-
private fun BottomNavigation(
189-
currentRoute: TopLevelRoute?,
190-
destinations: List<MainNavDestination<TopLevelRoute>>,
191-
onSelectRoute: (TopLevelRoute) -> Unit,
192-
) {
193-
val currentDestination = destinations.find { it.route == currentRoute }
194-
195-
Column(
196-
Modifier.padding(bottomInsetPadding()),
197-
) {
198-
HorizontalDivider(thickness = 1.dp, color = KotlinConfTheme.colors.strokePale)
199-
MainNavigationBar(
200-
currentDestination = currentDestination,
201-
destinations = destinations,
202-
onSelect = { selectedDestination ->
203-
onSelectRoute(selectedDestination.route)
204-
},
205-
)
206-
}
207-
}
154+
private class NavRailScene(
155+
private val scene: Scene<AppRoute>,
156+
private val navState: NavState,
157+
private val onSelectRoute: (TopLevelRoute) -> Unit,
158+
private val destinations: List<MainNavDestination<TopLevelRoute>>,
159+
private val windowSize: WindowSize,
160+
) : Scene<AppRoute> by scene {
161+
override val content: @Composable () -> Unit = {
162+
Row {
163+
MainNavigationRail(
164+
currentDestination = destinations.find { it.route == navState.topLevelRoute },
165+
destinations = destinations,
166+
onSelect = { selectedDestination ->
167+
onSelectRoute(selectedDestination.route)
168+
},
169+
expanded = windowSize == WindowSize.Large,
170+
modifier = Modifier.padding(topInsetPadding()),
171+
)
208172

209-
@Composable
210-
private fun SideNavigation(
211-
currentRoute: TopLevelRoute?,
212-
destinations: List<MainNavDestination<TopLevelRoute>>,
213-
onSelectRoute: (TopLevelRoute) -> Unit,
214-
expanded: Boolean,
215-
) {
216-
val currentDestination = destinations.find { it.route == currentRoute }
173+
VerticalDivider(thickness = 1.dp, color = KotlinConfTheme.colors.strokePale)
217174

218-
Row {
219-
MainNavigationRail(
220-
currentDestination = currentDestination,
221-
destinations = destinations,
222-
onSelect = { selectedDestination ->
223-
onSelectRoute(selectedDestination.route)
224-
},
225-
expanded = expanded,
226-
modifier = Modifier.padding(topInsetPadding()),
227-
)
228-
VerticalDivider(thickness = 1.dp, color = KotlinConfTheme.colors.strokePale)
175+
scene.content()
176+
}
229177
}
230178
}

0 commit comments

Comments
 (0)