|
|
@ -15,6 +15,7 @@
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
package com.google.samples.apps.nowinandroid.ui
|
|
|
|
package com.google.samples.apps.nowinandroid.ui
|
|
|
|
|
|
|
|
|
|
|
|
import androidx.compose.foundation.layout.Column
|
|
|
|
import androidx.compose.foundation.layout.Column
|
|
|
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
|
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
|
|
import androidx.compose.foundation.layout.Row
|
|
|
|
import androidx.compose.foundation.layout.Row
|
|
|
@ -46,6 +47,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|
|
|
import androidx.compose.runtime.setValue
|
|
|
|
import androidx.compose.runtime.setValue
|
|
|
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
|
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
|
|
import androidx.compose.ui.Modifier
|
|
|
|
import androidx.compose.ui.Modifier
|
|
|
|
|
|
|
|
import androidx.compose.ui.composed
|
|
|
|
import androidx.compose.ui.draw.drawWithContent
|
|
|
|
import androidx.compose.ui.draw.drawWithContent
|
|
|
|
import androidx.compose.ui.geometry.Offset
|
|
|
|
import androidx.compose.ui.geometry.Offset
|
|
|
|
import androidx.compose.ui.graphics.Color
|
|
|
|
import androidx.compose.ui.graphics.Color
|
|
|
@ -129,6 +131,8 @@ fun NiaApp(
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val unreadDestinations by appState.topLevelDestinationsWithUnreadResources.collectAsStateWithLifecycle()
|
|
|
|
|
|
|
|
|
|
|
|
Scaffold(
|
|
|
|
Scaffold(
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
testTagsAsResourceId = true
|
|
|
@ -139,7 +143,6 @@ fun NiaApp(
|
|
|
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
|
|
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
|
|
|
bottomBar = {
|
|
|
|
bottomBar = {
|
|
|
|
if (appState.shouldShowBottomBar) {
|
|
|
|
if (appState.shouldShowBottomBar) {
|
|
|
|
val unreadDestinations by appState.topLevelDestinationsWithUnreadResources.collectAsStateWithLifecycle()
|
|
|
|
|
|
|
|
NiaBottomBar(
|
|
|
|
NiaBottomBar(
|
|
|
|
destinations = appState.topLevelDestinations,
|
|
|
|
destinations = appState.topLevelDestinations,
|
|
|
|
destinationsWithUnreadResources = unreadDestinations,
|
|
|
|
destinationsWithUnreadResources = unreadDestinations,
|
|
|
@ -164,6 +167,7 @@ fun NiaApp(
|
|
|
|
if (appState.shouldShowNavRail) {
|
|
|
|
if (appState.shouldShowNavRail) {
|
|
|
|
NiaNavRail(
|
|
|
|
NiaNavRail(
|
|
|
|
destinations = appState.topLevelDestinations,
|
|
|
|
destinations = appState.topLevelDestinations,
|
|
|
|
|
|
|
|
destinationsWithUnreadResources = unreadDestinations,
|
|
|
|
onNavigateToDestination = appState::navigateToTopLevelDestination,
|
|
|
|
onNavigateToDestination = appState::navigateToTopLevelDestination,
|
|
|
|
currentDestination = appState.currentDestination,
|
|
|
|
currentDestination = appState.currentDestination,
|
|
|
|
modifier = Modifier
|
|
|
|
modifier = Modifier
|
|
|
@ -208,6 +212,7 @@ fun NiaApp(
|
|
|
|
@Composable
|
|
|
|
@Composable
|
|
|
|
private fun NiaNavRail(
|
|
|
|
private fun NiaNavRail(
|
|
|
|
destinations: List<TopLevelDestination>,
|
|
|
|
destinations: List<TopLevelDestination>,
|
|
|
|
|
|
|
|
destinationsWithUnreadResources: Set<TopLevelDestination>,
|
|
|
|
onNavigateToDestination: (TopLevelDestination) -> Unit,
|
|
|
|
onNavigateToDestination: (TopLevelDestination) -> Unit,
|
|
|
|
currentDestination: NavDestination?,
|
|
|
|
currentDestination: NavDestination?,
|
|
|
|
modifier: Modifier = Modifier,
|
|
|
|
modifier: Modifier = Modifier,
|
|
|
@ -215,6 +220,7 @@ private fun NiaNavRail(
|
|
|
|
NiaNavigationRail(modifier = modifier) {
|
|
|
|
NiaNavigationRail(modifier = modifier) {
|
|
|
|
destinations.forEach { destination ->
|
|
|
|
destinations.forEach { destination ->
|
|
|
|
val selected = currentDestination.isTopLevelDestinationInHierarchy(destination)
|
|
|
|
val selected = currentDestination.isTopLevelDestinationInHierarchy(destination)
|
|
|
|
|
|
|
|
val hasUnread = destinationsWithUnreadResources.contains(destination)
|
|
|
|
NiaNavigationRailItem(
|
|
|
|
NiaNavigationRailItem(
|
|
|
|
selected = selected,
|
|
|
|
selected = selected,
|
|
|
|
onClick = { onNavigateToDestination(destination) },
|
|
|
|
onClick = { onNavigateToDestination(destination) },
|
|
|
@ -237,7 +243,7 @@ private fun NiaNavRail(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
label = { Text(stringResource(destination.iconTextId)) },
|
|
|
|
label = { Text(stringResource(destination.iconTextId)) },
|
|
|
|
|
|
|
|
modifier = if (hasUnread) Modifier.notificationDot() else Modifier,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -279,30 +285,30 @@ private fun NiaBottomBar(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
label = { Text(stringResource(destination.iconTextId)) },
|
|
|
|
label = { Text(stringResource(destination.iconTextId)) },
|
|
|
|
modifier = if (hasUnread) notificationDot() else Modifier,
|
|
|
|
modifier = if (hasUnread) Modifier.notificationDot() else Modifier,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
private fun Modifier.notificationDot(): Modifier =
|
|
|
|
private fun notificationDot(): Modifier {
|
|
|
|
composed {
|
|
|
|
val tertiaryColor = MaterialTheme.colorScheme.tertiary
|
|
|
|
val tertiaryColor = MaterialTheme.colorScheme.tertiary
|
|
|
|
return Modifier.drawWithContent {
|
|
|
|
drawWithContent {
|
|
|
|
drawContent()
|
|
|
|
drawContent()
|
|
|
|
drawCircle(
|
|
|
|
drawCircle(
|
|
|
|
tertiaryColor,
|
|
|
|
tertiaryColor,
|
|
|
|
radius = 5.dp.toPx(),
|
|
|
|
radius = 5.dp.toPx(),
|
|
|
|
// This is based on the dimensions of the NavigationBar's "indicator pill";
|
|
|
|
// This is based on the dimensions of the NavigationBar's "indicator pill";
|
|
|
|
// however, its parameters are private, so we must depend on them implicitly
|
|
|
|
// however, its parameters are private, so we must depend on them implicitly
|
|
|
|
// (NavigationBarTokens.ActiveIndicatorWidth = 64.dp)
|
|
|
|
// (NavigationBarTokens.ActiveIndicatorWidth = 64.dp)
|
|
|
|
center = center + Offset(
|
|
|
|
center = center + Offset(
|
|
|
|
64.dp.toPx() * .45f,
|
|
|
|
64.dp.toPx() * .45f,
|
|
|
|
32.dp.toPx() * -.45f - 6.dp.toPx(),
|
|
|
|
32.dp.toPx() * -.45f - 6.dp.toPx(),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun NavDestination?.isTopLevelDestinationInHierarchy(destination: TopLevelDestination) =
|
|
|
|
private fun NavDestination?.isTopLevelDestinationInHierarchy(destination: TopLevelDestination) =
|
|
|
|
this?.hierarchy?.any {
|
|
|
|
this?.hierarchy?.any {
|
|
|
|