From fbc6272b1a4aa3cdbfce0fd3fb0d3e7609d7568e Mon Sep 17 00:00:00 2001 From: hanrui Date: Mon, 24 Aug 2026 15:47:34 +0800 Subject: [PATCH] Fix navigation bar width on narrow displays --- AdaptiveJetStream/gradle/libs.versions.toml | 6 ++-- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../app/AppLayoutSceneDecoratorStrategy.kt | 5 ++- .../app/JetStreamAppNavigation.kt | 36 ++++++++++++++++--- .../jetstream/presentation/theme/Size.kt | 20 ++--------- .../jetstream/presentation/theme/Space.kt | 14 ++++---- .../jetstream/presentation/theme/Theme.kt | 1 - 7 files changed, 49 insertions(+), 35 deletions(-) diff --git a/AdaptiveJetStream/gradle/libs.versions.toml b/AdaptiveJetStream/gradle/libs.versions.toml index a4c3ff3f..bcec3223 100644 --- a/AdaptiveJetStream/gradle/libs.versions.toml +++ b/AdaptiveJetStream/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] activity-compose = "1.13.0" -android-gradle-plugin = "9.2.1" -android-test-plugin = "9.2.1" +android-gradle-plugin = "9.3.1" +android-test-plugin = "9.3.1" androidx-baselineprofile = "1.5.0-alpha06" benchmark-macro-junit4 = "1.4.1" coil-compose = "2.7.0" @@ -17,7 +17,7 @@ junit4 = "4.13.2" kotlin-android = "2.3.21" kotlinx-coroutines = "1.10.2" kotlinx-serialization = "1.11.0" -ksp = "2.3.2" +ksp = "2.3.6" lifecycle-runtime-ktx = "2.10.0" material3-adaptive = "1.2.0" material3-adaptive-navigation = "1.4.0" diff --git a/AdaptiveJetStream/gradle/wrapper/gradle-wrapper.properties b/AdaptiveJetStream/gradle/wrapper/gradle-wrapper.properties index 5b59ea8e..f0d24e58 100644 --- a/AdaptiveJetStream/gradle/wrapper/gradle-wrapper.properties +++ b/AdaptiveJetStream/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/app/AppLayoutSceneDecoratorStrategy.kt b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/app/AppLayoutSceneDecoratorStrategy.kt index e00b233a..daad88ec 100644 --- a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/app/AppLayoutSceneDecoratorStrategy.kt +++ b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/app/AppLayoutSceneDecoratorStrategy.kt @@ -262,7 +262,10 @@ private sealed interface AppLayout { */ object NavigationBar : AppLayout { override val gridConfig: GridConfigurationScope.() -> Unit = { - column(GridTrackSize.MinMax(350.dp, 1.fr)) + // MinMax(0.dp, 1.fr), not a plain Flex(1.fr): a Flex track queries its content's + // min-content intrinsic width, which crashes when the content row holds a lazy list + // (SubcomposeLayout-backed), as it does here for the Home screen's carousels. + column(GridTrackSize.MinMax(0.dp, 1.fr)) row(GridTrackSize.Auto) row(GridTrackSize.MinMax(200.dp, 1.fr)) row(GridTrackSize.Auto) diff --git a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/app/JetStreamAppNavigation.kt b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/app/JetStreamAppNavigation.kt index c06b7ad4..7eb56e55 100644 --- a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/app/JetStreamAppNavigation.kt +++ b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/app/JetStreamAppNavigation.kt @@ -36,6 +36,8 @@ import androidx.compose.foundation.style.styleable import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationRailItem import androidx.compose.material3.PrimaryTabRow import androidx.compose.material3.Tab @@ -51,6 +53,7 @@ import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.xr.compose.material3.ExperimentalMaterial3XrApi import androidx.xr.compose.material3.NavigationRail @@ -142,15 +145,38 @@ object DefaultNavigation : JetStreamAppNavigation { onNavigation: (Destination) -> Unit, isVisible: Boolean, ) { - val direction = - when (LocalEngagementMode.current) { - is EngagementMode.Compact -> FlexDirection.Row - else -> FlexDirection.Column + // Compact devices use a dedicated bottom NavigationBar: unlike a FlexBox row of + // NavigationRailItems, it distributes items evenly so the bar always fits the + // available width instead of overflowing it on narrow screens. + if (LocalEngagementMode.current is EngagementMode.Compact) { + NavigationBar { + NavigationItem.RootDestinations.forEach { item -> + NavigationBarItem( + selected = item.destination == current, + onClick = { onNavigation(item.destination) }, + icon = { + Icon( + painter = item.icon, + contentDescription = item.name, + modifier = Modifier.size(24.dp), + ) + }, + label = { + Text( + text = item.name, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + }, + ) + } } + return + } FlexBox( config = { - direction(direction) + direction(FlexDirection.Column) justifyContent(FlexJustifyContent.Center) gap(4.dp) }, diff --git a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Size.kt b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Size.kt index 52888160..e4eaa3de 100644 --- a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Size.kt +++ b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Size.kt @@ -20,12 +20,14 @@ import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.ProvidableCompositionLocal +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.window.core.layout.WindowSizeClass import com.google.jetstream.presentation.components.feature.EngagementMode +import com.google.jetstream.presentation.components.feature.JetStreamUiMedia import com.google.jetstream.presentation.components.feature.LocalEngagementMode val LocalFeaturedCarouselHeight: ProvidableCompositionLocal = @@ -33,11 +35,6 @@ val LocalFeaturedCarouselHeight: ProvidableCompositionLocal = 324.dp } -val LocalVerticalCardAspectRatio: ProvidableCompositionLocal = - staticCompositionLocalOf { - 10.5f / 16f - } - val LocalCardWidth: ProvidableCompositionLocal = staticCompositionLocalOf { 126.dp @@ -54,19 +51,6 @@ fun rememberFeaturedCarouselHeight(): Dp { } } -@Composable -fun rememberVerticalCardAspectRatio(): Float { - val engagementMode = LocalEngagementMode.current - return remember(engagementMode) { - when (engagementMode) { - is EngagementMode.Leanback, is EngagementMode.Cabin, is EngagementMode.Workstation -> 0.65625f - - // 10.5f / 16f - else -> 0.67021f - } - } -} - @Composable fun rememberCardWidth( windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass, diff --git a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Space.kt b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Space.kt index ed34c73a..15af34d8 100644 --- a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Space.kt +++ b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Space.kt @@ -26,6 +26,7 @@ import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.window.core.layout.WindowSizeClass +import com.google.jetstream.presentation.components.feature.EngagementMode import com.google.jetstream.presentation.components.feature.LocalEngagementMode import com.google.jetstream.presentation.components.feature.isWidthAtLeastExpanded import com.google.jetstream.presentation.components.feature.isWidthAtLeastLarge @@ -38,12 +39,13 @@ val LocalListItemGap: ProvidableCompositionLocal = @Composable fun rememberListItemGap(): Dp { - val isFocusOptimized = LocalEngagementMode.current.isFocusOptimized() - return remember(isFocusOptimized) { - if (isFocusOptimized) { - 20.dp - } else { - 8.dp + val engagementMode = LocalEngagementMode.current + val isFocusOptimized = engagementMode.isFocusOptimized() + return remember(engagementMode, isFocusOptimized) { + when { + isFocusOptimized -> 20.dp + engagementMode is EngagementMode.Compact -> 4.dp + else -> 8.dp } } } diff --git a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Theme.kt b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Theme.kt index 8ef8f8b1..ee750d9a 100644 --- a/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Theme.kt +++ b/AdaptiveJetStream/jetstream/src/main/java/com/google/jetstream/presentation/theme/Theme.kt @@ -34,7 +34,6 @@ fun JetStreamTheme( // TODO: Consider refactoring this CompositionLocalProvider( LocalFeaturedCarouselHeight provides rememberFeaturedCarouselHeight(), - LocalVerticalCardAspectRatio provides rememberVerticalCardAspectRatio(), LocalCardWidth provides rememberCardWidth(), LocalListItemGap provides rememberListItemGap(), LocalProminentCardStyle provides rememberProminentCardStyle(),