Skip to content

Align modal bottom sheets with Figma#6480

Draft
andremion wants to merge 9 commits into
developfrom
refactor/compose-modal-bottom-sheets
Draft

Align modal bottom sheets with Figma#6480
andremion wants to merge 9 commits into
developfrom
refactor/compose-modal-bottom-sheets

Conversation

@andremion
Copy link
Copy Markdown
Contributor

@andremion andremion commented May 29, 2026

Closes AND-1203

Goal

Align every modal bottom sheet in the Compose SDK with the Figma design. The audit started from a dark-mode regression on the attachment command picker (it inherited M3's light surfaceContainerLow because the callsite didn't pass a containerColor) and revealed that modal bottom sheets across the SDK had each chosen their own values for shape, scrim, container color, and drag handle — none matching the Figma tokens, and three sheets bypassing M3 entirely with Popup+AnimatedVisibility or Box+Surface. Three deliverables fall out:

  1. Two opinionated wrappers — StreamCardBottomSheet and StreamScreenBottomSheet — bake the Figma tokens (corner radii, elevation/app surface, scrim, drag handle, max width) in one place. Every ModalBottomSheet callsite in the SDK now goes through them.
  2. ChannelActionsSheet replaces SelectedChannelMenu (deprecated, removed in v8) as a more discoverable, Figma-aligned channel-actions surface.
  3. @Preview and Paparazzi rendering — every sheet has light + dark snapshot coverage so future Figma drift surfaces at PR review instead of in production.

Implementation

Two internal wrappers consolidate sheet construction:

  • StreamCardBottomSheet — card sitting above the app: 32dp top corners, backgroundCoreElevation1 container, backgroundCoreScrim scrim, M3 drag handle.
  • StreamScreenBottomSheet — full-takeover surface: sheetMaxWidth = Dp.Unspecified, rectangular, no drag handle, backgroundCoreApp container.

Every modal bottom sheet in the SDK now goes through one of those two wrappers, including three that were previously built from Box+Surface or Popup+AnimatedVisibility (MediaGalleryPhotosMenu, PollAnswers, PollMoreOptionsDialog) — they inherit drag handle, swipe-to-dismiss, and scrim from M3 for free.

SelectedChannelMenu and SimpleMenu are marked @Deprecated (removal in v8) in favour of ChannelActionsSheet, a public @Composable built on StreamCardBottomSheet. The factory hook ChatComponentFactory.ChannelMenu delegates to the new sheet, so integrators using ChannelsScreen pick up the new rendering automatically; the sample's MyCustomUi is also migrated. SelectedChannelMenu keeps its existing public surface and develop-aligned defaults (16dp shape, overlayColor, slot params) — the Figma redesign lives on ChannelActionsSheet, while the deprecated path stays visually close to develop until removal.

@Preview calls wrap each sheet in Box(Modifier.fillMaxSize()) so the layout has bounds for M3 to compute the sheet's Expanded anchor against — without that, M3's internal show LaunchedEffect skips and the preview stays blank. For Paparazzi (single-frame capture; M3's show animation doesn't tick to completion in one frame), a private rememberStreamSheetState returns a pre-expanded SheetState under LocalInspectionMode; the IDE preview pane runs the animation on its own, so that swap is exclusively a Paparazzi enabler. Both behaviours are documented in the wrappers' KDoc, including the Google Issue Tracker reference.

Also fixes a small visual misalignment: ChannelInfoMemberInfoModalSheetTopBar was stacking a hardcoded top = spacingMd on top of the M3 drag handle's inset.

🎨 UI Changes

The rendered output for every modal bottom sheet is captured by the Paparazzi snapshots under stream-chat-android-compose/src/test/snapshots/images/ — reviewing the diff there is the most reliable way to see the before/after across light and dark modes.

Testing

