@@ -5,18 +5,25 @@ import androidx.compose.foundation.layout.Arrangement
55import androidx.compose.foundation.layout.Column
66import androidx.compose.foundation.layout.fillMaxSize
77import androidx.compose.foundation.layout.fillMaxWidth
8+ import androidx.compose.foundation.text.KeyboardActions
89import androidx.compose.foundation.text.KeyboardOptions
910import androidx.compose.material3.Button
1011import androidx.compose.material3.CircularProgressIndicator
1112import androidx.compose.material3.Text
1213import androidx.compose.material3.TextField
1314import androidx.compose.runtime.Composable
15+ import androidx.compose.runtime.LaunchedEffect
16+ import androidx.compose.runtime.getValue
17+ import androidx.compose.runtime.mutableStateOf
18+ import androidx.compose.runtime.saveable.rememberSaveable
19+ import androidx.compose.runtime.setValue
1420import androidx.compose.ui.Alignment
1521import androidx.compose.ui.Modifier
1622import androidx.compose.ui.graphics.ImageBitmap
1723import androidx.compose.ui.text.input.ImeAction
1824import androidx.compose.ui.text.input.KeyboardType
1925import androidx.compose.ui.tooling.preview.Preview
26+ import androidx.compose.ui.platform.LocalFocusManager
2027import androidx.core.text.isDigitsOnly
2128
2229@Composable
@@ -28,6 +35,16 @@ fun PatchableToReducedBitmap(
2835 computeReducedBitmap : () -> Unit = {},
2936 onColorCountChanged : (Int ) -> Unit = {}
3037) {
38+ // Local text state so users can clear or type partial numbers without snapping back to default
39+ var colorText by rememberSaveable { mutableStateOf(colorCount.toString()) }
40+
41+ // Keep local text in sync if colorCount changes from outside (e.g., recomputations)
42+ LaunchedEffect (colorCount) {
43+ colorText = colorCount.toString()
44+ }
45+
46+ val focusManager = LocalFocusManager .current
47+
3148 Column (
3249 modifier = modifier.fillMaxSize(),
3350 verticalArrangement = Arrangement .Center ,
@@ -45,22 +62,33 @@ fun PatchableToReducedBitmap(
4562 )
4663 }
4764 TextField (
48- value = " $colorCount " ,
49- onValueChange = {
50- if (it.isNotBlank() && it.isDigitsOnly()) {
51- onColorCountChanged(it.toInt())
52- } else {
53- colorCount
65+ value = colorText,
66+ onValueChange = { new ->
67+ // Allow empty and numeric-only input
68+ if (new.isEmpty()) {
69+ colorText = " "
70+ } else if (new.isDigitsOnly()) {
71+ colorText = new
72+ new.toIntOrNull()?.let { onColorCountChanged(it) }
5473 }
74+ // ignore non-digit edits
5575 },
5676 label = { Text (" How many colors do you need?" ) },
5777 keyboardOptions = KeyboardOptions .Default .copy(
5878 keyboardType = KeyboardType .Number ,
59- imeAction = ImeAction .Go
79+ imeAction = ImeAction .Done
80+ ),
81+ keyboardActions = KeyboardActions (
82+ onDone = {
83+ if (colorText.isNotEmpty()) {
84+ focusManager.clearFocus()
85+ computeReducedBitmap()
86+ }
87+ }
6088 )
6189 )
6290
63- Button (onClick = computeReducedBitmap) { Text (" Reduce" ) }
91+ Button (enabled = colorText.isNotEmpty(), onClick = computeReducedBitmap) { Text (" Reduce" ) }
6492
6593 reducedImage?.let {
6694 Image (
0 commit comments