Skip to content

refactor(sample, ui): redesign channel info and detail sheet#2638

Open
xsahil03x wants to merge 34 commits intov10.0.0from
refactor/redesign-channel-detail-sheet
Open

refactor(sample, ui): redesign channel info and detail sheet#2638
xsahil03x wants to merge 34 commits intov10.0.0from
refactor/redesign-channel-detail-sheet

Conversation

@xsahil03x
Copy link
Copy Markdown
Member

No description provided.

xsahil03x and others added 30 commits May 3, 2026 21:56
Redesign the long-press / swipe-action sheet on the channel list to match
the new design system (Figma node 14889-440044), built entirely on top of
existing SDK + stream_core_flutter components:

- Header: StreamChannelAvatar + StreamChannelName (with mute / pin state
  indicators) + StreamChannelInfo for the member count.
- Action rows: StreamListTile + a local StreamListTileTheme override for
  destructive (leave / delete) styling.
- Sheet hosting: showStreamSheet for the drag-to-dismiss / scrim behavior.

The sheet now follows the same dispatch pattern as StreamMessageWidget:

- A sealed ChannelDetailAction (ViewChannelInfo / PinChannel / UnpinChannel
  / LeaveChannel / DeleteChannel) replaces the per-action callback API.
- The sheet pops itself with the chosen action; the caller awaits the
  result and routes through a single switch — mirroring _onActionTap.
- Destructive confirmations use a Material AlertDialog with two ghost
  StreamButtons, matching PollEndVoteDialog / PollDeleteOptionDialog and
  the SDK-internal StreamMessageActionConfirmationModal.

SDK-level supporting changes:

- Export StreamListTileTheme / StreamListTileThemeData from
  stream_chat_flutter so consumers can override list-tile styling without
  reaching into stream_core_flutter directly.
- Drop the now-redundant direct stream_core_flutter import in
  stream_thread_list_tile.dart.
- Remove mainAxisSize: .min from stream_poll_option_votes_sheet so it
  keeps filling the screen after the upstream StreamSheet shrink-wrap fix
  in stream_core_flutter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add `StreamAppBar` and `StreamAppBarProps` to the show-allowlist re-export
so consumers (the sample app, downstream apps) can use the design system's
app bar without a direct stream_core_flutter import.

Also drop now-redundant `stream_core_flutter` imports in three SDK files
(`channel_header.dart`, `channel_list_header.dart`, `thread_header.dart`)
that the analyzer flagged as unnecessary once `StreamAppBar` flows through
the main SDK barrel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewrite the 1-1 channel detail screen to match the new design system
(Figma frame 8833:431680):

- StreamAppBar replaces the bespoke Stack-with-back-button header.
- Hero header with StreamUserAvatar (.xxl), heading-lg name with an
  inline mute-state indicator, and an online / last-seen subtitle.
- Two card-grouped sections via a private _Section widget — Pinned
  Messages / Photos & Videos / Files for navigation, and Mute / Block /
  Delete for actions.
- StreamSwitch drives the Mute toggle; the row's icon and label swap
  between mute / audio + Mute User / Unmute User reactively.
- Block User shows a "not implemented" snackbar (no SDK API available
  for it in this sample).
- Delete Conversation uses an AlertDialog + StreamButton confirmation
  matching the channel-list dialog pattern.
- Drops the legacy Shared Groups subroute (not in the design) and the
  ignore_for_file: deprecated_member_use override that came with the
  old StreamChatTheme paths.

Every value flows through stream_core_flutter primitives + semantics —
no hard-coded colors / paddings, no StreamChatTheme.of legacy paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewrite the group channel detail screen to match the new design system
(Figma frame 8779:381156):

