using System.Collections.ObjectModel; using System.Diagnostics; using CORP_MAUI.Models; using CORP_MAUI.ViewModels; namespace CORP_MAUI.Pages; public partial class PostsPage { private readonly ObservableCollection _posts; private int _currentPage = 1; private bool _isLoading; public PostsPage() { InitializeComponent(); _posts = new ObservableCollection(); PostsCollectionView.ItemsSource = _posts; } // Добавляем метод OnAppearing, чтобы обновлять данные при показе страницы, если нужно protected override void OnAppearing() { base.OnAppearing(); if (_posts.Count == 0) { _ = LoadPostsAsync(); } } private async Task LoadPostsAsync(bool refresh = false) { if (_isLoading) return; _isLoading = true; if (refresh) { _currentPage = 1; } try { LoadingIndicator.IsVisible = true; LoadingIndicator.IsRunning = true; PaginatedResponse response = await ServiceProvider.ApiService.GetPostsPaginatedAsync(_currentPage); if (refresh) { _posts.Clear(); } if (response.Results != null) { IEnumerable> tasks = response.Results.Select(async post => { PostViewModel vm = new PostViewModel(post); if (!string.IsNullOrEmpty(post.DisplayImageUrl)) { try { Uri uri = new Uri(post.DisplayImageUrl); // Sanitize filename string fileName = Path.GetFileName(uri.LocalPath); foreach (char invalidChar in Path.GetInvalidFileNameChars()) { fileName = fileName.Replace(invalidChar, '_'); } string cacheFileName = $"post_img_{post.Id}_{fileName}"; string cacheFilePath = Path.Combine(FileSystem.CacheDirectory, cacheFileName); bool isCached = false; // 1. Проверяем кэш if (File.Exists(cacheFilePath)) { FileInfo fileInfo = new FileInfo(cacheFilePath); if (fileInfo.Length > 0) { Trace.WriteLine($"[PostsPage] Изображение из кэша: {cacheFilePath}"); vm.LocalImagePath = cacheFilePath; isCached = true; } } // 2. Если нет в кэше - загружаем if (!isCached) { Trace.WriteLine($"[PostsPage] Загрузка изображения: {post.DisplayImageUrl}"); byte[]? bytes = await ServiceProvider.ApiService.GetImageBytesAsync(post.DisplayImageUrl); if (bytes != null && bytes.Length > 0) { await File.WriteAllBytesAsync(cacheFilePath, bytes); Trace.WriteLine($"[PostsPage] Сохранено в кэш: {cacheFilePath}"); vm.LocalImagePath = cacheFilePath; } } } catch(Exception imgEx) { Trace.WriteLine($"[PostsPage] Ошибка обработки изображения для поста {post.Id}: {imgEx.Message}"); } } return vm; }); // Ждем загрузки всех изображений перед отображением списка PostViewModel[] viewModels = await Task.WhenAll(tasks); foreach (PostViewModel vm in viewModels) { _posts.Add(vm); } } } catch (Exception ex) { Trace.WriteLine($"Ошибка загрузки постов: {ex.Message}"); await DisplayAlert("Ошибка", "Не удалось загрузить новости", "OK"); } finally { _isLoading = false; LoadingIndicator.IsVisible = false; LoadingIndicator.IsRunning = false; PostsRefreshView.IsRefreshing = false; } } private async void OnRefreshing(object sender, EventArgs e) { await LoadPostsAsync(true); } private async void OnPostSelected(object sender, SelectionChangedEventArgs e) { if (e.CurrentSelection.FirstOrDefault() is PostViewModel selectedPost) { // Навигация на страницу деталей await Navigation.PushAsync(new PostDetailsPage(selectedPost)); // Снимаем выделение PostsCollectionView.SelectedItem = null; } } }