using System.Collections.ObjectModel; using System.Diagnostics; using CORP_MAUI.Models; namespace CORP_MAUI.Pages; public partial class DocumentsPage : ContentPage { private readonly ObservableCollection _documents; private List _allDocuments = new(); private string _currentFilter = "all"; private string _searchText = string.Empty; public DocumentsPage() { try { Trace.WriteLine("=== DOCUMENTS PAGE CONSTRUCTOR START ==="); Trace.WriteLine("[DocumentsPage] >>> Вызов InitializeComponent"); InitializeComponent(); Trace.WriteLine("[DocumentsPage] >>> InitializeComponent завершен"); _documents = new ObservableCollection(); DocumentsCollectionView.ItemsSource = _documents; Trace.WriteLine("[DocumentsPage] >>> Запуск LoadDocumentsAsync"); // Загружаем документы _ = LoadDocumentsAsync(); Trace.WriteLine("=== DOCUMENTS PAGE CONSTRUCTOR END ==="); } catch (Exception ex) { Trace.WriteLine("=== DOCUMENTS PAGE CONSTRUCTOR ERROR ==="); Trace.WriteLine($"[DocumentsPage] ❌ Тип ошибки: {ex.GetType().FullName}"); Trace.WriteLine($"[DocumentsPage] ❌ Сообщение: {ex.Message}"); Trace.WriteLine($"[DocumentsPage] ❌ StackTrace: {ex.StackTrace}"); // Показываем ошибку напрямую Task.Run(async () => { await Task.Delay(100); if (Application.Current?.Windows.Count > 0) { Page? mainPage = Application.Current.Windows[0].Page; if (mainPage != null) { await mainPage.DisplayAlert("Ошибка DocumentsPage", $"Ошибка инициализации:\n{ex.Message}\n\nStackTrace:\n{ex.StackTrace}", "OK"); } } }); throw; } } private async Task LoadDocumentsAsync() { try { Trace.WriteLine("[DocumentsPage] >>> LoadDocumentsAsync START"); LoadingIndicator.IsVisible = true; LoadingIndicator.IsRunning = true; Trace.WriteLine("[DocumentsPage] >>> Вызов GetAllDocumentsAsync"); _allDocuments = await ServiceProvider.ApiService.GetAllDocumentsAsync(); Trace.WriteLine($"[DocumentsPage] >>> Получено документов: {_allDocuments.Count}"); ApplyFilters(); Trace.WriteLine($"[DocumentsPage] ✅ Документы загружены успешно"); } catch (Exception ex) { Trace.WriteLine($"[DocumentsPage] ❌ Ошибка загрузки: {ex.GetType().Name}"); Trace.WriteLine($"[DocumentsPage] Message: {ex.Message}"); Trace.WriteLine($"[DocumentsPage] StackTrace: {ex.StackTrace}"); await DisplayAlert("Ошибка", $"Не удалось загрузить список документов:\n{ex.Message}", "OK"); } finally { LoadingIndicator.IsVisible = false; LoadingIndicator.IsRunning = false; RefreshView.IsRefreshing = false; } } private void ApplyFilters() { IEnumerable filtered = _allDocuments; // Фильтр по статусу ознакомления filtered = _currentFilter switch { "acknowledged" => filtered.Where(d => d.IsAcknowledged), "not_acknowledged" => filtered.Where(d => !d.IsAcknowledged), _ => filtered }; // Фильтр по поиску if (!string.IsNullOrWhiteSpace(_searchText)) { string search = _searchText.ToLower(); filtered = filtered.Where(d => d.Title.ToLower().Contains(search) || d.Description.ToLower().Contains(search) || d.UploaderName.ToLower().Contains(search)); } // Сортировка по дате загрузки (новые сверху) filtered = filtered.OrderByDescending(d => d.UploadedAt); _documents.Clear(); foreach (var document in filtered) { _documents.Add(document); } Trace.WriteLine($"[DocumentsPage] >>> Отображено документов: {_documents.Count}"); } private async void OnRefreshing(object sender, EventArgs e) { await LoadDocumentsAsync(); } private void OnSearchTextChanged(object sender, TextChangedEventArgs e) { _searchText = e.NewTextValue ?? string.Empty; ApplyFilters(); } private async void OnDocumentSelected(object sender, SelectionChangedEventArgs e) { if (e.CurrentSelection.FirstOrDefault() is Document selectedDocument) { // Сбрасываем выделение DocumentsCollectionView.SelectedItem = null; Trace.WriteLine($"[DocumentsPage] >>> Выбран документ: {selectedDocument.Title}"); // Показываем диалог с выбором действия string action = await DisplayActionSheet( selectedDocument.Title, "Отмена", null, "📥 Открыть документ", "ℹ️ Информация о документе"); if (action == "📥 Открыть документ") { await OpenDocumentAsync(selectedDocument); } else if (action == "ℹ️ Информация о документе") { await ShowDocumentInfoAsync(selectedDocument); } } } private async Task OpenDocumentAsync(Document document) { try { if (string.IsNullOrEmpty(document.FileUrl)) { await DisplayAlert("Ошибка", "URL документа не найден", "OK"); return; } Trace.WriteLine($"[DocumentsPage] >>> Открытие документа: {document.FileUrl}"); // Открываем документ в браузере await Launcher.OpenAsync(new Uri(document.FileUrl)); } catch (Exception ex) { Trace.WriteLine($"[DocumentsPage] ❌ Ошибка открытия документа: {ex.Message}"); await DisplayAlert("Ошибка", $"Не удалось открыть документ:\n{ex.Message}", "OK"); } } private async Task ShowDocumentInfoAsync(Document document) { string info = $"📄 {document.Title}\n\n"; if (!string.IsNullOrEmpty(document.Description)) { info += $"📝 Описание:\n{document.Description}\n\n"; } info += $"👤 Загрузил: {document.UploaderName}\n"; info += $"📅 Дата загрузки: {document.DisplayUploadedAt}\n"; info += $"📁 Тип файла: {document.FileExtension.ToUpper()}\n"; info += $"📨 Для всех: {(document.SentToAll ? "Да" : "Нет")}\n"; info += $"{document.AcknowledgedIcon} Статус: {document.AcknowledgedText}"; await DisplayAlert("Информация о документе", info, "OK"); } private async void OnBackClicked(object sender, EventArgs e) { await Shell.Current.GoToAsync(".."); } #region Фильтры private void OnFilterAllTapped(object sender, TappedEventArgs e) { SetActiveFilter("all"); ApplyFilters(); } private void OnFilterAcknowledgedTapped(object sender, TappedEventArgs e) { SetActiveFilter("acknowledged"); ApplyFilters(); } private void OnFilterNotAcknowledgedTapped(object sender, TappedEventArgs e) { SetActiveFilter("not_acknowledged"); ApplyFilters(); } private void SetActiveFilter(string filter) { _currentFilter = filter; // Получаем стили из Application.Current.Resources Style? chipButton = Application.Current?.Resources["ChipButton"] as Style; Style? chipButtonActive = Application.Current?.Resources["ChipButtonActive"] as Style; Color? grayColor = Application.Current?.Resources["Gray700"] as Color ?? Colors.Gray; // Сбрасываем все фильтры на неактивные if (chipButton != null) { FilterAll.Style = chipButton; FilterAcknowledged.Style = chipButton; FilterNotAcknowledged.Style = chipButton; } // Обновляем цвет текста у неактивных if (FilterAll.Content is Label allLabel) allLabel.TextColor = grayColor; if (FilterAcknowledged.Content is Label acknowledgedLabel) acknowledgedLabel.TextColor = grayColor; if (FilterNotAcknowledged.Content is Label notAcknowledgedLabel) notAcknowledgedLabel.TextColor = grayColor; // Активируем выбранный фильтр Border activeFilter = filter switch { "acknowledged" => FilterAcknowledged, "not_acknowledged" => FilterNotAcknowledged, _ => FilterAll }; if (chipButtonActive != null) activeFilter.Style = chipButtonActive; if (activeFilter.Content is Label activeLabel) activeLabel.TextColor = Colors.White; } #endregion }