Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,52 @@ melos run generate:icons # regenerate icon font from SVGs
melos run gen-l10n # regenerate localizations
```

**Line width:** 120 characters (set in `analysis_options.yaml`).

### Icons

Source SVGs in `packages/stream_core_flutter/assets_source/icons/` come from the [design-system-tokens](https://github.com/GetStream/design-system-tokens/tree/main/assets/icons) repository. When adding or updating icons, pull the latest SVGs from that repo first, then run `melos run generate:icons` to regenerate the icon font and Dart classes.

**Line width:** 120 characters (set in `analysis_options.yaml`).
Upstream names carry a size suffix that this repo strips or rewrites: everything in `20/` keeps its bare name (`account-20.svg` → `account.svg`), `16/` currently holds only `xmark-small.svg`, and `32/` uses a `-large` suffix (`camera-32.svg` → `camera-large.svg`).

**Names must be unique across the size folders.** Glyphs are keyed by bare filename, so copying a whole upstream size folder is how you accidentally end up with e.g. `16/xmark-small.svg` and `20/xmark-small.svg` competing for one glyph. The generator fails on a duplicate rather than letting directory-listing order pick a winner.

**Code points are append-only.** `assets_source/icon_log.g.txt` records the date each icon was first seen, and the generator orders glyphs by that date so every icon keeps its code point across runs. The font ships as `lib/fonts/stream_icons_font.otf`, so a shifted code point silently repoints every icon after it in any app that has not rebuilt. Never reorder or hand-edit the log.

**Deleting an icon therefore requires a deprecation entry** in `assets_source/deprecated.txt` — one `deprecated;replacement;included` line per icon:

```
more;more-horizontal;true
```

- `replacement` — the icon whose SVG draws the glyph. A deprecated icon always keeps its glyph, and with it its code point; pointing at a replacement is what lets you delete the retired SVG and still render something sensible. Naming itself (`more;more;true`) keeps the original artwork while retiring the name.
- `included` — whether the name survives in the generated Dart. `true` emits `StreamIcons.more` and `StreamIconData.more` annotated with `@Deprecated('Use moreHorizontal instead.')`; `false` drops both while the glyph stays in the font.

Entries are effectively permanent — removing one releases its glyph and shifts every later code point. The generator fails if a replacement has no SVG file, or if a deprecated name has neither an SVG file nor a logged code point (which means a typo).

Deprecating an icon also means adding transforms to `lib/fix_data.yaml`; see [Deprecations](#deprecations).

## Design

UI components are designed in **Figma**. When implementing or modifying components, use the **Figma MCP** to inspect designs directly — check spacing, colors, typography, and component structure from the source rather than guessing.

## Deprecations

The policy itself lives in [`STYLE_GUIDE.md`](STYLE_GUIDE.md#clearly-mark-deprecated-apis): annotate with `@Deprecated('Use X instead.')`, add a `### 🛑 Breaking / Removals` CHANGELOG entry pointing at the replacement, and keep the deprecated API for at least one minor release.

