232 lines
8.4 KiB
C#
232 lines
8.4 KiB
C#
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; }
|
||
}
|