Fix auto-refresh issue and add missing games: Modretro Tetris and Tetris Mobile

This commit is contained in:
cmclark00 2025-03-24 17:17:26 -04:00
parent b7d0382ecc
commit aeb463fa88
3 changed files with 120 additions and 52 deletions

View file

@ -16,7 +16,9 @@ object ScalingFactors {
"Tetris DS" to RangeScalingFactor(3.0, 3.3, 4.5), "Tetris DS" to RangeScalingFactor(3.0, 3.3, 4.5),
"Tetris Effect" to RangeScalingFactor(2.5, 3.8, 4.5), "Tetris Effect" to RangeScalingFactor(2.5, 3.8, 4.5),
"Rosy Retrospection DX" to RangeScalingFactor(4.0, 1.5, 1.8), "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( "Game Boy Tetris" to mapOf(
"NES Tetris" to 1.33, "NES Tetris" to 1.33,
@ -24,7 +26,9 @@ object ScalingFactors {
"Tetris DS" to RangeScalingFactor(4.0, 2.0, 2.0), "Tetris DS" to RangeScalingFactor(4.0, 2.0, 2.0),
"Tetris Effect" to RangeScalingFactor(4.0, 2.3, 2.3), "Tetris Effect" to RangeScalingFactor(4.0, 2.3, 2.3),
"Rosy Retrospection DX" to 1.1, "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( "Tetris DX" to mapOf(
"NES Tetris" to 1.33, "NES Tetris" to 1.33,
@ -32,7 +36,9 @@ object ScalingFactors {
"Tetris DS" to RangeScalingFactor(4.0, 2.0, 2.0), "Tetris DS" to RangeScalingFactor(4.0, 2.0, 2.0),
"Tetris Effect" to RangeScalingFactor(4.0, 2.3, 2.3), "Tetris Effect" to RangeScalingFactor(4.0, 2.3, 2.3),
"Rosy Retrospection DX" to 1.1, "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( "Tetris DS" to mapOf(
"NES Tetris" to RangeScalingFactor(0.33, 0.3, 0.22), "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 DX" to RangeScalingFactor(0.25, 0.5, 0.5),
"Tetris Effect" to RangeScalingFactor(0.83, 0.91, 1.0), "Tetris Effect" to RangeScalingFactor(0.83, 0.91, 1.0),
"Rosy Retrospection DX" to RangeScalingFactor(0.25, 0.91, 0.67), "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( "Tetris Effect" to mapOf(
"NES Tetris" to RangeScalingFactor(0.4, 0.26, 0.22), "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 DX" to RangeScalingFactor(0.25, 0.43, 0.43),
"Tetris DS" to RangeScalingFactor(1.2, 1.1, 1.0), "Tetris DS" to RangeScalingFactor(1.2, 1.1, 1.0),
"Rosy Retrospection DX" to RangeScalingFactor(0.25, 0.43, 0.57), "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( "Rosy Retrospection DX" to mapOf(
"NES Tetris" to RangeScalingFactor(0.25, 0.67, 0.57), "NES Tetris" to RangeScalingFactor(0.25, 0.67, 0.57),
@ -56,7 +66,9 @@ object ScalingFactors {
"Tetris DX" to 0.91, "Tetris DX" to 0.91,
"Tetris DS" to RangeScalingFactor(4.0, 1.5, 1.8), "Tetris DS" to RangeScalingFactor(4.0, 1.5, 1.8),
"Tetris Effect" to RangeScalingFactor(4.0, 2.3, 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( "Apotris" to mapOf(
"NES Tetris" to RangeScalingFactor(0.56, 0.26, 0.23), "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 DX" to RangeScalingFactor(0.75, 0.75, 0.5),
"Tetris DS" to RangeScalingFactor(3.0, 1.5, 1.0), "Tetris DS" to RangeScalingFactor(3.0, 1.5, 1.0),
"Tetris Effect" to RangeScalingFactor(3.0, 1.7, 1.2), "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)
) )
) )

View file

@ -56,6 +56,50 @@ class EntryFragment : Fragment() {
if (game != null && score != null) { if (game != null && score != null) {
viewModel.refreshEquivalentScores(game, score) 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 DS",
"Tetris Effect", "Tetris Effect",
"Rosy Retrospection DX", "Rosy Retrospection DX",
"Apotris" "Apotris",
"Modretro Tetris",
"Tetris Mobile"
) )
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, games) val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, games)
binding.autoCompleteGameVersion.setAdapter(adapter) binding.autoCompleteGameVersion.setAdapter(adapter)
@ -90,8 +136,10 @@ class EntryFragment : Fragment() {
viewModel.showConversion.observe(viewLifecycleOwner) { shouldShow -> viewModel.showConversion.observe(viewLifecycleOwner) { shouldShow ->
// No need to show toast here - we'll do it only after score submission // No need to show toast here - we'll do it only after score submission
if (shouldShow) { if (shouldShow) {
// Refresh conversions whenever showConversion becomes true // Update card when showConversion changes
refreshConversions() updateAnalysisCard()
} else {
binding.cardAnalysisResults.visibility = View.GONE
} }
} }
@ -99,11 +147,8 @@ class EntryFragment : Fragment() {
viewModel.gamesWithScores.observe(viewLifecycleOwner) { games -> viewModel.gamesWithScores.observe(viewLifecycleOwner) { games ->
// Setup the game dropdown for adding equivalents - only with played games // Setup the game dropdown for adding equivalents - only with played games
if (games.isNotEmpty()) { if (games.isNotEmpty()) {
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line, games) // Update card when games list changes
binding.autoCompleteEquivalentGame.setAdapter(adapter) updateAnalysisCard()
// Also refresh conversions when game list changes
refreshConversions()
} }
} }
@ -126,39 +171,22 @@ class EntryFragment : Fragment() {
} }
// Observe last submitted score details // Observe last submitted score details
viewModel.lastSubmittedGame.observe(viewLifecycleOwner) { game -> viewModel.lastSubmittedGame.observe(viewLifecycleOwner) { _ ->
// Only continue if showConversion is true // Update the analysis card when last submitted game changes
if (viewModel.showConversion.value != true) { updateAnalysisCard()
binding.cardAnalysisResults.visibility = View.GONE
return@observe
} }
viewModel.lastSubmittedScore.value?.let { score -> // Observe last submitted score value
binding.textViewOriginalScore.text = "Your $game score of ${"%,d".format(score)} is equivalent to:" viewModel.lastSubmittedScore.observe(viewLifecycleOwner) { _ ->
// Update the analysis card when score changes
// Get the list of games with scores updateAnalysisCard()
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
}
}
} }
// Observe equivalent scores // Observe equivalent scores
viewModel.equivalentScores.observe(viewLifecycleOwner) { scores -> viewModel.equivalentScores.observe(viewLifecycleOwner) { scores ->
if (scores.isNotEmpty()) { if (scores.isNotEmpty()) {
// Force a clean update by clearing first
equivalentScoreAdapter.submitList(null)
equivalentScoreAdapter.submitList(scores) equivalentScoreAdapter.submitList(scores)
} else if (viewModel.showConversion.value == true) { } else if (viewModel.showConversion.value == true) {
// If we should be showing conversions but have no scores, probably no other games // If we should be showing conversions but have no scores, probably no other games
@ -185,7 +213,7 @@ class EntryFragment : Fragment() {
) )
clearInputs() clearInputs()
// Check after submission if we should show requirements toast // Force immediate refresh of conversions
if (viewModel.showConversion.value == false) { if (viewModel.showConversion.value == false) {
Toast.makeText( Toast.makeText(
context, context,
@ -193,7 +221,9 @@ class EntryFragment : Fragment() {
Toast.LENGTH_LONG Toast.LENGTH_LONG
).show() ).show()
} else { } else {
// Only scroll down if we're going to show conversions refreshConversions()
// Scroll down to show the analysis results
binding.root.post { binding.root.post {
binding.root.fullScroll(View.FOCUS_DOWN) binding.root.fullScroll(View.FOCUS_DOWN)
} }

View file

@ -23,7 +23,9 @@ class EntryViewModel(application: Application) : AndroidViewModel(application) {
"Tetris DS", "Tetris DS",
"Tetris Effect", "Tetris Effect",
"Rosy Retrospection DX", "Rosy Retrospection DX",
"Apotris" "Apotris",
"Modretro Tetris",
"Tetris Mobile"
) )
// Track user played games and score counts // Track user played games and score counts
@ -108,13 +110,14 @@ class EntryViewModel(application: Application) : AndroidViewModel(application) {
scoreDao.insert(newScore) scoreDao.insert(newScore)
// After inserting, update the last submitted values // After inserting, update the last submitted values
_lastSubmittedGame.postValue(gameVersion) _lastSubmittedGame.value = gameVersion // Use immediate value change instead of postValue
_lastSubmittedScore.postValue(score) _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 // Immediate refresh regardless if we just reached the criteria threshold
if (_showConversion.value == true) { if (totalScoreCount.value ?: 0 >= 3 && (gamesWithScores.value?.size ?: 0) >= 2) {
generateEquivalentScores(gameVersion, score) 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
} }
/** /**