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.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()
}
}
}

View File

@@ -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,16 +66,24 @@ 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)
if (listener is ISystemSettingsChangeListener) {
listener.onThemeChanged(theme)
listener.onLanguageChanged(language)
listener.onScreenOnChanged(keepScreenOn)
}
if (listener is IGameSettingsChangeListener) {
listener.onVictoryPointsChanged(victoryPoints)
}
}
fun unregisterOnChangeListener(listener: ISettingsChangeListener?) {
if (listener != null) {
listenerList.remove(listener)
@@ -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<ISystemSettingsChangeListener>().forEach {
it.onLanguageChanged(language)
}
}
private fun notifyListeners(theme: Theme) {
listenerList.forEach {
listenerList.filterIsInstance<ISystemSettingsChangeListener>().forEach {
it.onThemeChanged(theme)
}
}
private fun notifyListeners(keepScreenOn: KeepScreenOn) {
listenerList.forEach {
it.onScreenOnChanged(keepScreenOn)
private fun notifyListeners(victoryPoints: VictoryPoints) {
listenerList.filterIsInstance<IGameSettingsChangeListener>().forEach {
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.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
@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(
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()) },
)
}
}

View File

@@ -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<String> =
listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long")
override val victoryPoints: Int = 1000
override fun focusLastInput() {
}

View File

@@ -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<String>
val teamNameSuggestionsB: List<String>
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<Round>())
private set
@@ -114,6 +116,9 @@ class CounterViewModel @Inject constructor(
override var teamNameSuggestionsB by mutableStateOf(listOf<String>())
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)

View File

@@ -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,22 +145,33 @@ fun BooleanSetting(name: String, value: Boolean, updateValue: (Boolean) -> Unit)
@Composable
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) }
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),
selected.toString(),
style = MaterialTheme.typography.labelLarge
)
}
}
Column(Modifier.weight(1f)) {
Icon(
@@ -142,10 +179,9 @@ fun <T> StringSetting(name: String, map: Map<T, Int>, selected: T, onSelected: (
contentDescription = null,
modifier = Modifier.align(End)
)
}
DropDownMenu(
map,
list,
selected,
expanded,
) {
@@ -153,6 +189,7 @@ fun <T> StringSetting(name: String, map: Map<T, Int>, selected: T, onSelected: (
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)
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
}
}

View File

@@ -29,5 +29,7 @@
<string name="undo_question">RÜCKGÄNGIG</string>
<string name="activated_success">Spiel aktiviert.</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>

View File

@@ -33,4 +33,7 @@
<string name="undo_question">UNDO</string>
<string name="activated_success">Game activated.</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>