Swipe-to-reveal actions on channel list items#6188
Merged
aleksandar-apostolov merged 25 commits intoredesign/channel-listfrom Feb 25, 2026
Merged
Swipe-to-reveal actions on channel list items#6188aleksandar-apostolov merged 25 commits intoredesign/channel-listfrom
aleksandar-apostolov merged 25 commits intoredesign/channel-listfrom
Conversation
Add Pin/Unpin, Mute/Unmute, and Delete swipe actions behind channel list items using AnchoredDraggable from Compose Foundation 1.9.0. - SwipeableChannelItem wrapper with RTL support - SwipeRevealCoordinator for single-open-at-a-time behavior - DefaultChannelSwipeActions respecting channel capabilities - Overridable via ChatComponentFactory.ChannelSwipeActions() - Configurable via ChannelListConfig.swipeActionsEnabled - isPinned added to ChannelItemState
DM channels show Archive + More, group channels show Mute + More. Primary action resolved via fallback priority (DM: Archive→Mute→Pin, Group: Mute→Archive→Pin). "More" opens the channel options bottom sheet via selectChannel. Add SwipeActionStyle enum (Primary/Secondary/Destructive) for slot-based coloring. Fix missing background() on SwipeActionItem.
SideEffect does not track state reads for recomposition, so when onSizeChanged updated actionsWidthPx during layout, the anchor setup block never re-ran — leaving AnchoredDraggableState with no anchors and making the swipe gesture a no-op. Switch to LaunchedEffect(actionsWidthPx) so the key is tracked during composition and anchors are set after layout measurement. Also add height(IntrinsicSize.Min) to the outer Box so the background action Row can fillMaxHeight() properly inside LazyColumn's unbounded height context.
CustomChatComponentFactory overrode ChannelListItemContent without the SwipeableChannelItem wrapper, making swipe a no-op in the sample. - Add SwipeableChannelItem wrapper to the sample's override - Make LocalSwipeRevealCoordinator public so consumers who override ChannelListItemContent can check swipe availability
AnchoredDraggableState.offset returns Float.NaN when no anchors exist yet. roundToInt() throws on NaN in Kotlin. Guard with isNaN check, defaulting to 0 offset.
The ChannelItem's 4dp card inset left the action Row visible through the transparent margins. Add a backgroundColor param to SwipeableChannelItem that paints the foreground layer opaque, covering the actions when the item is in the closed position.
background() must be after offset() so the opaque layer moves with the channel item, covering actions when closed but revealing them when swiped open.
Place the secondary More action first (leftmost) and the primary action (Archive/Mute) second (rightmost) to match the Figma spec.
Rewrite ChannelAction from sealed class to interface carrying icon, label, capability, confirmation popup, and execution handler. This eliminates scattered when-switches, removes ChannelOptionState, and enables custom channel actions across Compose and XML surfaces. - ChannelAction: sealed class → interface with icon/label/onAction - Add ConfirmationPopup data class for deferred destructive actions - Copy 10 icon drawables to ui-common for cross-module access - Remove Cancel object (dismissal via onDismiss callbacks) - ViewModel: performChannelAction → executeOrConfirm/confirmPendingAction - Compose: delete ChannelOptionState, buildDefaultChannelActions returns List<ChannelAction> with ViewModel handlers bound - ChannelsScreen: generic confirmation dialog from action.confirmationPopup - ChatComponentFactory: ChannelOptionState refs → ChannelAction - Swipe actions: build ChannelAction objects directly - XML: factory returns List<ChannelAction>, delete ChannelOptionItem - Update tests, sample app, docs snippets, API dump
Contributor
PR checklist ✅All required conditions are satisfied:
🎉 Great job! This PR is ready for review. |
Contributor
SDK Size Comparison 📏
|
Remove dead `isOneToOne` extension (Detekt UnusedPrivateMember) and re-record ChannelItemTest Paparazzi snapshots.
Resolve conflicts from channel-list merge (which included v7/AND-1089 design system migration). Update legacy token references: - footnoteBold → captionEmphasis (SwipeActionItem) - errorAccent → accentError (ChatComponentFactory) - overlay → backgroundCoreScrim (SelectedChannelMenu) - highlight → backgroundCoreHighlight (CustomChatComponentFactory) - appBackground → backgroundCoreApp (CustomChatComponentFactory)
…com/GetStream/stream-chat-android into redesign/channel-list-swipe-actions
Replace legacy Material-style icons with filled variants from Stream Foundations. All icons now use 16x16 viewport with filled paths for consistent rendering. Mute/unmute switched from speaker to bell icons.
Mute/unmute: use IconMute (speaker) and IconVolumeFull instead of bell icons. Add: use IconPlusLarge (plus) instead of IconEditBigSolid (pen).
Reorder channel actions: ViewInfo, Mute, Pin, Archive, Leave, Delete. Destructive actions (Leave, Delete) are now grouped last. Mark LeaveGroup as isDestructive = true.
Replace horizontal member list with compact header: channel avatar (left) + channel name + member count/status (right). Matches Figma Channel Detail Sheet design.
…ions Channel list title: bodyDefault → headingSmall (semi-bold) to match Figma. Swipe actions: remove text label, show icon only in a centered Box.
Light gray background with dark icon instead of dark slate500 with white icon. Matches Figma swipe action design.
Item height 56dp → 48dp, icon container 56dp → 48dp with 12dp padding (24dp icon). More compact to match Figma design.
Icon: spacingXl (24dp) with spacingSm (12dp) horizontal padding. Replaces hardcoded 48dp/12dp values with design system tokens.
No dividers between channel options per Figma design.
Row height 48dp → 44dp, horizontal padding spacing2xs (4dp), icon 24dp with 8dp end gap. Matches Mobile / List Item Figma component.
…ngMd spacing2xs (4dp) → spacingMd (16dp) to match visible Figma padding.
spacingXs (8dp) bottom content padding for breathing room below last action item.
aec1cb4
into
redesign/channel-list
10 of 14 checks passed
Contributor
Author
|
Consolidated into #6181 — combined the channel list redesign and swipe actions into a single PR since most changes here (icons, bottom sheet, ChannelAction refactor) belong to the broader redesign scope. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goal
Add swipe-to-reveal actions on channel list items, matching the Figma spec. DM channels get More + Archive/Unarchive, group channels get More + Mute/Unmute. Provides a slot-based styling system and full customization support via
ChatComponentFactory.Implementation
Swipe Mechanism
SwipeableChannelItemwraps channel items withAnchoredDraggableState-based swipe gestureSwipeRevealCoordinatorensures only one item is open at a timeDefault Actions
Slot-Based Styling (
SwipeActionStyle)accentPrimary(blue)accentNeutral(gray)accentError(red)ChannelAction Refactor
ChannelActionis now a self-describing interface withicon,label,confirmationPopupCustomization
Two tiers via
ChatComponentFactory:ChannelSwipeActions()— replace which actions appear (keeps swipe mechanism)ChannelListItemContent()— full control over swipe wrapper + itemConfiguration
New Files
SwipeableChannelItem.ktAnchoredDraggableState-based swipe wrapperSwipeRevealCoordinator.ktSwipeRevealValue.ktClosed/OpenenumSwipeActionItem.ktSwipeActionStyle.ktDefaultChannelSwipeActions.ktTesting
CustomChatComponentFactoryupdated to include swipe wrapper