• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 @file:OptIn(ExperimentalAnimatableApi::class)
18 
19 package com.android.mechanics.demo.presentation
20 
21 import androidx.compose.animation.core.ExperimentalAnimatableApi
22 import androidx.compose.foundation.background
23 import androidx.compose.foundation.layout.Arrangement
24 import androidx.compose.foundation.layout.Column
25 import androidx.compose.foundation.layout.ColumnScope
26 import androidx.compose.foundation.layout.Row
27 import androidx.compose.foundation.layout.Spacer
28 import androidx.compose.foundation.layout.fillMaxWidth
29 import androidx.compose.foundation.layout.height
30 import androidx.compose.foundation.layout.padding
31 import androidx.compose.foundation.rememberScrollState
32 import androidx.compose.foundation.verticalScroll
33 import androidx.compose.material.icons.Icons
34 import androidx.compose.material.icons.filled.AllInclusive
35 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
36 import androidx.compose.material3.Icon
37 import androidx.compose.material3.LocalContentColor
38 import androidx.compose.material3.MaterialTheme
39 import androidx.compose.material3.MaterialTheme.typography
40 import androidx.compose.material3.Text
41 import androidx.compose.runtime.Composable
42 import androidx.compose.runtime.CompositionLocalProvider
43 import androidx.compose.runtime.getValue
44 import androidx.compose.runtime.mutableStateOf
45 import androidx.compose.runtime.remember
46 import androidx.compose.runtime.setValue
47 import androidx.compose.ui.Modifier
48 import androidx.compose.ui.unit.Dp
49 import androidx.compose.ui.unit.dp
50 import com.android.compose.animation.scene.ElementKey
51 import com.android.compose.modifiers.thenIf
52 import com.android.mechanics.demo.staging.behavior.reveal.FadeContentRevealSpec
53 import com.android.mechanics.demo.staging.behavior.reveal.fadeReveal
54 import com.android.mechanics.demo.staging.behavior.reveal.rememberFadeContentRevealSpec
55 import com.android.mechanics.demo.staging.behavior.reveal.revealContainer
56 import com.android.mechanics.demo.tuneable.Demo
57 import com.android.mechanics.demo.tuneable.DpSlider
58 import com.android.mechanics.demo.tuneable.GuaranteeSection
59 import com.android.mechanics.demo.tuneable.LabelledCheckbox
60 import com.android.mechanics.demo.tuneable.Section
61 import com.android.mechanics.demo.tuneable.SpringParameterSection
62 import com.android.mechanics.demo.util.ExpandableCard
63 
64 object PracticalDemoAppear : Demo<PracticalDemoAppear.Config> {
65     object Elements {
66         val ExpandableContent = ElementKey("ExpandableContent")
67     }
68 
69     data class Config(val fadeSpec: FadeContentRevealSpec, val showItemBackground: Boolean)
70 
71     @Composable
72     override fun DemoUi(config: Config, modifier: Modifier) {
73         val colors = MaterialTheme.colorScheme
74         ExpandableCard(
75             modifier = modifier.fillMaxWidth(),
76             header = { Text(text = "Contents", style = typography.titleMedium) },
77         ) { isExpanded ->
78             Column(
79                 verticalArrangement = Arrangement.spacedBy(8.dp),
80                 modifier =
81                     Modifier.fillMaxWidth()
82                         .element(Elements.ExpandableContent)
83                         .revealContainer(this@ExpandableCard)
84                         .verticalScroll(rememberScrollState())
85                         .padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
86             ) {
87                 if (isExpanded) {
88                     Spacer(modifier = Modifier.height(24.dp))
89                     repeat(10) {
90                         Row(
91                             horizontalArrangement = Arrangement.spacedBy(8.dp),
92                             modifier =
93                                 Modifier.noResizeDuringTransitions()
94                                     .fadeReveal(spec = config.fadeSpec, debug = true)
95                                     .fillMaxWidth()
96                                     .thenIf(config.showItemBackground) {
97                                         Modifier.background(colors.primary)
98                                     },
99                         ) {
100                             CompositionLocalProvider(
101                                 LocalContentColor provides
102                                     if (config.showItemBackground) colors.onPrimary
103                                     else colors.onSurface
104                             ) {
105                                 Icon(Icons.Default.AllInclusive, null)
106                                 Text(text = "Item ${it + 1}", modifier = Modifier.height(20.dp))
107                             }
108                         }
109                     }
110                 }
111             }
112         }
113     }
114 
115     @OptIn(ExperimentalMaterial3ExpressiveApi::class)
116     @Composable
117     override fun rememberDefaultConfig(): Config {
118         val fadeRevealSpec = rememberFadeContentRevealSpec(showDelta = 8.dp, hideDelta = 16.dp)
119         return remember(fadeRevealSpec) { Config(fadeRevealSpec, showItemBackground = false) }
120     }
121 
122     override var visualizationInputRange by mutableStateOf(0f..1000f)
123     override val collapsedGraphHeight: Dp = 20.dp
124 
125     @Composable
126     override fun ColumnScope.ConfigUi(config: Config, onConfigChanged: (Config) -> Unit) {
127         LabelledCheckbox(
128             "Show item background",
129             config.showItemBackground,
130             onCheckedChange = { onConfigChanged(config.copy(showItemBackground = it)) },
131             modifier = Modifier.fillMaxWidth(),
132         )
133 
134         Section(
135             "Show",
136             summary = { "" },
137             value = config.fadeSpec,
138             onValueChanged = { onConfigChanged(config.copy(fadeSpec = it)) },
139             sectionKey = "show spec",
140             modifier = Modifier.fillMaxWidth(),
141         ) { spec, onSpecChanged ->
142             SpringParameterSection(
143                 " Spring",
144                 spec.showSpring,
145                 onValueChanged = { onSpecChanged(spec.copy(showSpring = it)) },
146                 "showspring",
147                 modifier = Modifier.fillMaxWidth(),
148             )
149             GuaranteeSection(
150                 " Guarantee",
151                 spec.showGuarantee,
152                 { onSpecChanged(spec.copy(showGuarantee = it)) },
153                 "showguarantee",
154                 modifier = Modifier.fillMaxWidth(),
155             )
156 
157             Text(text = "Delta", modifier = Modifier.padding(start = 8.dp))
158             DpSlider(spec.showDelta, { onSpecChanged(spec.copy(showDelta = it)) }, 0.dp..24.dp)
159         }
160 
161         Section(
162             "Hide",
163             summary = { "" },
164             value = config.fadeSpec,
165             onValueChanged = { onConfigChanged(config.copy(fadeSpec = it)) },
166             sectionKey = "show spec",
167             modifier = Modifier.fillMaxWidth(),
168         ) { spec, onSpecChanged ->
169             SpringParameterSection(
170                 "Spring",
171                 spec.hideSpring,
172                 onValueChanged = { onSpecChanged(spec.copy(hideSpring = it)) },
173                 "hidespring",
174                 modifier = Modifier.fillMaxWidth(),
175             )
176             GuaranteeSection(
177                 "Guarantee",
178                 spec.hideGuarantee,
179                 { onSpecChanged(spec.copy(hideGuarantee = it)) },
180                 "hideguarantee",
181                 modifier = Modifier.fillMaxWidth(),
182             )
183 
184             Text(text = "Delta", modifier = Modifier.padding(start = 8.dp))
185             DpSlider(spec.hideDelta, { onSpecChanged(spec.copy(hideDelta = it)) }, 0.dp..24.dp)
186         }
187     }
188 
189     override val identifier: String = "PracticalDemoAppear"
190 }
191