Improve exit animation of the selected message menu#6191
Conversation
PR checklist ✅All required conditions are satisfied:
🎉 Great job! This PR is ready for review. |
SDK Size Comparison 📏
|
WalkthroughThe SelectedMessageMenu animation system is updated to replace animation easing, introduce coroutine-based dismissal with animation-out sequences before invoking callbacks, restructure animation initialization outside Dialog content, and configure window animation disabling and blur effects. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt (1)
126-132: Document the newonDismisstiming semantics in KDoc.
onDismissnow executes after exit animation (not immediately on request). Please document this behavioral change and expected calling thread/state for the publicSelectedMessageMenuAPI.As per coding guidelines,
**/*.kt: "Document public APIs with KDoc, including thread expectations and state notes".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt` around lines 126 - 132, Update the public KDoc for SelectedMessageMenu to state that the onDismiss callback is invoked only after the exit animation completes (not immediately when dismissal is requested), that the callback is called from the coroutine scope used by the component (it may be executed within a NonCancellable context during the animation cleanup), and note any relevant UI/state expectations (e.g., it runs off the main thread if launched on a background scope or on the main thread if the component scope is Main). Add these timing and thread/state semantics next to the SelectedMessageMenu declaration and reference the animatedDismiss/onDismiss behavior so callers know to avoid relying on immediate execution.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt`:
- Around line 121-124: The rememberMenuAnimation call creates a
MenuAnimationState once and never updates when bounds change; update the
remember usage to include dependency keys so the state is recreated when
relevant inputs change (e.g., pass LocalSelectedMessageBounds.current?.value and
messageAlignment as keys to remember or to rememberMenuAnimation if it accepts
keys), and replace LaunchedEffect(Unit) that starts the animation with a
LaunchedEffect keyed on the changing bounds/state (for example
LaunchedEffect(sourceBounds) or LaunchedEffect(animation) ) so the animation
re-triggers when LocalSelectedMessageBounds.current?.value or messageAlignment
changes; update references to MenuAnimationState, rememberMenuAnimation,
LocalSelectedMessageBounds.current?.value, and the LaunchedEffect invocation
accordingly.
- Around line 126-134: The animatedDismiss lambda currently can be invoked
concurrently causing multiple coroutines to call animation.animateOut() and
onDismiss() repeatedly; fix by adding a single-entry guard (e.g., an
AtomicBoolean flag or a Mutex/Job check) inside the remember block that ensures
only the first invocation proceeds to launch the coroutine which calls
animation.animateOut() and then onDismiss(), and subsequent calls return
immediately; update the KDoc for the onDismiss parameter to state it is invoked
asynchronously once after the exit animation completes.
---
Nitpick comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt`:
- Around line 126-132: Update the public KDoc for SelectedMessageMenu to state
that the onDismiss callback is invoked only after the exit animation completes
(not immediately when dismissal is requested), that the callback is called from
the coroutine scope used by the component (it may be executed within a
NonCancellable context during the animation cleanup), and note any relevant
UI/state expectations (e.g., it runs off the main thread if launched on a
background scope or on the main thread if the component scope is Main). Add
these timing and thread/state semantics next to the SelectedMessageMenu
declaration and reference the animatedDismiss/onDismiss behavior so callers know
to avoid relying on immediate execution.
ℹ️ Review info
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt
.../java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt
Show resolved
Hide resolved
.../java/io/getstream/chat/android/compose/ui/components/selectedmessage/SelectedMessageMenu.kt
Show resolved
Hide resolved
|


Goal
Update selected message menu with a custom exit animation
Implementation
Note: there is still some polishing to do that I'm already aware of (e.g. proper handling of the message footer, pinned state). For this PR, I'm focusing just on the animation.
🎨 UI Changes
Screen_recording_20260225_134503.mp4
Testing
The new animation can be checked as always in the sample
Summary by CodeRabbit
Release Notes