Files
buzz/mobile/lib/features/channels
Tom Brow 369e1ef322 perf(mobile): stop re-parsing message markdown on every rebuild (#8928)
## Context

Each message in a channel shows its text as Markdown. The `GptMarkdown`
widget parses that text. Parsing is slow for long messages.

`GptMarkdownTheme` gives Markdown colours and styles to the widgets
below it. When it gets a new theme data object, it tells all
`GptMarkdown` widgets below it to parse their text again. It compares
the old and new objects by identity, because `GptMarkdownThemeData` has
no value equality. Thus a new object with the same values also causes a
parse.

## Problem

Two widgets made a new theme data object on each build:
- `MessageContent` made one for each message bubble.
- `AppMarkdownTheme` made one for the full app.

Thus each rebuild parsed all messages on the screen again. Many events
cause a rebuild: a batch of profiles, a read marker, a keyboard frame.
In a large channel such as #4things (1,235 members), these events occur
almost all the time.

## Change

- `MessageContent` keeps its bubble theme until one of its inputs
changes. The inputs are: the app Markdown theme, the link colour, own or
other message, the ink colour and `onSurface`.
- `AppMarkdownTheme` makes new theme data only when `ThemeData` changes
or when an outer Markdown theme changes.

A change of colour, of brightness, or of own or other message still
makes new theme data. Then the Markdown parses again with the new
colours. This is correct.

### Related issue

None found.

## Testing

- New regression tests fail on main. They pass on this branch.
- `message_content_stability_test.dart`: When a bubble rebuilds with the
same inputs, it keeps the same theme object and the same parsed
`TextSpan`. The test does this for own messages and for other messages.
When own or other changes, the bubble gets a new theme.
- `app_markdown_theme_test.dart`: The app keeps one theme object when it
rebuilds. It makes a new one when light or dark mode changes.
- `just mobile-install mobile-check mobile-test` passes.
- Device test: iPhone 12 mini, Profile build, Tom's Block community,
open #4things. The two runs had different live traffic and different
cached content. Thus they show the cause and the fix. They do not give a
controlled speed measurement.
- Before: In the first 2.4 s, parses from rebuilds (`performRebuild`)
used approximately 90 ms. One frame used 116 ms. Approximately 48 ms of
that frame parsed visible messages again.
- After: In 30 s, rebuilds caused no parses. Only the first build of
each message (`_firstBuild`) parsed.
- An independent agent review found no defects. It found one small item:
`ChatColors` has no value equality. Thus a rebuild of `MaterialApp`
still makes new app theme data one time. This costs only a little
performance. We did not change it.

Not tested: A human test did not occur. The mobile testing exception
waives it, and an agent did the device test. No test occurred on an
Android device.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Tom Brow <tomb@squareup.com>
Co-authored-by: Tom Brow <tomb@squareup.com>
Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 08:00:33 -08:00
..