@ -44,12 +44,15 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavDestination.Companion.hierarchy
@ -67,6 +70,7 @@ import com.google.samples.apps.nowinandroid.core.designsystem.icon.Icon.ImageVec
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.GradientColors
import com.google.samples.apps.nowinandroid.core.designsystem.theme.GradientColors
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalGradientColors
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalGradientColors
import com.google.samples.apps.nowinandroid.core.domain.repository.UserNewsResourceRepository
import com.google.samples.apps.nowinandroid.feature.settings.SettingsDialog
import com.google.samples.apps.nowinandroid.feature.settings.SettingsDialog
import com.google.samples.apps.nowinandroid.navigation.NiaNavHost
import com.google.samples.apps.nowinandroid.navigation.NiaNavHost
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination
@ -85,6 +89,7 @@ fun NiaApp(
networkMonitor = networkMonitor ,
networkMonitor = networkMonitor ,
windowSizeClass = windowSizeClass ,
windowSizeClass = windowSizeClass ,
) ,
) ,
userNewsResourceRepository : UserNewsResourceRepository ,
) {
) {
val shouldShowGradientBackground =
val shouldShowGradientBackground =
appState . currentTopLevelDestination == TopLevelDestination . FOR _YOU
appState . currentTopLevelDestination == TopLevelDestination . FOR _YOU
@ -128,8 +133,17 @@ fun NiaApp(
snackbarHost = { SnackbarHost ( snackbarHostState ) } ,
snackbarHost = { SnackbarHost ( snackbarHostState ) } ,
bottomBar = {
bottomBar = {
if ( appState . shouldShowBottomBar ) {
if ( appState . shouldShowBottomBar ) {
val forYouNewsResources by userNewsResourceRepository . getUserNewsResourcesForFollowedTopics ( )
. collectAsStateWithLifecycle ( emptyList ( ) )
val unreadDestinations =
when {
forYouNewsResources . all { it . isViewed } -> emptySet ( )
else -> setOf ( TopLevelDestination . FOR _YOU )
}
NiaBottomBar (
NiaBottomBar (
destinations = appState . topLevelDestinations ,
destinations = appState . topLevelDestinations ,
destinationsWithUnreadResources = unreadDestinations ,
onNavigateToDestination = appState :: navigateToTopLevelDestination ,
onNavigateToDestination = appState :: navigateToTopLevelDestination ,
currentDestination = appState . currentDestination ,
currentDestination = appState . currentDestination ,
modifier = Modifier . testTag ( " NiaBottomBar " ) ,
modifier = Modifier . testTag ( " NiaBottomBar " ) ,
@ -211,6 +225,7 @@ private fun NiaNavRail(
imageVector = icon . imageVector ,
imageVector = icon . imageVector ,
contentDescription = null ,
contentDescription = null ,
)
)
is DrawableResourceIcon -> Icon (
is DrawableResourceIcon -> Icon (
painter = painterResource ( id = icon . id ) ,
painter = painterResource ( id = icon . id ) ,
contentDescription = null ,
contentDescription = null ,
@ -218,6 +233,7 @@ private fun NiaNavRail(
}
}
} ,
} ,
label = { Text ( stringResource ( destination . iconTextId ) ) } ,
label = { Text ( stringResource ( destination . iconTextId ) ) } ,
)
)
}
}
}
}
@ -226,6 +242,7 @@ private fun NiaNavRail(
@Composable
@Composable
private fun NiaBottomBar (
private fun NiaBottomBar (
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 ,
@ -234,6 +251,7 @@ private fun NiaBottomBar(
modifier = modifier ,
modifier = modifier ,
) {
) {
destinations . forEach { destination ->
destinations . forEach { destination ->
val hasUnread = destinationsWithUnreadResources . contains ( destination )
val selected = currentDestination . isTopLevelDestinationInHierarchy ( destination )
val selected = currentDestination . isTopLevelDestinationInHierarchy ( destination )
NiaNavigationBarItem (
NiaNavigationBarItem (
selected = selected ,
selected = selected ,
@ -257,6 +275,25 @@ private fun NiaBottomBar(
}
}
} ,
} ,
label = { Text ( stringResource ( destination . iconTextId ) ) } ,
label = { Text ( stringResource ( destination . iconTextId ) ) } ,
modifier = if ( hasUnread ) {
val tertiaryColor = MaterialTheme . colorScheme . tertiary
Modifier . drawWithContent {
drawContent ( )
drawCircle (
tertiaryColor ,
radius = 5. dp . toPx ( ) ,
// This is based on the dimensions of the NavigationBar's "indicator pill";
// however, its parameters are private, so we must depend on them implicitly
// (NavigationBarTokens.ActiveIndicatorWidth = 64.dp)
center = center + Offset (
64. dp . toPx ( ) * . 45f ,
32. dp . toPx ( ) * - . 45f - 6. dp . toPx ( ) ,
) ,
)
}
} else {
Modifier
} ,
)
)
}
}
}
}