diff --git a/.idea/.idea.CORP-MAUI/.idea/deviceManager.xml b/.idea/.idea.CORP-MAUI/.idea/deviceManager.xml
new file mode 100644
index 0000000..91f9558
--- /dev/null
+++ b/.idea/.idea.CORP-MAUI/.idea/deviceManager.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CORP-MAUI/Pages/PostsPage.xaml b/CORP-MAUI/Pages/PostsPage.xaml
index ed977cf..79c2335 100644
--- a/CORP-MAUI/Pages/PostsPage.xaml
+++ b/CORP-MAUI/Pages/PostsPage.xaml
@@ -13,7 +13,7 @@
HorizontalOptions="Center"
VerticalOptions="Center"
Color="{StaticResource Primary}"/>
-
+
> tasks = response.Results.Select(async post =>
{
- PostViewModel vm = new PostViewModel(post);
+ PostViewModel vm = new(post);
if (!string.IsNullOrEmpty(post.DisplayImageUrl))
{
@@ -63,11 +63,8 @@ public partial class PostsPage
{
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 fileName = Path.GetFileName(uri.LocalPath);
+ fileName = Path.GetInvalidFileNameChars().Aggregate(fileName, (current, invalidChar) => current.Replace(invalidChar, '_'));
string cacheFileName = $"post_img_{post.Id}_{fileName}";
string cacheFilePath = Path.Combine(FileSystem.CacheDirectory, cacheFileName);
@@ -91,7 +88,7 @@ public partial class PostsPage
{
Trace.WriteLine($"[PostsPage] Загрузка изображения: {post.DisplayImageUrl}");
byte[]? bytes = await ServiceProvider.ApiService.GetImageBytesAsync(post.DisplayImageUrl);
- if (bytes != null && bytes.Length > 0)
+ if (bytes is { Length: > 0 })
{
await File.WriteAllBytesAsync(cacheFilePath, bytes);
Trace.WriteLine($"[PostsPage] Сохранено в кэш: {cacheFilePath}");
@@ -137,13 +134,11 @@ public partial class PostsPage
private async void OnPostSelected(object sender, SelectionChangedEventArgs e)
{
- if (e.CurrentSelection.FirstOrDefault() is PostViewModel selectedPost)
- {
- // Навигация на страницу деталей
- await Navigation.PushAsync(new PostDetailsPage(selectedPost));
+ if (e.CurrentSelection.FirstOrDefault() is not PostViewModel selectedPost) return;
+ // Навигация на страницу деталей
+ await Navigation.PushAsync(new PostDetailsPage(selectedPost));
- // Снимаем выделение
- PostsCollectionView.SelectedItem = null;
- }
+ // Снимаем выделение
+ PostsCollectionView.SelectedItem = null;
}
}
diff --git a/CORP-MAUI/Services/ApiService.cs b/CORP-MAUI/Services/ApiService.cs
index 1d1dcf9..1eeb0c9 100644
--- a/CORP-MAUI/Services/ApiService.cs
+++ b/CORP-MAUI/Services/ApiService.cs
@@ -259,7 +259,7 @@ public class ApiService : IDisposable
{
try
{
- LoginRequest loginData = new LoginRequest { Email = email, Password = password };
+ LoginRequest loginData = new() { Email = email, Password = password };
// Используем относительный путь, так как BaseAddress уже установлен
string path = _config.TokenObtainPath.TrimStart('/');
@@ -269,7 +269,7 @@ public class ApiService : IDisposable
Trace.WriteLine($"[ApiService] >>> Ожидаемый URL: {_httpClient.BaseAddress}{path}\n");
// 🔓 Создаем запрос БЕЗ Authorization header (это запрос для получения токена!)
- HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, path)
+ HttpRequestMessage request = new(HttpMethod.Post, path)
{
Content = JsonContent.Create(loginData)
};
@@ -530,7 +530,7 @@ public class ApiService : IDisposable
string relativePath = path.TrimStart('/');
// Добавляем query параметры
- if (queryParams != null && queryParams.Any())
+ if (queryParams != null && queryParams.Count != 0)
{
string query = string.Join("&", queryParams.Select(kvp =>
$"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}"));
diff --git a/CORP-MAUI/ViewModels/PostViewModel.cs b/CORP-MAUI/ViewModels/PostViewModel.cs
index 93daff1..aad9013 100644
--- a/CORP-MAUI/ViewModels/PostViewModel.cs
+++ b/CORP-MAUI/ViewModels/PostViewModel.cs
@@ -1,4 +1,5 @@
using System.ComponentModel;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using CORP_MAUI.Models;
@@ -60,7 +61,23 @@ public class PostViewModel : INotifyPropertyChanged
get
{
if (_imageSource != null) return _imageSource;
- if (!string.IsNullOrEmpty(_localImagePath)) return ImageSource.FromFile(_localImagePath);
+
+ if (!string.IsNullOrEmpty(_localImagePath) && File.Exists(_localImagePath))
+ {
+ // Используем FromStream для надежности, чтобы не блокировать файл
+ // и гарантировать чтение даже из системных папок
+ return ImageSource.FromStream(() =>
+ {
+ try
+ {
+ return new FileStream(_localImagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
+ }
+ catch
+ {
+ return Stream.Null;
+ }
+ });
+ }
return null;
}
}