import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../i18n/strings.g.dart'; import '../services/profile_store.dart'; import '../services/social_service.dart'; import '../services/social_settings.dart'; import 'qr_view.dart'; import 'theme.dart'; /// Your own profile: the shareable identity (npub) plus a display name and short /// "about" others see instead of a raw key. Saving persists locally and, when /// online, publishes NIP-01 kind:0 metadata so peers can recognise you. class ProfileScreen extends StatefulWidget { const ProfileScreen({ required this.social, required this.settings, required this.profileStore, super.key, }); final SocialService social; final SocialSettings settings; final ProfileStore profileStore; @override State createState() => _ProfileScreenState(); } class _ProfileScreenState extends State { final _name = TextEditingController(); final _about = TextEditingController(); bool _loading = true; bool _saving = false; @override void initState() { super.initState(); _load(); } Future _load() async { _name.text = await widget.profileStore.name(); _about.text = await widget.profileStore.about(); if (mounted) setState(() => _loading = false); } Future _copyId() async { final messenger = ScaffoldMessenger.of(context); final t = context.t; await Clipboard.setData(ClipboardData(text: widget.social.npub)); if (!mounted) return; messenger.showSnackBar(SnackBar(content: Text(t.profile.copied))); } Future _save() async { final messenger = ScaffoldMessenger.of(context); final t = context.t; setState(() => _saving = true); await widget.profileStore.save(name: _name.text, about: _about.text); // Best-effort publish to the network so peers see the name. final relays = await widget.settings.relayUrls(); if (relays.isNotEmpty) { try { final session = await widget.social.openSession(relays); await session.profile.publish( name: _name.text.trim(), about: _about.text.trim(), ); await session.close(); } catch (_) { // offline / unreachable — the local copy is saved regardless. } } if (!mounted) return; setState(() => _saving = false); messenger.showSnackBar(SnackBar(content: Text(t.profile.saved))); } @override void dispose() { _name.dispose(); _about.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final t = context.t; return Scaffold( appBar: AppBar(title: Text(t.profile.title)), body: _loading ? const Center(child: CircularProgressIndicator()) : ListView( padding: const EdgeInsets.all(20), children: [ _IdentityCard(npub: widget.social.npub, onCopy: _copyId), const SizedBox(height: 24), TextField( key: const Key('profile.name'), controller: _name, decoration: InputDecoration( labelText: t.profile.name, helperText: t.profile.nameHint, ), ), const SizedBox(height: 16), TextField( key: const Key('profile.about'), controller: _about, minLines: 2, maxLines: 4, decoration: InputDecoration( labelText: t.profile.about, helperText: t.profile.aboutHint, ), ), const SizedBox(height: 24), FilledButton( key: const Key('profile.save'), onPressed: _saving ? null : _save, child: _saving ? const SizedBox( height: 18, width: 18, child: CircularProgressIndicator(strokeWidth: 2), ) : Text(t.profile.save), ), ], ), ); } } class _IdentityCard extends StatelessWidget { const _IdentityCard({required this.npub, required this.onCopy}); final String npub; final VoidCallback onCopy; @override Widget build(BuildContext context) { final t = context.t; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: seedPrimaryContainer.withValues(alpha: 0.4), borderRadius: BorderRadius.circular(14), border: Border.all(color: seedOutline), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( t.profile.yourId, style: const TextStyle( fontWeight: FontWeight.w600, color: seedOnSurface, ), ), const SizedBox(height: 4), Text( t.profile.idHelp, style: const TextStyle(color: seedMuted, fontSize: 12), ), const SizedBox(height: 14), Center(child: QrView(data: npub, size: 200)), const SizedBox(height: 12), SelectableText( npub, style: const TextStyle( fontFamily: 'monospace', fontSize: 12, color: seedOnSurface, ), ), const SizedBox(height: 8), Align( alignment: AlignmentDirectional.centerEnd, child: TextButton.icon( key: const Key('profile.copyId'), onPressed: onCopy, icon: const Icon(Icons.copy, size: 16), label: Text(t.profile.copy), ), ), ], ), ); } }