Skip to content
This repository was archived by the owner on Jul 11, 2025. It is now read-only.

Commit eb0ed27

Browse files
authored
Merge pull request #475 from tiwiz/material-1.1.0-alpha01
Update project to Material Adaptive Library 3 v 1.1.0-alpha02
2 parents c26f65d + 23b716f commit eb0ed27

File tree

10 files changed

+187
-75
lines changed

10 files changed

+187
-75
lines changed

CanonicalLayouts/list-detail-compose/app/build.gradle

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ plugins {
2020

2121
android {
2222
namespace 'com.example.listdetailcompose'
23-
compileSdk 34
23+
compileSdk 35
2424

2525
defaultConfig {
2626
applicationId "com.example.listdetailcompose"
2727
minSdk 21
28-
targetSdk 34
28+
targetSdk 35
2929
versionCode 1
3030
versionName "1.0"
3131

@@ -62,21 +62,22 @@ android {
6262
}
6363

6464
dependencies {
65-
def composeBom = platform('androidx.compose:compose-bom:2024.03.00')
65+
def composeBom = platform('androidx.compose:compose-bom:2024.09.00')
6666
implementation(composeBom)
6767

6868
implementation "com.google.accompanist:accompanist-adaptive:0.32.0"
69-
implementation 'androidx.core:core-ktx:1.12.0'
70-
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
71-
implementation 'androidx.activity:activity-compose:1.8.2'
72-
implementation "androidx.compose.foundation:foundation:1.6.4"
73-
implementation "androidx.compose.ui:ui:1.6.4"
69+
implementation 'androidx.core:core-ktx:1.13.1'
70+
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.5'
71+
implementation 'androidx.activity:activity-compose:1.9.2'
72+
implementation "androidx.compose.foundation:foundation:1.7.0"
73+
implementation "androidx.compose.ui:ui:1.7.0"
7474
implementation "androidx.compose.ui:ui-tooling-preview"
75-
implementation "androidx.window:window:1.2.0"
76-
implementation 'androidx.compose.material3:material3:1.3.0-alpha03'
77-
implementation 'androidx.compose.material3.adaptive:adaptive:1.0.0-alpha09'
78-
implementation 'androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha09'
79-
implementation 'androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha09'
80-
implementation "androidx.compose.material3:material3-window-size-class:1.3.0-alpha03"
75+
implementation "androidx.window:window:1.3.0"
76+
implementation 'androidx.compose.material3:material3:1.3.0'
77+
implementation 'androidx.compose.material3.adaptive:adaptive:1.1.0-alpha02'
78+
implementation 'androidx.compose.material3.adaptive:adaptive-layout:1.1.0-alpha02'
79+
implementation 'androidx.compose.material3.adaptive:adaptive-navigation:1.1.0-alpha02'
80+
implementation "androidx.compose.material3:material3-window-size-class:1.3.0"
81+
implementation "androidx.compose.animation:animation:1.7.0"
8182
testImplementation 'junit:junit:4.13.2'
8283
}

CanonicalLayouts/list-detail-compose/app/src/main/java/com/example/listdetailcompose/ui/ListDetailSample.kt

Lines changed: 136 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,25 @@
1414
* limitations under the License.
1515
*/
1616

17+
@file:OptIn(ExperimentalSharedTransitionApi::class, ExperimentalSharedTransitionApi::class)
18+
1719
package com.example.listdetailcompose.ui
1820

21+
import android.annotation.SuppressLint
1922
import androidx.activity.compose.BackHandler
23+
import androidx.annotation.DrawableRes
24+
import androidx.compose.animation.AnimatedContent
25+
import androidx.compose.animation.AnimatedVisibilityScope
26+
import androidx.compose.animation.ExperimentalSharedTransitionApi
27+
import androidx.compose.animation.SharedTransitionLayout
28+
import androidx.compose.animation.SharedTransitionScope
2029
import androidx.compose.foundation.BorderStroke
30+
import androidx.compose.foundation.Image
2131
import androidx.compose.foundation.clickable
2232
import androidx.compose.foundation.layout.Arrangement
2333
import androidx.compose.foundation.layout.Column
2434
import androidx.compose.foundation.layout.PaddingValues
35+
import androidx.compose.foundation.layout.Row
2536
import androidx.compose.foundation.layout.fillMaxWidth
2637
import androidx.compose.foundation.layout.padding
2738
import androidx.compose.foundation.lazy.LazyColumn
@@ -35,18 +46,25 @@ import androidx.compose.material3.CardDefaults
3546
import androidx.compose.material3.MaterialTheme
3647
import androidx.compose.material3.Text
3748
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
49+
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
50+
import androidx.compose.material3.adaptive.layout.AnimatedPane
3851
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
3952
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
4053
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
54+
import androidx.compose.material3.adaptive.layout.PaneExpansionDragHandle
55+
import androidx.compose.material3.adaptive.layout.rememberPaneExpansionState
4156
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
4257
import androidx.compose.runtime.Composable
4358
import androidx.compose.runtime.getValue
4459
import androidx.compose.runtime.mutableStateOf
4560
import androidx.compose.runtime.saveable.rememberSaveable
4661
import androidx.compose.runtime.setValue
4762
import androidx.compose.ui.Modifier
63+
import androidx.compose.ui.graphics.Color
64+
import androidx.compose.ui.res.painterResource
4865
import androidx.compose.ui.res.stringResource
4966
import androidx.compose.ui.unit.dp
67+
import androidx.window.core.layout.WindowWidthSizeClass
5068
import com.example.listdetailcompose.R
5169

5270
// Create some simple sample data
@@ -56,59 +74,84 @@ private val loremIpsum = """
5674
|Tempus quam pellentesque nec nam aliquam. Praesent semper feugiat nibh sed. Adipiscing elit duis tristique sollicitudin nibh sit. Netus et malesuada fames ac turpis egestas sed tempus urna. Quis varius quam quisque id diam vel quam. Urna duis convallis convallis tellus id interdum velit laoreet. Id eu nisl nunc mi ipsum. Fermentum dui faucibus in ornare. Nunc lobortis mattis aliquam faucibus. Vulputate mi sit amet mauris commodo quis. Porta nibh venenatis cras sed. Vitae tortor condimentum lacinia quis vel eros donec. Eu non diam phasellus vestibulum.
5775
""".trimMargin()
5876
private val sampleWords = listOf(
59-
"Apple" to loremIpsum,
60-
"Banana" to loremIpsum,
61-
"Cherry" to loremIpsum,
62-
"Date" to loremIpsum,
63-
"Elderberry" to loremIpsum,
64-
"Fig" to loremIpsum,
65-
"Grape" to loremIpsum,
66-
"Honeydew" to loremIpsum,
67-
).map { (word, definition) -> DefinedWord(word, definition) }
77+
"Apple" to R.drawable.ic_food,
78+
"Banana" to R.drawable.ic_no_food,
79+
"Cherry" to R.drawable.ic_food,
80+
"Date" to R.drawable.ic_no_food,
81+
"Elderberry" to R.drawable.ic_food,
82+
"Fig" to R.drawable.ic_no_food,
83+
"Grape" to R.drawable.ic_food,
84+
"Honeydew" to R.drawable.ic_no_food,
85+
).map { (word, icon) -> DefinedWord(word, icon) }
6886

6987
private data class DefinedWord(
7088
val word: String,
71-
val definition: String
89+
@DrawableRes val icon: Int,
90+
val definition: String = loremIpsum
7291
)
7392

93+
@SuppressLint("UnusedContentLambdaTargetStateParameter")
7494
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
7595
@Composable
7696
fun ListDetailSample() {
7797
var selectedWordIndex: Int? by rememberSaveable { mutableStateOf(null) }
7898
val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>()
99+
val isListAndDetailVisible =
100+
navigator.scaffoldValue[ListDetailPaneScaffoldRole.Detail] == PaneAdaptedValue.Expanded && navigator.scaffoldValue[ListDetailPaneScaffoldRole.List] == PaneAdaptedValue.Expanded
79101

80102
BackHandler(enabled = navigator.canNavigateBack()) {
81103
navigator.navigateBack()
82104
}
83105

84-
ListDetailPaneScaffold(
85-
directive = navigator.scaffoldDirective,
86-
value = navigator.scaffoldValue,
87-
listPane = {
88-
val currentSelectedWordIndex = selectedWordIndex
89-
val isDetailVisible =
90-
navigator.scaffoldValue[ListDetailPaneScaffoldRole.Detail] == PaneAdaptedValue.Expanded
91-
92-
ListContent(
93-
words = sampleWords.map(DefinedWord::word),
94-
selectionState = if (isDetailVisible && currentSelectedWordIndex != null) {
95-
SelectionVisibilityState.ShowSelection(currentSelectedWordIndex)
96-
} else {
97-
SelectionVisibilityState.NoSelection
106+
SharedTransitionLayout {
107+
AnimatedContent(targetState = isListAndDetailVisible, label = "simple sample") {
108+
ListDetailPaneScaffold(
109+
directive = navigator.scaffoldDirective,
110+
value = navigator.scaffoldValue,
111+
listPane = {
112+
val currentSelectedWordIndex = selectedWordIndex
113+
val isDetailVisible =
114+
navigator.scaffoldValue[ListDetailPaneScaffoldRole.Detail] == PaneAdaptedValue.Expanded
115+
AnimatedPane {
116+
ListContent(
117+
words = sampleWords,
118+
selectionState = if (isDetailVisible && currentSelectedWordIndex != null) {
119+
SelectionVisibilityState.ShowSelection(currentSelectedWordIndex)
120+
} else {
121+
SelectionVisibilityState.NoSelection
122+
},
123+
onIndexClick = { index ->
124+
selectedWordIndex = index
125+
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
126+
},
127+
isListAndDetailVisible = isListAndDetailVisible,
128+
isListVisible = !isDetailVisible,
129+
animatedVisibilityScope = this@AnimatedPane,
130+
sharedTransitionScope = this@SharedTransitionLayout
131+
)
132+
}
133+
},
134+
detailPane = {
135+
val definedWord = selectedWordIndex?.let(sampleWords::get)
136+
val isDetailVisible =
137+
navigator.scaffoldValue[ListDetailPaneScaffoldRole.Detail] == PaneAdaptedValue.Expanded
138+
AnimatedPane {
139+
DetailContent(
140+
definedWord = definedWord,
141+
isListAndDetailVisible = isListAndDetailVisible,
142+
isDetailVisible = isDetailVisible,
143+
animatedVisibilityScope = this@AnimatedPane,
144+
sharedTransitionScope = this@SharedTransitionLayout
145+
)
146+
}
98147
},
99-
onIndexClick = { index ->
100-
selectedWordIndex = index
101-
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
148+
paneExpansionState = rememberPaneExpansionState(navigator.scaffoldValue),
149+
paneExpansionDragHandle = { state ->
150+
PaneExpansionDragHandle(state, Color.Red)
102151
}
103152
)
104-
},
105-
detailPane = {
106-
val definedWord = selectedWordIndex?.let(sampleWords::get)
107-
DetailContent(
108-
definedWord = definedWord
109-
)
110153
}
111-
)
154+
}
112155
}
113156

114157
/**
@@ -137,10 +180,14 @@ sealed interface SelectionVisibilityState {
137180
*/
138181
@Composable
139182
private fun ListContent(
140-
words: List<String>,
183+
words: List<DefinedWord>,
141184
selectionState: SelectionVisibilityState,
142185
onIndexClick: (index: Int) -> Unit,
143-
modifier: Modifier = Modifier
186+
modifier: Modifier = Modifier,
187+
isListAndDetailVisible: Boolean,
188+
isListVisible: Boolean,
189+
sharedTransitionScope: SharedTransitionScope,
190+
animatedVisibilityScope: AnimatedVisibilityScope
144191
) {
145192
LazyColumn(
146193
contentPadding = PaddingValues(vertical = 16.dp),
@@ -204,12 +251,33 @@ private fun ListContent(
204251
.then(interactionModifier)
205252
.fillMaxWidth()
206253
) {
207-
Text(
208-
text = word,
209-
modifier = Modifier
210-
.fillMaxWidth()
211-
.padding(8.dp)
212-
)
254+
Row {
255+
val imageModifier = Modifier.padding(horizontal = 8.dp)
256+
if (!isListAndDetailVisible && isListVisible) {
257+
with(sharedTransitionScope) {
258+
val state = rememberSharedContentState(key = word.word)
259+
imageModifier.then(
260+
Modifier.sharedElement(
261+
state,
262+
animatedVisibilityScope = animatedVisibilityScope
263+
)
264+
)
265+
}
266+
}
267+
268+
Image(
269+
painter = painterResource(id = word.icon),
270+
contentDescription = word.word,
271+
modifier = imageModifier
272+
)
273+
Text(
274+
text = word.word,
275+
modifier = Modifier
276+
.fillMaxWidth()
277+
.padding(8.dp)
278+
)
279+
}
280+
213281
}
214282
}
215283
}
@@ -222,13 +290,39 @@ private fun ListContent(
222290
private fun DetailContent(
223291
definedWord: DefinedWord?,
224292
modifier: Modifier = Modifier,
293+
isListAndDetailVisible: Boolean,
294+
isDetailVisible: Boolean,
295+
sharedTransitionScope: SharedTransitionScope,
296+
animatedVisibilityScope: AnimatedVisibilityScope
225297
) {
226298
Column(
227299
modifier = modifier
228300
.verticalScroll(rememberScrollState())
229301
.padding(vertical = 16.dp)
230302
) {
231303
if (definedWord != null) {
304+
305+
val imageModifier = Modifier
306+
.padding(horizontal = 8.dp)
307+
.then(
308+
if (!isListAndDetailVisible && isDetailVisible) {
309+
with(sharedTransitionScope) {
310+
val state = rememberSharedContentState(key = definedWord.word)
311+
Modifier.sharedElement(
312+
state,
313+
animatedVisibilityScope = animatedVisibilityScope
314+
)
315+
}
316+
} else {
317+
Modifier
318+
}
319+
)
320+
321+
Image(
322+
painter = painterResource(id = definedWord.icon),
323+
contentDescription = definedWord.word,
324+
modifier = imageModifier
325+
)
232326
Text(
233327
text = definedWord.word,
234328
style = MaterialTheme.typography.headlineMedium
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" android:tint="?android:colorAccent" android:viewportHeight="24" android:viewportWidth="24" android:width="48dp">
2+
3+
<path android:fillColor="@android:color/white" android:pathData="M18.06,22.99h1.66c0.84,0 1.53,-0.64 1.63,-1.46L23,5.05h-5L18,1h-1.97v4.05h-4.97l0.3,2.34c1.71,0.47 3.31,1.32 4.27,2.26 1.44,1.42 2.43,2.89 2.43,5.29v8.05zM1,21.99L1,21h15.03v0.99c0,0.55 -0.45,1 -1.01,1L2.01,22.99c-0.56,0 -1.01,-0.45 -1.01,-1zM16.03,14.99c0,-8 -15.03,-8 -15.03,0h15.03zM1.02,17h15v2h-15z"/>
4+
5+
</vector>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" android:tint="?android:colorAccent" android:viewportHeight="24" android:viewportWidth="24" android:width="48dp">
2+
3+
<path android:fillColor="@android:color/white" android:pathData="M11.35,8.52L11,5h5V1h2v4h5l-1.38,13.79L11.35,8.52zM1,21v1c0,0.55 0.45,1 1,1h13c0.55,0 1,-0.45 1,-1v-1H1zM21.9,21.9L2.1,2.1L0.69,3.51l5.7,5.7C3.28,9.87 1,11.99 1,15h11.17l2,2H1v2h15v-0.17l4.49,4.49L21.9,21.9z"/>
4+
5+
</vector>

CanonicalLayouts/list-detail-compose/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616
plugins {
17-
id 'com.android.application' version '8.3.2' apply false
18-
id 'com.android.library' version '8.3.2' apply false
17+
id 'com.android.application' version '8.6.0' apply false
18+
id 'com.android.library' version '8.6.0' apply false
1919
id 'org.jetbrains.kotlin.android' version '1.9.22' apply false
2020
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#Wed May 25 14:11:15 UTC 2022
22
distributionBase=GRADLE_USER_HOME
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
44
distributionPath=wrapper/dists
55
zipStorePath=wrapper/dists
66
zipStoreBase=GRADLE_USER_HOME

CanonicalLayouts/supporting-pane-compose/app/build.gradle

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ plugins {
2121

2222
android {
2323
namespace 'com.example.supportingpanecompose'
24-
compileSdk 34
24+
compileSdk 35
2525

2626
defaultConfig {
2727
applicationId "com.example.supportingpanecompose"
2828
minSdk 21
29-
targetSdk 34
29+
targetSdk 35
3030
versionCode 1
3131
versionName "1.0"
3232

@@ -63,19 +63,19 @@ android {
6363
}
6464

6565
dependencies {
66-
def composeBom = platform('androidx.compose:compose-bom:2024.03.00')
66+
def composeBom = platform('androidx.compose:compose-bom:2024.09.00')
6767
implementation(composeBom)
6868

69-
implementation 'androidx.core:core-ktx:1.12.0'
70-
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
71-
implementation 'androidx.activity:activity-compose:1.8.2'
69+
implementation 'androidx.core:core-ktx:1.13.1'
70+
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.5'
71+
implementation 'androidx.activity:activity-compose:1.9.2'
7272
implementation "androidx.compose.ui:ui"
7373
implementation "androidx.compose.ui:ui-tooling-preview"
74-
implementation "androidx.window:window:1.2.0"
75-
implementation 'androidx.compose.material3:material3:1.3.0-alpha03'
76-
implementation 'androidx.compose.material3.adaptive:adaptive:1.0.0-alpha09'
77-
implementation 'androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha09'
78-
implementation 'androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha09'
79-
implementation "androidx.compose.material3:material3-window-size-class:1.3.0-alpha03"
74+
implementation "androidx.window:window:1.3.0"
75+
implementation 'androidx.compose.material3:material3:1.3.0'
76+
implementation 'androidx.compose.material3.adaptive:adaptive:1.1.0-alpha02'
77+
implementation 'androidx.compose.material3.adaptive:adaptive-layout:1.1.0-alpha02'
78+
implementation 'androidx.compose.material3.adaptive:adaptive-navigation:1.1.0-alpha02'
79+
implementation "androidx.compose.material3:material3-window-size-class:1.3.0"
8080
testImplementation 'junit:junit:4.13.2'
8181
}

0 commit comments

Comments
 (0)