Skip to content

Commit d2379d5

Browse files
committed
Allow changing starting number
1 parent 1593c0b commit d2379d5

5 files changed

Lines changed: 137 additions & 8 deletions

File tree

mobile/src/main/java/es/hegocre/scorecounter/ScoreViewModel.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package es.hegocre.scorecounter
22

33
import android.app.Application
44
import android.content.Context
5+
import androidx.compose.runtime.mutableIntStateOf
56
import androidx.compose.runtime.toMutableStateList
67
import androidx.lifecycle.AndroidViewModel
78
import androidx.lifecycle.viewModelScope
@@ -26,15 +27,26 @@ class ScoreViewModel(application: Application) : AndroidViewModel(application) {
2627
val scores: List<Score>
2728
get() = _scores
2829

30+
private val _startingScore = mutableIntStateOf(_preferencesManager.getInt("starting_score", 0))
31+
val startingScore: Int
32+
get() = _startingScore.intValue
33+
2934
private suspend fun saveScore() {
3035
withContext(Dispatchers.IO) {
3136
val scoresString = Json.encodeToString(_scores.toList())
3237
_preferencesManager.edit { putString("scores", scoresString) }
3338
}
3439
}
3540

36-
fun add() {
37-
_scores.add(Score())
41+
suspend fun setStartingScore(startingScore: Int) {
42+
_startingScore.intValue = startingScore
43+
withContext(Dispatchers.IO) {
44+
_preferencesManager.edit { putInt("starting_score", startingScore) }
45+
}
46+
}
47+
48+
fun add(startingScore: Int = 0) {
49+
_scores.add(Score(score = startingScore))
3850
viewModelScope.launch {
3951
saveScore()
4052
}

mobile/src/main/java/es/hegocre/scorecounter/ui/components/ScoreList.kt

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import android.annotation.SuppressLint
44
import android.content.Context
55
import android.content.res.Configuration
66
import androidx.compose.foundation.gestures.detectTapGestures
7+
import androidx.compose.foundation.interaction.MutableInteractionSource
8+
import androidx.compose.foundation.interaction.PressInteraction
79
import androidx.compose.foundation.layout.Box
810
import androidx.compose.foundation.layout.Column
911
import androidx.compose.foundation.layout.Row
@@ -15,6 +17,7 @@ import androidx.compose.foundation.layout.padding
1517
import androidx.compose.foundation.layout.width
1618
import androidx.compose.foundation.lazy.LazyColumn
1719
import androidx.compose.foundation.lazy.LazyRow
20+
import androidx.compose.foundation.text.KeyboardOptions
1821
import androidx.compose.material.icons.Icons
1922
import androidx.compose.material.icons.filled.Add
2023
import androidx.compose.material.icons.filled.Close
@@ -36,6 +39,7 @@ import androidx.compose.runtime.derivedStateOf
3639
import androidx.compose.runtime.getValue
3740
import androidx.compose.runtime.mutableStateOf
3841
import androidx.compose.runtime.remember
42+
import androidx.compose.runtime.rememberCoroutineScope
3943
import androidx.compose.runtime.saveable.rememberSaveable
4044
import androidx.compose.runtime.setValue
4145
import androidx.compose.ui.Alignment
@@ -46,7 +50,9 @@ import androidx.compose.ui.geometry.Offset
4650
import androidx.compose.ui.input.pointer.pointerInput
4751
import androidx.compose.ui.platform.LocalConfiguration
4852
import androidx.compose.ui.platform.LocalContext
53+
import androidx.compose.ui.platform.LocalViewConfiguration
4954
import androidx.compose.ui.res.stringResource
55+
import androidx.compose.ui.text.input.KeyboardType
5056
import androidx.compose.ui.unit.dp
5157
import androidx.compose.ui.unit.sp
5258
import androidx.compose.ui.window.Dialog
@@ -55,13 +61,17 @@ import es.hegocre.scorecounter.ScoreViewModel
5561
import es.hegocre.scorecounter.model.Score
5662
import es.hegocre.scorecounter.ui.theme.ScoreCounterTheme
5763
import androidx.core.content.edit
64+
import kotlinx.coroutines.delay
65+
import kotlinx.coroutines.flow.collectLatest
66+
import kotlinx.coroutines.launch
5867

5968
@SuppressLint("ConfigurationScreenWidthHeight")
6069
@Composable
6170
fun ScoreList(
6271
scoreViewModel: ScoreViewModel
6372
) {
6473
val context = LocalContext.current
74+
val coroutineScope = rememberCoroutineScope()
6575

6676
val scores = scoreViewModel.scores
6777
val scoresNum by remember {
@@ -74,13 +84,41 @@ fun ScoreList(
7484
.getBoolean("isFirstLaunch", true)
7585
)
7686
}
87+
var showSetStartingScoreDialog by remember { mutableStateOf(false) }
7788

7889
ScoreCounterTheme {
7990
val configuration = LocalConfiguration.current
8091

8192
Scaffold(
8293
floatingActionButton = {
83-
FloatingActionButton(onClick = { scoreViewModel.add() }) {
94+
val interactionSource = remember { MutableInteractionSource() }
95+
96+
val viewConfiguration = LocalViewConfiguration.current
97+
98+
LaunchedEffect(interactionSource) {
99+
var isLongClick = false
100+
101+
interactionSource.interactions.collectLatest { interaction ->
102+
when (interaction) {
103+
is PressInteraction.Press -> {
104+
isLongClick = false
105+
delay(viewConfiguration.longPressTimeoutMillis)
106+
isLongClick = true
107+
showSetStartingScoreDialog = true
108+
}
109+
110+
is PressInteraction.Release -> {
111+
if (isLongClick.not()) {
112+
scoreViewModel.add(scoreViewModel.startingScore)
113+
}
114+
115+
}
116+
117+
}
118+
}
119+
}
120+
121+
FloatingActionButton(onClick = { }, interactionSource = interactionSource) {
84122
Icon(
85123
imageVector = Icons.Default.Add,
86124
contentDescription = "Add Score"
@@ -150,8 +188,6 @@ fun ScoreList(
150188
}
151189
}
152190

153-
154-
155191
if (showTutorialDialog) {
156192
context.getSharedPreferences("preferences", Context.MODE_PRIVATE)
157193
.edit { putBoolean("isFirstLaunch", false) }
@@ -167,6 +203,20 @@ fun ScoreList(
167203
text = { Text(text = stringResource(id = R.string.dialog_tutorial_message)) }
168204
)
169205
}
206+
207+
if (showSetStartingScoreDialog) {
208+
InputStartingScoreDialog(
209+
currentStartingScore = scoreViewModel.startingScore,
210+
onSetStartingScore = {
211+
coroutineScope.launch {
212+
scoreViewModel.setStartingScore(it.toIntOrNull() ?: 0)
213+
}
214+
},
215+
onDismissRequest = {
216+
showSetStartingScoreDialog = false
217+
}
218+
)
219+
}
170220
}
171221
}
172222

@@ -299,6 +349,70 @@ fun InputPlayerNameDialog(
299349
}
300350
}
301351

352+
LaunchedEffect(key1 = Unit) {
353+
requester.requestFocus()
354+
}
355+
}
356+
357+
@Composable
358+
fun InputStartingScoreDialog(
359+
currentStartingScore: Int,
360+
onSetStartingScore: (String) -> Unit,
361+
onDismissRequest: (() -> Unit)? = null
362+
) {
363+
val requester = FocusRequester()
364+
365+
val (startingScore, setStartingScore) = remember { mutableStateOf(currentStartingScore.toString()) }
366+
367+
Dialog(
368+
onDismissRequest = { onDismissRequest?.invoke() },
369+
) {
370+
Surface(
371+
color = MaterialTheme.colorScheme.surface,
372+
contentColor = contentColorFor(backgroundColor = MaterialTheme.colorScheme.surface),
373+
shape = MaterialTheme.shapes.extraLarge,
374+
tonalElevation = 6.dp,
375+
) {
376+
Column(modifier = Modifier.padding(all = 24.dp)) {
377+
Text(
378+
text = stringResource(id = R.string.starting_score),
379+
style = MaterialTheme.typography.headlineSmall,
380+
modifier = Modifier.padding(bottom = 16.dp)
381+
)
382+
383+
OutlinedTextField(
384+
modifier = Modifier
385+
.padding(bottom = 16.dp, top = 8.dp)
386+
.focusRequester(requester),
387+
value = startingScore,
388+
onValueChange = { if (it.isBlank() || it.toIntOrNull() != null) setStartingScore(it) },
389+
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number),
390+
singleLine = true,
391+
maxLines = 1,
392+
label = { Text(text = stringResource(id = R.string.starting_score)) },
393+
placeholder = { Text(text = currentStartingScore.toString()) }
394+
)
395+
396+
397+
TextButton(
398+
onClick = {
399+
if (startingScore.isBlank()) {
400+
onSetStartingScore(currentStartingScore.toString())
401+
} else if (startingScore.toIntOrNull() != null) {
402+
onSetStartingScore(startingScore)
403+
}
404+
onDismissRequest?.invoke()
405+
},
406+
modifier = Modifier
407+
.align(Alignment.End)
408+
.padding(horizontal = 0.dp)
409+
) {
410+
Text(text = stringResource(android.R.string.ok))
411+
}
412+
}
413+
}
414+
}
415+
302416
LaunchedEffect(key1 = Unit) {
303417
requester.requestFocus()
304418
}

mobile/src/main/res/values-ca/strings.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<resources>
33
<string name="app_name">Marcador de puntuació</string>
44
<string name="dialog_tutorial_title">Com utilitzar</string>
5-
<string name="dialog_tutorial_message">Per canviar el marcador, premi a la part superior per incrementar-lo, la part inferior per reduir-lo, o mantingui premut per restablir-lo.</string>
5+
<string name="dialog_tutorial_message">Per canviar el marcador, premi a la part superior per incrementar-lo, la part inferior per reduir-lo, o mantingui premut per restablir-lo. Per canviar la puntuació inicial, mantingui premut el botó +.</string>
66
<string name="player_name">Nom del jugador</string>
77
<string name="player">Jugador</string>
8+
<string name="starting_score">Puntuació inicial</string>
89
</resources>

mobile/src/main/res/values-es/strings.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<resources>
33
<string name="app_name">Marcador de puntuación</string>
44
<string name="dialog_tutorial_title">Como utililizar</string>
5-
<string name="dialog_tutorial_message">Para cambiar el marcador, pulse en la parte superior para incrementarlo, la parte inferior para reducirlo, o mantenga pulsado para restablecerlo.</string>
5+
<string name="dialog_tutorial_message">Para cambiar el marcador, pulse en la parte superior para incrementarlo, la parte inferior para reducirlo, o mantenga pulsado para restablecerlo. Para cambiar la puntuación inicial, mantenga pulsado el botón +.</string>
66
<string name="player_name">Nombre del jugador</string>
77
<string name="player">Jugador</string>
8+
<string name="starting_score">Puntuación inicial</string>
89
</resources>
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<resources>
22
<string name="app_name">Score Counter</string>
33
<string name="dialog_tutorial_title">How to use</string>
4-
<string name="dialog_tutorial_message">To change a score, press on its upper part to increment it, on its lower part to decrement it, or long press to reset it.</string>
4+
<string name="dialog_tutorial_message">To change a score, press on its upper part to increment it, on its lower part to decrement it, or long press to reset it. Change the starting score by long pressing the + button.</string>
55
<string name="player_name">Player name</string>
66
<string name="player">Player</string>
7+
<string name="starting_score">Starting score</string>
78
</resources>

0 commit comments

Comments
 (0)