Browse Source

feat: implement adaptive menu positioning and layout flipping

- Add automatic menu side detection based on FAB center position
- Menu appears on right when FAB is on left side of screen (and vice versa)
- Flip menu item layout order based on FAB position:
  - Left side: [MiniFAB][Label] (mini FAB closest to main FAB)
  - Right side: [Label][MiniFAB] (mini FAB closest to main FAB)
- Adjust container gravity and item margins for proper alignment
- Add debug logging for layout decisions

This creates a symmetrical UX where mini FABs are always closest
to the main FAB and labels extend outward, preventing off-screen
menu items regardless of FAB position.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
feature/modern-capture-ui
Quildra 5 months ago
parent
commit
dd9554dfe3
  1. 70
      app/src/main/java/com/quillstudios/pokegoalshelper/ui/EnhancedFloatingFAB.kt

70
app/src/main/java/com/quillstudios/pokegoalshelper/ui/EnhancedFloatingFAB.kt

@ -160,13 +160,9 @@ class EnhancedFloatingFAB(
PixelFormat.TRANSLUCENT
).apply {
gravity = Gravity.TOP or Gravity.START
// Position menu to the left of FAB with proper spacing
val menuWidth = 200
val padding = dpToPx(8) // 8dp padding between menu and FAB
// Menu's right edge should align with FAB's left edge minus padding
x = maxOf(0, this@EnhancedFloatingFAB.currentX - menuWidth - padding)
y = this@EnhancedFloatingFAB.currentY // Same vertical position as FAB
// Initial positioning will be updated by updateMenuPosition() when menu is shown
x = 0
y = this@EnhancedFloatingFAB.currentY
}
// Add main FAB window
@ -217,9 +213,17 @@ class EnhancedFloatingFAB(
// Clear existing items
container.removeAllViews()
// Menu items should align to the right edge of the menu container
// so they appear closest to the main FAB
(container as LinearLayout).gravity = Gravity.TOP or Gravity.END
// Determine which side of screen the FAB is on for layout decisions
val screenWidth = getScreenSize().first
val fabCenterX = currentX + dpToPx(FAB_SIZE_DP) / 2
val isOnLeftSide = fabCenterX < screenWidth / 2
// Menu items should align appropriately based on FAB position
(container as LinearLayout).gravity = if (isOnLeftSide) {
Gravity.TOP or Gravity.START // Left align when menu is on right
} else {
Gravity.TOP or Gravity.END // Right align when menu is on left
}
// Add menu items with appropriate layout
val menuItems = listOf(
@ -245,13 +249,13 @@ class EnhancedFloatingFAB(
)
menuItems.forEach { item ->
val menuRow = createMenuRow(item)
val menuRow = createMenuRow(item, isOnLeftSide)
container.addView(menuRow)
}
}
}
private fun createMenuRow(item: MenuItemData): LinearLayout {
private fun createMenuRow(item: MenuItemData, isOnLeftSide: Boolean): LinearLayout {
return LinearLayout(context).apply {
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.CENTER_VERTICAL
@ -267,7 +271,12 @@ class EnhancedFloatingFAB(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).apply {
setMargins(0, 0, dpToPx(8), 0) // 8dp space between label and mini FAB
// Adjust margins based on layout direction
if (isOnLeftSide) {
setMargins(dpToPx(8), 0, 0, 0) // Space on left when FAB comes first
} else {
setMargins(0, 0, dpToPx(8), 0) // Space on right when label comes first
}
}
}
@ -290,9 +299,18 @@ class EnhancedFloatingFAB(
)
}
// Always: LABEL → FAB (label on left, mini FAB on right, closest to main FAB)
addView(label)
addView(miniFAB)
// Layout order depends on FAB position
if (isOnLeftSide) {
// FAB on left side: FAB → LABEL (mini FAB closest to main FAB)
addView(miniFAB)
addView(label)
Log.d(TAG, "Menu row: FAB → LABEL (FAB on left side)")
} else {
// FAB on right side: LABEL → FAB (mini FAB closest to main FAB)
addView(label)
addView(miniFAB)
Log.d(TAG, "Menu row: LABEL → FAB (FAB on right side)")
}
layoutParams = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
@ -405,12 +423,26 @@ class EnhancedFloatingFAB(
)
val menuWidth = menu.measuredWidth
val padding = dpToPx(8) // 8dp padding between menu and FAB
val screenWidth = getScreenSize().first
val fabCenterX = currentX + dpToPx(FAB_SIZE_DP) / 2
// Determine if FAB is on left or right side of screen
val isOnLeftSide = fabCenterX < screenWidth / 2
if (isOnLeftSide) {
// FAB on left side - menu appears to the right
val fabRightEdge = currentX + dpToPx(FAB_SIZE_DP)
params.x = fabRightEdge + padding
Log.d(TAG, "FAB on left side - menu to right at x=${params.x}")
} else {
// FAB on right side - menu appears to the left
params.x = maxOf(0, currentX - menuWidth - padding)
Log.d(TAG, "FAB on right side - menu to left at x=${params.x}")
}
// Menu's right edge should align with FAB's left edge minus padding
params.x = maxOf(0, currentX - menuWidth - padding)
params.y = currentY // Same vertical position as FAB (top alignment)
Log.d(TAG, "Menu position: x=${params.x}, y=${params.y}, measured width=${menuWidth}, FAB at: x=$currentX, y=$currentY")
Log.d(TAG, "Menu position: x=${params.x}, y=${params.y}, measured width=${menuWidth}, FAB center: x=$fabCenterX, screen width: $screenWidth")
try {
windowManager?.updateViewLayout(menu, params)
} catch (e: Exception) {

Loading…
Cancel
Save