corp-app/CORP-MAUI/Pages/ChatPage.xaml.cs

232 lines
8.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.ObjectModel;
using CORP_MAUI.Models;
using CORP_MAUI.Services;
namespace CORP_MAUI.Pages;
public partial class ChatPage : ContentPage
{
private readonly ObservableCollection<MessageViewModel> _messages;
private User _currentUser = new();
private User _recipient;
private System.Timers.Timer _typingTimer = new();
public ChatPage(User recipient)
{
InitializeComponent();
_recipient = recipient;
_messages = [];
MessagesCollectionView.ItemsSource = _messages;
// Устанавливаем аватар получателя
RecipientAvatar.Source = _recipient.DisplayAvatarSource;
// Подписываемся на события WebSocket
ServiceProvider.WebSocketService.MessageReceived += OnMessageReceived;
ServiceProvider.WebSocketService.MessageHistoryReceived += OnMessageHistoryReceived;
ServiceProvider.WebSocketService.ConnectionStatusChanged += OnConnectionStatusChanged;
// Инициализация
_ = InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
// Загружаем аватар получателя если еще не загружен
if (!_recipient.IsAvatarLoaded)
{
await ServiceProvider.ApiService.LoadUserAvatarAsync(_recipient);
RecipientAvatar.Source = _recipient.DisplayAvatarSource;
}
// Получаем текущего пользователя
User? user = await ServiceProvider.ApiService.GetCurrentUserAsync();
if (user != null)
{
_currentUser = user;
}
// Отображаем информацию о получателе
RecipientName.Text = _recipient.FullName;
RecipientStatus.Text = _recipient.IsOnline ? "В сети" : "Не в сети";
// Запрашиваем историю сообщений через WebSocket
if (ServiceProvider.WebSocketService.IsConnected)
{
await ServiceProvider.WebSocketService.RequestMessageHistoryAsync(_recipient.Id);
}
else
{
await DisplayAlert("Предупреждение", "WebSocket не подключен. История сообщений недоступна.", "OK");
}
}
catch (Exception ex)
{
await DisplayAlert("Ошибка", $"Не удалось загрузить данные: {ex.Message}", "OK");
}
}
private async void OnSendMessageClicked(object sender, EventArgs e)
{
string? content = MessageEntry.Text?.Trim();
if (string.IsNullOrEmpty(content))
return;
try
{
Message message = new Message
{
SenderId = _currentUser.Id,
SenderName = _currentUser.FullName ?? _currentUser.Username,
ReceiverId = _recipient.Id,
ReceiverName = _recipient.FullName ?? _recipient.Username,
Content = content,
Timestamp = DateTime.Now,
Type = MessageType.Personal
};
// Отправляем только через WebSocket
if (!ServiceProvider.WebSocketService.IsConnected)
{
await DisplayAlert("Ошибка", "WebSocket не подключен. Невозможно отправить сообщение.", "OK");
return;
}
await ServiceProvider.WebSocketService.SendMessageAsync(message);
// Добавляем сообщение в список
_messages.Add(new MessageViewModel
{
SenderId = message.SenderId,
SenderName = message.SenderName,
Content = message.Content,
Timestamp = message.Timestamp,
IsMyMessage = true
});
// Очищаем поле ввода
MessageEntry.Text = string.Empty;
// Прокручиваем к последнему сообщению
MessagesCollectionView.ScrollTo(_messages.Last(), position: ScrollToPosition.End, animate: true);
}
catch (Exception ex)
{
await DisplayAlert("Ошибка", $"Не удалось отправить сообщение: {ex.Message}", "OK");
}
}
private void OnMessageTextChanged(object sender, TextChangedEventArgs e)
{
// Отправляем индикатор набора текста
if (!string.IsNullOrEmpty(e.NewTextValue) && ServiceProvider.WebSocketService.IsConnected)
{
_ = ServiceProvider.WebSocketService.SendTypingIndicatorAsync(_recipient.Id, true);
// Отменяем предыдущий таймер
_typingTimer?.Stop();
_typingTimer?.Dispose();
// Создаем новый таймер для отправки статуса "не печатает"
_typingTimer = new System.Timers.Timer(2000);
_typingTimer.Elapsed += async (s, args) =>
{
await ServiceProvider.WebSocketService.SendTypingIndicatorAsync(_recipient.Id, false);
_typingTimer?.Dispose();
};
_typingTimer.Start();
}
}
private void OnMessageReceived(object? sender, Message message)
{
// Проверяем, что сообщение от нашего собеседника
if (message.SenderId == _recipient.Id)
{
MainThread.BeginInvokeOnMainThread(() =>
{
_messages.Add(new MessageViewModel
{
Id = message.Id,
SenderId = message.SenderId,
SenderName = message.SenderName,
Content = message.Content,
Timestamp = message.Timestamp,
IsMyMessage = false
});
MessagesCollectionView.ScrollTo(_messages.Last(), position: ScrollToPosition.End, animate: true);
});
}
}
private void OnMessageHistoryReceived(object? sender, List<Message> history)
{
MainThread.BeginInvokeOnMainThread(() =>
{
_messages.Clear();
foreach (Message message in history.OrderBy(m => m.Timestamp))
{
_messages.Add(new MessageViewModel
{
Id = message.Id,
SenderId = message.SenderId,
SenderName = message.SenderName,
Content = message.Content,
Timestamp = message.Timestamp,
IsMyMessage = message.SenderId == _currentUser?.Id
});
}
// Прокручиваем к последнему сообщению
if (_messages.Any())
{
MessagesCollectionView.ScrollTo(_messages.Last(), position: ScrollToPosition.End, animate: false);
}
});
}
private void OnConnectionStatusChanged(object? sender, bool isConnected)
{
MainThread.BeginInvokeOnMainThread(() =>
{
ConnectionIndicator.IsVisible = !isConnected;
});
}
private async void OnBackButtonClicked(object sender, EventArgs e)
{
// Возвращаемся к списку сотрудников (предыдущая страница)
await Navigation.PopAsync();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
// Отписываемся от событий
ServiceProvider.WebSocketService.MessageReceived -= OnMessageReceived;
ServiceProvider.WebSocketService.MessageHistoryReceived -= OnMessageHistoryReceived;
ServiceProvider.WebSocketService.ConnectionStatusChanged -= OnConnectionStatusChanged;
_typingTimer?.Dispose();
}
}
public class MessageViewModel
{
public int Id { get; set; }
public int SenderId { get; set; }
public string SenderName { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public DateTime Timestamp { get; set; }
public bool IsMyMessage { get; set; }
}