From 2599e3320a28f5813a94e3f2fde755e8b7ed248a Mon Sep 17 00:00:00 2001 From: Fabian Zobrist Date: Sat, 26 Aug 2023 15:20:43 +0200 Subject: [PATCH] Add alerts for winning and draw. --- .../me/zobrist/tichucounter/MainActivity.kt | 3 +- .../tichucounter/domain/ReviewService.kt | 18 +---- .../tichucounter/domain/SettingsAdapter.kt | 1 - .../zobrist/tichucounter/ui/MainViewModel.kt | 2 - .../tichucounter/ui/counter/CounterView.kt | 73 ++++++++++++++++++- .../ui/counter/CounterViewModel.kt | 53 ++++++++++---- app/src/main/res/values-de/strings.xml | 6 +- app/src/main/res/values/strings.xml | 8 +- 8 files changed, 127 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt b/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt index 1f62ef8..ca5b423 100644 --- a/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt +++ b/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt @@ -40,7 +40,6 @@ 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 @@ -230,7 +229,7 @@ class MainActivity : AppCompatActivity(), ISystemSettingsChangeListener { mainViewModel.activeGameHasRounds, { expanded = true } ) { - val newGameTranslated = stringResource(R.string.newGame) + val newGameTranslated = stringResource(R.string.new_game) DropDownMenu( listOf(newGameTranslated), "", diff --git a/app/src/main/java/me/zobrist/tichucounter/domain/ReviewService.kt b/app/src/main/java/me/zobrist/tichucounter/domain/ReviewService.kt index 63a1507..bc2c806 100644 --- a/app/src/main/java/me/zobrist/tichucounter/domain/ReviewService.kt +++ b/app/src/main/java/me/zobrist/tichucounter/domain/ReviewService.kt @@ -2,27 +2,17 @@ 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) { private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(appContext) - private val THREE_MONTHS : Long = 7776000000 + private val THREE_MONTHS: Long = 7776000000 private var requestCalled: Int get() = sharedPreferences.getInt("requestCalled", 0) @@ -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) 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 52862d0..e011f75 100644 --- a/app/src/main/java/me/zobrist/tichucounter/domain/SettingsAdapter.kt +++ b/app/src/main/java/me/zobrist/tichucounter/domain/SettingsAdapter.kt @@ -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 diff --git a/app/src/main/java/me/zobrist/tichucounter/ui/MainViewModel.kt b/app/src/main/java/me/zobrist/tichucounter/ui/MainViewModel.kt index 022f07b..db9d2b4 100644 --- a/app/src/main/java/me/zobrist/tichucounter/ui/MainViewModel.kt +++ b/app/src/main/java/me/zobrist/tichucounter/ui/MainViewModel.kt @@ -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 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 e9d7da3..1c6c68d 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 @@ -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 = listOf(Round(1, 10, 90), Round(1, 50, 50), Round(1, 70, 30)) @@ -123,7 +191,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 var showVictoryDialog: Boolean = false override fun focusLastInput() { } @@ -156,6 +224,9 @@ internal class PreviewViewModel : ICounterViewModel { override fun updateNameB(value: String) { } + override fun victoryDialogExecuted(result: Boolean) { + } + override fun updateFocusStateA(state: Boolean) { } 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 4439cf5..e56330f 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 @@ -11,8 +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 @@ -59,15 +61,17 @@ interface ICounterViewModel : IKeyBoardViewModel { val teamNameB: String val teamNameSuggestionsA: List val teamNameSuggestionsB: List - val victoryPoints: Int + 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, IGameSettingsChangeListener { @@ -115,8 +119,7 @@ class CounterViewModel @Inject constructor( override var teamNameSuggestionsB by mutableStateOf(listOf()) private set - - override var victoryPoints by mutableStateOf(0) + override var showVictoryDialog by mutableStateOf(false) private set override var activeValue: String @@ -160,11 +163,14 @@ class CounterViewModel @Inject constructor( private var distinctTeamNames = listOf() + 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 @@ -176,12 +182,16 @@ class CounterViewModel @Inject constructor( buildTeamNameSuggestions() - if (totalScoreA >= victoryPoints || totalScoreB >= victoryPoints) { - if (totalScoreA == totalScoreB) { - - } + if (it.game.uid != lastGame?.uid) { + victoryDialogShown = false + lastGame = it.game } + if (!victoryDialogShown) { + if (totalScoreA >= settings.victoryPoints || totalScoreB >= settings.victoryPoints) { + showVictoryDialog = true + } + } } } } @@ -193,6 +203,12 @@ class CounterViewModel @Inject constructor( buildTeamNameSuggestions() } } + + settings.registerOnChangeListener(this) + } + + override fun onCleared() { + settings.unregisterOnChangeListener(this) } override fun focusLastInput() { @@ -301,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) { @@ -341,10 +368,6 @@ class CounterViewModel @Inject constructor( } } - override fun onVictoryPointsChanged(victoryPoints: Int) { - this.victoryPoints = victoryPoints - } - private fun deleteLastDigitActive() { if (activeValue != "") { activeValue = activeValue.dropLast(1) @@ -378,4 +401,8 @@ class CounterViewModel @Inject constructor( return filtered.sorted().sortedBy { it.length }.take(10) } + + override fun onVictoryPointsChanged(victoryPoints: Int) { + victoryDialogShown = false + } } \ 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 82c3530..be1fb4e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -12,7 +12,7 @@ Einstellungen Ein Aus - Neues Spiel + Neues Spiel Verlauf löschen Wirklich den gesamten Verlauf löschen? Diese Aktion kann nicht rückgängig gemacht werden. Abbrechen @@ -32,4 +32,8 @@ Anzeige Spiel Siegespunkte + %1$s hat gewonnen + Sieht aus, als ob ihr ein neues Spiel starten solltet, um das endgültig zu klären. + Unentschieden + Herzliche Gratulation! Wie wäre es mit einer Revanche? \ 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 ff61cf2..f477b30 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,7 +15,7 @@ Settings On Off - New Game + New Game Delete history You really want to delete the history? This action can\'t be undone. Cancel @@ -28,7 +28,7 @@ About Contact us Play Store - Continue + Continue game Game deleted. UNDO Game activated. @@ -36,4 +36,8 @@ Display Game Victory points + %1$s won the game + Looks like you should start a new game to settle this for good. + Draw + Congratulations! How about a rematch? \ No newline at end of file