- StreamAppBar with a conditional outline-pill Edit button trailing.
- Hero header: StreamChannelAvatar (.xxl), heading-lg channel name with
  an inline mute-state icon, StreamChannelInfo subtitle ("X members ·
  Y online").
- Three card-grouped sections:
  - Pinned Messages / Photos & Videos / Files (shared _Section + _Tile
    pattern, mirrors Contact Info).
  - Members card with a count + Add button header, the first 5 members
    sorted with the current user first ("You"), and a View all footer
    when the channel has more.
  - Mute toggle (StreamSwitch swaps mute/audio icon + label) and a
    destructive Leave Group action that confirms via AlertDialog.
- Member rows render Online / Last seen status as the subtitle and an
  "Admin" trailing label for moderators / owners.

Stubs (snackbar): Editing the group, Adding members, the all-members
sheet — these land in chunks 4–7 alongside their dedicated routes /
sheets.

Drops the legacy file's inline name editing, the bespoke add-user modal,
the StreamBuilder<List<Member>> Scaffold scaffold, and every
StreamChatTheme.of legacy theme path. Net: 1046 → 437 lines, all values
flowing through stream_core_flutter primitives + semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire up the two member-driven flows from the channel detail design
(Figma frames 8833:434949 and 8833:434317):

- showAllMembersSheet — full-list bottom sheet with a StreamSheetHeader
  ("X Members" + circular outline user-add trailing button), driven by
  channel.state.membersStream and sorted with the current user first.
  Tapping a member stacks the contact-detail sheet on top via
  showStreamSheet's built-in stacked-sheet animation.
- showContactDetailSheet — compact sheet with a small avatar + name +
  online status header and three actions: Send Direct Message, Mute /
  Unmute User (reactive on client.state.currentUserStream's mute list),
  Block User. Pops with a ContactDetailAction subtype the caller
  dispatches via openContactDetail.
- openContactDetail — opens the sheet, awaits the action, dispatches
  through a switch expression — same shape as
  StreamMessageWidget._onActionTap. Handles: SendDirectMessage finds /
  creates the distinct 1-1 channel and pushes via GoRouter (popping any
  enclosing all-members sheet first via StreamSheetRoute.popSheet so the
  channel page lands on the regular page stack); MuteUser /
  UnmuteUser hit client.muteUser / unmuteUser; BlockUser shows a
  not-implemented snackbar per the agreed scope.
- ChannelMemberTile — single member row lifted out of group_info_screen
  so the preview list and the all-members sheet always render
  identically.

group_info_screen now uses ChannelMemberTile + openContactDetail for
member taps and showAllMembersSheet for the View all footer; the inline
_MemberTile and the 'all-members sheet' snackbar stub are gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire up the trailing _Edit_ button in Group Info to the redesigned
edit-group sheet (Figma frames 8833:446261, 8833:447144, and the
9857:302181 avatar picker):

- showEditGroupSheet — bottom sheet with a StreamSheetHeader (auto X
  leading, "Edit" title, solid-primary checkmark trailing). The save
  checkmark stays disabled until the user actually changes something.
- Hero avatar block — taps the avatar / "Upload" link to open a stacked
  _AvatarPickerSheet_ with three actions (Take Photo / Choose Image /
  Reset Picture, the latter rendered destructive via a local
  StreamListTileTheme override).
- Image picking via image_picker (added to sample_app pubspec) and
  uploaded immediately through the standalone client.sendImage API so
  the preview swaps as soon as the upload settles. The session-level
  override + reset flag drive a switch-expression preview that
  short-circuits StreamChannelAvatar.
- StreamTextInput drives the channel name; save persists via
  channel.updatePartial(set: {...}, unset: ['image']) in a single round
  trip — picks up name changes, the new avatar URL, or an "image"
  unset for resets.

Group Info's Edit-button stub now calls showEditGroupSheet directly.
The "Editing the group" snackbar is gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous version shrink-wrapped to its content, which left a
half-empty sheet sitting on top of the channel page. The Figma actually
shows a full-height sheet with the keyboard up — match that:

- Wrap the avatar + text-input column in an Expanded scrollable. With
  one Expanded child the outer Column fills available height, which in
  turn drags the StreamSheet up to its full-screen rest position via
  the upstream Stack(StackFit.loose) fix.
- Pad the scrollable's bottom by `MediaQuery.viewInsetsOf(context).bottom`
  so the StreamTextInput stays above the keyboard once it animates up.
  The sheet route applies SafeArea(bottom: false) so the inset is still
  ours to consume.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extract a separate _canSave getter that requires the name to be
non-empty in addition to the existing dirty + not-saving checks. Empty
group names aren't a meaningful identifier (and the API won't accept
them), so the save checkmark stays disabled when the user clears the
field.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The avatar picker is already pushed via showStreamSheet from inside the
edit sheet's context, so it auto-stacks (parent scales down, picker
animates in over it). What was breaking the visual was the soft
keyboard staying up while the stacked sheet animated — it fought the
parent sheet's MediaQuery viewInsets and produced a jittery push.

