From 2a478c4ec0f21d5793042a2ab2966951c50e545c Mon Sep 17 00:00:00 2001 From: "Ian G. Clifton" <1033551+IanGClifton@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:54:41 -0800 Subject: [PATCH] Added Compose adaptive layouts snippets (#165) * Added Compose adaptive layouts snippets * Apply Spotless * Fixed region tags --------- Co-authored-by: Ian G. Clifton --- compose/snippets/build.gradle.kts | 2 + .../SampleListDetailPaneScaffold.kt | 202 ++++++++++++++++++ gradle/libs.versions.toml | 3 + 3 files changed, 207 insertions(+) create mode 100644 compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleListDetailPaneScaffold.kt diff --git a/compose/snippets/build.gradle.kts b/compose/snippets/build.gradle.kts index 4a65136d..8c444ac1 100644 --- a/compose/snippets/build.gradle.kts +++ b/compose/snippets/build.gradle.kts @@ -91,6 +91,8 @@ dependencies { implementation(libs.androidx.compose.animation.graphics) implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.material3.adaptive) + implementation(libs.androidx.compose.material3.adaptive.navigation.suite) implementation(libs.androidx.compose.material) implementation(libs.androidx.compose.runtime) 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 new file mode 100644 index 00000000..82ebd757 --- /dev/null +++ b/compose/snippets/src/main/java/com/example/compose/snippets/adaptivelayouts/SampleListDetailPaneScaffold.kt @@ -0,0 +1,202 @@ +/* + * Copyright 2023 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.compose.snippets.adaptivelayouts + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Card +import androidx.compose.material3.ListItem +import androidx.compose.material3.Text +import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi +import androidx.compose.material3.adaptive.ListDetailPaneScaffold +import androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole +import androidx.compose.material3.adaptive.rememberListDetailPaneScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +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 + +@OptIn(ExperimentalMaterial3AdaptiveApi::class) +@Composable +fun SampleListDetailPaneScaffoldParts() { + // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part02] + val state = rememberListDetailPaneScaffoldState() + // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part02] + + // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part01] + var selectedItem: MyItem? by rememberSaveable { mutableStateOf(null) } + // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part01] + + // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part03] + ListDetailPaneScaffold( + scaffoldState = state, + /* ... */ + // [START_EXCLUDE] + listPane = {}, + detailPane = {}, + // [END_EXCLUDE] + ) + // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part03] + + // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part04] + ListDetailPaneScaffold( + scaffoldState = state, + listPane = { + MyList( + onItemClick = { id -> + // Set current item + selectedItem = id + // Switch focus to details pane + state.navigateTo(ListDetailPaneScaffoldRole.Detail) + } + ) + }, + /* ... */ + // [START_EXCLUDE] + detailPane = {}, + // [END_EXCLUDE] + ) + // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part04] + + // [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part05] + ListDetailPaneScaffold( + scaffoldState = state, + listPane = /* ... */ + // [START_EXCLUDE] + {}, + // [END_EXCLUDE] + detailPane = { + selectedItem?.let { item -> + MyDetails(item) + } + }, + ) + // [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_part05] +} + +@OptIn(ExperimentalMaterial3AdaptiveApi::class) +@Preview +@Composable +fun SampleListDetailPaneScaffoldFull() { +// [START android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_full] + // Create the ListDetailPaneScaffoldState + val state = rememberListDetailPaneScaffoldState() + + // Currently selected item + var selectedItem: MyItem? by rememberSaveable { mutableStateOf(null) } + + ListDetailPaneScaffold( + scaffoldState = state, + listPane = { + MyList( + onItemClick = { id -> + // Set current item + selectedItem = id + // Display the details pane + state.navigateTo(ListDetailPaneScaffoldRole.Detail) + }, + ) + }, + detailPane = { + // Show the details pane content if selected item is available + selectedItem?.let { item -> + MyDetails(item) + } + }, + ) +// [END android_compose_adaptivelayouts_sample_list_detail_pane_scaffold_full] +} + +@Composable +fun MyList( + onItemClick: (MyItem) -> Unit, +) { + Card { + LazyColumn { + shortStrings.forEachIndexed { id, string -> + item { + ListItem( + modifier = Modifier + .background(Color.Magenta) + .clickable { + onItemClick(MyItem(id)) + }, + headlineContent = { + Text( + text = string, + ) + }, + ) + } + } + } + } +} + +@Composable +fun MyDetails(item: MyItem) { + val text = shortStrings[item.id] + Card { + Column( + Modifier + .fillMaxSize() + .padding(16.dp) + ) { + Text( + text = "Details page for $text", + fontSize = 24.sp, + ) + Spacer(Modifier.size(16.dp)) + Text( + text = "TODO: Add great details here" + ) + } + } +} + +class MyItem(val id: Int) + +val shortStrings = listOf( + "Android", + "Petit four", + "Cupcake", + "Donut", + "Eclair", + "Froyo", + "Gingerbread", + "Honeycomb", + "Ice cream sandwich", + "Jelly bean", + "Kitkat", + "Lollipop", + "Marshmallow", + "Nougat", + "Oreo", + "Pie", +) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fe702b8a..117f2dcb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,6 +32,7 @@ kotlin = "1.8.21" ksp = "1.8.0-1.0.9" maps-compose = "3.1.1" material = "1.11.0-beta01" +material3-adaptive = "1.0.0-alpha01" # @keep minSdk = "21" recyclerview = "1.3.2" @@ -54,6 +55,8 @@ androidx-compose-foundation-layout = { module = "androidx.compose.foundation:fou androidx-compose-material = { module = "androidx.compose.material:material" } androidx-compose-material-iconsExtended = { module = "androidx.compose.material:material-icons-extended" } androidx-compose-material3 = { module = "androidx.compose.material3:material3" } +androidx-compose-material3-adaptive = { module = "androidx.compose.material3:material3-adaptive", version.ref = "material3-adaptive" } +androidx-compose-material3-adaptive-navigation-suite = { module = "androidx.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3-adaptive" } androidx-compose-materialWindow = { module = "androidx.compose.material3:material3-window-size-class" } androidx-compose-runtime = { module = "androidx.compose.runtime:runtime" } androidx-compose-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata" }