Browse Source

fix: add lifecycle owner to ComposeView in overlay

- Create OverlayLifecycleOwner implementing LifecycleOwner and SavedStateRegistryOwner
- Set ViewTreeLifecycleOwner and ViewTreeSavedStateRegistryOwner on ComposeView
- Manage lifecycle states (onCreate, onStart, onResume, onDestroy) for overlay
- Fixes: ViewTreeLifecycleOwner not found exception when using ComposeView in overlay

Error: java.lang.IllegalStateException: ViewTreeLifecycleOwner not found
Solution: Provide custom lifecycle owner for overlay context

🤖 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
3de42c27f3
  1. 49
      app/src/main/java/com/quillstudios/pokegoalshelper/ui/FloatingComposeOverlay.kt

49
app/src/main/java/com/quillstudios/pokegoalshelper/ui/FloatingComposeOverlay.kt

@ -7,6 +7,14 @@ import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.ViewTreeLifecycleOwner
import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
import androidx.savedstate.ViewTreeSavedStateRegistryOwner
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.gestures.detectDragGestures
@ -30,6 +38,38 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.quillstudios.pokegoalshelper.ui.theme.PokeGoalsHelperTheme
/**
* Simple lifecycle owner for ComposeView in overlay context
*/
class OverlayLifecycleOwner : LifecycleOwner, SavedStateRegistryOwner {
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
private val savedStateRegistryController = SavedStateRegistryController.create(this)
init {
savedStateRegistryController.performRestore(null)
lifecycleRegistry.currentState = Lifecycle.State.CREATED
}
fun onCreate() {
lifecycleRegistry.currentState = Lifecycle.State.CREATED
}
fun onStart() {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
}
fun onResume() {
lifecycleRegistry.currentState = Lifecycle.State.RESUMED
}
fun onDestroy() {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}
override val lifecycle: Lifecycle = lifecycleRegistry
override val savedStateRegistry: SavedStateRegistry = savedStateRegistryController.savedStateRegistry
}
/**
* True floating overlay using WindowManager + ComposeView.
* This creates a proper system overlay that floats over all apps.
@ -48,6 +88,7 @@ class FloatingComposeOverlay(
private var windowManager: WindowManager? = null
private var overlayView: ComposeView? = null
private var isShowing = false
private val lifecycleOwner = OverlayLifecycleOwner()
// Mutable state for Compose
private var fabPosition = mutableStateOf(Offset.Zero)
@ -57,6 +98,9 @@ class FloatingComposeOverlay(
try {
windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
lifecycleOwner.onCreate()
lifecycleOwner.onStart()
lifecycleOwner.onResume()
createOverlayView()
isShowing = true
Log.d(TAG, "✅ Floating Compose overlay shown")
@ -69,6 +113,7 @@ class FloatingComposeOverlay(
if (!isShowing) return
try {
lifecycleOwner.onDestroy()
overlayView?.let { windowManager?.removeView(it) }
overlayView = null
windowManager = null
@ -81,6 +126,10 @@ class FloatingComposeOverlay(
private fun createOverlayView() {
overlayView = ComposeView(context).apply {
// Set lifecycle owner for ComposeView
ViewTreeLifecycleOwner.set(this, lifecycleOwner)
ViewTreeSavedStateRegistryOwner.set(this, lifecycleOwner)
setContent {
PokeGoalsHelperTheme {
FloatingFABContent(

Loading…
Cancel
Save