Drop focus right before pushing the picker so the keyboard slides down
first, then the stacked sheet animates over a stable parent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pushing a new route already steals focus, so the manual
FocusScope.unfocus() before opening the avatar picker is unnecessary.
Drop it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The hand-styled TextButton + accent-colored Text was bypassing the
design system. Swap it for `StreamButton(type: .ghost, style: .primary,
size: .small)` so press states, hover, focus, and accent color all
flow through StreamButtonTheme.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the SDK's StreamAttachmentUploadStateBuilder pattern so the
avatar preview reports its own upload state instead of leaving the user
guessing while the network round-trips:

- Track determinate progress (0..1) in _uploadProgress; updates flow
  from client.sendImage's onSendProgress callback (count, total).
- Fall back to an indeterminate spinner (`null` value) when total is 0
  / unknown — same fallback the SDK's _defaultInProgressBuilder uses
  for content-length-less uploads.
- Overlay a translucent ColoredBox + StreamLoadingSpinner(.md) inside
  a ClipOval on top of the avatar while uploading. Matches the SDK
  visual.
- Gate _canSave on `_uploadProgress == null` so the user can't tap save
  before the URL has settled.

Re-export StreamLoadingSpinner / StreamLoadingSpinnerSize from
stream_chat_flutter so the sample-app side never has to reach into
stream_core_flutter directly. Drop the now-redundant stream_core_flutter
imports the analyzer flagged across 10 SDK files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The CircleAvatar fallback was rendering the freshly-uploaded image at
the right diameter (80px, matching StreamAvatarGroupSize.xxl) but
*without* the 1px border that StreamChannelAvatar's image branch draws
via StreamAvatar's foregroundDecoration. The result: a subtle visual
shift the moment an upload settled and we swapped previews.

Re-export StreamAvatar from stream_chat_flutter and render the override
via StreamAvatar(imageUrl: ..., size: .xxl) instead, so the picked
preview is pixel-identical to the channel's eventual rendering.
Placeholder falls back to the member-group avatar so a transient load
hiccup doesn't blank the slot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the GestureDetector wrapping the avatar so only the Upload
StreamButton opens the picker. Two overlapping hit targets pointing
at the same action made the affordance ambiguous and risked
accidental opens when scrolling near the avatar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the Expanded + SingleChildScrollView and let the sheet shrink-wrap
its content. The Stack(StackFit.loose) fix upstream means a
mainAxisSize.min Column in the body keeps the StreamSheet at its
intrinsic height — header + avatar + input + keyboard inset, no extra
empty space above the keyboard.

Keyboard handling stays via padding the body's bottom by
MediaQuery.viewInsetsOf(context).bottom — the input still rides above
the soft keyboard, the sheet just doesn't claim screen real estate it
isn't using.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three changes pulled together:

