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 * https://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 package com.android.permissioncontroller.wear.permission.components.material3
17
18 import androidx.compose.foundation.layout.BoxScope
19 import androidx.compose.foundation.layout.RowScope
20 import androidx.compose.foundation.layout.fillMaxWidth
21 import androidx.compose.runtime.Composable
22 import androidx.compose.ui.Modifier
23 import androidx.compose.ui.res.stringResource
24 import androidx.compose.ui.semantics.semantics
25 import androidx.compose.ui.semantics.stateDescription
26 import androidx.compose.ui.text.style.Hyphens
27 import androidx.wear.compose.material3.CheckboxButton
28 import androidx.wear.compose.material3.LocalTextConfiguration
29 import androidx.wear.compose.material3.LocalTextStyle
30 import androidx.wear.compose.material3.RadioButton
31 import androidx.wear.compose.material3.SwitchButton
32 import androidx.wear.compose.material3.Text
33 import com.android.permissioncontroller.wear.permission.components.R
34 import com.android.permissioncontroller.wear.permission.components.material2.ToggleChip
35 import com.android.permissioncontroller.wear.permission.components.theme.ResourceHelper
36 import com.android.permissioncontroller.wear.permission.components.theme.WearPermissionMaterialUIVersion
37
38 /** Defines various toggle control types. */
39 enum class WearPermissionToggleControlType {
40 Switch,
41 Radio,
42 Checkbox,
43 }
44
45 /**
46 * The custom component is a wrapper on different material3 toggle controls.
47 * 1. It provides an unified interface for RadioButton,CheckButton and SwitchButton.
48 * 2. It takes icon, primary, secondary label resources and construct them applying permission app
49 * defaults
50 * 3. Applies custom semantics for based on the toggle control type
51 */
52 @Composable
WearPermissionToggleControlnull53 fun WearPermissionToggleControl(
54 toggleControl: WearPermissionToggleControlType,
55 label: String,
56 checked: Boolean,
57 onCheckedChanged: (Boolean) -> Unit,
58 modifier: Modifier = Modifier,
59 labelMaxLines: Int? = null,
60 materialUIVersion: WearPermissionMaterialUIVersion = ResourceHelper.materialUIVersionInSettings,
61 iconBuilder: WearPermissionIconBuilder? = null,
62 secondaryLabel: String? = null,
63 secondaryLabelMaxLines: Int? = null,
64 enabled: Boolean = true,
65 style: WearPermissionToggleControlStyle = WearPermissionToggleControlStyle.Default,
66 ) {
67 if (materialUIVersion == WearPermissionMaterialUIVersion.MATERIAL2_5) {
68 ToggleChip(
69 toggleControl = toggleControl,
70 label = label,
71 labelMaxLine = labelMaxLines,
72 checked = checked,
73 onCheckedChanged = onCheckedChanged,
74 modifier = modifier,
75 icon = iconBuilder?.iconResource,
76 secondaryLabel = secondaryLabel,
77 secondaryLabelMaxLine = secondaryLabelMaxLines,
78 enabled = enabled,
79 colors = style.material2ToggleControlColors(),
80 )
81 } else {
82 WearPermissionToggleControlInternal(
83 label = label,
84 toggleControl = toggleControl,
85 checked = checked,
86 onCheckedChanged = onCheckedChanged,
87 modifier = modifier,
88 iconBuilder = iconBuilder,
89 labelMaxLines = labelMaxLines,
90 secondaryLabel = secondaryLabel,
91 secondaryLabelMaxLines = secondaryLabelMaxLines,
92 enabled = enabled,
93 style = style,
94 )
95 }
96 }
97
98 @Composable
WearPermissionToggleControlInternalnull99 private fun WearPermissionToggleControlInternal(
100 label: String,
101 toggleControl: WearPermissionToggleControlType,
102 checked: Boolean,
103 onCheckedChanged: (Boolean) -> Unit,
104 modifier: Modifier = Modifier,
105 iconBuilder: WearPermissionIconBuilder? = null,
106 labelMaxLines: Int? = null,
107 secondaryLabel: String? = null,
108 secondaryLabelMaxLines: Int? = null,
109 enabled: Boolean = true,
110 style: WearPermissionToggleControlStyle = WearPermissionToggleControlStyle.Default,
111 ) {
112 val labelParam: (@Composable RowScope.() -> Unit) = {
113 Text(
114 text = label,
115 modifier = Modifier.fillMaxWidth(),
116 maxLines = labelMaxLines ?: LocalTextConfiguration.current.maxLines,
117 style = LocalTextStyle.current.copy(hyphens = Hyphens.Auto),
118 )
119 }
120
121 val secondaryLabelParam: (@Composable RowScope.() -> Unit)? =
122 secondaryLabel?.let {
123 {
124 Text(
125 text = it,
126 modifier = Modifier.fillMaxWidth(),
127 maxLines = secondaryLabelMaxLines ?: LocalTextConfiguration.current.maxLines,
128 style = LocalTextStyle.current.copy(hyphens = Hyphens.Auto),
129 )
130 }
131 }
132
133 val iconParam: (@Composable BoxScope.() -> Unit)? = iconBuilder?.let { { it.build() } }
134 val toggleControlStateDescription =
135 stringResource(
136 if (checked) {
137 R.string.on
138 } else {
139 R.string.off
140 }
141 )
142 val updatedModifier =
143 modifier.fillMaxWidth().semantics { stateDescription = toggleControlStateDescription }
144
145 when (toggleControl) {
146 WearPermissionToggleControlType.Radio ->
147 RadioButton(
148 selected = checked,
149 onSelect = {
150 // We do not want to call if it is already checked.
151 // Radio button can't be toggled off
152 if (!checked) {
153 onCheckedChanged(true)
154 }
155 },
156 modifier = updatedModifier,
157 enabled = enabled,
158 icon = iconParam,
159 secondaryLabel = secondaryLabelParam,
160 label = labelParam,
161 colors = style.radioButtonColorScheme(),
162 )
163
164 WearPermissionToggleControlType.Checkbox ->
165 CheckboxButton(
166 checked = checked,
167 onCheckedChange = onCheckedChanged,
168 modifier = updatedModifier,
169 enabled = enabled,
170 icon = iconParam,
171 secondaryLabel = secondaryLabelParam,
172 label = labelParam,
173 colors = style.checkboxColorScheme(),
174 )
175
176 WearPermissionToggleControlType.Switch ->
177 SwitchButton(
178 checked = checked,
179 onCheckedChange = onCheckedChanged,
180 modifier = updatedModifier,
181 enabled = enabled,
182 icon = iconParam,
183 secondaryLabel = secondaryLabelParam,
184 label = labelParam,
185 colors = style.switchButtonColorScheme(),
186 )
187 }
188 }
189