Drop the DiceBear generated avatar (and dicebear_core/dicebear_styles/
flutter_svg): the default is again a Material coloured-initial disc from
the pubkey. Picking a photo now goes through a square crop step
(crop_your_image — pure Flutter, all platforms incl. desktop, Apache-2.0,
only pulls the image package we already had) before the 24 KB thumbnail.
Replace the flutter_boring_avatars fallback with a friendly DiceBear
"thumbs" face, generated offline (dicebear_core) and deterministically
from the pubkey, rendered as SVG (flutter_svg). The thumbs style is
CC0 1.0 (public domain) — no attribution, AGPL-clean — unlike Multiavatar
whose custom licence restricts use. Style parsed once and per-pubkey SVG
memoized; the CC0 <metadata> block is stripped to keep flutter_svg quiet.
People without a photo or seed illustration now get a deterministic
pattern avatar drawn from their pubkey (flutter_boring_avatars, MIT),
in an earthy seed-tone palette, replacing the coloured-initial disc.
Same pubkey renders the same picture on every device with nothing shared.
Follow-up to the avatar feature: peers' published photos/illustrations
now actually render where people appear.
- CachedAvatar: a PeerAvatar that resolves the person's picture from the
ProfileCache (FutureBuilder), falling back to the coloured-initial disc.
For list/row sites — one avatar each.
- Chat bubbles: the peer's and my own avatar are resolved once into state
(_peerPicture/_selfPicture — from the cache / ProfileStore, freshened
from the peer's published profile) and threaded to each bubble, so many
bubbles of two people don't each hit the cache.
- Chat list + your-people rows: swapped the static person-icon disc for
CachedAvatar, so photos/illustrations show there too.
- Tests: CachedAvatar render modes (cached illustration / initial / no
cache). analyze clean; chat + your-people suites green.
Market offers show no author avatar today (would be a new element, not a
swap) — left out of scope.
Profiles had only a coloured-initial disc. Now each person can set an
avatar — a real photo OR one of our own seed illustrations (so
pseudonymity stays the default; no photo required).
- ui/avatar.dart: the one-string value scheme carried in the kind:0
'picture' — a 'data:' photo thumbnail, a 'tane:seed:<glyph>' token, or
empty. The Nostr ProfileTransport already published 'picture'.
- Photos ride inline as a tiny thumbnail (reuses offerThumbnailDataUri,
24 KB cap) — no media server, like offer photos.
- avatar_edit.dart: pick/take a photo, choose a seed illustration, or
remove; ProfileStore stores it; ProfileScreen shows a big editable
avatar and publishes it.
- PeerAvatar renders photo / illustration / initial fallback.
- ProfileCache gains picture/setPicture; the inbox caches peers' avatars
alongside their names.
- i18n avatar block (en/es/pt/ast). Tests: value scheme + PeerAvatar
render modes, store + cache round-trips.
Follow-up: render peers' avatars in chat/market/your-people (thread the
cached picture into PeerAvatar at each call site).
- Anchor the message list to the bottom (`reverse: true`) so new messages
stay in view instead of landing below the fold.
- Move chat history from the OS keystore (O(n²) JSON blob, silent 200-msg
cap) to a separate encrypted Drift/SQLCipher DB (`ChatDatabase`):
indexed append, uncapped history, dedup as a unique-key invariant. It's
an ephemeral per-device cache, isolated from the inventory schema, its
migrations, and its sync. No data migration (pre-release).
- Add day separators (Today/Yesterday/locale date) and a per-bubble time,
all via ICU (12/24h per locale; Localizations locale maps Asturian →
Spanish for intl date symbols).
- Add peer avatars (deterministic colour from the pubkey + name initial),
surface send failures that were previously silent, and make bubble text
selectable (addresses, links).
- New i18n keys in en/es/pt/ast; tests for grouping, formatting, avatars,
scroll anchoring, storage and send errors.
Docs: docs/design/chat-storage.md + open-decisions.md.