feat(profile): drop seed-glyph illustrations from the avatar picker

The picker now offers only a photo; with none, the generated DiceBear
avatar is used. Removes the seedks-ttf illustration row (and the now-dead
avatarGlyphNames/avatarGlyphToken). tane:seed:<glyph> values set before
this still render (avatarGlyphChar kept) for backward compatibility.
This commit is contained in:
vjrj 2026-07-12 23:22:20 +02:00
parent d4a9142ee2
commit 9560d0d18f
3 changed files with 15 additions and 54 deletions

View file

@ -1,29 +1,19 @@
import 'seed_glyph.dart';
/// A profile avatar is carried in one string (stored locally and published as
/// the NIP-01 kind:0 `picture`), in one of three shapes:
/// the NIP-01 kind:0 `picture`), in one of two shapes:
/// - `data:image/jpeg;base64,` a tiny photo thumbnail (rides inline, no
/// media server, like offer photos);
/// - `tane:seed:<name>` one of our own seed illustrations (for people who'd
/// rather not put a real photo pseudonymity stays the default);
/// - empty a DiceBear "thumbs" face generated deterministically from the pubkey.
///
/// A legacy `tane:seed:<name>` value (a seed illustration, no longer offered in
/// the picker) is still rendered for anyone who set one before; see
/// [avatarGlyphChar].
const avatarGlyphPrefix = 'tane:seed:';
/// The seed illustrations offered as ready-made avatars. Names are the stable
/// storage key (appended to [avatarGlyphPrefix]); the glyphs already ship in
/// [SeedGlyphs]. Order is the picker order.
const avatarGlyphNames = <String>[
'jars',
'sack',
'jar',
'scattered',
'pouring',
'mug',
'bigSpoon',
'smallSpoon',
];
/// The glyph char for an avatar illustration [name], or null if unknown.
/// The glyph char for a legacy seed-illustration [name], or null if unknown.
/// Retained only to render `tane:seed:` avatars stored before the picker dropped
/// them; new avatars are photos or the generated default.
String? avatarGlyphChar(String name) => switch (name) {
'jars' => SeedGlyphs.jars,
'sack' => SeedGlyphs.sack,
@ -35,6 +25,3 @@ String? avatarGlyphChar(String name) => switch (name) {
'smallSpoon' => SeedGlyphs.smallSpoon,
_ => null,
};
/// The token that selects illustration [name] (e.g. `tane:seed:jars`).
String avatarGlyphToken(String name) => '$avatarGlyphPrefix$name';

View file

@ -2,16 +2,14 @@ import 'package:flutter/material.dart';
import '../i18n/strings.g.dart';
import '../services/offer_thumbnail.dart' show offerThumbnailDataUri;
import 'avatar.dart';
import 'photo_pick.dart';
import 'seed_glyph.dart';
import 'theme.dart';
/// Lets the user choose a profile avatar: take/pick a photo (shrunk to a tiny
/// inline thumbnail), pick one of our seed illustrations, or remove it.
/// inline thumbnail) or remove it. With no photo, a generated avatar is used.
///
/// Returns the new avatar value (`data:` thumbnail or `tane:seed:<glyph>`),
/// an empty string to clear it, or null when cancelled.
/// Returns the new avatar value (a `data:` photo thumbnail), an empty string to
/// clear it (falls back to the generated avatar), or null when cancelled.
Future<String?> showAvatarPicker(
BuildContext context, {
required String current,
@ -46,29 +44,6 @@ Future<String?> showAvatarPicker(
}
},
),
const SizedBox(height: 6),
Text(t.avatar.illustration,
style: const TextStyle(color: seedMuted, fontSize: 13)),
const SizedBox(height: 10),
Wrap(
spacing: 14,
runSpacing: 14,
children: [
for (final name in avatarGlyphNames)
InkWell(
key: Key('avatar.glyph.$name'),
borderRadius: BorderRadius.circular(40),
onTap: () => Navigator.of(sheetContext)
.pop(avatarGlyphToken(name)),
child: CircleAvatar(
radius: 24,
backgroundColor: seedGreen,
child: SeedGlyph(avatarGlyphChar(name)!,
size: 26, color: Colors.white),
),
),
],
),
if (current.isNotEmpty) ...[
const SizedBox(height: 8),
Align(