Merge pull request 'feature/winning-points' (#50) from feature/winning-points into develop
All checks were successful
Build Android / build (push) Successful in 8m16s
All checks were successful
Build Android / build (push) Successful in 8m16s
Reviewed-on: #50
This commit was merged in pull request #50.
This commit is contained in:
@@ -40,12 +40,11 @@ import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import com.google.android.play.core.review.ReviewManager
|
||||
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 +69,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 +191,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 +209,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 +229,16 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
|
||||
mainViewModel.activeGameHasRounds,
|
||||
{ expanded = true }
|
||||
) {
|
||||
val newGameTranslated = stringResource(R.string.new_game)
|
||||
DropDownMenu(
|
||||
mapOf("new" to R.string.newGame),
|
||||
listOf(newGameTranslated),
|
||||
"",
|
||||
expanded,
|
||||
) {
|
||||
expanded = false
|
||||
it?.let {
|
||||
when (it) {
|
||||
"new" -> mainViewModel.newGame()
|
||||
newGameTranslated -> mainViewModel.newGame()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,11 @@ package me.zobrist.tichucounter.domain
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.play.core.review.ReviewManagerFactory
|
||||
import com.google.android.play.core.review.testing.FakeReviewManager
|
||||
import dagger.hilt.android.internal.Contexts
|
||||
import dagger.hilt.android.qualifiers.ActivityContext
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
import dagger.hilt.android.scopes.FragmentScoped
|
||||
import dagger.hilt.android.scopes.ViewScoped
|
||||
import java.time.Duration
|
||||
import java.time.Period
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
class ReviewService @Inject constructor(@ActivityContext private val appContext: Context) {
|
||||
|
||||
@@ -43,10 +33,8 @@ class ReviewService @Inject constructor(@ActivityContext private val appContext:
|
||||
fun request() {
|
||||
requestCalled += 1
|
||||
|
||||
if(requestCalled >= 3)
|
||||
{
|
||||
if(nextReviewedDate.time < System.currentTimeMillis())
|
||||
{
|
||||
if (requestCalled >= 3) {
|
||||
if (nextReviewedDate.time < System.currentTimeMillis()) {
|
||||
requestCalled = 0
|
||||
nextReviewedDate = Date(System.currentTimeMillis() + THREE_MONTHS)
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.Context
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@@ -17,12 +16,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 +43,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 +65,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 +107,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 +125,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,8 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
import kotlinx.coroutines.launch
|
||||
import me.zobrist.tichucounter.data.entity.Round
|
||||
import me.zobrist.tichucounter.domain.ReviewService
|
||||
import me.zobrist.tichucounter.repository.GameRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@@ -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()) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,13 @@ package me.zobrist.tichucounter.ui.counter
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.EmojiEvents
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -12,7 +18,9 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import me.zobrist.tichucounter.R
|
||||
import me.zobrist.tichucounter.data.entity.Round
|
||||
import me.zobrist.tichucounter.ui.AppTheme
|
||||
|
||||
@@ -23,6 +31,18 @@ fun Counter(viewModel: ICounterViewModel = PreviewViewModel()) {
|
||||
var orientation by remember { mutableStateOf(Configuration.ORIENTATION_PORTRAIT) }
|
||||
orientation = LocalConfiguration.current.orientation
|
||||
|
||||
if (viewModel.showVictoryDialog) {
|
||||
GameVictoryDialog(
|
||||
viewModel.totalScoreA,
|
||||
viewModel.totalScoreB,
|
||||
viewModel.teamNameA,
|
||||
viewModel.teamNameB,
|
||||
{ viewModel.victoryDialogExecuted(false) })
|
||||
{
|
||||
viewModel.victoryDialogExecuted(true)
|
||||
}
|
||||
}
|
||||
|
||||
Surface {
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
Landscape(viewModel)
|
||||
@@ -102,6 +122,54 @@ fun CounterViewPreview() {
|
||||
}
|
||||
}
|
||||
|
||||
@Preview()
|
||||
@Composable
|
||||
fun GameVictoryDialog(
|
||||
pointsA: Int = 2000,
|
||||
pointsB: Int = 50,
|
||||
nameA: String = "nameA",
|
||||
nameB: String = "nameB",
|
||||
onDismiss: () -> Unit = {},
|
||||
onNewGame: () -> Unit = {},
|
||||
) {
|
||||
|
||||
val winner = if (pointsA > pointsB) {
|
||||
nameA
|
||||
} else {
|
||||
nameB
|
||||
}
|
||||
|
||||
val message = if (pointsA == pointsB) {
|
||||
stringResource(R.string.draw_message, winner, 100)
|
||||
} else {
|
||||
stringResource(R.string.victory_message)
|
||||
}
|
||||
|
||||
val title = if (pointsA == pointsB) {
|
||||
stringResource(R.string.draw_title)
|
||||
} else {
|
||||
stringResource(R.string.victory_title, winner)
|
||||
}
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = { onDismiss() },
|
||||
dismissButton = {
|
||||
TextButton({ onDismiss() }) {
|
||||
Text(stringResource(R.string.continue_play))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton({ onNewGame() }) {
|
||||
Text(stringResource(R.string.new_game))
|
||||
}
|
||||
},
|
||||
icon = { Icon(Icons.Outlined.EmojiEvents, null) },
|
||||
title = { Text(title) },
|
||||
text = { Text(message) }
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
internal class PreviewViewModel : ICounterViewModel {
|
||||
override var roundScoreList: List<Round> =
|
||||
listOf(Round(1, 10, 90), Round(1, 50, 50), Round(1, 70, 30))
|
||||
@@ -123,6 +191,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 var showVictoryDialog: Boolean = false
|
||||
|
||||
override fun focusLastInput() {
|
||||
}
|
||||
@@ -155,6 +224,9 @@ internal class PreviewViewModel : ICounterViewModel {
|
||||
override fun updateNameB(value: String) {
|
||||
}
|
||||
|
||||
override fun victoryDialogExecuted(result: Boolean) {
|
||||
}
|
||||
|
||||
override fun updateFocusStateA(state: Boolean) {
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Job
|
||||
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
|
||||
import me.zobrist.tichucounter.domain.getTotalPoints
|
||||
@@ -58,16 +61,19 @@ interface ICounterViewModel : IKeyBoardViewModel {
|
||||
val teamNameB: String
|
||||
val teamNameSuggestionsA: List<String>
|
||||
val teamNameSuggestionsB: List<String>
|
||||
val showVictoryDialog: Boolean
|
||||
|
||||
fun updateNameA(value: String)
|
||||
fun updateNameB(value: String)
|
||||
fun victoryDialogExecuted(result: Boolean)
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
class CounterViewModel @Inject constructor(
|
||||
private val gameRepository: GameRepository
|
||||
private val gameRepository: GameRepository,
|
||||
private val settings: SettingsAdapter
|
||||
) :
|
||||
ViewModel(), ICounterViewModel {
|
||||
ViewModel(), ICounterViewModel, IGameSettingsChangeListener {
|
||||
|
||||
override var roundScoreList by mutableStateOf(emptyList<Round>())
|
||||
private set
|
||||
@@ -113,6 +119,8 @@ class CounterViewModel @Inject constructor(
|
||||
|
||||
override var teamNameSuggestionsB by mutableStateOf(listOf<String>())
|
||||
private set
|
||||
override var showVictoryDialog by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
override var activeValue: String
|
||||
get() {
|
||||
@@ -155,11 +163,14 @@ class CounterViewModel @Inject constructor(
|
||||
|
||||
private var distinctTeamNames = listOf<String>()
|
||||
|
||||
private var victoryDialogShown = false
|
||||
|
||||
private var lastGame: Game? = null
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
gameRepository.getActiveGameFlow().collect {
|
||||
if (it != null) {
|
||||
|
||||
val score = it.getTotalPoints()
|
||||
|
||||
roundScoreList = it.rounds
|
||||
@@ -171,6 +182,16 @@ class CounterViewModel @Inject constructor(
|
||||
|
||||
buildTeamNameSuggestions()
|
||||
|
||||
if (it.game.uid != lastGame?.uid) {
|
||||
victoryDialogShown = false
|
||||
lastGame = it.game
|
||||
}
|
||||
|
||||
if (!victoryDialogShown) {
|
||||
if (totalScoreA >= settings.victoryPoints || totalScoreB >= settings.victoryPoints) {
|
||||
showVictoryDialog = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,6 +203,12 @@ class CounterViewModel @Inject constructor(
|
||||
buildTeamNameSuggestions()
|
||||
}
|
||||
}
|
||||
|
||||
settings.registerOnChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
settings.unregisterOnChangeListener(this)
|
||||
}
|
||||
|
||||
override fun focusLastInput() {
|
||||
@@ -290,6 +317,17 @@ class CounterViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun victoryDialogExecuted(result: Boolean) {
|
||||
showVictoryDialog = false
|
||||
victoryDialogShown = true
|
||||
|
||||
if (result) {
|
||||
viewModelScope.launch {
|
||||
gameRepository.newGame()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateFocusStateA(state: Boolean) {
|
||||
isAFocused = state
|
||||
if (state) {
|
||||
@@ -363,4 +401,8 @@ class CounterViewModel @Inject constructor(
|
||||
|
||||
return filtered.sorted().sortedBy { it.length }.take(10)
|
||||
}
|
||||
|
||||
override fun onVictoryPointsChanged(victoryPoints: Int) {
|
||||
victoryDialogShown = false
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
) {
|
||||
@@ -154,6 +190,7 @@ fun <T> StringSetting(name: String, map: Map<T, Int>, selected: T, onSelected: (
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview(name = "Light Mode")
|
||||
@@ -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,
|
||||
) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
<string name="menu_settings">Einstellungen</string>
|
||||
<string name="on">Ein</string>
|
||||
<string name="off">Aus</string>
|
||||
<string name="newGame">Neues Spiel</string>
|
||||
<string name="new_game">Neues Spiel</string>
|
||||
<string name="delete_inactive_title">Verlauf löschen</string>
|
||||
<string name="delete_inactive_text">Wirklich den gesamten Verlauf löschen? Diese Aktion kann nicht rückgängig gemacht werden.</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
@@ -29,5 +29,11 @@
|
||||
<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>
|
||||
<string name="victory_title">%1$s hat gewonnen</string>
|
||||
<string name="draw_message">Sieht aus, als ob ihr ein neues Spiel starten solltet, um das endgültig zu klären.</string>
|
||||
<string name="draw_title">Unentschieden</string>
|
||||
<string name="victory_message">Herzliche Gratulation! Wie wäre es mit einer Revanche?</string>
|
||||
</resources>
|
||||
@@ -15,7 +15,7 @@
|
||||
<string name="menu_settings">Settings</string>
|
||||
<string name="on">On</string>
|
||||
<string name="off">Off</string>
|
||||
<string name="newGame">New Game</string>
|
||||
<string name="new_game">New Game</string>
|
||||
<string name="delete_inactive_title">Delete history</string>
|
||||
<string name="delete_inactive_text">You really want to delete the history? This action can\'t be undone.</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
@@ -28,9 +28,16 @@
|
||||
<string name="menu_about">About</string>
|
||||
<string name="contact_us">Contact us</string>
|
||||
<string name="play_store" translatable="false">Play Store</string>
|
||||
<string name="continue_play">Continue</string>
|
||||
<string name="continue_play">Continue game</string>
|
||||
<string name="delete_success">Game deleted.</string>
|
||||
<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>
|
||||
<string name="victory_title">%1$s won the game</string>
|
||||
<string name="draw_message">Looks like you should start a new game to settle this for good.</string>
|
||||
<string name="draw_title">Draw</string>
|
||||
<string name="victory_message">Congratulations! How about a rematch?</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user