Skip to content

chore(repo): merge master into v10.0.0#2682

Merged
xsahil03x merged 20 commits into
v10.0.0from
chore/merge-peformance-improvements-into-v10
May 26, 2026
Merged

chore(repo): merge master into v10.0.0#2682
xsahil03x merged 20 commits into
v10.0.0from
chore/merge-peformance-improvements-into-v10

Conversation

@xsahil03x
Copy link
Copy Markdown
Member

@xsahil03x xsahil03x commented May 25, 2026

Summary

Brings master's perf / security / CI work into the v10 design-refresh branch.

Master is 17 commits ahead of v10.0.0 — this PR carries them into v10 so the upcoming v10 release ships with the latest LLC perf rewrites, the in-flight queryChannels dedup, the jose security floor, and the relaxed URL detection. On top of those, this PR ports the same perf approach into v10's design-refresh code (single-message fast path in _mergeMessagesIntoExisting, Jiffy removal from message-list predicates), rewrites the date formatter as a clock-driven extension, and overhauls the message-list pagination / scroll / highlight plumbing.

What landed

LLC (stream_chat)

stream_chat_flutter_core

stream_chat_flutter

Date formatting

  • date_formatter.dart rewritten — replaces Jiffy predicates with a DateTimeComparisonUtils extension (isToday, isYesterday, isWithinLastMinute, isWithinLastWeek, isInSameYear, single isSame(unit:) entry point with a DateTimeUnit enum). Uses package:clock for testable time. Cuts ~1.5s on the trace per the latest DevTools profile.
  • formatRecentDateTime output reworked to a five-state cascade matching the Figma design: Just now / Today at H:mm / Yesterday at H:mm / Weekday at H:mm / MMM do at H:mm.

