diff --git a/lib/data/session/session_service.dart b/lib/data/session/session_service.dart index 592cd94..b0a0224 100644 --- a/lib/data/session/session_service.dart +++ b/lib/data/session/session_service.dart @@ -382,6 +382,50 @@ class SessionService { await _loadPreferredRelaysIfAvailable(); } + /// Refreshes the current user's Nostr profile and preferred relays. + /// + /// Re-fetches the profile from relays and reloads preferred relays from NIP-05. + /// + /// Throws [SessionException] if refresh fails or if no user is logged in. + Future refreshNostrProfile() async { + if (_currentUser == null) { + throw SessionException('No user logged in.'); + } + + if (_nostrService == null) { + throw SessionException('Nostr service not available'); + } + + // Only refresh if user has Nostr profile (logged in with Nostr) + if (_currentUser!.nostrProfile == null && _currentUser!.nostrPrivateKey == null) { + throw SessionException('User is not logged in with Nostr'); + } + + try { + // Re-fetch profile from relays + NostrProfile? profile; + try { + profile = await _nostrService!.fetchProfile(_currentUser!.id); + } catch (e) { + debugPrint('Warning: Failed to refresh Nostr profile: $e'); + // Continue without profile update - offline-first behavior + } + + // Update user with refreshed profile + if (profile != null) { + _currentUser = _currentUser!.copyWith(nostrProfile: profile); + } + + // Reload preferred relays from NIP-05 if available + await _loadPreferredRelaysIfAvailable(); + } catch (e) { + if (e is SessionException) { + rethrow; + } + throw SessionException('Failed to refresh Nostr profile: $e'); + } + } + /// Internal method to load preferred relays from NIP-05 if available. Future _loadPreferredRelaysIfAvailable() async { if (_currentUser == null || _nostrService == null) { diff --git a/lib/ui/session/session_screen.dart b/lib/ui/session/session_screen.dart index 5f4d187..6e2246c 100644 --- a/lib/ui/session/session_screen.dart +++ b/lib/ui/session/session_screen.dart @@ -267,6 +267,33 @@ class _SessionScreenState extends State { } } + Future _handleRefresh() async { + if (widget.sessionService == null) return; + + try { + await widget.sessionService!.refreshNostrProfile(); + if (mounted) { + setState(() {}); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Session data refreshed'), + duration: Duration(seconds: 2), + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to refresh: ${e.toString().replaceAll('SessionException: ', '')}'), + backgroundColor: Colors.red, + duration: const Duration(seconds: 3), + ), + ); + } + } + } + @override Widget build(BuildContext context) { final isLoggedIn = widget.sessionService?.isLoggedIn ?? false; @@ -278,11 +305,20 @@ class _SessionScreenState extends State { ), body: _isLoading ? const Center(child: CircularProgressIndicator()) - : SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ + : _buildRefreshableContent(isLoggedIn, currentUser), + ); + } + + Widget _buildRefreshableContent(bool isLoggedIn, currentUser) { + final canRefresh = isLoggedIn && + (currentUser?.nostrProfile != null || currentUser?.nostrPrivateKey != null); + + final content = SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ if (isLoggedIn && currentUser != null) ...[ Card( child: Padding( @@ -613,9 +649,17 @@ class _SessionScreenState extends State { ), ], ], - ), - ), - ); + ), + ); + + if (canRefresh) { + return RefreshIndicator( + onRefresh: _handleRefresh, + child: content, + ); + } else { + return content; + } } }