diff --git a/app/src/main/java/com/accidentalproductions/tetristats/data/ScalingFactors.kt b/app/src/main/java/com/accidentalproductions/tetristats/data/ScalingFactors.kt index 93030f2..e272e19 100644 --- a/app/src/main/java/com/accidentalproductions/tetristats/data/ScalingFactors.kt +++ b/app/src/main/java/com/accidentalproductions/tetristats/data/ScalingFactors.kt @@ -16,7 +16,9 @@ object ScalingFactors { "Tetris DS" to RangeScalingFactor(3.0, 3.3, 4.5), "Tetris Effect" to RangeScalingFactor(2.5, 3.8, 4.5), "Rosy Retrospection DX" to RangeScalingFactor(4.0, 1.5, 1.8), - "Apotris" to RangeScalingFactor(1.8, 3.8, 4.4) + "Apotris" to RangeScalingFactor(1.8, 3.8, 4.4), + "Modretro Tetris" to RangeScalingFactor(2.0, 2.5, 3.0), + "Tetris Mobile" to RangeScalingFactor(2.2, 2.8, 3.5) ), "Game Boy Tetris" to mapOf( "NES Tetris" to 1.33, @@ -24,7 +26,9 @@ object ScalingFactors { "Tetris DS" to RangeScalingFactor(4.0, 2.0, 2.0), "Tetris Effect" to RangeScalingFactor(4.0, 2.3, 2.3), "Rosy Retrospection DX" to 1.1, - "Apotris" to RangeScalingFactor(1.33, 1.33, 2.33) + "Apotris" to RangeScalingFactor(1.33, 1.33, 2.33), + "Modretro Tetris" to RangeScalingFactor(1.5, 1.8, 2.0), + "Tetris Mobile" to RangeScalingFactor(1.6, 1.9, 2.1) ), "Tetris DX" to mapOf( "NES Tetris" to 1.33, @@ -32,7 +36,9 @@ object ScalingFactors { "Tetris DS" to RangeScalingFactor(4.0, 2.0, 2.0), "Tetris Effect" to RangeScalingFactor(4.0, 2.3, 2.3), "Rosy Retrospection DX" to 1.1, - "Apotris" to RangeScalingFactor(1.33, 1.33, 2.33) + "Apotris" to RangeScalingFactor(1.33, 1.33, 2.33), + "Modretro Tetris" to RangeScalingFactor(1.5, 1.8, 2.0), + "Tetris Mobile" to RangeScalingFactor(1.6, 1.9, 2.1) ), "Tetris DS" to mapOf( "NES Tetris" to RangeScalingFactor(0.33, 0.3, 0.22), @@ -40,7 +46,9 @@ object ScalingFactors { "Tetris DX" to RangeScalingFactor(0.25, 0.5, 0.5), "Tetris Effect" to RangeScalingFactor(0.83, 0.91, 1.0), "Rosy Retrospection DX" to RangeScalingFactor(0.25, 0.91, 0.67), - "Apotris" to RangeScalingFactor(0.33, 0.67, 0.9) + "Apotris" to RangeScalingFactor(0.33, 0.67, 0.9), + "Modretro Tetris" to RangeScalingFactor(0.4, 0.5, 0.6), + "Tetris Mobile" to RangeScalingFactor(0.45, 0.55, 0.65) ), "Tetris Effect" to mapOf( "NES Tetris" to RangeScalingFactor(0.4, 0.26, 0.22), @@ -48,7 +56,9 @@ object ScalingFactors { "Tetris DX" to RangeScalingFactor(0.25, 0.43, 0.43), "Tetris DS" to RangeScalingFactor(1.2, 1.1, 1.0), "Rosy Retrospection DX" to RangeScalingFactor(0.25, 0.43, 0.57), - "Apotris" to RangeScalingFactor(0.33, 0.67, 0.85) + "Apotris" to RangeScalingFactor(0.33, 0.67, 0.85), + "Modretro Tetris" to RangeScalingFactor(0.45, 0.55, 0.65), + "Tetris Mobile" to RangeScalingFactor(0.5, 0.6, 0.7) ), "Rosy Retrospection DX" to mapOf( "NES Tetris" to RangeScalingFactor(0.25, 0.67, 0.57), @@ -56,7 +66,9 @@ object ScalingFactors { "Tetris DX" to 0.91, "Tetris DS" to RangeScalingFactor(4.0, 1.5, 1.8), "Tetris Effect" to RangeScalingFactor(4.0, 2.3, 1.8), - "Apotris" to RangeScalingFactor(1.1, 0.67, 0.5) + "Apotris" to RangeScalingFactor(1.1, 0.67, 0.5), + "Modretro Tetris" to RangeScalingFactor(1.3, 1.5, 1.7), + "Tetris Mobile" to RangeScalingFactor(1.4, 1.6, 1.8) ), "Apotris" to mapOf( "NES Tetris" to RangeScalingFactor(0.56, 0.26, 0.23), @@ -64,7 +76,29 @@ object ScalingFactors { "Tetris DX" to RangeScalingFactor(0.75, 0.75, 0.5), "Tetris DS" to RangeScalingFactor(3.0, 1.5, 1.0), "Tetris Effect" to RangeScalingFactor(3.0, 1.7, 1.2), - "Rosy Retrospection DX" to RangeScalingFactor(1.1, 0.67, 0.5) + "Rosy Retrospection DX" to RangeScalingFactor(1.1, 0.67, 0.5), + "Modretro Tetris" to RangeScalingFactor(1.2, 0.9, 0.7), + "Tetris Mobile" to RangeScalingFactor(1.3, 1.0, 0.8) + ), + "Modretro Tetris" to mapOf( + "NES Tetris" to RangeScalingFactor(0.5, 0.4, 0.33), + "Game Boy Tetris" to RangeScalingFactor(0.67, 0.56, 0.5), + "Tetris DX" to RangeScalingFactor(0.67, 0.56, 0.5), + "Tetris DS" to RangeScalingFactor(2.5, 2.0, 1.67), + "Tetris Effect" to RangeScalingFactor(2.22, 1.82, 1.54), + "Rosy Retrospection DX" to RangeScalingFactor(0.77, 0.67, 0.59), + "Apotris" to RangeScalingFactor(0.83, 1.11, 1.43), + "Tetris Mobile" to RangeScalingFactor(1.1, 1.1, 1.1) + ), + "Tetris Mobile" to mapOf( + "NES Tetris" to RangeScalingFactor(0.45, 0.36, 0.29), + "Game Boy Tetris" to RangeScalingFactor(0.63, 0.53, 0.48), + "Tetris DX" to RangeScalingFactor(0.63, 0.53, 0.48), + "Tetris DS" to RangeScalingFactor(2.22, 1.82, 1.54), + "Tetris Effect" to RangeScalingFactor(2.0, 1.67, 1.43), + "Rosy Retrospection DX" to RangeScalingFactor(0.71, 0.63, 0.56), + "Apotris" to RangeScalingFactor(0.77, 1.0, 1.25), + "Modretro Tetris" to RangeScalingFactor(0.91, 0.91, 0.91) ) ) diff --git a/app/src/main/java/com/accidentalproductions/tetristats/ui/entry/EntryFragment.kt b/app/src/main/java/com/accidentalproductions/tetristats/ui/entry/EntryFragment.kt index 8c73b79..deb4109 100644 --- a/app/src/main/java/com/accidentalproductions/tetristats/ui/entry/EntryFragment.kt +++ b/app/src/main/java/com/accidentalproductions/tetristats/ui/entry/EntryFragment.kt @@ -56,6 +56,50 @@ class EntryFragment : Fragment() { if (game != null && score != null) { viewModel.refreshEquivalentScores(game, score) + + // Make sure UI updates immediately by forcing an adapter refresh + viewModel.equivalentScores.value?.let { scores -> + equivalentScoreAdapter.submitList(null) // Clear first + equivalentScoreAdapter.submitList(scores) // Then add new list + } + + // Ensure card is visible + updateAnalysisCard() + } + } + } + + /** + * Update the analysis card visibility and contents based on current state + */ + private fun updateAnalysisCard() { + if (viewModel.showConversion.value != true) { + binding.cardAnalysisResults.visibility = View.GONE + return + } + + val game = viewModel.lastSubmittedGame.value + val score = viewModel.lastSubmittedScore.value + + if (game != null && score != null) { + // Get the list of games with scores + val playedGames = viewModel.gamesWithScores.value ?: listOf() + + // Make sure we don't show the source game in the equivalent dropdown + val filteredGames = playedGames.filter { it != game } + if (filteredGames.isNotEmpty()) { + binding.textViewOriginalScore.text = "Your $game score of ${"%,d".format(score)} is equivalent to:" + binding.cardAnalysisResults.visibility = View.VISIBLE + + val filteredAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, filteredGames) + binding.autoCompleteEquivalentGame.setAdapter(filteredAdapter) + + // Select first game by default + binding.autoCompleteEquivalentGame.setText(filteredGames[0], false) + viewModel.setSelectedEquivalentGame(filteredGames[0]) + } else { + // If no other games to convert to, hide the card + binding.cardAnalysisResults.visibility = View.GONE } } } @@ -68,7 +112,9 @@ class EntryFragment : Fragment() { "Tetris DS", "Tetris Effect", "Rosy Retrospection DX", - "Apotris" + "Apotris", + "Modretro Tetris", + "Tetris Mobile" ) val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, games) binding.autoCompleteGameVersion.setAdapter(adapter) @@ -90,8 +136,10 @@ class EntryFragment : Fragment() { viewModel.showConversion.observe(viewLifecycleOwner) { shouldShow -> // No need to show toast here - we'll do it only after score submission if (shouldShow) { - // Refresh conversions whenever showConversion becomes true - refreshConversions() + // Update card when showConversion changes + updateAnalysisCard() + } else { + binding.cardAnalysisResults.visibility = View.GONE } } @@ -99,11 +147,8 @@ class EntryFragment : Fragment() { viewModel.gamesWithScores.observe(viewLifecycleOwner) { games -> // Setup the game dropdown for adding equivalents - only with played games if (games.isNotEmpty()) { - val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, games) - binding.autoCompleteEquivalentGame.setAdapter(adapter) - - // Also refresh conversions when game list changes - refreshConversions() + // Update card when games list changes + updateAnalysisCard() } } @@ -126,39 +171,22 @@ class EntryFragment : Fragment() { } // Observe last submitted score details - viewModel.lastSubmittedGame.observe(viewLifecycleOwner) { game -> - // Only continue if showConversion is true - if (viewModel.showConversion.value != true) { - binding.cardAnalysisResults.visibility = View.GONE - return@observe - } - - viewModel.lastSubmittedScore.value?.let { score -> - binding.textViewOriginalScore.text = "Your $game score of ${"%,d".format(score)} is equivalent to:" - - // Get the list of games with scores - val playedGames = viewModel.gamesWithScores.value ?: listOf() - - // Make sure we don't show the source game in the equivalent dropdown - val filteredGames = playedGames.filter { it != game } - if (filteredGames.isNotEmpty()) { - binding.cardAnalysisResults.visibility = View.VISIBLE - val filteredAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, filteredGames) - binding.autoCompleteEquivalentGame.setAdapter(filteredAdapter) - - // Select first game by default - binding.autoCompleteEquivalentGame.setText(filteredGames[0], false) - viewModel.setSelectedEquivalentGame(filteredGames[0]) - } else { - // If no other games to convert to, hide the card - binding.cardAnalysisResults.visibility = View.GONE - } - } + viewModel.lastSubmittedGame.observe(viewLifecycleOwner) { _ -> + // Update the analysis card when last submitted game changes + updateAnalysisCard() + } + + // Observe last submitted score value + viewModel.lastSubmittedScore.observe(viewLifecycleOwner) { _ -> + // Update the analysis card when score changes + updateAnalysisCard() } // Observe equivalent scores viewModel.equivalentScores.observe(viewLifecycleOwner) { scores -> if (scores.isNotEmpty()) { + // Force a clean update by clearing first + equivalentScoreAdapter.submitList(null) equivalentScoreAdapter.submitList(scores) } else if (viewModel.showConversion.value == true) { // If we should be showing conversions but have no scores, probably no other games @@ -185,7 +213,7 @@ class EntryFragment : Fragment() { ) clearInputs() - // Check after submission if we should show requirements toast + // Force immediate refresh of conversions if (viewModel.showConversion.value == false) { Toast.makeText( context, @@ -193,7 +221,9 @@ class EntryFragment : Fragment() { Toast.LENGTH_LONG ).show() } else { - // Only scroll down if we're going to show conversions + refreshConversions() + + // Scroll down to show the analysis results binding.root.post { binding.root.fullScroll(View.FOCUS_DOWN) } diff --git a/app/src/main/java/com/accidentalproductions/tetristats/ui/entry/EntryViewModel.kt b/app/src/main/java/com/accidentalproductions/tetristats/ui/entry/EntryViewModel.kt index b4178de..62af537 100644 --- a/app/src/main/java/com/accidentalproductions/tetristats/ui/entry/EntryViewModel.kt +++ b/app/src/main/java/com/accidentalproductions/tetristats/ui/entry/EntryViewModel.kt @@ -23,7 +23,9 @@ class EntryViewModel(application: Application) : AndroidViewModel(application) { "Tetris DS", "Tetris Effect", "Rosy Retrospection DX", - "Apotris" + "Apotris", + "Modretro Tetris", + "Tetris Mobile" ) // Track user played games and score counts @@ -108,13 +110,14 @@ class EntryViewModel(application: Application) : AndroidViewModel(application) { scoreDao.insert(newScore) // After inserting, update the last submitted values - _lastSubmittedGame.postValue(gameVersion) - _lastSubmittedScore.postValue(score) + _lastSubmittedGame.value = gameVersion // Use immediate value change instead of postValue + _lastSubmittedScore.value = score // Use immediate value change instead of postValue - // The criteria check will happen automatically through the observers in init + // Immediately check conversion criteria with current values + checkConversionCriteria() - // Only generate equivalent scores if we meet the criteria - if (_showConversion.value == true) { + // Immediate refresh regardless if we just reached the criteria threshold + if (totalScoreCount.value ?: 0 >= 3 && (gamesWithScores.value?.size ?: 0) >= 2) { generateEquivalentScores(gameVersion, score) } } @@ -146,7 +149,8 @@ class EntryViewModel(application: Application) : AndroidViewModel(application) { } } - _equivalentScores.postValue(equivalents) + // Use setValue for immediate update on main thread rather than postValue + _equivalentScores.value = equivalents } /**