nostr login fetch details and nip05

This commit is contained in:
gitea
2025-11-06 21:07:14 +01:00
parent d68124d975
commit 120a04c69f
10 changed files with 652 additions and 118 deletions
+194
View File
@@ -1,17 +1,20 @@
import 'package:flutter/material.dart';
import '../../data/session/session_service.dart';
import '../../data/firebase/firebase_service.dart';
import '../../data/nostr/nostr_service.dart';
/// Screen for user session management (login/logout).
class SessionScreen extends StatefulWidget {
final SessionService? sessionService;
final FirebaseService? firebaseService;
final NostrService? nostrService;
final VoidCallback? onSessionChanged;
const SessionScreen({
super.key,
this.sessionService,
this.firebaseService,
this.nostrService,
this.onSessionChanged,
});
@@ -342,6 +345,17 @@ class _SessionScreenState extends State<SessionScreen> {
const Divider(),
const SizedBox(height: 12),
],
// NIP-05 section
if (currentUser.nostrProfile?.nip05 != null &&
currentUser.nostrProfile!.nip05!.isNotEmpty)
_Nip05Section(
nip05: currentUser.nostrProfile!.nip05!,
publicKey: currentUser.id,
nostrService: widget.nostrService,
),
if (currentUser.nostrProfile?.nip05 != null &&
currentUser.nostrProfile!.nip05!.isNotEmpty)
const SizedBox(height: 12),
Text('User ID: ${currentUser.id.substring(0, currentUser.id.length > 32 ? 32 : currentUser.id.length)}${currentUser.id.length > 32 ? '...' : ''}'),
Text('Username: ${currentUser.username}'),
Text(
@@ -494,3 +508,183 @@ class _SessionScreenState extends State<SessionScreen> {
}
}
/// Widget for displaying NIP-05 information including domain and preferred relays.
class _Nip05Section extends StatefulWidget {
final String nip05;
final String publicKey;
final NostrService? nostrService;
const _Nip05Section({
required this.nip05,
required this.publicKey,
this.nostrService,
});
@override
State<_Nip05Section> createState() => _Nip05SectionState();
}
class _Nip05SectionState extends State<_Nip05Section> {
List<String> _preferredRelays = [];
bool _isLoading = false;
String? _error;
@override
void initState() {
super.initState();
_loadPreferredRelays();
}
Future<void> _loadPreferredRelays() async {
if (widget.nostrService == null) {
setState(() {
_error = 'Nostr service not available';
});
return;
}
setState(() {
_isLoading = true;
_error = null;
});
try {
final relays = await widget.nostrService!.fetchPreferredRelaysFromNip05(
widget.nip05,
widget.publicKey,
);
setState(() {
_preferredRelays = relays;
_isLoading = false;
});
} catch (e) {
setState(() {
_error = e.toString().replaceAll('NostrException: ', '');
_isLoading = false;
});
}
}
String _getDomain() {
final parts = widget.nip05.split('@');
if (parts.length == 2) {
return parts[1];
}
return widget.nip05;
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'NIP-05',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Row(
children: [
const Icon(Icons.verified, size: 16, color: Colors.blue),
const SizedBox(width: 8),
Expanded(
child: Text(
widget.nip05,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
],
),
const SizedBox(height: 8),
Text(
'Domain: ${_getDomain()}',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
const SizedBox(height: 12),
const Text(
'Preferred Relays',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
if (_isLoading)
const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
)
else if (_error != null)
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.red.shade50,
borderRadius: BorderRadius.circular(4),
border: Border.all(color: Colors.red.shade200),
),
child: Row(
children: [
Icon(Icons.error_outline, size: 16, color: Colors.red.shade700),
const SizedBox(width: 8),
Expanded(
child: Text(
_error!,
style: TextStyle(
fontSize: 12,
color: Colors.red.shade700,
),
),
),
],
),
)
else if (_preferredRelays.isEmpty)
Text(
'No preferred relays found',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
fontStyle: FontStyle.italic,
),
)
else
..._preferredRelays.map((relay) => Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(
children: [
Icon(
Icons.link,
size: 14,
color: Colors.grey[600],
),
const SizedBox(width: 8),
Expanded(
child: Text(
relay,
style: TextStyle(
fontSize: 12,
color: Colors.grey[700],
),
),
),
],
),
)),
],
);
}
}