generated from bitwarden/template
-
Notifications
You must be signed in to change notification settings - Fork 9
/
BitwardenStepper.kt
110 lines (108 loc) · 4.55 KB
/
BitwardenStepper.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package com.bitwarden.authenticator.ui.platform.components.stepper
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.text.input.KeyboardType
import com.bitwarden.authenticator.R
import com.bitwarden.authenticator.ui.platform.base.util.ZERO_WIDTH_CHARACTER
import com.bitwarden.authenticator.ui.platform.base.util.orNullIfBlank
import com.bitwarden.authenticator.ui.platform.components.field.BitwardenTextFieldWithActions
import com.bitwarden.authenticator.ui.platform.components.icon.BitwardenIconButtonWithResource
import com.bitwarden.authenticator.ui.platform.components.model.IconResource
import com.bitwarden.authenticator.ui.platform.components.util.rememberVectorPainter
/**
* Displays a stepper that allows the user to increment and decrement an int value.
*
* @param label Label for the stepper.
* @param value Value to display. Null will display nothing. Will be clamped to [range] before
* display.
* @param onValueChange callback invoked when the user increments or decrements the count. Note
* that this will not be called if the attempts to move value outside of [range].
* @param modifier Modifier.
* @param range Range of valid values.
* @param isIncrementEnabled whether or not the increment button should be enabled.
* @param isDecrementEnabled whether or not the decrement button should be enabled.
* @param textFieldReadOnly whether or not the text field should be read only. The stepper
* increment and decrement buttons function regardless of this value.
*/
@Suppress("LongMethod")
@Composable
fun BitwardenStepper(
label: String,
value: Int?,
onValueChange: (Int) -> Unit,
modifier: Modifier = Modifier,
range: ClosedRange<Int> = 1..Int.MAX_VALUE,
isIncrementEnabled: Boolean = true,
isDecrementEnabled: Boolean = true,
textFieldReadOnly: Boolean = true,
stepperActionsTestTag: String? = null,
increaseButtonTestTag: String? = null,
decreaseButtonTestTag: String? = null,
) {
val clampedValue = value?.coerceIn(range)
if (clampedValue != value && clampedValue != null) {
onValueChange(clampedValue)
}
BitwardenTextFieldWithActions(
label = label,
// We use the zero width character instead of an empty string to make sure label is shown
// small and above the input
value = clampedValue
?.toString()
?: ZERO_WIDTH_CHARACTER,
actionsTestTag = stepperActionsTestTag,
actions = {
BitwardenIconButtonWithResource(
iconRes = IconResource(
iconPainter = rememberVectorPainter(id = R.drawable.ic_minus),
contentDescription = "\u2212",
),
onClick = {
val decrementedValue = ((value ?: 0) - 1).coerceIn(range)
if (decrementedValue != value) {
onValueChange(decrementedValue)
}
},
isEnabled = isDecrementEnabled,
modifier = Modifier.semantics {
if (decreaseButtonTestTag != null) {
testTag = decreaseButtonTestTag
}
},
)
BitwardenIconButtonWithResource(
iconRes = IconResource(
iconPainter = rememberVectorPainter(id = R.drawable.ic_plus),
contentDescription = "+",
),
onClick = {
val incrementedValue = ((value ?: 0) + 1).coerceIn(range)
if (incrementedValue != value) {
onValueChange(incrementedValue)
}
},
isEnabled = isIncrementEnabled,
modifier = Modifier.semantics {
if (increaseButtonTestTag != null) {
testTag = increaseButtonTestTag
}
},
)
},
readOnly = textFieldReadOnly,
keyboardType = KeyboardType.Number,
onValueChange = { newValue ->
onValueChange(
newValue
// Make sure the placeholder is gone, since it will mess up the int conversion
.replace(ZERO_WIDTH_CHARACTER, "")
.orNullIfBlank()
?.let { it.toIntOrNull()?.coerceIn(range) ?: value }
?: range.start,
)
},
modifier = modifier,
)
}