|
|
|
@ -1,7 +1,5 @@ |
|
|
|
package com.quillstudios.pokegoalshelper.ui |
|
|
|
|
|
|
|
import android.animation.Animator |
|
|
|
import android.animation.AnimatorListenerAdapter |
|
|
|
import android.animation.ObjectAnimator |
|
|
|
import android.animation.ValueAnimator |
|
|
|
import android.content.Context |
|
|
|
@ -9,11 +7,8 @@ import android.content.pm.PackageManager |
|
|
|
import android.graphics.PixelFormat |
|
|
|
import android.graphics.drawable.GradientDrawable |
|
|
|
import android.os.Build |
|
|
|
import android.os.Handler |
|
|
|
import android.os.Looper |
|
|
|
import android.os.VibrationEffect |
|
|
|
import android.os.Vibrator |
|
|
|
import android.util.Log |
|
|
|
import android.util.TypedValue |
|
|
|
import android.view.* |
|
|
|
import android.view.animation.AccelerateDecelerateInterpolator |
|
|
|
@ -41,13 +36,11 @@ class EnhancedFloatingFAB( |
|
|
|
private val onClose: () -> Unit |
|
|
|
) { |
|
|
|
companion object { |
|
|
|
private const val TAG = "EnhancedFloatingFAB" |
|
|
|
private const val FAB_SIZE_DP = 56 |
|
|
|
private const val MINI_FAB_SIZE_DP = 40 |
|
|
|
private const val EDGE_SNAP_THRESHOLD_DP = 50 |
|
|
|
private const val SNAP_ANIMATION_DURATION = 300L |
|
|
|
private const val MENU_ANIMATION_DURATION = 250L |
|
|
|
private const val AUTO_HIDE_DELAY = 3000L |
|
|
|
} |
|
|
|
|
|
|
|
private var windowManager: WindowManager? = null |
|
|
|
@ -70,8 +63,6 @@ class EnhancedFloatingFAB( |
|
|
|
private var initialY = 0 |
|
|
|
|
|
|
|
private val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator |
|
|
|
private val handler = Handler(Looper.getMainLooper()) |
|
|
|
private var autoHideRunnable: Runnable? = null |
|
|
|
|
|
|
|
fun show() { |
|
|
|
if (isShowing) return |
|
|
|
@ -80,9 +71,8 @@ class EnhancedFloatingFAB( |
|
|
|
windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager |
|
|
|
createFloatingView() |
|
|
|
isShowing = true |
|
|
|
Log.d(TAG, "✅ Enhanced floating FAB shown") |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "❌ Error showing enhanced floating FAB", e) |
|
|
|
// Silently handle errors |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -104,10 +94,8 @@ class EnhancedFloatingFAB( |
|
|
|
menuParams = null |
|
|
|
windowManager = null |
|
|
|
isShowing = false |
|
|
|
handler.removeCallbacksAndMessages(null) |
|
|
|
Log.d(TAG, "🗑️ Enhanced floating FAB hidden") |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "❌ Error hiding enhanced floating FAB", e) |
|
|
|
// Silently handle errors |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -304,12 +292,10 @@ class EnhancedFloatingFAB( |
|
|
|
// 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( |
|
|
|
@ -347,7 +333,6 @@ class EnhancedFloatingFAB( |
|
|
|
initialTouchY = event.rawY |
|
|
|
initialX = currentX |
|
|
|
initialY = currentY |
|
|
|
cancelAutoHide() |
|
|
|
true |
|
|
|
} |
|
|
|
|
|
|
|
@ -373,7 +358,6 @@ class EnhancedFloatingFAB( |
|
|
|
MotionEvent.ACTION_UP -> { |
|
|
|
if (isDragging) { |
|
|
|
snapToEdgeIfNeeded() |
|
|
|
// scheduleAutoHide() // Disabled - no auto-hide after drag |
|
|
|
} else { |
|
|
|
// Handle click |
|
|
|
performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) |
|
|
|
@ -382,7 +366,6 @@ class EnhancedFloatingFAB( |
|
|
|
} else { |
|
|
|
showMenu() |
|
|
|
} |
|
|
|
// scheduleAutoHide() // Disabled - menu stays open until manually closed |
|
|
|
} |
|
|
|
isDragging = false |
|
|
|
true |
|
|
|
@ -402,7 +385,7 @@ class EnhancedFloatingFAB( |
|
|
|
try { |
|
|
|
windowManager?.updateViewLayout(fab, params) |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "Failed to update FAB position", e) |
|
|
|
// Silently handle errors |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -436,11 +419,9 @@ class EnhancedFloatingFAB( |
|
|
|
// 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}") |
|
|
|
} |
|
|
|
|
|
|
|
// Determine vertical positioning with bounds checking |
|
|
|
@ -453,18 +434,15 @@ class EnhancedFloatingFAB( |
|
|
|
// Menu would go off bottom - adjust upward with safety margin |
|
|
|
val adjustedY = safeScreenHeight - menuHeight |
|
|
|
params.y = maxOf(0, adjustedY) // Ensure we don't go off top either |
|
|
|
Log.d(TAG, "Menu adjusted up: desired Y=$desiredY, adjusted Y=${params.y} (menu height=$menuHeight, safe screen height=$safeScreenHeight)") |
|
|
|
} else { |
|
|
|
// Menu fits normally - align with FAB top |
|
|
|
params.y = desiredY |
|
|
|
Log.d(TAG, "Menu positioned normally at Y=${params.y}") |
|
|
|
} |
|
|
|
|
|
|
|
Log.d(TAG, "Final menu position: x=${params.x}, y=${params.y}, size=${menuWidth}x${menuHeight}, FAB at: x=$currentX, y=$currentY") |
|
|
|
try { |
|
|
|
windowManager?.updateViewLayout(menu, params) |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "Failed to update menu position", e) |
|
|
|
// Silently handle errors |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -508,8 +486,6 @@ class EnhancedFloatingFAB( |
|
|
|
private fun showMenu() { |
|
|
|
if (isMenuExpanded) return |
|
|
|
|
|
|
|
Log.d(TAG, "showMenu() called") |
|
|
|
|
|
|
|
// Update menu layout for current position |
|
|
|
updateMenuLayout() |
|
|
|
|
|
|
|
@ -518,11 +494,9 @@ class EnhancedFloatingFAB( |
|
|
|
|
|
|
|
// Add menu window |
|
|
|
menuContainer?.let { container -> |
|
|
|
Log.d(TAG, "Adding menu container to WindowManager") |
|
|
|
container.visibility = View.VISIBLE |
|
|
|
windowManager?.addView(container, menuParams) |
|
|
|
isMenuExpanded = true |
|
|
|
Log.d(TAG, "Menu window added, isMenuExpanded = $isMenuExpanded") |
|
|
|
|
|
|
|
// Animate menu items in |
|
|
|
for (i in 0 until container.childCount) { |
|
|
|
@ -558,7 +532,7 @@ class EnhancedFloatingFAB( |
|
|
|
windowManager?.removeView(container) |
|
|
|
isMenuExpanded = false |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "Failed to remove menu window", e) |
|
|
|
// Silently handle errors |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -566,25 +540,10 @@ class EnhancedFloatingFAB( |
|
|
|
mainFAB?.background = createFABBackground(android.R.color.holo_blue_bright) |
|
|
|
} |
|
|
|
|
|
|
|
private fun scheduleAutoHide() { |
|
|
|
cancelAutoHide() |
|
|
|
autoHideRunnable = Runnable { |
|
|
|
if (isMenuExpanded) { |
|
|
|
hideMenu() |
|
|
|
} |
|
|
|
} |
|
|
|
handler.postDelayed(autoHideRunnable!!, AUTO_HIDE_DELAY) |
|
|
|
} |
|
|
|
|
|
|
|
private fun cancelAutoHide() { |
|
|
|
autoHideRunnable?.let { handler.removeCallbacks(it) } |
|
|
|
autoHideRunnable = null |
|
|
|
} |
|
|
|
|
|
|
|
private fun performHapticFeedback(feedbackType: Int) { |
|
|
|
// Check if we have vibrate permission |
|
|
|
if (context.checkSelfPermission(android.Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED) { |
|
|
|
Log.w(TAG, "Vibrate permission not granted, skipping haptic feedback") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
@ -595,10 +554,8 @@ class EnhancedFloatingFAB( |
|
|
|
@Suppress("DEPRECATION") |
|
|
|
vibrator.vibrate(25) |
|
|
|
} |
|
|
|
} catch (e: SecurityException) { |
|
|
|
Log.w(TAG, "SecurityException during vibrate: ${e.message}") |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "Exception during vibrate: ${e.message}") |
|
|
|
// Silently handle vibration errors |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|