On top of that, give every deprecated member a migration in `packages/stream_core_flutter/lib/fix_data.yaml` ([format docs](https://dart.dev/tools/dart-fix)) so consumers can move off it with:

```bash
dart fix --apply
```

Things worth knowing about that file:

- Dart only reads it at `lib/fix_data.yaml` or `lib/fix_data/*.yaml`. `element.uris` must list the library that declares the member **and** every barrel it is exported from (`core.dart`, `chat.dart`, `stream_core_flutter.dart`) — a transform whose uris miss the barrel the consumer actually imported never fires.
- Treat it as **append-only**. A transform's real value is carrying someone across the release that finally deletes the member, so it has to outlive the deprecation that motivated it. Never drop an entry just because the member is gone.
- A member reached only through generated code needs its own transform, and may not warn at all. `StreamIcons.copyWith(more: ...)` is the worked example: `copyWith` is generated onto the private `_$StreamIcons` mixin, which does not inherit the field's `@Deprecated`, so the call raises no warning while the field exists — its transform (`inMixin: "_$StreamIcons"`) only fires once the field is deleted and the call becomes an `undefined_named_parameter` error.
- **Verify a transform by running it, not by reading the YAML.** Write a throwaway file exercising each call shape (bare constant, instance field, constructor argument, `copyWith`), run `dart fix --dry-run`, then re-run with the transform removed to confirm the fix disappears — the analyzer offers generic "did you mean" fixes that are easy to mistake for your own.

## Architecture

### Public-Barrel Contract (`stream_core_flutter`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class _PlaygroundMediaViewerState extends State<_PlaygroundMediaViewer> {
title: const Text('You'),
subtitle: const Text('14/01/2026, 16:06'),
trailing: StreamButton.icon(
icon: Icon(icons.more),
icon: Icon(icons.moreHorizontal),
style: StreamButtonStyle.secondary,
type: StreamButtonType.ghost,
onPressed: () {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Widget buildStreamScaffoldDrawers(BuildContext context) {
leading: showDrawer
? Builder(
builder: (ctx) => StreamButton.icon(
icon: Icon(ctx.streamIcons.more),
icon: Icon(ctx.streamIcons.moreHorizontal),
style: StreamButtonStyle.secondary,
type: StreamButtonType.ghost,
onPressed: () => Scaffold.of(ctx).openDrawer(),
Expand Down Expand Up @@ -250,7 +250,7 @@ PreferredSizeWidget _demoAppBar(
leading: withDrawerButton
? Builder(
builder: (context) => StreamButton.icon(
icon: Icon(context.streamIcons.more),
icon: Icon(context.streamIcons.moreHorizontal),
style: StreamButtonStyle.secondary,
type: floating ? StreamButtonType.outline : StreamButtonType.ghost,
isFloating: floating,
Expand Down
20 changes: 20 additions & 0 deletions packages/stream_core_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,31 @@
### ✨ Features

- Added `StreamReactions.onReactionLongPressed`, reporting the long-pressed `StreamReactionsItem` — or `null` for the cluster/overflow chip. When null, the chips register no long-press gesture, leaving it to an ancestor.
- Refreshed the icon set from the design tokens and added 44 icons, including a
filled variant for many existing icons: `blurFill`, `boltFill`,
`cameraFlipFill`, `captionFill`, `caretDown`, `caretUp`, `copyFill`,
`darkMode`, `emojiAddFill`, `fullBlurFill`, `fullscreenFill`, `gridFill`,
`gridPixelFill`, `language`, `leftToRight`, `lightMode`, `menu`,
`messageBubblesFill`, `moreHorizontal`, `moreVerticalFill`, `noSignFill`,
`phoneDownFill`, `pinFill`, `pipFill`, `presentDesktopFill`,
`presentMobileFill`, `questionCircleFill`, `raiseHandFill`,
`recordLibraryFill`, `recordingFill`, `recordingStopFill`, `settings`,
`settingsFill`, `slidersFill`, `starFill`, `statsFill`, `unpinFill`,
`userAddFill`, `userRemoveFill`, `usersFill`, `verifiedFill`, `videoOffFill`,
`voiceOffFill`, and `xmarkSmall`.
- Added a `fix_data.yaml`, so deprecated members can be migrated with
`dart fix --apply`.

### 🔄 Changed

- Raised the minimum Flutter version to `>=3.44.0` and the Dart SDK to `^3.12.0`.

### 🛑 Breaking / Removals

- Deprecated `StreamIcons.more` / `StreamIconData.more` in favour of
`moreHorizontal`, which keeps the original artwork. A vertical variant is now
available as `moreVerticalFill`. Run `dart fix --apply` to migrate.

## 0.5.0

### ✨ Features
Expand Down
3 changes: 3 additions & 0 deletions packages/stream_core_flutter/assets_source/deprecated.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Icons deprecated and replaced with a new one, following `deprecated;replacement;included` pattern.
# Deprecated icons are kept around for some time, but will be removed at some point. When included is `false` we do keep the code points of other icons in the right order.
more;more-horizontal;true
43 changes: 43 additions & 0 deletions packages/stream_core_flutter/assets_source/icon_log.g.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,46 @@ xmark-small;2026414
unsupported-attachment;2026416
megaphone;2026610
shield;2026610
more-horizontal;2026818
present-mobile-fill;2026818
caret-down;2026818
video-off-fill;2026818
fullscreen-fill;2026818
raise-hand-fill;2026818
dark-mode;2026818
settings-fill;2026818
caption-fill;2026818
grid-fill;2026818
blur-fill;2026818
no-sign-fill;2026818
pip-fill;2026818
star-fill;2026818
emoji-add-fill;2026818
settings;2026818
recording-stop-fill;2026818
caret-up;2026818
sliders-fill;2026818
left-to-right;2026818
full-blur-fill;2026818
pin-fill;2026818
menu;2026818
grid-pixel-fill;2026818
users-fill;2026818
present-desktop-fill;2026818
bolt-fill;2026818
more-vertical-fill;2026818
user-remove-fill;2026818
light-mode;2026818
camera-flip-fill;2026818
voice-off-fill;2026818
copy-fill;2026818
message-bubbles-fill;2026818
user-add-fill;2026818
question-circle-fill;2026818
stats-fill;2026818
record-library-fill;2026818
phone-down-fill;2026818
language;2026818
verified-fill;2026818
unpin-fill;2026818
recording-fill;2026818
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading