diff --git a/QtCNETAPI/Dtos/Room/RoomDto.cs b/QtCNETAPI/Dtos/Room/RoomDto.cs new file mode 100644 index 0000000..2d5ced6 --- /dev/null +++ b/QtCNETAPI/Dtos/Room/RoomDto.cs @@ -0,0 +1,8 @@ +namespace QtCNETAPI.Dtos.Room +{ + public class RoomDto + { + public string Name { get; set; } = string.Empty; + public DateTime CreatedAt { get; set; } = new DateTime(); + } +} diff --git a/QtCNETAPI/Dtos/User/UserDto.cs b/QtCNETAPI/Dtos/User/UserDto.cs new file mode 100644 index 0000000..0d915e6 --- /dev/null +++ b/QtCNETAPI/Dtos/User/UserDto.cs @@ -0,0 +1,10 @@ +namespace QtCNETAPI.Dtos.User +{ + public class UserDto + { + public string Username { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; + public DateTime DateOfBirth { get; set; } = new DateTime(); + } +} diff --git a/QtCNETAPI/Dtos/User/UserInformationDto.cs b/QtCNETAPI/Dtos/User/UserInformationDto.cs new file mode 100644 index 0000000..2108dbb --- /dev/null +++ b/QtCNETAPI/Dtos/User/UserInformationDto.cs @@ -0,0 +1,15 @@ +namespace QtCNETAPI.Dtos.User +{ + public class UserInformationDto + { + public string Id { get; set; } = string.Empty; + public string Username { get; set; } = string.Empty; + public string ProfilePicture { get; set; } = string.Empty; + public string Bio { get; set; } = string.Empty; + public string Role { get; set; } = string.Empty; + public DateTime DateOfBirth { get; set; } = new DateTime(); + public DateTime CreatedAt { get; set; } = new DateTime(); + public int Status { get; set; } = 0; + public int CurrencyAmount { get; set; } = 0; + } +} diff --git a/QtCNETAPI/Dtos/User/UserLoginDto.cs b/QtCNETAPI/Dtos/User/UserLoginDto.cs new file mode 100644 index 0000000..7a21de7 --- /dev/null +++ b/QtCNETAPI/Dtos/User/UserLoginDto.cs @@ -0,0 +1,9 @@ +namespace QtCNETAPI.Dtos.User +{ + public class UserLoginDto + { + public string Email { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + public bool RememberMe { get; set; } = false; + } +} diff --git a/QtCNETAPI/Dtos/User/UserRefreshLoginDto.cs b/QtCNETAPI/Dtos/User/UserRefreshLoginDto.cs new file mode 100644 index 0000000..7933b1f --- /dev/null +++ b/QtCNETAPI/Dtos/User/UserRefreshLoginDto.cs @@ -0,0 +1,8 @@ +namespace QtCNETAPI.Dtos.User +{ + public class UserRefreshLoginDto + { + public string Email { get; set; } = string.Empty; + public string RefreshToken { get; set; } = string.Empty; + } +} diff --git a/QtCNETAPI/Dtos/User/UserStatusDto.cs b/QtCNETAPI/Dtos/User/UserStatusDto.cs new file mode 100644 index 0000000..3e628be --- /dev/null +++ b/QtCNETAPI/Dtos/User/UserStatusDto.cs @@ -0,0 +1,8 @@ +namespace QtCNETAPI.Dtos.User +{ + public class UserStatusDto + { + public string Id { get; set; } = string.Empty; + public int Status { get; set; } = 0; + } +} diff --git a/QtCNETAPI/Dtos/User/UserUpdateInformationDto.cs b/QtCNETAPI/Dtos/User/UserUpdateInformationDto.cs new file mode 100644 index 0000000..b7ee27a --- /dev/null +++ b/QtCNETAPI/Dtos/User/UserUpdateInformationDto.cs @@ -0,0 +1,10 @@ +namespace QtCNETAPI.Dtos.User +{ + public class UserUpdateInformationDto + { + public string Id { get; set; } = string.Empty; + public string Username { get; set; } = string.Empty; + public string Bio { get; set; } = string.Empty; + public DateTime DateOfBirth { get; set; } = new DateTime(); + } +} diff --git a/QtCNETAPI/Events/ClientFunctionEventArgs.cs b/QtCNETAPI/Events/ClientFunctionEventArgs.cs new file mode 100644 index 0000000..53847ff --- /dev/null +++ b/QtCNETAPI/Events/ClientFunctionEventArgs.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QtCNETAPI.Events +{ + public class ClientFunctionEventArgs : EventArgs + { + public required string Function { get; set; } + } +} diff --git a/QtCNETAPI/Events/DirectMessageEventArgs.cs b/QtCNETAPI/Events/DirectMessageEventArgs.cs new file mode 100644 index 0000000..581aef7 --- /dev/null +++ b/QtCNETAPI/Events/DirectMessageEventArgs.cs @@ -0,0 +1,16 @@ +using QtCNETAPI.Dtos.User; +using QtCNETAPI.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QtCNETAPI.Events +{ + public class DirectMessageEventArgs : EventArgs + { + public required Message Message { get; set; } + public required UserInformationDto User { get; set; } + } +} diff --git a/QtCNETAPI/Events/ServerConfigEventArgs.cs b/QtCNETAPI/Events/ServerConfigEventArgs.cs new file mode 100644 index 0000000..862d443 --- /dev/null +++ b/QtCNETAPI/Events/ServerConfigEventArgs.cs @@ -0,0 +1,14 @@ +using QtCNETAPI.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QtCNETAPI.Events +{ + public class ServerConfigEventArgs : EventArgs + { + public required ServerConfig ServerConfig { get; set; } + } +} diff --git a/QtCNETAPI/Events/ServerConnectionClosedEventArgs.cs b/QtCNETAPI/Events/ServerConnectionClosedEventArgs.cs new file mode 100644 index 0000000..0c25439 --- /dev/null +++ b/QtCNETAPI/Events/ServerConnectionClosedEventArgs.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QtCNETAPI.Events +{ + public class ServerConnectionClosedEventArgs : EventArgs + { + public Exception? Error { get; set; } + } +} diff --git a/QtCNETAPI/Events/ServerConnectionReconnectingEventArgs.cs b/QtCNETAPI/Events/ServerConnectionReconnectingEventArgs.cs new file mode 100644 index 0000000..dd43f65 --- /dev/null +++ b/QtCNETAPI/Events/ServerConnectionReconnectingEventArgs.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QtCNETAPI.Events +{ + public class ServerConnectionReconnectingEventArgs : EventArgs + { + public Exception? Error { get; set; } + } +} diff --git a/QtCNETAPI/Events/ServerMessageEventArgs.cs b/QtCNETAPI/Events/ServerMessageEventArgs.cs new file mode 100644 index 0000000..de24b5e --- /dev/null +++ b/QtCNETAPI/Events/ServerMessageEventArgs.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QtCNETAPI.Events +{ + public class ServerMessageEventArgs : EventArgs + { + public required string Message { get; set; } + } +} diff --git a/QtCNETAPI/Models/Contact.cs b/QtCNETAPI/Models/Contact.cs new file mode 100644 index 0000000..ebdcdde --- /dev/null +++ b/QtCNETAPI/Models/Contact.cs @@ -0,0 +1,16 @@ +namespace QtCNETAPI.Models +{ + public class Contact + { + public string Id { get; set; } = string.Empty; + public string OwnerId { get; set; } = string.Empty; + public string UserId { get; set; } = string.Empty; + public ContactStatus OwnerStatus { get; set; } = ContactStatus.AwaitingApprovalFromOther; + public ContactStatus UserStatus { get; set; } = ContactStatus.AwaitingApprovalFromSelf; + + public virtual User? Owner { get; } + public virtual User? User { get; } + + public enum ContactStatus { AwaitingApprovalFromOther = 0, AwaitingApprovalFromSelf = 1, Accepted = 2 } + } +} diff --git a/QtCNETAPI/Models/Message.cs b/QtCNETAPI/Models/Message.cs new file mode 100644 index 0000000..c6623aa --- /dev/null +++ b/QtCNETAPI/Models/Message.cs @@ -0,0 +1,10 @@ +namespace QtCNETAPI.Models +{ + public class Message + { + public string Id { get; set; } = string.Empty; + public string AuthorId { get; set; } = string.Empty; + public string Content { get; set; } = string.Empty; + public DateTime CreatedAt { get; set; } = new DateTime(); + } +} diff --git a/QtCNETAPI/Models/RefreshToken.cs b/QtCNETAPI/Models/RefreshToken.cs new file mode 100644 index 0000000..a0c247f --- /dev/null +++ b/QtCNETAPI/Models/RefreshToken.cs @@ -0,0 +1,12 @@ +namespace QtCNETAPI.Models +{ + public class RefreshToken + { + public string ID { get; set; } = string.Empty; + public string UserID { get; set; } = string.Empty; + public string Token { get; set; } = string.Empty; + public DateTime Expires { get; set; } + + public virtual User User { get; } = null!; + } +} diff --git a/QtCNETAPI/Models/Room.cs b/QtCNETAPI/Models/Room.cs new file mode 100644 index 0000000..6988721 --- /dev/null +++ b/QtCNETAPI/Models/Room.cs @@ -0,0 +1,10 @@ +namespace QtCNETAPI.Models +{ + public class Room + { + public string Id { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string CreatorId { get; set; } = string.Empty; + public DateTime CreatedAt { get; set; } = new DateTime(); + } +} diff --git a/QtCNETAPI/Models/ServerConfig.cs b/QtCNETAPI/Models/ServerConfig.cs new file mode 100644 index 0000000..5d52143 --- /dev/null +++ b/QtCNETAPI/Models/ServerConfig.cs @@ -0,0 +1,11 @@ +namespace QtCNETAPI.Models +{ + public class ServerConfig + { + public string? Name { get; set; } + public string? Description { get; set; } + public string? AdminUserId { get; set; } + public bool IsDown { get; set; } + public string? IsDownMessage { get; set; } + } +} diff --git a/QtCNETAPI/Models/ServiceResponse.cs b/QtCNETAPI/Models/ServiceResponse.cs new file mode 100644 index 0000000..f1f8e4f --- /dev/null +++ b/QtCNETAPI/Models/ServiceResponse.cs @@ -0,0 +1,9 @@ +namespace QtCNETAPI.Models +{ + public class ServiceResponse + { + public T? Data { get; set; } + public bool Success { get; set; } = false; + public string Message { get; set; } = string.Empty; + } +} diff --git a/QtCNETAPI/Models/User.cs b/QtCNETAPI/Models/User.cs new file mode 100644 index 0000000..94bbf27 --- /dev/null +++ b/QtCNETAPI/Models/User.cs @@ -0,0 +1,22 @@ +namespace QtCNETAPI.Models +{ + public class User + { + public string Id { get; set; } = string.Empty; + public string Username { get; set; } = string.Empty; + public string ProfilePicture { get; set; } = string.Empty; + public string Bio { get; set; } = string.Empty; + public string Role { get; set; } = string.Empty; + public string PasswordHash { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; + public DateTime DateOfBirth { get; set; } + public DateTime CreatedAt { get; set; } + public int Status { get; set; } = 0; + public int CurrencyAmount { get; set; } = 0; + public DateTime LastCurrencySpin { get; set; } + + public virtual IEnumerable? RefreshTokens { get; } + public virtual IEnumerable? ContactsMade { get; } + public virtual IEnumerable? ContactsList { get; } + } +} diff --git a/QtCNETAPI/QtCNETAPI.csproj b/QtCNETAPI/QtCNETAPI.csproj new file mode 100644 index 0000000..0edb883 --- /dev/null +++ b/QtCNETAPI/QtCNETAPI.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + + + + + + + + + + diff --git a/QtCNETAPI/Services/ApiService/ApiService.cs b/QtCNETAPI/Services/ApiService/ApiService.cs new file mode 100644 index 0000000..1026c5d --- /dev/null +++ b/QtCNETAPI/Services/ApiService/ApiService.cs @@ -0,0 +1,570 @@ +using QtCNETAPI.Dtos.Room; +using QtCNETAPI.Dtos.User; +using QtCNETAPI.Models; +using RestSharp; +using System.IdentityModel.Tokens.Jwt; +using System.Text.Json; + +namespace QtCNETAPI.Services.ApiService +{ + public class ApiService : IApiService + { + private User? user; + private RestClient _client; + + internal string? sessionToken; + internal string apiUri; + + public string? SessionToken + { + get { return sessionToken; } + set { sessionToken = value; } + } + + public User? CurrentUser + { + get { return user; } + } + + public ApiService(string apiUrl) + { + apiUri = apiUrl; + _client = new RestClient(apiUri); + } + + public async Task> PingServerAsync() + { + var serviceResponse = new ServiceResponse(); + + try + { + var request = new RestRequest("general/ping"); + var response = await _client.GetAsync(request); + + if (response != null) + { + if (response != "Pong!") serviceResponse.Success = false; + else serviceResponse.Success = true; + } + else serviceResponse.Success = false; + } catch (HttpRequestException ex) + { + serviceResponse.Success = false; + serviceResponse.Message = ex.Message; + } + + return serviceResponse; + } + + public async Task>> GetOnlineUsersAsync() + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse>(); + + if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var request = new RestRequest("users/users-online") + .AddHeader("Authorization", $"Bearer {SessionToken}"); + var response = await _client.GetAsync>>(request); + + if (response != null || response!.Data != null) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } else + { + serviceResponse.Success = false; + serviceResponse.Message = "API didn't respond with online users."; + } + + return serviceResponse; + } + + public async Task> GetUserInformationAsync(string id) + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse(); + + if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var request = new RestRequest($"users/user-info") + .AddHeader("Authorization", $"Bearer {SessionToken}") + .AddQueryParameter("id", id); + var response = await _client.GetAsync>(request); + + if(response != null || response!.Data != null) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } else + { + serviceResponse.Success = false; + serviceResponse.Message = "API did not return user information."; + } + + return serviceResponse; + } + + public async Task> UpdateUserInformationAsync(UserUpdateInformationDto request) + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse(); + + var restRequest = new RestRequest("users/update") + .AddJsonBody(request) + .AddHeader("Authorization", $"Bearer {SessionToken}"); + var response = await _client.PutAsync>(restRequest); + + if(response != null || response!.Data != null) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + + // update currentuser model + CurrentUser!.Username = response.Data!.Username; + CurrentUser.Bio = response.Data.Bio; + CurrentUser.DateOfBirth = response.Data.DateOfBirth; + } else + { + serviceResponse.Success = false; + serviceResponse.Message = "API never responded."; + } + + return serviceResponse; + } + + public async Task> UpdateUserProfilePic(string filePath) + { + var serviceResponse = new ServiceResponse(); + + try + { + var restRequest = new RestRequest($"users/upload-profile-pic") + .AddQueryParameter("userId", CurrentUser!.Id) + .AddHeader("Authorization", $"Bearer {SessionToken}") + .AddFile("file", filePath); + var response = await _client.PostAsync>(restRequest); + + if (response != null && response.Success != false) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } + else + { + serviceResponse.Success = false; + serviceResponse.Data = "Upload Failed."; + } + } catch (JsonException) + { + serviceResponse.Success = false; + serviceResponse.Message = "Profile Pictures Can Only Be Less Then 3 MB In Size."; + } catch (HttpRequestException ex) + { + serviceResponse.Success = false; + serviceResponse.Data = ex.Message; + } + + return serviceResponse; + } + + public async Task> GetUserProfilePic(string userId) + { + var serviceResponse = new ServiceResponse(); + try + { + var restRequest = new RestRequest($"users/profile-pic/{userId}") + .AddHeader("Authorization", $"Bearer {SessionToken}"); + var response = await _client.GetAsync(restRequest); + + if (response != null) + { + serviceResponse.Success = true; + serviceResponse.Data = response.RawBytes; + } + else + { + serviceResponse.Success = false; + serviceResponse.Message = "No Profile Picture Received."; + } + + return serviceResponse; + } catch (HttpRequestException ex) + { + serviceResponse.Success = false; + serviceResponse.Message = ex.Message; + return serviceResponse; + } + } + + public async Task> LoginAsync(UserLoginDto userLoginDto) + { + var serviceResponse = new ServiceResponse(); + + try + { + if (string.IsNullOrWhiteSpace(userLoginDto.Email) || string.IsNullOrWhiteSpace(userLoginDto.Password)) + { + serviceResponse.Success = false; + serviceResponse.Message = "Email or Password cannot be null."; + } + + var request = new RestRequest("auth/login") + .AddJsonBody(userLoginDto); + var response = await _client.PostAsync>(request); + + if (response != null) + { + if (response.Data != null && response.Success) + { + SessionToken = response.Data!; + + await File.WriteAllTextAsync("./session.token", response.Message); + + var user = await SetCurrentUser(); + + serviceResponse.Success = true; + if (response.Message != null) serviceResponse.Message = response.Message; + serviceResponse.Data = user; + } + else + { + serviceResponse.Success = false; + serviceResponse.Message = response.Message; + } + } + } catch (Exception ex) + { + serviceResponse.Success = false; + serviceResponse.Message = ex.Message; + } + + return serviceResponse; + } + + private async Task SetCurrentUser() + { + var userRequest = new RestRequest("users/user-authorized") + .AddHeader("Authorization", $"Bearer {SessionToken}"); + var userResponse = await _client.GetAsync>(userRequest); + + if (userResponse != null || userResponse!.Data != null) + { + user = userResponse.Data; + return userResponse.Data!; + } else + { + throw new NullReferenceException("Current User could not be set."); + } + } + + public async Task> RefreshLogin(string refreshToken) + { + var serviceResponse = new ServiceResponse(); + + try + { + if (string.IsNullOrEmpty(refreshToken)) + { + serviceResponse.Success = false; + serviceResponse.Message = "No Refresh Token Specified."; + } + + var request = new RestRequest("auth/refresh") + .AddQueryParameter("token", refreshToken); + var response = await _client.PostAsync>(request); + + if (response != null && response.Success != false) + { + SessionToken = response.Data; + + if (user == null) + { + var user = await SetCurrentUser(); + + serviceResponse.Success = true; + serviceResponse.Data = user; + } + + serviceResponse.Success = true; + serviceResponse.Data = CurrentUser; + } + else + { + serviceResponse.Success = false; + serviceResponse.Message = "API didn't respond with a session token."; + } + } catch (Exception ex) + { + serviceResponse.Success = false; + serviceResponse.Message = ex.Message; + } + + return serviceResponse; + } + + public async Task> RefreshSessionIfInvalid() + { + var tokenHandler = new JwtSecurityTokenHandler(); + var refToken = await File.ReadAllTextAsync("./session.token"); + + JwtSecurityToken token = tokenHandler.ReadJwtToken(SessionToken); + + if(DateTime.Compare(DateTime.UtcNow, token.ValidTo) > 0) + { + if (!File.Exists("./session.token")) { return new ServiceResponse { Success = false, Message = "Session File Not Found. Session Expired." }; } + + var result = await RefreshLogin(refToken); + + if (result == null || result.Success == false) + { + File.Delete("./session.token"); + + return new ServiceResponse { Success = false, Message = "Session Expired." }; + } else return new ServiceResponse { Success = true, Data = refToken }; + } else return new ServiceResponse { Success = true, Data = refToken }; + } + + public async Task> RegisterAsync(UserDto userDto) + { + var serviceResponse = new ServiceResponse(); + + if (string.IsNullOrEmpty(userDto.Username) || string.IsNullOrEmpty(userDto.Password) || string.IsNullOrEmpty(userDto.Email)) + { + serviceResponse.Success = false; + serviceResponse.Message = "Incomplete UserDto."; + } + + var request = new RestRequest("auth/register") + .AddJsonBody(userDto); + var response = await _client.PostAsync>(request); + + if (response != null || response!.Success == true) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } else + { + serviceResponse.Success = false; + serviceResponse.Message = "API never responded with created user."; + } + + return serviceResponse; + } + + public async Task> CreateRoomAsync(RoomDto request) + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse(); + + if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var restRequest = new RestRequest($"rooms/create-room?userId={user!.Id}") + .AddJsonBody(request) + .AddHeader("Authorization", $"Bearer {SessionToken}"); + var response = await _client.PostAsync>(restRequest); + + if(response != null || response!.Data != null) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } else + { + serviceResponse.Success = false; + serviceResponse.Message = "API never responded with created room."; + } + + return serviceResponse; + } + + public async Task>> GetAllRoomsAsync() + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse>(); + + if(SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var request = new RestRequest("rooms/get-all-rooms") + .AddHeader("Authorization", $"Bearer {SessionToken}"); + var response = await _client.GetAsync>>(request); + + if (response != null || response!.Data != null) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } + else + { + serviceResponse.Success = false; + serviceResponse.Message = "API never responded with rooms."; + } + + return serviceResponse; + } + + public async Task> DeleteRoomAsync(string roomId) + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse(); + + if(SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var request = new RestRequest($"rooms/delete-room?roomId={roomId}") + .AddHeader("Authorization", $"Bearer {SessionToken}"); + var response = await _client.DeleteAsync>(request); + + if (response != null || response!.Data != null) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } else + { + serviceResponse.Success = false; + serviceResponse.Message = "API never responded."; + } + + return serviceResponse; + } + + public async Task>> GetCurrentUserContacts() + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse>(); + + if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var request = new RestRequest("contacts/get-user-contacts") + .AddHeader("Authorization", $"Bearer {SessionToken}") + .AddJsonBody(CurrentUser!); + var response = await _client.GetAsync>>(request); + + if (response == null) + { + serviceResponse.Success = false; + serviceResponse.Message = "API didn't respond."; + + return serviceResponse; + } + + if (response.Message == "User Has No Contacts.") + { + serviceResponse.Success = true; + serviceResponse.Message = "No Contacts Found."; + } + + if (response.Success == true) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } + + return serviceResponse; + } + + public async Task> AddContactToCurrentUser(string userId) + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse(); + + if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var restRequest = new RestRequest("contacts/add-contact") + .AddHeader("Authorization", $"Bearer {SessionToken}") + .AddQueryParameter("ownerId", CurrentUser!.Id) + .AddQueryParameter("userId", userId); + var response = await _client.PostAsync>(restRequest); + + if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } + + if (response.Success) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } + + return serviceResponse; + } + + public async Task> AcceptContactRequest(string userId) + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse(); + + if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var restRequest = new RestRequest("contacts/approve-contact") + .AddHeader("Authorization", $"Bearer {SessionToken}") + .AddQueryParameter("ownerId", CurrentUser!.Id) + .AddQueryParameter("userId", userId); + var response = await _client.PostAsync>(restRequest); + + if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } + + if (response.Success) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } + + return serviceResponse; + } + + public async Task> RemoveContactFromCurrentUser(string userId) + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse(); + + if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var restRequest = new RestRequest("contacts/remove-contact") + .AddHeader("Authorization", $"Bearer {SessionToken}") + .AddQueryParameter("userId", userId); + var response = await _client.DeleteAsync>(restRequest); + + if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } + + if (response.Success) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } + + return serviceResponse; + } + + public async Task> AddCurrencyToCurrentUser(int amount, bool isSpinClaim) + { + await RefreshSessionIfInvalid(); + + var serviceResponse = new ServiceResponse(); + + if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made."); + + var restRequest = new RestRequest("users/update-user-currency") + .AddHeader("Authorization", $"Bearer {SessionToken}") + .AddQueryParameter("amount", amount) + .AddQueryParameter("isSpinClaim", isSpinClaim); + var response = await _client.PostAsync>(restRequest); + + if (response == null) { serviceResponse.Success = false; serviceResponse.Message = "API did not respond."; return serviceResponse; } + + if (response.Success) + { + serviceResponse.Success = true; + serviceResponse.Data = response.Data; + } + + return serviceResponse; + } + } +} diff --git a/QtCNETAPI/Services/ApiService/IApiService.cs b/QtCNETAPI/Services/ApiService/IApiService.cs new file mode 100644 index 0000000..3d526e3 --- /dev/null +++ b/QtCNETAPI/Services/ApiService/IApiService.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Mvc; +using QtCNETAPI.Dtos.User; +using QtCNETAPI.Dtos.Room; +using QtCNETAPI.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace QtCNETAPI.Services.ApiService +{ + public interface IApiService + { + public string? SessionToken { get; set; } + public User CurrentUser { get; } + + public Task> PingServerAsync(); + public Task>> GetOnlineUsersAsync(); + public Task> LoginAsync(UserLoginDto userLoginDto); + public Task> RefreshLogin(string refreshToken); + public Task> RefreshSessionIfInvalid(); + public Task> RegisterAsync(UserDto userDto); + public Task> GetUserInformationAsync(string id); + public Task> UpdateUserInformationAsync(UserUpdateInformationDto request); + public Task> UpdateUserProfilePic(string filePath); + public Task> GetUserProfilePic(string userId); + public Task> CreateRoomAsync(RoomDto request); + public Task> DeleteRoomAsync(string roomId); + public Task>> GetAllRoomsAsync(); + public Task>> GetCurrentUserContacts(); + public Task> AddContactToCurrentUser(string userId); + public Task> AcceptContactRequest(string userId); + public Task> RemoveContactFromCurrentUser(string userId); + public Task> AddCurrencyToCurrentUser(int amount, bool isSpinClaim); + } +} diff --git a/QtCNETAPI/Services/GatewayService/GatewayService.cs b/QtCNETAPI/Services/GatewayService/GatewayService.cs new file mode 100644 index 0000000..6ef9d9f --- /dev/null +++ b/QtCNETAPI/Services/GatewayService/GatewayService.cs @@ -0,0 +1,188 @@ +using Microsoft.AspNetCore.SignalR.Client; +using QtCNETAPI.Dtos.User; +using QtCNETAPI.Events; +using QtCNETAPI.Models; +using QtCNETAPI.Services.ApiService; + +namespace QtCNETAPI.Services.GatewayService +{ + public class GatewayService : IGatewayService + { + internal string gwBaseUri = "127.0.0.1"; + + public Room? CurrentRoom { get; private set; } + public bool InLobby { get; private set; } + public HubConnection? HubConnection { get; private set; } + + + public event EventHandler OnServerMessageReceived; + public event EventHandler OnClientFunctionReceived; + public event EventHandler OnDirectMessageReceived; + public event EventHandler OnServerConfigReceived; + public event EventHandler OnServerDisconnect; + public event EventHandler OnServerReconnecting; + public event EventHandler OnServerReconnected; + + private IApiService _apiService; + + public GatewayService(string GWUrl, IApiService apiService) + { + gwBaseUri = GWUrl; + _apiService = apiService; + } + + public async Task StartAsync() + { + // just to be safe (it doesn't load the server since it shouldn't request a new one unless its actually expired) + await _apiService.RefreshSessionIfInvalid(); + + // build connection + var gwConBuilder = new HubConnectionBuilder() + .WithAutomaticReconnect() + .WithUrl(gwBaseUri, options => + { + options.AccessTokenProvider = () => Task.FromResult(_apiService.SessionToken); + }); + HubConnection = gwConBuilder.Build(); + + // start connection + await HubConnection.StartAsync(); + + // register events + HubConnection.On("rm", (serverMessage) => OnServerMessageReceived?.Invoke(this, new ServerMessageEventArgs{Message = serverMessage})); + HubConnection.On("cf", (function) => OnClientFunctionReceived?.Invoke(this, new ClientFunctionEventArgs{Function = function})); + HubConnection.On("rdm", (message, user) => OnDirectMessageReceived?.Invoke(this, new DirectMessageEventArgs { Message = message, User = user })); + HubConnection.On("rc", (serverConfig) => OnServerConfigReceived?.Invoke(this, new ServerConfigEventArgs{ServerConfig = serverConfig})); + + HubConnection.Closed += HubConnection_Closed; + HubConnection.Reconnecting += HubConnection_Reconnecting; + HubConnection.Reconnected += HubConnection_Reconnected; + + if (HubConnection != null && HubConnection.State == HubConnectionState.Connected) + await HubConnection.SendAsync("l", _apiService.CurrentUser); + } + + public async Task StopAsync() + { + if (HubConnection != null && HubConnection.State == HubConnectionState.Connected) + { + await HubConnection.StopAsync(); + } + } + + public async Task DisposeAsync() + { + if (HubConnection != null && HubConnection.State == HubConnectionState.Disconnected) + { + await HubConnection.DisposeAsync(); + + HubConnection = null; + CurrentRoom = null; + } + } + + public async Task JoinLobbyAsync() + { + await _apiService.RefreshSessionIfInvalid(); + + if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made."); + + await HubConnection.SendAsync("jl", _apiService.CurrentUser); + InLobby = true; + CurrentRoom = null; + } + + public async Task JoinRoomAsync(Room room) + { + await _apiService.RefreshSessionIfInvalid(); + + if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made."); + + if (InLobby == true) + { + await HubConnection.SendAsync("ll", _apiService.CurrentUser); + InLobby = false; + } + else if (CurrentRoom != null) + { + await HubConnection.SendAsync("lr", _apiService.CurrentUser, CurrentRoom); + } + + await HubConnection.SendAsync("jr", _apiService.CurrentUser, room); + CurrentRoom = room; + } + + public async Task LeaveRoomAsync() + { + await _apiService.RefreshSessionIfInvalid(); + + if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made."); + + if (InLobby) + { + await HubConnection.SendAsync("ll", _apiService.CurrentUser); + InLobby = false; + } + else + { + await HubConnection.SendAsync("lr", _apiService.CurrentUser, CurrentRoom); + CurrentRoom = null; + } + } + + public async Task RefreshContactsForUser(UserInformationDto user) + { + await _apiService.RefreshSessionIfInvalid(); + + if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made."); + + await HubConnection.SendAsync("rcl", user, _apiService.CurrentUser); + } + + public async Task PostMessageAsync(Message message) + { + await _apiService.RefreshSessionIfInvalid(); + + if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made."); + + await HubConnection.SendAsync("s", _apiService.CurrentUser, message, InLobby, CurrentRoom); + } + + public async Task SendDirectMessageAsync(UserInformationDto user, Message message) + { + await _apiService.RefreshSessionIfInvalid(); + + if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made."); + + await HubConnection.SendAsync("sdm", _apiService.CurrentUser, user, message); + } + + public async Task UpdateStatus(int status) + { + await _apiService.RefreshSessionIfInvalid(); + + if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made."); + + await HubConnection.SendAsync("us", _apiService.CurrentUser, status); + } + + + private Task HubConnection_Closed(Exception? arg) + { + OnServerDisconnect?.Invoke(this, new ServerConnectionClosedEventArgs { Error = arg }); + return Task.CompletedTask; + } + + private Task HubConnection_Reconnecting(Exception? arg) + { + OnServerReconnecting?.Invoke(this, new ServerConnectionReconnectingEventArgs { Error = arg }); + return Task.CompletedTask; + } + + private Task HubConnection_Reconnected(string? arg) + { + OnServerReconnected?.Invoke(this, EventArgs.Empty); + return Task.CompletedTask; + } + } +} diff --git a/QtCNETAPI/Services/GatewayService/IGatewayService.cs b/QtCNETAPI/Services/GatewayService/IGatewayService.cs new file mode 100644 index 0000000..f620f36 --- /dev/null +++ b/QtCNETAPI/Services/GatewayService/IGatewayService.cs @@ -0,0 +1,140 @@ +using Microsoft.AspNetCore.SignalR.Client; +using QtCNETAPI.Dtos.User; +using QtCNETAPI.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace QtCNETAPI.Services.GatewayService +{ + public interface IGatewayService + { + // VARIABLES + + /// + /// The Current Room The Current User Is In + /// + public Room? CurrentRoom { get; } + /// + /// Is The User Currently In The Lobby? + /// + public bool InLobby { get; } + /// + /// The Current Connection To The Gateway + /// + public HubConnection? HubConnection { get; } + + // FUNCTIONS + + /// + /// The Function Used To Connect To The Gateway Server Asynchronously + /// + /// + public Task StartAsync(); + + /// + /// Stops The Connection To The Gateway Server + /// + /// + public Task StopAsync(); + + /// + /// Disposes Of The Gateway Connection And Clears Other Variables + /// + /// + public Task DisposeAsync(); + + /// + /// Joins The Lobby Of The Server + /// + /// + /// Thrown if the function is called before the connection is established. + public Task JoinLobbyAsync(); + + /// + /// Joins The Current User To A Room On The Server + /// + /// Room To Join + /// + /// Thrown if the function is called before the connection is established. + public Task JoinRoomAsync(Room room); + + /// + /// Leaves The Current Room The Current User Is In + /// + /// + public Task LeaveRoomAsync(); + + /// + /// Posts A Message To Whatever Room The User Is In + /// + /// Message To Post + /// + /// Thrown if the function is called before the connection is established. + public Task PostMessageAsync(Message message); + + /// + /// Sends A Direct Message To The Specified User + /// + /// The User You Wish To DM + /// Yourself + /// + /// + public Task SendDirectMessageAsync(UserInformationDto user, Message message); + + /// + /// Refreshes Contacts List For A Specified User + /// + /// The User You Wish To Refresh + /// Yourself + /// + public Task RefreshContactsForUser(UserInformationDto user); + + /// + /// Updates The Status For The Current User + /// + /// The Status You Want To Set On The Current User + /// + public Task UpdateStatus(int status); + + // EVENTS + + /// + /// When A Server Message Is Received, This Event Fires + /// + public event EventHandler OnServerMessageReceived; + + /// + /// When A Client Function/Event Is Received, This Event Fires + /// + public event EventHandler OnClientFunctionReceived; + + /// + /// When The Client Received A DM, This Event Fires + /// + public event EventHandler OnDirectMessageReceived; + + /// + /// When The Server Config Is Received, This Event Fires + /// + public event EventHandler OnServerConfigReceived; + + /// + /// When The Connection To The Gateway Is Lost, This Event Fires + /// + public event EventHandler OnServerDisconnect; + + /// + /// When The Connection Attempts To Reconnect, This Event Fires + /// + public event EventHandler OnServerReconnecting; + + /// + /// When the Connection Reconnects, This Event Fires + /// + public event EventHandler OnServerReconnected; + } +} diff --git a/qtc-net-client-2.sln b/qtc-net-client-2.sln new file mode 100644 index 0000000..76d6188 --- /dev/null +++ b/qtc-net-client-2.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.36105.23 d17.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "qtc-net-client-2", "qtc-net-client-2\qtc-net-client-2.csproj", "{D12EE167-2DE3-4AD8-9D74-2E3956EAECC9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtCNETAPI", "QtCNETAPI\QtCNETAPI.csproj", "{92DB3A4B-4B30-4719-8608-5772608428CD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D12EE167-2DE3-4AD8-9D74-2E3956EAECC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D12EE167-2DE3-4AD8-9D74-2E3956EAECC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D12EE167-2DE3-4AD8-9D74-2E3956EAECC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D12EE167-2DE3-4AD8-9D74-2E3956EAECC9}.Release|Any CPU.Build.0 = Release|Any CPU + {92DB3A4B-4B30-4719-8608-5772608428CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92DB3A4B-4B30-4719-8608-5772608428CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92DB3A4B-4B30-4719-8608-5772608428CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92DB3A4B-4B30-4719-8608-5772608428CD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E5B052F2-C964-4F70-ADF5-82E32374D35B} + EndGlobalSection +EndGlobal diff --git a/qtc-net-client-2/ClientModel/Config.cs b/qtc-net-client-2/ClientModel/Config.cs new file mode 100644 index 0000000..b38fb88 --- /dev/null +++ b/qtc-net-client-2/ClientModel/Config.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace qtc_net_client_2.ClientModel +{ + public class Config + { + [JsonPropertyName("apiEndpoint")] + public string ApiEndpoint { get; set; } = "https://qtc.alanmoon.net/api"; + [JsonPropertyName("gatewayEndpoint")] + public string GatewayEndpoint { get; set; } = "https://qtc.alanmoon.net/chat"; + } +} diff --git a/qtc-net-client-2/ClientModel/UserStatus.cs b/qtc-net-client-2/ClientModel/UserStatus.cs new file mode 100644 index 0000000..c97400d --- /dev/null +++ b/qtc-net-client-2/ClientModel/UserStatus.cs @@ -0,0 +1,11 @@ +namespace qtc_net_client_2.ClientModel +{ + public enum UserStatus + { + Offline = 0, + Online = 1, + Away = 2, + DoNotDisturb = 3, + Unknown + } +} diff --git a/qtc-net-client-2/Forms/Chat.Designer.cs b/qtc-net-client-2/Forms/Chat.Designer.cs new file mode 100644 index 0000000..e2af058 --- /dev/null +++ b/qtc-net-client-2/Forms/Chat.Designer.cs @@ -0,0 +1,91 @@ +namespace qtc_net_client_2.Forms +{ + partial class Chat + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Chat)); + rtxtChatbox = new RichTextBox(); + btnSend = new Button(); + rtxtChat = new RichTextBox(); + SuspendLayout(); + // + // rtxtChatbox + // + rtxtChatbox.Location = new Point(12, 268); + rtxtChatbox.Name = "rtxtChatbox"; + rtxtChatbox.Size = new Size(512, 54); + rtxtChatbox.TabIndex = 1; + rtxtChatbox.Text = ""; + // + // btnSend + // + btnSend.FlatAppearance.BorderSize = 0; + btnSend.FlatStyle = FlatStyle.Flat; + btnSend.Image = Properties.Resources.SendIcon; + btnSend.Location = new Point(530, 268); + btnSend.Name = "btnSend"; + btnSend.Size = new Size(75, 54); + btnSend.TabIndex = 2; + btnSend.UseVisualStyleBackColor = true; + btnSend.Click += btnSend_Click; + // + // rtxtChat + // + rtxtChat.Location = new Point(12, 12); + rtxtChat.Name = "rtxtChat"; + rtxtChat.ReadOnly = true; + rtxtChat.Size = new Size(593, 250); + rtxtChat.TabIndex = 3; + rtxtChat.Text = ""; + // + // frmChat + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(617, 334); + Controls.Add(rtxtChat); + Controls.Add(btnSend); + Controls.Add(rtxtChatbox); + FormBorderStyle = FormBorderStyle.FixedSingle; + Icon = (Icon)resources.GetObject("$this.Icon"); + MaximizeBox = false; + Name = "frmChat"; + StartPosition = FormStartPosition.CenterScreen; + Text = "QtC.NET Client - Chat Room"; + FormClosing += frmChat_FormClosing; + Load += frmChat_Load; + ResumeLayout(false); + } + + #endregion + private RichTextBox rtxtChatbox; + private Button btnSend; + private RichTextBox rtxtChat; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/Chat.cs b/qtc-net-client-2/Forms/Chat.cs new file mode 100644 index 0000000..729c1b1 --- /dev/null +++ b/qtc-net-client-2/Forms/Chat.cs @@ -0,0 +1,80 @@ +using qtc_net_client_2.Services; +using QtCNETAPI.Events; +using QtCNETAPI.Models; +using QtCNETAPI.Services.ApiService; +using QtCNETAPI.Services.GatewayService; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace qtc_net_client_2.Forms +{ + public partial class Chat : Form + { + IGatewayService _gatewayService; + IApiService _apiService; + AudioService AudioService = new(); + public Chat(IGatewayService gatewayService, IApiService apiService) + { + _gatewayService = gatewayService; + _apiService = apiService; + InitializeComponent(); + } + + private void frmChat_Load(object sender, EventArgs e) + { + // subscribe to server message event + _gatewayService.OnServerMessageReceived += _gatewayService_OnServerMessageReceived; + + if (_gatewayService.CurrentRoom != null) Text = $"QtC.NET Client - Chat Room - {_gatewayService.CurrentRoom.Name}"; + else if (_gatewayService.InLobby) Text = $"QtC.NET Client - Chat Room - Lobby"; + } + + private async void frmChat_FormClosing(object sender, FormClosingEventArgs e) + { + // unsubscribe from server message event + _gatewayService.OnServerMessageReceived -= _gatewayService_OnServerMessageReceived; + + if (_gatewayService.CurrentRoom != null || _gatewayService.InLobby) + { + // 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.Clear(); + AudioService.PlaySoundEffect("sndSendClick"); + } + } + + private void _gatewayService_OnServerMessageReceived(object? sender, EventArgs e) + { + var msgEventArgs = (ServerMessageEventArgs)e; + + AddMessage(msgEventArgs.Message); + if (!msgEventArgs.Message.Contains(_apiService.CurrentUser.Username)) AudioService.PlaySoundEffect("sndMessage"); + } + + private void AddMessage(string message) + { + if (InvokeRequired) + Invoke(delegate { rtxtChat.Text += message + "\n"; }); + else rtxtChat.Text += message + "\n"; + } + } +} diff --git a/qtc-net-client-2/Forms/Chat.resx b/qtc-net-client-2/Forms/Chat.resx new file mode 100644 index 0000000..b5414cd --- /dev/null +++ b/qtc-net-client-2/Forms/Chat.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAEA8AAAEACABDBQAAFgAAACgAAAAQAAAAHgAAAAEACAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA9dN/APXTgAD00XoA9M5wAPPLZwDzyF8A8sZZAPLEVADywk4A8L9FAPC8PAD104AA9dF6APTL + aQD0z3UA9dSDAPC9PwDvtisA7rIeAPTOcgD0zW8A8sRVAPC7OgDsqgkA4J8AAPPJYwDxwUkA4KIMAM2S + AADxwUoAtYEAAO+3LQCbbgAA7K0PAOuoBACneQYAfloAANubAADYmQAAgVsAAGRHAADMkQAAuIMAALqF + AAB2VAAAWT8AAF5CAACpeAAAmm4AAJhsAACfcQAAfFgAAG9VFgCjlncAxr6sAI9mAACCXQAAfVkAAHdU + AABxUAAAa0wAAGRHAABcQgAAVTwAAN3a0QDt7e0A3t7eAOnp6QDi4uIA+fn5APPz8wD09PQA4uLiAM7O + zgD///8A/Pz8APPz8wDc3NwA+OOtAPzy2QD9+e4A/fblAPrpwAD22I8A6+fcAN3d3QDZ2dkA19fXAL6+ + vgD+/foA+uvEAPTMawD++/QAoqKiAF9fXwBdXV0AW1tbAFRUVAD///8A+vr6AOPPnADusyIA+eSyAP7+ + /gDk5OQA4uLiAN7e3gDo6OgA4+PjALOvpQDLmR4A7awPAPnmuAD9/f0A9/f3AEFBQQA9PT0ANTU1AIiI + iAC9vb0Afnx1ALWHFgDrxGUA39/dAKurqwCjo6MAlpaWAHl5eQDExMQAdHR0AGhbOgDgogkAw6dkAGlp + aABGRkYATExMAEVFRQA6OjoAXFxcAFRMOACgdg0AzJIDALuQJQCJdkgAaGFSAFZVUwBTUEgAXFI2AH9k + IgChdAUAq3oDAKx8BQCoegYAoXQGAJJpAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABNTgAAAAAAAAAAAAAAAAAAS0wAAAAAAAAAAAAAAABISUoAAAAAAAAA + AAAAAABERUZHAAAAODk6Ozw9Pj9AQUJDAAAAMDEyM5eYmZqbNDU2NwAAKissjo+QkZKTlJWWLS4vACYn + hIWGh4iIiYqLjI0oKQAiI3t8WX1+Xn+AgYKDJCUAIHBxcnN0dXV1dnd4eXohAB5mZ2NoaWpqamtsbW5v + HwAaG1xdXl9gYGFiY2RlHB0AFBUWVFVWV1dYWVpbFxgZAAAMDQ4PT1BRUlMQERITAAAAAAECAwQFBgcI + CQoLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/ConnectionClosed.Designer.cs b/qtc-net-client-2/Forms/ConnectionClosed.Designer.cs new file mode 100644 index 0000000..7797a2f --- /dev/null +++ b/qtc-net-client-2/Forms/ConnectionClosed.Designer.cs @@ -0,0 +1,110 @@ +namespace qtc_net_client_2.Forms +{ + partial class ConnectionClosed + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + lblHead = new Label(); + btnReconnect = new Button(); + btnQuit = new Button(); + lblReason = new Label(); + SuspendLayout(); + // + // lblHead + // + lblHead.AutoSize = true; + lblHead.Font = new Font("Segoe UI", 11F, FontStyle.Bold); + lblHead.Location = new Point(12, 9); + lblHead.Name = "lblHead"; + lblHead.Size = new Size(444, 20); + lblHead.TabIndex = 0; + lblHead.Text = "Your Connection To The QtC.NET Server Was Lost. What Now?"; + // + // btnReconnect + // + btnReconnect.ForeColor = Color.Black; + btnReconnect.Location = new Point(12, 33); + btnReconnect.Name = "btnReconnect"; + btnReconnect.Size = new Size(75, 23); + btnReconnect.TabIndex = 1; + btnReconnect.Text = "Reconnect"; + btnReconnect.UseVisualStyleBackColor = true; + btnReconnect.Click += btnReconnect_Click; + // + // btnQuit + // + btnQuit.ForeColor = Color.Black; + btnQuit.Location = new Point(381, 32); + btnQuit.Name = "btnQuit"; + btnQuit.Size = new Size(75, 23); + btnQuit.TabIndex = 2; + btnQuit.Text = "Quit"; + btnQuit.UseVisualStyleBackColor = true; + btnQuit.Click += btnQuit_Click; + // + // lblReason + // + lblReason.AutoSize = true; + lblReason.Font = new Font("Segoe UI", 5F, FontStyle.Bold); + lblReason.Location = new Point(88, 40); + lblReason.Name = "lblReason"; + lblReason.Size = new Size(72, 10); + lblReason.TabIndex = 3; + lblReason.Text = "Reason: ${REASON}"; + // + // frmConnectionClosed + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(463, 65); + Controls.Add(lblReason); + Controls.Add(btnQuit); + Controls.Add(btnReconnect); + Controls.Add(lblHead); + Font = new Font("Segoe UI", 9F); + ForeColor = Color.White; + FormBorderStyle = FormBorderStyle.FixedDialog; + Margin = new Padding(4, 3, 4, 3); + MaximizeBox = false; + MinimizeBox = false; + Name = "frmConnectionClosed"; + StartPosition = FormStartPosition.CenterScreen; + Text = "QtC.NET Client - Connection Lost"; + Load += frmConnectionClosed_Load; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label lblHead; + private Button btnReconnect; + private Button btnQuit; + private Label lblReason; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/ConnectionClosed.cs b/qtc-net-client-2/Forms/ConnectionClosed.cs new file mode 100644 index 0000000..7b32e22 --- /dev/null +++ b/qtc-net-client-2/Forms/ConnectionClosed.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace qtc_net_client_2.Forms +{ + public partial class ConnectionClosed : Form + { + public string? Reason { get; set; } = string.Empty; + public ConnectionClosed(string? reason = "") + { + Reason = reason; + InitializeComponent(); + } + + private void frmConnectionClosed_Load(object sender, EventArgs e) + { + if (string.IsNullOrEmpty(Reason)) lblReason.Visible = false; + else lblReason.Text = $"Reason: {Reason}"; + } + + private void btnReconnect_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + Close(); + } + + private void btnQuit_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } + } +} diff --git a/qtc-net-client-2/Forms/ConnectionClosed.resx b/qtc-net-client-2/Forms/ConnectionClosed.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/qtc-net-client-2/Forms/ConnectionClosed.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/CreateRoom.Designer.cs b/qtc-net-client-2/Forms/CreateRoom.Designer.cs new file mode 100644 index 0000000..e5fef4a --- /dev/null +++ b/qtc-net-client-2/Forms/CreateRoom.Designer.cs @@ -0,0 +1,104 @@ +namespace qtc_net_client_2.Forms +{ + partial class CreateRoom + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CreateRoom)); + lblHeader = new Label(); + lblHeader2 = new Label(); + txtRoomName = new TextBox(); + btnCreate = new Button(); + SuspendLayout(); + // + // lblHeader + // + lblHeader.AutoSize = true; + lblHeader.Location = new Point(12, 9); + lblHeader.Name = "lblHeader"; + lblHeader.Size = new Size(273, 15); + lblHeader.TabIndex = 0; + lblHeader.Text = "Enter The Name Of The Room You Want To Create."; + // + // lblHeader2 + // + lblHeader2.AutoSize = true; + lblHeader2.Font = new Font("Segoe UI", 6F); + lblHeader2.Location = new Point(47, 24); + lblHeader2.Name = "lblHeader2"; + lblHeader2.Size = new Size(195, 11); + lblHeader2.TabIndex = 1; + lblHeader2.Text = "Tip: Make Rooms With Names That Describe Its Topic!"; + // + // txtRoomName + // + txtRoomName.Location = new Point(12, 41); + txtRoomName.Name = "txtRoomName"; + txtRoomName.Size = new Size(273, 23); + txtRoomName.TabIndex = 2; + // + // btnCreate + // + btnCreate.ForeColor = Color.Black; + btnCreate.Location = new Point(106, 70); + btnCreate.Name = "btnCreate"; + btnCreate.Size = new Size(75, 23); + btnCreate.TabIndex = 3; + btnCreate.Text = "Create"; + btnCreate.UseVisualStyleBackColor = true; + btnCreate.Click += btnCreate_Click; + // + // frmCreateRoom + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(298, 100); + Controls.Add(btnCreate); + Controls.Add(txtRoomName); + Controls.Add(lblHeader2); + Controls.Add(lblHeader); + ForeColor = Color.White; + FormBorderStyle = FormBorderStyle.FixedDialog; + Icon = (Icon)resources.GetObject("$this.Icon"); + MaximizeBox = false; + MinimizeBox = false; + Name = "frmCreateRoom"; + StartPosition = FormStartPosition.CenterParent; + Text = "Create Room"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label lblHeader; + private Label lblHeader2; + private TextBox txtRoomName; + private Button btnCreate; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/CreateRoom.cs b/qtc-net-client-2/Forms/CreateRoom.cs new file mode 100644 index 0000000..17cd4db --- /dev/null +++ b/qtc-net-client-2/Forms/CreateRoom.cs @@ -0,0 +1,37 @@ +using QtCNETAPI.Services.ApiService; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace qtc_net_client_2.Forms +{ + public partial class CreateRoom : Form + { + private IApiService _apiService; + public CreateRoom(IApiService apiService) + { + _apiService = apiService; + InitializeComponent(); + } + + private async void btnCreate_Click(object sender, EventArgs e) + { + if(!string.IsNullOrEmpty(txtRoomName.Text)) + { + await _apiService.CreateRoomAsync(new QtCNETAPI.Dtos.Room.RoomDto + { + Name = txtRoomName.Text, + CreatedAt = DateTime.UtcNow, + }); + DialogResult = DialogResult.OK; + Close(); + } + } + } +} diff --git a/qtc-net-client-2/Forms/CreateRoom.resx b/qtc-net-client-2/Forms/CreateRoom.resx new file mode 100644 index 0000000..db6c178 --- /dev/null +++ b/qtc-net-client-2/Forms/CreateRoom.resx @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAABMLAAATCwAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAO24wAMtuMAFjbjABy24wAetuMAHHbjABW24wAL9uMAAzbjAAA24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAf24wAdNuMAMTbjADu24wA/duMAP/bjAD/24wA/9uMAPzbjADs24wAv9uM + AG3bjAAa24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAJ24wAYduMANXbjAD+24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/duMAM7bjABY24wABtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAA24wAEtuMAJPbjAD324wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPTbjACH24wADtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMABDbjACf24wA/duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPzbjACT24wAC9uMAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAE24wAh9uMAP3bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPrbjAB524wAAtuM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAE3bjADw24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AOrbjABA24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAQ24wAvduMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAK/bjAAK24wAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAFHbjAD324wA/9uM + AP/bjAD/24wA/9uLAP/biwD/24wA/9uMAP/bjAD/24wA/9uMAP/biwD/24wA/9uMAP/bjAD/24sA/9uL + AP/bjAD/24wA/9uMAP/bjAD/24wA8tuMAEPbjAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAC24wAntuM + AP/bjAD/24wA/9uLAP/ckQz/4Jwj/9+YG//bjQP/3JEM/9yPB//biwD/3ZIN/96YGv/bjQP/24wA/9uM + Af/elRX/4Jwk/92TD//biwD/24wA/9uMAP/bjAD/24wAj9uMAADbjAAAAAAAAAAAAAAAAAAA24wAANuM + ABbbjADU24wA/9uMAP/biwD/4qM1//Tet//57dj/+OnR/+/Ok//y16f/5atG/92TD//y2Kr/9N63/96V + FP/bjAL/6Lhi//fnzf/47Nf/9uPB/+WrR//biwD/24wA/9uMAP/bjADH24wAD9uMAAAAAAAAAAAAAAAA + AADbjAAA24wAMtuMAO7bjAD/24wA/92TD//14b3/89mt/+SoP//w0Jj///////Parv/dkg3/4qIy//rw + 3v/msFH/24wA/+OlOf/68N//7MJ5/+KkNf/uy47/+OrS/+CcJP/biwD/24wA/9uMAObbjAAm24wAAAAA + AAAAAAAAAAAAANuMAADbjABI24wA+duMAP/biwD/4qIy//nv3f/iozX/3pUX//LWpv/25cj/8tis/9uM + AP/ipDb/+ezY/+CcJ//aiQD/68F3//bjwv/ckAz/24oA/92RD//puWX/4Jwl/9uLAP/bjAD/24wA89uM + ADrbjAAAAAAAAAAAAAAAAAAA24wAANuMAFHbjAD824wA/9uKAP/jpzz/+e7b/+CdJ//bjAH/3ZMQ/+zD + fP/137v/240D/+KkNv/57Nj/4J0n/9qJAP/tx4X/89yz/9uNBP/bjAD/24wA/9qKAP/biwD/24wA/9uM + AP/bjAD324wAQtuMAAAAAAAAAAAAAAAAAADbjAAA24wATNuMAPrbjAD/24oA/+OnPP/57tv/4J0n/9uL + AP/aigD/7MJ6//Xfu//cjgX/5axI//rv3v/kqED/24sA/+3Hhf/z3LL/244E/9uMAP/bjAD/24sA/9uM + AP/bjAD/24wA/9uMAPXbjAA924wAAAAAAAAAAAAAAAAAANuMAADbjAA524wA8tuMAP/bigD/46Y6//nu + 2//gnin/24sA/9qKAP/sw37/9N+4/9yRC//x0p7//v37//Tdtv/dkxD/7cWB//Tdtv/cjgX/24wA/9uM + Av/elRb/3JAK/9uMAP/bjAD/24wA69uMACzbjAAAAAAAAAAAAAAAAAAA24wAANuMAB7bjADd24wA/9uL + AP/gmyL/+e3Z/+i4Yv/bjAD/3ZMP//TdtP/w0Jj/24sA/+WuS//68eD/5KpD/9uLAP/otl3/+e3Y/+Gf + Kv/biwD/46c8//XiwP/iozT/24sA/9uMAP/bjADS24wAFduMAAAAAAAAAAAAAAAAAADbjAAA24wABtuM + AK/bjAD/24wA/9uNAv/sxH3/+vDg//LZq//14sH/+OvU/+KkNv/aigD/4Z4p//HUov/fmB3/24oA/96V + Fv/03bX/+OnQ//LWpv/57dn/8NGa/9yQCv/bjAD/24wA/9uMAKDbjAAC24wAAAAAAAAAAAAAAAAAANuM + AADbjAAA24wAZtuMAP3bjAD/24wA/9yPCf/mr0//7cmI/+zCef/hoCz/24wA/9uMAP/bjQL/3I8I/9uN + Af/bjAD/24sA/96XGf/pu2r/7sqK/+i1XP/dkg//24sA/9uMAP/bjAD624wAVtuMAADbjAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAc24wA09uMAP/bjAD/24wA/9qKAP/biwD/2ooA/9uLAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24sA/9qKAP/biwD/2ooA/9uMAP/bjAD/24wA/9uMAMfbjAAU24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjABr24wA+9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD324wAXNuM + AADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAA7bjACr24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AJ7bjAAJ24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMACTbjADG24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAC724wAHduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuM + ACvbjADA24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD+24wAtduMACPbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADbjAAA24wAANuMABzbjACV24wA8duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA7tuMAIvbjAAW24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAAbbjABG24wAqtuMAOnbjAD+24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD924wA59uMAKTbjAA/24wABNuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjAAH24wALtuMAGXbjACS24wAq9uM + ALPbjACq24wAj9uMAGHbjAAq24wABduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuM + AADbjAAD24wABduMAALbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA//////////////////AH///AAf//AAB//gAAP/wAAB/4AAAP+AAAD/AA + AAfwAAAH4AAAB+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD8AAAB/AAAAf4AAAP+AAAD/wA + AB/+AAA//wAAf/+AAP//4AP///4///////8= + + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/DirectMessage.Designer.cs b/qtc-net-client-2/Forms/DirectMessage.Designer.cs new file mode 100644 index 0000000..bb3626a --- /dev/null +++ b/qtc-net-client-2/Forms/DirectMessage.Designer.cs @@ -0,0 +1,113 @@ +namespace qtc_net_client_2.Forms +{ + partial class DirectMessage + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DirectMessage)); + rtxtChat = new RichTextBox(); + btnSend = new Button(); + rtxtChatbox = new RichTextBox(); + lblUsername = new Label(); + SuspendLayout(); + // + // rtxtChat + // + rtxtChat.Location = new Point(12, 56); + rtxtChat.Margin = new Padding(4, 3, 4, 3); + rtxtChat.Name = "rtxtChat"; + rtxtChat.ReadOnly = true; + rtxtChat.Size = new Size(593, 317); + rtxtChat.TabIndex = 6; + rtxtChat.Text = ""; + // + // btnSend + // + btnSend.FlatAppearance.BorderSize = 0; + btnSend.FlatStyle = FlatStyle.Flat; + btnSend.ForeColor = Color.Black; + btnSend.Image = Properties.Resources.SendIcon; + btnSend.Location = new Point(530, 379); + btnSend.Margin = new Padding(4, 3, 4, 3); + btnSend.Name = "btnSend"; + btnSend.Size = new Size(75, 54); + btnSend.TabIndex = 5; + btnSend.UseVisualStyleBackColor = true; + btnSend.Click += btnSend_Click; + // + // rtxtChatbox + // + rtxtChatbox.Location = new Point(12, 379); + rtxtChatbox.Margin = new Padding(4, 3, 4, 3); + rtxtChatbox.Name = "rtxtChatbox"; + rtxtChatbox.Size = new Size(511, 54); + rtxtChatbox.TabIndex = 4; + rtxtChatbox.Text = ""; + // + // lblUsername + // + lblUsername.AutoSize = true; + lblUsername.Font = new Font("Segoe UI", 25F, FontStyle.Bold | FontStyle.Italic); + lblUsername.Location = new Point(6, 7); + lblUsername.Margin = new Padding(4, 0, 4, 0); + lblUsername.Name = "lblUsername"; + lblUsername.Size = new Size(181, 46); + lblUsername.TabIndex = 7; + lblUsername.Text = "Username"; + // + // frmDirectMessage + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(618, 450); + Controls.Add(lblUsername); + Controls.Add(rtxtChat); + Controls.Add(btnSend); + Controls.Add(rtxtChatbox); + Font = new Font("Segoe UI", 9F); + ForeColor = Color.White; + FormBorderStyle = FormBorderStyle.FixedSingle; + Icon = (Icon)resources.GetObject("$this.Icon"); + Margin = new Padding(4, 3, 4, 3); + MaximizeBox = false; + Name = "frmDirectMessage"; + StartPosition = FormStartPosition.CenterScreen; + Text = "QtC.NET Client - Direct Message With ${USER}"; + Load += frmDirectMessage_Load; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private RichTextBox rtxtChat; + private Button btnSend; + private RichTextBox rtxtChatbox; + private Label lblUsername; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/DirectMessage.cs b/qtc-net-client-2/Forms/DirectMessage.cs new file mode 100644 index 0000000..61cca20 --- /dev/null +++ b/qtc-net-client-2/Forms/DirectMessage.cs @@ -0,0 +1,99 @@ +using Microsoft.AspNetCore.Mvc.ModelBinding; +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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace qtc_net_client_2.Forms +{ + public partial class DirectMessage : Form + { + private IGatewayService _gatewayService; + private IApiService _apiService; + private QtCNETAPI.Models.Message? InitMessage; + private AudioService AudioService = new(); + public UserInformationDto User { get; set; } + public ObservableCollection Messages { get; set; } + public DirectMessage(IGatewayService gatewayService, IApiService apiService, UserInformationDto user, QtCNETAPI.Models.Message? initMsg = null) + { + _gatewayService = gatewayService; + _apiService = apiService; + User = user; + Messages = new ObservableCollection(); + InitMessage = initMsg; + InitializeComponent(); + } + + private void frmDirectMessage_Load(object sender, EventArgs e) + { + lblUsername.Text = User.Username; + Text = $"QtC.NET Client - Direct Message With {User.Username}"; + Messages.CollectionChanged += Messages_CollectionChanged; + + if (InitMessage != null) + { + Messages.Add($"[{User.Username}] {InitMessage.Content}\n"); + AudioService.PlaySoundEffect("sndDirectMsg"); + } + } + + private async void btnSend_Click(object sender, EventArgs e) + { + if(InvokeRequired) + { + await Invoke(async delegate () + { + if (!string.IsNullOrEmpty(rtxtChatbox.Text)) + { + await _gatewayService.SendDirectMessageAsync(User, new QtCNETAPI.Models.Message { Content = rtxtChatbox.Text, AuthorId = _apiService.CurrentUser.Id }); + Messages.Add($"[{_apiService.CurrentUser.Username}] {rtxtChatbox.Text}\n"); + rtxtChatbox.Clear(); + AudioService.PlaySoundEffect("sndSendClick"); + } + }); + } + else + { + if (!string.IsNullOrEmpty(rtxtChatbox.Text)) + { + await _gatewayService.SendDirectMessageAsync(User, new QtCNETAPI.Models.Message { Content = rtxtChatbox.Text, AuthorId = _apiService.CurrentUser.Id }); + Messages.Add($"[{_apiService.CurrentUser.Username}] {rtxtChatbox.Text}\n"); + rtxtChatbox.Clear(); + AudioService.PlaySoundEffect("sndSendClick"); + } + } + } + + private void Messages_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if(e.NewItems != null) + { + if (InvokeRequired) + { + Invoke(delegate () + { + rtxtChat.Text += e.NewItems.Cast().FirstOrDefault(); + AudioService.PlaySoundEffect("sndMessage"); + }); + } + else + { + rtxtChat.Text += e.NewItems.Cast().FirstOrDefault(); + AudioService.PlaySoundEffect("sndMessage"); + } + } + } + } +} diff --git a/qtc-net-client-2/Forms/DirectMessage.resx b/qtc-net-client-2/Forms/DirectMessage.resx new file mode 100644 index 0000000..b5414cd --- /dev/null +++ b/qtc-net-client-2/Forms/DirectMessage.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAEA8AAAEACABDBQAAFgAAACgAAAAQAAAAHgAAAAEACAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA9dN/APXTgAD00XoA9M5wAPPLZwDzyF8A8sZZAPLEVADywk4A8L9FAPC8PAD104AA9dF6APTL + aQD0z3UA9dSDAPC9PwDvtisA7rIeAPTOcgD0zW8A8sRVAPC7OgDsqgkA4J8AAPPJYwDxwUkA4KIMAM2S + AADxwUoAtYEAAO+3LQCbbgAA7K0PAOuoBACneQYAfloAANubAADYmQAAgVsAAGRHAADMkQAAuIMAALqF + AAB2VAAAWT8AAF5CAACpeAAAmm4AAJhsAACfcQAAfFgAAG9VFgCjlncAxr6sAI9mAACCXQAAfVkAAHdU + AABxUAAAa0wAAGRHAABcQgAAVTwAAN3a0QDt7e0A3t7eAOnp6QDi4uIA+fn5APPz8wD09PQA4uLiAM7O + zgD///8A/Pz8APPz8wDc3NwA+OOtAPzy2QD9+e4A/fblAPrpwAD22I8A6+fcAN3d3QDZ2dkA19fXAL6+ + vgD+/foA+uvEAPTMawD++/QAoqKiAF9fXwBdXV0AW1tbAFRUVAD///8A+vr6AOPPnADusyIA+eSyAP7+ + /gDk5OQA4uLiAN7e3gDo6OgA4+PjALOvpQDLmR4A7awPAPnmuAD9/f0A9/f3AEFBQQA9PT0ANTU1AIiI + iAC9vb0Afnx1ALWHFgDrxGUA39/dAKurqwCjo6MAlpaWAHl5eQDExMQAdHR0AGhbOgDgogkAw6dkAGlp + aABGRkYATExMAEVFRQA6OjoAXFxcAFRMOACgdg0AzJIDALuQJQCJdkgAaGFSAFZVUwBTUEgAXFI2AH9k + IgChdAUAq3oDAKx8BQCoegYAoXQGAJJpAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABNTgAAAAAAAAAAAAAAAAAAS0wAAAAAAAAAAAAAAABISUoAAAAAAAAA + AAAAAABERUZHAAAAODk6Ozw9Pj9AQUJDAAAAMDEyM5eYmZqbNDU2NwAAKissjo+QkZKTlJWWLS4vACYn + hIWGh4iIiYqLjI0oKQAiI3t8WX1+Xn+AgYKDJCUAIHBxcnN0dXV1dnd4eXohAB5mZ2NoaWpqamtsbW5v + HwAaG1xdXl9gYGFiY2RlHB0AFBUWVFVWV1dYWVpbFxgZAAAMDQ4PT1BRUlMQERITAAAAAAECAwQFBgcI + CQoLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/Login.Designer.cs b/qtc-net-client-2/Forms/Login.Designer.cs new file mode 100644 index 0000000..f352484 --- /dev/null +++ b/qtc-net-client-2/Forms/Login.Designer.cs @@ -0,0 +1,162 @@ +namespace qtc_net_client_2.Forms +{ + partial class Login + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Login)); + pbLoginBanner = new PictureBox(); + tbEmail = new TextBox(); + lblEmail = new Label(); + label1 = new Label(); + tbPassword = new TextBox(); + btnLogin = new Button(); + llblRegister = new LinkLabel(); + cbRememberMe = new CheckBox(); + ((System.ComponentModel.ISupportInitialize)pbLoginBanner).BeginInit(); + SuspendLayout(); + // + // pbLoginBanner + // + pbLoginBanner.Image = Properties.Resources.LoginBanner; + pbLoginBanner.Location = new Point(-4, 0); + pbLoginBanner.Name = "pbLoginBanner"; + pbLoginBanner.Size = new Size(521, 99); + pbLoginBanner.SizeMode = PictureBoxSizeMode.StretchImage; + pbLoginBanner.TabIndex = 0; + pbLoginBanner.TabStop = false; + // + // tbEmail + // + tbEmail.Location = new Point(71, 106); + tbEmail.Name = "tbEmail"; + tbEmail.Size = new Size(424, 23); + tbEmail.TabIndex = 1; + // + // lblEmail + // + lblEmail.AutoSize = true; + lblEmail.Font = new Font("Segoe UI Light", 9F); + lblEmail.ForeColor = SystemColors.ControlLight; + lblEmail.Location = new Point(32, 109); + lblEmail.Name = "lblEmail"; + lblEmail.Size = new Size(33, 15); + lblEmail.TabIndex = 2; + lblEmail.Text = "Email"; + // + // label1 + // + label1.AutoSize = true; + label1.Font = new Font("Segoe UI Light", 9F); + label1.ForeColor = SystemColors.ControlLight; + label1.Location = new Point(11, 138); + label1.Name = "label1"; + label1.Size = new Size(55, 15); + label1.TabIndex = 4; + label1.Text = "Password"; + // + // tbPassword + // + tbPassword.Location = new Point(71, 135); + tbPassword.Name = "tbPassword"; + tbPassword.PasswordChar = '*'; + tbPassword.Size = new Size(424, 23); + tbPassword.TabIndex = 3; + // + // btnLogin + // + btnLogin.Location = new Point(71, 164); + btnLogin.Name = "btnLogin"; + btnLogin.Size = new Size(75, 23); + btnLogin.TabIndex = 5; + btnLogin.Text = "Login"; + btnLogin.UseVisualStyleBackColor = true; + btnLogin.Click += btnLogin_Click; + // + // llblRegister + // + llblRegister.AutoSize = true; + llblRegister.Font = new Font("Segoe UI Light", 9F); + llblRegister.LinkColor = SystemColors.ControlLight; + llblRegister.Location = new Point(148, 168); + llblRegister.Name = "llblRegister"; + llblRegister.Size = new Size(48, 15); + llblRegister.TabIndex = 6; + llblRegister.TabStop = true; + llblRegister.Text = "Register"; + llblRegister.LinkClicked += llblRegister_LinkClicked; + // + // cbRememberMe + // + cbRememberMe.AutoSize = true; + cbRememberMe.Font = new Font("Segoe UI Light", 9F); + cbRememberMe.ForeColor = SystemColors.ControlLight; + cbRememberMe.Location = new Point(198, 168); + cbRememberMe.Name = "cbRememberMe"; + cbRememberMe.Size = new Size(157, 19); + cbRememberMe.TabIndex = 7; + cbRememberMe.Text = "Remember Me For 7 Days"; + cbRememberMe.UseVisualStyleBackColor = true; + // + // frmLogin + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(515, 203); + Controls.Add(cbRememberMe); + Controls.Add(llblRegister); + Controls.Add(btnLogin); + Controls.Add(label1); + Controls.Add(tbPassword); + Controls.Add(lblEmail); + Controls.Add(tbEmail); + Controls.Add(pbLoginBanner); + FormBorderStyle = FormBorderStyle.FixedDialog; + Icon = (Icon)resources.GetObject("$this.Icon"); + MaximizeBox = false; + Name = "frmLogin"; + StartPosition = FormStartPosition.CenterParent; + Text = "QtC.NET Client - Login"; + Load += frmLogin_Load; + ((System.ComponentModel.ISupportInitialize)pbLoginBanner).EndInit(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private PictureBox pbLoginBanner; + private TextBox tbEmail; + private Label lblEmail; + private Label label1; + private TextBox tbPassword; + private Button btnLogin; + private LinkLabel llblRegister; + private CheckBox cbRememberMe; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/Login.cs b/qtc-net-client-2/Forms/Login.cs new file mode 100644 index 0000000..39320a7 --- /dev/null +++ b/qtc-net-client-2/Forms/Login.cs @@ -0,0 +1,91 @@ +using QtCNETAPI.Services.ApiService; +using QtCNETAPI.Dtos.User; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace qtc_net_client_2.Forms +{ + public partial class Login : Form + { + private IApiService _apiService; + public Login(IApiService apiService) + { + _apiService = apiService; + + InitializeComponent(); + } + + private async void frmLogin_Load(object sender, EventArgs e) + { + if (File.Exists("./session.token")) + { + ToggleControls(false, false); + + // try logging in with the token in the file + string token = File.ReadAllText("./session.token"); + + var result = await _apiService.RefreshLogin(token); + if (result.Success) + { + DialogResult = DialogResult.OK; + Close(); + } + else + ToggleControls(true, false); + } + } + + private async void btnLogin_Click(object sender, EventArgs e) + { + if (!string.IsNullOrEmpty(tbEmail.Text) && !string.IsNullOrEmpty(tbPassword.Text)) + { + ToggleControls(false, false); + + var result = await _apiService.LoginAsync(new UserLoginDto + { + Email = tbEmail.Text, + Password = tbPassword.Text, + RememberMe = cbRememberMe.Checked + }); + + if (result.Success) + { + DialogResult = DialogResult.OK; + Close(); + } + else + { + ToggleControls(true, true); + MessageBox.Show(result.Message, "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + + private void ToggleControls(bool enable, bool clearText) + { + tbEmail.Enabled = enable; + tbPassword.Enabled = enable; + btnLogin.Enabled = enable; + llblRegister.Enabled = enable; + + if (clearText) + { + tbEmail.Text = string.Empty; + tbPassword.Text = string.Empty; + } + } + + private void llblRegister_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Register frmRegister = new Register(_apiService); + frmRegister.ShowDialog(); + } + } +} diff --git a/qtc-net-client-2/Forms/Login.resx b/qtc-net-client-2/Forms/Login.resx new file mode 100644 index 0000000..db6c178 --- /dev/null +++ b/qtc-net-client-2/Forms/Login.resx @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAABMLAAATCwAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAO24wAMtuMAFjbjABy24wAetuMAHHbjABW24wAL9uMAAzbjAAA24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAf24wAdNuMAMTbjADu24wA/duMAP/bjAD/24wA/9uMAPzbjADs24wAv9uM + AG3bjAAa24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAJ24wAYduMANXbjAD+24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/duMAM7bjABY24wABtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAA24wAEtuMAJPbjAD324wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPTbjACH24wADtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMABDbjACf24wA/duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPzbjACT24wAC9uMAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAE24wAh9uMAP3bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPrbjAB524wAAtuM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAE3bjADw24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AOrbjABA24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAQ24wAvduMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAK/bjAAK24wAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAFHbjAD324wA/9uM + AP/bjAD/24wA/9uLAP/biwD/24wA/9uMAP/bjAD/24wA/9uMAP/biwD/24wA/9uMAP/bjAD/24sA/9uL + AP/bjAD/24wA/9uMAP/bjAD/24wA8tuMAEPbjAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAC24wAntuM + AP/bjAD/24wA/9uLAP/ckQz/4Jwj/9+YG//bjQP/3JEM/9yPB//biwD/3ZIN/96YGv/bjQP/24wA/9uM + Af/elRX/4Jwk/92TD//biwD/24wA/9uMAP/bjAD/24wAj9uMAADbjAAAAAAAAAAAAAAAAAAA24wAANuM + ABbbjADU24wA/9uMAP/biwD/4qM1//Tet//57dj/+OnR/+/Ok//y16f/5atG/92TD//y2Kr/9N63/96V + FP/bjAL/6Lhi//fnzf/47Nf/9uPB/+WrR//biwD/24wA/9uMAP/bjADH24wAD9uMAAAAAAAAAAAAAAAA + AADbjAAA24wAMtuMAO7bjAD/24wA/92TD//14b3/89mt/+SoP//w0Jj///////Parv/dkg3/4qIy//rw + 3v/msFH/24wA/+OlOf/68N//7MJ5/+KkNf/uy47/+OrS/+CcJP/biwD/24wA/9uMAObbjAAm24wAAAAA + AAAAAAAAAAAAANuMAADbjABI24wA+duMAP/biwD/4qIy//nv3f/iozX/3pUX//LWpv/25cj/8tis/9uM + AP/ipDb/+ezY/+CcJ//aiQD/68F3//bjwv/ckAz/24oA/92RD//puWX/4Jwl/9uLAP/bjAD/24wA89uM + ADrbjAAAAAAAAAAAAAAAAAAA24wAANuMAFHbjAD824wA/9uKAP/jpzz/+e7b/+CdJ//bjAH/3ZMQ/+zD + fP/137v/240D/+KkNv/57Nj/4J0n/9qJAP/tx4X/89yz/9uNBP/bjAD/24wA/9qKAP/biwD/24wA/9uM + AP/bjAD324wAQtuMAAAAAAAAAAAAAAAAAADbjAAA24wATNuMAPrbjAD/24oA/+OnPP/57tv/4J0n/9uL + AP/aigD/7MJ6//Xfu//cjgX/5axI//rv3v/kqED/24sA/+3Hhf/z3LL/244E/9uMAP/bjAD/24sA/9uM + AP/bjAD/24wA/9uMAPXbjAA924wAAAAAAAAAAAAAAAAAANuMAADbjAA524wA8tuMAP/bigD/46Y6//nu + 2//gnin/24sA/9qKAP/sw37/9N+4/9yRC//x0p7//v37//Tdtv/dkxD/7cWB//Tdtv/cjgX/24wA/9uM + Av/elRb/3JAK/9uMAP/bjAD/24wA69uMACzbjAAAAAAAAAAAAAAAAAAA24wAANuMAB7bjADd24wA/9uL + AP/gmyL/+e3Z/+i4Yv/bjAD/3ZMP//TdtP/w0Jj/24sA/+WuS//68eD/5KpD/9uLAP/otl3/+e3Y/+Gf + Kv/biwD/46c8//XiwP/iozT/24sA/9uMAP/bjADS24wAFduMAAAAAAAAAAAAAAAAAADbjAAA24wABtuM + AK/bjAD/24wA/9uNAv/sxH3/+vDg//LZq//14sH/+OvU/+KkNv/aigD/4Z4p//HUov/fmB3/24oA/96V + Fv/03bX/+OnQ//LWpv/57dn/8NGa/9yQCv/bjAD/24wA/9uMAKDbjAAC24wAAAAAAAAAAAAAAAAAANuM + AADbjAAA24wAZtuMAP3bjAD/24wA/9yPCf/mr0//7cmI/+zCef/hoCz/24wA/9uMAP/bjQL/3I8I/9uN + Af/bjAD/24sA/96XGf/pu2r/7sqK/+i1XP/dkg//24sA/9uMAP/bjAD624wAVtuMAADbjAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAc24wA09uMAP/bjAD/24wA/9qKAP/biwD/2ooA/9uLAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24sA/9qKAP/biwD/2ooA/9uMAP/bjAD/24wA/9uMAMfbjAAU24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjABr24wA+9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD324wAXNuM + AADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAA7bjACr24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AJ7bjAAJ24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMACTbjADG24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAC724wAHduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuM + ACvbjADA24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD+24wAtduMACPbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADbjAAA24wAANuMABzbjACV24wA8duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA7tuMAIvbjAAW24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAAbbjABG24wAqtuMAOnbjAD+24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD924wA59uMAKTbjAA/24wABNuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjAAH24wALtuMAGXbjACS24wAq9uM + ALPbjACq24wAj9uMAGHbjAAq24wABduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuM + AADbjAAD24wABduMAALbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA//////////////////AH///AAf//AAB//gAAP/wAAB/4AAAP+AAAD/AA + AAfwAAAH4AAAB+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD8AAAB/AAAAf4AAAP+AAAD/wA + AB/+AAA//wAAf/+AAP//4AP///4///////8= + + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/Main.Designer.cs b/qtc-net-client-2/Forms/Main.Designer.cs new file mode 100644 index 0000000..df97dbf --- /dev/null +++ b/qtc-net-client-2/Forms/Main.Designer.cs @@ -0,0 +1,393 @@ +namespace qtc_net_client_2 +{ + partial class Main + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Main)); + tbcMain = new TabControl(); + tbpContacts = new TabPage(); + lvContacts = new ListView(); + ilProfilePics = new ImageList(components); + tbpRooms = new TabPage(); + lbRooms = new ListBox(); + tbpOnlineUsers = new TabPage(); + lbOnlineUsers = new ListBox(); + ilTabIcons = new ImageList(components); + pbUserPfp = new PictureBox(); + ctxmChangeStatus = new ContextMenuStrip(components); + onlineToolStripMenuItem = new ToolStripMenuItem(); + awayToolStripMenuItem = new ToolStripMenuItem(); + doNotDisturbToolStripMenuItem = new ToolStripMenuItem(); + invisibleToolStripMenuItem = new ToolStripMenuItem(); + lblWelcome = new Label(); + llblSignIn = new LinkLabel(); + llblSignOut = new LinkLabel(); + llblEditProfile = new LinkLabel(); + lblRequestNotif = new Label(); + niMain = new NotifyIcon(components); + btnAddRoom = new Button(); + pbCurrencyIcon = new PictureBox(); + lblCurrencyAmount = new Label(); + llblClaimSpin = new LinkLabel(); + tbcMain.SuspendLayout(); + tbpContacts.SuspendLayout(); + tbpRooms.SuspendLayout(); + tbpOnlineUsers.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)pbUserPfp).BeginInit(); + ctxmChangeStatus.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)pbCurrencyIcon).BeginInit(); + SuspendLayout(); + // + // tbcMain + // + tbcMain.Controls.Add(tbpContacts); + tbcMain.Controls.Add(tbpRooms); + tbcMain.Controls.Add(tbpOnlineUsers); + tbcMain.Enabled = false; + tbcMain.ImageList = ilTabIcons; + tbcMain.Location = new Point(12, 66); + tbcMain.Name = "tbcMain"; + tbcMain.SelectedIndex = 0; + tbcMain.Size = new Size(258, 535); + tbcMain.TabIndex = 0; + // + // tbpContacts + // + tbpContacts.Controls.Add(lvContacts); + tbpContacts.ImageKey = "ContactsIcon.png"; + tbpContacts.Location = new Point(4, 24); + tbpContacts.Name = "tbpContacts"; + tbpContacts.Padding = new Padding(3); + tbpContacts.Size = new Size(250, 507); + tbpContacts.TabIndex = 0; + tbpContacts.Text = "Contacts"; + tbpContacts.UseVisualStyleBackColor = true; + // + // lvContacts + // + lvContacts.LargeImageList = ilProfilePics; + lvContacts.Location = new Point(0, 0); + lvContacts.Name = "lvContacts"; + lvContacts.Size = new Size(250, 507); + lvContacts.SmallImageList = ilProfilePics; + lvContacts.TabIndex = 1; + lvContacts.UseCompatibleStateImageBehavior = false; + lvContacts.View = View.List; + lvContacts.DoubleClick += lvContacts_DoubleClick; + // + // ilProfilePics + // + ilProfilePics.ColorDepth = ColorDepth.Depth32Bit; + ilProfilePics.ImageSize = new Size(16, 16); + ilProfilePics.TransparentColor = Color.Transparent; + // + // tbpRooms + // + tbpRooms.Controls.Add(lbRooms); + tbpRooms.ImageKey = "RoomsChatIcon.png"; + tbpRooms.Location = new Point(4, 24); + tbpRooms.Name = "tbpRooms"; + tbpRooms.Padding = new Padding(3); + tbpRooms.Size = new Size(250, 507); + tbpRooms.TabIndex = 1; + tbpRooms.Text = "Rooms"; + tbpRooms.UseVisualStyleBackColor = true; + // + // lbRooms + // + lbRooms.FormattingEnabled = true; + lbRooms.ItemHeight = 15; + lbRooms.Location = new Point(0, 0); + lbRooms.Name = "lbRooms"; + lbRooms.Size = new Size(250, 514); + lbRooms.TabIndex = 0; + lbRooms.DoubleClick += lbRooms_DoubleClick; + // + // tbpOnlineUsers + // + tbpOnlineUsers.Controls.Add(lbOnlineUsers); + tbpOnlineUsers.ImageIndex = 0; + tbpOnlineUsers.Location = new Point(4, 24); + tbpOnlineUsers.Name = "tbpOnlineUsers"; + tbpOnlineUsers.Padding = new Padding(3); + tbpOnlineUsers.Size = new Size(250, 507); + tbpOnlineUsers.TabIndex = 2; + tbpOnlineUsers.Text = "Online Users"; + tbpOnlineUsers.UseVisualStyleBackColor = true; + // + // lbOnlineUsers + // + lbOnlineUsers.FormattingEnabled = true; + lbOnlineUsers.ItemHeight = 15; + lbOnlineUsers.Location = new Point(0, 0); + lbOnlineUsers.Name = "lbOnlineUsers"; + lbOnlineUsers.Size = new Size(250, 514); + lbOnlineUsers.TabIndex = 0; + lbOnlineUsers.DoubleClick += lbOnlineUsers_DoubleClick; + // + // ilTabIcons + // + ilTabIcons.ColorDepth = ColorDepth.Depth32Bit; + ilTabIcons.ImageStream = (ImageListStreamer)resources.GetObject("ilTabIcons.ImageStream"); + ilTabIcons.TransparentColor = Color.Transparent; + ilTabIcons.Images.SetKeyName(0, "ContactsIcon.png"); + ilTabIcons.Images.SetKeyName(1, "RoomsChatIcon.png"); + // + // pbUserPfp + // + pbUserPfp.BorderStyle = BorderStyle.FixedSingle; + pbUserPfp.ContextMenuStrip = ctxmChangeStatus; + pbUserPfp.Image = Properties.Resources.DefaultPfp; + pbUserPfp.Location = new Point(12, 10); + pbUserPfp.Name = "pbUserPfp"; + pbUserPfp.Size = new Size(51, 50); + pbUserPfp.SizeMode = PictureBoxSizeMode.StretchImage; + pbUserPfp.TabIndex = 1; + pbUserPfp.TabStop = false; + pbUserPfp.Click += pbUserPfp_Click; + // + // ctxmChangeStatus + // + ctxmChangeStatus.Items.AddRange(new ToolStripItem[] { onlineToolStripMenuItem, awayToolStripMenuItem, doNotDisturbToolStripMenuItem, invisibleToolStripMenuItem }); + ctxmChangeStatus.Name = "ctxmChangeStatus"; + ctxmChangeStatus.Size = new Size(154, 92); + ctxmChangeStatus.ItemClicked += ctxmChangeStatus_ItemClicked; + // + // onlineToolStripMenuItem + // + onlineToolStripMenuItem.Image = Properties.Resources.OnlineIcon; + onlineToolStripMenuItem.Name = "onlineToolStripMenuItem"; + onlineToolStripMenuItem.Size = new Size(153, 22); + onlineToolStripMenuItem.Text = "Online"; + // + // awayToolStripMenuItem + // + awayToolStripMenuItem.Image = Properties.Resources.AwayIcon; + awayToolStripMenuItem.Name = "awayToolStripMenuItem"; + awayToolStripMenuItem.Size = new Size(153, 22); + awayToolStripMenuItem.Text = "Away"; + // + // doNotDisturbToolStripMenuItem + // + doNotDisturbToolStripMenuItem.Image = Properties.Resources.DNDIcon; + doNotDisturbToolStripMenuItem.Name = "doNotDisturbToolStripMenuItem"; + doNotDisturbToolStripMenuItem.Size = new Size(153, 22); + doNotDisturbToolStripMenuItem.Text = "Do Not Disturb"; + // + // invisibleToolStripMenuItem + // + invisibleToolStripMenuItem.Image = Properties.Resources.OfflineIcon; + invisibleToolStripMenuItem.Name = "invisibleToolStripMenuItem"; + invisibleToolStripMenuItem.Size = new Size(153, 22); + invisibleToolStripMenuItem.Text = "Invisible"; + // + // lblWelcome + // + lblWelcome.AutoSize = true; + lblWelcome.Font = new Font("Segoe UI Light", 9F); + lblWelcome.ForeColor = SystemColors.ControlLightLight; + lblWelcome.Location = new Point(65, 17); + lblWelcome.Name = "lblWelcome"; + lblWelcome.Size = new Size(60, 15); + lblWelcome.TabIndex = 2; + lblWelcome.Text = "Welcome, "; + // + // llblSignIn + // + llblSignIn.AutoSize = true; + llblSignIn.Font = new Font("Segoe UI Light", 9F); + llblSignIn.LinkColor = Color.White; + llblSignIn.Location = new Point(118, 17); + llblSignIn.Name = "llblSignIn"; + llblSignIn.Size = new Size(40, 15); + llblSignIn.TabIndex = 3; + llblSignIn.TabStop = true; + llblSignIn.Text = "Sign In"; + llblSignIn.LinkClicked += llblSignIn_LinkClicked; + // + // llblSignOut + // + llblSignOut.AutoSize = true; + llblSignOut.Font = new Font("Segoe UI Light", 9F); + llblSignOut.LinkColor = Color.White; + llblSignOut.Location = new Point(65, 35); + llblSignOut.Name = "llblSignOut"; + llblSignOut.Size = new Size(50, 15); + llblSignOut.TabIndex = 4; + llblSignOut.TabStop = true; + llblSignOut.Text = "Sign Out"; + llblSignOut.Visible = false; + llblSignOut.LinkClicked += llblSignOut_LinkClicked; + // + // llblEditProfile + // + llblEditProfile.AutoSize = true; + llblEditProfile.Font = new Font("Segoe UI Light", 9F); + llblEditProfile.LinkColor = Color.White; + llblEditProfile.Location = new Point(113, 35); + llblEditProfile.Name = "llblEditProfile"; + llblEditProfile.Size = new Size(60, 15); + llblEditProfile.TabIndex = 5; + llblEditProfile.TabStop = true; + llblEditProfile.Text = "Edit Profile"; + llblEditProfile.Visible = false; + llblEditProfile.LinkClicked += llblEditProfile_LinkClicked; + // + // lblRequestNotif + // + lblRequestNotif.AutoSize = true; + lblRequestNotif.Font = new Font("Segoe UI", 7F, FontStyle.Bold); + lblRequestNotif.Location = new Point(128, 54); + lblRequestNotif.Name = "lblRequestNotif"; + lblRequestNotif.Size = new Size(138, 12); + lblRequestNotif.TabIndex = 6; + lblRequestNotif.Text = "You Have Contacts Requests!"; + lblRequestNotif.Visible = false; + // + // niMain + // + niMain.Icon = (Icon)resources.GetObject("niMain.Icon"); + niMain.Text = "QtC.NET Client"; + niMain.Visible = true; + niMain.DoubleClick += niMain_DoubleClick; + // + // btnAddRoom + // + btnAddRoom.FlatAppearance.BorderSize = 0; + btnAddRoom.FlatStyle = FlatStyle.Flat; + btnAddRoom.Location = new Point(260, 1); + btnAddRoom.Name = "btnAddRoom"; + btnAddRoom.Size = new Size(20, 22); + btnAddRoom.TabIndex = 7; + btnAddRoom.UseVisualStyleBackColor = true; + btnAddRoom.Click += btnAddRoom_Click; + // + // pbCurrencyIcon + // + pbCurrencyIcon.Image = Properties.Resources.CurrencyIcon; + pbCurrencyIcon.Location = new Point(223, 5); + pbCurrencyIcon.Name = "pbCurrencyIcon"; + pbCurrencyIcon.Size = new Size(15, 14); + pbCurrencyIcon.SizeMode = PictureBoxSizeMode.StretchImage; + pbCurrencyIcon.TabIndex = 9; + pbCurrencyIcon.TabStop = false; + // + // lblCurrencyAmount + // + lblCurrencyAmount.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + lblCurrencyAmount.AutoSize = true; + lblCurrencyAmount.BackColor = Color.Transparent; + lblCurrencyAmount.Font = new Font("Segoe UI", 9F, FontStyle.Bold); + lblCurrencyAmount.ForeColor = Color.White; + lblCurrencyAmount.Location = new Point(239, 5); + lblCurrencyAmount.Name = "lblCurrencyAmount"; + lblCurrencyAmount.Size = new Size(14, 15); + lblCurrencyAmount.TabIndex = 10; + lblCurrencyAmount.Text = "0"; + lblCurrencyAmount.TextAlign = ContentAlignment.MiddleCenter; + // + // llblClaimSpin + // + llblClaimSpin.AutoSize = true; + llblClaimSpin.Font = new Font("Segoe UI", 9F, FontStyle.Bold); + llblClaimSpin.Location = new Point(185, 35); + llblClaimSpin.Name = "llblClaimSpin"; + llblClaimSpin.Size = new Size(94, 15); + llblClaimSpin.TabIndex = 11; + llblClaimSpin.TabStop = true; + llblClaimSpin.Text = "Claim Daily Spin"; + llblClaimSpin.Visible = false; + llblClaimSpin.LinkClicked += llblClaimSpin_LinkClicked; + // + // Main + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(282, 613); + Controls.Add(llblClaimSpin); + Controls.Add(pbCurrencyIcon); + Controls.Add(lblCurrencyAmount); + Controls.Add(btnAddRoom); + Controls.Add(lblRequestNotif); + Controls.Add(llblEditProfile); + Controls.Add(llblSignOut); + Controls.Add(llblSignIn); + Controls.Add(lblWelcome); + Controls.Add(pbUserPfp); + Controls.Add(tbcMain); + FormBorderStyle = FormBorderStyle.FixedDialog; + Icon = (Icon)resources.GetObject("$this.Icon"); + MaximizeBox = false; + Name = "Main"; + StartPosition = FormStartPosition.CenterScreen; + Text = "QtC.NET Client"; + FormClosed += frmMain_FormClosed; + Load += frmMain_Load; + Resize += frmMain_Resize; + tbcMain.ResumeLayout(false); + tbpContacts.ResumeLayout(false); + tbpRooms.ResumeLayout(false); + tbpOnlineUsers.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)pbUserPfp).EndInit(); + ctxmChangeStatus.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)pbCurrencyIcon).EndInit(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private TabControl tbcMain; + private TabPage tbpContacts; + private TabPage tbpRooms; + private ListBox lbRooms; + private PictureBox pbUserPfp; + private Label lblWelcome; + private LinkLabel llblSignIn; + private LinkLabel llblSignOut; + private TabPage tbpOnlineUsers; + private ListBox lbOnlineUsers; + private LinkLabel llblEditProfile; + private Label lblRequestNotif; + private ListView lvContacts; + private ImageList ilProfilePics; + private NotifyIcon niMain; + private ImageList ilTabIcons; + private ContextMenuStrip ctxmChangeStatus; + private ToolStripMenuItem onlineToolStripMenuItem; + private ToolStripMenuItem awayToolStripMenuItem; + private ToolStripMenuItem doNotDisturbToolStripMenuItem; + private ToolStripMenuItem invisibleToolStripMenuItem; + private Button btnAddRoom; + private PictureBox pbCurrencyIcon; + private Label lblCurrencyAmount; + private LinkLabel llblClaimSpin; + } +} diff --git a/qtc-net-client-2/Forms/Main.cs b/qtc-net-client-2/Forms/Main.cs new file mode 100644 index 0000000..1af0ecf --- /dev/null +++ b/qtc-net-client-2/Forms/Main.cs @@ -0,0 +1,706 @@ +using QtCNETAPI.Dtos.User; +using QtCNETAPI.Services.ApiService; +using QtCNETAPI.Services.GatewayService; +using QtCNETAPI.Events; +using QtCNETAPI.Models; +using qtc_net_client_2.Forms; +using qtc_net_client_2.Services; +using qtc_net_client_2.ClientModel; + +namespace qtc_net_client_2 +{ + public partial class Main : Form + { + private IApiService _apiService; + private IGatewayService _gatewayService; + private AudioService AudioService = new(); + + private List RoomList = []; + private List OnlineUsers = []; + private List Contacts = []; + public Main(IApiService apiService, IGatewayService gatewayService) + { + _apiService = apiService; + _gatewayService = gatewayService; + + InitializeComponent(); + } + + private async void frmMain_Load(object sender, EventArgs e) + { + // start request notif blink task + Thread blinkThread = new Thread(async () => await StartRequestNotifBlankLoop(lblRequestNotif)); + blinkThread.Start(); + + // check if client is already logged in + if (_apiService.CurrentUser == null) + { + // not logged in, load the login form + Login frmLogin = new Login(_apiService); + var result = frmLogin.ShowDialog(this); + + if (result == DialogResult.OK) + await OnSuccessfulLogin(); + } + } + + private async void llblSignIn_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + // just reshow the login dialog lol + Login frmLogin = new Login(_apiService); + var result = frmLogin.ShowDialog(this); + + if (result == DialogResult.OK) + await OnSuccessfulLogin(); + } + + private async void lbRooms_DoubleClick(object sender, EventArgs e) + { + if (lbRooms.SelectedItems.Count > 0) + { + string? selectedRoom = (string?)lbRooms.SelectedItems[lbRooms.SelectedItems.Count - 1]; + if (selectedRoom != null) + { + if (selectedRoom == "Lobby") + { + // join lobby + if (!_gatewayService.InLobby) await _gatewayService.JoinLobbyAsync(); + + Chat frmChat = new Chat(_gatewayService, _apiService); + frmChat.ShowDialog(this); + return; + } + + // join the room + Room? room = RoomList.FirstOrDefault(e => e.Name == selectedRoom); + if (room != null) + { + if (_gatewayService.CurrentRoom != room) await _gatewayService.JoinRoomAsync(room); + + Chat frmChat = new Chat(_gatewayService, _apiService); + frmChat.ShowDialog(this); + } + } + } + } + + private void pbUserPfp_Click(object sender, EventArgs e) + { + var args = (MouseEventArgs)e; + if (args.Button == MouseButtons.Right) return; + + Thread t = new Thread(new ThreadStart(async () => + { + using (OpenFileDialog openFileDialog = new OpenFileDialog()) + { + openFileDialog.InitialDirectory = Environment.CurrentDirectory; + openFileDialog.Title = "Select New Profile Picture"; + openFileDialog.Filter = "Image Files (*.png, *.jpg)|*.png;*.jpg"; + + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + // upload to server with api endpoint + var res = await _apiService.UpdateUserProfilePic(openFileDialog.FileName); + + if (res.Success) + { + // update profile pic in ui + var pfpRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id); + if (pfpRes.Success && pfpRes.Data != null) + { + using (var ms = new MemoryStream(pfpRes.Data)) + { + pbUserPfp.Image = Image.FromStream(ms); + ms.Dispose(); + } + } + } + } + } + })); + + t.SetApartmentState(ApartmentState.STA); + t.Start(); + } + + private void llblSignOut_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (MessageBox.Show("Are You Sure You Want To Sign Out?\nThis Deletes Your session.token, Requiring You To Sign In Again", "are you sure...?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) + { + File.Delete("./session.token"); + Environment.Exit(0); + } + } + + private async void lbOnlineUsers_DoubleClick(object sender, EventArgs e) + { + if (lbOnlineUsers.SelectedItems.Count > 0) + { + string? selectedUser = (string?)lbOnlineUsers.SelectedItems[lbOnlineUsers.SelectedItems.Count - 1]; + + if (selectedUser != null) + { + // get user info and open profile dialog + var res = await _apiService.GetUserInformationAsync(OnlineUsers.FirstOrDefault(e => e.Username == selectedUser)!.Id); + + if (res.Data != null && res.Success) + { + Profile frmProfile = new Profile(res.Data, _apiService, _gatewayService); + frmProfile.ShowDialog(this); + } + } + } + } + + private void llblEditProfile_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + ProfileEdit frmProfileEdit = new ProfileEdit(_apiService); + var dialogResult = frmProfileEdit.ShowDialog(this); + if (dialogResult == DialogResult.OK) + { + MessageBox.Show("If you updated your username, hit the refresh button to see it update on your lists.\nThe top username will not update until you restart your client."); + } + } + + private async void lvContacts_DoubleClick(object sender, EventArgs e) + { + if (lvContacts.SelectedItems.Count > 0) + { + string? selectedUser = (string?)lvContacts.SelectedItems[lvContacts.SelectedItems.Count - 1].Text; + + if (selectedUser != null) + { + // split from [ if it exists + if (selectedUser.Contains('[')) selectedUser = selectedUser.Split('[', options: StringSplitOptions.TrimEntries)[0]; + + // get user info and open profile dialog + var res = await _apiService.GetUserInformationAsync(Contacts.FirstOrDefault(e => e.Username == selectedUser)!.Id); + + if (res.Data != null && res.Success) + { + Profile frmProfile = new Profile(res.Data, _apiService, _gatewayService); + frmProfile.ShowDialog(this); + } + } + } + } + + private async void btnRefresh_Click(object sender, EventArgs e) + { + // refresh all + await RefreshContactsList(); + await RefreshRoomsList(); + await RefreshOnlineUsersList(); + } + + private void frmMain_Resize(object sender, EventArgs e) + { + if (WindowState == FormWindowState.Minimized) Hide(); + } + + private void niMain_DoubleClick(object sender, EventArgs e) + { + Show(); + WindowState = FormWindowState.Normal; + } + + private async void frmMain_FormClosed(object sender, FormClosedEventArgs e) + { + DialogResult = DialogResult.OK; + + // ensure the gateway stops the connection and disposes properly + await _gatewayService.StopAsync(); + await _gatewayService.DisposeAsync(); + } + + private async void ctxmChangeStatus_ItemClicked(object sender, ToolStripItemClickedEventArgs e) + { + if (e.ClickedItem != null) + { + UserStatus userStatus = UserStatus.Unknown; + switch (e.ClickedItem.Name) + { + case "onlineToolStripMenuItem": + userStatus = UserStatus.Online; + onlineToolStripMenuItem.Checked = true; + awayToolStripMenuItem.Checked = false; + doNotDisturbToolStripMenuItem.Checked = false; + invisibleToolStripMenuItem.Checked = false; + break; + case "awayToolStripMenuItem": + userStatus = UserStatus.Away; + onlineToolStripMenuItem.Checked = false; + awayToolStripMenuItem.Checked = true; + doNotDisturbToolStripMenuItem.Checked = false; + invisibleToolStripMenuItem.Checked = false; + break; + case "doNotDisturbToolStripMenuItem": + userStatus = UserStatus.DoNotDisturb; + onlineToolStripMenuItem.Checked = false; + awayToolStripMenuItem.Checked = false; + doNotDisturbToolStripMenuItem.Checked = true; + invisibleToolStripMenuItem.Checked = false; + break; + case "invisibleToolStripMenuItem": + userStatus = UserStatus.Offline; + onlineToolStripMenuItem.Checked = false; + awayToolStripMenuItem.Checked = false; + doNotDisturbToolStripMenuItem.Checked = false; + invisibleToolStripMenuItem.Checked = true; + break; + } + + // set it + await _gatewayService.UpdateStatus((int)userStatus); + } + } + + private void btnAddRoom_Click(object sender, EventArgs e) + { + CreateRoom createRoom = new CreateRoom(_apiService); + createRoom.ShowDialog(); + } + + private async void llblClaimSpin_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + TokenJackpotSpinner tokenJackpotSpinner = new TokenJackpotSpinner(); + var frmResult = tokenJackpotSpinner.ShowDialog(); + + if (frmResult == DialogResult.OK && tokenJackpotSpinner.TokensWon > 0) + { + // claim + var result = await _apiService.AddCurrencyToCurrentUser(tokenJackpotSpinner.TokensWon, true); + if (result.Success) + { + lblCurrencyAmount.Text = (_apiService.CurrentUser.CurrencyAmount + tokenJackpotSpinner.TokensWon).ToString(); + llblClaimSpin.Visible = false; + } + else MessageBox.Show("We Were Unable To Claim Your Prize At This Time. Please Try Again Later.", "Uh Oh.", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private async Task OnSuccessfulLogin() + { + // double check + if (_apiService.CurrentUser != null && _apiService.SessionToken != null) + { + // start gateway connection + await _gatewayService.StartAsync(); + + // subscribe to gateway events + _gatewayService.OnServerReconnecting += _gatewayService_OnServerReconnecting; + _gatewayService.OnServerReconnected += _gatewayService_OnServerReconnected; + _gatewayService.OnServerDisconnect += _gatewayService_OnServerDisconnect; + _gatewayService.OnClientFunctionReceived += _gatewayService_OnClientFunctionReceived; + _gatewayService.OnDirectMessageReceived += _gatewayService_OnDirectMessageReceived; + _gatewayService.OnServerConfigReceived += _gatewayService_OnServerConfigReceived; + + if (_gatewayService.HubConnection != null && _gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected) + { + // we are fully logged in, get current user profile pic and set up ui + llblSignIn.Visible = false; + lblWelcome.Text = $"Welcome, {_apiService.CurrentUser.Username}"; + lblCurrencyAmount.Text = _apiService.CurrentUser.CurrencyAmount.ToString(); + llblSignOut.Visible = true; + llblEditProfile.Visible = true; + tbcMain.Enabled = true; + + var pfpRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id); + if (pfpRes.Success && pfpRes.Data != null) + { + using (var ms = new MemoryStream(pfpRes.Data)) + { + pbUserPfp.Image = Image.FromStream(ms); + ms.Dispose(); + } + } + + await RefreshContactsList(); + await RefreshRoomsList(); + await RefreshOnlineUsersList(); + + // TODO - figure out server side why online status is invisible on login + _apiService.CurrentUser.Status = 1; + + // set status context menu checked + UserStatus cuStatus = (UserStatus)_apiService.CurrentUser.Status; + switch (cuStatus) + { + case UserStatus.Online: + onlineToolStripMenuItem.Checked = true; + awayToolStripMenuItem.Checked = false; + doNotDisturbToolStripMenuItem.Checked = false; + invisibleToolStripMenuItem.Checked = false; + break; + case UserStatus.Away: + onlineToolStripMenuItem.Checked = false; + awayToolStripMenuItem.Checked = true; + doNotDisturbToolStripMenuItem.Checked = false; + invisibleToolStripMenuItem.Checked = false; + break; + case UserStatus.DoNotDisturb: + onlineToolStripMenuItem.Checked = false; + awayToolStripMenuItem.Checked = false; + doNotDisturbToolStripMenuItem.Checked = true; + invisibleToolStripMenuItem.Checked = false; + break; + case UserStatus.Offline: + onlineToolStripMenuItem.Checked = false; + awayToolStripMenuItem.Checked = false; + doNotDisturbToolStripMenuItem.Checked = false; + invisibleToolStripMenuItem.Checked = true; + break; + } + + if (_apiService.CurrentUser.Role == "Admin") btnAddRoom.Enabled = true; + else btnAddRoom.Enabled = false; + + if (DateTime.Compare(DateTime.UtcNow, _apiService.CurrentUser.LastCurrencySpin) < 0 || _apiService.CurrentUser.LastCurrencySpin == new DateTime()) llblClaimSpin.Visible = true; + else llblClaimSpin.Visible = false; + } + } + } + + private async Task RefreshOnlineUsersList() + { + if (InvokeRequired) + { + await Invoke(async delegate () + { + lbOnlineUsers.Items.Clear(); + var usersOnlineRes = await _apiService.GetOnlineUsersAsync(); + if (usersOnlineRes.Success && usersOnlineRes.Data != null) + { + foreach (var user in usersOnlineRes.Data) + { + lbOnlineUsers.Items.Add(user.Username); + } + OnlineUsers = usersOnlineRes.Data; + } + }); + return; + } + + lbOnlineUsers.Items.Clear(); + var usersOnlineRes = await _apiService.GetOnlineUsersAsync(); + if (usersOnlineRes.Success && usersOnlineRes.Data != null) + { + lbOnlineUsers.Items.Clear(); + foreach (var user in usersOnlineRes.Data) + { + lbOnlineUsers.Items.Add(user.Username); + } + OnlineUsers = usersOnlineRes.Data; + } + } + + private async Task RefreshRoomsList() + { + if (InvokeRequired) + { + await Invoke(async delegate () + { + lbRooms.Items.Clear(); + var roomsRes = await _apiService.GetAllRoomsAsync(); + if (roomsRes.Success && roomsRes.Data != null) + { + foreach (var room in roomsRes.Data) + { + lbRooms.Items.Add(room.Name); + } + RoomList = roomsRes.Data; + } + + // always add lobby room to rooms list + lbRooms.Items.Add("Lobby"); + }); + return; + } + + lbRooms.Items.Clear(); + var roomsRes = await _apiService.GetAllRoomsAsync(); + if (roomsRes.Success && roomsRes.Data != null) + { + lbRooms.Items.Clear(); + foreach (var room in roomsRes.Data) + { + lbRooms.Items.Add(room.Name); + } + RoomList = roomsRes.Data; + } + + // always add lobby room to rooms list + lbRooms.Items.Add("Lobby"); + } + + private async Task RefreshContactsList() + { + if (InvokeRequired) + { + await Invoke(async delegate () + { + lvContacts.Items.Clear(); + Contacts.Clear(); + lblRequestNotif.Visible = false; + var contactsRes = await _apiService.GetCurrentUserContacts(); + if (contactsRes.Success && contactsRes.Data != null) + { + if (contactsRes.Data.Where(e => e.UserId == _apiService.CurrentUser!.Id && e.UserStatus == Contact.ContactStatus.AwaitingApprovalFromSelf).Count() >= 1) + lblRequestNotif.Visible = true; + else + lblRequestNotif.Visible = false; + + foreach (var contact in contactsRes.Data) + { + ServiceResponse user = null!; + if (contact.OwnerId == _apiService.CurrentUser!.Id) + user = await _apiService.GetUserInformationAsync(contact.UserId); + else if (contact.UserId == _apiService.CurrentUser!.Id) + user = await _apiService.GetUserInformationAsync(contact.OwnerId); + + if (user.Data != null) + { + Contacts.Add(user.Data); + if (contact.OwnerId == _apiService.CurrentUser!.Id) + { + switch (contact.OwnerStatus) + { + case Contact.ContactStatus.AwaitingApprovalFromOther: + var lvi = lvContacts.Items.Add($"{user.Data.Username} [Request Sent]"); + await AddProfilePicToList(user.Data.Id); + lvi.ImageKey = user.Data.Id; + break; + case Contact.ContactStatus.Accepted: + var lvi2 = lvContacts.Items.Add($"{user.Data.Username}"); + await AddProfilePicToList(user.Data.Id); + lvi2.ImageKey = user.Data.Id; + break; + } + } + else if (contact.UserId == _apiService.CurrentUser!.Id) + { + switch (contact.UserStatus) + { + case Contact.ContactStatus.AwaitingApprovalFromSelf: + var lvi = lvContacts.Items.Add($"{user.Data.Username} [Contact Request]"); + await AddProfilePicToList(user.Data.Id); + lvi.ImageKey = user.Data.Id; + AudioService.PlaySoundEffect("sndContactRequest"); + break; + case Contact.ContactStatus.Accepted: + var lvi2 = lvContacts.Items.Add($"{user.Data.Username}"); + await AddProfilePicToList(user.Data.Id); + lvi2.ImageKey = user.Data.Id; + break; + } + } + } + } + } + }); + return; + } + + lvContacts.Items.Clear(); + Contacts.Clear(); + lblRequestNotif.Visible = false; + var contactsRes = await _apiService.GetCurrentUserContacts(); + if (contactsRes.Success && contactsRes.Data != null) + { + if (contactsRes.Data.Where(e => e.UserId == _apiService.CurrentUser!.Id && e.UserStatus == Contact.ContactStatus.AwaitingApprovalFromSelf).Count() >= 1) + lblRequestNotif.Visible = true; + else + lblRequestNotif.Visible = false; + + foreach (var contact in contactsRes.Data) + { + ServiceResponse user = null!; + if (contact.OwnerId == _apiService.CurrentUser!.Id) + user = await _apiService.GetUserInformationAsync(contact.UserId); + else if (contact.UserId == _apiService.CurrentUser!.Id) + user = await _apiService.GetUserInformationAsync(contact.OwnerId); + + if (user.Data != null) + { + Contacts.Add(user.Data); + if (contact.OwnerId == _apiService.CurrentUser!.Id) + { + switch (contact.OwnerStatus) + { + case Contact.ContactStatus.AwaitingApprovalFromOther: + var lvi = lvContacts.Items.Add($"{user.Data.Username} [Request Sent]"); + await AddProfilePicToList(user.Data.Id); + lvi.ImageKey = user.Data.Id; + break; + case Contact.ContactStatus.Accepted: + var lvi2 = lvContacts.Items.Add($"{user.Data.Username}"); + await AddProfilePicToList(user.Data.Id); + lvi2.ImageKey = user.Data.Id; + break; + } + } + else if (contact.UserId == _apiService.CurrentUser!.Id) + { + switch (contact.UserStatus) + { + case Contact.ContactStatus.AwaitingApprovalFromSelf: + var lvi = lvContacts.Items.Add($"{user.Data.Username} [Contact Request]"); + await AddProfilePicToList(user.Data.Id); + lvi.ImageKey = user.Data.Id; + AudioService.PlaySoundEffect("sndContactRequest"); + break; + case Contact.ContactStatus.Accepted: + var lvi2 = lvContacts.Items.Add($"{user.Data.Username}"); + await AddProfilePicToList(user.Data.Id); + lvi2.ImageKey = user.Data.Id; + break; + } + } + } + } + } + } + + private async Task StartRequestNotifBlankLoop(Label label) + { + while (true) + { + if (InvokeRequired && label.IsHandleCreated) + { + await Invoke(async delegate () + { + label.ForeColor = Color.Red; + await Task.Delay(500); + label.ForeColor = Color.Blue; + await Task.Delay(500); + }); + } + else if (label.IsHandleCreated) + { + label.ForeColor = Color.Red; + await Task.Delay(500); + label.ForeColor = Color.Blue; + await Task.Delay(500); + } + } + } + + private async Task AddProfilePicToList(string userId) + { + var result = await _apiService.GetUserProfilePic(userId); + if (result != null && result.Success && result.Data != null) + { + using (var ms = new MemoryStream(result.Data)) + { + ilProfilePics.Images.Add(userId, Image.FromStream(ms)); + ms.Dispose(); + } + } + } + + private async void _gatewayService_OnServerDisconnect(object? sender, EventArgs e) + { + if (DialogResult == DialogResult.OK) return; + + var args = (ServerConnectionClosedEventArgs)e; + string? error = string.Empty; + if (args.Error != null) error = args.Error.Message; + + // disconnect can sometimes be caused by an expired JWT token, attempt connection restart + await _gatewayService.StopAsync(); + await _gatewayService.StartAsync(); + + if (_gatewayService.HubConnection != null && _gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected) + { BeginInvoke(delegate () { Enabled = true; }); return; } + + ConnectionClosed frmConnectionClosed = new ConnectionClosed(error); + var result = frmConnectionClosed.ShowDialog(); + + if (result == DialogResult.OK) + { + // tell the gateway service to attempt reconnection + Reconnect: + if (_gatewayService.HubConnection != null) + { + try + { + await _gatewayService.StopAsync(); + await _gatewayService.StartAsync(); + if (_gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected) + BeginInvoke(delegate () { Enabled = true; }); + } + catch (HttpRequestException ex) + { + // reshow the dialog + frmConnectionClosed.Reason = ex.Message; + var result1 = frmConnectionClosed.ShowDialog(); + if (result1 == DialogResult.OK) goto Reconnect; + else Environment.Exit(0); + } + } + } + else Environment.Exit(0); + } + + private void _gatewayService_OnServerReconnecting(object? sender, EventArgs e) => BeginInvoke(delegate () { Enabled = false; }); + private void _gatewayService_OnServerReconnected(object? sender, EventArgs e) => BeginInvoke(delegate () { Enabled = true; }); + + private async void _gatewayService_OnClientFunctionReceived(object? sender, EventArgs e) + { + var args = (ClientFunctionEventArgs)e; + + switch (args.Function) + { + case "rul": + await RefreshOnlineUsersList(); + break; + case "rr": + await RefreshRoomsList(); + break; + case "rcl": + await RefreshContactsList(); + break; + } + } + + private async void _gatewayService_OnServerConfigReceived(object? sender, EventArgs e) + { + var args = (ServerConfigEventArgs)e; + + if (args.ServerConfig != null) + { + if (args.ServerConfig.IsDown) + { + MessageBox.Show($"Sorry, This Server Is Currently Down.\nMessage: {args.ServerConfig.IsDownMessage}\n\nPlease Try Again Later"); + + if (_gatewayService.HubConnection != null && _gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected) + { + await _gatewayService.StopAsync(); + await _gatewayService.DisposeAsync(); + } + Environment.Exit(0); + } + + BeginInvoke(delegate () { Text = $"QtC.NET Client = Connected To {args.ServerConfig.Name}"; }); + } + } + + private void _gatewayService_OnDirectMessageReceived(object? sender, EventArgs e) + { + var args = (DirectMessageEventArgs)e; + + DirectMessage? existingForm = (DirectMessage?)Application.OpenForms.Cast
().FirstOrDefault(e => e.Name == "frmDirectMessage"); + if (existingForm != null && existingForm.User.Id == args.User.Id) + { + // we want to just add to its text box + existingForm.Messages.Add($"[{args.User.Username}] {args.Message.Content}\n"); + } + else + { + // start a new form + DirectMessage frmDirectMessage = new DirectMessage(_gatewayService, _apiService, args.User, args.Message); + Task.Run(frmDirectMessage.ShowDialog); + } + } + } +} diff --git a/qtc-net-client-2/Forms/Main.resx b/qtc-net-client-2/Forms/Main.resx new file mode 100644 index 0000000..a2c632d --- /dev/null +++ b/qtc-net-client-2/Forms/Main.resx @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 122, 19 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs + LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu + SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA8AgAAAJNU0Z0AUkBTAIBAQIB + AAGAAQABgAEAARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAARADAAEBAQABIAYAARAS + AANvAe8BbQFnAVQB7wFnAV0BVAHvAWcBWwFUAe8BZwFbAVQB7wFnAVkBVAHvAWcBZAFZAe8DZwHvA2cB + 7wNnAe8DZwHvA2cB7wNnAe8DZwHvA2cB7wNnAe84AAMzAVEDhwH1gAAD+AH/AbkBlQE8Af8BgwF9AW4B + /wGEAX0BbAH/AaoBhAEnAf8BrAF7AQAB/wHMAbwBlAH/A34B/wN+Af8DfgH/A34B/wN+Af8DfgH/A34B + /wN+Af8DjgH/OAADEgEYAz8BbYAABP8BlwGLAW0B/wKBAYAB/wGCAYEBgAH/AZgBiAFgAf8BygGQAQAB + /wHdAcwBnwH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DkwH/NAADXwHTAz0BZ4QABP8B + hgGEAX0B/wOBAf8DgQH/AYcBgwF6Af8BzwGUAQAB/wHeAcwBnwH/A+AB/wPgAf8D4AH/A+AB/wPgAf8D + 4AH/A+AB/wPgAf8DvAH/NAADWgHCAzQBU4QABP8BiwGGAXoB/wOBAf8DgQH/AY4BhgFxAf8BzwGUAQAB + /wHeAcwBnyH/A8oB/xAAAw0BEQM/AWwDUwGnAVwCWQG+AVgCVgGzAUgCRwGDAyEBMAQAA4MB8wM6AWCI + AAT/AawBlgFgAf8BgwGCAX8B/wGFAYIBfQH/AbMBkwFEAf8BzwGUAQAB/wHeAcwBnwH/A7AB/wOwAf8D + sAH/A7AB/wOwAf8DsAH/A7AB/wOwAf8DqAH/CAADGgEkA1IBoAFyAWMBPAH2AaIBcwEAAf8BrgF8AQAB + /wGwAX0BAAH/AagBeAEAAf8BlQFqAQAB/wGAAWQBEAH+AVwCWQHGA1cBtQMWAR6IAAT/AdkBqgE3Af8B + vgGYATgB/wHAAZgBNgH/AdwBogEUAf8BzwGUAQAB/wHeAcwBnwH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D + gQH/A4EB/wOBAf8DkwH/BAADIAEtAWgBYwFaAekBvwGIAQAB/wHNAZUBCgH/AbABiAEnAf8BcwFkAT8B + /wFNAUsBRwH/AU4BSwFCAf8BZgFXATEB/wGaAXQBFwH/AaQBdgEDAf8BcAFPAQAB/wNDAXYEAYQABP8B + 4QGuATEB/wG9AZcBOwH/AcABmAE1Af8B4wGlAQoB/wHPAZQBAAH/Ad4BzAGfAf8DwAH/A8AB/wPAAf8D + wAH/A8AB/wPAAf8DwAH/A8AB/wOvAf8EAAFpAWQBWgHpAdkBmgEAAf8B2gGjARwB/wKOAYwB/wOKAf8D + lwH/A5sB/wORAf8DdAH/A0gB/wFDAUIBPwH/AbUBgwEHAf8BegFXAQAB/wM2AViEAAT/AbsBnQFTAf8B + iAGEAXkB/wGMAYUBdAH/AcQBmQEwAf8BzwGUAQAB/wHeAcwBnyH/A8oB/wNDAXYB6QGnAQIB/wHpAasB + EgH/AdABygG7Af8DrAH/A10B/wNMAf8DSwH/A0QB/wMPAf8DswH/A2YB/wFUAUwBOgH/Aa4BfQEEAf8D + XQHMhAAE/wGUAYoBcwH/A4EB/wOBAf8BmgGKAWMB/wHPAZQBAAH/Ad4BzAGfAf8D0AH/A9AB/wPQAf8D + 0AH/A9AB/wPQAf8D0AH/A9AB/wO1Af8CagFhAeYB7QGtARAB/wH0AdABdgH/A/oB/wP6Af8DfQH/A38B + /wOAAf8DgAH/A34B/wOEAf8DuwH/A2oB/wGoAYABHAH/AXMBYwE8AfaEAAT/AYYBgwF+Af8DgQH/A4EB + /wGGAYMBewH/Ac8BlAEAAf8B3gHMAZ8B/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A5MB + /wFxAW0BXwHuAe8BtAEhAf8B9wHcAZcJ/wORAf8DiAH/A4cB/wOHAf8DgQH/A1cB/wPmAf8DowH/AbYB + kQE2Af8BiwFqAS8B+YQABP8BiwGGAXkB/wOBAf8DgQH/AY4BhgFxAf8BzwGUAQAB/wHeAcwBnwH/A6EB + /wOhAf8DoQH/A6EB/wOhAf8DoQH/A6EB/wOhAf8DoQH/A0sBjQHwAb4BPwH/AfQBzQFsIf8D+wH/A9AB + /wHXAacBMQH/AmEBXQHRhAAE/wGnAZQBZwH/AYMBggF/Af8BhQGDAX4B/wGwAZQBTgH/AdMBlwECAf8B + 4AHOAZ8B/wPnAf8D5wH/A+cB/wPnAf8D5wH/A+cB/wPnAf8D5wH/A8AB/wMHAQkBcQFuAWIB7gHxAbwB + OwH/AfoB6gHCAf8D3AH/A3cB/wNoAf8DaAH/A2gB/wMyCf8B8gHdAakB/wHqAakBCAH/Az4BaoQABP8B + 1wGxAVIB/wGaAY8BdAH/AaABkgFtAf8B4AGvATcB/wHnAakBEAH/AesB1QGgAf8DgQH/A4EB/wOBAf8D + gQH/A4EB/wOBAf8DgQH/A4EB/wOTAf8EAAMzAVEBdgFvAWgB8AHzAcYBWAH/AfoB5wG4Fv8B/gH7Af8B + +QHiAaoB/wHvAbgBLQH/A04BlgQChAAE/wH0Ac0BbAH/AfQBywFmAf8B9AHLAWUB/wH0AcsBZQH/AfEB + wQFJAf8B+QHjAawB/wOJAf8DiQH/A4kB/wOJAf8DiQH/A4kB/wOJAf8DiQH/A5oB/wgAAyIBMQNfAckB + rAGbAWcB+gHzAcoBZQH/AfkB4QGmAf8B+wHtAcwB/wH7AewByAH/AfgB3QGbAf8B0gGkAWEB/gJlAV4B + 4gM9AWgEAYgAQP8QAAMPARMDRwGCA2QB2wHAAa4BbwH8AWoCZwHqA1QBqAMoATuUAAFCAU0BPgcAAT4D + AAEoAwABQAMAARADAAEBAQABAQUAAYAXAAP/AwAB/wH8BgAB/wH8BgAB/wH5BgAB/wH5BgAB8AETBgAB + wAEDBgABgAEBBgABgAEBBwABAQcAAQEHAAEBBwABAQcAAQEGAAGAAQEGAAHAAQMGAAHwAR8EAAs= + + + + 297, 21 + + + 216, 21 + + + + + AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAABMLAAATCwAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAO24wAMtuMAFjbjABy24wAetuMAHHbjABW24wAL9uMAAzbjAAA24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAf24wAdNuMAMTbjADu24wA/duMAP/bjAD/24wA/9uMAPzbjADs24wAv9uM + AG3bjAAa24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAJ24wAYduMANXbjAD+24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/duMAM7bjABY24wABtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAA24wAEtuMAJPbjAD324wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPTbjACH24wADtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMABDbjACf24wA/duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPzbjACT24wAC9uMAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAE24wAh9uMAP3bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPrbjAB524wAAtuM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAE3bjADw24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AOrbjABA24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAQ24wAvduMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAK/bjAAK24wAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAFHbjAD324wA/9uM + AP/bjAD/24wA/9uLAP/biwD/24wA/9uMAP/bjAD/24wA/9uMAP/biwD/24wA/9uMAP/bjAD/24sA/9uL + AP/bjAD/24wA/9uMAP/bjAD/24wA8tuMAEPbjAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAC24wAntuM + AP/bjAD/24wA/9uLAP/ckQz/4Jwj/9+YG//bjQP/3JEM/9yPB//biwD/3ZIN/96YGv/bjQP/24wA/9uM + Af/elRX/4Jwk/92TD//biwD/24wA/9uMAP/bjAD/24wAj9uMAADbjAAAAAAAAAAAAAAAAAAA24wAANuM + ABbbjADU24wA/9uMAP/biwD/4qM1//Tet//57dj/+OnR/+/Ok//y16f/5atG/92TD//y2Kr/9N63/96V + FP/bjAL/6Lhi//fnzf/47Nf/9uPB/+WrR//biwD/24wA/9uMAP/bjADH24wAD9uMAAAAAAAAAAAAAAAA + AADbjAAA24wAMtuMAO7bjAD/24wA/92TD//14b3/89mt/+SoP//w0Jj///////Parv/dkg3/4qIy//rw + 3v/msFH/24wA/+OlOf/68N//7MJ5/+KkNf/uy47/+OrS/+CcJP/biwD/24wA/9uMAObbjAAm24wAAAAA + AAAAAAAAAAAAANuMAADbjABI24wA+duMAP/biwD/4qIy//nv3f/iozX/3pUX//LWpv/25cj/8tis/9uM + AP/ipDb/+ezY/+CcJ//aiQD/68F3//bjwv/ckAz/24oA/92RD//puWX/4Jwl/9uLAP/bjAD/24wA89uM + ADrbjAAAAAAAAAAAAAAAAAAA24wAANuMAFHbjAD824wA/9uKAP/jpzz/+e7b/+CdJ//bjAH/3ZMQ/+zD + fP/137v/240D/+KkNv/57Nj/4J0n/9qJAP/tx4X/89yz/9uNBP/bjAD/24wA/9qKAP/biwD/24wA/9uM + AP/bjAD324wAQtuMAAAAAAAAAAAAAAAAAADbjAAA24wATNuMAPrbjAD/24oA/+OnPP/57tv/4J0n/9uL + AP/aigD/7MJ6//Xfu//cjgX/5axI//rv3v/kqED/24sA/+3Hhf/z3LL/244E/9uMAP/bjAD/24sA/9uM + AP/bjAD/24wA/9uMAPXbjAA924wAAAAAAAAAAAAAAAAAANuMAADbjAA524wA8tuMAP/bigD/46Y6//nu + 2//gnin/24sA/9qKAP/sw37/9N+4/9yRC//x0p7//v37//Tdtv/dkxD/7cWB//Tdtv/cjgX/24wA/9uM + Av/elRb/3JAK/9uMAP/bjAD/24wA69uMACzbjAAAAAAAAAAAAAAAAAAA24wAANuMAB7bjADd24wA/9uL + AP/gmyL/+e3Z/+i4Yv/bjAD/3ZMP//TdtP/w0Jj/24sA/+WuS//68eD/5KpD/9uLAP/otl3/+e3Y/+Gf + Kv/biwD/46c8//XiwP/iozT/24sA/9uMAP/bjADS24wAFduMAAAAAAAAAAAAAAAAAADbjAAA24wABtuM + AK/bjAD/24wA/9uNAv/sxH3/+vDg//LZq//14sH/+OvU/+KkNv/aigD/4Z4p//HUov/fmB3/24oA/96V + Fv/03bX/+OnQ//LWpv/57dn/8NGa/9yQCv/bjAD/24wA/9uMAKDbjAAC24wAAAAAAAAAAAAAAAAAANuM + AADbjAAA24wAZtuMAP3bjAD/24wA/9yPCf/mr0//7cmI/+zCef/hoCz/24wA/9uMAP/bjQL/3I8I/9uN + Af/bjAD/24sA/96XGf/pu2r/7sqK/+i1XP/dkg//24sA/9uMAP/bjAD624wAVtuMAADbjAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAc24wA09uMAP/bjAD/24wA/9qKAP/biwD/2ooA/9uLAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24sA/9qKAP/biwD/2ooA/9uMAP/bjAD/24wA/9uMAMfbjAAU24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjABr24wA+9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD324wAXNuM + AADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAA7bjACr24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AJ7bjAAJ24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMACTbjADG24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAC724wAHduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuM + ACvbjADA24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD+24wAtduMACPbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADbjAAA24wAANuMABzbjACV24wA8duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA7tuMAIvbjAAW24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAAbbjABG24wAqtuMAOnbjAD+24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD924wA59uMAKTbjAA/24wABNuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjAAH24wALtuMAGXbjACS24wAq9uM + ALPbjACq24wAj9uMAGHbjAAq24wABduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuM + AADbjAAD24wABduMAALbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA//////////////////AH///AAf//AAB//gAAP/wAAB/4AAAP+AAAD/AA + AAfwAAAH4AAAB+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD8AAAB/AAAAf4AAAP+AAAD/wA + AB/+AAA//wAAf/+AAP//4AP///4///////8= + + + + 55 + + + + AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAABMLAAATCwAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAO24wAMtuMAFjbjABy24wAetuMAHHbjABW24wAL9uMAAzbjAAA24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAf24wAdNuMAMTbjADu24wA/duMAP/bjAD/24wA/9uMAPzbjADs24wAv9uM + AG3bjAAa24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAJ24wAYduMANXbjAD+24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/duMAM7bjABY24wABtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAA24wAEtuMAJPbjAD324wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPTbjACH24wADtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMABDbjACf24wA/duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPzbjACT24wAC9uMAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAE24wAh9uMAP3bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPrbjAB524wAAtuM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAE3bjADw24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AOrbjABA24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAQ24wAvduMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAK/bjAAK24wAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAFHbjAD324wA/9uM + AP/bjAD/24wA/9uLAP/biwD/24wA/9uMAP/bjAD/24wA/9uMAP/biwD/24wA/9uMAP/bjAD/24sA/9uL + AP/bjAD/24wA/9uMAP/bjAD/24wA8tuMAEPbjAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAC24wAntuM + AP/bjAD/24wA/9uLAP/ckQz/4Jwj/9+YG//bjQP/3JEM/9yPB//biwD/3ZIN/96YGv/bjQP/24wA/9uM + Af/elRX/4Jwk/92TD//biwD/24wA/9uMAP/bjAD/24wAj9uMAADbjAAAAAAAAAAAAAAAAAAA24wAANuM + ABbbjADU24wA/9uMAP/biwD/4qM1//Tet//57dj/+OnR/+/Ok//y16f/5atG/92TD//y2Kr/9N63/96V + FP/bjAL/6Lhi//fnzf/47Nf/9uPB/+WrR//biwD/24wA/9uMAP/bjADH24wAD9uMAAAAAAAAAAAAAAAA + AADbjAAA24wAMtuMAO7bjAD/24wA/92TD//14b3/89mt/+SoP//w0Jj///////Parv/dkg3/4qIy//rw + 3v/msFH/24wA/+OlOf/68N//7MJ5/+KkNf/uy47/+OrS/+CcJP/biwD/24wA/9uMAObbjAAm24wAAAAA + AAAAAAAAAAAAANuMAADbjABI24wA+duMAP/biwD/4qIy//nv3f/iozX/3pUX//LWpv/25cj/8tis/9uM + AP/ipDb/+ezY/+CcJ//aiQD/68F3//bjwv/ckAz/24oA/92RD//puWX/4Jwl/9uLAP/bjAD/24wA89uM + ADrbjAAAAAAAAAAAAAAAAAAA24wAANuMAFHbjAD824wA/9uKAP/jpzz/+e7b/+CdJ//bjAH/3ZMQ/+zD + fP/137v/240D/+KkNv/57Nj/4J0n/9qJAP/tx4X/89yz/9uNBP/bjAD/24wA/9qKAP/biwD/24wA/9uM + AP/bjAD324wAQtuMAAAAAAAAAAAAAAAAAADbjAAA24wATNuMAPrbjAD/24oA/+OnPP/57tv/4J0n/9uL + AP/aigD/7MJ6//Xfu//cjgX/5axI//rv3v/kqED/24sA/+3Hhf/z3LL/244E/9uMAP/bjAD/24sA/9uM + AP/bjAD/24wA/9uMAPXbjAA924wAAAAAAAAAAAAAAAAAANuMAADbjAA524wA8tuMAP/bigD/46Y6//nu + 2//gnin/24sA/9qKAP/sw37/9N+4/9yRC//x0p7//v37//Tdtv/dkxD/7cWB//Tdtv/cjgX/24wA/9uM + Av/elRb/3JAK/9uMAP/bjAD/24wA69uMACzbjAAAAAAAAAAAAAAAAAAA24wAANuMAB7bjADd24wA/9uL + AP/gmyL/+e3Z/+i4Yv/bjAD/3ZMP//TdtP/w0Jj/24sA/+WuS//68eD/5KpD/9uLAP/otl3/+e3Y/+Gf + Kv/biwD/46c8//XiwP/iozT/24sA/9uMAP/bjADS24wAFduMAAAAAAAAAAAAAAAAAADbjAAA24wABtuM + AK/bjAD/24wA/9uNAv/sxH3/+vDg//LZq//14sH/+OvU/+KkNv/aigD/4Z4p//HUov/fmB3/24oA/96V + Fv/03bX/+OnQ//LWpv/57dn/8NGa/9yQCv/bjAD/24wA/9uMAKDbjAAC24wAAAAAAAAAAAAAAAAAANuM + AADbjAAA24wAZtuMAP3bjAD/24wA/9yPCf/mr0//7cmI/+zCef/hoCz/24wA/9uMAP/bjQL/3I8I/9uN + Af/bjAD/24sA/96XGf/pu2r/7sqK/+i1XP/dkg//24sA/9uMAP/bjAD624wAVtuMAADbjAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAc24wA09uMAP/bjAD/24wA/9qKAP/biwD/2ooA/9uLAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24sA/9qKAP/biwD/2ooA/9uMAP/bjAD/24wA/9uMAMfbjAAU24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjABr24wA+9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD324wAXNuM + AADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAA7bjACr24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AJ7bjAAJ24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMACTbjADG24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAC724wAHduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuM + ACvbjADA24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD+24wAtduMACPbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADbjAAA24wAANuMABzbjACV24wA8duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA7tuMAIvbjAAW24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAAbbjABG24wAqtuMAOnbjAD+24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD924wA59uMAKTbjAA/24wABNuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjAAH24wALtuMAGXbjACS24wAq9uM + ALPbjACq24wAj9uMAGHbjAAq24wABduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuM + AADbjAAD24wABduMAALbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA//////////////////AH///AAf//AAB//gAAP/wAAB/4AAAP+AAAD/AA + AAfwAAAH4AAAB+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD8AAAB/AAAAf4AAAP+AAAD/wA + AB/+AAA//wAAf/+AAP//4AP///4///////8= + + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/Profile.Designer.cs b/qtc-net-client-2/Forms/Profile.Designer.cs new file mode 100644 index 0000000..0d496f4 --- /dev/null +++ b/qtc-net-client-2/Forms/Profile.Designer.cs @@ -0,0 +1,257 @@ +namespace qtc_net_client_2.Forms +{ + partial class Profile + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Profile)); + pbUserPfp = new PictureBox(); + lblUsername = new Label(); + rtxtBio = new RichTextBox(); + btnAddContact = new Button(); + btnAccept = new Button(); + btnDecline = new Button(); + btnCancelRequest = new Button(); + btnMessage = new Button(); + pbUserStatus = new PictureBox(); + pbCurrencyIcon = new PictureBox(); + lblCurrencyAmount = new Label(); + flpUsernameCurrency = new FlowLayoutPanel(); + flpCurrency = new FlowLayoutPanel(); + ((System.ComponentModel.ISupportInitialize)pbUserPfp).BeginInit(); + ((System.ComponentModel.ISupportInitialize)pbUserStatus).BeginInit(); + ((System.ComponentModel.ISupportInitialize)pbCurrencyIcon).BeginInit(); + flpUsernameCurrency.SuspendLayout(); + flpCurrency.SuspendLayout(); + SuspendLayout(); + // + // pbUserPfp + // + pbUserPfp.BorderStyle = BorderStyle.FixedSingle; + pbUserPfp.Image = Properties.Resources.DefaultPfp; + pbUserPfp.Location = new Point(12, 12); + pbUserPfp.Name = "pbUserPfp"; + pbUserPfp.Size = new Size(128, 126); + pbUserPfp.SizeMode = PictureBoxSizeMode.StretchImage; + pbUserPfp.TabIndex = 2; + pbUserPfp.TabStop = false; + // + // lblUsername + // + lblUsername.AutoSize = true; + lblUsername.Font = new Font("Segoe UI Light", 15F, FontStyle.Bold); + lblUsername.ForeColor = SystemColors.ControlLight; + lblUsername.Location = new Point(3, 0); + lblUsername.Name = "lblUsername"; + lblUsername.Size = new Size(105, 28); + lblUsername.TabIndex = 3; + lblUsername.Text = "Username"; + // + // rtxtBio + // + rtxtBio.Location = new Point(151, 42); + rtxtBio.Name = "rtxtBio"; + rtxtBio.ReadOnly = true; + rtxtBio.Size = new Size(356, 96); + rtxtBio.TabIndex = 4; + rtxtBio.Text = ""; + // + // btnAddContact + // + btnAddContact.BackColor = Color.DodgerBlue; + btnAddContact.FlatAppearance.BorderSize = 0; + btnAddContact.FlatStyle = FlatStyle.Flat; + btnAddContact.Image = Properties.Resources.AddContactIcon; + btnAddContact.Location = new Point(455, 4); + btnAddContact.Name = "btnAddContact"; + btnAddContact.Size = new Size(59, 36); + btnAddContact.TabIndex = 5; + btnAddContact.UseVisualStyleBackColor = false; + btnAddContact.Visible = false; + // + // btnAccept + // + btnAccept.BackColor = Color.DodgerBlue; + btnAccept.FlatAppearance.BorderSize = 0; + btnAccept.FlatStyle = FlatStyle.Flat; + btnAccept.Image = Properties.Resources.AcceptContactIcon; + btnAccept.Location = new Point(404, 4); + btnAccept.Name = "btnAccept"; + btnAccept.Size = new Size(54, 38); + btnAccept.TabIndex = 6; + btnAccept.UseVisualStyleBackColor = false; + btnAccept.Visible = false; + btnAccept.Click += btnAccept_Click; + // + // btnDecline + // + btnDecline.BackColor = Color.DodgerBlue; + btnDecline.FlatAppearance.BorderSize = 0; + btnDecline.FlatStyle = FlatStyle.Flat; + btnDecline.Image = Properties.Resources.DeclineContactIcon; + btnDecline.Location = new Point(455, 3); + btnDecline.Name = "btnDecline"; + btnDecline.Size = new Size(52, 38); + btnDecline.TabIndex = 7; + btnDecline.UseVisualStyleBackColor = false; + btnDecline.Visible = false; + btnDecline.Click += btnDecline_Click; + // + // btnCancelRequest + // + btnCancelRequest.BackColor = Color.DodgerBlue; + btnCancelRequest.FlatAppearance.BorderSize = 0; + btnCancelRequest.FlatStyle = FlatStyle.Flat; + btnCancelRequest.Image = Properties.Resources.CancelRequestIcon; + btnCancelRequest.Location = new Point(400, 1); + btnCancelRequest.Name = "btnCancelRequest"; + btnCancelRequest.Size = new Size(57, 42); + btnCancelRequest.TabIndex = 8; + btnCancelRequest.UseVisualStyleBackColor = false; + btnCancelRequest.Visible = false; + btnCancelRequest.Click += btnCancelRequest_Click; + // + // btnMessage + // + btnMessage.BackColor = Color.DodgerBlue; + btnMessage.FlatAppearance.BorderSize = 0; + btnMessage.FlatStyle = FlatStyle.Flat; + btnMessage.Image = Properties.Resources.MessageIcon; + btnMessage.Location = new Point(405, 1); + btnMessage.Name = "btnMessage"; + btnMessage.Size = new Size(46, 42); + btnMessage.TabIndex = 9; + btnMessage.UseVisualStyleBackColor = false; + btnMessage.Visible = false; + btnMessage.Click += btnMessage_Click; + // + // pbUserStatus + // + pbUserStatus.BackColor = Color.Transparent; + pbUserStatus.Image = Properties.Resources.OfflineIcon; + pbUserStatus.Location = new Point(115, 1); + pbUserStatus.Name = "pbUserStatus"; + pbUserStatus.Size = new Size(32, 32); + pbUserStatus.SizeMode = PictureBoxSizeMode.StretchImage; + pbUserStatus.TabIndex = 10; + pbUserStatus.TabStop = false; + // + // pbCurrencyIcon + // + pbCurrencyIcon.Image = Properties.Resources.CurrencyIcon; + pbCurrencyIcon.Location = new Point(3, 3); + pbCurrencyIcon.Name = "pbCurrencyIcon"; + pbCurrencyIcon.Size = new Size(15, 14); + pbCurrencyIcon.SizeMode = PictureBoxSizeMode.StretchImage; + pbCurrencyIcon.TabIndex = 11; + pbCurrencyIcon.TabStop = false; + // + // lblCurrencyAmount + // + lblCurrencyAmount.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + lblCurrencyAmount.AutoSize = true; + lblCurrencyAmount.BackColor = Color.Transparent; + lblCurrencyAmount.Font = new Font("Segoe UI", 9F, FontStyle.Bold); + lblCurrencyAmount.ForeColor = Color.White; + lblCurrencyAmount.Location = new Point(24, 5); + lblCurrencyAmount.Name = "lblCurrencyAmount"; + lblCurrencyAmount.Size = new Size(14, 15); + lblCurrencyAmount.TabIndex = 12; + lblCurrencyAmount.Text = "0"; + lblCurrencyAmount.TextAlign = ContentAlignment.MiddleCenter; + // + // flpUsernameCurrency + // + flpUsernameCurrency.BackColor = Color.Transparent; + flpUsernameCurrency.Controls.Add(lblUsername); + flpUsernameCurrency.Controls.Add(flpCurrency); + flpUsernameCurrency.Location = new Point(152, 8); + flpUsernameCurrency.Name = "flpUsernameCurrency"; + flpUsernameCurrency.Size = new Size(246, 33); + flpUsernameCurrency.TabIndex = 13; + flpUsernameCurrency.WrapContents = false; + // + // flpCurrency + // + flpCurrency.Controls.Add(pbCurrencyIcon); + flpCurrency.Controls.Add(lblCurrencyAmount); + flpCurrency.Location = new Point(114, 3); + flpCurrency.Name = "flpCurrency"; + flpCurrency.Size = new Size(76, 23); + flpCurrency.TabIndex = 4; + // + // Profile + // + AutoScaleDimensions = new SizeF(6F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(519, 155); + Controls.Add(flpUsernameCurrency); + Controls.Add(btnAccept); + Controls.Add(btnDecline); + Controls.Add(btnCancelRequest); + Controls.Add(pbUserStatus); + Controls.Add(btnAddContact); + Controls.Add(rtxtBio); + Controls.Add(pbUserPfp); + Controls.Add(btnMessage); + Font = new Font("Segoe UI Light", 9F); + FormBorderStyle = FormBorderStyle.FixedDialog; + Icon = (Icon)resources.GetObject("$this.Icon"); + MaximizeBox = false; + MinimizeBox = false; + Name = "Profile"; + StartPosition = FormStartPosition.CenterParent; + Text = "QtC.NET Client - User Profile"; + Load += frmProfile_Load; + ((System.ComponentModel.ISupportInitialize)pbUserPfp).EndInit(); + ((System.ComponentModel.ISupportInitialize)pbUserStatus).EndInit(); + ((System.ComponentModel.ISupportInitialize)pbCurrencyIcon).EndInit(); + flpUsernameCurrency.ResumeLayout(false); + flpUsernameCurrency.PerformLayout(); + flpCurrency.ResumeLayout(false); + flpCurrency.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private PictureBox pbUserPfp; + private Label lblUsername; + private RichTextBox rtxtBio; + private Button btnAddContact; + private Button btnAccept; + private Button btnDecline; + private Button btnCancelRequest; + private Button btnMessage; + private PictureBox pbUserStatus; + private PictureBox pbCurrencyIcon; + private Label lblCurrencyAmount; + private FlowLayoutPanel flpUsernameCurrency; + private FlowLayoutPanel flpCurrency; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/Profile.cs b/qtc-net-client-2/Forms/Profile.cs new file mode 100644 index 0000000..6c1525a --- /dev/null +++ b/qtc-net-client-2/Forms/Profile.cs @@ -0,0 +1,211 @@ +using QtCNETAPI.Dtos.User; +using QtCNETAPI.Services.ApiService; +using QtCNETAPI.Models; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using QtCNETAPI.Services.GatewayService; +using qtc_net_client_2.ClientModel; +using qtc_net_client_2.Properties; + +namespace qtc_net_client_2.Forms +{ + public partial class Profile : Form + { + UserInformationDto _userInformationDto; + IApiService _apiService; + IGatewayService _gatewayService; + public Profile(UserInformationDto userInfo, IApiService apiService, IGatewayService gatewayService) + { + _userInformationDto = userInfo; + _apiService = apiService; + _gatewayService = gatewayService; + InitializeComponent(); + } + + private async void frmProfile_Load(object sender, EventArgs e) + { + lblUsername.Text = _userInformationDto.Username; + lblCurrencyAmount.Text = _userInformationDto.CurrencyAmount.ToString(); + rtxtBio.Text = _userInformationDto.Bio; + + var pfpRes = await _apiService.GetUserProfilePic(_userInformationDto.Id); + if (pfpRes.Success && pfpRes.Data != null) + { + using (var ms = new MemoryStream(pfpRes.Data)) + { + pbUserPfp.Image = Image.FromStream(ms); + ms.Dispose(); + } + } + + var userStatus = (UserStatus)_userInformationDto.Status; + switch(userStatus) + { + case UserStatus.Online: + pbUserStatus.Image = Resources.OnlineIcon; + break; + case UserStatus.Away: + pbUserStatus.Image = Resources.AwayIcon; + break; + case UserStatus.DoNotDisturb: + pbUserStatus.Image = Resources.DNDIcon; + break; + case UserStatus.Offline: + pbUserStatus.Image = Resources.OfflineIcon; + break; + } + + if (_userInformationDto.Id == _apiService.CurrentUser!.Id) + { + btnAddContact.Visible = false; + btnMessage.Visible = false; + return; // do not run contact getting code + } + + var contactsResult = await _apiService.GetCurrentUserContacts(); + if (contactsResult.Success && contactsResult.Data != null) + { + var contact = contactsResult.Data.FirstOrDefault(e => e.UserId == _userInformationDto.Id || e.OwnerId == _userInformationDto.Id); + if (contact != null) + { + if (contact.OwnerId == _apiService.CurrentUser.Id) + { + // the user requesting this profile initiated a contact relationship with this user + switch (contact.OwnerStatus) + { + case Contact.ContactStatus.AwaitingApprovalFromOther: + btnAddContact.Enabled = false; + + using (var ms = new MemoryStream(Resources.RequestSentIcon)) { btnAddContact.Image = Image.FromStream(ms); ms.Dispose(); } + btnCancelRequest.Visible = true; + break; + case Contact.ContactStatus.Accepted: + btnAddContact.Enabled = true; + btnAddContact.Image = Resources.RemoveContactIcon; + btnAddContact.Click += btnAddContact_Click_Remove; + if (_userInformationDto.Status >= 1) btnMessage.Visible = true; + break; + } + } + else if (contact.UserId == _apiService.CurrentUser.Id) + { + // the user requesting this profile did not initiate a contact relationship with the user + switch (contact.UserStatus) + { + case Contact.ContactStatus.AwaitingApprovalFromSelf: + btnAddContact.Visible = false; + + btnAccept.Visible = true; + btnDecline.Visible = true; + btnCancelRequest.Visible = false; + break; + case Contact.ContactStatus.Accepted: + btnAccept.Visible = false; + btnDecline.Visible = false; + btnCancelRequest.Visible = false; + + btnAddContact.Visible = true; + btnAddContact.Image = Resources.RemoveContactIcon; + btnAddContact.Click += btnAddContact_Click_Remove; + if (_userInformationDto.Status >= 1) btnMessage.Visible = true; + break; + } + } + } + } + else + { + btnAddContact.Visible = true; + btnAddContact.Click += btnAddContact_Click_Add; + } + } + + private async void btnAddContact_Click_Add(object sender, EventArgs e) + { + var result = await _apiService.AddContactToCurrentUser(_userInformationDto.Id); + if (result.Success) + { + btnAddContact.Enabled = false; + using (var ms = new MemoryStream(Resources.RequestSentIcon)) { btnAddContact.Image = Image.FromStream(ms); ms.Dispose(); } + btnCancelRequest.Visible = true; + + await _gatewayService.RefreshContactsForUser(_userInformationDto); + } + } + + private async void btnAddContact_Click_Remove(object sender, EventArgs e) + { + var result = await _apiService.RemoveContactFromCurrentUser(_userInformationDto.Id); + if (result.Success) + { + btnAddContact.Image = Resources.AddContactIcon; + btnAddContact.Click += btnAddContact_Click_Add; + btnMessage.Visible = false; + + await _gatewayService.RefreshContactsForUser(_userInformationDto); + } + } + + private async void btnAccept_Click(object sender, EventArgs e) + { + var result = await _apiService.AcceptContactRequest(_userInformationDto.Id); + if (result.Success) + { + btnAccept.Visible = false; + btnDecline.Visible = false; + + btnAddContact.Visible = true; + btnAddContact.Image = Resources.RemoveContactIcon; + btnAddContact.Click += btnAddContact_Click_Remove; + if (_userInformationDto.Status >= 1) btnMessage.Visible = true; + + await _gatewayService.RefreshContactsForUser(_userInformationDto); + } + } + + private async void btnDecline_Click(object sender, EventArgs e) + { + var result = await _apiService.RemoveContactFromCurrentUser(_userInformationDto.Id); + if (result.Success) + { + btnAccept.Visible = false; + btnDecline.Visible = false; + + btnAddContact.Visible = true; + btnAddContact.Image = Resources.AddContactIcon; + btnAddContact.Click += btnAddContact_Click_Add; + + await _gatewayService.RefreshContactsForUser(_userInformationDto); + } + } + + private async void btnCancelRequest_Click(object sender, EventArgs e) + { + var result = await _apiService.RemoveContactFromCurrentUser(_userInformationDto.Id); + if (result.Success) + { + btnAddContact.Enabled = true; + btnAddContact.Image = Resources.AddContactIcon; + btnAddContact.Click += btnAddContact_Click_Add; + + btnCancelRequest.Visible = false; + + await _gatewayService.RefreshContactsForUser(_userInformationDto); + } + } + + private void btnMessage_Click(object sender, EventArgs e) + { + DirectMessage frmDirectMessage = new DirectMessage(_gatewayService, _apiService, _userInformationDto); + Close(); + frmDirectMessage.Show(); + } + } +} diff --git a/qtc-net-client-2/Forms/Profile.resx b/qtc-net-client-2/Forms/Profile.resx new file mode 100644 index 0000000..54df8da --- /dev/null +++ b/qtc-net-client-2/Forms/Profile.resx @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEACAUAAAEACABZBAAAFgAAACgAAAAIAAAACgAAAAEACAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAA + AADy4bcA18WYAO/LcwDPyr0Aq6urALKysgC0sKcAgYGBAK+KLwDHwbEAp6enANvChQCrkE4AypQOAN3X + xwDV1dUAwsLCALy0oACCgX4AtYwnAL+rewCCdFQAnncVAJqUhwB5eXkAgICAAP///wAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAFBUWFxgYGBkREhMODw8PEAsMDQ4PDw8QBgcICQQEBAoAAQIDBAQEBQAAAAAAAAAAAA== + + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/ProfileEdit.Designer.cs b/qtc-net-client-2/Forms/ProfileEdit.Designer.cs new file mode 100644 index 0000000..32429b8 --- /dev/null +++ b/qtc-net-client-2/Forms/ProfileEdit.Designer.cs @@ -0,0 +1,114 @@ +namespace qtc_net_client_2.Forms +{ + partial class ProfileEdit + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + tbUsername = new TextBox(); + lblUsername = new Label(); + rtxtBio = new RichTextBox(); + lblBio = new Label(); + btnSave = new Button(); + SuspendLayout(); + // + // tbUsername + // + tbUsername.Location = new Point(76, 17); + tbUsername.Name = "tbUsername"; + tbUsername.Size = new Size(257, 23); + tbUsername.TabIndex = 0; + // + // lblUsername + // + lblUsername.AutoSize = true; + lblUsername.Location = new Point(12, 20); + lblUsername.Name = "lblUsername"; + lblUsername.Size = new Size(58, 15); + lblUsername.TabIndex = 1; + lblUsername.Text = "Username"; + // + // rtxtBio + // + rtxtBio.Location = new Point(76, 46); + rtxtBio.Name = "rtxtBio"; + rtxtBio.Size = new Size(257, 96); + rtxtBio.TabIndex = 2; + rtxtBio.Text = ""; + // + // lblBio + // + lblBio.AutoSize = true; + lblBio.Location = new Point(47, 49); + lblBio.Name = "lblBio"; + lblBio.Size = new Size(23, 15); + lblBio.TabIndex = 3; + lblBio.Text = "Bio"; + // + // btnSave + // + btnSave.ForeColor = Color.Black; + btnSave.Location = new Point(76, 148); + btnSave.Name = "btnSave"; + btnSave.Size = new Size(43, 23); + btnSave.TabIndex = 4; + btnSave.Text = "Save"; + btnSave.UseVisualStyleBackColor = true; + btnSave.Click += btnSave_Click; + // + // frmProfileEdit + // + AutoScaleDimensions = new SizeF(6F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(345, 187); + Controls.Add(btnSave); + Controls.Add(lblBio); + Controls.Add(rtxtBio); + Controls.Add(lblUsername); + Controls.Add(tbUsername); + Font = new Font("Segoe UI Light", 9F); + ForeColor = SystemColors.ControlLight; + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + Name = "frmProfileEdit"; + StartPosition = FormStartPosition.CenterParent; + Text = "QtC.NET Client - Edit Profile"; + Load += frmProfileEdit_Load; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private TextBox tbUsername; + private Label lblUsername; + private RichTextBox rtxtBio; + private Label lblBio; + private Button btnSave; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/ProfileEdit.cs b/qtc-net-client-2/Forms/ProfileEdit.cs new file mode 100644 index 0000000..db4cb2d --- /dev/null +++ b/qtc-net-client-2/Forms/ProfileEdit.cs @@ -0,0 +1,59 @@ +using QtCNETAPI.Dtos.User; +using QtCNETAPI.Services.ApiService; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace qtc_net_client_2.Forms +{ + public partial class ProfileEdit : Form + { + IApiService _apiService; + public ProfileEdit(IApiService apiService) + { + _apiService = apiService; + InitializeComponent(); + } + + private void frmProfileEdit_Load(object sender, EventArgs e) + { + tbUsername.Text = _apiService.CurrentUser!.Username; + rtxtBio.Text = _apiService.CurrentUser!.Bio; + } + + private async void btnSave_Click(object sender, EventArgs e) + { + if(!string.IsNullOrEmpty(tbUsername.Text) && (tbUsername.Text != _apiService.CurrentUser!.Username || rtxtBio.Text != _apiService.CurrentUser!.Bio)) + { + // update user info + UserUpdateInformationDto userUpdateInformationDto = new UserUpdateInformationDto + { + Id = _apiService.CurrentUser.Id, + Username = tbUsername.Text, + Bio = rtxtBio.Text, + DateOfBirth = _apiService.CurrentUser.DateOfBirth + }; + + var res = await _apiService.UpdateUserInformationAsync(userUpdateInformationDto); + + if (res.Success) + { + DialogResult = DialogResult.OK; + Close(); + } + else + { + MessageBox.Show(res.Message, "Info Update Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + DialogResult = DialogResult.Cancel; + Close(); + } + } + } + } +} diff --git a/qtc-net-client-2/Forms/ProfileEdit.resx b/qtc-net-client-2/Forms/ProfileEdit.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/qtc-net-client-2/Forms/ProfileEdit.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/Register.Designer.cs b/qtc-net-client-2/Forms/Register.Designer.cs new file mode 100644 index 0000000..76cb81e --- /dev/null +++ b/qtc-net-client-2/Forms/Register.Designer.cs @@ -0,0 +1,241 @@ +namespace qtc_net_client_2.Forms +{ + partial class Register + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Register)); + pbLoginBanner = new PictureBox(); + lblEmail = new Label(); + tbEmail = new TextBox(); + lblPassword = new Label(); + tbPassword = new TextBox(); + lblConPassword = new Label(); + tbConPassword = new TextBox(); + lblConEmail = new Label(); + tbConEmail = new TextBox(); + dtpDateOfBirth = new DateTimePicker(); + lblDateOfBirth = new Label(); + btnRegister = new Button(); + cbAgreement = new CheckBox(); + lblUsername = new Label(); + tbUsername = new TextBox(); + ((System.ComponentModel.ISupportInitialize)pbLoginBanner).BeginInit(); + SuspendLayout(); + // + // pbLoginBanner + // + pbLoginBanner.Image = Properties.Resources.LoginBanner; + pbLoginBanner.Location = new Point(-2, -1); + pbLoginBanner.Name = "pbLoginBanner"; + pbLoginBanner.Size = new Size(543, 99); + pbLoginBanner.SizeMode = PictureBoxSizeMode.StretchImage; + pbLoginBanner.TabIndex = 1; + pbLoginBanner.TabStop = false; + // + // lblEmail + // + lblEmail.AutoSize = true; + lblEmail.Font = new Font("Segoe UI Light", 9F); + lblEmail.ForeColor = SystemColors.ControlLight; + lblEmail.Location = new Point(29, 143); + lblEmail.Name = "lblEmail"; + lblEmail.Size = new Size(33, 15); + lblEmail.TabIndex = 4; + lblEmail.Text = "Email"; + // + // tbEmail + // + tbEmail.Location = new Point(68, 140); + tbEmail.Name = "tbEmail"; + tbEmail.Size = new Size(461, 23); + tbEmail.TabIndex = 3; + // + // lblPassword + // + lblPassword.AutoSize = true; + lblPassword.Font = new Font("Segoe UI Light", 9F); + lblPassword.ForeColor = SystemColors.ControlLight; + lblPassword.Location = new Point(7, 172); + lblPassword.Name = "lblPassword"; + lblPassword.Size = new Size(55, 15); + lblPassword.TabIndex = 6; + lblPassword.Text = "Password"; + // + // tbPassword + // + tbPassword.Location = new Point(68, 169); + tbPassword.Name = "tbPassword"; + tbPassword.PasswordChar = '*'; + tbPassword.Size = new Size(461, 23); + tbPassword.TabIndex = 5; + // + // lblConPassword + // + lblConPassword.AutoSize = true; + lblConPassword.Font = new Font("Segoe UI Light", 6F); + lblConPassword.ForeColor = SystemColors.ControlLight; + lblConPassword.Location = new Point(2, 232); + lblConPassword.Name = "lblConPassword"; + lblConPassword.Size = new Size(64, 11); + lblConPassword.TabIndex = 10; + lblConPassword.Text = "Confirm Password"; + // + // tbConPassword + // + tbConPassword.Location = new Point(68, 227); + tbConPassword.Name = "tbConPassword"; + tbConPassword.PasswordChar = '*'; + tbConPassword.Size = new Size(461, 23); + tbConPassword.TabIndex = 9; + // + // lblConEmail + // + lblConEmail.AutoSize = true; + lblConEmail.Font = new Font("Segoe UI Light", 7F); + lblConEmail.ForeColor = SystemColors.ControlLight; + lblConEmail.Location = new Point(2, 203); + lblConEmail.Name = "lblConEmail"; + lblConEmail.Size = new Size(63, 12); + lblConEmail.TabIndex = 8; + lblConEmail.Text = "Confirm Email"; + // + // tbConEmail + // + tbConEmail.Location = new Point(68, 198); + tbConEmail.Name = "tbConEmail"; + tbConEmail.Size = new Size(461, 23); + tbConEmail.TabIndex = 7; + // + // dtpDateOfBirth + // + dtpDateOfBirth.Location = new Point(68, 256); + dtpDateOfBirth.Name = "dtpDateOfBirth"; + dtpDateOfBirth.Size = new Size(461, 23); + dtpDateOfBirth.TabIndex = 11; + // + // lblDateOfBirth + // + lblDateOfBirth.AutoSize = true; + lblDateOfBirth.Font = new Font("Segoe UI Light", 8F); + lblDateOfBirth.ForeColor = SystemColors.ControlLight; + lblDateOfBirth.Location = new Point(0, 260); + lblDateOfBirth.Name = "lblDateOfBirth"; + lblDateOfBirth.Size = new Size(66, 13); + lblDateOfBirth.TabIndex = 12; + lblDateOfBirth.Text = "Date Of Birth"; + // + // btnRegister + // + btnRegister.Location = new Point(68, 285); + btnRegister.Name = "btnRegister"; + btnRegister.Size = new Size(75, 23); + btnRegister.TabIndex = 13; + btnRegister.Text = "Register"; + btnRegister.UseVisualStyleBackColor = true; + btnRegister.Click += btnRegister_Click; + // + // cbAgreement + // + cbAgreement.AutoSize = true; + cbAgreement.Font = new Font("Segoe UI Light", 9F); + cbAgreement.ForeColor = SystemColors.ControlLight; + cbAgreement.Location = new Point(149, 288); + cbAgreement.Name = "cbAgreement"; + cbAgreement.Size = new Size(356, 19); + cbAgreement.TabIndex = 14; + cbAgreement.Text = "By Registering, I Agree To Any Rules Or Terms This Server Imposes"; + cbAgreement.UseVisualStyleBackColor = true; + // + // lblUsername + // + lblUsername.AutoSize = true; + lblUsername.Font = new Font("Segoe UI Light", 9F); + lblUsername.ForeColor = SystemColors.ControlLight; + lblUsername.Location = new Point(8, 114); + lblUsername.Name = "lblUsername"; + lblUsername.Size = new Size(58, 15); + lblUsername.TabIndex = 16; + lblUsername.Text = "Username"; + // + // tbUsername + // + tbUsername.Location = new Point(68, 111); + tbUsername.Name = "tbUsername"; + tbUsername.Size = new Size(461, 23); + tbUsername.TabIndex = 15; + // + // frmRegister + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(537, 319); + Controls.Add(lblUsername); + Controls.Add(tbUsername); + Controls.Add(cbAgreement); + Controls.Add(btnRegister); + Controls.Add(lblDateOfBirth); + Controls.Add(dtpDateOfBirth); + Controls.Add(lblConPassword); + Controls.Add(tbConPassword); + Controls.Add(lblConEmail); + Controls.Add(tbConEmail); + Controls.Add(lblPassword); + Controls.Add(tbPassword); + Controls.Add(lblEmail); + Controls.Add(tbEmail); + Controls.Add(pbLoginBanner); + FormBorderStyle = FormBorderStyle.FixedDialog; + Icon = (Icon)resources.GetObject("$this.Icon"); + Name = "frmRegister"; + StartPosition = FormStartPosition.CenterParent; + Text = "QtC.NET Client - Register"; + ((System.ComponentModel.ISupportInitialize)pbLoginBanner).EndInit(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private PictureBox pbLoginBanner; + private Label lblEmail; + private TextBox tbEmail; + private Label lblPassword; + private TextBox tbPassword; + private Label lblConPassword; + private TextBox tbConPassword; + private Label lblConEmail; + private TextBox tbConEmail; + private DateTimePicker dtpDateOfBirth; + private Label lblDateOfBirth; + private Button btnRegister; + private CheckBox cbAgreement; + private Label lblUsername; + private TextBox tbUsername; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/Register.cs b/qtc-net-client-2/Forms/Register.cs new file mode 100644 index 0000000..270f0e0 --- /dev/null +++ b/qtc-net-client-2/Forms/Register.cs @@ -0,0 +1,68 @@ +using QtCNETAPI.Services.ApiService; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace qtc_net_client_2.Forms +{ + public partial class Register : Form + { + IApiService _apiService; + public Register(IApiService apiService) + { + _apiService = apiService; + InitializeComponent(); + } + + private async void btnRegister_Click(object sender, EventArgs e) + { + if( !string.IsNullOrEmpty(tbUsername.Text) && + !string.IsNullOrEmpty(tbEmail.Text) && + !string.IsNullOrEmpty(tbPassword.Text) && + !string.IsNullOrEmpty(tbConEmail.Text) && + !string.IsNullOrEmpty(tbConPassword.Text) && + tbConEmail.Text == tbEmail.Text && + tbConPassword.Text == tbPassword.Text && + cbAgreement.Checked) + { + DisableControls(); + + var registerResult = await _apiService.RegisterAsync(new QtCNETAPI.Dtos.User.UserDto + { + Username = tbUsername.Text, + Email = tbEmail.Text, + Password = tbPassword.Text, + DateOfBirth = dtpDateOfBirth.Value + }); + + if(registerResult.Success) + { + DialogResult = DialogResult.OK; + Close(); + } else + { + MessageBox.Show(registerResult.Message, "Registration Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + DialogResult = DialogResult.Cancel; + Close(); + } + } + } + + private void DisableControls() + { + tbUsername.Enabled = false; + tbEmail.Enabled = false; + tbConEmail.Enabled = false; + tbPassword.Enabled = false; + tbConPassword.Enabled = false; + dtpDateOfBirth.Enabled = false; + cbAgreement.Enabled = false; + } + } +} diff --git a/qtc-net-client-2/Forms/Register.resx b/qtc-net-client-2/Forms/Register.resx new file mode 100644 index 0000000..db6c178 --- /dev/null +++ b/qtc-net-client-2/Forms/Register.resx @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAABMLAAATCwAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAO24wAMtuMAFjbjABy24wAetuMAHHbjABW24wAL9uMAAzbjAAA24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA24wAANuMAADbjAAf24wAdNuMAMTbjADu24wA/duMAP/bjAD/24wA/9uMAPzbjADs24wAv9uM + AG3bjAAa24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAJ24wAYduMANXbjAD+24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/duMAM7bjABY24wABtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAA24wAEtuMAJPbjAD324wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPTbjACH24wADtuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMABDbjACf24wA/duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPzbjACT24wAC9uMAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAE24wAh9uMAP3bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAPrbjAB524wAAtuM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAE3bjADw24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AOrbjABA24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAQ24wAvduMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAK/bjAAK24wAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMAFHbjAD324wA/9uM + AP/bjAD/24wA/9uLAP/biwD/24wA/9uMAP/bjAD/24wA/9uMAP/biwD/24wA/9uMAP/bjAD/24sA/9uL + AP/bjAD/24wA/9uMAP/bjAD/24wA8tuMAEPbjAAAAAAAAAAAAAAAAAAAAAAAANuMAADbjAAC24wAntuM + AP/bjAD/24wA/9uLAP/ckQz/4Jwj/9+YG//bjQP/3JEM/9yPB//biwD/3ZIN/96YGv/bjQP/24wA/9uM + Af/elRX/4Jwk/92TD//biwD/24wA/9uMAP/bjAD/24wAj9uMAADbjAAAAAAAAAAAAAAAAAAA24wAANuM + ABbbjADU24wA/9uMAP/biwD/4qM1//Tet//57dj/+OnR/+/Ok//y16f/5atG/92TD//y2Kr/9N63/96V + FP/bjAL/6Lhi//fnzf/47Nf/9uPB/+WrR//biwD/24wA/9uMAP/bjADH24wAD9uMAAAAAAAAAAAAAAAA + AADbjAAA24wAMtuMAO7bjAD/24wA/92TD//14b3/89mt/+SoP//w0Jj///////Parv/dkg3/4qIy//rw + 3v/msFH/24wA/+OlOf/68N//7MJ5/+KkNf/uy47/+OrS/+CcJP/biwD/24wA/9uMAObbjAAm24wAAAAA + AAAAAAAAAAAAANuMAADbjABI24wA+duMAP/biwD/4qIy//nv3f/iozX/3pUX//LWpv/25cj/8tis/9uM + AP/ipDb/+ezY/+CcJ//aiQD/68F3//bjwv/ckAz/24oA/92RD//puWX/4Jwl/9uLAP/bjAD/24wA89uM + ADrbjAAAAAAAAAAAAAAAAAAA24wAANuMAFHbjAD824wA/9uKAP/jpzz/+e7b/+CdJ//bjAH/3ZMQ/+zD + fP/137v/240D/+KkNv/57Nj/4J0n/9qJAP/tx4X/89yz/9uNBP/bjAD/24wA/9qKAP/biwD/24wA/9uM + AP/bjAD324wAQtuMAAAAAAAAAAAAAAAAAADbjAAA24wATNuMAPrbjAD/24oA/+OnPP/57tv/4J0n/9uL + AP/aigD/7MJ6//Xfu//cjgX/5axI//rv3v/kqED/24sA/+3Hhf/z3LL/244E/9uMAP/bjAD/24sA/9uM + AP/bjAD/24wA/9uMAPXbjAA924wAAAAAAAAAAAAAAAAAANuMAADbjAA524wA8tuMAP/bigD/46Y6//nu + 2//gnin/24sA/9qKAP/sw37/9N+4/9yRC//x0p7//v37//Tdtv/dkxD/7cWB//Tdtv/cjgX/24wA/9uM + Av/elRb/3JAK/9uMAP/bjAD/24wA69uMACzbjAAAAAAAAAAAAAAAAAAA24wAANuMAB7bjADd24wA/9uL + AP/gmyL/+e3Z/+i4Yv/bjAD/3ZMP//TdtP/w0Jj/24sA/+WuS//68eD/5KpD/9uLAP/otl3/+e3Y/+Gf + Kv/biwD/46c8//XiwP/iozT/24sA/9uMAP/bjADS24wAFduMAAAAAAAAAAAAAAAAAADbjAAA24wABtuM + AK/bjAD/24wA/9uNAv/sxH3/+vDg//LZq//14sH/+OvU/+KkNv/aigD/4Z4p//HUov/fmB3/24oA/96V + Fv/03bX/+OnQ//LWpv/57dn/8NGa/9yQCv/bjAD/24wA/9uMAKDbjAAC24wAAAAAAAAAAAAAAAAAANuM + AADbjAAA24wAZtuMAP3bjAD/24wA/9yPCf/mr0//7cmI/+zCef/hoCz/24wA/9uMAP/bjQL/3I8I/9uN + Af/bjAD/24sA/96XGf/pu2r/7sqK/+i1XP/dkg//24sA/9uMAP/bjAD624wAVtuMAADbjAAAAAAAAAAA + AAAAAAAAAAAAANuMAADbjAAc24wA09uMAP/bjAD/24wA/9qKAP/biwD/2ooA/9uLAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24sA/9qKAP/biwD/2ooA/9uMAP/bjAD/24wA/9uMAMfbjAAU24wAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjABr24wA+9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD324wAXNuM + AADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAA7bjACr24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AJ7bjAAJ24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuMACTbjADG24wA/9uM + AP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAC724wAHduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbjAAA24wAANuM + ACvbjADA24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD+24wAtduMACPbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADbjAAA24wAANuMABzbjACV24wA8duMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD/24wA7tuMAIvbjAAW24wAANuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAAbbjABG24wAqtuMAOnbjAD+24wA/9uMAP/bjAD/24wA/9uM + AP/bjAD924wA59uMAKTbjAA/24wABNuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuMAADbjAAH24wALtuMAGXbjACS24wAq9uM + ALPbjACq24wAj9uMAGHbjAAq24wABduMAADbjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA24wAANuM + AADbjAAD24wABduMAALbjAAA24wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA//////////////////AH///AAf//AAB//gAAP/wAAB/4AAAP+AAAD/AA + AAfwAAAH4AAAB+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD8AAAB/AAAAf4AAAP+AAAD/wA + AB/+AAA//wAAf/+AAP//4AP///4///////8= + + + \ No newline at end of file diff --git a/qtc-net-client-2/Forms/TokenJackpotSpinner.Designer.cs b/qtc-net-client-2/Forms/TokenJackpotSpinner.Designer.cs new file mode 100644 index 0000000..7c39bb2 --- /dev/null +++ b/qtc-net-client-2/Forms/TokenJackpotSpinner.Designer.cs @@ -0,0 +1,85 @@ +namespace qtc_net_client_2.Forms +{ + partial class TokenJackpotSpinner + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + lblTokensWon = new Label(); + btnClaim = new Button(); + SuspendLayout(); + // + // lblTokensWon + // + lblTokensWon.AutoSize = true; + lblTokensWon.Font = new Font("Segoe UI Black", 13F); + lblTokensWon.Location = new Point(137, 30); + lblTokensWon.Name = "lblTokensWon"; + lblTokensWon.Size = new Size(137, 25); + lblTokensWon.TabIndex = 0; + lblTokensWon.Text = "0 Tokens Won"; + lblTokensWon.TextAlign = ContentAlignment.MiddleCenter; + // + // btnClaim + // + btnClaim.Enabled = false; + btnClaim.Location = new Point(167, 76); + btnClaim.Name = "btnClaim"; + btnClaim.Size = new Size(75, 23); + btnClaim.TabIndex = 1; + btnClaim.Text = "Claim"; + btnClaim.UseVisualStyleBackColor = true; + btnClaim.Click += btnClaim_Click; + // + // TokenJackpotSpinner + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + BackColor = Color.DodgerBlue; + ClientSize = new Size(427, 125); + Controls.Add(btnClaim); + Controls.Add(lblTokensWon); + DoubleBuffered = true; + ForeColor = Color.Black; + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + Name = "TokenJackpotSpinner"; + StartPosition = FormStartPosition.CenterScreen; + Text = "QtC.NET Client - Daily Jackpot Spin"; + FormClosing += TokenJackpotSpinner_FormClosing; + FormClosed += TokenJackpotSpinner_FormClosed; + Load += TokenJackpotSpinner_Load; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label lblTokensWon; + private Button btnClaim; + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Forms/TokenJackpotSpinner.cs b/qtc-net-client-2/Forms/TokenJackpotSpinner.cs new file mode 100644 index 0000000..2a3c8c9 --- /dev/null +++ b/qtc-net-client-2/Forms/TokenJackpotSpinner.cs @@ -0,0 +1,77 @@ +using qtc_net_client_2.Services; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace qtc_net_client_2.Forms +{ + public partial class TokenJackpotSpinner : Form + { + public int TokensWon { get; private set; } + + private bool AllowClose = false; + private AudioService _audioService = new(); + public TokenJackpotSpinner() + { + InitializeComponent(); + } + + private async void TokenJackpotSpinner_Load(object sender, EventArgs e) + { + btnClaim.Enabled = false; + AllowClose = false; + await StartSpinAnimation(lblTokensWon); + } + + private void TokenJackpotSpinner_FormClosed(object sender, FormClosedEventArgs e) + { + DialogResult = DialogResult.OK; + Close(); + } + + private void TokenJackpotSpinner_FormClosing(object sender, FormClosingEventArgs e) + { + if (!AllowClose) e.Cancel = true; + } + + private void btnClaim_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + Close(); + } + + public async Task StartSpinAnimation(Label label) + { + if (label.IsHandleCreated) + { + Random rnd = new Random(); + _audioService.PlaySoundEffect("sndTokenSpinLoop"); + + while (_audioService.OutputDevice?.PlaybackState == NAudio.Wave.PlaybackState.Playing) + { + label.BeginInvoke(delegate () { label.Text = $"{rnd.Next(0, 300)} Tokens Won"; }); + await Task.Delay(10); + } + + var win = rnd.Next(0, 300); + + label.BeginInvoke(delegate () + { + label.Text = $"{win} Tokens Won"; + btnClaim.Enabled = true; + _audioService.PlaySoundEffect("sndTokenWin"); + }); + + _audioService.Dispose(); + AllowClose = true; + TokensWon = win; + } + } + } +} diff --git a/qtc-net-client-2/Forms/TokenJackpotSpinner.resx b/qtc-net-client-2/Forms/TokenJackpotSpinner.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/qtc-net-client-2/Forms/TokenJackpotSpinner.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/qtc-net-client-2/Icons/AcceptContactIcon.png b/qtc-net-client-2/Icons/AcceptContactIcon.png new file mode 100644 index 0000000..a4fe6d7 Binary files /dev/null and b/qtc-net-client-2/Icons/AcceptContactIcon.png differ diff --git a/qtc-net-client-2/Icons/AddContactIcon.png b/qtc-net-client-2/Icons/AddContactIcon.png new file mode 100644 index 0000000..4f47d6e Binary files /dev/null and b/qtc-net-client-2/Icons/AddContactIcon.png differ diff --git a/qtc-net-client-2/Icons/AwayIcon.png b/qtc-net-client-2/Icons/AwayIcon.png new file mode 100644 index 0000000..1d7c1e1 Binary files /dev/null and b/qtc-net-client-2/Icons/AwayIcon.png differ diff --git a/qtc-net-client-2/Icons/CancelRequestIcon.png b/qtc-net-client-2/Icons/CancelRequestIcon.png new file mode 100644 index 0000000..575e430 Binary files /dev/null and b/qtc-net-client-2/Icons/CancelRequestIcon.png differ diff --git a/qtc-net-client-2/Icons/ContactsIcon.ico b/qtc-net-client-2/Icons/ContactsIcon.ico new file mode 100644 index 0000000..51b6158 Binary files /dev/null and b/qtc-net-client-2/Icons/ContactsIcon.ico differ diff --git a/qtc-net-client-2/Icons/ContactsIcon.png b/qtc-net-client-2/Icons/ContactsIcon.png new file mode 100644 index 0000000..439d0f4 Binary files /dev/null and b/qtc-net-client-2/Icons/ContactsIcon.png differ diff --git a/qtc-net-client-2/Icons/CurrencyIcon.png b/qtc-net-client-2/Icons/CurrencyIcon.png new file mode 100644 index 0000000..50fda3e Binary files /dev/null and b/qtc-net-client-2/Icons/CurrencyIcon.png differ diff --git a/qtc-net-client-2/Icons/DNDIcon.png b/qtc-net-client-2/Icons/DNDIcon.png new file mode 100644 index 0000000..9f40d39 Binary files /dev/null and b/qtc-net-client-2/Icons/DNDIcon.png differ diff --git a/qtc-net-client-2/Icons/DeclineContactIcon.png b/qtc-net-client-2/Icons/DeclineContactIcon.png new file mode 100644 index 0000000..c4ec267 Binary files /dev/null and b/qtc-net-client-2/Icons/DeclineContactIcon.png differ diff --git a/qtc-net-client-2/Icons/MessageIcon.png b/qtc-net-client-2/Icons/MessageIcon.png new file mode 100644 index 0000000..9cb7de7 Binary files /dev/null and b/qtc-net-client-2/Icons/MessageIcon.png differ diff --git a/qtc-net-client-2/Icons/OfflineIcon.png b/qtc-net-client-2/Icons/OfflineIcon.png new file mode 100644 index 0000000..83b3df8 Binary files /dev/null and b/qtc-net-client-2/Icons/OfflineIcon.png differ diff --git a/qtc-net-client-2/Icons/OnlineIcon.png b/qtc-net-client-2/Icons/OnlineIcon.png new file mode 100644 index 0000000..8441506 Binary files /dev/null and b/qtc-net-client-2/Icons/OnlineIcon.png differ diff --git a/qtc-net-client-2/Icons/RemoveContactIcon.png b/qtc-net-client-2/Icons/RemoveContactIcon.png new file mode 100644 index 0000000..47c2d70 Binary files /dev/null and b/qtc-net-client-2/Icons/RemoveContactIcon.png differ diff --git a/qtc-net-client-2/Icons/RequestSentIcon.png b/qtc-net-client-2/Icons/RequestSentIcon.png new file mode 100644 index 0000000..b28a833 Binary files /dev/null and b/qtc-net-client-2/Icons/RequestSentIcon.png differ diff --git a/qtc-net-client-2/Icons/RoomsChatIcon.ico b/qtc-net-client-2/Icons/RoomsChatIcon.ico new file mode 100644 index 0000000..ea00dfb Binary files /dev/null and b/qtc-net-client-2/Icons/RoomsChatIcon.ico differ diff --git a/qtc-net-client-2/Icons/RoomsChatIcon.png b/qtc-net-client-2/Icons/RoomsChatIcon.png new file mode 100644 index 0000000..b20ae52 Binary files /dev/null and b/qtc-net-client-2/Icons/RoomsChatIcon.png differ diff --git a/qtc-net-client-2/Icons/SendIcon.png b/qtc-net-client-2/Icons/SendIcon.png new file mode 100644 index 0000000..d74e96d Binary files /dev/null and b/qtc-net-client-2/Icons/SendIcon.png differ diff --git a/qtc-net-client-2/Program.cs b/qtc-net-client-2/Program.cs new file mode 100644 index 0000000..d8af02e --- /dev/null +++ b/qtc-net-client-2/Program.cs @@ -0,0 +1,60 @@ +using qtc_net_client_2.ClientModel; +using QtCNETAPI.Services.ApiService; +using QtCNETAPI.Services.GatewayService; +using System.Text.Json; +using System.Threading.Tasks; + +namespace qtc_net_client_2 +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static async Task Main() + { + Config clientConfig = new Config(); + + // find config file + if(!File.Exists("./config.json")) + { + // create it using default config model + string configJson = JsonSerializer.Serialize(clientConfig, options: new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText("./config.json", configJson); + } else + { + // use config in file + Config? fileConfig = JsonSerializer.Deserialize(File.ReadAllText("./config.json")); + if(fileConfig != null) + clientConfig = fileConfig; + } + + // instantiate new ApiService and GatewayService for this session + // this will keep the gateway thread in the main thread (i think) + IApiService api = new ApiService(clientConfig.ApiEndpoint); + IGatewayService gateway = new GatewayService(clientConfig.GatewayEndpoint, api); + + // ping api + var pingResult = api.PingServerAsync().GetAwaiter().GetResult(); + if (!pingResult.Success) + { + MessageBox.Show("The API Specified In The Config Could Not Be Reached.\nCheck The URL Specified, Otherwise Contact The Server Admin.", "Uh Oh.", MessageBoxButtons.OK, MessageBoxIcon.Error); + Environment.Exit(1); + } + + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new Main(api, gateway)); + + // if application loop is exited, dispose everything + await gateway.DisposeAsync(); + + api = null; + gateway = null; + + Environment.Exit(0); + } + } +} \ No newline at end of file diff --git a/qtc-net-client-2/Properties/Resources.Designer.cs b/qtc-net-client-2/Properties/Resources.Designer.cs new file mode 100644 index 0000000..c224803 --- /dev/null +++ b/qtc-net-client-2/Properties/Resources.Designer.cs @@ -0,0 +1,213 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace qtc_net_client_2.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("qtc_net_client_2.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap AcceptContactIcon { + get { + object obj = ResourceManager.GetObject("AcceptContactIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap AddContactIcon { + get { + object obj = ResourceManager.GetObject("AddContactIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap AwayIcon { + get { + object obj = ResourceManager.GetObject("AwayIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap CancelRequestIcon { + get { + object obj = ResourceManager.GetObject("CancelRequestIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap CurrencyIcon { + get { + object obj = ResourceManager.GetObject("CurrencyIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DeclineContactIcon { + get { + object obj = ResourceManager.GetObject("DeclineContactIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DefaultPfp { + get { + object obj = ResourceManager.GetObject("DefaultPfp", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DNDIcon { + get { + object obj = ResourceManager.GetObject("DNDIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap LoginBanner { + get { + object obj = ResourceManager.GetObject("LoginBanner", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap MessageIcon { + get { + object obj = ResourceManager.GetObject("MessageIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap OfflineIcon { + get { + object obj = ResourceManager.GetObject("OfflineIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap OnlineIcon { + get { + object obj = ResourceManager.GetObject("OnlineIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap RemoveContactIcon { + get { + object obj = ResourceManager.GetObject("RemoveContactIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] RequestSentIcon { + get { + object obj = ResourceManager.GetObject("RequestSentIcon", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap SendIcon { + get { + object obj = ResourceManager.GetObject("SendIcon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/qtc-net-client-2/Properties/Resources.resx b/qtc-net-client-2/Properties/Resources.resx new file mode 100644 index 0000000..8d7726e --- /dev/null +++ b/qtc-net-client-2/Properties/Resources.resx @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Icons\SendIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\DefaultPfp.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\OfflineIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\OnlineIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\CancelRequestIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\DNDIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\AwayIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\AddContactIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\RequestSentIcon.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Icons\RemoveContactIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\MessageIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\LoginBanner.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\DeclineContactIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\AcceptContactIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\CurrencyIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/qtc-net-client-2/QtCNETAppIconV2.ico b/qtc-net-client-2/QtCNETAppIconV2.ico new file mode 100644 index 0000000..b58cb19 Binary files /dev/null and b/qtc-net-client-2/QtCNETAppIconV2.ico differ diff --git a/qtc-net-client-2/Resources/DefaultPfp.jpg b/qtc-net-client-2/Resources/DefaultPfp.jpg new file mode 100644 index 0000000..b8d0e69 Binary files /dev/null and b/qtc-net-client-2/Resources/DefaultPfp.jpg differ diff --git a/qtc-net-client-2/Resources/LoginBanner.jpg b/qtc-net-client-2/Resources/LoginBanner.jpg new file mode 100644 index 0000000..c278135 Binary files /dev/null and b/qtc-net-client-2/Resources/LoginBanner.jpg differ diff --git a/qtc-net-client-2/Services/AudioService.cs b/qtc-net-client-2/Services/AudioService.cs new file mode 100644 index 0000000..942d28f --- /dev/null +++ b/qtc-net-client-2/Services/AudioService.cs @@ -0,0 +1,53 @@ +using NAudio.Wave; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Media; +using System.Text; +using System.Threading.Tasks; + +namespace qtc_net_client_2.Services +{ + public class AudioService : IDisposable + { + public WaveOutEvent? OutputDevice { get; set; } + public AudioFileReader? AudioFileReader { get; set; } + public void PlaySoundEffect(string soundName) + { + if (!File.Exists($"./Sounds/{soundName}.wav")) return; + + OutputDevice = new WaveOutEvent(); + AudioFileReader = new AudioFileReader($"./Sounds/{soundName}.wav"); + OutputDevice.Init(AudioFileReader); + OutputDevice.Play(); + + return; + } + + public void PlaySoundLooped(string soundName, int loopCount) + { + if (!File.Exists($"./Sounds/{soundName}.wav")) return; + + OutputDevice = new WaveOutEvent(); + AudioFileReader = new AudioFileReader($"./Sounds/{soundName}.wav"); + OutputDevice.Init(AudioFileReader); + OutputDevice.Play(); + + int i = 0; + OutputDevice.PlaybackStopped += (sender, args) => + { + i++; + if (i == loopCount) { OutputDevice.PlaybackStopped += null; return; } + + AudioFileReader.Seek(0, SeekOrigin.Begin); + OutputDevice.Play(); + }; + } + + public void Dispose() + { + if (OutputDevice != null) { OutputDevice.Dispose(); OutputDevice = null; } + if (AudioFileReader != null) { AudioFileReader.Dispose(); AudioFileReader = null; } + } + } +} diff --git a/qtc-net-client-2/Sounds/sndContactRequest.wav b/qtc-net-client-2/Sounds/sndContactRequest.wav new file mode 100644 index 0000000..8d7dda6 Binary files /dev/null and b/qtc-net-client-2/Sounds/sndContactRequest.wav differ diff --git a/qtc-net-client-2/Sounds/sndDirectMsg.wav b/qtc-net-client-2/Sounds/sndDirectMsg.wav new file mode 100644 index 0000000..dd43f90 Binary files /dev/null and b/qtc-net-client-2/Sounds/sndDirectMsg.wav differ diff --git a/qtc-net-client-2/Sounds/sndMessage.wav b/qtc-net-client-2/Sounds/sndMessage.wav new file mode 100644 index 0000000..4a76cbf Binary files /dev/null and b/qtc-net-client-2/Sounds/sndMessage.wav differ diff --git a/qtc-net-client-2/Sounds/sndSendClick.wav b/qtc-net-client-2/Sounds/sndSendClick.wav new file mode 100644 index 0000000..d4c0538 Binary files /dev/null and b/qtc-net-client-2/Sounds/sndSendClick.wav differ diff --git a/qtc-net-client-2/Sounds/sndTokenJackpot.wav b/qtc-net-client-2/Sounds/sndTokenJackpot.wav new file mode 100644 index 0000000..ad94fb4 Binary files /dev/null and b/qtc-net-client-2/Sounds/sndTokenJackpot.wav differ diff --git a/qtc-net-client-2/Sounds/sndTokenSpinLoop.wav b/qtc-net-client-2/Sounds/sndTokenSpinLoop.wav new file mode 100644 index 0000000..e0b497e Binary files /dev/null and b/qtc-net-client-2/Sounds/sndTokenSpinLoop.wav differ diff --git a/qtc-net-client-2/Sounds/sndTokenWin.wav b/qtc-net-client-2/Sounds/sndTokenWin.wav new file mode 100644 index 0000000..80ecd63 Binary files /dev/null and b/qtc-net-client-2/Sounds/sndTokenWin.wav differ diff --git a/qtc-net-client-2/qtc-net-client-2.csproj b/qtc-net-client-2/qtc-net-client-2.csproj new file mode 100644 index 0000000..f6638d0 --- /dev/null +++ b/qtc-net-client-2/qtc-net-client-2.csproj @@ -0,0 +1,65 @@ + + + + WinExe + net8.0-windows + qtc_net_client_2 + enable + true + enable + QtCNETAppIconV2.ico + QtCNetChat + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + \ No newline at end of file