- Avatar reactivity: drop the local _imageOverride / _imageRemoved
  state. Pick + reset now persist eagerly via channel.updateImage /
  channel.updatePartial(unset: ['image']) — StreamChannelAvatar reloads
  via channel.imageStream, both in this sheet and everywhere else
  showing the channel's avatar. Save handles only the deferred name
  edit (it's the only thing that batches across keystrokes).
- Spinner overlay sizing: replace the loose-constraints
  ClipOval/SizedBox.expand combo with an explicit width/height
  Container + BoxShape.circle decoration, so the dim-overlay
  geometry exactly matches the .xxl avatar (80×80) regardless of how
  Stack lays out non-positioned children.
- Header button parity: drop the size: .small on the trailing
  checkmark in EditGroupSheet *and* the trailing user-add button in
  AllMembersSheet. The auto-implied close on the leading side renders
  at default .medium (40px), so the trailing buttons were 8px shorter
  and the header looked lopsided.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Walk back the eager updateImage / updatePartial(unset) — picking or
resetting now stages the change locally; nothing hits `channel.image`
until the user taps the save checkmark. Dismissing the sheet leaves the
channel untouched even though the picked bytes have already shipped to
the CDN as a standalone attachment.

- _imageOverride: CDN URL of an in-session pick, displayed via
  StreamAvatar so the diameter + 1px border match the channel-image
  branch.
- _imageRemoved: tracks the user's intent to clear the avatar; the
  preview falls back to the member-group avatar.
- _save persists name + image (or unset) in a single
  channel.updatePartial round-trip, same as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two bugs the deferred-save model exposed:

- Avatar flicker: the preview was driven off `_imageOverride` (CDN URL),
  so after upload settled the avatar swapped to a `StreamAvatar` whose
  CachedNetworkImage had to round-trip the same URL through the cache —
  and during that round-trip its placeholder briefly showed the
  member-group fallback. Fix: track the picked file path in
  `_pickedPath` and render the preview via `Image.file` slotted into
  `StreamAvatar`'s placeholder, so the swap is instant. Same pattern
  the LLC uses in sendMessage attachment uploads — local file beats
  URL when both are available.
- Orphan uploads: dismissing the sheet (or replacing a pick before
  saving) left the standalone-uploaded bytes leaking on the CDN. Now
  every successful upload's URL is appended to a `_trackedUploads`
  list. On save, the URL we just persisted is stripped from the list
  and the rest are deleted via `client.deleteImage`. On dispose
  (without save), every tracked URL is deleted. `client.deleteImage()
  .ignore()` keeps the cleanup fire-and-forget.

Also clear the local preview when an upload fails so the channel's
current avatar reverts — paired with the snackbar, the user knows to
re-pick instead of seeing a phantom file image.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Once the standalone upload returns a CDN URL, render the preview from
that URL via StreamAvatar (so the in-memory file image gets released)
instead of holding the local file open for the lifetime of the sheet.
The local file becomes the placeholder during the brief
CachedNetworkImage round-trip — no flicker on the swap because both
states render through the same StreamAvatar chrome.

Switch ladder reads:
  - URL set:        StreamAvatar(url) with file as placeholder
  - URL still null: StreamAvatar(null) with file as placeholder
  - Removed:        member-group fallback
  - Untouched:      StreamChannelAvatar (channel.imageStream-driven)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire up the Add buttons in the group-info members card and the
all-members sheet to a redesigned Add Members sheet (Figma frames
9857:114080 + Selected / Search / No Result variants):

- StreamSheetHeader with auto-implied close + a primary checkmark
  trailing button. Checkmark stays disabled until at least one row is
  ticked and re-enables once any add-members call completes.
- StreamTextInput (with the search-icon leading slot) drives the
  filter on a StreamUserListController. Edits are debounced 350ms
  before they flow into the controller so we don't fire a query on
  every keystroke.
- Paginated StreamUserListView. Custom itemBuilder renders a
  StreamListTile (avatar + name + StreamCheckbox.circular trailing);
  tapping anywhere on the row toggles selection. The controller's
  filter excludes the current user and existing channel members
  upfront so they don't show up as candidates.
- Custom emptyBuilder — search icon + "No user found" caption (the
  No Result variant from the Figma).
- On confirm: channel.addMembers is awaited, the sheet pops with
  `true`. On failure: the sheet stays open with a snackbar so the user
  can retry.

Drops the now-unused _showNotImplementedSnack helper from
group_info_screen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reuse the rounded pill SearchTextField that already drives the channel
list's search instead of re-rolling a StreamTextInput + leading-icon
combo. Keeps the search affordance visually consistent across the app
and trims a few lines of styling that duplicated SearchTextField's
internals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Swap Flexible + shrinkWrap for Expanded so the user list gets bounded
constraints and scrolls independently of the sheet. Shrink-wrapping
glued the sheet's height to however many rows happened to be loaded,
which fought the controller's pagination and the keyboard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the bespoke _NoResults widget with a centered
StreamScrollViewEmptyWidget — same shape StreamChannelListView,
StreamUserListView, and friends use for empty states (icon + caption,
textTertiary icon at size 32, captionDefault textSecondary title).
Loading isn't overridden, so the default centered
StreamScrollViewLoadingWidget kicks in for free.

Centering now lives at the call site (`Center(...)` wrapping the
empty widget), matching the SDK convention so the empty / loading
overlays land in the middle of the visible scroll area.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewrite the pinned-messages screen to match the new design (Figma
8833:437280 + 8833:437021):

- StreamAppBar replaces the bespoke AppBar + StreamBackButton.
- Body keeps the existing StreamMessageSearchListController + filter
  (cid + pinned) and renders via StreamMessageSearchListView so the
  list rows pick up the SDK's tile styling for free.
- Empty state is a private widget — pin icon at textTertiary, a bold
  textPrimary headline ("No pinned messages") and a textSecondary
  subtitle ("Long-press a message to pin it to the chat") — centered
  via the SDK convention.
- All values flow through stream_core_flutter primitives + semantics;
  the legacy file's StreamChatTheme.of paths and the
  ignore_for_file: deprecated_member_use override are gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewrite the photos/videos list to match the new design (Figma
8833:437788, 13495:418984, 8833:437329):

- StreamAppBar replaces the bespoke AppBar + StreamBackButton.
- Body is a 3-column GridView with 1px gutters fed by the existing
  StreamMessageSearchListController (filtered to image / video
  attachments). Each cell renders the attachment thumbnail via
  StreamNetworkImage; videos overlay a StreamVideoPlayIndicator. Tap
  opens StreamFullScreenMedia at that index, with every other media
  item wired up as a swipeable sibling.
- LazyLoadScrollView drives pagination — loadMore on end-of-page,
  same as the legacy implementation.
- Empty / loading / error states match the SDK convention — centered
  StreamScrollViewLoadingWidget while loading, custom empty (image
  icon + headline + subtitle) per the Figma, centered
  StreamScrollViewErrorWidget on failure.
- Drops the per-video VideoPlayerController preinit cache; thumbnails
  use thumbUrl now, so we don't pay the cost of N video pipelines for
  rows the user might never tap. Playback still works because
  StreamFullScreenMedia spins up its own player when a video tile is
  opened.

Re-export StreamScrollViewLoadingWidget, StreamScrollViewErrorWidget,
and StreamNetworkImage from stream_chat_flutter so the sample app
never has to reach into stream_core_flutter / src directly. Drop the
now-redundant `src/scroll_view/stream_scroll_view_loading_widget.dart`
and `src/scroll_view/stream_scroll_view_error_widget.dart` imports
the analyzer flagged across 10 SDK files once these flow through the
main barrel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewrite the file-attachments list to match the new design (Figma
8833:437706 + 8833:437407):

- StreamAppBar replaces the bespoke AppBar + StreamBackButton.
- Body groups attachments by the message month (March 2026, February
  2026, …). Each section header is a light-surface band with a bold
  caption; entries without a timestamp fall under "Earlier".
- File rows are StreamListTiles — leading StreamFileTypeIcon
  (auto-derived from the attachment's mimeType), filename title with
  ellipsis, human-readable file-size subtitle ("4 MB" / "5 KB"). Pure
  preview, no tap action — mirrors the legacy implementation.
- Empty / loading / error states use the SDK convention — centered
  StreamScrollViewLoadingWidget while loading, custom Figma empty
  (folder icon + "No files" headline + textSecondary subtitle), and
  centered StreamScrollViewErrorWidget on failure with a retry button.
- LazyLoadScrollView drives pagination — same as the legacy
  implementation.
- Drops the unused VideoPlayerController cache, the
  ignore_for_file: deprecated_member_use override, and every
  StreamChatTheme.of legacy theme path.

A small `_humanizeBytes` helper lives at the bottom of the file —
returns "4 MB", "512 KB", "2 GB" — sized to match the figma's tight
unit format.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migrate StreamChannelHeader, StreamChannelListHeader, StreamThreadHeader,
and StreamGalleryHeader to a single slot model (leading / title /
subtitle / trailing) and a single theme type (StreamAppBarThemeData),
replacing the legacy AppBar-style API.

Per-header highlights:

- StreamChannelHeader: new onChannelAvatarPressed callback for the
  default channel-avatar trailing, and an opt-in default
  StreamBackButton via automaticallyImplyLeading.
- StreamChannelListHeader: renames onUserAvatarTap to onUserAvatarPressed,
  drops the leading slot (the avatar is always the signed-in user) and
  the default "new chat" trailing — consumers pass their own trailing
  widget. The avatar mirrors Material AppBar's auto-implied leading and
  opens the enclosing Scaffold's drawer when one exists.
- StreamThreadHeader / StreamGalleryHeader: same slot model.
- StreamFullScreenMedia: paints backgroundApp when the headers are
  visible and StreamColors.black when they're hidden.

Theme:

- StreamChannelHeaderThemeData, StreamChannelListHeaderThemeData, and
  StreamGalleryHeaderThemeData are deleted. The accessors on
  StreamChatThemeData (channelHeaderTheme, channelListHeaderTheme,
  threadHeaderTheme, galleryHeaderTheme) now hold StreamAppBarThemeData;
  per-instance overrides flow through a new style: StreamAppBarStyle?
  parameter on each header.
- kStreamHeaderHeight (72 px) and StreamColors are re-exported from
  package:stream_chat_flutter/stream_chat_flutter.dart.

The migrations/redesign/headers_and_icons.md guide is rewritten with
per-header parameter mapping tables, before/after snippets, and an
updated migration checklist covering the new slot model, removed
parameters, theme migration, and the kStreamHeaderHeight constant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cumulative cleanup pass across the sample app:

- Migrate stale Material AppBar usages to StreamAppBar (config /
  advanced options / new-chat / new-group-chat / location dialogs).
- Switch legacy `actions: [...]` slots to the new `trailing:` slot on
  group / chat info screens.
- Hide the "add member" affordance on distinct (1:1) channels in the
  members sheet — the API rejects member changes on those.
- Extract avatar-picker rows into a `_PickerTile` helper in the edit
  group sheet.
- Modernise list / option iteration with switch expressions and
  `collection.sorted`.
- Restructure padding so info screens own their scroll padding rather
  than each section duplicating it.
- Bump iOS / Android Ruby toolchain to 3.3.9.

No SDK behaviour changes — all touched files belong to the sample app.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Migrate example app to the new StreamChannelHeader slot model:
  swap `onBackPressed` / `onImageTap` / `showBackButton` for an
  explicit `leading: StreamBackButton(...)` + `trailing:` widget,
  and replace `showBackButton: false` with
  `automaticallyImplyLeading: false` in the split-view shell.
- Align StreamGalleryFooter's preferredSize with the new
  kStreamHeaderHeight (72) so the footer matches the redesigned
  bar above it instead of sitting at Material's kToolbarHeight (56).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Swap legacy icons for their design-system counterparts in the
attachment actions modal — `eyeFill` → `messageBubble` for "Show in
Chat", `save` → `arrowDownCircle` for "Save Image / Video" — and
shrink them from 24 to 20 px so they line up with the rest of the
icon set. Visual-only change; no API impact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
xsahil03x and others added 2 commits May 4, 2026 07:33
Refresh `docs_screenshots` goldens and tests against the redesigned
SDK widgets:

- Bump the channel-header / channel-list-header golden constraints
  from kToolbarHeight (56) to kStreamHeaderHeight (72) and stop
  injecting an inline `const StreamChannelHeader(...)` / `const
  StreamChannelListHeader(...)` default — the test scaffolds now
  expect callers to pass an explicit `header:`.
- Re-render every macOS golden (channel / draft list / message input
  / message list / message search / polls / thread list / user list
  / voice recording) so the bytes match the redesigned components.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a `reactionsCountText(int count)` translation alongside the
existing `threadReplyCountText` / `*CountText` family, replacing the
hardcoded `'1 Reaction' / '$visibleCount Reactions'` switch in the
reaction detail sheet header with `context.translations
.reactionsCountText(visibleCount)`.

Each of the 11 bundled locales (ca, de, en, es, fr, hi, it, ja, ko,
no, pt) gets its own override that mirrors that locale's existing
thread-reply count style — English and Italian keep the singular /
plural distinction; the others use a single `$count [plural]` form
in line with the translator's prior choices.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12d05fe3-5193-455b-a5fa-fc83f2ecac78

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/redesign-channel-detail-sheet

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.

xsahil03x and others added 2 commits May 4, 2026 08:25
Update changelogs, the localizations migration guide, and the
DefaultTranslations / supported-locale tests to cover the new
`reactionsCountText(int count)` translation. Also adds the override
to `add_new_lang.dart` so the example compiles against the new
abstract member.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`package:stream_chat_flutter/stream_chat_flutter.dart` already
re-exports the stream_core_flutter symbols these files use, so the
explicit imports were redundant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant