import 'package:flutter/material.dart'; import 'dart:typed_data'; import '../../core/service_locator.dart'; import '../navigation/main_navigation_scaffold.dart'; /// Primary AppBar widget with user icon for all main screens. class PrimaryAppBar extends StatefulWidget implements PreferredSizeWidget { final String title; const PrimaryAppBar({ super.key, required this.title, }); @override State createState() => _PrimaryAppBarState(); @override Size get preferredSize => const Size.fromHeight(kToolbarHeight); } class _PrimaryAppBarState extends State { Uint8List? _avatarBytes; bool _isLoadingAvatar = false; String? _lastProfilePictureUrl; // Track URL to avoid reloading @override void initState() { super.initState(); _loadAvatar(); } @override void didChangeDependencies() { super.didChangeDependencies(); // Only reload if the profile picture URL has changed final sessionService = ServiceLocator.instance.sessionService; if (sessionService != null && sessionService.isLoggedIn) { final currentUser = sessionService.currentUser; final profilePictureUrl = currentUser?.nostrProfile?.picture; if (profilePictureUrl != _lastProfilePictureUrl) { _lastProfilePictureUrl = profilePictureUrl; _loadAvatar(); } } } Future _loadAvatar() async { final sessionService = ServiceLocator.instance.sessionService; if (sessionService == null || !sessionService.isLoggedIn) { // Clear avatar when logged out if (mounted) { setState(() { _avatarBytes = null; _isLoadingAvatar = false; _lastProfilePictureUrl = null; }); } return; } final currentUser = sessionService.currentUser; if (currentUser == null) { if (mounted) { setState(() { _avatarBytes = null; _isLoadingAvatar = false; _lastProfilePictureUrl = null; }); } return; } final profilePictureUrl = currentUser.nostrProfile?.picture; if (profilePictureUrl == null || profilePictureUrl.isEmpty) { // Clear avatar if no profile picture if (mounted) { setState(() { _avatarBytes = null; _isLoadingAvatar = false; _lastProfilePictureUrl = null; }); } return; } // Don't reload if it's the same URL if (profilePictureUrl == _lastProfilePictureUrl && _avatarBytes != null) { return; } _lastProfilePictureUrl = profilePictureUrl; setState(() { _isLoadingAvatar = true; }); try { // Extract asset ID from Immich URL using regex (same as SessionScreen) final mediaService = ServiceLocator.instance.mediaService; if (mediaService != null) { // Try to extract asset ID from URL (format: .../api/assets/{id}/original or .../share/{shareId}) final assetIdMatch = RegExp(r'/api/assets/([^/]+)/').firstMatch(profilePictureUrl); String? assetId; if (assetIdMatch != null) { assetId = assetIdMatch.group(1); } else { // For Blossom URLs, use the full URL assetId = profilePictureUrl; } if (assetId != null) { final bytes = await mediaService.fetchImageBytes(assetId, isThumbnail: true); if (mounted) { setState(() { _avatarBytes = bytes; _isLoadingAvatar = false; }); } return; } } // Fallback: try to fetch as regular image (for non-Immich URLs or shared links) // For now, we'll just set loading to false if (mounted) { setState(() { _isLoadingAvatar = false; }); } } catch (e) { // Log error for debugging debugPrint('Failed to load avatar: $e'); if (mounted) { setState(() { _isLoadingAvatar = false; _avatarBytes = null; // Clear on error }); } } } @override Widget build(BuildContext context) { return AppBar( title: Text(widget.title), actions: [ // Only show user icon on Home screen (title == 'Home') if (widget.title == 'Home') IconButton( icon: _buildUserIcon(), tooltip: 'User', onPressed: () { // Navigate to User screen by finding the MainNavigationScaffold final scaffold = context.findAncestorStateOfType(); scaffold?.navigateToUser(); }, ), ], ); } Widget _buildUserIcon() { if (_isLoadingAvatar) { return const CircleAvatar( radius: 12, backgroundColor: Colors.transparent, child: SizedBox( width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2), ), ); } if (_avatarBytes != null) { return CircleAvatar( radius: 12, backgroundImage: MemoryImage(_avatarBytes!), onBackgroundImageError: (_, __) { // Clear avatar on error if (mounted) { setState(() { _avatarBytes = null; }); } }, ); } return const CircleAvatar( radius: 12, child: Icon(Icons.person, size: 16), ); } }