Run the Compose sample in dark mode.

  1. Open the message composer and trigger the attachment command picker (the original dark-mode bug). The sheet now renders with the dark elevation token, not M3's default light surfaceContainerLow.
  2. Long-press a channel in the channel list. The channel actions sheet renders with 32dp rounded top corners, drag handle, and the Figma-aligned scrim — both in light and dark modes.
  3. From the channel actions sheet, tap Channel Info → long-press a member. The member info sheet renders with the avatar aligned directly under the drag handle (no extra top padding stacking on top of M3's inset).
  4. Open a poll message and trigger each of the poll bottom sheets from its overflow menu (poll results, poll comments, more options). Each takes over the full screen with a rectangular sheet, no drag handle, system bar inset applied.
  5. Open a media attachment and trigger the gallery options menu and the photos menu. Both render as card sheets with the Stream scrim.
  6. Uncomment // MyCustomUi() at ChannelsActivity.kt:262 and re-run. Long-press a channel — confirm it opens ChannelActionsSheet (the new API), not the deprecated SelectedChannelMenu.

Automated coverage: Paparazzi snapshots (light + dark) for every modal bottom sheet in the SDK. ./gradlew :stream-chat-android-compose:verifyPaparazziDebug runs all 820 tests green. IDE-preview rendering was spot-checked on ChannelActionsSheet and PollMoreOptionsDialog; the same wrapping pattern (Box(Modifier.fillMaxSize())) is applied to every other affected preview.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced improved channel actions interface with a new sheet-based presentation for channel menu options.
  • Improvements

    • Enhanced consistency across bottom sheet components throughout the app for a unified user experience.
    • Simplified channel menu presentation with cleaner, more streamlined interface interactions.
    • Modernized dialog and menu components for improved visual consistency.
  • Deprecations

    • Deprecated legacy channel menu and action components in favor of new sheet-based alternatives (removal planned for v8).

Review Change Stack

andremion added 5 commits May 29, 2026 15:16
Fixes the dark-mode regression on the attachment command picker (it
inherited M3's light surfaceContainerLow because the callsite didn't
pass containerColor). All nine ModalBottomSheet callsites now go through
StreamCardBottomSheet or StreamScreenBottomSheet, which bake the
Figma-aligned tokens (backgroundCoreElevation1/backgroundCoreApp,
backgroundCoreScrim, radius/4xl, drag handle, sheetMaxWidth).

Adds light + dark snapshot coverage for every modal bottom sheet in the
SDK.
Replaces SelectedChannelMenu (now @deprecated, removed in v8) with a
Material 3 bottom sheet built on StreamCardBottomSheet. The old menu
stays for backwards compatibility — its shape/overlayColor/centered-Card
path keeps working.

Migrates MediaGalleryPhotosMenu, PollAnswers, and PollMoreOptionsDialog
from hand-rolled Box+Surface/Popup implementations to the Stream
wrappers, inheriting M3 semantics (drag handle, swipe-to-dismiss, scrim)
and the design tokens. Drops ChannelsScreen's redundant AnimatedVisibility
since the new sheet supplies its own animation.

Plumbs ChannelMenuHeaderContentParams.modifier (previously dead) through
the factory so the deprecated SelectedChannelMenu can express the 16dp
top inset it needs (no drag handle), while ChannelActionsSheet leaves it
empty.
Moves DefaultChannelMenuHeaderContent (renamed from
DefaultSelectedChannelMenuHeaderContent) and its private helpers to
ChannelActionsSheet.kt. When SelectedChannelMenu is removed in v8, the
old file becomes a single git rm.

No behavior change — the factory still delegates to the same function.
- Wrap @Preview calls in Box(Modifier.fillMaxSize()) so the underlying
  Dialog has bounds to compute sheet anchors; without it M3 skips its
  show animation and the preview stays blank.
- Add rememberStreamSheetState: under LocalInspectionMode it returns a
  pre-expanded SheetState. Paparazzi captures a single frame and won't
  tick M3's show LaunchedEffect, so a Hidden-initial sheet renders blank.
- Drop the body-extraction workaround on ChannelActionsSheet now that the
  real sheet path renders through both surfaces.
The StreamCardBottomSheet wrapper already includes the M3 drag handle,
which provides the top inset. The hardcoded top padding stacked on top
of that and misaligned the avatar against sibling sheets.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 29, 2026

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@andremion andremion added the pr:improvement Improvement label May 29, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 29, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.83 MB 5.83 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.07 MB 11.07 MB 0.00 MB 🟢
stream-chat-android-compose 12.46 MB 12.47 MB 0.01 MB 🟢

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
72.1% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@andremion
Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

The previous content-level Sample (`ReactionsMenuContentOneReaction` /
`ManyReactions`) bypassed the public `ReactionsMenu` composable and the
StreamCardBottomSheet wrapper — they predate sheet-level rendering being
viable in @Preview and Paparazzi. Now that both surfaces render the
real sheet path, drive the previews and snapshots through
`ReactionsMenuSample*` instead, which calls the public `ReactionsMenu`
end-to-end. Closes the 0% new-code coverage gap on the file.

Renames `ReactionsMenuContentTest` → `ReactionsMenuTest` and relocates
it under `ui.components.messageactions` (the package of the file under
test). Switches from `snapshotWithDarkMode` to `snapshot` + light/dark
pairs, matching the pattern used by every other sheet test.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Walkthrough

This PR consolidates bottom-sheet handling across the SDK by introducing reusable StreamCardBottomSheet and StreamScreenBottomSheet components, adding a new ChannelActionsSheet to replace SelectedChannelMenu, migrating dozens of existing bottom-sheet dialogs to use the new infrastructure, and comprehensively updating test coverage with explicit light/dark mode snapshots.

Changes

Bottom-Sheet Refactoring and Channel Actions UI

Layer / File(s) Summary
Stream bottom-sheet components and state management
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt
Introduces StreamCardBottomSheet (card-style rounded container) and StreamScreenBottomSheet (full-screen rectangle), each wrapping Material3 ModalBottomSheet with Stream theme colors/shapes. Adds rememberStreamSheetState helper that switches between rememberModalBottomSheetState (production) and rememberSaveable with custom SheetState.Saver (preview inspection mode for snapshot stability).
ChannelActionsSheet implementation with header content
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheet.kt
New public composable ChannelActionsSheet renders channel actions via Material3 bottom sheet delegated through ChatTheme.componentFactory. Includes DefaultChannelMenuHeaderContent with mute/pin icon logic, isChannelOrCounterpartMuted helper (checks channel mute and DM counterpart mute), HeaderTitleRow / HeaderStateIcon rendering, and preview fixtures.
SelectedChannelMenu deprecation and token updates
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/SelectedChannelMenu.kt
Marks SelectedChannelMenu as @Deprecated with replaceWith = ChannelActionsSheet(...) and v8 removal notice. Updates default shape from hardcoded 16dp to StreamTokens.radius4xl with explicit zero bottom-corner sizes. Adjusts header padding to use StreamTokens.spacingMd.
SimpleMenu deprecation marker
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/SimpleMenu.kt
Adds @Deprecated annotation directing users to ChannelActionsSheet or Material 3 ModalBottomSheet, scheduled for v8 removal.
Media gallery sheet migrations
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/, internal/
Migrates MediaGalleryPreviewOptionsMenu and MediaGalleryPhotosMenu from ModalBottomSheet to StreamCardBottomSheet, removes manual scrim overlays, adds MediaGalleryPhotosMenuSample composable using PreviewMessageData.
Channel media attachments preview sheet
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsGrid.kt
Updates preview UI from ModalBottomSheet to StreamScreenBottomSheet, adds ChannelMediaAttachmentsPreviewSheet internal composable and @Preview wrapper rendering items from PreviewMessageData.
Channel info member and edit screen sheets
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheet.kt, GroupChannelEditScreen.kt
ChannelInfoMemberInfoModalSheet replaces ModalBottomSheet with StreamCardBottomSheet, refactors preview to internal ChannelInfoMemberInfoSheet(banned: Boolean) helper. GroupChannelEditScreen image picker now uses StreamCardBottomSheet with @VisibleForTesting and @OptIn(ExperimentalMaterial3Api::class) annotations, adds ImagePickerSheetWith/NoRemove variants.
Reactions menu and attachment picker sheets
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenu.kt, ui/messages/attachments/AttachmentSystemPicker.kt
Migrates ReactionsMenu to StreamCardBottomSheet, adds AttachmentCommandPickerSheet composable wrapping AttachmentCommandPicker in StreamCardBottomSheet.
Poll component bottom-sheet migrations
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/
Replaces Popup + AnimatedVisibility with StreamScreenBottomSheet across PollAnswersDialog, PollMoreOptionsDialog, PollOptionVotesDialog, PollViewResultDialog. Adds systemBarsPadding() to dialog content, renames preview composables to Sheet variants (e.g., PollOptionVotesSheetLoading), adds @OptIn(ExperimentalMaterial3Api::class) annotations.
Channel menu screen and factory integration
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/ChannelsScreen.kt, ui/theme/ChatComponentFactory.kt
ChannelsScreen removes AnimatedVisibility wrapper for menu, renders conditionally on selectedChannel presence. ChatComponentFactory routes ChannelMenu factory to ChannelActionsSheet instead of SelectedChannelMenu, uses DefaultChannelMenuHeaderContent instead of deprecated header.
Sample app ChannelsActivity update
stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt
Replaces SelectedChannelMenu with ChannelActionsSheet in custom UI, updates imports, adjusts documentation to describe new sheet behavior.
API surface changes from Compose compiler
stream-chat-android-compose/api/stream-chat-android-compose.api
Compiler-generated ComposableSingletons lambda getters updated; new ChannelActionsSheet function and ComposableSingletons$ChannelActionsSheetKt singleton added to public API; various getLambda$... entries regenerated.

Test Snapshot Coverage Updates

Layer / File(s) Summary
Gallery and attachments preview tests
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/*, ui/channel/attachments/ChannelMediaAttachmentsPreviewSheetTest.kt
Updates MediaGalleryPreviewOptionsMenuTest to explicit snapshot(isInDarkMode = ...) pattern with helper composables, adds new MediaGalleryPhotosMenuTest and ChannelMediaAttachmentsPreviewSheetTest with light/dark snapshots and connection state mocking.
Channel info and image picker tests
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheetTest.kt, GroupChannelEditScreenTest.kt
Simplifies ChannelInfoMemberInfoModalSheetTest to direct snapshot rendering with ChannelInfoMemberInfoSheet helper, removes modal state management. Updates GroupChannelEditScreenTest to snapshot ImagePickerSheetWith/NoRemove variants.
Selected channel menu snapshots
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/SelectedChannelMenuTest.kt
Refactors to explicit snapshot(isInDarkMode = true) pattern for dark-mode variants across all dialog styles.
Poll component tests with refactored snapshots
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/*Test.kt
Updates PollAnswersTest, PollMoreOptionsDialogTest, PollOptionVotesDialogTest, PollViewResultDialogTest to explicit light/dark snapshot methods, renames preview composables to Sheet variants, preserves all dark-mode coverage.
Reactions picker and attachment system tests
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPickerTest.kt, ui/messages/attachments/AttachmentSystemPickerTest.kt
Updates ReactionsPickerTest to snapshot ReactionsPicker with explicit light/dark modes, adds new AttachmentCommandPickerSheet test entries.
New ChannelActionsSheet test suite
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheetTest.kt
Introduces new test class with Paparazzi configuration for Pixel 2, includes light and dark mode snapshot tests for the new sheet component.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • GetStream/stream-chat-android#6474: Both PRs modify the channel "selected channel" UI header to show mute/pin state, but this PR swaps the implementation from SelectedChannelMenu to the new ChannelActionsSheet.

Suggested reviewers

  • gpunto

🐰 Hops through the sheets with glee 🎉
Bottom-sheets now reusable, tests snapshot bright,
Channel actions unified—the UI feels just right!
Old menus deprecated, new paths take flight,
Polls and pickers dancing in Material light!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.47% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Align modal bottom sheets with Figma' clearly summarizes the main change: consolidating modal bottom sheet implementations across the SDK to align with Figma design tokens.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering goal, implementation details, UI changes, and testing instructions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/compose-modal-bottom-sheets

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt (1)

358-368: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Dismiss the sheet before handling ViewInfo.

Line 362 passes ::viewChannelInfo straight into buildDefaultChannelActions, so the sample skips the dismissChannelAction() call that ChannelsScreen performs before navigation. That leaves selectedChannel set when the user comes back from the info screen, so the sheet can reopen immediately.

Suggested fix
                 val channelActions = buildDefaultChannelActions(
                     selectedChannel = selectedChannel,
                     ownCapabilities = selectedChannel.ownCapabilities,
                     viewModel = channelsViewModel,
-                    onViewInfoAction = ::viewChannelInfo,
+                    onViewInfoAction = { channel ->
+                        channelsViewModel.dismissChannelAction()
+                        viewChannelInfo(channel)
+                    },
                 )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt`
around lines 358 - 368, The sample passes ::viewChannelInfo directly into
buildDefaultChannelActions which skips dismissing the sheet first; change the
callback passed for the "view info" action to a lambda that first invokes
channelsViewModel.dismissChannelAction() (or
channelsViewModel.dismissChannelAction(Unit) as appropriate) and then calls
viewChannelInfo(selectedChannel) so the sheet is cleared before navigation;
update the call site where buildDefaultChannelActions is invoked to pass this
wrapped lambda instead of ::viewChannelInfo.
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialog.kt (1)

95-120: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Avoid nesting StreamScreenBottomSheet inside the results sheet.

When showAllOptionVotes is non-null, this branch renders PollOptionVotesDialog inside the outer StreamScreenBottomSheet, but PollOptionVotesDialog now creates its own StreamScreenBottomSheet. That gives the “Show All” flow two modal sheets at once, which is likely to produce stacked scrims and conflicting back/dismiss behavior. Please switch the outer sheet’s content instead of instantiating a second sheet here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialog.kt`
around lines 95 - 120, The outer StreamScreenBottomSheet currently remains
active while showAllOptionVotes is non-null, and the code calls
PollOptionVotesDialog which itself creates a second StreamScreenBottomSheet,
causing stacked sheets; fix it by switching the outer sheet’s content when
showAllOptionVotes != null instead of instantiating a nested sheet: inside the
Crossfade targetState branch (where showAllOptionVotes/option is handled) either
render the inner dialog UI directly (extract PollOptionVotesDialog’s content
into a composable like PollOptionVotesContent and call that here) or add a
parameter to PollOptionVotesDialog (e.g., wrapInSheet: Boolean) and call
PollOptionVotesDialog(..., wrapInSheet = false) so no second
StreamScreenBottomSheet is created; update calls to PollOptionVotesDialog and
any back/dismiss handlers (onDismissRequest/onBackPressed) to set
showAllOptionVotes = null accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt`:
- Around line 358-368: The sample passes ::viewChannelInfo directly into
buildDefaultChannelActions which skips dismissing the sheet first; change the
callback passed for the "view info" action to a lambda that first invokes
channelsViewModel.dismissChannelAction() (or
channelsViewModel.dismissChannelAction(Unit) as appropriate) and then calls
viewChannelInfo(selectedChannel) so the sheet is cleared before navigation;
update the call site where buildDefaultChannelActions is invoked to pass this
wrapped lambda instead of ::viewChannelInfo.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialog.kt`:
- Around line 95-120: The outer StreamScreenBottomSheet currently remains active
while showAllOptionVotes is non-null, and the code calls PollOptionVotesDialog
which itself creates a second StreamScreenBottomSheet, causing stacked sheets;
fix it by switching the outer sheet’s content when showAllOptionVotes != null
instead of instantiating a nested sheet: inside the Crossfade targetState branch
(where showAllOptionVotes/option is handled) either render the inner dialog UI
directly (extract PollOptionVotesDialog’s content into a composable like
PollOptionVotesContent and call that here) or add a parameter to
PollOptionVotesDialog (e.g., wrapInSheet: Boolean) and call
PollOptionVotesDialog(..., wrapInSheet = false) so no second
StreamScreenBottomSheet is created; update calls to PollOptionVotesDialog and
any back/dismiss handlers (onDismissRequest/onBackPressed) to set
showAllOptionVotes = null accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 10987f75-6190-4f69-9fdd-595a1a618606

📥 Commits

Reviewing files that changed from the base of the PR and between 4560c3d and bdac541.

⛔ Files ignored due to path filters (49)
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview.internal_MediaGalleryPhotosMenuTest_photos_menu.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview.internal_MediaGalleryPhotosMenuTest_photos_menu_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_gallery_bottom_sheet.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_options_menu.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsPreviewSheetTest_preview_sheet.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsPreviewSheetTest_preview_sheet_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_light_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_light_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_more_options.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_more_options_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_poll_results.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_poll_results_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_Default_reaction_picker_content.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_reaction_picker.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_reaction_picker_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments_AttachmentSystemPickerTest_command_picker_sheet.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments_AttachmentSystemPickerTest_command_picker_sheet_in_dark_mode.png is excluded by !**/*.png
📒 Files selected for processing (33)
  • stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt
  • stream-chat-android-compose/api/stream-chat-android-compose.api
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenu.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenu.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsGrid.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheet.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreen.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/ChannelsScreen.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheet.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/SelectedChannelMenu.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/SimpleMenu.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenu.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollAnswers.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialog.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialog.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialog.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPicker.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenuTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenuTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsPreviewSheetTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheetTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreenTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/SelectedChannelMenuTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheetTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollAnswersTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialogTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialogTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialogTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPickerTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPickerTest.kt

andremion added 3 commits May 29, 2026 17:00
Adds two sample/preview/test variants that the deprecated
SelectedChannelMenuTest exercises but ChannelActionsSheetTest didn't yet:
muted+pinned channel state (verifies the inline mute and pin icons render
in the header) and a null-currentUser variant (exercises the
`currentUser: User? = null` default branch).

Combined with the existing default-render tests, ChannelActionsSheetTest
now has 6 baselines (3 scenarios × light/dark), matching SelectedChannelMenuTest's
scope. The centered-dialog variant doesn't translate — ChannelActionsSheet
is a real M3 Dialog and is always bottom-aligned.
The deprecated SelectedChannelMenu doesn't need to be Figma-aligned —
that's ChannelActionsSheet's job. Reverts the public shape default from
the 32dp four-corner StreamTokens shape back to develop's
`RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)`, plus the
matching change in the internal SelectedChannelMenuSample preview helper.

The 4 affected SelectedChannelMenuTest baselines are re-recorded;
centered-dialog baselines untouched (they pass an explicit shape).

The @deprecated annotation, the headerContent modifier with top padding
(required because the relocated DefaultChannelMenuHeaderContent no longer
has inline top padding and SimpleMenu has no drag handle), and the
function relocations to ChannelActionsSheet.kt all remain.
The shape default on SelectedChannelMenuSample and the dropped explicit
shape args at the two call sites were churn from when the public default
was 32dp. Now that the public default is back to 16dp, restore
SelectedChannelMenuSample to develop's signature (shape required, after
alignment) and pass the explicit shape at the two call sites.

Snapshots unchanged — same render, fewer modified lines.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:improvement Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant