diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 56e265c45..972f95389 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -100,6 +100,7 @@ dependencies { implementation(libs.androidx.navigation.compose) implementation(libs.androidx.profileinstaller) implementation(libs.androidx.tracing.ktx) + implementation(libs.androidx.window.core) implementation(libs.kotlinx.coroutines.guava) implementation(libs.coil.kt) diff --git a/app/dependencies/prodReleaseRuntimeClasspath.txt b/app/dependencies/prodReleaseRuntimeClasspath.txt index 85adaf6fc..33af141ce 100644 --- a/app/dependencies/prodReleaseRuntimeClasspath.txt +++ b/app/dependencies/prodReleaseRuntimeClasspath.txt @@ -123,9 +123,9 @@ androidx.vectordrawable:vectordrawable:1.1.0 androidx.versionedparcelable:versionedparcelable:1.1.1 androidx.viewpager:viewpager:1.0.0 androidx.window.extensions.core:core:1.0.0 -androidx.window:window-core-android:1.3.0-alpha02 -androidx.window:window-core:1.3.0-alpha02 -androidx.window:window:1.3.0-alpha02 +androidx.window:window-core-android:1.3.0-alpha03 +androidx.window:window-core:1.3.0-alpha03 +androidx.window:window:1.3.0-alpha03 androidx.work:work-runtime-ktx:2.9.0 androidx.work:work-runtime:2.9.0 com.caverock:androidsvg-aar:1.4 diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt index aab864f5b..51c98cec6 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt @@ -179,6 +179,7 @@ internal fun NiaApp( Column(Modifier.fillMaxSize()) { // Show the top app bar on top level destinations. val destination = appState.currentTopLevelDestination + val shouldShowTopAppBar = destination != null if (destination != null) { NiaTopAppBar( titleRes = destination.titleTextId, @@ -207,6 +208,13 @@ internal fun NiaApp( duration = Short, ) == ActionPerformed }, + modifier = if (shouldShowTopAppBar) { + Modifier.consumeWindowInsets( + WindowInsets.safeDrawing.only(WindowInsetsSides.Top), + ) + } else { + Modifier + }, ) } diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt index 335f83371..a6c2edcf7 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/interests2pane/InterestsListDetailScreen.kt @@ -17,15 +17,29 @@ package com.google.samples.apps.nowinandroid.ui.interests2pane import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi +import androidx.compose.material3.adaptive.Posture +import androidx.compose.material3.adaptive.WindowAdaptiveInfo +import androidx.compose.material3.adaptive.allVerticalHingeBounds +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.material3.adaptive.layout.HingePolicy 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.layout.PaneScaffoldDirective +import androidx.compose.material3.adaptive.layout.calculateStandardPaneScaffoldDirective import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator +import androidx.compose.material3.adaptive.occludingVerticalHingeBounds +import androidx.compose.material3.adaptive.separatingVerticalHingeBounds import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder @@ -34,6 +48,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument +import androidx.window.core.layout.WindowWidthSizeClass import com.google.samples.apps.nowinandroid.feature.interests.InterestsRoute import com.google.samples.apps.nowinandroid.feature.interests.navigation.INTERESTS_ROUTE import com.google.samples.apps.nowinandroid.feature.interests.navigation.TOPIC_ID_ARG @@ -76,7 +91,12 @@ internal fun InterestsListDetailScreen( selectedTopicId: String?, onTopicClick: (String) -> Unit, ) { - val listDetailNavigator = rememberListDetailPaneScaffoldNavigator() + val scaffoldDirective = calculateNoContentPaddingScaffoldDirective( + currentWindowAdaptiveInfo(), + ) + val listDetailNavigator = rememberListDetailPaneScaffoldNavigator( + scaffoldDirective = scaffoldDirective, + ) BackHandler(listDetailNavigator.canNavigateBack()) { listDetailNavigator.navigateBack() } @@ -116,6 +136,7 @@ internal fun InterestsListDetailScreen( } } }, + windowInsets = WindowInsets(0, 0, 0, 0), ) LaunchedEffect(Unit) { if (selectedTopicId != null) { @@ -132,3 +153,59 @@ private fun ThreePaneScaffoldNavigator.isListPaneVisible(): Boolean = @OptIn(ExperimentalMaterial3AdaptiveApi::class) private fun ThreePaneScaffoldNavigator.isDetailPaneVisible(): Boolean = scaffoldValue[ListDetailPaneScaffoldRole.Detail] == PaneAdaptedValue.Expanded + +/** + * This is a direct clone of [calculateStandardPaneScaffoldDirective] with the only change of + * passing 0 content padding to the panes. + */ +@OptIn(ExperimentalMaterial3AdaptiveApi::class) +private fun calculateNoContentPaddingScaffoldDirective( + windowAdaptiveInfo: WindowAdaptiveInfo, + verticalHingePolicy: HingePolicy = HingePolicy.AvoidSeparating, +): PaneScaffoldDirective { + val maxHorizontalPartitions: Int + val verticalSpacerSize: Dp + when (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass) { + WindowWidthSizeClass.COMPACT -> { + maxHorizontalPartitions = 1 + verticalSpacerSize = 0.dp + } + WindowWidthSizeClass.MEDIUM -> { + maxHorizontalPartitions = 1 + verticalSpacerSize = 0.dp + } + else -> { + maxHorizontalPartitions = 2 + verticalSpacerSize = 24.dp + } + } + val maxVerticalPartitions: Int + val horizontalSpacerSize: Dp + + if (windowAdaptiveInfo.windowPosture.isTabletop) { + maxVerticalPartitions = 2 + horizontalSpacerSize = 24.dp + } else { + maxVerticalPartitions = 1 + horizontalSpacerSize = 0.dp + } + + return PaneScaffoldDirective( + PaddingValues(0.dp), + maxHorizontalPartitions, + verticalSpacerSize, + maxVerticalPartitions, + horizontalSpacerSize, + getExcludedVerticalBounds(windowAdaptiveInfo.windowPosture, verticalHingePolicy), + ) +} + +@OptIn(ExperimentalMaterial3AdaptiveApi::class) +private fun getExcludedVerticalBounds(posture: Posture, hingePolicy: HingePolicy): List { + return when (hingePolicy) { + HingePolicy.AvoidSeparating -> posture.separatingVerticalHingeBounds + HingePolicy.AvoidOccluding -> posture.occludingVerticalHingeBounds + HingePolicy.AlwaysAvoid -> posture.allVerticalHingeBounds + else -> emptyList() + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 26da6907d..d3ea109ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,7 +27,7 @@ androidxTestRules = "1.5.0" androidxTestRunner = "1.5.2" androidxTracing = "1.3.0-alpha02" androidxUiAutomator = "2.2.0" -androidxWindowManager = "1.2.0" +androidxWindowManager = "1.3.0-alpha03" androidxWork = "2.9.0" coil = "2.6.0" dependencyGuard = "0.4.3" @@ -101,6 +101,7 @@ androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = " androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidxTestRunner" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidxUiAutomator" } androidx-tracing-ktx = { group = "androidx.tracing", name = "tracing-ktx", version.ref = "androidxTracing" } +androidx-window-core = { group = "androidx.window", name = "window-core", version.ref = "androidxWindowManager" } androidx-work-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidxWork" } androidx-work-testing = { group = "androidx.work", name = "work-testing", version.ref = "androidxWork" } coil-kt = { group = "io.coil-kt", name = "coil", version.ref = "coil" }