Skip to content

Commit

Permalink
Use NavigationSuiteScaffold and ListDetailPaneScaffold
Browse files Browse the repository at this point in the history
  • Loading branch information
joreilly committed Jun 18, 2024
1 parent 7b35f69 commit e9c28b7
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 263 deletions.
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ dependencies {
implementation(libs.androidx.compose.ui.tooling)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material3.windowSizeClass)
implementation(libs.androidx.compose.material3.adaptive)
implementation(libs.androidx.compose.material3.adaptive.layout)
implementation(libs.androidx.compose.material3.adaptive.navigation)
implementation(libs.androidx.compose.material3.adaptive.navigation.suite)


implementation(libs.coilCompose)
implementation(libs.glance.appwidget)
Expand Down
6 changes: 2 additions & 4 deletions app/src/main/java/com/surrus/peopleinspace/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ package com.surrus.peopleinspace
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.activity.enableEdgeToEdge
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import com.surrus.peopleinspace.ui.PeopleInSpaceApp


class MainActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
Expand All @@ -21,7 +19,7 @@ class MainActivity : ComponentActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false)

setContent {
PeopleInSpaceApp(calculateWindowSizeClass(this))
PeopleInSpaceApp()
}
}
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ import com.surrus.peopleinspace.ui.component.PeopleInSpaceGradientBackground


