Update view with victory points setting.

Add victory points to settings adapter.
This commit is contained in:
2023-08-26 13:00:30 +02:00
parent 37bbf45ce0
commit c97d98704b
9 changed files with 146 additions and 62 deletions

View File

@@ -45,7 +45,7 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.zobrist.tichucounter.domain.DrawerItem 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.KeepScreenOn
import me.zobrist.tichucounter.domain.Language import me.zobrist.tichucounter.domain.Language
import me.zobrist.tichucounter.domain.ReviewService import me.zobrist.tichucounter.domain.ReviewService
@@ -70,7 +70,7 @@ import me.zobrist.tichucounter.ui.settings.SettingsViewModel
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : AppCompatActivity(), ISettingsChangeListener { class MainActivity : AppCompatActivity(), ISystemSettingsChangeListener {
@Inject @Inject
lateinit var settingsAdapter: SettingsAdapter lateinit var settingsAdapter: SettingsAdapter
@@ -192,7 +192,6 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
var topBarState by remember { mutableStateOf(TopBarState()) } var topBarState by remember { mutableStateOf(TopBarState()) }
var snackbarHostState by remember { mutableStateOf(SnackbarHostState()) } var snackbarHostState by remember { mutableStateOf(SnackbarHostState()) }
val scope = rememberCoroutineScope()
Scaffold( Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) }, snackbarHost = { SnackbarHost(snackbarHostState) },
@@ -211,7 +210,7 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
startDestination = Route.COUNTER.name, startDestination = Route.COUNTER.name,
modifier = Modifier.padding(paddings) modifier = Modifier.padding(paddings)
) { ) {
composable(Route.COUNTER.name) { this.composable(Route.COUNTER.name.toString()) {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
@@ -231,15 +230,16 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
mainViewModel.activeGameHasRounds, mainViewModel.activeGameHasRounds,
{ expanded = true } { expanded = true }
) { ) {
val newGameTranslated = stringResource(R.string.newGame)
DropDownMenu( DropDownMenu(
mapOf("new" to R.string.newGame), listOf(newGameTranslated),
"", "",
expanded, expanded,
) { ) {
expanded = false expanded = false
it?.let { it?.let {
when (it) { when (it) {
"new" -> mainViewModel.newGame() newGameTranslated -> mainViewModel.newGame()
} }
} }
} }

View File

@@ -17,12 +17,19 @@ enum class Language(val value: LocaleListCompat) {
enum class KeepScreenOn(val value: Boolean) { ON(true), OFF(false) } 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 onLanguageChanged(language: Language)
fun onThemeChanged(theme: Theme) fun onThemeChanged(theme: Theme)
fun onScreenOnChanged(keepOn: KeepScreenOn) fun onScreenOnChanged(keepOn: KeepScreenOn)
} }
interface IGameSettingsChangeListener : ISettingsChangeListener {
fun onVictoryPointsChanged(victoryPoints: Int)
}
@Singleton @Singleton
class SettingsAdapter @Inject constructor(@ApplicationContext private val context: Context) { class SettingsAdapter @Inject constructor(@ApplicationContext private val context: Context) {
@@ -37,9 +44,9 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
var keepScreenOn: KeepScreenOn var keepScreenOn: KeepScreenOn
private set private set
var reviewDialogShownDate: Date
get() = Date(sharedPreferences.getLong("reviewDialogShownDate", 0)) var victoryPoints: Int
set(value) = updatePreference("reviewDialogShownDate", value.time) private set
init { init {
language = try { language = try {
@@ -59,14 +66,22 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
} catch (_: java.lang.Exception) { } catch (_: java.lang.Exception) {
KeepScreenOn.OFF KeepScreenOn.OFF
} }
victoryPoints = sharedPreferences.getInt(VictoryPoints::class.simpleName, 1000)
} }
fun registerOnChangeListener(listener: ISettingsChangeListener) { fun registerOnChangeListener(listener: ISettingsChangeListener) {
listenerList.add(listener) listenerList.add(listener)
listener.onThemeChanged(theme) if (listener is ISystemSettingsChangeListener) {
listener.onLanguageChanged(language) listener.onThemeChanged(theme)
listener.onScreenOnChanged(keepScreenOn) listener.onLanguageChanged(language)
listener.onScreenOnChanged(keepScreenOn)
}
if (listener is IGameSettingsChangeListener) {
listener.onVictoryPointsChanged(victoryPoints)
}
} }
fun unregisterOnChangeListener(listener: ISettingsChangeListener?) { fun unregisterOnChangeListener(listener: ISettingsChangeListener?) {
@@ -93,6 +108,12 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
notifyListeners(setting) notifyListeners(setting)
} }
fun setVictoryPoints(setting: Int) {
this.victoryPoints = setting
updatePreference(VictoryPoints::class.simpleName, setting)
notifyListeners(setting)
}
private fun updatePreference(name: String?, value: String) { private fun updatePreference(name: String?, value: String) {
val editor = sharedPreferences.edit() val editor = sharedPreferences.edit()
editor.putString(name, value) editor.putString(name, value)
@@ -105,22 +126,33 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
editor.apply() editor.apply()
} }
private fun updatePreference(name: String?, value: Int) {
val editor = sharedPreferences.edit()
editor.putInt(name, value)
editor.apply()
}
private fun notifyListeners(language: Language) { private fun notifyListeners(language: Language) {
listenerList.forEach { listenerList.filterIsInstance<ISystemSettingsChangeListener>().forEach {
it.onLanguageChanged(language) it.onLanguageChanged(language)
} }
} }
private fun notifyListeners(theme: Theme) { private fun notifyListeners(theme: Theme) {
listenerList.forEach { listenerList.filterIsInstance<ISystemSettingsChangeListener>().forEach {
it.onThemeChanged(theme) it.onThemeChanged(theme)
} }
} }
private fun notifyListeners(keepScreenOn: KeepScreenOn) { private fun notifyListeners(victoryPoints: VictoryPoints) {
listenerList.forEach { listenerList.filterIsInstance<IGameSettingsChangeListener>().forEach {
it.onScreenOnChanged(keepScreenOn) it.onVictoryPointsChanged(victoryPoints)
} }
} }
private fun notifyListeners(keepScreenOn: KeepScreenOn) {
listenerList.filterIsInstance<ISystemSettingsChangeListener>().forEach {
it.onScreenOnChanged(keepScreenOn)
}
}
} }

View File

@@ -7,25 +7,29 @@ import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
@Composable @Composable
fun <T> DropDownMenu(map: Map<T, Int>, selected: T, expanded: Boolean, onSelected: (T?) -> Unit) { fun <T> DropDownMenu(
list: Collection<T>,
selected: T,
expanded: Boolean,
onSelected: (T?) -> Unit
) {
DropdownMenu( DropdownMenu(
expanded = expanded, expanded = expanded,
onDismissRequest = { onSelected(null) } onDismissRequest = { onSelected(null) }
) { ) {
map.forEach { list.forEach {
DropdownMenuItem( DropdownMenuItem(
onClick = { onClick = {
onSelected(it.key) onSelected(it)
}, },
trailingIcon = { trailingIcon = {
if (it.key == selected) { if (it == selected) {
Icon(Icons.Outlined.Check, null) Icon(Icons.Outlined.Check, null)
} }
}, },
text = { Text(stringResource(it.value)) }, text = { Text(it.toString()) },
) )
} }
} }

View File

@@ -123,6 +123,7 @@ internal class PreviewViewModel : ICounterViewModel {
listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long") listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long")
override val teamNameSuggestionsB: List<String> = override val teamNameSuggestionsB: List<String> =
listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long") listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long")
override val victoryPoints: Int = 1000
override fun focusLastInput() { override fun focusLastInput() {
} }

View File

@@ -12,6 +12,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.entity.Round import me.zobrist.tichucounter.data.entity.Round
import me.zobrist.tichucounter.domain.IGameSettingsChangeListener
import me.zobrist.tichucounter.domain.Tichu import me.zobrist.tichucounter.domain.Tichu
import me.zobrist.tichucounter.domain.digitCount import me.zobrist.tichucounter.domain.digitCount
import me.zobrist.tichucounter.domain.getTotalPoints import me.zobrist.tichucounter.domain.getTotalPoints
@@ -58,6 +59,7 @@ interface ICounterViewModel : IKeyBoardViewModel {
val teamNameB: String val teamNameB: String
val teamNameSuggestionsA: List<String> val teamNameSuggestionsA: List<String>
val teamNameSuggestionsB: List<String> val teamNameSuggestionsB: List<String>
val victoryPoints: Int
fun updateNameA(value: String) fun updateNameA(value: String)
fun updateNameB(value: String) fun updateNameB(value: String)
@@ -67,7 +69,7 @@ interface ICounterViewModel : IKeyBoardViewModel {
class CounterViewModel @Inject constructor( class CounterViewModel @Inject constructor(
private val gameRepository: GameRepository private val gameRepository: GameRepository
) : ) :
ViewModel(), ICounterViewModel { ViewModel(), ICounterViewModel, IGameSettingsChangeListener {
override var roundScoreList by mutableStateOf(emptyList<Round>()) override var roundScoreList by mutableStateOf(emptyList<Round>())
private set private set
@@ -114,6 +116,9 @@ class CounterViewModel @Inject constructor(
override var teamNameSuggestionsB by mutableStateOf(listOf<String>()) override var teamNameSuggestionsB by mutableStateOf(listOf<String>())
private set private set
override var victoryPoints by mutableStateOf(0)
private set
override var activeValue: String override var activeValue: String
get() { get() {
return if (isBFocused) { return if (isBFocused) {
@@ -171,6 +176,12 @@ class CounterViewModel @Inject constructor(
buildTeamNameSuggestions() 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() { private fun deleteLastDigitActive() {
if (activeValue != "") { if (activeValue != "") {
activeValue = activeValue.dropLast(1) activeValue = activeValue.dropLast(1)

View File

@@ -44,6 +44,7 @@ val themeMap = mapOf(
Theme.LIGHT to R.string.light Theme.LIGHT to R.string.light
) )
val victoryPointsList = listOf(500, 1000, 1500, 2000)
@Composable @Composable
fun SettingsView(viewModel: SettingsViewModel) { fun SettingsView(viewModel: SettingsViewModel) {
@@ -51,9 +52,11 @@ fun SettingsView(viewModel: SettingsViewModel) {
viewModel.screenOn.value, viewModel.screenOn.value,
viewModel.language, viewModel.language,
viewModel.theme, viewModel.theme,
viewModel.victoryPoints,
{ viewModel.updateScreenOn(it) }, { viewModel.updateScreenOn(it) },
{ viewModel.updateLanguage(it) }, { viewModel.updateLanguage(it) },
{ viewModel.updateTheme(it) }) { viewModel.updateTheme(it) },
{ viewModel.updateVictoryPoints(it) })
} }
@Composable @Composable
@@ -61,11 +64,22 @@ fun SettingsView(
valueScreenOn: Boolean = true, valueScreenOn: Boolean = true,
valueLanguage: Language = Language.ENGLISH, valueLanguage: Language = Language.ENGLISH,
valueTheme: Theme = Theme.DARK, valueTheme: Theme = Theme.DARK,
valueVictoryPoints: Int = 1000,
updateScreenOn: (KeepScreenOn) -> Unit = {}, updateScreenOn: (KeepScreenOn) -> Unit = {},
updateLanguage: (Language) -> 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( BooleanSetting(
stringResource(R.string.keep_screen_on), stringResource(R.string.keep_screen_on),
valueScreenOn valueScreenOn
@@ -82,6 +96,18 @@ fun SettingsView(
themeMap, themeMap,
valueTheme, valueTheme,
) { updateTheme(it) } ) { 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( Row(
Modifier Modifier
.padding(20.dp) .padding(bottom = 15.dp, top = 5.dp)
.fillMaxWidth() .fillMaxWidth()
) { ) {
Column(Modifier.weight(5f)) { Column(Modifier.weight(5f)) {
@@ -119,21 +145,32 @@ fun BooleanSetting(name: String, value: Boolean, updateValue: (Boolean) -> Unit)
@Composable @Composable
fun <T> StringSetting(name: String, map: Map<T, Int>, selected: T, onSelected: (T) -> Unit) { fun <T> StringSetting(name: String, map: Map<T, Int>, 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 <T> ListSetting(name: String, list: Collection<T>, selected: T, onSelected: (T) -> Unit) {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
Row( Row(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(20.dp) .padding(bottom = 15.dp, top = 5.dp)
.clickable { expanded = true }) { .clickable { expanded = true }) {
Column(Modifier.weight(5f)) { Column(Modifier.weight(5f)) {
Text(name, style = MaterialTheme.typography.bodyLarge, overflow = TextOverflow.Ellipsis) Text(name, style = MaterialTheme.typography.bodyLarge, overflow = TextOverflow.Ellipsis)
map[selected]?.let { Text(
Text( selected.toString(),
stringResource(it), style = MaterialTheme.typography.labelLarge
style = MaterialTheme.typography.labelLarge )
)
}
} }
Column(Modifier.weight(1f)) { Column(Modifier.weight(1f)) {
@@ -142,15 +179,15 @@ fun <T> StringSetting(name: String, map: Map<T, Int>, selected: T, onSelected: (
contentDescription = null, contentDescription = null,
modifier = Modifier.align(End) modifier = Modifier.align(End)
) )
}
DropDownMenu( DropDownMenu(
map, list,
selected, selected,
expanded, expanded,
) { ) {
expanded = false expanded = false
it?.let { onSelected(it) } 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,
) {}
}
}
}

View File

@@ -24,6 +24,9 @@ class SettingsViewModel @Inject constructor(private val settings: SettingsAdapte
var screenOn by mutableStateOf(settings.keepScreenOn) var screenOn by mutableStateOf(settings.keepScreenOn)
private set private set
var victoryPoints by mutableStateOf(settings.victoryPoints)
private set
fun updateLanguage(language: Language) { fun updateLanguage(language: Language) {
settings.setLanguage(language) settings.setLanguage(language)
this.language = settings.language this.language = settings.language
@@ -39,4 +42,8 @@ class SettingsViewModel @Inject constructor(private val settings: SettingsAdapte
screenOn = settings.keepScreenOn screenOn = settings.keepScreenOn
} }
fun updateVictoryPoints(value: Int) {
settings.setVictoryPoints(value)
victoryPoints = settings.victoryPoints
}
} }

View File

@@ -29,5 +29,7 @@
<string name="undo_question">RÜCKGÄNGIG</string> <string name="undo_question">RÜCKGÄNGIG</string>
<string name="activated_success">Spiel aktiviert.</string> <string name="activated_success">Spiel aktiviert.</string>
<string name="to_calculator_question">WEITERSPIELEN</string> <string name="to_calculator_question">WEITERSPIELEN</string>
<string name="display">Anzeige</string>
<string name="game">Spiel</string>
<string name="victory_points">Siegespunkte</string>
</resources> </resources>

View File

@@ -33,4 +33,7 @@
<string name="undo_question">UNDO</string> <string name="undo_question">UNDO</string>
<string name="activated_success">Game activated.</string> <string name="activated_success">Game activated.</string>
<string name="to_calculator_question">CONTINUE PLAYING</string> <string name="to_calculator_question">CONTINUE PLAYING</string>
<string name="display">Display</string>
<string name="game">Game</string>
<string name="victory_points">Victory points</string>
</resources> </resources>