1- @file:OptIn(ExperimentalCoroutinesApi ::class )
1+ @file:OptIn(ExperimentalCoroutinesApi ::class , ExperimentalMaterial3WindowSizeClassApi ::class ,
2+ ExperimentalMaterial3Api ::class
3+ )
24
35package dev.johnoreilly.galwaybus
46
@@ -8,7 +10,15 @@ import android.graphics.Color
810import android.os.Bundle
911import androidx.activity.ComponentActivity
1012import androidx.activity.compose.setContent
13+ import androidx.compose.foundation.layout.Row
14+ import androidx.compose.foundation.layout.WindowInsets
15+ import androidx.compose.foundation.layout.WindowInsetsSides
1116import androidx.compose.foundation.layout.fillMaxSize
17+ import androidx.compose.foundation.layout.only
18+ import androidx.compose.foundation.layout.padding
19+ import androidx.compose.foundation.layout.safeDrawing
20+ import androidx.compose.foundation.layout.safeDrawingPadding
21+ import androidx.compose.foundation.layout.windowInsetsPadding
1222import androidx.compose.material.BottomNavigation
1323import androidx.compose.material.BottomNavigationItem
1424import androidx.compose.material3.Text
@@ -19,17 +29,27 @@ import androidx.compose.material.icons.outlined.DirectionsBike
1929import androidx.compose.material.icons.outlined.Favorite
2030import androidx.compose.material.icons.outlined.FavoriteBorder
2131import androidx.compose.material.icons.outlined.LocationOn
32+ import androidx.compose.material3.ExperimentalMaterial3Api
2233import androidx.compose.material3.IconToggleButton
2334import androidx.compose.material3.MaterialTheme
2435import androidx.compose.material3.NavigationBar
2536import androidx.compose.material3.NavigationBarItem
37+ import androidx.compose.material3.NavigationRail
38+ import androidx.compose.material3.NavigationRailItem
39+ import androidx.compose.material3.Scaffold
2640import androidx.compose.material3.Surface
41+ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
42+ import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
43+ import androidx.compose.material3.windowsizeclass.WindowSizeClass
44+ import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
45+ import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
2746import androidx.compose.runtime.*
2847import androidx.compose.ui.Modifier
2948import androidx.compose.ui.graphics.vector.ImageVector
3049import androidx.compose.ui.res.stringResource
3150import androidx.compose.ui.unit.dp
3251import androidx.core.view.WindowCompat
52+ import androidx.navigation.NavDestination.Companion.hierarchy
3353import androidx.navigation.NavHostController
3454import androidx.navigation.compose.*
3555import com.surrus.galwaybus.common.model.Location
@@ -68,7 +88,7 @@ class MainActivity : ComponentActivity() {
6888 if (showLandingScreen) {
6989 LandingScreen (galwayBusViewModel, onTimeout = { showLandingScreen = false })
7090 } else {
71- MainLayout (fineLocation, fusedLocationWrapper, galwayBusViewModel)
91+ MainLayout (calculateWindowSizeClass( this ), fineLocation, fusedLocationWrapper, galwayBusViewModel)
7292 }
7393
7494 }
@@ -88,14 +108,18 @@ sealed class Screens(val route: String, val label: String, val selectedIcon: Ima
88108
89109@SuppressLint(" MissingPermission" , " UnusedMaterialScaffoldPaddingParameter" )
90110@Composable
91- fun MainLayout (fineLocation : PermissionState ,
111+ fun MainLayout (windowSizeClass : WindowSizeClass ,
112+ fineLocation : PermissionState ,
92113 fusedLocationWrapper : FusedLocationWrapper ,
93114 viewModel : GalwayBusViewModel
94115) {
95116 val navController = rememberNavController()
96117 val bottomNavigationItems = listOf (Screens .NearbyScreen , Screens .BikeShareScreen , Screens .FavoritesScreen )
97118 val hasLocationPermission by fineLocation.hasPermission.collectAsState()
98- val bottomBar: @Composable () -> Unit = { GalwayBusBottomNavigation (navController, bottomNavigationItems) }
119+
120+ val shouldShowBottomBar = windowSizeClass.widthSizeClass == WindowWidthSizeClass .Compact ||
121+ windowSizeClass.heightSizeClass == WindowHeightSizeClass .Compact
122+
99123
100124 if (hasLocationPermission) {
101125 LaunchedEffect (fusedLocationWrapper) {
@@ -106,25 +130,48 @@ fun MainLayout(fineLocation: PermissionState,
106130 viewModel.setLocation(Location (location.latitude, location.longitude))
107131 }
108132
109- NavHost (navController, startDestination = Screens .NearbyScreen .route) {
110- composable(Screens .NearbyScreen .route) {
111- NearestBusStopsScreen (bottomBar, viewModel, navController)
112- }
113- composable(Screens .FavoritesScreen .route) {
114- FavoritesScreen (bottomBar, viewModel, navController)
115- }
116- composable(Screens .BusInfoScreen .route) {
117- BusInfoScreen (viewModel, popBack = { navController.popBackStack() }) { busId ->
118- navController.navigate(Screens .BusRouteScreen .route + " /$busId " )
133+
134+ Scaffold (
135+ containerColor = androidx.compose.ui.graphics.Color .Transparent ,
136+ contentColor = MaterialTheme .colorScheme.onBackground,
137+ contentWindowInsets = WindowInsets (0 , 0 , 0 , 0 ),
138+ bottomBar = {
139+ if (shouldShowBottomBar) {
140+ GalwayBusBottomNavigation (navController, bottomNavigationItems)
119141 }
120142 }
121- composable(Screens .BusRouteScreen .route+ " /{busId}" ) { backStackEntry ->
122- BusRouteScreen (viewModel,
123- backStackEntry.arguments?.get(" busId" ) as String ,
124- popBack = { navController.popBackStack() })
125- }
126- composable(Screens .BikeShareScreen .route) {
127- BikeShareScreen (bottomBar, viewModel)
143+ ) { padding ->
144+
145+ Row (Modifier .fillMaxSize().padding(padding)) {
146+
147+ if (! shouldShowBottomBar) {
148+ GalwayBusNavigationRail (navController, bottomNavigationItems)
149+ }
150+
151+
152+ NavHost (navController, startDestination = Screens .NearbyScreen .route) {
153+ composable(Screens .NearbyScreen .route) {
154+ NearestBusStopsScreen (viewModel, navController)
155+ }
156+ composable(Screens .FavoritesScreen .route) {
157+ FavoritesScreen (viewModel, navController)
158+ }
159+ composable(Screens .BusInfoScreen .route) {
160+ BusInfoScreen (
161+ viewModel,
162+ popBack = { navController.popBackStack() }) { busId ->
163+ navController.navigate(Screens .BusRouteScreen .route + " /$busId " )
164+ }
165+ }
166+ composable(Screens .BusRouteScreen .route + " /{busId}" ) { backStackEntry ->
167+ BusRouteScreen (viewModel,
168+ backStackEntry.arguments?.get(" busId" ) as String ,
169+ popBack = { navController.popBackStack() })
170+ }
171+ composable(Screens .BikeShareScreen .route) {
172+ BikeShareScreen (viewModel)
173+ }
174+ }
128175 }
129176 }
130177 } else {
@@ -136,8 +183,7 @@ fun MainLayout(fineLocation: PermissionState,
136183@Composable
137184private fun GalwayBusBottomNavigation (navController : NavHostController , items : List <Screens >) {
138185
139- NavigationBar (
140- ) {
186+ NavigationBar {
141187 val navBackStackEntry by navController.currentBackStackEntryAsState()
142188 val currentRoute = navBackStackEntry?.destination?.route
143189
@@ -149,9 +195,7 @@ private fun GalwayBusBottomNavigation(navController: NavHostController, items: L
149195 } else {
150196 screen.unSelectedIcon
151197 }
152- icon?.let {
153- Icon (icon, contentDescription = screen.label)
154- }
198+ icon?.let { Icon (icon, contentDescription = screen.label) }
155199 },
156200 label = { Text (screen.label) },
157201 selected = currentRoute == screen.route,
@@ -168,6 +212,42 @@ private fun GalwayBusBottomNavigation(navController: NavHostController, items: L
168212 }
169213}
170214
215+
216+ @Composable
217+ private fun GalwayBusNavigationRail (navController : NavHostController , items : List <Screens >) {
218+
219+ NavigationRail (
220+ // modifier = modifier,
221+ containerColor = androidx.compose.ui.graphics.Color .Transparent ,
222+ // contentColor = PeopleInSpaceNavigationDefaults.navigationContentColor(),
223+ ) {
224+ val navBackStackEntry by navController.currentBackStackEntryAsState()
225+ val currentRoute = navBackStackEntry?.destination?.route
226+
227+ items.forEach { screen ->
228+ val selected = currentRoute == screen.route
229+
230+ NavigationRailItem (
231+ selected = selected,
232+ onClick = {
233+ if (currentRoute != screen.route) {
234+ navController.navigate(screen.route)
235+ }
236+ },
237+ icon = {
238+ val icon = if (selected) {
239+ screen.selectedIcon
240+ } else {
241+ screen.unSelectedIcon
242+ }
243+ icon?.let { Icon (icon, contentDescription = screen.label) }
244+ }
245+ )
246+ }
247+ }
248+ }
249+
250+
171251@Composable
172252fun FavoritesButton (
173253 isFavorite : Boolean ,
0 commit comments