1 /*
2  * Copyright 2023 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.glance.template
18 
19 import android.content.Context
20 import androidx.compose.runtime.Composable
21 import androidx.compose.runtime.CompositionLocalProvider
22 import androidx.compose.ui.unit.Dp
23 import androidx.compose.ui.unit.DpSize
24 import androidx.compose.ui.unit.dp
25 import androidx.glance.GlanceComposable
26 import androidx.glance.GlanceId
27 import androidx.glance.LocalSize
28 import androidx.glance.appwidget.GlanceAppWidget
29 import androidx.glance.appwidget.SizeMode
30 import androidx.glance.appwidget.provideContent
31 import androidx.glance.state.GlanceStateDefinition
32 import androidx.glance.state.PreferencesGlanceStateDefinition
33 
34 /** A [GlanceAppWidget] that provides template local values. */
35 abstract class GlanceTemplateAppWidget : GlanceAppWidget() {
36 
37     companion object {
38         internal val sizeMin = 30.dp
39         internal val sizeS = 200.dp
40         internal val sizeM = 241.dp
41         internal val sizeL = 350.dp
42         internal val sizeXL = 600.dp
43         private val COLLAPSED = DpSize(sizeMin, sizeMin)
44         private val HORIZONTAL_S = DpSize(sizeM, sizeMin)
45         private val HORIZONTAL_M = DpSize(sizeM, sizeS)
46         private val HORIZONTAL_L = DpSize(sizeL, sizeMin)
47         private val HORIZONTAL_XL = DpSize(sizeXL, sizeL)
48         private val VERTICAL_S = DpSize(sizeMin, sizeM)
49         private val VERTICAL_M = DpSize(sizeS, sizeM)
50         private val VERTICAL_L = DpSize(sizeS, sizeL)
51     }
52 
53     /** Default widget size mode is [SizeMode.Responsive] */
54     override val sizeMode: SizeMode =
55         SizeMode.Responsive(
56             setOf(
57                 COLLAPSED,
58                 VERTICAL_S,
59                 VERTICAL_M,
60                 VERTICAL_L,
61                 HORIZONTAL_S,
62                 HORIZONTAL_M,
63                 HORIZONTAL_L,
64                 HORIZONTAL_XL
65             )
66         )
67 
68     /** Default widget state definition is [PreferencesGlanceStateDefinition] */
69     override val stateDefinition: GlanceStateDefinition<*>? = PreferencesGlanceStateDefinition
70 
<lambda>null71     final override suspend fun provideGlance(context: Context, id: GlanceId) = provideContent {
72         CompositionLocalProvider(
73             LocalTemplateMode provides mode(),
74         ) {
75             TemplateContent()
76         }
77     }
78 
TemplateContentnull79     @Composable @GlanceComposable abstract fun TemplateContent()
80 
81     /** Resolves the current display mode */
82     @Composable
83     private fun mode(): TemplateMode {
84         val height = LocalSize.current.height
85         val width = LocalSize.current.width
86         return if (height <= Dp(240f) && width <= Dp(240f)) {
87             TemplateMode.Collapsed
88         } else if ((width / height) < (3.0 / 2.0)) {
89             TemplateMode.Vertical
90         } else {
91             TemplateMode.Horizontal
92         }
93     }
94 }
95