mirror of
https://github.com/cmclark00/mintris.git
synced 2025-05-18 00:25:20 +01:00
Fix customization menu navigation and layout issues: - Fix D-pad navigation between theme and block skin selectors - Prevent word wrapping in customization title - Add ThemeManager for theme color management - Improve menu item highlighting and focus handling
This commit is contained in:
parent
a8f095cf42
commit
71a8efff91
6 changed files with 555 additions and 114 deletions
|
@ -105,6 +105,10 @@ class MainActivity : AppCompatActivity(),
|
|||
// Track currently selected menu item in pause menu for gamepad navigation
|
||||
private var currentMenuSelection = 0
|
||||
private val pauseMenuItems = mutableListOf<View>()
|
||||
private val customizationMenuItems = mutableListOf<View>()
|
||||
|
||||
// Add these new properties at the class level
|
||||
private var currentCustomizationMenuSelection = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// Register activity result launcher for high score entry
|
||||
|
@ -130,8 +134,8 @@ class MainActivity : AppCompatActivity(),
|
|||
highScoreManager = HighScoreManager(this)
|
||||
statsManager = StatsManager(this)
|
||||
progressionManager = PlayerProgressionManager(this)
|
||||
themeSelector = binding.themeSelector
|
||||
blockSkinSelector = binding.blockSkinSelector
|
||||
themeSelector = binding.customizationThemeSelector!!
|
||||
blockSkinSelector = binding.customizationBlockSkinSelector!!
|
||||
pauseMenuScrollView = binding.pauseMenuScrollView
|
||||
|
||||
// Initialize gamepad controller
|
||||
|
@ -190,44 +194,6 @@ class MainActivity : AppCompatActivity(),
|
|||
}
|
||||
}
|
||||
|
||||
// Set up landscape mode theme selector if available
|
||||
val inPauseThemeSelector = findViewById<ThemeSelector>(R.id.inPauseThemeSelector)
|
||||
inPauseThemeSelector?.onThemeSelected = { themeId: String ->
|
||||
// Apply the new theme
|
||||
applyTheme(themeId)
|
||||
|
||||
// Provide haptic feedback
|
||||
gameHaptics.vibrateForPieceLock()
|
||||
|
||||
// Refresh the pause menu
|
||||
showPauseMenu()
|
||||
}
|
||||
|
||||
// Set up block skin selector
|
||||
blockSkinSelector.onBlockSkinSelected = { skinId: String ->
|
||||
// Apply the new block skin
|
||||
gameView.setBlockSkin(skinId)
|
||||
|
||||
// Save the selection
|
||||
progressionManager.setSelectedBlockSkin(skinId)
|
||||
|
||||
// Provide haptic feedback
|
||||
gameHaptics.vibrateForPieceLock()
|
||||
}
|
||||
|
||||
// Set up landscape mode block skin selector if available
|
||||
val inPauseBlockSkinSelector = findViewById<BlockSkinSelector>(R.id.inPauseBlockSkinSelector)
|
||||
inPauseBlockSkinSelector?.onBlockSkinSelected = { skinId: String ->
|
||||
// Apply the new block skin
|
||||
gameView.setBlockSkin(skinId)
|
||||
|
||||
// Save the selection
|
||||
progressionManager.setSelectedBlockSkin(skinId)
|
||||
|
||||
// Provide haptic feedback
|
||||
gameHaptics.vibrateForPieceLock()
|
||||
}
|
||||
|
||||
// Set up title screen
|
||||
titleScreen.onStartGame = {
|
||||
titleScreen.visibility = View.GONE
|
||||
|
@ -405,6 +371,18 @@ class MainActivity : AppCompatActivity(),
|
|||
startActivity(intent)
|
||||
}
|
||||
|
||||
// Set up customization button
|
||||
binding.customizationButton.setOnClickListener {
|
||||
gameHaptics.performHapticFeedback(it, HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
showCustomizationMenu()
|
||||
}
|
||||
|
||||
// Set up customization back button
|
||||
binding.customizationBackButton.setOnClickListener {
|
||||
gameHaptics.performHapticFeedback(it, HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
hideCustomizationMenu()
|
||||
}
|
||||
|
||||
// Initialize level selector
|
||||
updateLevelSelector()
|
||||
|
||||
|
@ -493,12 +471,6 @@ class MainActivity : AppCompatActivity(),
|
|||
Log.d("MainActivity", "Triggering game over animation")
|
||||
gameView.startGameOverAnimation()
|
||||
|
||||
// Hide game UI elements in landscape mode
|
||||
if (resources.configuration.orientation == android.content.res.Configuration.ORIENTATION_LANDSCAPE) {
|
||||
binding.leftControlsPanel?.visibility = View.GONE
|
||||
binding.rightControlsPanel?.visibility = View.GONE
|
||||
}
|
||||
|
||||
// Wait a moment before showing progression screen to let animation be visible
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
// Show progression screen first with XP animation
|
||||
|
@ -549,11 +521,119 @@ class MainActivity : AppCompatActivity(),
|
|||
progressionScreen.visibility = View.GONE
|
||||
}
|
||||
|
||||
/**
|
||||
* Show customization menu
|
||||
*/
|
||||
private fun showCustomizationMenu() {
|
||||
binding.customizationContainer.visibility = View.VISIBLE
|
||||
binding.pauseContainer.visibility = View.GONE
|
||||
|
||||
// Update theme colors
|
||||
val themeColors = ThemeManager.getThemeColors()
|
||||
binding.customizationContainer.setBackgroundColor(themeColors.background)
|
||||
|
||||
// Update level badge
|
||||
binding.customizationLevelBadge.setLevel(progressionManager.getPlayerLevel())
|
||||
binding.customizationLevelBadge.setThemeColor(themeColors.accent)
|
||||
|
||||
// Apply theme colors to text
|
||||
binding.customizationTitle.setTextColor(themeColors.text.toInt())
|
||||
|
||||
// Update theme and block skin selectors
|
||||
binding.customizationThemeSelector.updateThemes(
|
||||
progressionManager.getUnlockedThemes(),
|
||||
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(
|
||||
progressionManager.getUnlockedBlocks(),
|
||||
gameView.getCurrentBlockSkin(),
|
||||
progressionManager.getPlayerLevel()
|
||||
)
|
||||
|
||||
// Reset scroll position
|
||||
binding.customizationMenuScrollView.scrollTo(0, 0)
|
||||
|
||||
// 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
|
||||
initCustomizationMenuNavigation()
|
||||
}
|
||||
|
||||
private fun initCustomizationMenuNavigation() {
|
||||
customizationMenuItems.clear()
|
||||
|
||||
// Add items in order
|
||||
customizationMenuItems.addAll(listOf(
|
||||
binding.customizationThemeSelector,
|
||||
binding.customizationBlockSkinSelector,
|
||||
binding.customizationBackButton
|
||||
).filterNotNull().filter { it.visibility == View.VISIBLE })
|
||||
|
||||
// Set up focus change listener for scrolling
|
||||
binding.customizationMenuScrollView.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (hasFocus) {
|
||||
// When scroll view gets focus, scroll to focused item
|
||||
val focusedView = currentFocus
|
||||
if (focusedView != null) {
|
||||
val scrollView = binding.customizationMenuScrollView
|
||||
val itemTop = focusedView.top
|
||||
val scrollViewHeight = scrollView.height
|
||||
|
||||
// Calculate scroll position to center the focused item
|
||||
val scrollY = itemTop - (scrollViewHeight / 2) + (focusedView.height / 2)
|
||||
scrollView.smoothScrollTo(0, scrollY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up focus handling between items
|
||||
customizationMenuItems.forEachIndexed { index, item ->
|
||||
item.setOnFocusChangeListener { _, hasFocus ->
|
||||
if (hasFocus) {
|
||||
currentCustomizationMenuSelection = index
|
||||
highlightCustomizationMenuItem(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide customization menu
|
||||
*/
|
||||
private fun hideCustomizationMenu() {
|
||||
binding.customizationContainer.visibility = View.GONE
|
||||
binding.pauseContainer.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
/**
|
||||
* Show settings menu
|
||||
*/
|
||||
private fun showPauseMenu() {
|
||||
binding.pauseContainer.visibility = View.VISIBLE
|
||||
binding.customizationContainer.visibility = View.GONE
|
||||
|
||||
// Set button visibility based on game state
|
||||
if (gameView.isPaused) {
|
||||
|
@ -589,6 +669,7 @@ class MainActivity : AppCompatActivity(),
|
|||
binding.pauseLevelDownButton?.setTextColor(themeColor) // Safe call
|
||||
binding.settingsButton?.setTextColor(themeColor) // Safe call for sound toggle button text
|
||||
binding.musicToggle?.setColorFilter(themeColor) // Safe call
|
||||
binding.customizationButton?.setTextColor(themeColor) // Safe call
|
||||
|
||||
// Apply theme colors to text elements (using safe calls)
|
||||
binding.settingsTitle?.setTextColor(themeColor)
|
||||
|
@ -596,30 +677,8 @@ class MainActivity : AppCompatActivity(),
|
|||
binding.musicText?.setTextColor(themeColor)
|
||||
binding.pauseLevelText?.setTextColor(themeColor)
|
||||
|
||||
// Apply theme to specific labels in portrait/landscape - RELY ON HELPER BELOW
|
||||
if (isLandscape) {
|
||||
// findViewById<TextView>(R.id.selectThemeTextLandscape)?.setTextColor(themeColor) // REMOVED
|
||||
// findViewById<TextView>(R.id.selectBlockSkinTextLandscape)?.setTextColor(themeColor) // REMOVED
|
||||
// Also color general text views in the landscape container, avoiding selectors
|
||||
applyThemeColorToTextViews(findViewById(R.id.pauseContainer), themeColor)
|
||||
} else {
|
||||
// binding.selectThemeText?.setTextColor(themeColor) // REMOVED
|
||||
// binding.selectBlockSkinText?.setTextColor(themeColor) // REMOVED
|
||||
// Apply to portrait container as well if needed (assuming root or specific container)
|
||||
applyThemeColorToTextViews(binding.pauseContainer, themeColor) // Apply to main container
|
||||
}
|
||||
|
||||
// Update theme selector instances
|
||||
val currentUnlockedThemes = progressionManager.getUnlockedThemes()
|
||||
binding.themeSelector.updateThemes(currentUnlockedThemes, currentTheme)
|
||||
findViewById<ThemeSelector>(R.id.inPauseThemeSelector)?.updateThemes(currentUnlockedThemes, currentTheme)
|
||||
|
||||
// Update block skin selector instances
|
||||
val currentBlockSkin = gameView.getCurrentBlockSkin()
|
||||
val currentUnlockedBlocks = progressionManager.getUnlockedBlocks()
|
||||
val currentLevel = progressionManager.getPlayerLevel()
|
||||
binding.blockSkinSelector.updateBlockSkins(currentUnlockedBlocks, currentBlockSkin, currentLevel)
|
||||
findViewById<BlockSkinSelector>(R.id.inPauseBlockSkinSelector)?.updateBlockSkins(currentUnlockedBlocks, currentBlockSkin, currentLevel)
|
||||
// Apply to portrait container as well if needed (assuming root or specific container)
|
||||
applyThemeColorToTextViews(binding.pauseContainer, themeColor) // Apply to main container
|
||||
|
||||
// Reset scroll position
|
||||
binding.pauseMenuScrollView?.scrollTo(0, 0)
|
||||
|
@ -913,7 +972,7 @@ class MainActivity : AppCompatActivity(),
|
|||
* Update the theme selector with unlocked themes
|
||||
*/
|
||||
private fun updateThemeSelector() {
|
||||
binding.themeSelector.updateThemes(
|
||||
binding.customizationThemeSelector?.updateThemes(
|
||||
unlockedThemes = progressionManager.getUnlockedThemes(),
|
||||
currentTheme = currentTheme
|
||||
)
|
||||
|
@ -1224,8 +1283,10 @@ class MainActivity : AppCompatActivity(),
|
|||
runOnUiThread {
|
||||
if (binding.pauseContainer.visibility == View.VISIBLE) {
|
||||
moveMenuSelectionUp()
|
||||
// Ensure the selected item is visible
|
||||
scrollToSelectedItem()
|
||||
} else if (binding.customizationContainer.visibility == View.VISIBLE) {
|
||||
moveCustomizationMenuSelectionUp()
|
||||
scrollToSelectedCustomizationItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1234,8 +1295,10 @@ class MainActivity : AppCompatActivity(),
|
|||
runOnUiThread {
|
||||
if (binding.pauseContainer.visibility == View.VISIBLE) {
|
||||
moveMenuSelectionDown()
|
||||
// Ensure the selected item is visible
|
||||
scrollToSelectedItem()
|
||||
} else if (binding.customizationContainer.visibility == View.VISIBLE) {
|
||||
moveCustomizationMenuSelectionDown()
|
||||
scrollToSelectedCustomizationItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1248,18 +1311,30 @@ class MainActivity : AppCompatActivity(),
|
|||
is ThemeSelector -> selectedItem.focusPreviousItem()
|
||||
is BlockSkinSelector -> selectedItem.focusPreviousItem()
|
||||
}
|
||||
} else if (binding.customizationContainer.visibility == View.VISIBLE && customizationMenuItems.isNotEmpty()) {
|
||||
val selectedItem = customizationMenuItems.getOrNull(currentCustomizationMenuSelection)
|
||||
when (selectedItem) {
|
||||
is ThemeSelector -> selectedItem.focusPreviousItem()
|
||||
is BlockSkinSelector -> selectedItem.focusPreviousItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMenuRight() {
|
||||
runOnUiThread {
|
||||
if (binding.pauseContainer.visibility == View.VISIBLE && pauseMenuItems.isNotEmpty()) {
|
||||
if (binding.pauseContainer.visibility == View.VISIBLE && pauseMenuItems.isNotEmpty()) {
|
||||
val selectedItem = pauseMenuItems.getOrNull(currentMenuSelection)
|
||||
when (selectedItem) {
|
||||
is ThemeSelector -> selectedItem.focusNextItem()
|
||||
is BlockSkinSelector -> selectedItem.focusNextItem()
|
||||
}
|
||||
} else if (binding.customizationContainer.visibility == View.VISIBLE && customizationMenuItems.isNotEmpty()) {
|
||||
val selectedItem = customizationMenuItems.getOrNull(currentCustomizationMenuSelection)
|
||||
when (selectedItem) {
|
||||
is ThemeSelector -> selectedItem.focusNextItem()
|
||||
is BlockSkinSelector -> selectedItem.focusNextItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1267,7 +1342,9 @@ class MainActivity : AppCompatActivity(),
|
|||
override fun onMenuSelect() {
|
||||
runOnUiThread {
|
||||
if (binding.pauseContainer.visibility == View.VISIBLE && pauseMenuItems.isNotEmpty()) {
|
||||
activateSelectedMenuItem() // Handles selectors and other items
|
||||
activateSelectedMenuItem()
|
||||
} else if (binding.customizationContainer.visibility == View.VISIBLE && customizationMenuItems.isNotEmpty()) {
|
||||
activateSelectedCustomizationMenuItem()
|
||||
} else if (titleScreen.visibility == View.VISIBLE) {
|
||||
titleScreen.performClick()
|
||||
} else if (progressionScreen.visibility == View.VISIBLE) {
|
||||
|
@ -1295,12 +1372,9 @@ class MainActivity : AppCompatActivity(),
|
|||
orderedViews.add(binding.resumeButton)
|
||||
}
|
||||
if (binding.pauseStartButton.visibility == View.VISIBLE) {
|
||||
// In pause menu, the 'Start New Game' button might be visible if paused from title?
|
||||
// Let's assume pauseRestartButton is the primary one during active pause.
|
||||
// Keep the logic simple: add if visible.
|
||||
orderedViews.add(binding.pauseStartButton)
|
||||
}
|
||||
orderedViews.add(binding.pauseRestartButton) // Always add restart
|
||||
orderedViews.add(binding.pauseRestartButton)
|
||||
|
||||
// Group 2: Stats and Scoring
|
||||
orderedViews.add(binding.highScoresButton)
|
||||
|
@ -1314,24 +1388,11 @@ class MainActivity : AppCompatActivity(),
|
|||
orderedViews.add(binding.settingsButton) // Sound toggle (Button)
|
||||
orderedViews.add(binding.musicToggle) // Music toggle (ImageButton)
|
||||
|
||||
// Group 5: Visual customization (Theme and Block Skins)
|
||||
// Choose the correct instance based on orientation and visibility
|
||||
val themeSelectorInstance = if (isLandscape) findViewById<ThemeSelector>(R.id.inPauseThemeSelector) else binding.themeSelector
|
||||
val blockSkinSelectorInstance = if (isLandscape) findViewById<BlockSkinSelector>(R.id.inPauseBlockSkinSelector) else binding.blockSkinSelector
|
||||
|
||||
// Only add the selectors if they are actually visible in the current layout
|
||||
if (themeSelectorInstance?.visibility == View.VISIBLE) {
|
||||
orderedViews.add(themeSelectorInstance)
|
||||
}
|
||||
if (blockSkinSelectorInstance?.visibility == View.VISIBLE) {
|
||||
orderedViews.add(blockSkinSelectorInstance)
|
||||
}
|
||||
// Group 5: Customization Menu
|
||||
orderedViews.add(binding.customizationButton) // Add the customization button
|
||||
|
||||
// Add all non-null, visible items from the defined order to the final navigation list
|
||||
pauseMenuItems.addAll(orderedViews.filterNotNull().filter { it.visibility == View.VISIBLE })
|
||||
|
||||
// Reset selection index (will be set and highlighted in showPauseMenu)
|
||||
// currentMenuSelection = 0
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1609,4 +1670,182 @@ class MainActivity : AppCompatActivity(),
|
|||
// If no landscape ScrollView is found, fall back to the default one
|
||||
return binding.pauseMenuScrollView
|
||||
}
|
||||
|
||||
// Add these new methods for customization menu navigation
|
||||
private fun moveCustomizationMenuSelectionUp() {
|
||||
if (customizationMenuItems.isEmpty()) return
|
||||
|
||||
val previousSelection = currentCustomizationMenuSelection
|
||||
currentCustomizationMenuSelection = (currentCustomizationMenuSelection - 1)
|
||||
|
||||
if (currentCustomizationMenuSelection < 0) {
|
||||
currentCustomizationMenuSelection = 0
|
||||
return
|
||||
}
|
||||
|
||||
if (previousSelection != currentCustomizationMenuSelection) {
|
||||
highlightCustomizationMenuItem(currentCustomizationMenuSelection)
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveCustomizationMenuSelectionDown() {
|
||||
if (customizationMenuItems.isEmpty()) return
|
||||
|
||||
val previousSelection = currentCustomizationMenuSelection
|
||||
currentCustomizationMenuSelection = (currentCustomizationMenuSelection + 1)
|
||||
|
||||
if (currentCustomizationMenuSelection >= customizationMenuItems.size) {
|
||||
currentCustomizationMenuSelection = customizationMenuItems.size - 1
|
||||
return
|
||||
}
|
||||
|
||||
if (previousSelection != currentCustomizationMenuSelection) {
|
||||
highlightCustomizationMenuItem(currentCustomizationMenuSelection)
|
||||
}
|
||||
}
|
||||
|
||||
private fun highlightCustomizationMenuItem(index: Int) {
|
||||
if (customizationMenuItems.isEmpty() || index < 0 || index >= customizationMenuItems.size) {
|
||||
Log.w(TAG, "highlightCustomizationMenuItem called with invalid index: $index or empty items")
|
||||
return
|
||||
}
|
||||
|
||||
val themeColor = getThemeColor(currentTheme)
|
||||
val highlightBorderColor = themeColor
|
||||
|
||||
customizationMenuItems.forEachIndexed { i, item ->
|
||||
val isSelected = (i == index)
|
||||
|
||||
item.alpha = if (isSelected) 1.0f else 0.7f
|
||||
if (item is Button || item is ImageButton) {
|
||||
item.scaleX = 1.0f
|
||||
item.scaleY = 1.0f
|
||||
}
|
||||
|
||||
when (item) {
|
||||
is Button -> item.background = ColorDrawable(Color.TRANSPARENT)
|
||||
is ImageButton -> item.background = null
|
||||
is ThemeSelector -> {
|
||||
item.background = ColorDrawable(Color.TRANSPARENT)
|
||||
item.setHasFocus(false)
|
||||
}
|
||||
is BlockSkinSelector -> {
|
||||
item.background = ColorDrawable(Color.TRANSPARENT)
|
||||
item.setHasFocus(false)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
is ImageButton -> {
|
||||
item.background = GradientDrawable().apply {
|
||||
setColor(Color.TRANSPARENT)
|
||||
setStroke(borderWidth, highlightBorderColor)
|
||||
setCornerRadius(cornerRadius)
|
||||
}
|
||||
}
|
||||
is ThemeSelector -> {
|
||||
item.background = GradientDrawable().apply {
|
||||
setColor(Color.TRANSPARENT)
|
||||
setStroke(borderWidth, highlightBorderColor)
|
||||
setCornerRadius(cornerRadius)
|
||||
}
|
||||
item.setHasFocus(true)
|
||||
}
|
||||
is BlockSkinSelector -> {
|
||||
item.background = GradientDrawable().apply {
|
||||
setColor(Color.TRANSPARENT)
|
||||
setStroke(borderWidth, highlightBorderColor)
|
||||
setCornerRadius(cornerRadius)
|
||||
}
|
||||
item.setHasFocus(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gameHaptics.vibrateForPieceMove()
|
||||
scrollToSelectedCustomizationItem()
|
||||
}
|
||||
|
||||
private fun scrollToSelectedCustomizationItem() {
|
||||
if (customizationMenuItems.isEmpty() || currentCustomizationMenuSelection < 0 || currentCustomizationMenuSelection >= customizationMenuItems.size) return
|
||||
|
||||
val selectedItem = customizationMenuItems[currentCustomizationMenuSelection]
|
||||
val scrollView = binding.customizationMenuScrollView
|
||||
|
||||
scrollView.post {
|
||||
try {
|
||||
val scrollBounds = Rect()
|
||||
scrollView.getHitRect(scrollBounds)
|
||||
|
||||
val itemLocation = IntArray(2)
|
||||
selectedItem.getLocationOnScreen(itemLocation)
|
||||
|
||||
val scrollLocation = IntArray(2)
|
||||
scrollView.getLocationOnScreen(scrollLocation)
|
||||
|
||||
val itemY = itemLocation[1] - scrollLocation[1]
|
||||
val itemTop = itemY
|
||||
val itemBottom = itemY + selectedItem.height
|
||||
val visibleHeight = scrollView.height
|
||||
val padding = 50
|
||||
val scrollY = scrollView.scrollY
|
||||
|
||||
if (itemTop < padding) {
|
||||
scrollView.smoothScrollTo(0, scrollY + (itemTop - padding))
|
||||
} else if (itemBottom > visibleHeight - padding) {
|
||||
scrollView.smoothScrollTo(0, scrollY + (itemBottom - visibleHeight + padding))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error scrolling to selected customization item", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun activateSelectedCustomizationMenuItem() {
|
||||
if (customizationMenuItems.isEmpty() || currentCustomizationMenuSelection < 0 || currentCustomizationMenuSelection >= customizationMenuItems.size) return
|
||||
|
||||
val selectedItem = customizationMenuItems[currentCustomizationMenuSelection]
|
||||
gameHaptics.vibrateForPieceLock()
|
||||
|
||||
when (selectedItem) {
|
||||
is ThemeSelector -> {
|
||||
selectedItem.confirmSelection()
|
||||
Handler(Looper.getMainLooper()).postDelayed({ showCustomizationMenu() }, 100)
|
||||
}
|
||||
is BlockSkinSelector -> {
|
||||
selectedItem.confirmSelection()
|
||||
// The onBlockSkinSelected callback will handle updating the game view and saving the selection
|
||||
}
|
||||
else -> {
|
||||
selectedItem.performClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
app/src/main/java/com/mintris/ThemeManager.kt
Normal file
19
app/src/main/java/com/mintris/ThemeManager.kt
Normal file
|
@ -0,0 +1,19 @@
|
|||
package com.mintris
|
||||
|
||||
import android.graphics.Color
|
||||
|
||||
object ThemeManager {
|
||||
data class ThemeColors(
|
||||
val background: Int,
|
||||
val text: Int,
|
||||
val accent: Int
|
||||
)
|
||||
|
||||
fun getThemeColors(): ThemeColors {
|
||||
return ThemeColors(
|
||||
background = Color.BLACK,
|
||||
text = Color.WHITE,
|
||||
accent = Color.WHITE
|
||||
)
|
||||
}
|
||||
}
|
6
app/src/main/res/drawable/menu_section_background.xml
Normal file
6
app/src/main/res/drawable/menu_section_background.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#80000000" />
|
||||
<corners android:radius="16dp" />
|
||||
</shape>
|
|
@ -421,22 +421,23 @@
|
|||
android:src="@drawable/ic_volume_up"
|
||||
android:contentDescription="@string/music" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Theme Selector -->
|
||||
<com.mintris.ui.ThemeSelector
|
||||
android:id="@+id/inPauseThemeSelector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<!-- Block Skin Selector -->
|
||||
<com.mintris.ui.BlockSkinSelector
|
||||
android:id="@+id/inPauseBlockSkinSelector"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
<!-- Customization Button -->
|
||||
<Button
|
||||
android:id="@+id/customizationButton"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/customization"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textAllCaps="false"
|
||||
android:singleLine="true"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
@ -623,4 +624,97 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Customization Menu overlay -->
|
||||
<LinearLayout
|
||||
android:id="@+id/customizationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginBottom="32dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/customizationTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/customization"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:fontFamily="sans-serif"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textAllCaps="false"
|
||||
android:singleLine="true" />
|
||||
|
||||
<com.mintris.ui.LevelBadge
|
||||
android:id="@+id/customizationLevelBadge"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/customizationMenuScrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:scrollbars="none"
|
||||
android:overScrollMode="never"
|
||||
android:fillViewport="true"
|
||||
android:paddingBottom="32dp"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="32dp">
|
||||
|
||||
<!-- Theme Selector -->
|
||||
<com.mintris.ui.ThemeSelector
|
||||
android:id="@+id/customizationThemeSelector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
|
||||
<!-- Block Skin Selector -->
|
||||
<com.mintris.ui.BlockSkinSelector
|
||||
android:id="@+id/customizationBlockSkinSelector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
|
||||
<!-- Back Button -->
|
||||
<Button
|
||||
android:id="@+id/customizationBackButton"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/back"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textAllCaps="false"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -518,22 +518,104 @@
|
|||
android:src="@drawable/ic_volume_up"
|
||||
android:contentDescription="@string/music" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<!-- Customization Button -->
|
||||
<Button
|
||||
android:id="@+id/customizationButton"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/customization"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textAllCaps="false" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Customization Menu overlay -->
|
||||
<LinearLayout
|
||||
android:id="@+id/customizationContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginBottom="32dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/customizationTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/customization"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:fontFamily="sans-serif"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textAllCaps="false"
|
||||
android:singleLine="true" />
|
||||
|
||||
<com.mintris.ui.LevelBadge
|
||||
android:id="@+id/customizationLevelBadge"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/customizationMenuScrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:scrollbars="none"
|
||||
android:overScrollMode="never"
|
||||
android:fillViewport="false">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="32dp">
|
||||
|
||||
<!-- Theme Selector -->
|
||||
<com.mintris.ui.ThemeSelector
|
||||
android:id="@+id/themeSelector"
|
||||
android:id="@+id/customizationThemeSelector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<!-- Block Skin Selector -->
|
||||
<com.mintris.ui.BlockSkinSelector
|
||||
android:id="@+id/blockSkinSelector"
|
||||
android:id="@+id/customizationBlockSkinSelector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- Back Button -->
|
||||
<Button
|
||||
android:id="@+id/customizationBackButton"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
android:layout_marginTop="32dp"
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/back"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textAllCaps="false" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -47,4 +47,5 @@
|
|||
<string name="tetrises">tetrises: %d</string>
|
||||
<string name="reset_stats">reset stats</string>
|
||||
<string name="music">music</string>
|
||||
<string name="customization">Customization</string>
|
||||
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue