@@ -3,21 +3,17 @@ package org.jetbrains.kotlinconf.navigation
33import androidx.compose.animation.AnimatedVisibility
44import androidx.compose.animation.core.AnimationConstants
55import androidx.compose.animation.core.tween
6- import androidx.compose.animation.expandHorizontally
76import androidx.compose.animation.expandVertically
87import androidx.compose.animation.fadeOut
9- import androidx.compose.animation.shrinkHorizontally
108import androidx.compose.animation.shrinkVertically
11- import androidx.compose.foundation.background
129import androidx.compose.foundation.layout.Box
1310import androidx.compose.foundation.layout.Column
1411import androidx.compose.foundation.layout.Row
1512import androidx.compose.foundation.layout.WindowInsets
16- import androidx.compose.foundation.layout.fillMaxSize
1713import androidx.compose.foundation.layout.ime
1814import androidx.compose.foundation.layout.padding
1915import androidx.compose.runtime.Composable
20- import androidx.compose.runtime.remember
16+ import androidx.compose.runtime.getValue
2117import androidx.compose.runtime.rememberUpdatedState
2218import androidx.compose.ui.Modifier
2319import androidx.compose.ui.platform.LocalDensity
@@ -48,12 +44,11 @@ import org.jetbrains.kotlinconf.ui.components.MainNavigationBar
4844import org.jetbrains.kotlinconf.ui.components.MainNavigationRail
4945import org.jetbrains.kotlinconf.ui.components.VerticalDivider
5046import org.jetbrains.kotlinconf.ui.theme.KotlinConfTheme
51- import org.jetbrains.kotlinconf.utils.LocalWindowSize
5247import org.jetbrains.kotlinconf.utils.WindowSize
5348import org.jetbrains.kotlinconf.utils.bottomInsetPadding
5449import 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