From 1970210c87260b8a4454db18e9f361a7b7597ed8 Mon Sep 17 00:00:00 2001 From: meikpiep Date: Sat, 9 Nov 2024 16:41:25 +0100 Subject: [PATCH] Show the game solved dialog if the app was just started and the current grid has already been solved --- CHANGELOG.md | 2 + .../gauguin/ui/main/GameSolvedFragment.kt | 67 +++++++++++-------- .../gauguin/ui/main/GameTopFragment.kt | 2 +- .../piepmeyer/gauguin/ui/main/MainActivity.kt | 6 +- .../gauguin/ui/main/MainViewModel.kt | 21 +++--- .../kotlin/org/piepmeyer/gauguin/game/Game.kt | 25 +++---- .../gauguin/game/GameSolvedListener.kt | 2 +- 7 files changed, 71 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c15155d0..d063cff0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Show the game solved dialog if the grid shown at the start of the app has alredy been solved. + ### Deprecated ### Removed diff --git a/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/GameSolvedFragment.kt b/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/GameSolvedFragment.kt index efea6120..07f9452f 100644 --- a/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/GameSolvedFragment.kt +++ b/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/GameSolvedFragment.kt @@ -21,6 +21,7 @@ import org.piepmeyer.gauguin.game.GameLifecycle import org.piepmeyer.gauguin.preferences.StatisticsManager import org.piepmeyer.gauguin.preferences.TypeOfSolution import org.piepmeyer.gauguin.ui.statistics.StatisticsActivity +import kotlin.time.Duration.Companion.milliseconds class GameSolvedFragment : Fragment(R.layout.fragment_main_game_solved), @@ -51,8 +52,11 @@ class GameSolvedFragment : viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { when (it.state) { - MainUiState.SOLVED -> puzzleSolved(false) - MainUiState.SOLVED_BY_REVEAL -> puzzleSolved(true) + MainUiState.SOLVED, MainUiState.ALREADY_SOLVED -> { + puzzleSolved() + + binding.gameSolvedCardView.visibility = View.VISIBLE + } MainUiState.CALCULATING_NEW_GRID, MainUiState.PLAYING -> { binding.gameSolvedCardView.visibility = View.GONE } @@ -79,44 +83,51 @@ class GameSolvedFragment : } } - fun puzzleSolved(troughReveal: Boolean) { + private fun puzzleSolved() { this.context?.let { - if (!troughReveal) { - val icon = - when (statisticsManager.typeOfSolution(game.grid)) { - TypeOfSolution.FirstGame -> R.drawable.trophy_variant_outline - TypeOfSolution.FirstGameOfKind -> R.drawable.trophy_variant_outline - TypeOfSolution.BestTimeOfKind -> R.drawable.podium_gold - TypeOfSolution.Regular -> null - } + val typeOfSolution = + if (game.grid.isCheated()) { + TypeOfSolution.Regular + } else { + statisticsManager.typeOfSolution(game.grid) + } - val text = - when (statisticsManager.typeOfSolution(game.grid)) { - TypeOfSolution.FirstGame -> it.getString(R.string.puzzle_solved_type_of_solution_first_game_solved) - TypeOfSolution.FirstGameOfKind -> it.getString(R.string.puzzle_solved_type_of_solution_first_game_of_kind_solved) - TypeOfSolution.BestTimeOfKind -> it.getString(R.string.puzzle_solved_type_of_solution_best_time_of_kind_solved) - TypeOfSolution.Regular -> + val icon = + when (typeOfSolution) { + TypeOfSolution.FirstGame -> R.drawable.trophy_variant_outline + TypeOfSolution.FirstGameOfKind -> R.drawable.trophy_variant_outline + TypeOfSolution.BestTimeOfKind -> R.drawable.podium_gold + TypeOfSolution.Regular -> null + } + + val text = + when (typeOfSolution) { + TypeOfSolution.FirstGame -> it.getString(R.string.puzzle_solved_type_of_solution_first_game_solved) + TypeOfSolution.FirstGameOfKind -> it.getString(R.string.puzzle_solved_type_of_solution_first_game_of_kind_solved) + TypeOfSolution.BestTimeOfKind -> it.getString(R.string.puzzle_solved_type_of_solution_best_time_of_kind_solved) + TypeOfSolution.Regular -> { + val bestTime = statisticsManager.getBestTime(game.grid) + + if (bestTime > 0.milliseconds) { it.getString( R.string.puzzle_solved_type_of_solution_regular_display_best_time, - Utils.displayableGameDuration(statisticsManager.getBestTime(game.grid)), + Utils.displayableGameDuration(bestTime), ) + } else { + "" + } } - - if (icon != null) { - binding.detailsIcon.setImageResource(icon) - binding.detailsIcon.visibility = View.VISIBLE - } else { - binding.detailsIcon.visibility = View.INVISIBLE } - binding.detailsText.text = text - binding.detailsText.visibility = View.VISIBLE + if (icon != null) { + binding.detailsIcon.setImageResource(icon) + binding.detailsIcon.visibility = View.VISIBLE } else { binding.detailsIcon.visibility = View.INVISIBLE - binding.detailsText.visibility = View.INVISIBLE } - binding.gameSolvedCardView.visibility = View.VISIBLE + binding.detailsText.text = text + binding.detailsText.visibility = View.VISIBLE } } } diff --git a/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/GameTopFragment.kt b/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/GameTopFragment.kt index 2e399903..a7555782 100644 --- a/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/GameTopFragment.kt +++ b/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/GameTopFragment.kt @@ -96,7 +96,7 @@ class GameTopFragment : lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { - if (it.state == MainUiState.PLAYING) { + if (it.state == MainUiState.PLAYING || it.state == MainUiState.ALREADY_SOLVED) { freshGridWasCreated() } } diff --git a/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/MainActivity.kt b/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/MainActivity.kt index 14c57736..ca35756f 100644 --- a/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/MainActivity.kt +++ b/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/MainActivity.kt @@ -138,11 +138,13 @@ class MainActivity : AppCompatActivity() { binding.gridview.invalidate() } - MainUiState.SOLVED_BY_REVEAL -> bottomAppBarService.updateAppBarState() + MainUiState.ALREADY_SOLVED -> bottomAppBarService.updateAppBarState() MainUiState.SOLVED -> { bottomAppBarService.updateAppBarState() - KonfettiStarter(binding.konfettiView).startKonfetti() + if (!game.grid.isCheated()) { + KonfettiStarter(binding.konfettiView).startKonfetti() + } } } } diff --git a/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/MainViewModel.kt b/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/MainViewModel.kt index 0855c1df..92e6e605 100644 --- a/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/MainViewModel.kt +++ b/gauguin-app/src/main/kotlin/org/piepmeyer/gauguin/ui/main/MainViewModel.kt @@ -18,7 +18,7 @@ enum class MainUiState { PLAYING, CALCULATING_NEW_GRID, SOLVED, - SOLVED_BY_REVEAL, + ALREADY_SOLVED, } data class MainUiStateWithGrid( @@ -45,7 +45,7 @@ class MainViewModel : private val calculationService: GridCalculationService by inject() private val game: Game by inject() - private val _uiState = MutableStateFlow(MainUiStateWithGrid(MainUiState.PLAYING, game.grid)) + private val _uiState = MutableStateFlow(initialUiState()) private val _nextGridState = MutableStateFlow(NextGridState.CALCULATED) private val _fastFinishingModeState = MutableStateFlow(FastFinishingModeState.INACTIVE) @@ -89,13 +89,18 @@ class MainViewModel : _uiState.value = MainUiStateWithGrid(MainUiState.PLAYING, game.grid) } - override fun puzzleSolved(troughReveal: Boolean) { - _uiState.value = - if (troughReveal) { - MainUiStateWithGrid(MainUiState.SOLVED_BY_REVEAL, game.grid) + private fun initialUiState() = + MainUiStateWithGrid( + if (game.grid.isSolved()) { + MainUiState.ALREADY_SOLVED } else { - MainUiStateWithGrid(MainUiState.SOLVED, game.grid) - } + MainUiState.PLAYING + }, + game.grid, + ) + + override fun puzzleSolved() { + _uiState.value = MainUiStateWithGrid(MainUiState.SOLVED, game.grid) } override fun changedGameMode() { diff --git a/gauguin-core/src/main/kotlin/org/piepmeyer/gauguin/game/Game.kt b/gauguin-core/src/main/kotlin/org/piepmeyer/gauguin/game/Game.kt index 2d4444f6..8100bc3d 100644 --- a/gauguin-core/src/main/kotlin/org/piepmeyer/gauguin/game/Game.kt +++ b/gauguin-core/src/main/kotlin/org/piepmeyer/gauguin/game/Game.kt @@ -66,21 +66,16 @@ data class Game( logger.info { "Updated grid to: ${grid.detailedToString()}" } } - fun enterNumber( - number: Int, - reveal: Boolean = false, - ) { + fun enterNumber(number: Int) { val selectedCell = grid.selectedCell ?: return - if (!grid.isActive || selectedCell.isCheated) { + if (!grid.isActive) { return } gridHasBeenPlayed() clearLastModified() - if (!reveal) { - undoManager.saveUndo(selectedCell, false) - } + undoManager.saveUndo(selectedCell, false) selectedCell.setUserValueExtern(number) if (applicationPreferences.removePencils()) { @@ -93,15 +88,17 @@ data class Game( ensureNotInFastFinishingMode() - if (!reveal) { + val cheated = grid.isCheated() + + if (!cheated) { statisticsManager.puzzleSolved(grid) statisticsManager.storeStatisticsAfterFinishedGame(grid) } - statisticsManager.storeStreak(!reveal) + statisticsManager.storeStreak(!cheated) - vipSolvedListeners.forEach { it.puzzleSolved(reveal) } - solvedListeners.forEach { it.puzzleSolved(reveal) } + vipSolvedListeners.forEach { it.puzzleSolved() } + solvedListeners.forEach { it.puzzleSolved() } } grid.userValueChanged() @@ -112,9 +109,9 @@ data class Game( fun revealCell(cell: GridCell) { if (!cell.isUserValueCorrect) { - selectCell(cell) - enterNumber(cell.value, reveal = true) cell.isCheated = true + selectCell(cell) + enterNumber(cell.value) } } diff --git a/gauguin-core/src/main/kotlin/org/piepmeyer/gauguin/game/GameSolvedListener.kt b/gauguin-core/src/main/kotlin/org/piepmeyer/gauguin/game/GameSolvedListener.kt index f44aba1d..c806a968 100644 --- a/gauguin-core/src/main/kotlin/org/piepmeyer/gauguin/game/GameSolvedListener.kt +++ b/gauguin-core/src/main/kotlin/org/piepmeyer/gauguin/game/GameSolvedListener.kt @@ -1,5 +1,5 @@ package org.piepmeyer.gauguin.game fun interface GameSolvedListener { - fun puzzleSolved(troughReveal: Boolean) + fun puzzleSolved() }