From 3de42c27f334b3494992cda042a403eb2887c4d2 Mon Sep 17 00:00:00 2001 From: Quildra Date: Fri, 1 Aug 2025 08:11:53 +0100 Subject: [PATCH] fix: add lifecycle owner to ComposeView in overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .../ui/FloatingComposeOverlay.kt | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/app/src/main/java/com/quillstudios/pokegoalshelper/ui/FloatingComposeOverlay.kt b/app/src/main/java/com/quillstudios/pokegoalshelper/ui/FloatingComposeOverlay.kt index 29ca8f7..a4eec42 100644 --- a/app/src/main/java/com/quillstudios/pokegoalshelper/ui/FloatingComposeOverlay.kt +++ b/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(