fix(ui): share the markdown style sheet between message texts - #192
Conversation
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #192 +/- ##
==========================================
+ Coverage 68.77% 70.05% +1.28%
==========================================
Files 213 213
Lines 8762 8773 +11
==========================================
+ Hits 6026 6146 +120
+ Misses 2736 2627 -109 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The row cache was cleared on every didUpdateWidget, so a parent that rebuilds StreamMessageListView often (for example a call-state builder around a livestream overlay) emptied it on each rebuild. It is now only cleared when a value the rows are built from changes: the configuration, the parent message, the message and row builders, and the row callbacks. Also bumps stream_core_flutter to include the shared markdown style sheet (GetStream/stream-core-flutter#192). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hmark Points stream_chat_flutter at GetStream/stream-chat-flutter#3024 (message rows are only rebuilt when they change), stream_core_flutter at GetStream/stream-core-flutter#192 (shared markdown style sheet), and stream_video_flutter at GetStream/stream-video-flutter#1392 (repaint boundaries around the livestream player). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The row cache was cleared on every didUpdateWidget, so a parent that rebuilds StreamMessageListView often (for example a call-state builder around a livestream overlay) emptied it on each rebuild. It is now only cleared when a value the rows are built from changes: the configuration, the parent message, the message and row builders, and the row callbacks. Also bumps stream_core_flutter to include the shared markdown style sheet (GetStream/stream-core-flutter#192). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The row cache was cleared on every didUpdateWidget, so a parent that rebuilds StreamMessageListView often (for example a call-state builder around a livestream overlay) emptied it on each rebuild. It is now only cleared when a value the rows are built from changes: the configuration, the parent message, the message and row builders, and the row callbacks. Also bumps stream_core_flutter to include the shared markdown style sheet (GetStream/stream-core-flutter#192). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DefaultStreamMessageText built a ThemeData copy, a full MarkdownStyleSheet and a new mention syntax (recompiling its pattern) on every build of every message. Style sheets are now memoized per theme and style inputs, and the mention syntax is a single shared instance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MarkdownStyleSheet's == and hashCode skip tableScrollbarThumbVisibility, so keying the cache on the caller's sheet let two different sheets share one entry. Key on the text and link style only and merge the caller's sheet after the lookup. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
b6f5e1c to
801c431
Compare
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(ui): only rebuild message rows that changed StreamMessageListView rebuilt every visible row in full on each new message, costing about one janky frame per message in busy channels. Rows are now reused while their message, neighbours and the current user are unchanged, so a new message rebuilds only its own row and the one it lands next to. The cache is cleared whenever the list widget or its dependencies change. StreamMessageText also resubscribed to the current user stream on every rebuild because it passed a freshly mapped stream; it now passes the stream unmapped and compares on language. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ui): cap the message row cache at 64 rows Only rows that are still mounted benefit from the cache, so it is now a least-recently-used cache of at most 64 rows instead of one entry per loaded message. This keeps memory constant in long-running channels where maximumMessageLimit is not set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ui): keep cached message rows when the list's parent rebuilds The row cache was cleared on every didUpdateWidget, so a parent that rebuilds StreamMessageListView often (for example a call-state builder around a livestream overlay) emptied it on each rebuild. It is now only cleared when a value the rows are built from changes: the configuration, the parent message, the message and row builders, and the row callbacks. Also bumps stream_core_flutter to include the shared markdown style sheet (GetStream/stream-core-flutter#192). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * perf(ui): reuse message rows until what they're built from changes Replace the message row cache with an internal MemoizedBuilder keyed on each row's StreamMessageItemProps, layout data and builder. A new message now rebuilds its own row, plus its neighbor's when that row's place in a run of messages changes; an edit or reaction rebuilds only its own row. This covers threads and lists with any number of mounted rows, and removes the 64-row cap and the cache clears. - StreamMessageItemProps now compares by value (Equatable). - The thread parent row is memoized the same way. System, ephemeral and moderated rows are unchanged, so custom builders keep the list's context and can still reach the page's ScaffoldMessenger. - The content kind is resolved only when a row rebuilds. - Point stream_core_flutter at the merged core#192 (1546087), which also restores #193. - Document when messageBuilder and the parent message builder run again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: Update Goldens * test(docs): stub isMarkedAsUnread in the docs channel state mock The message list reads it when it attaches to a channel; unstubbed, the mock returned null and the docs screenshots rendered an error screen. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: Update Goldens --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Sahil Kumar <sahil@getstream.io> Co-authored-by: xsahil03x <25670178+xsahil03x@users.noreply.github.com>
Why
A livestream load test on stream_chat_flutter showed about one janky frame per incoming message, with build time over budget. On every build of every message,
DefaultStreamMessageText.build:ThemeDatawithtextTheme.apply(...)MarkdownStyleSheet.fromTheme(...)_StreamMentionSyntax, recompiling itsRegExpWhat
ThemeDatainstance (held weakly in anExpando), keyed by the effective text style and link style. Messages with the same styles share one sheet. The cache holds at most 32 entries per theme and drops the oldest when it's full.styleSheetis merged on top after the lookup.static finalinstance.Testing
stream_message_text_style_sheet_test.dartcovers:styleSheetoverride stays separate;The full
stream_core_fluttersuite passes. Against the CI goldens, the same 50 local host-drift failures occur with and without this change, so there is no visual diff.Pixel 4, profile mode, 100 messages at 10/s, mean build time per message:
Companion to the stream-chat-flutter PR that stops
StreamMessageListViewrebuilding unchanged rows.🤖 Generated with Claude Code
Summary by CodeRabbit