import 'dart:convert'; /// Represents a Nostr user profile (metadata from kind 0 events). class NostrProfile { /// Public key (npub or hex). final String publicKey; /// Display name or username. final String? name; /// About/bio text. final String? about; /// Profile picture URL. final String? picture; /// Website URL. final String? website; /// NIP-05 identifier (e.g., user@domain.com). final String? nip05; /// Banner image URL. final String? banner; /// LUD16 (Lightning address). final String? lud16; /// Raw metadata JSON for additional fields. final Map rawMetadata; /// Timestamp when profile was last updated. final DateTime? updatedAt; /// Creates a [NostrProfile] instance. NostrProfile({ required this.publicKey, this.name, this.about, this.picture, this.website, this.nip05, this.banner, this.lud16, Map? rawMetadata, this.updatedAt, }) : rawMetadata = rawMetadata ?? {}; /// Creates a [NostrProfile] from Nostr metadata event content (JSON string). /// /// [publicKey] - The public key of the profile owner. /// [content] - JSON string from kind 0 event content. /// [updatedAt] - Optional timestamp when profile was updated. factory NostrProfile.fromEventContent({ required String publicKey, required String content, DateTime? updatedAt, }) { try { final metadata = jsonDecode(content) as Map; return NostrProfile( publicKey: publicKey, name: metadata['name'] as String?, about: metadata['about'] as String?, picture: metadata['picture'] as String?, website: metadata['website'] as String?, nip05: metadata['nip05'] as String?, banner: metadata['banner'] as String?, lud16: metadata['lud16'] as String?, rawMetadata: metadata, updatedAt: updatedAt ?? DateTime.now(), ); } catch (e) { // Return minimal profile if parsing fails return NostrProfile( publicKey: publicKey, rawMetadata: {}, updatedAt: updatedAt ?? DateTime.now(), ); } } /// Creates a [NostrProfile] from a JSON map. factory NostrProfile.fromJson(Map json) { return NostrProfile( publicKey: json['publicKey'] as String, name: json['name'] as String?, about: json['about'] as String?, picture: json['picture'] as String?, website: json['website'] as String?, nip05: json['nip05'] as String?, banner: json['banner'] as String?, lud16: json['lud16'] as String?, rawMetadata: json['rawMetadata'] as Map? ?? {}, updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt'] as String) : null, ); } /// Converts [NostrProfile] to JSON. Map toJson() { return { 'publicKey': publicKey, 'name': name, 'about': about, 'picture': picture, 'website': website, 'nip05': nip05, 'banner': banner, 'lud16': lud16, 'rawMetadata': rawMetadata, 'updatedAt': updatedAt?.toIso8601String(), }; } /// Gets display name (name, nip05, or public key prefix). String get displayName { if (name != null && name!.isNotEmpty) return name!; if (nip05 != null && nip05!.isNotEmpty) return nip05!; return publicKey.length > 16 ? '${publicKey.substring(0, 8)}...${publicKey.substring(publicKey.length - 8)}' : publicKey; } @override String toString() { return 'NostrProfile(publicKey: ${publicKey.substring(0, 8)}..., name: $name)'; } }