@Composable
fun PersonDetailsScreen(person: Assignment, popBack: () -> Unit) {
fun PersonDetailsScreen(person: Assignment, showBackButton: Boolean, popBack: () -> Unit) {
PeopleInSpaceGradientBackground {
Scaffold(
topBar = {
PersonDetailsTopAppBar(personName = person.name, popBack = popBack)
PersonDetailsTopAppBar(personName = person.name, showBackButton, popBack = popBack)
},
containerColor = Color.Transparent,
contentWindowInsets = WindowInsets(0, 0, 0, 0)
Expand All @@ -47,12 +47,14 @@ fun PersonDetailsScreen(person: Assignment, popBack: () -> Unit) {
}

@Composable
fun PersonDetailsTopAppBar(personName: String, popBack: () -> Unit) {
fun PersonDetailsTopAppBar(personName: String, showBackButton: Boolean, popBack: () -> Unit) {
CenterAlignedTopAppBar(
title = { Text(personName) },
navigationIcon = {
IconButton(onClick = { popBack() }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
if (showBackButton) {
IconButton(onClick = { popBack() }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
}
}
},
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
Expand Down
209 changes: 79 additions & 130 deletions app/src/main/java/com/surrus/peopleinspace/ui/PeopleInSpaceApp.kt
Original file line number Diff line number Diff line change
@@ -1,153 +1,102 @@
package com.surrus.peopleinspace.ui


import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.activity.compose.BackHandler
import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.LocationOn
import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationRail
import androidx.compose.material3.NavigationRailItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.surrus.peopleinspace.navigation.PeopleInSpaceNavHost
import com.surrus.peopleinspace.navigation.TopLevelDestination
import com.surrus.peopleinspace.ui.component.PeopleInSpaceBackground
import com.surrus.common.remote.Assignment
import com.surrus.peopleinspace.R
import com.surrus.peopleinspace.issposition.ISSPositionRoute
import com.surrus.peopleinspace.persondetails.PersonDetailsScreen
import com.surrus.peopleinspace.personlist.PersonListRoute

@Composable
fun PeopleInSpaceApp(
windowSizeClass: WindowSizeClass,
appState: PeopleInSpaceAppState = rememberPeopleInSpaceAppState(windowSizeClass)
enum class AppDestinations(
@StringRes val label: Int,
val icon: ImageVector,
@StringRes val contentDescription: Int
) {
val navController = rememberNavController()
PERSON_LIST(R.string.people, Icons.Default.Person, R.string.people),
ISS_POSITION(R.string.iss_position, Icons.Default.LocationOn, R.string.iss_position),
}

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun PeopleInSpaceApp() {
var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.PERSON_LIST) }
val navigator = rememberListDetailPaneScaffoldNavigator<Assignment>()

BackHandler(navigator.canNavigateBack()) {
navigator.navigateBack()
}

PeopleInSpaceTheme {
PeopleInSpaceBackground {
Scaffold(
containerColor = Color.Transparent,
contentColor = MaterialTheme.colorScheme.onBackground,
contentWindowInsets = WindowInsets(0, 0, 0, 0),
bottomBar = {
if (appState.shouldShowBottomBar) {
PeopleInSpaceBottomBar(
navController = navController,
destinations = appState.topLevelDestinations
)
}
}
) { padding ->
Row(
Modifier
.fillMaxSize()
.windowInsetsPadding(
WindowInsets.safeDrawing.only(
WindowInsetsSides.Horizontal
NavigationSuiteScaffold(
navigationSuiteItems = {
AppDestinations.entries.forEach {
item(
icon = {
Icon(
it.icon,
contentDescription = stringResource(it.contentDescription)
)
)
) {
if (appState.shouldShowNavRail) {
PeopleInSpaceNavRail(
navController = navController,
destinations = appState.topLevelDestinations,
modifier = Modifier.safeDrawingPadding()
)
}

PeopleInSpaceNavHost(
navController = navController,
onBackClick = { navController.popBackStack() },
modifier = Modifier
.padding(padding)
.windowInsetsPadding(WindowInsets.statusBars)
},
label = { Text(stringResource(it.label)) },
selected = it == currentDestination,
onClick = { currentDestination = it }
)
}
}
}
}
}


@Composable
private fun PeopleInSpaceNavRail(
navController: NavController,
destinations: List<TopLevelDestination>,
modifier: Modifier = Modifier,
) {

NavigationRail(
modifier = modifier,
containerColor = Color.Transparent,
contentColor = PeopleInSpaceNavigationDefaults.navigationContentColor(),
) {
destinations.forEach { destination ->
val currentDestination = navController.currentBackStackEntryAsState().value?.destination
val selected = currentDestination?.route == destination.route::class.qualifiedName
NavigationRailItem(
selected = selected,
onClick = { navController.navigate(destination.route) },
icon = {
val icon = if (selected) {
destination.selectedIcon
} else {
destination.unselectedIcon
}
Icon(icon, contentDescription = stringResource(destination.iconTextId))
) {
when (currentDestination) {
AppDestinations.PERSON_LIST -> {
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
PersonListRoute { person ->
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, person)
}
},
detailPane = {
navigator.currentDestination?.content?.let {
PersonDetailsScreen(
person = it,
showBackButton = !navigator.isListPaneVisible(),
navigator::navigateBack
)
}
}
)
}
AppDestinations.ISS_POSITION -> {
ISSPositionRoute()
}
)
}
}
}
}


@Composable
private fun PeopleInSpaceBottomBar(
navController: NavController,
destinations: List<TopLevelDestination>
) {
NavigationBar(
contentColor = PeopleInSpaceNavigationDefaults.navigationContentColor(),
tonalElevation = 0.dp,
) {
destinations.forEach { destination ->
val currentDestination = navController.currentBackStackEntryAsState().value?.destination
val selected = currentDestination?.route == destination.route::class.qualifiedName
NavigationBarItem(
selected = selected,
onClick = { navController.navigate(destination.route) },
icon = {
val icon = if (selected) {
destination.selectedIcon
} else {
destination.unselectedIcon
}
Icon(icon, contentDescription = stringResource(destination.iconTextId))
},
label = { Text(stringResource(destination.iconTextId)) }
)
}
}
}
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
private fun <T> ThreePaneScaffoldNavigator<T>.isListPaneVisible(): Boolean =
scaffoldValue[ListDetailPaneScaffoldRole.List] == PaneAdaptedValue.Expanded

object PeopleInSpaceNavigationDefaults {
@Composable
fun navigationContentColor() = MaterialTheme.colorScheme.onSurfaceVariant
}

Loading

0 comments on commit e9c28b7

Please sign in to comment.