1 /*
2  * Copyright 2024 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 package androidx.wear.protolayout.material3.samples
18 
19 import android.content.Context
20 import androidx.annotation.Sampled
21 import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters
22 import androidx.wear.protolayout.DimensionBuilders.dp
23 import androidx.wear.protolayout.DimensionBuilders.expand
24 import androidx.wear.protolayout.DimensionBuilders.weight
25 import androidx.wear.protolayout.LayoutElementBuilders
26 import androidx.wear.protolayout.LayoutElementBuilders.Box
27 import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
28 import androidx.wear.protolayout.ModifiersBuilders
29 import androidx.wear.protolayout.ModifiersBuilders.Clickable
30 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat
31 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString
32 import androidx.wear.protolayout.material3.AppCardStyle
33 import androidx.wear.protolayout.material3.CardDefaults.filledTonalCardColors
34 import androidx.wear.protolayout.material3.CardDefaults.filledVariantCardColors
35 import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults
36 import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults.filledTonalProgressIndicatorColors
37 import androidx.wear.protolayout.material3.CircularProgressIndicatorDefaults.filledVariantProgressIndicatorColors
38 import androidx.wear.protolayout.material3.DataCardStyle.Companion.extraLargeDataCardStyle
39 import androidx.wear.protolayout.material3.DataCardStyle.Companion.largeCompactDataCardStyle
40 import androidx.wear.protolayout.material3.GraphicDataCardStyle.Companion.largeGraphicDataCardStyle
41 import androidx.wear.protolayout.material3.MaterialScope
42 import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MAX_PRIMARY_LAYOUT_MARGIN
43 import androidx.wear.protolayout.material3.TitleCardStyle.Companion.largeTitleCardStyle
44 import androidx.wear.protolayout.material3.Typography
45 import androidx.wear.protolayout.material3.appCard
46 import androidx.wear.protolayout.material3.avatarButton
47 import androidx.wear.protolayout.material3.avatarImage
48 import androidx.wear.protolayout.material3.backgroundImage
49 import androidx.wear.protolayout.material3.button
50 import androidx.wear.protolayout.material3.buttonGroup
51 import androidx.wear.protolayout.material3.card
52 import androidx.wear.protolayout.material3.circularProgressIndicator
53 import androidx.wear.protolayout.material3.compactButton
54 import androidx.wear.protolayout.material3.graphicDataCard
55 import androidx.wear.protolayout.material3.icon
56 import androidx.wear.protolayout.material3.iconButton
57 import androidx.wear.protolayout.material3.iconDataCard
58 import androidx.wear.protolayout.material3.iconEdgeButton
59 import androidx.wear.protolayout.material3.imageButton
60 import androidx.wear.protolayout.material3.materialScope
61 import androidx.wear.protolayout.material3.primaryLayout
62 import androidx.wear.protolayout.material3.segmentedCircularProgressIndicator
63 import androidx.wear.protolayout.material3.text
64 import androidx.wear.protolayout.material3.textButton
65 import androidx.wear.protolayout.material3.textDataCard
66 import androidx.wear.protolayout.material3.textEdgeButton
67 import androidx.wear.protolayout.material3.titleCard
68 import androidx.wear.protolayout.modifiers.LayoutModifier
69 import androidx.wear.protolayout.modifiers.background
70 import androidx.wear.protolayout.modifiers.clickable
71 import androidx.wear.protolayout.modifiers.contentDescription
72 import androidx.wear.protolayout.types.LayoutString
73 import androidx.wear.protolayout.types.asLayoutConstraint
74 import androidx.wear.protolayout.types.layoutString
75 
76 /** Builds Material3 text element with default options. */
77 @Sampled
helloWorldTextDefaultnull78 fun helloWorldTextDefault(context: Context, deviceConfiguration: DeviceParameters): LayoutElement =
79     materialScope(context, deviceConfiguration) {
80         text(text = "Hello Material3".layoutString, typography = Typography.DISPLAY_LARGE)
81     }
82 
83 /** Builds Material3 text element with some of the overridden defaults. */
84 @Sampled
helloWorldTextDynamicCustomnull85 fun helloWorldTextDynamicCustom(
86     context: Context,
87     deviceConfiguration: DeviceParameters
88 ): LayoutElement =
89     materialScope(context, deviceConfiguration) {
90         this.text(
91             text =
92                 LayoutString(
93                     "Static",
94                     DynamicString.constant("Dynamic"),
95                     "LongestConstraint".asLayoutConstraint()
96                 ),
97             typography = Typography.DISPLAY_LARGE,
98             color = colorScheme.tertiary,
99             underline = true,
100             maxLines = 5
101         )
102     }
103 
104 @Sampled
edgeButtonSampleIconnull105 fun edgeButtonSampleIcon(
106     context: Context,
107     deviceConfiguration: DeviceParameters,
108     clickable: Clickable
109 ): LayoutElement =
110     materialScope(context, deviceConfiguration) {
111         iconEdgeButton(
112             onClick = clickable,
113             modifier = LayoutModifier.contentDescription("Description of a button")
114         ) {
115             icon(protoLayoutResourceId = "id")
116         }
117     }
118 
119 @Sampled
edgeButtonSampleTextnull120 fun edgeButtonSampleText(
121     context: Context,
122     deviceConfiguration: DeviceParameters,
123     clickable: Clickable
124 ): LayoutElement =
125     materialScope(context, deviceConfiguration) {
126         textEdgeButton(
127             onClick = clickable,
128             modifier = LayoutModifier.contentDescription("Description of a button")
129         ) {
130             text("Hello".layoutString)
131         }
132     }
133 
134 @Sampled
topLevelLayoutnull135 fun topLevelLayout(
136     context: Context,
137     deviceConfiguration: DeviceParameters,
138     clickable: Clickable
139 ): LayoutElement =
140     materialScope(context, deviceConfiguration) {
141         primaryLayout(
142             titleSlot = { text("App title".layoutString) },
143             mainSlot = {
144                 buttonGroup {
145                     // To be populated with proper components
146                     buttonGroupItem {
147                         LayoutElementBuilders.Box.Builder()
148                             .setModifiers(
149                                 ModifiersBuilders.Modifiers.Builder()
150                                     .setBackground(
151                                         ModifiersBuilders.Background.Builder()
152                                             .setCorner(shapes.small)
153                                             .build()
154                                     )
155                                     .build()
156                             )
157                             .build()
158                     }
159                 }
160             },
161             // Adjust margins as the corner of the inner content is on the square side.
162             margins = MAX_PRIMARY_LAYOUT_MARGIN,
163             bottomSlot = {
164                 iconEdgeButton(
165                     onClick = clickable,
166                     modifier = LayoutModifier.contentDescription("Description")
167                 ) {
168                     icon("id")
169                 }
170             }
171         )
172     }
173 
174 @Sampled
cardSamplenull175 fun cardSample(
176     context: Context,
177     deviceConfiguration: DeviceParameters,
178     clickable: Clickable
179 ): LayoutElement =
180     materialScope(context, deviceConfiguration) {
181         primaryLayout(
182             mainSlot = {
183                 card(
184                     onClick = clickable,
185                     modifier =
186                         LayoutModifier.contentDescription("Card with image background")
187                             .clickable(id = "card"),
188                     width = expand(),
189                     height = expand(),
190                     backgroundContent = { backgroundImage(protoLayoutResourceId = "id") }
191                 ) {
192                     text("Content of the Card!".layoutString)
193                 }
194             }
195         )
196     }
197 
198 @Sampled
titleCardSamplenull199 fun titleCardSample(
200     context: Context,
201     deviceConfiguration: DeviceParameters,
202     clickable: Clickable
203 ): LayoutElement =
204     materialScope(context, deviceConfiguration) {
205         primaryLayout(
206             mainSlot = {
207                 titleCard(
208                     onClick = clickable,
209                     modifier = LayoutModifier.contentDescription("Title Card"),
210                     height = expand(),
211                     colors = filledVariantCardColors(),
212                     style = largeTitleCardStyle(),
213                     title = { text("This is title of the title card".layoutString) },
214                     time = { text("NOW".layoutString) },
215                     content = { text("Content of the Card!".layoutString) }
216                 )
217             }
218         )
219     }
220 
221 @Sampled
appCardSamplenull222 fun appCardSample(
223     context: Context,
224     deviceConfiguration: DeviceParameters,
225     clickable: Clickable
226 ): LayoutElement =
227     materialScope(context, deviceConfiguration) {
228         primaryLayout(
229             mainSlot = {
230                 appCard(
231                     onClick = clickable,
232                     modifier = LayoutModifier.contentDescription("App Card"),
233                     height = expand(),
234                     colors = filledTonalCardColors(),
235                     style = AppCardStyle.largeAppCardStyle(),
236                     title = { text("This is title of the app card".layoutString) },
237                     time = { text("NOW".layoutString) },
238                     label = { text("Label".layoutString) },
239                     content = { text("Content of the Card!".layoutString) },
240                 )
241             }
242         )
243     }
244 
245 @Sampled
dataCardSamplenull246 fun dataCardSample(
247     context: Context,
248     deviceConfiguration: DeviceParameters,
249     clickable: Clickable
250 ): LayoutElement =
251     materialScope(context, deviceConfiguration) {
252         primaryLayout(
253             mainSlot = {
254                 buttonGroup {
255                     buttonGroupItem {
256                         textDataCard(
257                             onClick = clickable,
258                             modifier = LayoutModifier.contentDescription("Data Card with text"),
259                             width = weight(1f),
260                             height = expand(),
261                             colors = filledTonalCardColors(),
262                             style = extraLargeDataCardStyle(),
263                             title = { this.text("1km".layoutString) },
264                             content = { this.text("Run".layoutString) },
265                             secondaryText = { this.text("Nice!".layoutString) }
266                         )
267                     }
268                     buttonGroupItem {
269                         iconDataCard(
270                             onClick = clickable,
271                             modifier = LayoutModifier.contentDescription("Data Card with icon"),
272                             width = weight(1f),
273                             height = expand(),
274                             colors = filledTonalCardColors(),
275                             style = extraLargeDataCardStyle(),
276                             title = { this.text("2km".layoutString) },
277                             secondaryIcon = { icon("id") },
278                             content = { this.text("Run".layoutString) },
279                         )
280                     }
281                     buttonGroupItem {
282                         textDataCard(
283                             onClick = clickable,
284                             modifier =
285                                 LayoutModifier.contentDescription(
286                                     "Compact Data Card without icon or secondary label"
287                                 ),
288                             width = weight(3f),
289                             height = expand(),
290                             colors = filledVariantCardColors(),
291                             style = largeCompactDataCardStyle(),
292                             title = { this.text("10:30".layoutString) },
293                             content = { this.text("PM".layoutString) },
294                         )
295                     }
296                 }
297             }
298         )
299     }
300 
301 @Sampled
graphicDataCardSamplenull302 fun graphicDataCardSample(
303     context: Context,
304     deviceConfiguration: DeviceParameters,
305     clickable: Clickable
306 ): LayoutElement =
307     materialScope(context, deviceConfiguration) {
308         primaryLayout(
309             mainSlot = {
310                 graphicDataCard(
311                     onClick = clickable,
312                     modifier = LayoutModifier.contentDescription("Data Card with graphic"),
313                     height = expand(),
314                     colors = filledVariantCardColors(),
315                     style = largeGraphicDataCardStyle(),
316                     title = { text("1,234".layoutString) },
317                     content = { icon("steps") },
318                     graphic = {
319                         segmentedCircularProgressIndicator(
320                             segmentCount = 5,
321                             staticProgress = 0.5F,
322                             colors = filledTonalProgressIndicatorColors(),
323                         )
324                     },
325                 )
326             }
327         )
328     }
329 
330 @Sampled
customButtonSamplenull331 fun customButtonSample(
332     context: Context,
333     deviceConfiguration: DeviceParameters,
334     clickable: Clickable
335 ): LayoutElement =
336     materialScope(context, deviceConfiguration) {
337         primaryLayout(
338             mainSlot = {
339                 // Button with custom content inside
340                 button(
341                     onClick = clickable,
342                     modifier =
343                         LayoutModifier.contentDescription("Big button with image background")
344                             .background(colorScheme.primary),
345                     width = expand(),
346                     height = expand(),
347                     labelContent = {
348                         // This can be further built.
349                         Box.Builder().build()
350                     }
351                 )
352             }
353         )
354     }
355 
356 @Sampled
oneSlotButtonsSamplenull357 fun oneSlotButtonsSample(
358     context: Context,
359     deviceConfiguration: DeviceParameters,
360     clickable: Clickable
361 ): LayoutElement =
362     materialScope(context, deviceConfiguration) {
363         primaryLayout(
364             mainSlot = {
365                 buttonGroup {
366                     buttonGroupItem {
367                         iconButton(
368                             onClick = clickable,
369                             modifier =
370                                 LayoutModifier.contentDescription(
371                                     "Big button with image background"
372                                 ),
373                             width = expand(),
374                             height = expand(),
375                             iconContent = { icon("id1") }
376                         )
377                     }
378                     buttonGroupItem {
379                         iconButton(
380                             onClick = clickable,
381                             modifier =
382                                 LayoutModifier.contentDescription(
383                                     "Big button with image background"
384                                 ),
385                             width = expand(),
386                             height = expand(),
387                             shape = shapes.large,
388                             iconContent = { icon("id2") }
389                         )
390                     }
391                     buttonGroupItem {
392                         textButton(
393                             onClick = clickable,
394                             modifier =
395                                 LayoutModifier.contentDescription(
396                                     "Big button with image background"
397                                 ),
398                             width = expand(),
399                             height = expand(),
400                             shape = shapes.large,
401                             labelContent = { text("Dec".layoutString) }
402                         )
403                     }
404                 }
405             }
406         )
407     }
408 
409 @Sampled
imageButtonSamplenull410 fun imageButtonSample(
411     context: Context,
412     deviceConfiguration: DeviceParameters,
413     clickable: Clickable
414 ): LayoutElement =
415     materialScope(context, deviceConfiguration) {
416         primaryLayout(
417             mainSlot = {
418                 imageButton(
419                     onClick = clickable,
420                     modifier =
421                         LayoutModifier.contentDescription("Big button with image background"),
422                     width = expand(),
423                     height = expand(),
424                     backgroundContent = { backgroundImage(protoLayoutResourceId = "id") }
425                 )
426             }
427         )
428     }
429 
430 @Sampled
singleSegmentCircularProgressIndicatornull431 fun singleSegmentCircularProgressIndicator(
432     context: Context,
433     deviceParameters: DeviceParameters,
434 ): LayoutElement =
435     materialScope(context, deviceParameters) {
436         circularProgressIndicator(
437             dynamicProgress =
438                 DynamicFloat.animate(
439                     0.0F,
440                     1.1F,
441                     CircularProgressIndicatorDefaults.recommendedAnimationSpec
442                 ),
443             startAngleDegrees = 200F,
444             endAngleDegrees = 520F,
445             colors = filledVariantProgressIndicatorColors(),
446             size = dp(85F)
447         )
448     }
449 
450 @Sampled
pillShapeButtonsSamplenull451 fun pillShapeButtonsSample(
452     context: Context,
453     deviceConfiguration: DeviceParameters,
454     clickable: Clickable
455 ): LayoutElement =
456     materialScope(context, deviceConfiguration) {
457         primaryLayout(
458             mainSlot = {
459                 button(
460                     onClick = clickable,
461                     modifier = LayoutModifier.contentDescription("Pill shape button"),
462                     width = expand(),
463                     height = expand(),
464                     labelContent = { text("First label".layoutString) },
465                     secondaryLabelContent = { text("Second label".layoutString) },
466                     iconContent = { icon("id") }
467                 )
468             }
469         )
470     }
471 
472 @Sampled
avatarButtonSamplenull473 fun MaterialScope.avatarButtonSample() =
474     avatarButton(
475         onClick = clickable(),
476         modifier = LayoutModifier.contentDescription("Pill button"),
477         avatarContent = { avatarImage("id") },
<lambda>null478         labelContent = { text("Primary label".layoutString) },
<lambda>null479         secondaryLabelContent = { text("Secondary label".layoutString) },
480     )
481 
482 @Sampled
compactButtonsSamplenull483 fun compactButtonsSample(
484     context: Context,
485     deviceConfiguration: DeviceParameters,
486     clickable: Clickable
487 ): LayoutElement =
488     materialScope(context, deviceConfiguration) {
489         primaryLayout(
490             mainSlot = {
491                 compactButton(
492                     onClick = clickable,
493                     modifier = LayoutModifier.contentDescription("Compact button"),
494                     width = expand(),
495                     labelContent = { text("Action".layoutString) },
496                     iconContent = { icon("id") }
497                 )
498             }
499         )
500     }
501 
502 @Sampled
multipleSegmentsCircularProgressIndicatornull503 fun multipleSegmentsCircularProgressIndicator(
504     context: Context,
505     deviceParameters: DeviceParameters,
506 ): LayoutElement =
507     materialScope(context, deviceParameters) {
508         segmentedCircularProgressIndicator(
509             segmentCount = 5,
510             dynamicProgress =
511                 DynamicFloat.animate(
512                     0.0F,
513                     1.1F,
514                     CircularProgressIndicatorDefaults.recommendedAnimationSpec
515                 ),
516             startAngleDegrees = 200F,
517             endAngleDegrees = 520F,
518             colors = filledVariantProgressIndicatorColors(),
519             size = dp(85F)
520         )
521     }
522