Skip to content

feat(mobile): Pulse polish — flat feed, compose page, shared filter chips, like + accent fixes#796

Merged
wesbillman merged 8 commits into
mainfrom
brain/pulse-polish
May 29, 2026
Merged

feat(mobile): Pulse polish — flat feed, compose page, shared filter chips, like + accent fixes#796
wesbillman merged 8 commits into
mainfrom
brain/pulse-polish

Conversation

@wesbillman
Copy link
Copy Markdown
Collaborator

@wesbillman wesbillman commented May 29, 2026

Pulse polish (mobile)

A series of mobile Pulse + shared-UI polish fixes, built iteratively with Wes on the sim.

Pulse feed & composer

  • Flatten the Pulse timeline (dividers instead of boxed cards) in agent_activity_card and note_card.
  • Replace the always-on inline composer with a full-screen ComposeNotePage reached via a + FAB and the note reply button; retire the old note_composer.
  • Reply preview renders the replied-to note as a compact, read-only list-style row (avatar + name + relative time + rich MessageContent so images/links/mentions show), clipped to a bounded height.

Shared components & consistency

  • Extract a single shared FilterChipBar and migrate Pulse, Search, and Activity onto it (deletes two hand-rolled chip rows). Fixes the “glow under the Pulse title” and unifies the chip style.
  • Selected filter chips use the accent via the Material-3 color WidgetStateProperty (the legacy selectedColor is ignored by M3 chips).
  • Make the Pulse FAB round + + to match Home; switch the Pulse bottom-nav icon to activity to match desktop.

Like button

  • Filled red heart when liked (Material favorite/favorite_border; Lucide is a stroke font where Icon.fill is a no-op).
  • Fix the like-count flash: keep the optimistic value sticky until the refetched server state matches it.

Theme

  • Saturate the dark-theme default Mauve accent (#C6A0F6#A875F5) so the default accent reads as a real color instead of near-white; drop the redundant duplicate “Lilac” accent.

Hero fix

  • Give the Pulse/Channels/Forum FABs unique heroTags — they coexist in HomePage's always-alive IndexedStack and were colliding on the default tag (“multiple heroes share the same tag”).

Tests

  • New widget tests: ComposeNotePage reply preview (renders rich content, stays height-bounded) + new-note state; FilterChipBar selected chip resolves the accent.
  • flutter analyze clean; full suite 341 pass / 1 skipped.

Screenshots (iPhone 17 Pro sim, dark theme)

Pulse feed — flat list with dividers, round + FAB, activity bottom-nav icon, accent-colored selected tab + nav label, and filled red like-hearts:

Pulse feed

Saturated default accent (bottom nav, "Pulse" selected) — the default Mauve now reads as a real color instead of near-white:

Accent nav

Note: images are hosted on the Sprout stage relay. The reply-compose page (full-screen ComposeNotePage with a compact rich preview of the replied-to note) is covered by widget tests; a live screenshot can be added on request.

@wesbillman wesbillman requested a review from a team as a code owner May 29, 2026 21:12
wesbillman and others added 8 commits May 29, 2026 14:14
…hips

- Flatten Pulse timeline (dividers instead of boxed cards) in
  agent_activity_card and note_card.
- Replace the inline note composer with a full-screen ComposeNotePage
  reached via a pencil/+ FAB and the note reply button; retire
  note_composer.dart.
- Make the Pulse FAB round (+) to match Home; switch the Pulse bottom-nav
  icon to activity to match desktop.
- Extract a shared FilterChipBar widget and migrate Activity, Pulse, and
  Search onto it; delete the two hand-rolled chip rows (PulseTabBar and
  Search's _FilterChips). Fixes the glow under the Pulse title and unifies
  the chip style across tabs.

flutter analyze clean; full suite 336 pass / 1 skipped.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
- Give the Pulse, Channels, and Forum FloatingActionButtons explicit
  heroTags. HomePage keeps tabs alive in an IndexedStack, so the Channels
  and Pulse FABs coexisted with Flutter's default hero tag and collided
  ("multiple heroes share the same tag") on any Hero flight — e.g. pushing
  the compose page or a reply.
- Render the replied-to note in ComposeNotePage as a read-only list-style
  row (avatar + name + relative time + formatted MessageContent) instead
  of raw text, capped at 140px height with clipping.

flutter analyze clean; full suite 336 pass / 1 skipped.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Widget tests asserting the reply-mode preview renders the replied-to
note (author name, "Replying to X", content) and pumps without throwing,
and that new-note mode shows no preview. Guards the rich reply preview.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
- The reply preview reserved a fixed ~140px height (ConstrainedBox), so
  even a one-line note rendered tall with a big gap before the divider.
  Render the row shrink-wrapped and cap the quoted content at 3 lines with
  ellipsis instead of the height-greedy markdown widget.
- Add breathing room between the "Replying to <name>" label and the row.
- Add a widget test asserting the preview hugs its content for short notes
  (guards the "too tall" regression).

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Restore MessageContent in the compose reply preview so images, links and
mentions render instead of raw markdown (e.g. "![image](https://…)").
Wrap it in a topLeft Align + ClipRect bounded to 132px so a tall image or
long note is clipped rather than blowing up the page — MessageContent
shrink-wraps for short content, so one-liners stay compact.

Add a widget test asserting an image note renders rich content (no raw
markdown) and the preview stays height-bounded.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
- Heart icon: Lucide is a stroke font and Icon.fill is a no-op for it, so
  the liked heart only ever showed a colored outline. Use Material's
  favorite/favorite_border pair so a liked note shows a filled red heart.
- Like count flash: the optimistic flag was cleared in `finally` before the
  reactions provider refetched, so the count flickered 1 → (stale 0) → 1.
  Keep the optimistic value sticky and clear it via an effect only once the
  refetched server state matches it.
- Filter chips: the shared chipTheme set no selectedColor, so selected
  tabs used Material's muted default. Use the accent (scheme.primary) for
  the selected chip with onPrimary label/icon, applied via chipTheme +
  FilterChipBar — Pulse, Search, and Activity all get the accent state.

flutter analyze clean; full suite 340 pass / 1 skipped.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
The previous fix set ChipThemeData.selectedColor, which is the legacy
Material-2 path that Material-3 FilterChips ignore — so selected chips fell
back to the near-white default instead of the accent. Drive the chip
container via the M3 `color` WidgetStateProperty (accent when selected,
surfaceContainerHighest otherwise). The accent is scheme.primary, which
already carries the user's chosen accent at runtime (same path the bottom
nav uses).

Add a widget test asserting the chip theme resolves the accent for the
selected state under a non-default (Blue) accent.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
The dark-theme default accent (Macchiato Mauve #C6A0F6) was so desaturated
it read as near-white — the default "accent" was indistinguishable from no
accent. Bump the dark Mauve to a saturated #A875F5 (primary, surfaceTint,
and the light scheme's inversePrimary), and update the Settings default
swatch to match so preview == applied. Also remove the redundant "Lilac"
accent (#C0A2F1), which was a near-duplicate of the old pale Mauve.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman wesbillman force-pushed the brain/pulse-polish branch 2 times, most recently from 14093fa to 18f160d Compare May 29, 2026 21:23
@wesbillman wesbillman merged commit b820420 into main May 29, 2026
15 checks passed
@wesbillman wesbillman deleted the brain/pulse-polish branch May 29, 2026 21:33
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