import 'package:flutter/material.dart'; /// A small round avatar for a chat peer. We have no profile photos yet, so it's /// a deterministic disc coloured from the peer's pubkey, showing the first /// letter of their [name] when known (else a person glyph). Same pubkey → same /// colour on every device, so the peer is visually recognizable. class PeerAvatar extends StatelessWidget { const PeerAvatar({ required this.pubkey, this.name, this.radius = 14, super.key, }); final String pubkey; final String? name; final double radius; @override Widget build(BuildContext context) { final letter = _initial(name); return CircleAvatar( radius: radius, backgroundColor: peerAvatarColor(pubkey), child: letter == null ? Icon(Icons.person_outline, size: radius, color: Colors.white) : Text( letter, style: TextStyle( color: Colors.white, fontSize: radius, fontWeight: FontWeight.w600, ), ), ); } static String? _initial(String? name) { if (name == null) return null; final trimmed = name.trim(); if (trimmed.isEmpty) return null; // characters.first handles emoji/combining marks safely. return trimmed.characters.first.toUpperCase(); } } /// A deterministic, readable avatar colour derived from [pubkey]. Hashes the /// key to a hue, then fixes saturation/lightness so white text stays legible on /// top. Pure and stable — exposed for testing. Color peerAvatarColor(String pubkey) { // FNV-1a over the code units — cheap, stable, well-spread across hues. var hash = 0x811c9dc5; for (final unit in pubkey.codeUnits) { hash = (hash ^ unit) * 0x01000193; hash &= 0xffffffff; } final hue = (hash % 360).toDouble(); return HSLColor.fromAHSL(1, hue, 0.45, 0.42).toColor(); }