Message-list view internals

  • mlv_utils.dart: _isGroupBoundary, _resolveSpacingRules, and computeStackPosition drop Jiffy in favor of the new extension.
  • scrollable_positioned_list/: master version taken in full. Bounded _keyToIndexMap, isScrolling / isScrollingListenable, itemKeyBuilder anchor preservation, fit-anchor fallback in UnboundedRenderViewport, sensible defaults on scrollTo (perf(repo): cut StreamMessageListView UI-thread work under flood load #2651).
  • tld.dart removed (chore(ui): drop the bundled IANA TLD list #2654); StreamMessageComposer relaxed its URL regex from [a-z]{2,4} to [a-z]{2,} and dropped the isValidTLD filter at both call sites.
  • StreamMessageListView and separated_reorderable_list_view: v10's design-refresh version retained on top of the perf changes.

Scroll, highlight, pagination plumbing

  • _moveToAndHighlight renamed to _scrollToMessage and tightened: messageId is required (was nullable), dropped the unused messages / initialScrollIndex / scrollTo parameters, added alignment (default 0.5) and highlight (default true) knobs, guards on controller.isAttached before scrolling. In thread mode, bails when the target reply isn't loaded (no thread-around-reply loader is exposed today — matches Android/RN; iOS/SwiftUI have loadPageAroundReplyId and remain the proper-fix template).
  • Initial-highlight selection discriminates channel vs thread — threads read _ThreadHighlightScope only, the channel reads streamChannel.initialMessageId only. Previously the channel-scoped id leaked into thread mode and could mis-route _scrollToMessage into the channel pagination path. Matches Android's parentMessageId-discriminated focus and SwiftUI's per-VM highlight environment. _ThreadHighlightScope.of switched to dependOnInheritedWidgetOfExactType for O(1) lookup.
  • Pagination LoadingIndicator reworked: StatefulWidget that caches the queryTopMessages / queryBottomMessages stream (matches MessageListCore's pattern — the getters on StreamChannelState return a fresh BehaviorSubject view per access), reads StreamChannel.of(context) instead of taking it as a prop, drops the unused streamTheme / isThreadConversation fields. In-flight spinner uses StreamLoadingSpinner and the existing widget.builders.paginationLoadingIndicator override; the error tile is a tappable StreamScrollViewLoadMoreError.list that retries via _paginateData. Initial-load defaultErrorBuilder upgraded from plain Text to StreamScrollViewErrorWidget with retry → streamChannel.reloadChannel(). _paginateData drops its unused channel parameter.
  • Inner ScrollablePositionedList.separated gets a stable Key('mlv-${cid}-${parentId}') — same-channel/same-thread rebuilds keep the SPL's scroll position and item-position cache; channel swap or thread enter/leave forces a clean remount.
  • MessageListView default builders switched from if (X != null) return X!(...) to if (X case final builder?) return builder(...), dropping the bang-assertions.

Other

  • Committed two previously-untracked generated part files (stream_chat_theme.g.theme.dart, thread_list_tile_theme.g.theme.dart) — CI analyze couldn't compile without them.
  • Suppressed a deprecation on SizeTransition.axisAlignment — its replacement alignment was added after Flutter 3.41, beyond the SDK floor (3.38.1).
  • Added auto_scroll_test.dart and stream_chat_theme_test.dart (10 tests covering message-list scroll behavior and theme ancestor lookup).

sample_app

  • Completed the Sentry → Firebase Crashlytics migration (chore(samples): replace Sentry with Firebase Crashlytics #2665) on v10's redesigned sample app: removed sentry_flutter from pubspec.yaml and swapped the Sentry.captureException call in auth_controller.dart for FirebaseCrashlytics.instance.recordError(error, stack, reason: record.message). main.dart was already on Crashlytics; the log handler in auth_controller was the last sentry consumer.

CI / repo

Docs / tests

  • docs_screenshots/voice_recording_test.dart: replaced StreamChatThemeData().copyWith(...) with the factory constructor — the generator-emitted copyWith returns the base ThemeExtension<StreamChatThemeData> type, which isn't assignable to a StreamChatThemeData? parameter.

Notes / follow-ups

  • sample_app/: v10's redesigned sample app retained as a unit (gradle, manifest, main.dart, pbxproj — auto-merge would have left it inconsistent with v10's app.dart / pubspec). chore(samples): replace Sentry with Firebase Crashlytics #2665's Sentry → Crashlytics work is now fully ported (see above).
  • mark_read_test.dart: dropped a dead when(() => channel.on(any(), any(), any(), any())) stub that leaked any() matchers into the next setUp (since MockChannel.on() is a concrete override, not a mocktail stub).
  • Locale: formatRecentDateTime hardcodes English 'at' separator — needs a dateAtTimeText({date, time}) Translations method for locale support. Tracked.
  • Deferred perf: StreamTimestamp / StreamDateDivider still call Jiffy (~684ms / 11.8% in the latest profile) — should move to a cached intl.DateFormat.
  • Goldens: 49 pixel-diff failures in reactions / polls / avatars / icons remain — pre-existing Flutter-SDK rendering drift, unrelated to this PR. Regenerate with melos run update:goldens if needed.
  • Channel.query() truncate-on-reload: after a loadChannelAtMessage(Y) jump, calling reloadChannel() merges the latest 30 with the around-Y window instead of replacing — older messages (including the one that contained the quoted tap) end up unreachable without paginating back. Fix needs to land in v9 first (same LLC code), then port to v10. Tracked.
  • Thread-around-reply loader: _scrollToMessage bails in thread mode when the target reply isn't loaded. Backend supports id_around on GET /messages/{parent_id}/replies and the LLC already exposes it via Channel.getReplies(parentId, options: PaginationParams(idAround: ...)); iOS UIKit (MessageController.loadPageAroundReplyId) and SwiftUI wire it through, Android and React Native do not. Wire a loadPageAroundReplyId-style helper into StreamChannel / the thread controller as a follow-up.

Test plan

  • dart test packages/stream_chat — 1381/1381 pass
  • flutter test packages/stream_chat_flutter_core — 239/239 pass
  • flutter test packages/stream_chat_flutter — touched-area tests all pass (date_formatter_test, message_list_view_test, mark_read_test, auto_scroll_test, timestamp_test, stream_chat_test, stream_channel_test)
  • CI: analyze, format, test, build (android) green
  • CI: build (ios) — Sentry/Crashlytics archive failure was the prior blocker; should clear now that sentry_flutter is gone (first run since the migration)
  • Manual: sample_app boots against v10 on at least one platform

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 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: 9faee784-7411-4cf8-9e44-c8f4e69d471b

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 chore/merge-peformance-improvements-into-v10

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 xsahil03x mentioned this pull request May 25, 2026
7 tasks
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xsahil03x xsahil03x force-pushed the chore/merge-peformance-improvements-into-v10 branch from 1056e0d to 2b455a2 Compare May 25, 2026 20:35
@xsahil03x xsahil03x changed the title chore: merge master perf improvements into v10.0.0 chore: merge master into v10.0.0 May 25, 2026
xsahil03x and others added 6 commits May 25, 2026 22:43
…ce recording test

The generated copyWith returns ThemeExtension<StreamChatThemeData>, not
StreamChatThemeData, so it could not be passed where the latter was
expected. The factory accepts voiceRecordingAttachmentTheme directly,
which avoids the wide return type entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…eme part files

These were left untracked locally — CI fails analyze because the .dart
files reference them with `part`. Aligns with the rest of the .g.theme.dart
files in the package, which are committed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…roll tests

stream_chat_theme_test pins StreamChatTheme.of ancestor lookup. auto_scroll_test
covers the scroll-position behavior of StreamMessageListView when remote messages
arrive (do not flap at the bottom, do not auto-scroll while scrolled up, etc.).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dart 3.12's formatter (Flutter 3.44 in CI) collapses `value\n;` to `value;`
on the final enum entry. Dart 3.10 left them split. Reformat to match CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The format check used \`flutter-version: 3.x\` which resolved to 3.44 /
Dart 3.12 — newer than the SDK floor (Flutter 3.38.1 / Dart 3.10).
\`dart format\` output diverged between versions for trailing enum
semicolons, so CI rejected code that's correctly formatted at the min
SDK. Pin format to the floor so contributors on supported Dart versions
can produce identical output locally.

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

codecov Bot commented May 25, 2026

Codecov Report

❌ Patch coverage is 87.51625% with 96 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (v10.0.0@29fc127). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...r/lib/src/message_list_view/message_list_view.dart 55.55% 56 Missing ⚠️
...r/lib/src/message_list_view/loading_indicator.dart 68.18% 7 Missing ⚠️
...m_chat_flutter_core/lib/src/message_list_core.dart 92.22% 7 Missing ⚠️
...t_view/stream_message_list_view_configuration.dart 0.00% 6 Missing ⚠️
packages/stream_chat/lib/src/client/channel.dart 91.93% 5 Missing ⚠️
...crollable_positioned_list/src/positioned_list.dart 97.67% 4 Missing ⚠️
...at_flutter_core/lib/src/better_stream_builder.dart 85.18% 4 Missing ⚠️
packages/stream_chat/lib/src/client/client.dart 57.14% 3 Missing ⚠️
...ositioned_list/src/scrollable_positioned_list.dart 96.47% 3 Missing ⚠️
...lib/src/message_input/stream_message_composer.dart 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             v10.0.0    #2682   +/-   ##
==========================================
  Coverage           ?   66.98%           
==========================================
  Files              ?      407           
  Lines              ?    24365           
  Branches           ?        0           
==========================================
  Hits               ?    16320           
  Misses             ?     8045           
  Partials           ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

xsahil03x and others added 2 commits May 25, 2026 23:06
The replacement \`alignment\` property was added after Flutter 3.41, but
our SDK floor is 3.38.1. Suppress the deprecation warning so analyze
passes on newer Flutter versions while remaining buildable on the min.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match the existing style of inline ignore directives in this repo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xsahil03x xsahil03x changed the title chore: merge master into v10.0.0 chore(repo): merge master into v10.0.0 May 25, 2026
xsahil03x and others added 6 commits May 25, 2026 23:17
… changelogs

stream_chat: SortedListX.merge from 9.24.0 was split into
SortedListX.mergeSorted (two-pointer, sorted output) and IterableMergeX.merge
(keyed-map, unsorted) — breaking for any direct caller of the former.

stream_chat_flutter: DateTimeComparisonUtils extension and DateTimeUnit enum
are now exported; formatRecentDateTime emits the new five-state cascade
matching the Figma design.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`dart format` from Dart 3.10 incorrectly emits `value\n  ;` for enums
with parameters under `trailing_commas: preserve` (dart-lang/dart_style#1785,
fixed in 3.12). CI now runs on the fixed formatter; rerun across the repo
to land the corrected output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e_crashlytics

Completes the Sentry → Firebase Crashlytics migration (#2665) for v10's
redesigned sample app. main.dart was already on Crashlytics; auth_controller
was the last sentry consumer. Removes the dep, swaps Sentry.captureException
for FirebaseCrashlytics.instance.recordError, and unblocks the iOS build —
sentry_flutter 8.14.2 wasn't compatible with the latest Sentry-iOS pod
(\`SentryBinaryImageCache has no member 'image'\`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ndler

Matches master's log handler (#2665) — the StreamChat log message
becomes the Crashlytics report reason, making errors triageable in the
dashboard instead of surfacing as bare stack traces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
xsahil03x and others added 3 commits May 26, 2026 12:33
In thread mode the message list was reading streamChannel.initialMessageId
as a fallback when the thread-local highlight wasn't set. But initialMessageId
is a channel-scoped pointer (set when navigating to the channel via deep
link); inside a thread it points at a message that doesn't belong to the
thread, leading _moveToAndHighlight into the wrong loader.

Switch on the conversation mode instead so each scope reads only its own
highlight source — _ThreadHighlightScope in threads, initialMessageId in
the channel. Matches Android's parentMessageId-discriminated focus path
and SwiftUI's per-view-model highlight environment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…vior

- Rename _moveToAndHighlight → _scrollToMessage; matches Android's
  scrollToMessage naming and the sibling scrollToBottom*/scrollToUnread*
  helpers in this file.
- Drop the unused `messages` param (always read `this.messages` so we
  stay current across awaits), the dead `initialScrollIndex` branch
  (SPL already mounts at it), and the `scrollTo: false` toggle (the
  jumpTo path was only used at initial highlight, where the SPL is
  already at the target).
- Make `messageId` required (no more nullable wrap), add `alignment`
  (default 0.5) and `highlight` (default true) knobs.
- Guard on `controller.isAttached` before calling `scrollTo`.
- In thread mode, bail when the target reply isn't loaded instead of
  falling through to loadChannelAtMessage (which would paginate the
  parent channel with a thread-reply id — wrong scope, clobbers the
  channel window). Matches Android/RN until a proper around-reply
  loader is wired.
- _ThreadHighlightScope.of switches to dependOnInheritedWidgetOfExactType
  (O(1) via the element's inheritance map, idiomatic for InheritedWidget).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- LoadingIndicator becomes a StatefulWidget and caches the
  queryTopMessages / queryBottomMessages stream as State (matches
  MessageListCore's `_messagesStream` pattern) — the getters on
  StreamChannelState return a fresh BehaviorSubject view per access, so
  reading them inside `build` caused BetterStreamBuilder to resubscribe
  on every rebuild.
- StreamChannelState is now read via StreamChannel.of(context); dropped
  the externally-passed `streamChannelState` field and the unused
  `streamTheme` / `isThreadConversation` fields.
- Retry callback is injected via onRetryPressed; the call site routes it
  through the existing _paginateData helper (which itself dispatches
  channel vs thread via MessageListController).
- In-flight spinner: now uses StreamLoadingSpinner (consistent with the
  other v10 scroll views) and `widget.builders.paginationLoadingIndicator`
  can still override it.
- Error tile: shows StreamScrollViewLoadMoreError.list with retry tap,
  replacing the previous plain Text — matches reaction / member / user
  grid views.
- _paginateData drops the unused `channel` parameter.
- Removed `_streamTheme` State field from StreamMessageListView (no
  remaining consumers after the indicator no longer needs it).

Also upgrades the initial-load defaultErrorBuilder in MessageListView
from plain text to StreamScrollViewErrorWidget with a retry that calls
streamChannel.reloadChannel(), so the empty/loading/error states all
share the same v10 visual language.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xsahil03x xsahil03x force-pushed the chore/merge-peformance-improvements-into-v10 branch from 15dff4f to ab9e403 Compare May 26, 2026 12:50
…ll check

Aligns with the `if (X case final Y?)` style used in LoadingIndicator
and drops the bang-assertion calls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without an explicit key, an unrelated rebuild in the surrounding tree
can drop the SPL's state — scroll position, item-position cache,
itemKeyBuilder anchors — and force a fresh mount. Keying on
\`cid:parentId\` makes the SPL stable across same-channel/same-thread
rebuilds, and forces a clean remount when the channel swaps or the
user enters/leaves a thread.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xsahil03x xsahil03x merged commit 427609a into v10.0.0 May 26, 2026
9 checks passed
@xsahil03x xsahil03x deleted the chore/merge-peformance-improvements-into-v10 branch May 26, 2026 13:16
@xsahil03x xsahil03x mentioned this pull request May 28, 2026
6 tasks
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.

2 participants