Add random mode toggle and fix resource linking issues

This commit is contained in:
cmclark00 2025-03-31 16:37:57 -04:00
parent 0b78bf7833
commit b2a9c40539
6 changed files with 209 additions and 100 deletions

View file

@ -45,6 +45,7 @@ import android.widget.ScrollView
import android.widget.ImageButton import android.widget.ImageButton
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
import android.widget.TextView import android.widget.TextView
import android.widget.Switch
class MainActivity : AppCompatActivity(), class MainActivity : AppCompatActivity(),
GamepadController.GamepadConnectionListener, GamepadController.GamepadConnectionListener,
@ -80,6 +81,7 @@ class MainActivity : AppCompatActivity(),
private var gameStartTime: Long = 0 private var gameStartTime: Long = 0
private var piecesPlaced: Int = 0 private var piecesPlaced: Int = 0
private var currentTheme = PlayerProgressionManager.THEME_CLASSIC private var currentTheme = PlayerProgressionManager.THEME_CLASSIC
private var isRandomModeEnabled = false
// Activity result launcher for high score entry // Activity result launcher for high score entry
private lateinit var highScoreEntryLauncher: ActivityResultLauncher<Intent> private lateinit var highScoreEntryLauncher: ActivityResultLauncher<Intent>
@ -138,6 +140,10 @@ class MainActivity : AppCompatActivity(),
blockSkinSelector = binding.customizationBlockSkinSelector!! blockSkinSelector = binding.customizationBlockSkinSelector!!
pauseMenuScrollView = binding.pauseMenuScrollView pauseMenuScrollView = binding.pauseMenuScrollView
// Load random mode setting
isRandomModeEnabled = getSharedPreferences("com.mintris.preferences", Context.MODE_PRIVATE)
.getBoolean("random_mode_enabled", false)
// Initialize gamepad controller // Initialize gamepad controller
gamepadController = GamepadController(gameView) gamepadController = GamepadController(gameView)
gamepadController.setGamepadConnectionListener(this) gamepadController.setGamepadConnectionListener(this)
@ -241,16 +247,33 @@ class MainActivity : AppCompatActivity(),
// Set up callbacks // Set up callbacks
gameView.onGameStateChanged = { score, level, lines -> gameView.onGameStateChanged = { score, level, lines ->
updateUI(score, level, lines) currentScore = score
} currentLevel = level
// Track pieces placed using callback binding.scoreText.text = "$score"
gameBoard.onPieceLock = { binding.currentLevelText.text = "$level"
// Increment pieces placed counter binding.linesText.text = "$lines"
piecesPlaced++ binding.comboText.text = gameBoard.getCombo().toString()
// Provide haptic feedback // If random mode is enabled and we've leveled up, select random theme and block skin
gameHaptics.vibrateForPieceLock() 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 -> gameView.onGameOver = { finalScore ->
@ -525,8 +548,8 @@ class MainActivity : AppCompatActivity(),
* Show customization menu * Show customization menu
*/ */
private fun showCustomizationMenu() { private fun showCustomizationMenu() {
binding.customizationContainer.visibility = View.VISIBLE
binding.pauseContainer.visibility = View.GONE binding.pauseContainer.visibility = View.GONE
binding.customizationContainer.visibility = View.VISIBLE
// Get theme colors // Get theme colors
val themeColor = getThemeColor(currentTheme) val themeColor = getThemeColor(currentTheme)
@ -535,58 +558,48 @@ class MainActivity : AppCompatActivity(),
// Apply background color to customization container // Apply background color to customization container
binding.customizationContainer.setBackgroundColor(backgroundColor) binding.customizationContainer.setBackgroundColor(backgroundColor)
// Update level badge // Update level badge with player's level and theme color
binding.customizationLevelBadge.setLevel(progressionManager.getPlayerLevel()) binding.customizationLevelBadge.setLevel(progressionManager.getPlayerLevel())
binding.customizationLevelBadge.setThemeColor(themeColor) binding.customizationLevelBadge.setThemeColor(themeColor)
// Apply theme colors to text and buttons // Apply theme color to all text views in the container
binding.customizationTitle.setTextColor(themeColor)
binding.customizationBackButton.setTextColor(themeColor)
// Apply theme colors to all text views in the container
applyThemeColorToTextViews(binding.customizationContainer, themeColor) applyThemeColorToTextViews(binding.customizationContainer, themeColor)
// Update theme and block skin selectors // Update theme selector with available themes
binding.customizationThemeSelector.updateThemes( binding.customizationThemeSelector?.updateThemes(
progressionManager.getUnlockedThemes(), unlockedThemes = progressionManager.getUnlockedThemes(),
currentTheme currentTheme = currentTheme
) )
// Set up block skin selector callback // Update block skin selector with available skins
binding.customizationBlockSkinSelector.onBlockSkinSelected = { selectedSkin -> binding.customizationBlockSkinSelector?.updateBlockSkins(
// 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(
progressionManager.getUnlockedBlocks(), progressionManager.getUnlockedBlocks(),
gameView.getCurrentBlockSkin(), gameView.getCurrentBlockSkin(),
progressionManager.getPlayerLevel() progressionManager.getPlayerLevel()
) )
// Reset scroll position // Set up block skin selection callback
binding.customizationMenuScrollView.scrollTo(0, 0) binding.customizationBlockSkinSelector?.onBlockSkinSelected = { blockSkin ->
gameView.setBlockSkin(blockSkin)
progressionManager.setSelectedBlockSkin(blockSkin)
gameHaptics.vibrateForPieceLock()
}
// Initialize customization menu items // Initialize customization menu items for gamepad navigation
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
initCustomizationMenuNavigation() 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() { private fun initCustomizationMenuNavigation() {
@ -595,6 +608,7 @@ class MainActivity : AppCompatActivity(),
// Add items in order // Add items in order
customizationMenuItems.addAll(listOf( customizationMenuItems.addAll(listOf(
binding.customizationThemeSelector, binding.customizationThemeSelector,
binding.randomModeSwitch,
binding.customizationBlockSkinSelector, binding.customizationBlockSkinSelector,
binding.customizationBackButton binding.customizationBackButton
).filterNotNull().filter { it.visibility == View.VISIBLE }) ).filterNotNull().filter { it.visibility == View.VISIBLE })
@ -835,6 +849,26 @@ class MainActivity : AppCompatActivity(),
binding.currentLevelText.text = "$level" binding.currentLevelText.text = "$level"
binding.linesText.text = "$lines" binding.linesText.text = "$lines"
binding.comboText.text = gameBoard.getCombo().toString() 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 -> gameView.onGameOver = { finalScore ->
@ -1431,7 +1465,7 @@ class MainActivity : AppCompatActivity(),
item.scaleX = 1.0f item.scaleX = 1.0f
item.scaleY = 1.0f item.scaleY = 1.0f
} }
// Reset background/focus state for all items before applying highlight // Reset
when (item) { when (item) {
is Button -> item.background = ColorDrawable(Color.TRANSPARENT) is Button -> item.background = ColorDrawable(Color.TRANSPARENT)
is ImageButton -> item.background = null // Let default background handle non-selected is ImageButton -> item.background = null // Let default background handle non-selected
@ -1470,37 +1504,34 @@ class MainActivity : AppCompatActivity(),
item.background = it item.background = it
} }
} ?: run { } ?: run {
// Absolute fallback: create a border if drawable fails // Fallback to simple border if drawable not found
item.background = GradientDrawable().apply { var gradientDrawable = GradientDrawable().apply {
setColor(Color.TRANSPARENT) setColor(Color.TRANSPARENT)
setStroke(borderWidth, highlightBorderColor) setStroke(borderWidth, highlightBorderColor)
setCornerRadius(cornerRadius) setCornerRadius(cornerRadius)
} }
item.background = gradientDrawable
} }
} }
is ImageButton -> { is ImageButton -> {
item.background = GradientDrawable().apply { // Similar handling for ImageButton
setColor(Color.TRANSPARENT) // Keep original button look, just add border ContextCompat.getDrawable(this, R.drawable.menu_item_selected)?.mutate()?.let {
setStroke(borderWidth, highlightBorderColor) if (it is GradientDrawable) {
setCornerRadius(cornerRadius) 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 themeColor = getThemeColor(currentTheme)
val highlightBorderColor = themeColor val highlightBorderColor = themeColor
val borderWidth = 4 // Define border width for highlight
val cornerRadius = 12f
customizationMenuItems.forEachIndexed { i, item -> customizationMenuItems.forEachIndexed { i, item ->
val isSelected = (i == index) val isSelected = (i == index)
@ -1747,58 +1780,55 @@ class MainActivity : AppCompatActivity(),
item.background = ColorDrawable(Color.TRANSPARENT) item.background = ColorDrawable(Color.TRANSPARENT)
item.setHasFocus(false) item.setHasFocus(false)
} }
is Switch -> {
item.background = ColorDrawable(Color.TRANSPARENT)
}
} }
if (isSelected) { 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) { when (item) {
is Button -> { is Button -> {
ContextCompat.getDrawable(this, R.drawable.menu_item_selected)?.mutate()?.let { var gradientDrawable = GradientDrawable().apply {
if (it is GradientDrawable) { setColor(Color.TRANSPARENT)
it.setStroke(borderWidth, highlightBorderColor) setStroke(borderWidth, highlightBorderColor)
item.background = it setCornerRadius(cornerRadius)
} else {
it.setTint(highlightBorderColor)
item.background = it
}
} ?: run {
item.background = GradientDrawable().apply {
setColor(Color.TRANSPARENT)
setStroke(borderWidth, highlightBorderColor)
setCornerRadius(cornerRadius)
}
} }
item.background = gradientDrawable
} }
is ImageButton -> { is ImageButton -> {
item.background = GradientDrawable().apply { var gradientDrawable = GradientDrawable().apply {
setColor(Color.TRANSPARENT) setColor(Color.TRANSPARENT)
setStroke(borderWidth, highlightBorderColor) setStroke(borderWidth, highlightBorderColor)
setCornerRadius(cornerRadius) setCornerRadius(cornerRadius)
} }
item.background = gradientDrawable
} }
is ThemeSelector -> { is ThemeSelector -> {
item.background = GradientDrawable().apply { var gradientDrawable = GradientDrawable().apply {
setColor(Color.TRANSPARENT) setColor(Color.TRANSPARENT)
setStroke(borderWidth, highlightBorderColor) setStroke(borderWidth, highlightBorderColor)
setCornerRadius(cornerRadius) setCornerRadius(cornerRadius)
} }
item.background = gradientDrawable
item.setHasFocus(true) item.setHasFocus(true)
} }
is BlockSkinSelector -> { is BlockSkinSelector -> {
item.background = GradientDrawable().apply { var gradientDrawable = GradientDrawable().apply {
setColor(Color.TRANSPARENT) setColor(Color.TRANSPARENT)
setStroke(borderWidth, highlightBorderColor) setStroke(borderWidth, highlightBorderColor)
setCornerRadius(cornerRadius) setCornerRadius(cornerRadius)
} }
item.background = gradientDrawable
item.setHasFocus(true) 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() selectedItem.confirmSelection()
// The onBlockSkinSelected callback will handle updating the game view and saving the selection // The onBlockSkinSelected callback will handle updating the game view and saving the selection
} }
is Switch -> {
if (selectedItem.isEnabled) {
selectedItem.isChecked = !selectedItem.isChecked
}
}
else -> { else -> {
selectedItem.performClick() selectedItem.performClick()
} }

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="8dp" />
<stroke
android:width="1dp"
android:color="#33FFFFFF" />
<solid android:color="#1AFFFFFF" />
</shape>

View file

@ -691,6 +691,37 @@
android:focusable="true" android:focusable="true"
android:focusableInTouchMode="true" /> android:focusableInTouchMode="true" />
<!-- Random Mode Switch -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:layout_marginBottom="16dp"
android:background="@drawable/menu_section_background"
android:focusable="true"
android:focusableInTouchMode="true">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/random_mode"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
android:fontFamily="sans-serif" />
<Switch
android:id="@+id/randomModeSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:focusable="true"
android:focusableInTouchMode="true" />
</LinearLayout>
<!-- Block Skin Selector --> <!-- Block Skin Selector -->
<com.mintris.ui.BlockSkinSelector <com.mintris.ui.BlockSkinSelector
android:id="@+id/customizationBlockSkinSelector" android:id="@+id/customizationBlockSkinSelector"

View file

@ -602,7 +602,38 @@
<com.mintris.ui.BlockSkinSelector <com.mintris.ui.BlockSkinSelector
android:id="@+id/customizationBlockSkinSelector" android:id="@+id/customizationBlockSkinSelector"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/menu_item_background"
android:padding="16dp" />
<LinearLayout
android:id="@+id/randomModeContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/menu_item_background"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/random_mode"
android:textSize="18sp"
android:textColor="@android:color/white" />
<Switch
android:id="@+id/randomModeSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleX="1.5"
android:scaleY="1.5"
android:thumbTint="@color/switch_thumb_color"
android:trackTint="@color/switch_track_color" />
</LinearLayout>
<!-- Back Button --> <!-- Back Button -->
<Button <Button

View file

@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="black">#000000</color> <color name="black">#FF000000</color>
<color name="white">#FFFFFF</color> <color name="white">#FFFFFFFF</color>
<color name="gray_dark">#222222</color> <color name="gray_dark">#222222</color>
<color name="gray_light">#CCCCCC</color> <color name="gray_light">#CCCCCC</color>
<color name="transparent">#00000000</color> <color name="transparent">#00000000</color>
<color name="switch_track_color">#33FFFFFF</color>
<color name="switch_thumb_color">#FFFFFF</color>
</resources> </resources>

View file

@ -48,4 +48,5 @@
<string name="reset_stats">reset stats</string> <string name="reset_stats">reset stats</string>
<string name="music">music</string> <string name="music">music</string>
<string name="customization">Customization</string> <string name="customization">Customization</string>
<string name="random_mode">Random Mode</string>
</resources> </resources>