using System.Collections.ObjectModel; using CloudPrint.Client.Infrastructure; using CloudPrint.Client.Models; using CloudPrint.Client.Services; using CloudPrint.Client.Services.Abstractions; using Microsoft.Win32; namespace CloudPrint.Client.ViewModels; public sealed class LibraryViewModel : ObservableObject { private readonly IFileService _fileService; private readonly IPrintBackendClient _backendClient; private readonly ClientSettings _settings; private LibraryCategory? _selectedCategory; private CloudPrintDocument? _selectedDocument; private string _statusMessage = "文库就绪"; public LibraryViewModel() : this(new FileService(), new GrpcService(), new ClientSettings()) { } public LibraryViewModel(IFileService fileService, IPrintBackendClient backendClient, ClientSettings settings) { _fileService = fileService; _backendClient = backendClient; _settings = settings; Categories.Add(new LibraryCategory { Id = 1, Name = "教材资料", Icon = "📘", SortOrder = 1 }); Categories.Add(new LibraryCategory { Id = 2, Name = "考试真题", Icon = "📝", SortOrder = 2 }); Categories.Add(new LibraryCategory { Id = 3, Name = "证件照片", Icon = "🖼️", SortOrder = 3 }); Categories.Add(new LibraryCategory { Id = 4, Name = "其他文件", Icon = "📁", SortOrder = 99 }); SelectedCategory = Categories.FirstOrDefault(); AddDocumentCommand = new RelayCommand(AddDocument); RemoveDocumentCommand = new RelayCommand(RemoveSelectedDocument, () => SelectedDocument is not null); SyncSelectedCommand = new AsyncRelayCommand(SyncSelectedAsync, () => SelectedDocument is not null && _backendClient.IsConnected); SyncAllCommand = new AsyncRelayCommand(SyncAllAsync, () => Documents.Any(document => !document.IsUploaded) && _backendClient.IsConnected); } public ObservableCollection Categories { get; } = new(); public ObservableCollection Documents { get; } = new(); public LibraryCategory? SelectedCategory { get => _selectedCategory; set => SetProperty(ref _selectedCategory, value); } public CloudPrintDocument? SelectedDocument { get => _selectedDocument; set { if (SetProperty(ref _selectedDocument, value)) { RemoveDocumentCommand.RaiseCanExecuteChanged(); SyncSelectedCommand.RaiseCanExecuteChanged(); } } } public string StatusMessage { get => _statusMessage; private set => SetProperty(ref _statusMessage, value); } public RelayCommand AddDocumentCommand { get; } public RelayCommand RemoveDocumentCommand { get; } public AsyncRelayCommand SyncSelectedCommand { get; } public AsyncRelayCommand SyncAllCommand { get; } public void RefreshCommandState() { SyncSelectedCommand.RaiseCanExecuteChanged(); SyncAllCommand.RaiseCanExecuteChanged(); } private void AddDocument() { var dialog = new Microsoft.Win32.OpenFileDialog { Title = "选择要加入文库的文件", Multiselect = true, Filter = "支持的文件|*.pdf;*.doc;*.docx;*.txt;*.xls;*.xlsx;*.ppt;*.pptx;*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.zip;*.rar|所有文件|*.*" }; if (dialog.ShowDialog() != true) { return; } var addedCount = 0; var categoryName = SelectedCategory?.Name ?? "未分类"; var limit = Math.Max(1, _settings.MaxUploadSizeMb) * 1024L * 1024L; foreach (var fileName in dialog.FileNames) { var validation = _fileService.ValidateFile(fileName, limit); if (!validation.IsValid) { StatusMessage = $"跳过 {System.IO.Path.GetFileName(fileName)}:{validation.Message}"; continue; } var document = _fileService.CopyToLibrary(fileName, _settings.LibraryRoot, categoryName, SelectedCategory?.Id ?? 0); Documents.Insert(0, document); addedCount++; } StatusMessage = addedCount > 0 ? $"已加入 {addedCount} 个文件到文库" : "没有文件被加入文库"; RefreshCommandState(); } private void RemoveSelectedDocument() { if (SelectedDocument is null) { return; } var document = SelectedDocument; Documents.Remove(document); SelectedDocument = null; StatusMessage = $"已从列表移除:{document.Title}"; RefreshCommandState(); } private async Task SyncSelectedAsync() { if (SelectedDocument is null) { return; } await _backendClient.UploadLibraryDocumentAsync(SelectedDocument).ConfigureAwait(true); StatusMessage = $"已同步:{SelectedDocument.Title}"; RefreshCommandState(); } private async Task SyncAllAsync() { var pendingDocuments = Documents.Where(document => !document.IsUploaded).ToList(); foreach (var document in pendingDocuments) { await _backendClient.UploadLibraryDocumentAsync(document).ConfigureAwait(true); } StatusMessage = $"已同步 {pendingDocuments.Count} 个文库文件"; RefreshCommandState(); } }