From 03376af446d2c2b56cecb43f10d496b27437da9e Mon Sep 17 00:00:00 2001 From: iris-ai <4+iris-ai@noreply.localhost> Date: Thu, 17 Sep 2026 14:13:05 -0400 Subject: [PATCH] Fix panel drag release flicker --- .../kotlin/com/example/aiapp/SubagentPanel.kt | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/app/androidApp/src/main/kotlin/com/example/aiapp/SubagentPanel.kt b/app/androidApp/src/main/kotlin/com/example/aiapp/SubagentPanel.kt index e5443f2..035a2dd 100644 --- a/app/androidApp/src/main/kotlin/com/example/aiapp/SubagentPanel.kt +++ b/app/androidApp/src/main/kotlin/com/example/aiapp/SubagentPanel.kt @@ -1,7 +1,7 @@ package com.example.aiapp import androidx.activity.compose.BackHandler -import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.Animatable import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -73,29 +73,39 @@ fun SubagentPanel( onOpenSubagent: (SubagentSummary) -> Unit, content: @Composable () -> Unit, ) { + val scope = rememberCoroutineScope() var open by remember(summary.id) { mutableStateOf(false) } var dragging by remember(summary.id) { mutableStateOf(false) } var draggedReveal by remember(summary.id) { mutableFloatStateOf(0f) } - val animatedReveal by animateFloatAsState(if (open) 1f else 0f, label = "subagent panel") - val reveal = if (dragging) draggedReveal else animatedReveal + val animatedReveal = remember(summary.id) { Animatable(0f) } + val reveal = if (dragging) draggedReveal else animatedReveal.value val flingThreshold = with(LocalDensity.current) { FLING_THRESHOLD.toPx() } - fun startDrag() { - draggedReveal = reveal + suspend fun startDrag() { + animatedReveal.stop() + draggedReveal = animatedReveal.value dragging = true } - fun finishDrag(velocity: Float) { - open = + suspend fun finishDrag(velocity: Float) { + val targetOpen = when { velocity < -flingThreshold -> true velocity > flingThreshold -> false else -> draggedReveal >= OPEN_THRESHOLD } + open = targetOpen + animatedReveal.snapTo(draggedReveal) dragging = false + animatedReveal.animateTo(if (targetOpen) 1f else 0f) } - BackHandler(enabled = open) { open = false } + fun setOpen(targetOpen: Boolean) { + open = targetOpen + scope.launch { animatedReveal.animateTo(if (targetOpen) 1f else 0f) } + } + + BackHandler(enabled = open) { setOpen(false) } BoxWithConstraints(Modifier.fillMaxSize()) { val panelWidth = maxWidth * 0.88f @@ -126,7 +136,7 @@ fun SubagentPanel( .alpha(reveal * 0.32f) .background(MaterialTheme.colorScheme.scrim) .semantics { contentDescription = "Dismiss subagent panel" } - .clickable { open = false } + .clickable { setOpen(false) } ) } @@ -144,7 +154,7 @@ fun SubagentPanel( settings = settings, summary = summary, active = open, - onClose = { open = false }, + onClose = { setOpen(false) }, onOpenSubagent = onOpenSubagent, ) }