Settings as state flow.

This commit is contained in:
2023-09-08 18:20:56 +02:00
parent 6a96749501
commit 27cb2f670b
4 changed files with 73 additions and 120 deletions

View File

@@ -34,6 +34,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@@ -44,7 +45,6 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.domain.DrawerItem
import me.zobrist.tichucounter.domain.ISystemSettingsChangeListener
import me.zobrist.tichucounter.domain.KeepScreenOn
import me.zobrist.tichucounter.domain.Language
import me.zobrist.tichucounter.domain.ReviewService
@@ -69,7 +69,7 @@ import me.zobrist.tichucounter.ui.settings.SettingsViewModel
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : AppCompatActivity(), ISystemSettingsChangeListener {
class MainActivity : AppCompatActivity() {
@Inject
lateinit var settingsAdapter: SettingsAdapter
@@ -86,7 +86,26 @@ class MainActivity : AppCompatActivity(), ISystemSettingsChangeListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
settingsAdapter.registerOnChangeListener(this)
changeTheme(settingsAdapter.theme.value)
setKeepScreenOn(settingsAdapter.keepScreenOn.value)
changeLanguage(settingsAdapter.language.value)
lifecycleScope.launch {
settingsAdapter.theme.collect {
changeTheme(it)
}
}
lifecycleScope.launch {
settingsAdapter.keepScreenOn.collect {
setKeepScreenOn(it)
}
}
lifecycleScope.launch {
settingsAdapter.language.collect {
changeLanguage(it)
}
}
mainViewModel.onNewGame = {
reviewService.request()
@@ -101,16 +120,11 @@ class MainActivity : AppCompatActivity(), ISystemSettingsChangeListener {
}
}
override fun onDestroy() {
super.onDestroy()
settingsAdapter.unregisterOnChangeListener(this)
}
override fun onLanguageChanged(language: Language) {
private fun changeLanguage(language: Language) {
AppCompatDelegate.setApplicationLocales(language.value)
}
override fun onThemeChanged(theme: Theme) {
private fun changeTheme(theme: Theme) {
val themeValue = when (theme) {
Theme.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
Theme.DARK -> AppCompatDelegate.MODE_NIGHT_YES
@@ -119,7 +133,7 @@ class MainActivity : AppCompatActivity(), ISystemSettingsChangeListener {
AppCompatDelegate.setDefaultNightMode(themeValue)
}
override fun onScreenOnChanged(keepOn: KeepScreenOn) {
private fun setKeepScreenOn(keepOn: KeepScreenOn) {
if (keepOn.value) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {

View File

@@ -4,6 +4,10 @@ import android.content.Context
import androidx.core.os.LocaleListCompat
import androidx.preference.PreferenceManager
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
@@ -18,99 +22,64 @@ enum class KeepScreenOn(val value: Boolean) { ON(true), OFF(false) }
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) {
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
private var listenerList = mutableListOf<ISettingsChangeListener>()
var language: Language
private set
val language = MutableStateFlow(Language.DEFAULT)
var theme: Theme
private set
val theme = MutableStateFlow(Theme.DEFAULT)
var keepScreenOn: KeepScreenOn
private set
val keepScreenOn = MutableStateFlow(KeepScreenOn.OFF)
var victoryPoints: Int
private set
val victoryPoints = MutableStateFlow(0)
init {
language = try {
language.value = try {
enumValueOf(sharedPreferences.getString(Language::class.simpleName, null)!!)
} catch (_: NullPointerException) {
Language.DEFAULT
}
theme = try {
theme.value = try {
enumValueOf(sharedPreferences.getString(Theme::class.simpleName, null)!!)
} catch (_: java.lang.Exception) {
Theme.DEFAULT
}
keepScreenOn = try {
keepScreenOn.value = try {
enumValueOf(sharedPreferences.getString(KeepScreenOn::class.simpleName, null)!!)
} catch (_: java.lang.Exception) {
KeepScreenOn.OFF
}
victoryPoints = sharedPreferences.getInt(VictoryPoints::class.simpleName, 1000)
}
victoryPoints.value = 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)
CoroutineScope(Dispatchers.IO).launch {
language.collect {
updatePreference(Language::class.simpleName, it.name)
}
}
if (listener is IGameSettingsChangeListener) {
listener.onVictoryPointsChanged(victoryPoints)
CoroutineScope(Dispatchers.IO).launch {
theme.collect {
updatePreference(Theme::class.simpleName, it.name)
}
}
}
fun unregisterOnChangeListener(listener: ISettingsChangeListener?) {
if (listener != null) {
listenerList.remove(listener)
CoroutineScope(Dispatchers.IO).launch {
keepScreenOn.collect {
updatePreference(KeepScreenOn::class.simpleName, it.name)
}
}
}
fun setLanguage(language: Language) {
this.language = language
updatePreference(Language::class.simpleName, language.name)
notifyListeners(language)
}
fun setTheme(theme: Theme) {
this.theme = theme
updatePreference(Theme::class.simpleName, theme.name)
notifyListeners(theme)
}
fun setKeepScreenOn(setting: KeepScreenOn) {
this.keepScreenOn = setting
updatePreference(KeepScreenOn::class.simpleName, setting.name)
notifyListeners(setting)
}
fun setVictoryPoints(setting: Int) {
this.victoryPoints = setting
updatePreference(VictoryPoints::class.simpleName, setting)
notifyListeners(setting)
CoroutineScope(Dispatchers.IO).launch {
victoryPoints.collect {
updatePreference(VictoryPoints::class.simpleName, it)
}
}
}
private fun updatePreference(name: String?, value: String) {
@@ -130,28 +99,4 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
editor.putInt(name, value)
editor.apply()
}
private fun notifyListeners(language: Language) {
listenerList.filterIsInstance<ISystemSettingsChangeListener>().forEach {
it.onLanguageChanged(language)
}
}
private fun notifyListeners(theme: Theme) {
listenerList.filterIsInstance<ISystemSettingsChangeListener>().forEach {
it.onThemeChanged(theme)
}
}
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

@@ -13,7 +13,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.entity.Game
import me.zobrist.tichucounter.data.entity.Round
import me.zobrist.tichucounter.domain.IGameSettingsChangeListener
import me.zobrist.tichucounter.domain.SettingsAdapter
import me.zobrist.tichucounter.domain.Tichu
import me.zobrist.tichucounter.domain.digitCount
@@ -73,7 +72,7 @@ class CounterViewModel @Inject constructor(
private val gameRepository: GameRepository,
private val settings: SettingsAdapter
) :
ViewModel(), ICounterViewModel, IGameSettingsChangeListener {
ViewModel(), ICounterViewModel {
override var roundScoreList by mutableStateOf(emptyList<Round>())
private set
@@ -188,7 +187,7 @@ class CounterViewModel @Inject constructor(
}
if (!victoryDialogShown) {
if (totalScoreA >= settings.victoryPoints || totalScoreB >= settings.victoryPoints) {
if (totalScoreA >= settings.victoryPoints.value || totalScoreB >= settings.victoryPoints.value) {
showVictoryDialog = true
}
}
@@ -202,13 +201,11 @@ class CounterViewModel @Inject constructor(
buildTeamNameSuggestions()
}
settings.victoryPoints.collect {
victoryDialogShown = false
}
}
settings.registerOnChangeListener(this)
}
override fun onCleared() {
settings.unregisterOnChangeListener(this)
}
override fun focusLastInput() {
@@ -401,8 +398,4 @@ class CounterViewModel @Inject constructor(
return filtered.sorted().sortedBy { it.length }.take(10)
}
override fun onVictoryPointsChanged(victoryPoints: Int) {
victoryDialogShown = false
}
}

View File

@@ -1,6 +1,7 @@
package me.zobrist.tichucounter.ui.settings
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
@@ -15,35 +16,35 @@ import javax.inject.Inject
class SettingsViewModel @Inject constructor(private val settings: SettingsAdapter) : ViewModel() {
var language by mutableStateOf(settings.language)
var language by mutableStateOf(settings.language.value)
private set
var theme by mutableStateOf(settings.theme)
var theme by mutableStateOf(settings.theme.value)
private set
var screenOn by mutableStateOf(settings.keepScreenOn)
var screenOn by mutableStateOf(settings.keepScreenOn.value)
private set
var victoryPoints by mutableStateOf(settings.victoryPoints)
var victoryPoints by mutableIntStateOf(settings.victoryPoints.value)
private set
fun updateLanguage(language: Language) {
settings.setLanguage(language)
this.language = settings.language
settings.language.value = language
this.language = language
}
fun updateTheme(theme: Theme) {
settings.setTheme(theme)
this.theme = settings.theme
settings.theme.value = theme
this.theme = theme
}
fun updateScreenOn(value: KeepScreenOn) {
settings.setKeepScreenOn(value)
screenOn = settings.keepScreenOn
settings.keepScreenOn.value = value
screenOn = value
}
fun updateVictoryPoints(value: Int) {
settings.setVictoryPoints(value)
victoryPoints = settings.victoryPoints
settings.victoryPoints.value = value
victoryPoints = value
}
}