diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleListDetailPaneScaffold.kt b/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleListDetailPaneScaffold.kt index b79f7ee71..f642c5076 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleListDetailPaneScaffold.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleListDetailPaneScaffold.kt @@ -17,7 +17,6 @@ package com.example.compose.snippets.adaptivelayouts import android.os.Parcelable -import androidx.activity.compose.BackHandler import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -33,30 +32,31 @@ import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi import androidx.compose.material3.adaptive.layout.AnimatedPane import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole +import androidx.compose.material3.adaptive.navigation.BackNavigationBehavior +import androidx.compose.material3.adaptive.navigation.NavigableListDetailPaneScaffold +import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldPredictiveBackHandler import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable -fun SampleListDetailPaneScaffoldParts() { +fun SampleNavigableListDetailPaneScaffoldParts() { // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part02] - val navigator = rememberListDetailPaneScaffoldNavigator() - - BackHandler(navigator.canNavigateBack()) { - navigator.navigateBack() - } + val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator() + val scope = rememberCoroutineScope() // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part02] // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part03] - ListDetailPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, + NavigableListDetailPaneScaffold( + navigator = scaffoldNavigator, // [START_EXCLUDE] listPane = {}, detailPane = {}, @@ -65,16 +65,21 @@ fun SampleListDetailPaneScaffoldParts() { // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part03] // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part04] - ListDetailPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, + NavigableListDetailPaneScaffold( + navigator = scaffoldNavigator, listPane = { AnimatedPane { MyList( onItemClick = { item -> // Navigate to the detail pane with the passed item - navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) - } + scope.launch { + scaffoldNavigator + .navigateTo( + ListDetailPaneScaffoldRole.Detail, + item + ) + } + }, ) } }, @@ -85,16 +90,14 @@ fun SampleListDetailPaneScaffoldParts() { // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part04] // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part05] - ListDetailPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, - listPane = + NavigableListDetailPaneScaffold( + navigator = scaffoldNavigator, // [START_EXCLUDE] - {}, + listPane = {}, // [END_EXCLUDE] detailPane = { AnimatedPane { - navigator.currentDestination?.content?.let { + scaffoldNavigator.currentDestination?.contentKey?.let { MyDetails(it) } } @@ -106,23 +109,66 @@ fun SampleListDetailPaneScaffoldParts() { @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Preview @Composable -fun SampleListDetailPaneScaffoldFull() { -// [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_full] - val navigator = rememberListDetailPaneScaffoldNavigator() +fun SampleNavigableListDetailPaneScaffoldFull() { + // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_full] + val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator() + val scope = rememberCoroutineScope() - BackHandler(navigator.canNavigateBack()) { - navigator.navigateBack() - } + NavigableListDetailPaneScaffold( + navigator = scaffoldNavigator, + listPane = { + AnimatedPane { + MyList( + onItemClick = { item -> + // Navigate to the detail pane with the passed item + scope.launch { + scaffoldNavigator.navigateTo( + ListDetailPaneScaffoldRole.Detail, + item + ) + } + }, + ) + } + }, + detailPane = { + AnimatedPane { + // Show the detail pane content if selected item is available + scaffoldNavigator.currentDestination?.contentKey?.let { + MyDetails(it) + } + } + }, + ) + // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_full] +} + +@OptIn(ExperimentalMaterial3AdaptiveApi::class) +@Composable +fun SampleListDetailPaneScaffoldWithPredictiveBackFull() { + // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_with_pb_full] + val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator() + val scope = rememberCoroutineScope() + + ThreePaneScaffoldPredictiveBackHandler( + navigator = scaffoldNavigator, + backBehavior = BackNavigationBehavior.PopUntilContentChange + ) ListDetailPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, + directive = scaffoldNavigator.scaffoldDirective, + scaffoldState = scaffoldNavigator.scaffoldState, listPane = { AnimatedPane { MyList( onItemClick = { item -> // Navigate to the detail pane with the passed item - navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) + scope.launch { + scaffoldNavigator.navigateTo( + ListDetailPaneScaffoldRole.Detail, + item + ) + } }, ) } @@ -130,13 +176,13 @@ fun SampleListDetailPaneScaffoldFull() { detailPane = { AnimatedPane { // Show the detail pane content if selected item is available - navigator.currentDestination?.content?.let { + scaffoldNavigator.currentDestination?.contentKey?.let { MyDetails(it) } } }, ) -// [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_full] + // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_with_pb_full] } @Composable diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleSupportingPaneScaffold.kt b/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleSupportingPaneScaffold.kt index ad2e0d30f..7132c5e7f 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleSupportingPaneScaffold.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleSupportingPaneScaffold.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Android Open Source Project + * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,9 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3AdaptiveApi::class) - package com.example.compose.snippets.adaptivelayouts -import androidx.activity.compose.BackHandler +import androidx.compose.foundation.background import androidx.compose.foundation.layout.safeContentPadding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material3.Button @@ -28,52 +26,61 @@ import androidx.compose.material3.adaptive.layout.AnimatedPane import androidx.compose.material3.adaptive.layout.PaneAdaptedValue import androidx.compose.material3.adaptive.layout.SupportingPaneScaffold import androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldRole +import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole -import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope +import androidx.compose.material3.adaptive.navigation.BackNavigationBehavior +import androidx.compose.material3.adaptive.navigation.NavigableSupportingPaneScaffold +import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldPredictiveBackHandler import androidx.compose.material3.adaptive.navigation.rememberSupportingPaneScaffoldNavigator import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import kotlinx.coroutines.launch +@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable -fun SampleSupportingPaneScaffoldParts() { +fun SampleNavigableSupportingPaneScaffoldParts() { // [START android_compose_adaptivelayouts_sample_supporting_pane_scaffold_nav_and_back] - val navigator = rememberSupportingPaneScaffoldNavigator() + val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() + val scope = rememberCoroutineScope() - BackHandler(navigator.canNavigateBack()) { - navigator.navigateBack() - } // [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_nav_and_back] // [START android_compose_adaptivelayouts_sample_supporting_pane_scaffold_params] - SupportingPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, + NavigableSupportingPaneScaffold( + navigator = scaffoldNavigator, mainPane = { /*...*/ }, supportingPane = { /*...*/ }, ) // [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_params] } +@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable -fun SampleSupportingPaneScaffoldFull() { +@Preview +fun SampleNavigableSupportingPaneScaffoldFull() { // [START android_compose_adaptivelayouts_sample_supporting_pane_scaffold_full] - val navigator = rememberSupportingPaneScaffoldNavigator() + val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() + val scope = rememberCoroutineScope() - BackHandler(navigator.canNavigateBack()) { - navigator.navigateBack() - } - - SupportingPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, + NavigableSupportingPaneScaffold( + navigator = scaffoldNavigator, mainPane = { - AnimatedPane(modifier = Modifier.safeContentPadding()) { - // Main pane content - if (navigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden) { + AnimatedPane( + modifier = Modifier + .safeContentPadding() + .background(Color.Red) + ) { + if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden) { Button( - modifier = Modifier.wrapContentSize(), + modifier = Modifier + .wrapContentSize(), onClick = { - navigator.navigateTo(SupportingPaneScaffoldRole.Supporting) + scope.launch { + scaffoldNavigator.navigateTo(SupportingPaneScaffoldRole.Supporting) + } } ) { Text("Show supporting pane") @@ -85,22 +92,24 @@ fun SampleSupportingPaneScaffoldFull() { }, supportingPane = { AnimatedPane(modifier = Modifier.safeContentPadding()) { - // Supporting pane content Text("Supporting pane") } - }, + } ) // [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_full] } // [START android_compose_adaptivelayouts_sample_supporting_pane_scaffold_extracted_panes] +@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable -fun ThreePaneScaffoldScope.MainPane( +fun ThreePaneScaffoldPaneScope.MainPane( shouldShowSupportingPaneButton: Boolean, onNavigateToSupportingPane: () -> Unit, modifier: Modifier = Modifier, ) { - AnimatedPane(modifier = modifier.safeContentPadding()) { + AnimatedPane( + modifier = modifier.safeContentPadding() + ) { // Main pane content if (shouldShowSupportingPaneButton) { Button(onClick = onNavigateToSupportingPane) { @@ -112,8 +121,9 @@ fun ThreePaneScaffoldScope.MainPane( } } +@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable -fun ThreePaneScaffoldScope.SupportingPane( +fun ThreePaneScaffoldPaneScope.SupportingPane( modifier: Modifier = Modifier, ) { AnimatedPane(modifier = modifier.safeContentPadding()) { @@ -123,25 +133,56 @@ fun ThreePaneScaffoldScope.SupportingPane( } // [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_extracted_panes] +@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable -fun SampleSupportingPaneScaffoldSimplified() { -// [START android_compose_adaptivelayouts_sample_supporting_pane_scaffold_simplified] - val navigator = rememberSupportingPaneScaffoldNavigator() +fun SampleNavigableSupportingPaneScaffoldSimplified() { + // [START android_compose_adaptivelayouts_sample_supporting_pane_scaffold_simplified] + val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() + val scope = rememberCoroutineScope() - BackHandler(navigator.canNavigateBack()) { - navigator.navigateBack() - } + NavigableSupportingPaneScaffold( + navigator = scaffoldNavigator, + mainPane = { + MainPane( + shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, + onNavigateToSupportingPane = { + scope.launch { + scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary) + } + } + ) + }, + supportingPane = { SupportingPane() }, + ) + // [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_simplified] +} + +@OptIn(ExperimentalMaterial3AdaptiveApi::class) +@Composable +fun SampleSupportingPaneScaffoldSimplifiedWithPredictiveBackHandler() { + // [START android_compose_adaptivelayouts_sample_supporting_pane_scaffold_simplified_with_predictive_back_handler] + val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() + val scope = rememberCoroutineScope() + + ThreePaneScaffoldPredictiveBackHandler( + navigator = scaffoldNavigator, + backBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange + ) SupportingPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, + directive = scaffoldNavigator.scaffoldDirective, + scaffoldState = scaffoldNavigator.scaffoldState, mainPane = { MainPane( - shouldShowSupportingPaneButton = navigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, - onNavigateToSupportingPane = { navigator.navigateTo(ThreePaneScaffoldRole.Secondary) } + shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, + onNavigateToSupportingPane = { + scope.launch { + scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary) + } + } ) }, supportingPane = { SupportingPane() }, ) -// [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_simplified] + // [END android_compose_adaptivelayouts_sample_supporting_pane_scaffold_simplified_with_predictive_back_handler] } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fdc4663df..d4f85ba2d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ kotlinxSerializationJson = "1.8.0" ksp = "2.1.10-1.0.29" maps-compose = "6.4.2" material = "1.13.0-alpha10" -material3-adaptive = "1.0.0" +material3-adaptive = "1.1.0-beta01" material3-adaptive-navigation-suite = "1.3.1" media3 = "1.5.1" # @keep