using qtc_net_client_2.ClientModel; using qtc_net_client_2.Controls; using qtc_net_client_2.Services; using QtCNETAPI.Dtos.User; using QtCNETAPI.Events; using QtCNETAPI.Models; using QtCNETAPI.Services.ApiService; using QtCNETAPI.Services.GatewayService; using System.Threading.Tasks; namespace qtc_net_client_2.Forms { public partial class ChatRoom : Form { private readonly IGatewayService _gatewayService; private readonly IApiService _apiService; private readonly AudioService AudioService = new(); private readonly List RoomUserList = new(); private Room? Room; public ChatRoom(IGatewayService gatewayService, IApiService apiService, Room? room = null) { _gatewayService = gatewayService; _apiService = apiService; Room = room; // subscribe to server message event _gatewayService.OnRoomMessageReceived += _gatewayService_OnServerMessageReceived; _gatewayService.OnRoomUserListReceived += _gatewayService_OnRoomUserListReceived; _gatewayService.OnRoomDeleted += _gatewayService_OnRoomDeleted; _gatewayService.OnGuestUserJoin += _gatewayService_OnGuestUserJoin; InitializeComponent(); } private async void frmChat_Load(object sender, EventArgs e) { if (Room == null) { // join lobby await _gatewayService.JoinRoomAsync(); Room = new Room { Id = "LOBBY", Name = "Lobby" }; } else { // join selected room await _gatewayService.JoinRoomAsync(Room); } // init ui Text = $"QtC.NET Client - Chat Room - {Room.Name}"; lblRoomName.Text = Room.Name; RoomUserList.Clear(); lvUserList.Items.Clear(); } private async void frmChat_FormClosing(object sender, FormClosingEventArgs e) { // unsubscribe from server message event _gatewayService.OnRoomMessageReceived -= _gatewayService_OnServerMessageReceived; _gatewayService.OnRoomUserListReceived -= _gatewayService_OnRoomUserListReceived; if (_gatewayService.CurrentRoom != null) { // leave any room user is in await _gatewayService.LeaveRoomAsync(); } } private async void btnSend_Click(object sender, EventArgs e) { if (!string.IsNullOrWhiteSpace(rtxtChatbox.Text)) { // construct message QtCNETAPI.Models.Message message = new() { Content = rtxtChatbox.Text }; // send it and clear text box await _gatewayService.PostMessageAsync(message); rtxtChatbox.Text = string.Empty; AudioService.PlaySoundEffect("sndSendClick"); } } private void rtxtChatbox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) btnSend_Click(sender, e); } private async void lvUserList_DoubleClick(object sender, EventArgs e) { if (lvUserList.SelectedItems.Count > 0) { string? selectedUser = (string?)lvUserList.SelectedItems[lvUserList.SelectedItems.Count - 1].Text; if (selectedUser != null) { // split from [ if it exists if (selectedUser.Contains('[')) selectedUser = selectedUser.Split('[', options: StringSplitOptions.TrimEntries)[0]; // in this context, we need to find the main form to get the current user directory Main? mainForm = (Main?)Application.OpenForms[0]; if (mainForm != null) { // get user info and open profile dialog var user = mainForm.UserDirectory.FirstOrDefault(e => e.Username == selectedUser); if (user != null) { var res = await _apiService.GetUserInformationAsync(user.Id); var pfpRes = await _apiService.GetUserProfilePic(user.Id); if (res.Data != null && res.Success) { Profile frmProfile = new Profile(res.Data, pfpRes, mainForm.Contacts, _apiService, _gatewayService); frmProfile.Show(); } } } } } } private async void _gatewayService_OnServerMessageReceived(object? sender, EventArgs e) { var msgEventArgs = (ServerMessageEventArgs)e; var user = RoomUserList.FirstOrDefault(e => e.Username == msgEventArgs.Message.Split(':')[0]); AddMessage(msgEventArgs.Message, user?.Id); if (!msgEventArgs.Message.Contains(_apiService.CurrentUser.Username)) AudioService.PlaySoundEffect("sndMessage"); } private void _gatewayService_OnRoomUserListReceived(object? sender, EventArgs e) { var args = (RoomListEventArgs)e; if (IsHandleCreated && !IsDisposed) { Invoke(async delegate () { RoomUserList.Clear(); lvUserList.Items.Clear(); foreach (var user in args.UserList) { lvUserList.Items.Add(user.Username, user.Status); RoomUserList.Add(user); // TODO - probably do this only when a message is received (requires response model change) var pfpRes = await _apiService.GetUserProfilePic(user.Id); if (pfpRes != null && pfpRes.Success && pfpRes.Data != null) { using var ms = new MemoryStream(pfpRes.Data); using var bmp = new Bitmap(ms); ilProfileImages.Images.Add(user.Id, bmp); } } }); } } private void _gatewayService_OnGuestUserJoin(object? sender, EventArgs e) { var args = (GuestUserJoinEventArgs)e; AddMessage($"Server: Guest User {args.Username} Has Joined {_gatewayService.CurrentRoom?.Name}"); } private void _gatewayService_OnRoomDeleted(object? sender, EventArgs e) { if (IsHandleCreated && !IsDisposed) { Invoke(delegate () { AddMessage($"Server: This Room Was Deleted By An Admin."); lvUserList.Items.Clear(); RoomUserList.Clear(); lvUserList.Enabled = false; rtxtChatbox.Enabled = false; btnSend.Enabled = false; }); } } private void AddMessage(string message, string? userId = null) { if (IsHandleCreated && !IsDisposed) { Invoke((Delegate)delegate () { var ctrl = new ChatMessageControl() { Avatar = ilProfileImages.Images[userId] ?? ilProfileImages.Images[0], Username = message.Split(':')[0], Message = message.Split(':')[1].Trim(), Width = fpnlMessages.ClientSize.Width - SystemInformation.VerticalScrollBarWidth }; ctrl.Height = ctrl.CalculateHeight(ctrl.Width); fpnlMessages.Controls.Add(ctrl); fpnlMessages.VerticalScroll.Value = fpnlMessages.VerticalScroll.Maximum; fpnlMessages.PerformLayout(); }); } } } }