corp-app/CORP-MAUI/ViewModels/ProfileViewModel.cs

219 lines
7.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<Skill> Skills => _user?.Skills ?? new List<Skill>();
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));
}