From b2a9c4053953ed95c7b72fac03cdd9501d89d18e Mon Sep 17 00:00:00 2001 From: cmclark00 Date: Mon, 31 Mar 2025 16:37:57 -0400 Subject: [PATCH] Add random mode toggle and fix resource linking issues --- app/src/main/java/com/mintris/MainActivity.kt | 229 ++++++++++-------- .../res/drawable/menu_item_background.xml | 9 + .../main/res/layout-land/activity_main.xml | 31 +++ app/src/main/res/layout/activity_main.xml | 33 ++- app/src/main/res/values/colors.xml | 6 +- app/src/main/res/values/strings.xml | 1 + 6 files changed, 209 insertions(+), 100 deletions(-) create mode 100644 app/src/main/res/drawable/menu_item_background.xml diff --git a/app/src/main/java/com/mintris/MainActivity.kt b/app/src/main/java/com/mintris/MainActivity.kt index 2427b0d..322f9dd 100644 --- a/app/src/main/java/com/mintris/MainActivity.kt +++ b/app/src/main/java/com/mintris/MainActivity.kt @@ -45,6 +45,7 @@ import android.widget.ScrollView import android.widget.ImageButton import android.graphics.drawable.GradientDrawable import android.widget.TextView +import android.widget.Switch class MainActivity : AppCompatActivity(), GamepadController.GamepadConnectionListener, @@ -80,6 +81,7 @@ class MainActivity : AppCompatActivity(), private var gameStartTime: Long = 0 private var piecesPlaced: Int = 0 private var currentTheme = PlayerProgressionManager.THEME_CLASSIC + private var isRandomModeEnabled = false // Activity result launcher for high score entry private lateinit var highScoreEntryLauncher: ActivityResultLauncher @@ -138,6 +140,10 @@ class MainActivity : AppCompatActivity(), blockSkinSelector = binding.customizationBlockSkinSelector!! pauseMenuScrollView = binding.pauseMenuScrollView + // Load random mode setting + isRandomModeEnabled = getSharedPreferences("com.mintris.preferences", Context.MODE_PRIVATE) + .getBoolean("random_mode_enabled", false) + // Initialize gamepad controller gamepadController = GamepadController(gameView) gamepadController.setGamepadConnectionListener(this) @@ -241,16 +247,33 @@ class MainActivity : AppCompatActivity(), // Set up callbacks gameView.onGameStateChanged = { score, level, lines -> - updateUI(score, level, lines) - } - - // Track pieces placed using callback - gameBoard.onPieceLock = { - // Increment pieces placed counter - piecesPlaced++ + currentScore = score + currentLevel = level - // Provide haptic feedback - gameHaptics.vibrateForPieceLock() + binding.scoreText.text = "$score" + binding.currentLevelText.text = "$level" + binding.linesText.text = "$lines" + binding.comboText.text = gameBoard.getCombo().toString() + + // If random mode is enabled and we've leveled up, select random theme and block skin + if (isRandomModeEnabled && level > 1) { + val unlockedThemes = progressionManager.getUnlockedThemes().toList() + val unlockedBlocks = progressionManager.getUnlockedBlocks().toList() + + // Randomly change theme (50% chance) + if (unlockedThemes.isNotEmpty() && Math.random() < 0.5) { + val randomTheme = unlockedThemes.random() + currentTheme = randomTheme + applyTheme(randomTheme) + } + + // Randomly change block skin (50% chance) + if (unlockedBlocks.isNotEmpty() && Math.random() < 0.5) { + val randomBlock = unlockedBlocks.random() + gameView.setBlockSkin(randomBlock) + progressionManager.setSelectedBlockSkin(randomBlock) + } + } } gameView.onGameOver = { finalScore -> @@ -525,8 +548,8 @@ class MainActivity : AppCompatActivity(), * Show customization menu */ private fun showCustomizationMenu() { - binding.customizationContainer.visibility = View.VISIBLE binding.pauseContainer.visibility = View.GONE + binding.customizationContainer.visibility = View.VISIBLE // Get theme colors val themeColor = getThemeColor(currentTheme) @@ -535,58 +558,48 @@ class MainActivity : AppCompatActivity(), // Apply background color to customization container binding.customizationContainer.setBackgroundColor(backgroundColor) - // Update level badge + // Update level badge with player's level and theme color binding.customizationLevelBadge.setLevel(progressionManager.getPlayerLevel()) binding.customizationLevelBadge.setThemeColor(themeColor) - // Apply theme colors to text and buttons - binding.customizationTitle.setTextColor(themeColor) - binding.customizationBackButton.setTextColor(themeColor) - - // Apply theme colors to all text views in the container + // Apply theme color to all text views in the container applyThemeColorToTextViews(binding.customizationContainer, themeColor) - // Update theme and block skin selectors - binding.customizationThemeSelector.updateThemes( - progressionManager.getUnlockedThemes(), - currentTheme + // Update theme selector with available themes + binding.customizationThemeSelector?.updateThemes( + unlockedThemes = progressionManager.getUnlockedThemes(), + currentTheme = currentTheme ) - // Set up block skin selector callback - binding.customizationBlockSkinSelector.onBlockSkinSelected = { selectedSkin -> - // Update the game view with the selected block skin - gameView.setBlockSkin(selectedSkin) - // Save the selection - progressionManager.setSelectedBlockSkin(selectedSkin) - } - - // Update block skin selector with current selection - binding.customizationBlockSkinSelector.updateBlockSkins( + // Update block skin selector with available skins + binding.customizationBlockSkinSelector?.updateBlockSkins( progressionManager.getUnlockedBlocks(), gameView.getCurrentBlockSkin(), progressionManager.getPlayerLevel() ) - // Reset scroll position - binding.customizationMenuScrollView.scrollTo(0, 0) + // Set up block skin selection callback + binding.customizationBlockSkinSelector?.onBlockSkinSelected = { blockSkin -> + gameView.setBlockSkin(blockSkin) + progressionManager.setSelectedBlockSkin(blockSkin) + gameHaptics.vibrateForPieceLock() + } - // Initialize customization menu items - customizationMenuItems.clear() - customizationMenuItems.addAll(listOf( - binding.customizationThemeSelector, - binding.customizationBlockSkinSelector, - binding.customizationBackButton - ).filterNotNull().filter { it.visibility == View.VISIBLE }) - - // Set initial selection and highlight - currentCustomizationMenuSelection = 0 - highlightCustomizationMenuItem(currentCustomizationMenuSelection) - - // Set initial focus to theme selector - binding.customizationThemeSelector.requestFocus() - - // Initialize customization menu navigation + // Initialize customization menu items for gamepad navigation initCustomizationMenuNavigation() + + // Set up random mode switch + binding.randomModeSwitch?.apply { + isChecked = isRandomModeEnabled + isEnabled = progressionManager.getPlayerLevel() >= 5 + setOnCheckedChangeListener { _, isChecked -> + isRandomModeEnabled = isChecked + getSharedPreferences("com.mintris.preferences", Context.MODE_PRIVATE) + .edit() + .putBoolean("random_mode_enabled", isChecked) + .apply() + } + } } private fun initCustomizationMenuNavigation() { @@ -595,6 +608,7 @@ class MainActivity : AppCompatActivity(), // Add items in order customizationMenuItems.addAll(listOf( binding.customizationThemeSelector, + binding.randomModeSwitch, binding.customizationBlockSkinSelector, binding.customizationBackButton ).filterNotNull().filter { it.visibility == View.VISIBLE }) @@ -835,6 +849,26 @@ class MainActivity : AppCompatActivity(), binding.currentLevelText.text = "$level" binding.linesText.text = "$lines" binding.comboText.text = gameBoard.getCombo().toString() + + // If random mode is enabled and we've leveled up, select random theme and block skin + if (isRandomModeEnabled && level > 1) { + val unlockedThemes = progressionManager.getUnlockedThemes().toList() + val unlockedBlocks = progressionManager.getUnlockedBlocks().toList() + + // Randomly change theme (50% chance) + if (unlockedThemes.isNotEmpty() && Math.random() < 0.5) { + val randomTheme = unlockedThemes.random() + currentTheme = randomTheme + applyTheme(randomTheme) + } + + // Randomly change block skin (50% chance) + if (unlockedBlocks.isNotEmpty() && Math.random() < 0.5) { + val randomBlock = unlockedBlocks.random() + gameView.setBlockSkin(randomBlock) + progressionManager.setSelectedBlockSkin(randomBlock) + } + } } gameView.onGameOver = { finalScore -> @@ -1431,7 +1465,7 @@ class MainActivity : AppCompatActivity(), item.scaleX = 1.0f item.scaleY = 1.0f } - // Reset background/focus state for all items before applying highlight + // Reset when (item) { is Button -> item.background = ColorDrawable(Color.TRANSPARENT) is ImageButton -> item.background = null // Let default background handle non-selected @@ -1470,37 +1504,34 @@ class MainActivity : AppCompatActivity(), item.background = it } } ?: run { - // Absolute fallback: create a border if drawable fails - item.background = GradientDrawable().apply { - setColor(Color.TRANSPARENT) + // Fallback to simple border if drawable not found + var gradientDrawable = GradientDrawable().apply { + setColor(Color.TRANSPARENT) setStroke(borderWidth, highlightBorderColor) setCornerRadius(cornerRadius) } + item.background = gradientDrawable } } is ImageButton -> { - item.background = GradientDrawable().apply { - setColor(Color.TRANSPARENT) // Keep original button look, just add border - setStroke(borderWidth, highlightBorderColor) - setCornerRadius(cornerRadius) + // Similar handling for ImageButton + ContextCompat.getDrawable(this, R.drawable.menu_item_selected)?.mutate()?.let { + if (it is GradientDrawable) { + it.setStroke(borderWidth, highlightBorderColor) + item.background = it + } else { + it.setTint(highlightBorderColor) + item.background = it + } + } ?: run { + var gradientDrawable = GradientDrawable().apply { + setColor(Color.TRANSPARENT) + setStroke(borderWidth, highlightBorderColor) + setCornerRadius(cornerRadius) + } + item.background = gradientDrawable } } - is ThemeSelector -> { - item.background = GradientDrawable().apply { - setColor(Color.TRANSPARENT) - setStroke(borderWidth, highlightBorderColor) - setCornerRadius(cornerRadius) - } - item.setHasFocus(true) // Tell selector it HAS component focus - } - is BlockSkinSelector -> { - item.background = GradientDrawable().apply { - setColor(Color.TRANSPARENT) - setStroke(borderWidth, highlightBorderColor) - setCornerRadius(cornerRadius) - } - item.setHasFocus(true) // Tell selector it HAS component focus - } } } } @@ -1726,6 +1757,8 @@ class MainActivity : AppCompatActivity(), val themeColor = getThemeColor(currentTheme) val highlightBorderColor = themeColor + val borderWidth = 4 // Define border width for highlight + val cornerRadius = 12f customizationMenuItems.forEachIndexed { i, item -> val isSelected = (i == index) @@ -1747,58 +1780,55 @@ class MainActivity : AppCompatActivity(), item.background = ColorDrawable(Color.TRANSPARENT) item.setHasFocus(false) } + is Switch -> { + item.background = ColorDrawable(Color.TRANSPARENT) + } } if (isSelected) { - if (item is Button || item is ImageButton) { - item.scaleX = 1.1f - item.scaleY = 1.1f - } - - val borderWidth = 4 - val cornerRadius = 12f - when (item) { is Button -> { - ContextCompat.getDrawable(this, R.drawable.menu_item_selected)?.mutate()?.let { - if (it is GradientDrawable) { - it.setStroke(borderWidth, highlightBorderColor) - item.background = it - } else { - it.setTint(highlightBorderColor) - item.background = it - } - } ?: run { - item.background = GradientDrawable().apply { - setColor(Color.TRANSPARENT) - setStroke(borderWidth, highlightBorderColor) - setCornerRadius(cornerRadius) - } + var gradientDrawable = GradientDrawable().apply { + setColor(Color.TRANSPARENT) + setStroke(borderWidth, highlightBorderColor) + setCornerRadius(cornerRadius) } + item.background = gradientDrawable } is ImageButton -> { - item.background = GradientDrawable().apply { + var gradientDrawable = GradientDrawable().apply { setColor(Color.TRANSPARENT) setStroke(borderWidth, highlightBorderColor) setCornerRadius(cornerRadius) } + item.background = gradientDrawable } is ThemeSelector -> { - item.background = GradientDrawable().apply { + var gradientDrawable = GradientDrawable().apply { setColor(Color.TRANSPARENT) setStroke(borderWidth, highlightBorderColor) setCornerRadius(cornerRadius) } + item.background = gradientDrawable item.setHasFocus(true) } is BlockSkinSelector -> { - item.background = GradientDrawable().apply { + var gradientDrawable = GradientDrawable().apply { setColor(Color.TRANSPARENT) setStroke(borderWidth, highlightBorderColor) setCornerRadius(cornerRadius) } + item.background = gradientDrawable item.setHasFocus(true) } + is Switch -> { + var gradientDrawable = GradientDrawable().apply { + setColor(Color.TRANSPARENT) + setStroke(borderWidth, highlightBorderColor) + setCornerRadius(cornerRadius) + } + item.background = gradientDrawable + } } } } @@ -1857,6 +1887,11 @@ class MainActivity : AppCompatActivity(), selectedItem.confirmSelection() // The onBlockSkinSelected callback will handle updating the game view and saving the selection } + is Switch -> { + if (selectedItem.isEnabled) { + selectedItem.isChecked = !selectedItem.isChecked + } + } else -> { selectedItem.performClick() } diff --git a/app/src/main/res/drawable/menu_item_background.xml b/app/src/main/res/drawable/menu_item_background.xml new file mode 100644 index 0000000..4beb4d7 --- /dev/null +++ b/app/src/main/res/drawable/menu_item_background.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml index 04a9726..bc58860 100644 --- a/app/src/main/res/layout-land/activity_main.xml +++ b/app/src/main/res/layout-land/activity_main.xml @@ -691,6 +691,37 @@ android:focusable="true" android:focusableInTouchMode="true" /> + + + + + + + + + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:background="@drawable/menu_item_background" + android:padding="16dp" /> + + + + + + +