diff --git a/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt b/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt index f42db16..1f62ef8 100644 --- a/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt +++ b/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt @@ -45,7 +45,7 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import me.zobrist.tichucounter.domain.DrawerItem -import me.zobrist.tichucounter.domain.ISettingsChangeListener +import me.zobrist.tichucounter.domain.ISystemSettingsChangeListener import me.zobrist.tichucounter.domain.KeepScreenOn import me.zobrist.tichucounter.domain.Language import me.zobrist.tichucounter.domain.ReviewService @@ -70,7 +70,7 @@ import me.zobrist.tichucounter.ui.settings.SettingsViewModel import javax.inject.Inject @AndroidEntryPoint -class MainActivity : AppCompatActivity(), ISettingsChangeListener { +class MainActivity : AppCompatActivity(), ISystemSettingsChangeListener { @Inject lateinit var settingsAdapter: SettingsAdapter @@ -192,7 +192,6 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener { var topBarState by remember { mutableStateOf(TopBarState()) } var snackbarHostState by remember { mutableStateOf(SnackbarHostState()) } - val scope = rememberCoroutineScope() Scaffold( snackbarHost = { SnackbarHost(snackbarHostState) }, @@ -211,7 +210,7 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener { startDestination = Route.COUNTER.name, modifier = Modifier.padding(paddings) ) { - composable(Route.COUNTER.name) { + this.composable(Route.COUNTER.name.toString()) { var expanded by remember { mutableStateOf(false) } @@ -231,15 +230,16 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener { mainViewModel.activeGameHasRounds, { expanded = true } ) { + val newGameTranslated = stringResource(R.string.newGame) DropDownMenu( - mapOf("new" to R.string.newGame), + listOf(newGameTranslated), "", expanded, ) { expanded = false it?.let { when (it) { - "new" -> mainViewModel.newGame() + newGameTranslated -> mainViewModel.newGame() } } } diff --git a/app/src/main/java/me/zobrist/tichucounter/domain/SettingsAdapter.kt b/app/src/main/java/me/zobrist/tichucounter/domain/SettingsAdapter.kt index 6f7e074..52862d0 100644 --- a/app/src/main/java/me/zobrist/tichucounter/domain/SettingsAdapter.kt +++ b/app/src/main/java/me/zobrist/tichucounter/domain/SettingsAdapter.kt @@ -17,12 +17,19 @@ enum class Language(val value: LocaleListCompat) { enum class KeepScreenOn(val value: Boolean) { ON(true), OFF(false) } -interface ISettingsChangeListener { +typealias VictoryPoints = Int + +interface ISettingsChangeListener +interface ISystemSettingsChangeListener : ISettingsChangeListener { fun onLanguageChanged(language: Language) fun onThemeChanged(theme: Theme) fun onScreenOnChanged(keepOn: KeepScreenOn) } +interface IGameSettingsChangeListener : ISettingsChangeListener { + fun onVictoryPointsChanged(victoryPoints: Int) +} + @Singleton class SettingsAdapter @Inject constructor(@ApplicationContext private val context: Context) { @@ -37,9 +44,9 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex var keepScreenOn: KeepScreenOn private set - var reviewDialogShownDate: Date - get() = Date(sharedPreferences.getLong("reviewDialogShownDate", 0)) - set(value) = updatePreference("reviewDialogShownDate", value.time) + + var victoryPoints: Int + private set init { language = try { @@ -59,14 +66,22 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex } catch (_: java.lang.Exception) { KeepScreenOn.OFF } + + victoryPoints = sharedPreferences.getInt(VictoryPoints::class.simpleName, 1000) } fun registerOnChangeListener(listener: ISettingsChangeListener) { listenerList.add(listener) - listener.onThemeChanged(theme) - listener.onLanguageChanged(language) - listener.onScreenOnChanged(keepScreenOn) + if (listener is ISystemSettingsChangeListener) { + listener.onThemeChanged(theme) + listener.onLanguageChanged(language) + listener.onScreenOnChanged(keepScreenOn) + } + + if (listener is IGameSettingsChangeListener) { + listener.onVictoryPointsChanged(victoryPoints) + } } fun unregisterOnChangeListener(listener: ISettingsChangeListener?) { @@ -93,6 +108,12 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex notifyListeners(setting) } + fun setVictoryPoints(setting: Int) { + this.victoryPoints = setting + updatePreference(VictoryPoints::class.simpleName, setting) + notifyListeners(setting) + } + private fun updatePreference(name: String?, value: String) { val editor = sharedPreferences.edit() editor.putString(name, value) @@ -105,22 +126,33 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex editor.apply() } + private fun updatePreference(name: String?, value: Int) { + val editor = sharedPreferences.edit() + editor.putInt(name, value) + editor.apply() + } + private fun notifyListeners(language: Language) { - listenerList.forEach { + listenerList.filterIsInstance().forEach { it.onLanguageChanged(language) } } private fun notifyListeners(theme: Theme) { - listenerList.forEach { + listenerList.filterIsInstance().forEach { it.onThemeChanged(theme) } } - private fun notifyListeners(keepScreenOn: KeepScreenOn) { - listenerList.forEach { - it.onScreenOnChanged(keepScreenOn) + private fun notifyListeners(victoryPoints: VictoryPoints) { + listenerList.filterIsInstance().forEach { + it.onVictoryPointsChanged(victoryPoints) } } + private fun notifyListeners(keepScreenOn: KeepScreenOn) { + listenerList.filterIsInstance().forEach { + it.onScreenOnChanged(keepScreenOn) + } + } } \ No newline at end of file diff --git a/app/src/main/java/me/zobrist/tichucounter/ui/composables/DropDownMenu.kt b/app/src/main/java/me/zobrist/tichucounter/ui/composables/DropDownMenu.kt index 12a9700..6042af4 100644 --- a/app/src/main/java/me/zobrist/tichucounter/ui/composables/DropDownMenu.kt +++ b/app/src/main/java/me/zobrist/tichucounter/ui/composables/DropDownMenu.kt @@ -7,25 +7,29 @@ import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource @Composable -fun DropDownMenu(map: Map, selected: T, expanded: Boolean, onSelected: (T?) -> Unit) { +fun DropDownMenu( + list: Collection, + selected: T, + expanded: Boolean, + onSelected: (T?) -> Unit +) { DropdownMenu( expanded = expanded, onDismissRequest = { onSelected(null) } ) { - map.forEach { + list.forEach { DropdownMenuItem( onClick = { - onSelected(it.key) + onSelected(it) }, trailingIcon = { - if (it.key == selected) { + if (it == selected) { Icon(Icons.Outlined.Check, null) } }, - text = { Text(stringResource(it.value)) }, + text = { Text(it.toString()) }, ) } } diff --git a/app/src/main/java/me/zobrist/tichucounter/ui/counter/CounterView.kt b/app/src/main/java/me/zobrist/tichucounter/ui/counter/CounterView.kt index a338d72..e9d7da3 100644 --- a/app/src/main/java/me/zobrist/tichucounter/ui/counter/CounterView.kt +++ b/app/src/main/java/me/zobrist/tichucounter/ui/counter/CounterView.kt @@ -123,6 +123,7 @@ internal class PreviewViewModel : ICounterViewModel { listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long") override val teamNameSuggestionsB: List = listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long") + override val victoryPoints: Int = 1000 override fun focusLastInput() { } diff --git a/app/src/main/java/me/zobrist/tichucounter/ui/counter/CounterViewModel.kt b/app/src/main/java/me/zobrist/tichucounter/ui/counter/CounterViewModel.kt index f943a48..4439cf5 100644 --- a/app/src/main/java/me/zobrist/tichucounter/ui/counter/CounterViewModel.kt +++ b/app/src/main/java/me/zobrist/tichucounter/ui/counter/CounterViewModel.kt @@ -12,6 +12,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import me.zobrist.tichucounter.data.entity.Round +import me.zobrist.tichucounter.domain.IGameSettingsChangeListener import me.zobrist.tichucounter.domain.Tichu import me.zobrist.tichucounter.domain.digitCount import me.zobrist.tichucounter.domain.getTotalPoints @@ -58,6 +59,7 @@ interface ICounterViewModel : IKeyBoardViewModel { val teamNameB: String val teamNameSuggestionsA: List val teamNameSuggestionsB: List + val victoryPoints: Int fun updateNameA(value: String) fun updateNameB(value: String) @@ -67,7 +69,7 @@ interface ICounterViewModel : IKeyBoardViewModel { class CounterViewModel @Inject constructor( private val gameRepository: GameRepository ) : - ViewModel(), ICounterViewModel { + ViewModel(), ICounterViewModel, IGameSettingsChangeListener { override var roundScoreList by mutableStateOf(emptyList()) private set @@ -114,6 +116,9 @@ class CounterViewModel @Inject constructor( override var teamNameSuggestionsB by mutableStateOf(listOf()) private set + override var victoryPoints by mutableStateOf(0) + private set + override var activeValue: String get() { return if (isBFocused) { @@ -171,6 +176,12 @@ class CounterViewModel @Inject constructor( buildTeamNameSuggestions() + if (totalScoreA >= victoryPoints || totalScoreB >= victoryPoints) { + if (totalScoreA == totalScoreB) { + + } + } + } } } @@ -330,6 +341,10 @@ class CounterViewModel @Inject constructor( } } + override fun onVictoryPointsChanged(victoryPoints: Int) { + this.victoryPoints = victoryPoints + } + private fun deleteLastDigitActive() { if (activeValue != "") { activeValue = activeValue.dropLast(1) diff --git a/app/src/main/java/me/zobrist/tichucounter/ui/settings/SettingsView.kt b/app/src/main/java/me/zobrist/tichucounter/ui/settings/SettingsView.kt index bcdddf4..83ffacb 100644 --- a/app/src/main/java/me/zobrist/tichucounter/ui/settings/SettingsView.kt +++ b/app/src/main/java/me/zobrist/tichucounter/ui/settings/SettingsView.kt @@ -44,6 +44,7 @@ val themeMap = mapOf( Theme.LIGHT to R.string.light ) +val victoryPointsList = listOf(500, 1000, 1500, 2000) @Composable fun SettingsView(viewModel: SettingsViewModel) { @@ -51,9 +52,11 @@ fun SettingsView(viewModel: SettingsViewModel) { viewModel.screenOn.value, viewModel.language, viewModel.theme, + viewModel.victoryPoints, { viewModel.updateScreenOn(it) }, { viewModel.updateLanguage(it) }, - { viewModel.updateTheme(it) }) + { viewModel.updateTheme(it) }, + { viewModel.updateVictoryPoints(it) }) } @Composable @@ -61,11 +64,22 @@ fun SettingsView( valueScreenOn: Boolean = true, valueLanguage: Language = Language.ENGLISH, valueTheme: Theme = Theme.DARK, + valueVictoryPoints: Int = 1000, updateScreenOn: (KeepScreenOn) -> Unit = {}, updateLanguage: (Language) -> Unit = {}, - updateTheme: (Theme) -> Unit = {} + updateTheme: (Theme) -> Unit = {}, + updateVictoryPoints: (Int) -> Unit = {} ) { - Column { + Column( + Modifier + .padding(20.dp) + ) { + + Text( + text = stringResource(R.string.display), + style = MaterialTheme.typography.headlineMedium + ) + BooleanSetting( stringResource(R.string.keep_screen_on), valueScreenOn @@ -82,6 +96,18 @@ fun SettingsView( themeMap, valueTheme, ) { updateTheme(it) } + + Text( + text = stringResource(R.string.game), + style = MaterialTheme.typography.headlineMedium + ) + + + ListSetting( + stringResource(R.string.victory_points), + victoryPointsList, + valueVictoryPoints + ) { updateVictoryPoints(it) } } } @@ -90,7 +116,7 @@ fun BooleanSetting(name: String, value: Boolean, updateValue: (Boolean) -> Unit) Row( Modifier - .padding(20.dp) + .padding(bottom = 15.dp, top = 5.dp) .fillMaxWidth() ) { Column(Modifier.weight(5f)) { @@ -119,21 +145,32 @@ fun BooleanSetting(name: String, value: Boolean, updateValue: (Boolean) -> Unit) @Composable fun StringSetting(name: String, map: Map, selected: T, onSelected: (T) -> Unit) { + val translated = map.map { it.key to stringResource(it.value) }.toMap() + val getValue = map.map { stringResource(it.value) to it.key }.toMap() + + ListSetting( + name, + translated.values, + translated[selected] + ) { getValue[it]?.let { it1 -> onSelected(it1) } } +} + +@Composable +fun ListSetting(name: String, list: Collection, selected: T, onSelected: (T) -> Unit) { + var expanded by remember { mutableStateOf(false) } Row( Modifier .fillMaxWidth() - .padding(20.dp) + .padding(bottom = 15.dp, top = 5.dp) .clickable { expanded = true }) { Column(Modifier.weight(5f)) { Text(name, style = MaterialTheme.typography.bodyLarge, overflow = TextOverflow.Ellipsis) - map[selected]?.let { - Text( - stringResource(it), - style = MaterialTheme.typography.labelLarge - ) - } + Text( + selected.toString(), + style = MaterialTheme.typography.labelLarge + ) } Column(Modifier.weight(1f)) { @@ -142,15 +179,15 @@ fun StringSetting(name: String, map: Map, selected: T, onSelected: ( contentDescription = null, modifier = Modifier.align(End) ) - } - DropDownMenu( - map, - selected, - expanded, - ) { - expanded = false - it?.let { onSelected(it) } + DropDownMenu( + list, + selected, + expanded, + ) { + expanded = false + it?.let { onSelected(it) } + } } } } @@ -167,20 +204,3 @@ fun SettingsViewPreview() { } } } - -@Preview(name = "Light Mode") -@Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true) -@Composable -fun StringSettingPreview() { - - AppTheme { - Surface { - DropDownMenu( - themeMap, - Theme.LIGHT, - true, - ) {} - } - } -} - diff --git a/app/src/main/java/me/zobrist/tichucounter/ui/settings/SettingsViewModel.kt b/app/src/main/java/me/zobrist/tichucounter/ui/settings/SettingsViewModel.kt index b37e1bd..b3657b3 100644 --- a/app/src/main/java/me/zobrist/tichucounter/ui/settings/SettingsViewModel.kt +++ b/app/src/main/java/me/zobrist/tichucounter/ui/settings/SettingsViewModel.kt @@ -24,6 +24,9 @@ class SettingsViewModel @Inject constructor(private val settings: SettingsAdapte var screenOn by mutableStateOf(settings.keepScreenOn) private set + var victoryPoints by mutableStateOf(settings.victoryPoints) + private set + fun updateLanguage(language: Language) { settings.setLanguage(language) this.language = settings.language @@ -39,4 +42,8 @@ class SettingsViewModel @Inject constructor(private val settings: SettingsAdapte screenOn = settings.keepScreenOn } + fun updateVictoryPoints(value: Int) { + settings.setVictoryPoints(value) + victoryPoints = settings.victoryPoints + } } \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d2138cd..82c3530 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -29,5 +29,7 @@ RÜCKGÄNGIG Spiel aktiviert. WEITERSPIELEN - + Anzeige + Spiel + Siegespunkte \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3d18461..ff61cf2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,4 +33,7 @@ UNDO Game activated. CONTINUE PLAYING + Display + Game + Victory points \ No newline at end of file