Replace explicit types with explicit types
This commit is contained in:
parent
674e470272
commit
e261cc77de
@ -1,4 +1,4 @@
|
||||
using CORP_MAUI.Pages;
|
||||
using CORP_MAUI.Pages;
|
||||
using CORP_MAUI.Models;
|
||||
using System.Diagnostics;
|
||||
|
||||
@ -29,7 +29,7 @@ public partial class App : Application
|
||||
|
||||
// Создаем окно с начальной страницей загрузки
|
||||
#if ANDROID || IOS || MACCATALYST || WINDOWS
|
||||
var loadingPage = new ContentPage
|
||||
ContentPage loadingPage = new ContentPage
|
||||
{
|
||||
Content = new VerticalStackLayout
|
||||
{
|
||||
@ -52,10 +52,10 @@ public partial class App : Application
|
||||
}
|
||||
};
|
||||
|
||||
var window = new Window(loadingPage);
|
||||
Window window = new Window(loadingPage);
|
||||
#else
|
||||
// Фолбэк для платформ вне целевых (не должен использоваться в текущих TFM)
|
||||
var window = new Window();
|
||||
Window window = new Window();
|
||||
#endif
|
||||
|
||||
// Асинхронно проверяем токен и определяем начальную страницу
|
||||
@ -114,7 +114,7 @@ public partial class App : Application
|
||||
try
|
||||
{
|
||||
Trace.WriteLine("[App] >>> Connecting to WebSocket...");
|
||||
var token = ServiceProvider.ApiService.GetAccessToken();
|
||||
string? token = ServiceProvider.ApiService.GetAccessToken();
|
||||
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
|
||||
@ -44,7 +44,7 @@ public partial class AppShell : Shell
|
||||
await Task.Delay(100);
|
||||
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||
{
|
||||
var mainPage = Application.Current?.Windows[0]?.Page;
|
||||
Page? mainPage = Application.Current?.Windows[0]?.Page;
|
||||
if (mainPage != null)
|
||||
{
|
||||
await mainPage.DisplayAlert("Ошибка AppShell",
|
||||
@ -72,7 +72,7 @@ public partial class AppShell : Shell
|
||||
if (ServiceProvider.ApiService.IsAuthenticated)
|
||||
{
|
||||
// Получаем токен для WebSocket
|
||||
var accessToken = await SecureStorage.GetAsync("api.jwt_access");
|
||||
string? accessToken = await SecureStorage.GetAsync("api.jwt_access");
|
||||
|
||||
Trace.WriteLine($"[AppShell] Access token exists: {!string.IsNullOrEmpty(accessToken)}");
|
||||
Trace.WriteLine($"[AppShell] WebSocket connected: {ServiceProvider.WebSocketService.IsConnected}");
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
using CORP_MAUI.Services;
|
||||
using CORP_MAUI.Pages;
|
||||
|
||||
@ -8,7 +8,7 @@ public static class MauiProgram
|
||||
{
|
||||
public static MauiApp CreateMauiApp()
|
||||
{
|
||||
var builder = MauiApp.CreateBuilder();
|
||||
MauiAppBuilder builder = MauiApp.CreateBuilder();
|
||||
builder
|
||||
.UseMauiApp<App>()
|
||||
.ConfigureFonts(fonts =>
|
||||
|
||||
@ -47,11 +47,8 @@ public class Comment
|
||||
get
|
||||
{
|
||||
// Если CreatedAt валидный (больше 2000 года, чтоб отсечь дефолт), берем его
|
||||
if (CreatedAt.Year > 2000) return CreatedAt;
|
||||
// Иначе пробуем поле Date
|
||||
if (Date.HasValue) return Date.Value;
|
||||
// Иначе текущее время
|
||||
return DateTime.Now;
|
||||
DateTime d = CreatedAt.Year > 2000 ? CreatedAt : (Date ?? DateTime.Now);
|
||||
return d.ToLocalTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ public class Post
|
||||
{
|
||||
get
|
||||
{
|
||||
var url = !string.IsNullOrEmpty(ImageUrl) ? ImageUrl : Image;
|
||||
string? url = !string.IsNullOrEmpty(ImageUrl) ? ImageUrl : Image;
|
||||
if (string.IsNullOrEmpty(url)) return null;
|
||||
|
||||
// Если ссылка уже абсолютная - возвращаем как есть
|
||||
@ -42,7 +42,7 @@ public class Post
|
||||
|
||||
// Если ссылка относительная - добавляем домен
|
||||
// Обрабатываем случай, когда url начинается со / или без
|
||||
var cleanUrl = url.TrimStart('/');
|
||||
string cleanUrl = url.TrimStart('/');
|
||||
return $"https://corp.robotail.pro/{cleanUrl}";
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,7 @@ public class Post
|
||||
public DateTime? Date { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public DateTime DisplayDate => CreatedAt.Year > 2000 ? CreatedAt : (Date ?? DateTime.Now);
|
||||
public DateTime DisplayDate => (CreatedAt.Year > 2000 ? CreatedAt : (Date ?? DateTime.Now)).ToLocalTime();
|
||||
|
||||
public User? Author { get; set; }
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ public partial class ChatPage : ContentPage
|
||||
InitializeComponent();
|
||||
|
||||
_recipient = recipient;
|
||||
_messages = new ObservableCollection<MessageViewModel>();
|
||||
_messages = [];
|
||||
|
||||
MessagesCollectionView.ItemsSource = _messages;
|
||||
|
||||
@ -34,7 +34,7 @@ public partial class ChatPage : ContentPage
|
||||
try
|
||||
{
|
||||
// Получаем текущего пользователя
|
||||
var user = await ServiceProvider.ApiService.GetCurrentUserAsync();
|
||||
User? user = await ServiceProvider.ApiService.GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
_currentUser = user;
|
||||
@ -63,14 +63,14 @@ public partial class ChatPage : ContentPage
|
||||
|
||||
private async void OnSendMessageClicked(object sender, EventArgs e)
|
||||
{
|
||||
var content = MessageEntry.Text?.Trim();
|
||||
string? content = MessageEntry.Text?.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var message = new Message
|
||||
Message message = new Message
|
||||
{
|
||||
SenderId = _currentUser.Id,
|
||||
SenderName = _currentUser.FullName ?? _currentUser.Username,
|
||||
@ -162,7 +162,7 @@ public partial class ChatPage : ContentPage
|
||||
{
|
||||
_messages.Clear();
|
||||
|
||||
foreach (var message in history.OrderBy(m => m.Timestamp))
|
||||
foreach (Message message in history.OrderBy(m => m.Timestamp))
|
||||
{
|
||||
_messages.Add(new MessageViewModel
|
||||
{
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using CORP_MAUI.Models;
|
||||
|
||||
namespace CORP_MAUI.Pages;
|
||||
|
||||
@ -14,8 +15,8 @@ public partial class LoginPage : ContentPage
|
||||
{
|
||||
Trace.WriteLine("=== LOGIN BUTTON CLICKED ===");
|
||||
|
||||
var username = UsernameEntry.Text?.Trim();
|
||||
var password = PasswordEntry.Text?.Trim();
|
||||
string? username = UsernameEntry.Text?.Trim();
|
||||
string? password = PasswordEntry.Text?.Trim();
|
||||
|
||||
Trace.WriteLine($"[LoginPage] >>> Кнопка входа нажата");
|
||||
Trace.WriteLine($"[LoginPage] Username: {username}");
|
||||
@ -36,7 +37,7 @@ public partial class LoginPage : ContentPage
|
||||
Trace.WriteLine($"[LoginPage] >>> Вызываем ApiService.LoginAsync...");
|
||||
|
||||
// Выполняем вход
|
||||
var result = await ServiceProvider.ApiService.LoginAsync(username, password);
|
||||
AuthResponse result = await ServiceProvider.ApiService.LoginAsync(username, password);
|
||||
|
||||
Trace.WriteLine($"[LoginPage] <<< Получен результат логина");
|
||||
Trace.WriteLine($"[LoginPage] Success: {result.Success}");
|
||||
@ -50,7 +51,7 @@ public partial class LoginPage : ContentPage
|
||||
try
|
||||
{
|
||||
// Получаем токен (из результата или напрямую из ApiService)
|
||||
var token = result.Token ?? ServiceProvider.ApiService.GetAccessToken();
|
||||
string? token = result.Token ?? ServiceProvider.ApiService.GetAccessToken();
|
||||
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
@ -99,7 +100,7 @@ public partial class LoginPage : ContentPage
|
||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
Trace.WriteLine($"[LoginPage] >>> Создание AppShell...");
|
||||
var app = Application.Current;
|
||||
Application? app = Application.Current;
|
||||
if (app != null && app.Windows.Count > 0)
|
||||
{
|
||||
app.Windows[0].Page = new AppShell();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using CORP_MAUI.Models;
|
||||
using CORP_MAUI.ViewModels;
|
||||
|
||||
namespace CORP_MAUI.Pages;
|
||||
@ -28,12 +29,12 @@ public partial class PostDetailsPage : ContentPage
|
||||
_viewModel.IsLoadingComments = true;
|
||||
try
|
||||
{
|
||||
var response = await ServiceProvider.ApiService.GetCommentsPaginatedAsync(postId: _viewModel.PostViewModel.Post.Id);
|
||||
PaginatedResponse<Comment> response = await ServiceProvider.ApiService.GetCommentsPaginatedAsync(postId: _viewModel.PostViewModel.Post.Id);
|
||||
|
||||
_viewModel.Comments.Clear();
|
||||
if (response.Results != null)
|
||||
{
|
||||
foreach (var comment in response.Results)
|
||||
foreach (Comment comment in response.Results)
|
||||
{
|
||||
_viewModel.Comments.Add(comment);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using CORP_MAUI.Models;
|
||||
using CORP_MAUI.ViewModels;
|
||||
|
||||
namespace CORP_MAUI.Pages;
|
||||
@ -43,7 +44,7 @@ public partial class PostsPage
|
||||
LoadingIndicator.IsVisible = true;
|
||||
LoadingIndicator.IsRunning = true;
|
||||
|
||||
var response = await ServiceProvider.ApiService.GetPostsPaginatedAsync(_currentPage);
|
||||
PaginatedResponse<Post> response = await ServiceProvider.ApiService.GetPostsPaginatedAsync(_currentPage);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
@ -52,85 +53,66 @@ public partial class PostsPage
|
||||
|
||||
if (response.Results != null)
|
||||
{
|
||||
foreach (var post in response.Results)
|
||||
IEnumerable<Task<PostViewModel>> tasks = response.Results.Select(async post =>
|
||||
{
|
||||
Trace.WriteLine($"[PostsPage] Post {post.Id}: '{post.Title}'");
|
||||
Trace.WriteLine($" CreatedAt: {post.CreatedAt}");
|
||||
Trace.WriteLine($" DisplayImageUrl: {post.DisplayImageUrl}");
|
||||
Trace.WriteLine($" Content length: {post.Content?.Length ?? 0}");
|
||||
PostViewModel vm = new PostViewModel(post);
|
||||
|
||||
var vm = new PostViewModel(post);
|
||||
_posts.Add(vm);
|
||||
|
||||
// Асинхронно загружаем изображение с токеном
|
||||
_ = Task.Run(async () =>
|
||||
if (!string.IsNullOrEmpty(post.DisplayImageUrl))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(post.DisplayImageUrl))
|
||||
try
|
||||
{
|
||||
try
|
||||
Uri uri = new Uri(post.DisplayImageUrl);
|
||||
// Sanitize filename
|
||||
string fileName = Path.GetFileName(uri.LocalPath);
|
||||
foreach (char invalidChar in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
// Используем имя файла из URL как ключ кэша
|
||||
var uri = new Uri(post.DisplayImageUrl);
|
||||
var fileName = Path.GetFileName(uri.LocalPath);
|
||||
// Добавляем префикс, чтобы избежать коллизий
|
||||
var cacheFileName = $"cache_{post.Id}_{fileName}";
|
||||
var cacheFilePath = Path.Combine(FileSystem.CacheDirectory, cacheFileName);
|
||||
|
||||
// Проверяем кэш
|
||||
if (File.Exists(cacheFilePath))
|
||||
{
|
||||
var fileInfo = new FileInfo(cacheFilePath);
|
||||
if (fileInfo.Length > 0)
|
||||
{
|
||||
Trace.WriteLine($"[PostsPage] >> Image found in cache: {cacheFilePath}");
|
||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
vm.LocalImagePath = cacheFilePath;
|
||||
});
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Удаляем пустой файл
|
||||
File.Delete(cacheFilePath);
|
||||
}
|
||||
}
|
||||
fileName = fileName.Replace(invalidChar, '_');
|
||||
}
|
||||
|
||||
// Загружаем, если нет в кэше
|
||||
var bytes = await ServiceProvider.ApiService.GetImageBytesAsync(post.DisplayImageUrl);
|
||||
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)
|
||||
{
|
||||
Trace.WriteLine($"[PostsPage] >> Image loaded ({bytes.Length} bytes), saving to {cacheFilePath}");
|
||||
|
||||
// Сразу показываем
|
||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
vm.AuthorizedImageSource = ImageSource.FromStream(() => new MemoryStream(bytes));
|
||||
});
|
||||
|
||||
await File.WriteAllBytesAsync(cacheFilePath, bytes);
|
||||
|
||||
// Обновляем путь (на всякий случай, для будущего)
|
||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
vm.LocalImagePath = cacheFilePath;
|
||||
});
|
||||
Trace.WriteLine($"[PostsPage] Сохранено в кэш: {cacheFilePath}");
|
||||
vm.LocalImagePath = cacheFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.WriteLine($"[PostsPage] >> Image failed to load for post {post.Id} (null/empty)");
|
||||
}
|
||||
}
|
||||
catch(Exception imgEx)
|
||||
{
|
||||
Trace.WriteLine($"[PostsPage] >> Exception loading image for post {post.Id}: {imgEx.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
catch(Exception imgEx)
|
||||
{
|
||||
Trace.WriteLine($"[PostsPage] >> No image URL for post {post.Id}");
|
||||
Trace.WriteLine($"[PostsPage] Ошибка обработки изображения для поста {post.Id}: {imgEx.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
return vm;
|
||||
});
|
||||
|
||||
// Ждем загрузки всех изображений перед отображением списка
|
||||
PostViewModel[] viewModels = await Task.WhenAll(tasks);
|
||||
|
||||
foreach (PostViewModel vm in viewModels)
|
||||
{
|
||||
_posts.Add(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ public partial class ProfilePage : ContentPage
|
||||
LoadingIndicator.IsRunning = true;
|
||||
|
||||
// Загружаем профиль
|
||||
var user = await ServiceProvider.ApiService.GetCurrentUserAsync();
|
||||
User? user = await ServiceProvider.ApiService.GetCurrentUserAsync();
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
@ -57,7 +57,7 @@ public partial class ProfilePage : ContentPage
|
||||
|
||||
private async void OnLogoutClicked(object sender, EventArgs e)
|
||||
{
|
||||
var result = await DisplayAlert("Выход", "Вы уверены, что хотите выйти?", "Да", "Нет");
|
||||
bool result = await DisplayAlert("Выход", "Вы уверены, что хотите выйти?", "Да", "Нет");
|
||||
|
||||
if (result)
|
||||
{
|
||||
|
||||
@ -45,7 +45,7 @@ public partial class UsersPage : ContentPage
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(100);
|
||||
var mainPage = Application.Current?.Windows[0]?.Page;
|
||||
Page? mainPage = Application.Current?.Windows[0]?.Page;
|
||||
if (mainPage != null)
|
||||
{
|
||||
await mainPage.DisplayAlert("Ошибка UsersPage",
|
||||
@ -71,7 +71,7 @@ public partial class UsersPage : ContentPage
|
||||
Trace.WriteLine($"[UsersPage] >>> Получено пользователей: {_allUsers.Count}");
|
||||
|
||||
_users.Clear();
|
||||
foreach (var user in _allUsers.OrderBy(u => u.FullName))
|
||||
foreach (User user in _allUsers.OrderBy(u => u.FullName))
|
||||
{
|
||||
_users.Add(user);
|
||||
}
|
||||
@ -113,13 +113,13 @@ public partial class UsersPage : ContentPage
|
||||
|
||||
private void OnSearchTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
var searchText = e.NewTextValue?.ToLower() ?? string.Empty;
|
||||
string searchText = e.NewTextValue?.ToLower() ?? string.Empty;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(searchText))
|
||||
{
|
||||
// Показываем всех пользователей
|
||||
_users.Clear();
|
||||
foreach (var user in _allUsers.OrderBy(u => u.FullName))
|
||||
foreach (User user in _allUsers.OrderBy(u => u.FullName))
|
||||
{
|
||||
_users.Add(user);
|
||||
}
|
||||
@ -127,7 +127,7 @@ public partial class UsersPage : ContentPage
|
||||
else
|
||||
{
|
||||
// Фильтруем пользователей
|
||||
var filtered = _allUsers.Where(u =>
|
||||
List<User> filtered = _allUsers.Where(u =>
|
||||
u.FullName.ToLower().Contains(searchText) ||
|
||||
u.Username.ToLower().Contains(searchText) ||
|
||||
u.DepartmentName.ToLower().Contains(searchText) ||
|
||||
@ -135,7 +135,7 @@ public partial class UsersPage : ContentPage
|
||||
).ToList();
|
||||
|
||||
_users.Clear();
|
||||
foreach (var user in filtered.OrderBy(u => u.FullName))
|
||||
foreach (User user in filtered.OrderBy(u => u.FullName))
|
||||
{
|
||||
_users.Add(user);
|
||||
}
|
||||
@ -147,14 +147,14 @@ public partial class UsersPage : ContentPage
|
||||
// Обновляем статус пользователя в списке
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
var user = _users.FirstOrDefault(u => u.Id == updatedUser.Id);
|
||||
User? user = _users.FirstOrDefault(u => u.Id == updatedUser.Id);
|
||||
if (user != null)
|
||||
{
|
||||
user.IsOnline = updatedUser.IsOnline;
|
||||
}
|
||||
|
||||
// Обновляем в основном списке
|
||||
var allUser = _allUsers?.FirstOrDefault(u => u.Id == updatedUser.Id);
|
||||
User? allUser = _allUsers?.FirstOrDefault(u => u.Id == updatedUser.Id);
|
||||
if (allUser != null)
|
||||
{
|
||||
allUser.IsOnline = updatedUser.IsOnline;
|
||||
|
||||
@ -10,7 +10,7 @@ class Program : MauiApplication
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var app = new Program();
|
||||
Program app = new Program();
|
||||
app.Run(args);
|
||||
}
|
||||
}
|
||||
@ -126,9 +126,9 @@ public class ApiService : IDisposable
|
||||
Trace.WriteLine($"║ URI: {request.RequestUri}");
|
||||
Trace.WriteLine($"║ BaseAddress: {_httpClient.BaseAddress}");
|
||||
Trace.WriteLine($"║ Headers:");
|
||||
foreach (var header in request.Headers)
|
||||
foreach (KeyValuePair<string, IEnumerable<string>> header in request.Headers)
|
||||
{
|
||||
var value = header.Key == "Authorization" ? "[HIDDEN]" : string.Join(", ", header.Value);
|
||||
string value = header.Key == "Authorization" ? "[HIDDEN]" : string.Join(", ", header.Value);
|
||||
Trace.WriteLine($"║ {header.Key}: {value}");
|
||||
}
|
||||
if (request.Content != null)
|
||||
@ -260,7 +260,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
var loginData = new { email, password };
|
||||
// Используем относительный путь, так как BaseAddress уже установлен
|
||||
var path = _config.TokenObtainPath.TrimStart('/');
|
||||
string path = _config.TokenObtainPath.TrimStart('/');
|
||||
|
||||
Trace.WriteLine($"\n[ApiService] >>> Начинаем логин для {email}");
|
||||
Trace.WriteLine($"[ApiService] >>> Путь токена: {_config.TokenObtainPath} → {path}");
|
||||
@ -268,7 +268,7 @@ public class ApiService : IDisposable
|
||||
Trace.WriteLine($"[ApiService] >>> Ожидаемый URL: {_httpClient.BaseAddress}{path}\n");
|
||||
|
||||
// 🔓 Создаем запрос БЕЗ Authorization header (это запрос для получения токена!)
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, path)
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, path)
|
||||
{
|
||||
Content = JsonContent.Create(loginData)
|
||||
};
|
||||
@ -278,13 +278,13 @@ public class ApiService : IDisposable
|
||||
|
||||
LogHttpDetails("LOGIN REQUEST", request, null, $"Email: {email}");
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(request);
|
||||
|
||||
LogHttpDetails("LOGIN RESPONSE", request, response);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var errorText = await response.Content.ReadAsStringAsync();
|
||||
string errorText = await response.Content.ReadAsStringAsync();
|
||||
Trace.WriteLine($"\n[ApiService] ❌ Ошибка логина:");
|
||||
Trace.WriteLine($" Status Code: {(int)response.StatusCode} {response.StatusCode}");
|
||||
Trace.WriteLine($" Request URL: {response.RequestMessage?.RequestUri}");
|
||||
@ -298,7 +298,7 @@ public class ApiService : IDisposable
|
||||
}
|
||||
|
||||
// Проверяем Content-Type
|
||||
var contentType = response.Content.Headers.ContentType?.MediaType ?? "";
|
||||
string contentType = response.Content.Headers.ContentType?.MediaType ?? "";
|
||||
if (!contentType.Contains("application/json"))
|
||||
{
|
||||
Trace.WriteLine($"[ApiService] ❌ Неверный Content-Type: {contentType}");
|
||||
@ -311,10 +311,10 @@ public class ApiService : IDisposable
|
||||
|
||||
try
|
||||
{
|
||||
var responseBody = await response.Content.ReadAsStringAsync();
|
||||
string responseBody = await response.Content.ReadAsStringAsync();
|
||||
Trace.WriteLine($"\n[ApiService] Response Body: {responseBody}\n");
|
||||
|
||||
var tokenData = JsonSerializer.Deserialize<TokenResponse>(responseBody, new JsonSerializerOptions
|
||||
TokenResponse? tokenData = JsonSerializer.Deserialize<TokenResponse>(responseBody, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
});
|
||||
@ -338,7 +338,7 @@ public class ApiService : IDisposable
|
||||
|
||||
// Получаем информацию о пользователе
|
||||
Trace.WriteLine($"[ApiService] >>> Получаем информацию о пользователе...\n");
|
||||
var user = await GetCurrentUserAsync();
|
||||
User? user = await GetCurrentUserAsync();
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
@ -409,7 +409,7 @@ public class ApiService : IDisposable
|
||||
Trace.WriteLine("╠════════════════════════════════════════════════════════════════════════════════════");
|
||||
|
||||
// Используем относительный путь, так как BaseAddress уже установлен
|
||||
var path = _config.TokenRefreshPath.TrimStart('/');
|
||||
string path = _config.TokenRefreshPath.TrimStart('/');
|
||||
var refreshData = new { refresh = _refreshToken };
|
||||
|
||||
Trace.WriteLine($"║ Request Path: {path}");
|
||||
@ -418,21 +418,21 @@ public class ApiService : IDisposable
|
||||
Trace.WriteLine("╚════════════════════════════════════════════════════════════════════════════════════");
|
||||
|
||||
// Создаем запрос БЕЗ авторизации (для refresh используется только refresh токен в теле)
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, path)
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, path)
|
||||
{
|
||||
Content = JsonContent.Create(refreshData)
|
||||
};
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(request);
|
||||
|
||||
Trace.WriteLine($"\n[ApiService] Refresh response: {(int)response.StatusCode} {response.StatusCode}");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var responseText = await response.Content.ReadAsStringAsync();
|
||||
string responseText = await response.Content.ReadAsStringAsync();
|
||||
Trace.WriteLine($"[ApiService] Response body: {responseText}");
|
||||
|
||||
var tokenData = JsonSerializer.Deserialize<TokenResponse>(responseText, new JsonSerializerOptions
|
||||
TokenResponse? tokenData = JsonSerializer.Deserialize<TokenResponse>(responseText, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
});
|
||||
@ -480,7 +480,7 @@ public class ApiService : IDisposable
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorText = await response.Content.ReadAsStringAsync();
|
||||
string errorText = await response.Content.ReadAsStringAsync();
|
||||
Trace.WriteLine($"[ApiService] ❌ Refresh failed: {response.StatusCode}");
|
||||
Trace.WriteLine($" Error: {errorText}");
|
||||
}
|
||||
@ -526,17 +526,17 @@ public class ApiService : IDisposable
|
||||
}
|
||||
|
||||
// Используем относительный путь, так как BaseAddress установлен
|
||||
var relativePath = path.TrimStart('/');
|
||||
string relativePath = path.TrimStart('/');
|
||||
|
||||
// Добавляем query параметры
|
||||
if (queryParams != null && queryParams.Any())
|
||||
{
|
||||
var query = string.Join("&", queryParams.Select(kvp =>
|
||||
string query = string.Join("&", queryParams.Select(kvp =>
|
||||
$"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}"));
|
||||
relativePath = $"{relativePath}?{query}";
|
||||
}
|
||||
|
||||
var request = new HttpRequestMessage(method, relativePath);
|
||||
HttpRequestMessage request = new HttpRequestMessage(method, relativePath);
|
||||
|
||||
// 🔑 АВТОМАТИЧЕСКИ добавляем Authorization header если есть токен
|
||||
if (requiresAuth && !string.IsNullOrEmpty(_accessToken))
|
||||
@ -548,7 +548,7 @@ public class ApiService : IDisposable
|
||||
// Добавляем дополнительные заголовки
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
foreach (KeyValuePair<string, string> header in headers)
|
||||
{
|
||||
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
|
||||
}
|
||||
@ -570,7 +570,7 @@ public class ApiService : IDisposable
|
||||
Trace.WriteLine($" Has Body: Yes");
|
||||
}
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(request);
|
||||
|
||||
Trace.WriteLine($"[ApiService] <<< Response: {(int)response.StatusCode} {response.StatusCode}");
|
||||
Trace.WriteLine($" Content-Type: {response.Content.Headers.ContentType?.MediaType ?? "N/A"}\n");
|
||||
@ -600,7 +600,7 @@ public class ApiService : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync();
|
||||
string responseText = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -713,12 +713,12 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var queryParams = new Dictionary<string, string>();
|
||||
Dictionary<string, string> queryParams = new Dictionary<string, string>();
|
||||
if (page.HasValue) queryParams["page"] = page.Value.ToString();
|
||||
if (pageSize.HasValue) queryParams["page_size"] = pageSize.Value.ToString();
|
||||
if (!string.IsNullOrEmpty(search)) queryParams["search"] = search;
|
||||
|
||||
var response = await GetAsync<PaginatedResponse<User>>("api/v1/employees/", queryParams);
|
||||
ApiResponse<PaginatedResponse<User>> response = await GetAsync<PaginatedResponse<User>>("api/v1/employees/", queryParams);
|
||||
return response.Ok && response.Data != null ? response.Data : new PaginatedResponse<User>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -735,7 +735,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var allEmployees = new List<User>();
|
||||
List<User> allEmployees = new();
|
||||
int currentPage = 1;
|
||||
PaginatedResponse<User>? response;
|
||||
|
||||
@ -765,7 +765,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await GetAsync<User>("api/v1/employees/me/");
|
||||
ApiResponse<User> response = await GetAsync<User>("api/v1/employees/me/");
|
||||
return response.Ok ? response.Data : null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -782,7 +782,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await GetAsync<User>($"api/v1/employees/{id}/");
|
||||
ApiResponse<User> response = await GetAsync<User>($"api/v1/employees/{id}/");
|
||||
return response.Ok ? response.Data : null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -803,11 +803,11 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var queryParams = new Dictionary<string, string>();
|
||||
Dictionary<string, string> queryParams = new Dictionary<string, string>();
|
||||
if (page.HasValue) queryParams["page"] = page.Value.ToString();
|
||||
if (pageSize.HasValue) queryParams["page_size"] = pageSize.Value.ToString();
|
||||
|
||||
var response = await GetAsync<PaginatedResponse<Department>>("api/v1/departments/", queryParams);
|
||||
ApiResponse<PaginatedResponse<Department>> response = await GetAsync<PaginatedResponse<Department>>("api/v1/departments/", queryParams);
|
||||
return response.Ok && response.Data != null ? response.Data : new PaginatedResponse<Department>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -824,7 +824,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var allDepartments = new List<Department>();
|
||||
List<Department> allDepartments = new List<Department>();
|
||||
int currentPage = 1;
|
||||
PaginatedResponse<Department>? response;
|
||||
|
||||
@ -858,7 +858,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await GetAsync<List<Position>>("api/v1/positions/");
|
||||
ApiResponse<List<Position>> response = await GetAsync<List<Position>>("api/v1/positions/");
|
||||
return response.Ok && response.Data != null ? response.Data : new List<Position>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -879,7 +879,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await GetAsync<List<Skill>>("api/v1/skills/");
|
||||
ApiResponse<List<Skill>> response = await GetAsync<List<Skill>>("api/v1/skills/");
|
||||
return response.Ok && response.Data != null ? response.Data : new List<Skill>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -900,7 +900,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await GetAsync<List<CalendarEvent>>("api/v1/calendar/events/");
|
||||
ApiResponse<List<CalendarEvent>> response = await GetAsync<List<CalendarEvent>>("api/v1/calendar/events/");
|
||||
return response.Ok && response.Data != null ? response.Data : new List<CalendarEvent>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -921,11 +921,11 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var queryParams = new Dictionary<string, string>();
|
||||
Dictionary<string, string> queryParams = new Dictionary<string, string>();
|
||||
if (page.HasValue) queryParams["page"] = page.Value.ToString();
|
||||
if (pageSize.HasValue) queryParams["page_size"] = pageSize.Value.ToString();
|
||||
|
||||
var response = await GetAsync<PaginatedResponse<Document>>("api/v1/documents/", queryParams);
|
||||
ApiResponse<PaginatedResponse<Document>> response = await GetAsync<PaginatedResponse<Document>>("api/v1/documents/", queryParams);
|
||||
return response.Ok && response.Data != null ? response.Data : new PaginatedResponse<Document>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -946,11 +946,11 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var queryParams = new Dictionary<string, string>();
|
||||
Dictionary<string, string> queryParams = new Dictionary<string, string>();
|
||||
if (page.HasValue) queryParams["page"] = page.Value.ToString();
|
||||
if (pageSize.HasValue) queryParams["page_size"] = pageSize.Value.ToString();
|
||||
|
||||
var response = await GetAsync<PaginatedResponse<Request>>("api/v1/requests/", queryParams);
|
||||
ApiResponse<PaginatedResponse<Request>> response = await GetAsync<PaginatedResponse<Request>>("api/v1/requests/", queryParams);
|
||||
return response.Ok && response.Data != null ? response.Data : new PaginatedResponse<Request>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -971,7 +971,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await GetAsync<List<EmployeeAction>>("api/v1/employee-actions/");
|
||||
ApiResponse<List<EmployeeAction>> response = await GetAsync<List<EmployeeAction>>("api/v1/employee-actions/");
|
||||
return response.Ok && response.Data != null ? response.Data : new List<EmployeeAction>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -992,11 +992,11 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var queryParams = new Dictionary<string, string>();
|
||||
Dictionary<string, string> queryParams = new Dictionary<string, string>();
|
||||
if (page.HasValue) queryParams["page"] = page.Value.ToString();
|
||||
if (pageSize.HasValue) queryParams["page_size"] = pageSize.Value.ToString();
|
||||
|
||||
var response = await GetAsync<PaginatedResponse<Post>>("api/v1/posts/", queryParams);
|
||||
ApiResponse<PaginatedResponse<Post>> response = await GetAsync<PaginatedResponse<Post>>("api/v1/posts/", queryParams);
|
||||
return response.Ok && response.Data != null ? response.Data : new PaginatedResponse<Post>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1017,12 +1017,12 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var queryParams = new Dictionary<string, string>();
|
||||
Dictionary<string, string> queryParams = new Dictionary<string, string>();
|
||||
if (page.HasValue) queryParams["page"] = page.Value.ToString();
|
||||
if (pageSize.HasValue) queryParams["page_size"] = pageSize.Value.ToString();
|
||||
if (postId.HasValue) queryParams["post"] = postId.Value.ToString();
|
||||
|
||||
var response = await GetAsync<PaginatedResponse<Comment>>("api/v1/comments/", queryParams);
|
||||
ApiResponse<PaginatedResponse<Comment>> response = await GetAsync<PaginatedResponse<Comment>>("api/v1/comments/", queryParams);
|
||||
return response.Ok && response.Data != null ? response.Data : new PaginatedResponse<Comment>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1043,11 +1043,11 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var queryParams = new Dictionary<string, string>();
|
||||
Dictionary<string, string> queryParams = new Dictionary<string, string>();
|
||||
if (page.HasValue) queryParams["page"] = page.Value.ToString();
|
||||
if (pageSize.HasValue) queryParams["page_size"] = pageSize.Value.ToString();
|
||||
|
||||
var response = await GetAsync<PaginatedResponse<DepartmentRole>>("api/v1/department-roles/", queryParams);
|
||||
ApiResponse<PaginatedResponse<DepartmentRole>> response = await GetAsync<PaginatedResponse<DepartmentRole>>("api/v1/department-roles/", queryParams);
|
||||
return response.Ok && response.Data != null ? response.Data : new PaginatedResponse<DepartmentRole>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1078,7 +1078,7 @@ public class ApiService : IDisposable
|
||||
? $"api/v1/messages/?user_id={userId.Value}"
|
||||
: "api/v1/messages/";
|
||||
|
||||
var response = await GetAsync<List<Message>>(path);
|
||||
ApiResponse<List<Message>> response = await GetAsync<List<Message>>(path);
|
||||
return response.Ok && response.Data != null ? response.Data : new List<Message>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1095,7 +1095,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await PostAsync<Message>("api/v1/messages/", message);
|
||||
ApiResponse<Message> response = await PostAsync<Message>("api/v1/messages/", message);
|
||||
return response.Ok;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1112,8 +1112,8 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var queryParams = new Dictionary<string, string> { { "q", query } };
|
||||
var response = await GetAsync<List<User>>("api/v1/users/search/", queryParams);
|
||||
Dictionary<string, string> queryParams = new() { { "q", query } };
|
||||
ApiResponse<List<User>> response = await GetAsync<List<User>>("api/v1/users/search/", queryParams);
|
||||
return response.Ok && response.Data != null ? response.Data : new List<User>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1130,7 +1130,7 @@ public class ApiService : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await PutAsync<object>("api/v1/users/status/", new { isOnline });
|
||||
ApiResponse<object> response = await PutAsync<object>("api/v1/users/status/", new { isOnline });
|
||||
return response.Ok;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1158,23 +1158,23 @@ public class ApiService : IDisposable
|
||||
await EnsureTokensLoadedAsync();
|
||||
|
||||
// Добавляем токен, если есть
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
if (!string.IsNullOrEmpty(_accessToken))
|
||||
{
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
|
||||
}
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(request);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var mediaType = response.Content.Headers.ContentType?.MediaType;
|
||||
string? mediaType = response.Content.Headers.ContentType?.MediaType;
|
||||
if (mediaType != null && !mediaType.StartsWith("image/"))
|
||||
{
|
||||
Trace.WriteLine($"[ApiService] ⚠️ URL {url} вернул не изображение, а {mediaType}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var bytes = await response.Content.ReadAsByteArrayAsync();
|
||||
byte[] bytes = await response.Content.ReadAsByteArrayAsync();
|
||||
Trace.WriteLine($"[ApiService] ✅ Загружено изображение {url} ({bytes.Length} bytes)");
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ public class WebSocketService
|
||||
// Пробуем подключиться к разным URL по очереди
|
||||
Exception? lastException = null;
|
||||
|
||||
foreach (var url in WebSocketUrls)
|
||||
foreach (string url in WebSocketUrls)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -71,7 +71,7 @@ public class WebSocketService
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var uri = new Uri(url);
|
||||
Uri uri = new Uri(url);
|
||||
Trace.WriteLine($"[WebSocket] Connecting to: {uri}");
|
||||
await _webSocket.ConnectAsync(uri, _cancellationTokenSource.Token);
|
||||
|
||||
@ -167,14 +167,14 @@ public class WebSocketService
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(new
|
||||
string json = JsonConvert.SerializeObject(new
|
||||
{
|
||||
type = "message",
|
||||
data = message
|
||||
});
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
var buffer = new ArraySegment<byte>(bytes);
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(json);
|
||||
ArraySegment<byte> buffer = new ArraySegment<byte>(bytes);
|
||||
|
||||
await _webSocket.SendAsync(buffer, WebSocketMessageType.Text, true, _cancellationTokenSource.Token);
|
||||
}
|
||||
@ -194,14 +194,14 @@ public class WebSocketService
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(new
|
||||
string json = JsonConvert.SerializeObject(new
|
||||
{
|
||||
type = "typing",
|
||||
data = new { recipientId, isTyping }
|
||||
});
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
var buffer = new ArraySegment<byte>(bytes);
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(json);
|
||||
ArraySegment<byte> buffer = new ArraySegment<byte>(bytes);
|
||||
|
||||
await _webSocket.SendAsync(buffer, WebSocketMessageType.Text, true, _cancellationTokenSource.Token);
|
||||
}
|
||||
@ -221,14 +221,14 @@ public class WebSocketService
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(new
|
||||
string json = JsonConvert.SerializeObject(new
|
||||
{
|
||||
type = "get_history",
|
||||
data = new { userId }
|
||||
});
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
var buffer = new ArraySegment<byte>(bytes);
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(json);
|
||||
ArraySegment<byte> buffer = new ArraySegment<byte>(bytes);
|
||||
|
||||
await _webSocket.SendAsync(buffer, WebSocketMessageType.Text, true, _cancellationTokenSource.Token);
|
||||
Trace.WriteLine($"[WebSocket] Запрошена история сообщений с пользователем {userId}");
|
||||
@ -241,13 +241,13 @@ public class WebSocketService
|
||||
|
||||
private async Task ReceiveMessagesAsync()
|
||||
{
|
||||
var buffer = new byte[8192];
|
||||
byte[] buffer = new byte[8192];
|
||||
|
||||
try
|
||||
{
|
||||
while (_webSocket?.State == WebSocketState.Open && _cancellationTokenSource is { Token.IsCancellationRequested: false })
|
||||
{
|
||||
var result = await _webSocket.ReceiveAsync(
|
||||
WebSocketReceiveResult result = await _webSocket.ReceiveAsync(
|
||||
new ArraySegment<byte>(buffer),
|
||||
_cancellationTokenSource.Token);
|
||||
|
||||
@ -263,7 +263,7 @@ public class WebSocketService
|
||||
break;
|
||||
}
|
||||
|
||||
var json = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||
string json = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||
await ProcessMessageAsync(json);
|
||||
}
|
||||
}
|
||||
@ -283,7 +283,7 @@ public class WebSocketService
|
||||
{
|
||||
try
|
||||
{
|
||||
var wrapper = JsonConvert.DeserializeObject<WebSocketMessage>(json);
|
||||
WebSocketMessage? wrapper = JsonConvert.DeserializeObject<WebSocketMessage>(json);
|
||||
|
||||
await MainThread.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
@ -295,12 +295,12 @@ public class WebSocketService
|
||||
break;
|
||||
|
||||
case "message_history":
|
||||
var history = JsonConvert.DeserializeObject<List<Message>>(wrapper.Data.ToString() ?? string.Empty);
|
||||
List<Message>? history = JsonConvert.DeserializeObject<List<Message>>(wrapper.Data.ToString() ?? string.Empty);
|
||||
if (history != null) MessageHistoryReceived?.Invoke(this, history);
|
||||
break;
|
||||
|
||||
case "user_status":
|
||||
var user = JsonConvert.DeserializeObject<User>(wrapper.Data.ToString() ?? string.Empty);
|
||||
User? user = JsonConvert.DeserializeObject<User>(wrapper.Data.ToString() ?? string.Empty);
|
||||
if (user != null) UserStatusChanged?.Invoke(this, user);
|
||||
break;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user