@@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.defaultMinSize
11
11
import androidx.compose.foundation.layout.fillMaxWidth
12
12
import androidx.compose.foundation.layout.height
13
13
import androidx.compose.foundation.layout.padding
14
+ import androidx.compose.foundation.layout.size
14
15
import androidx.compose.foundation.layout.width
15
16
import androidx.compose.material3.Switch
16
17
import androidx.compose.material3.Text
@@ -23,14 +24,18 @@ import androidx.compose.ui.semantics.semantics
23
24
import androidx.compose.ui.semantics.toggleableState
24
25
import androidx.compose.ui.state.ToggleableState
25
26
import androidx.compose.ui.text.AnnotatedString
27
+ import androidx.compose.ui.text.style.TextOverflow
26
28
import androidx.compose.ui.tooling.preview.Preview
29
+ import androidx.compose.ui.unit.Dp
27
30
import androidx.compose.ui.unit.dp
28
31
import com.x8bit.bitwarden.R
29
32
import com.x8bit.bitwarden.ui.platform.base.util.cardStyle
30
33
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
31
34
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
32
35
import com.x8bit.bitwarden.ui.platform.components.divider.BitwardenHorizontalDivider
33
36
import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
37
+ import com.x8bit.bitwarden.ui.platform.components.model.TooltipData
38
+ import com.x8bit.bitwarden.ui.platform.components.row.BitwardenRowOfActions
34
39
import com.x8bit.bitwarden.ui.platform.components.toggle.color.bitwardenSwitchColors
35
40
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
36
41
@@ -42,8 +47,10 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
42
47
* @param onCheckedChange A lambda that is invoked when the switch's state changes.
43
48
* @param cardStyle Indicates the type of card style to be applied.
44
49
* @param modifier A [Modifier] that you can use to apply custom modifications to the composable.
50
+ * @param subtext The text to be displayed under the [label].
45
51
* @param supportingText An optional supporting text to be displayed below the [label].
46
52
* @param contentDescription A description of the switch's UI for accessibility purposes.
53
+ * @param tooltip The data required to display a tooltip.
47
54
* @param readOnly Disables the click functionality without modifying the other UI characteristics.
48
55
* @param enabled Whether or not this switch is enabled. This is similar to setting [readOnly] but
49
56
* comes with some additional visual changes.
@@ -58,18 +65,22 @@ fun BitwardenSwitch(
58
65
onCheckedChange : ((Boolean ) -> Unit )? ,
59
66
cardStyle : CardStyle ? ,
60
67
modifier : Modifier = Modifier ,
68
+ subtext : String? = null,
61
69
supportingText : String? = null,
62
70
contentDescription : String? = null,
71
+ tooltip : TooltipData ? = null,
63
72
readOnly : Boolean = false,
64
73
enabled : Boolean = true,
65
74
actions : (@Composable RowScope .() -> Unit )? = null,
66
75
) {
67
76
BitwardenSwitch (
68
77
modifier = modifier,
69
78
label = label.toAnnotatedString(),
79
+ subtext = subtext,
70
80
isChecked = isChecked,
71
81
onCheckedChange = onCheckedChange,
72
82
contentDescription = contentDescription,
83
+ tooltip = tooltip,
73
84
readOnly = readOnly,
74
85
enabled = enabled,
75
86
cardStyle = cardStyle,
@@ -98,8 +109,10 @@ fun BitwardenSwitch(
98
109
* @param onCheckedChange A lambda that is invoked when the switch's state changes.
99
110
* @param cardStyle Indicates the type of card style to be applied.
100
111
* @param modifier A [Modifier] that you can use to apply custom modifications to the composable.
112
+ * @param subtext The text to be displayed under the [label].
101
113
* @param supportingText An optional supporting text to be displayed below the [label].
102
114
* @param contentDescription A description of the switch's UI for accessibility purposes.
115
+ * @param tooltip The data required to display a tooltip.
103
116
* @param readOnly Disables the click functionality without modifying the other UI characteristics.
104
117
* @param enabled Whether or not this switch is enabled. This is similar to setting [readOnly] but
105
118
* comes with some additional visual changes.
@@ -114,18 +127,22 @@ fun BitwardenSwitch(
114
127
onCheckedChange : ((Boolean ) -> Unit )? ,
115
128
cardStyle : CardStyle ? ,
116
129
modifier : Modifier = Modifier ,
130
+ subtext : String? = null,
117
131
supportingText : String? = null,
118
132
contentDescription : String? = null,
133
+ tooltip : TooltipData ? = null,
119
134
readOnly : Boolean = false,
120
135
enabled : Boolean = true,
121
136
actions : (@Composable RowScope .() -> Unit )? = null,
122
137
) {
123
138
BitwardenSwitch (
124
139
modifier = modifier,
125
140
label = label,
141
+ subtext = subtext,
126
142
isChecked = isChecked,
127
143
onCheckedChange = onCheckedChange,
128
144
contentDescription = contentDescription,
145
+ tooltip = tooltip,
129
146
readOnly = readOnly,
130
147
enabled = enabled,
131
148
cardStyle = cardStyle,
@@ -154,6 +171,7 @@ fun BitwardenSwitch(
154
171
* @param onCheckedChange A lambda that is invoked when the switch's state changes.
155
172
* @param cardStyle Indicates the type of card style to be applied.
156
173
* @param modifier A [Modifier] that you can use to apply custom modifications to the composable.
174
+ * @param subtext The text to be displayed under the [label].
157
175
* @param contentDescription A description of the switch's UI for accessibility purposes.
158
176
* @param readOnly Disables the click functionality without modifying the other UI characteristics.
159
177
* @param enabled Whether or not this switch is enabled. This is similar to setting [readOnly] but
@@ -170,6 +188,7 @@ fun BitwardenSwitch(
170
188
onCheckedChange : ((Boolean ) -> Unit )? ,
171
189
cardStyle : CardStyle ? ,
172
190
modifier : Modifier = Modifier ,
191
+ subtext : String? = null,
173
192
contentDescription : String? = null,
174
193
readOnly : Boolean = false,
175
194
enabled : Boolean = true,
@@ -179,6 +198,7 @@ fun BitwardenSwitch(
179
198
BitwardenSwitch (
180
199
modifier = modifier,
181
200
label = label.toAnnotatedString(),
201
+ subtext = subtext,
182
202
isChecked = isChecked,
183
203
onCheckedChange = onCheckedChange,
184
204
contentDescription = contentDescription,
@@ -198,7 +218,9 @@ fun BitwardenSwitch(
198
218
* @param onCheckedChange A lambda that is invoked when the switch's state changes.
199
219
* @param cardStyle Indicates the type of card style to be applied.
200
220
* @param modifier A [Modifier] that you can use to apply custom modifications to the composable.
221
+ * @param subtext The text to be displayed under the [label].
201
222
* @param contentDescription A description of the switch's UI for accessibility purposes.
223
+ * @param tooltip The data required to display a tooltip.
202
224
* @param readOnly Disables the click functionality without modifying the other UI characteristics.
203
225
* @param enabled Whether or not this switch is enabled. This is similar to setting [readOnly] but
204
226
* comes with some additional visual changes.
@@ -207,15 +229,17 @@ fun BitwardenSwitch(
207
229
* defining the layout of the actions.
208
230
* @param supportingContent A lambda containing content directly below the label.
209
231
*/
210
- @Suppress(" LongMethod" )
232
+ @Suppress(" LongMethod" , " CyclomaticComplexMethod " )
211
233
@Composable
212
234
fun BitwardenSwitch (
213
235
label : AnnotatedString ,
214
236
isChecked : Boolean ,
215
237
onCheckedChange : ((Boolean ) -> Unit )? ,
216
238
cardStyle : CardStyle ? ,
217
239
modifier : Modifier = Modifier ,
240
+ subtext : String? = null,
218
241
contentDescription : String? = null,
242
+ tooltip : TooltipData ? = null,
219
243
readOnly : Boolean = false,
220
244
enabled : Boolean = true,
221
245
supportingContentPadding : PaddingValues = PaddingValues (vertical = 12.dp, horizontal = 16.dp),
@@ -240,26 +264,50 @@ fun BitwardenSwitch(
240
264
) {
241
265
Row (
242
266
verticalAlignment = Alignment .CenterVertically ,
243
- modifier = Modifier
244
- .defaultMinSize(minHeight = 36 .dp)
245
- .padding(horizontal = 16 .dp),
267
+ modifier = Modifier .defaultMinSize(minHeight = 36 .dp),
246
268
) {
269
+ Spacer (modifier = Modifier .width(width = 16 .dp))
247
270
Row (
248
271
modifier = Modifier .weight(weight = 1f ),
249
272
verticalAlignment = Alignment .CenterVertically ,
250
273
) {
251
- Text (
252
- text = label,
253
- style = BitwardenTheme .typography.bodyLarge,
254
- color = if (enabled) {
255
- BitwardenTheme .colorScheme.text.primary
256
- } else {
257
- BitwardenTheme .colorScheme.filledButton.foregroundDisabled
258
- },
259
- modifier = Modifier .testTag(tag = " SwitchText" ),
260
- )
261
-
262
- actions?.invoke(this )
274
+ Column (modifier = Modifier .weight(weight = 1f , fill = false )) {
275
+ Row (verticalAlignment = Alignment .CenterVertically ) {
276
+ Text (
277
+ text = label,
278
+ style = BitwardenTheme .typography.bodyLarge,
279
+ color = if (enabled) {
280
+ BitwardenTheme .colorScheme.text.primary
281
+ } else {
282
+ BitwardenTheme .colorScheme.filledButton.foregroundDisabled
283
+ },
284
+ modifier = Modifier .testTag(tag = " SwitchText" ),
285
+ )
286
+ tooltip?.let {
287
+ ToolTip (
288
+ tooltip = it,
289
+ isVisible = subtext != null ,
290
+ size = 16 .dp,
291
+ )
292
+ }
293
+ }
294
+ subtext?.let {
295
+ Spacer (modifier = Modifier .height(height = 2 .dp))
296
+ Text (
297
+ text = it,
298
+ style = BitwardenTheme .typography.bodyMedium,
299
+ color = if (enabled) {
300
+ BitwardenTheme .colorScheme.text.secondary
301
+ } else {
302
+ BitwardenTheme .colorScheme.filledButton.foregroundDisabled
303
+ },
304
+ maxLines = 2 ,
305
+ overflow = TextOverflow .Ellipsis ,
306
+ modifier = Modifier .testTag(tag = " SwitchSubtext" ),
307
+ )
308
+ }
309
+ }
310
+ tooltip?.let { ToolTip (tooltip = it, isVisible = subtext == null ) }
263
311
}
264
312
Spacer (modifier = Modifier .width(width = 16 .dp))
265
313
Switch (
@@ -271,27 +319,59 @@ fun BitwardenSwitch(
271
319
onCheckedChange = null ,
272
320
colors = bitwardenSwitchColors(),
273
321
)
322
+ actions?.let { BitwardenRowOfActions (actions = it) }
323
+ Spacer (modifier = Modifier .width(width = if (actions == null ) 16 .dp else 4 .dp))
274
324
}
275
325
supportingContent
276
326
?.let { content ->
277
- Spacer (modifier = Modifier .height(height = 12 .dp))
278
- BitwardenHorizontalDivider (
279
- modifier = Modifier
280
- .fillMaxWidth()
281
- .padding(start = 16 .dp),
282
- )
283
- Column (
284
- verticalArrangement = Arrangement .Center ,
285
- modifier = Modifier
286
- .defaultMinSize(minHeight = 48 .dp)
287
- .padding(paddingValues = supportingContentPadding),
327
+ SupportingContent (
328
+ paddingValues = supportingContentPadding,
288
329
content = content,
289
330
)
290
331
}
291
332
? : Spacer (modifier = Modifier .height(height = cardStyle?.let { 12 .dp } ? : 0 .dp))
292
333
}
293
334
}
294
335
336
+ @Composable
337
+ private fun ColumnScope.SupportingContent (
338
+ paddingValues : PaddingValues ,
339
+ content : @Composable ColumnScope .() -> Unit ,
340
+ ) {
341
+ Spacer (modifier = Modifier .height(height = 12 .dp))
342
+ BitwardenHorizontalDivider (
343
+ modifier = Modifier
344
+ .fillMaxWidth()
345
+ .padding(start = 16 .dp),
346
+ )
347
+ Column (
348
+ modifier = Modifier
349
+ .defaultMinSize(minHeight = 48 .dp)
350
+ .padding(paddingValues = paddingValues),
351
+ verticalArrangement = Arrangement .Center ,
352
+ content = content,
353
+ )
354
+ }
355
+
356
+ @Composable
357
+ private fun RowScope.ToolTip (
358
+ tooltip : TooltipData ,
359
+ isVisible : Boolean ,
360
+ size : Dp = 48.dp,
361
+ ) {
362
+ if (! isVisible) return
363
+ Spacer (modifier = Modifier .width(width = 8 .dp))
364
+ BitwardenStandardIconButton (
365
+ vectorIconRes = R .drawable.ic_question_circle_small,
366
+ contentDescription = tooltip.contentDescription,
367
+ onClick = tooltip.onClick,
368
+ contentColor = BitwardenTheme .colorScheme.icon.secondary,
369
+ modifier = Modifier
370
+ .size(size = size)
371
+ .testTag(tag = " SwitchTooltip" ),
372
+ )
373
+ }
374
+
295
375
@Preview
296
376
@Composable
297
377
private fun BitwardenSwitch_preview () {
@@ -314,22 +394,37 @@ private fun BitwardenSwitch_preview() {
314
394
supportingText = " description" ,
315
395
isChecked = true ,
316
396
onCheckedChange = {},
397
+ tooltip = TooltipData (
398
+ onClick = { },
399
+ contentDescription = " content description" ,
400
+ ),
317
401
actions = {
318
402
BitwardenStandardIconButton (
319
- vectorIconRes = R .drawable.ic_question_circle ,
403
+ vectorIconRes = R .drawable.ic_generate ,
320
404
contentDescription = " content description" ,
321
405
onClick = {},
322
406
)
323
407
},
324
408
cardStyle = CardStyle .Middle (),
325
409
)
410
+ BitwardenSwitch (
411
+ label = " Label" ,
412
+ supportingText = " description" ,
413
+ isChecked = true ,
414
+ onCheckedChange = {},
415
+ tooltip = TooltipData (
416
+ onClick = { },
417
+ contentDescription = " content description" ,
418
+ ),
419
+ cardStyle = CardStyle .Middle (),
420
+ )
326
421
BitwardenSwitch (
327
422
label = " Label" ,
328
423
isChecked = false ,
329
424
onCheckedChange = {},
330
425
actions = {
331
426
BitwardenStandardIconButton (
332
- vectorIconRes = R .drawable.ic_question_circle ,
427
+ vectorIconRes = R .drawable.ic_generate ,
333
428
contentDescription = " content description" ,
334
429
onClick = {},
335
430
)
0 commit comments