using System.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Windows.Input; using CORP_MAUI.Models; using CORP_MAUI.Pages; using CORP_MAUI.Services; namespace CORP_MAUI.ViewModels; public class ProfileViewModel : INotifyPropertyChanged { private User? _user; private bool _isLoading; private string? _localImagePath; private ImageSource? _imageSource; public ProfileViewModel() { LoadProfileCommand = new Command(async () => await LoadProfileAsync()); LogoutCommand = new Command(async () => await LogoutAsync()); } public User? User { get => _user; set { _user = value; OnPropertyChanged(); OnPropertyChanged(nameof(FullName)); OnPropertyChanged(nameof(Username)); OnPropertyChanged(nameof(Email)); OnPropertyChanged(nameof(Position)); OnPropertyChanged(nameof(Department)); OnPropertyChanged(nameof(StatusText)); OnPropertyChanged(nameof(StatusColor)); OnPropertyChanged(nameof(Skills)); OnPropertyChanged(nameof(HasSkills)); } } public bool IsLoading { get => _isLoading; set { _isLoading = value; OnPropertyChanged(); } } // Wrappers for UI binding public string FullName => _user?.FullName ?? "Загрузка..."; public string Username => _user != null ? $"@{_user.Username}" : ""; public string Email => _user?.Email ?? "-"; public string Position => _user?.PositionName ?? "-"; public string Department => _user?.DepartmentName ?? "-"; public bool IsOnline => _user?.IsOnline ?? false; public string StatusText => IsOnline ? "В сети" : "Не в сети"; public Color StatusColor => IsOnline ? Colors.LimeGreen : Colors.Gray; public List Skills => _user?.Skills ?? new List(); public bool HasSkills => Skills.Any(); // Image Logic public ImageSource? DisplayImageSource { get { if (_imageSource != null) return _imageSource; if (!string.IsNullOrEmpty(_localImagePath) && File.Exists(_localImagePath)) { try { if (new FileInfo(_localImagePath).Length == 0) return null; return ImageSource.FromStream(() => { try { return new FileStream(_localImagePath, FileMode.Open, FileAccess.Read, FileShare.Read); } catch { return null; } }); } catch { return null; } } // Default placeholder if needed return ImageSource.FromFile("dotnet_bot.png"); } } public ICommand LoadProfileCommand { get; } public ICommand LogoutCommand { get; } public async Task LoadProfileAsync() { if (IsLoading) return; IsLoading = true; try { User? loadedUser = await ServiceProvider.ApiService.GetCurrentUserAsync(); if (loadedUser != null) { User = loadedUser; await LoadAvatarAsync(); } } catch (Exception ex) { Trace.WriteLine($"Error loading profile: {ex.Message}"); Page? mainPage = Application.Current?.Windows.FirstOrDefault()?.Page; if (mainPage != null) await mainPage.DisplayAlert("Ошибка", "Не удалось загрузить профиль", "OK"); } finally { IsLoading = false; } } private async Task LoadAvatarAsync() { if (_user == null || string.IsNullOrEmpty(_user.DisplayAvatarUrl)) return; try { string url = _user.DisplayAvatarUrl; // Generate cache filename Uri uri = new Uri(url); string extension = Path.GetExtension(uri.LocalPath); if (string.IsNullOrEmpty(extension)) extension = ".jpg"; string fileName = Path.GetFileNameWithoutExtension(uri.LocalPath); fileName = Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c, '_')); string cacheFileName = $"user_{_user.Id}_{fileName}{extension}"; string cacheFilePath = Path.Combine(FileSystem.CacheDirectory, cacheFileName); // Check cache if (File.Exists(cacheFilePath)) { FileInfo fileInfo = new FileInfo(cacheFilePath); if (fileInfo.Length > 0) { _localImagePath = cacheFilePath; OnPropertyChanged(nameof(DisplayImageSource)); return; } } // Download byte[]? bytes = await ServiceProvider.ApiService.GetImageBytesAsync(url); if (bytes is { Length: > 0 }) { // Simple signature check bool isImage = false; if (bytes.Length > 2) { if (bytes[0] == 0xFF && bytes[1] == 0xD8) isImage = true; else if (bytes[0] == 0x89 && bytes[1] == 0x50) isImage = true; else isImage = true; // Relaxed check if (bytes[0] == '<') isImage = false; // HTML check } if (isImage) { await File.WriteAllBytesAsync(cacheFilePath, bytes); _localImagePath = cacheFilePath; OnPropertyChanged(nameof(DisplayImageSource)); } } } catch (Exception ex) { Trace.WriteLine($"Avatar load error: {ex.Message}"); } } private async Task LogoutAsync() { Page? mainPage = Application.Current?.Windows.FirstOrDefault()?.Page; if (mainPage == null) return; bool result = await mainPage.DisplayAlert("Выход", "Вы уверены, что хотите выйти?", "Да", "Нет"); if (result) { try { await ServiceProvider.ApiService.UpdateStatusAsync(false); await ServiceProvider.WebSocketService.DisconnectAsync(); ServiceProvider.ApiService.Logout(); SecureStorage.Remove("user_id"); SecureStorage.Remove("username"); if (Application.Current?.Windows.Count > 0) { Application.Current.Windows[0].Page = new NavigationPage(new LoginPage()); } } catch(Exception ex) { await mainPage.DisplayAlert("Ошибка", $"Ошибка при выходе: {ex.Message}", "OK"); } } } public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string? name = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); }