Add project files.
This commit is contained in:
parent
695afb8449
commit
d351ed86be
8
QtCNETAPI/Dtos/Room/RoomDto.cs
Normal file
8
QtCNETAPI/Dtos/Room/RoomDto.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
10
QtCNETAPI/Dtos/User/UserDto.cs
Normal file
10
QtCNETAPI/Dtos/User/UserDto.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
17
QtCNETAPI/Dtos/User/UserInformationDto.cs
Normal file
17
QtCNETAPI/Dtos/User/UserInformationDto.cs
Normal file
@ -0,0 +1,17 @@
|
||||
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 DateTime LastLogin { get; set; } = new DateTime();
|
||||
public int Status { get; set; } = 0;
|
||||
public int CurrencyAmount { get; set; } = 0;
|
||||
public int ProfileCosmeticId { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
9
QtCNETAPI/Dtos/User/UserLoginDto.cs
Normal file
9
QtCNETAPI/Dtos/User/UserLoginDto.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
14
QtCNETAPI/Dtos/User/UserPasswordResetDto.cs
Normal file
14
QtCNETAPI/Dtos/User/UserPasswordResetDto.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace QtCNETAPI.Dtos.User
|
||||
{
|
||||
public class UserPasswordResetDto
|
||||
{
|
||||
public string Token { get; set; } = string.Empty;
|
||||
public string Password { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
8
QtCNETAPI/Dtos/User/UserRefreshLoginDto.cs
Normal file
8
QtCNETAPI/Dtos/User/UserRefreshLoginDto.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
8
QtCNETAPI/Dtos/User/UserStatusDto.cs
Normal file
8
QtCNETAPI/Dtos/User/UserStatusDto.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace QtCNETAPI.Dtos.User
|
||||
{
|
||||
public class UserStatusDto
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public int Status { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
8
QtCNETAPI/Dtos/User/UserStockActionResultDto.cs
Normal file
8
QtCNETAPI/Dtos/User/UserStockActionResultDto.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace QtCNETAPI.Dtos.User
|
||||
{
|
||||
public class UserStockActionResultDto
|
||||
{
|
||||
public int StockAmount { get; set; }
|
||||
public int CurrencyAmount { get; set; }
|
||||
}
|
||||
}
|
||||
11
QtCNETAPI/Dtos/User/UserUpdateInformationDto.cs
Normal file
11
QtCNETAPI/Dtos/User/UserUpdateInformationDto.cs
Normal file
@ -0,0 +1,11 @@
|
||||
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();
|
||||
public int ProfileCosmeticId { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
13
QtCNETAPI/Enums/GameStatus.cs
Normal file
13
QtCNETAPI/Enums/GameStatus.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace QtCNETAPI.Enums
|
||||
{
|
||||
public enum GameStatus
|
||||
{
|
||||
WaitingForPlayer,
|
||||
SelectingSymbol,
|
||||
Ongoing,
|
||||
P1Win,
|
||||
P2Win,
|
||||
NoWin,
|
||||
PlayerDisconnected
|
||||
}
|
||||
}
|
||||
16
QtCNETAPI/Enums/NumberGuessResult.cs
Normal file
16
QtCNETAPI/Enums/NumberGuessResult.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace QtCNETAPI.Enums
|
||||
{
|
||||
public enum NumberGuessResult
|
||||
{
|
||||
Higher,
|
||||
Lower,
|
||||
Correct,
|
||||
Incorrect
|
||||
}
|
||||
}
|
||||
8
QtCNETAPI/Enums/StoreItemType.cs
Normal file
8
QtCNETAPI/Enums/StoreItemType.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace QtCNETAPI.Enums
|
||||
{
|
||||
public enum StoreItemType
|
||||
{
|
||||
ProfileCosmetic = 1,
|
||||
ClientCosmetic = 2
|
||||
}
|
||||
}
|
||||
9
QtCNETAPI/Enums/TicTacToeSymbol.cs
Normal file
9
QtCNETAPI/Enums/TicTacToeSymbol.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace QtCNETAPI.Enums
|
||||
{
|
||||
public enum TicTacToeSymbol
|
||||
{
|
||||
X,
|
||||
O,
|
||||
Blank
|
||||
}
|
||||
}
|
||||
13
QtCNETAPI/Events/ClientFunctionEventArgs.cs
Normal file
13
QtCNETAPI/Events/ClientFunctionEventArgs.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
16
QtCNETAPI/Events/DirectMessageEventArgs.cs
Normal file
16
QtCNETAPI/Events/DirectMessageEventArgs.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
13
QtCNETAPI/Events/GuestUserJoinEventArgs.cs
Normal file
13
QtCNETAPI/Events/GuestUserJoinEventArgs.cs
Normal file
@ -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 GuestUserJoinEventArgs : EventArgs
|
||||
{
|
||||
public required string Username { get; set; }
|
||||
}
|
||||
}
|
||||
14
QtCNETAPI/Events/RoomListEventArgs.cs
Normal file
14
QtCNETAPI/Events/RoomListEventArgs.cs
Normal file
@ -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 RoomListEventArgs : EventArgs
|
||||
{
|
||||
public required List<User> UserList { get; set; }
|
||||
}
|
||||
}
|
||||
14
QtCNETAPI/Events/ServerConfigEventArgs.cs
Normal file
14
QtCNETAPI/Events/ServerConfigEventArgs.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
13
QtCNETAPI/Events/ServerConnectionClosedEventArgs.cs
Normal file
13
QtCNETAPI/Events/ServerConnectionClosedEventArgs.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
13
QtCNETAPI/Events/ServerConnectionReconnectingEventArgs.cs
Normal file
13
QtCNETAPI/Events/ServerConnectionReconnectingEventArgs.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
13
QtCNETAPI/Events/ServerMessageEventArgs.cs
Normal file
13
QtCNETAPI/Events/ServerMessageEventArgs.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
16
QtCNETAPI/Models/Contact.cs
Normal file
16
QtCNETAPI/Models/Contact.cs
Normal file
@ -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 }
|
||||
}
|
||||
}
|
||||
10
QtCNETAPI/Models/Message.cs
Normal file
10
QtCNETAPI/Models/Message.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
14
QtCNETAPI/Models/OwnedStoreItem.cs
Normal file
14
QtCNETAPI/Models/OwnedStoreItem.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace QtCNETAPI.Models
|
||||
{
|
||||
public class OwnedStoreItem
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
public int StoreItemId { get; set; }
|
||||
|
||||
public virtual User? User { get; }
|
||||
}
|
||||
}
|
||||
12
QtCNETAPI/Models/RefreshToken.cs
Normal file
12
QtCNETAPI/Models/RefreshToken.cs
Normal file
@ -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!;
|
||||
}
|
||||
}
|
||||
11
QtCNETAPI/Models/Room.cs
Normal file
11
QtCNETAPI/Models/Room.cs
Normal file
@ -0,0 +1,11 @@
|
||||
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();
|
||||
public int UserCount { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
11
QtCNETAPI/Models/ServerConfig.cs
Normal file
11
QtCNETAPI/Models/ServerConfig.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
9
QtCNETAPI/Models/ServiceResponse.cs
Normal file
9
QtCNETAPI/Models/ServiceResponse.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace QtCNETAPI.Models
|
||||
{
|
||||
public class ServiceResponse<T>
|
||||
{
|
||||
public T? Data { get; set; }
|
||||
public bool Success { get; set; } = false;
|
||||
public string Message { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
28
QtCNETAPI/Models/User.cs
Normal file
28
QtCNETAPI/Models/User.cs
Normal file
@ -0,0 +1,28 @@
|
||||
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 bool IsEmailVerified { get; set; } = false;
|
||||
public DateTime DateOfBirth { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public int Status { get; set; } = 0;
|
||||
public int CurrencyAmount { get; set; } = 0;
|
||||
public int StockAmount { get; set; } = 0;
|
||||
public DateTime LastCurrencySpin { get; set; }
|
||||
public int ActiveProfileCosmetic { get; set; } = 0;
|
||||
public string CurrentRoomId { get; set; } = string.Empty;
|
||||
public DateTime LastLogin { get; set; }
|
||||
|
||||
public virtual IEnumerable<RefreshToken>? RefreshTokens { get; }
|
||||
public virtual IEnumerable<Contact>? ContactsMade { get; }
|
||||
public virtual IEnumerable<Contact>? ContactsList { get; }
|
||||
public virtual IEnumerable<OwnedStoreItem>? OwnedStoreItems { get; }
|
||||
}
|
||||
}
|
||||
17
QtCNETAPI/QtCNETAPI.csproj
Normal file
17
QtCNETAPI/QtCNETAPI.csproj
Normal file
@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Meziantou.Framework.Win32.CredentialManager" Version="1.7.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.16" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.9" />
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
QtCNETAPI/Schema/GameRoom.cs
Normal file
16
QtCNETAPI/Schema/GameRoom.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using QtCNETAPI.Enums;
|
||||
using QtCNETAPI.Models;
|
||||
|
||||
namespace QtCNETAPI.Schema
|
||||
{
|
||||
public class GameRoom
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public GameStatus Status { get; set; }
|
||||
public TicTacToeBoard Board { get; set; } = new();
|
||||
public User? Player1 { get; set; }
|
||||
public TicTacToeSymbol P1Symbol { get; set; } = TicTacToeSymbol.Blank;
|
||||
public User? Player2 { get; set; }
|
||||
public TicTacToeSymbol P2Symbol { get; set; } = TicTacToeSymbol.Blank;
|
||||
}
|
||||
}
|
||||
23
QtCNETAPI/Schema/StoreItem.cs
Normal file
23
QtCNETAPI/Schema/StoreItem.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using QtCNETAPI.Enums;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace QtCNETAPI.Schema
|
||||
{
|
||||
public class StoreItem
|
||||
{
|
||||
[JsonPropertyName("Id")]
|
||||
public int Id { get; set; }
|
||||
[JsonPropertyName("Type")]
|
||||
public StoreItemType Type { get; set; }
|
||||
[JsonPropertyName("Price")]
|
||||
public int Price { get; set; }
|
||||
[JsonPropertyName("Name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
[JsonPropertyName("Description")]
|
||||
public string Description { get; set; } = string.Empty;
|
||||
[JsonPropertyName("AssetUrl")]
|
||||
public string AssetUrl { get; set; } = string.Empty;
|
||||
[JsonPropertyName("ThumbnailUrl")]
|
||||
public string ThumbnailUrl { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
17
QtCNETAPI/Schema/TicTacToeBoard.cs
Normal file
17
QtCNETAPI/Schema/TicTacToeBoard.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using QtCNETAPI.Enums;
|
||||
|
||||
namespace QtCNETAPI.Schema
|
||||
{
|
||||
public class TicTacToeBoard
|
||||
{
|
||||
public TicTacToeSymbol Square1 { get; set; } = TicTacToeSymbol.Blank;
|
||||
public TicTacToeSymbol Square2 { get; set; } = TicTacToeSymbol.Blank;
|
||||
public TicTacToeSymbol Square3 { get; set; } = TicTacToeSymbol.Blank;
|
||||
public TicTacToeSymbol Square4 { get; set; } = TicTacToeSymbol.Blank;
|
||||
public TicTacToeSymbol Square5 { get; set; } = TicTacToeSymbol.Blank;
|
||||
public TicTacToeSymbol Square6 { get; set; } = TicTacToeSymbol.Blank;
|
||||
public TicTacToeSymbol Square7 { get; set; } = TicTacToeSymbol.Blank;
|
||||
public TicTacToeSymbol Square8 { get; set; } = TicTacToeSymbol.Blank;
|
||||
public TicTacToeSymbol Square9 { get; set; } = TicTacToeSymbol.Blank;
|
||||
}
|
||||
}
|
||||
10
QtCNETAPI/Schema/TicTacToeMove.cs
Normal file
10
QtCNETAPI/Schema/TicTacToeMove.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using QtCNETAPI.Models;
|
||||
|
||||
namespace QtCNETAPI.Schema
|
||||
{
|
||||
public class TicTacToeMove
|
||||
{
|
||||
public User User { get; set; } = new();
|
||||
public int Point { get; set; }
|
||||
}
|
||||
}
|
||||
956
QtCNETAPI/Services/ApiService/ApiService.cs
Normal file
956
QtCNETAPI/Services/ApiService/ApiService.cs
Normal file
@ -0,0 +1,956 @@
|
||||
using QtCNETAPI.Dtos.Room;
|
||||
using QtCNETAPI.Dtos.User;
|
||||
using QtCNETAPI.Enums;
|
||||
using QtCNETAPI.Models;
|
||||
using QtCNETAPI.Schema;
|
||||
using RestSharp;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace QtCNETAPI.Services.ApiService
|
||||
{
|
||||
public class ApiService : IApiService
|
||||
{
|
||||
private User? user;
|
||||
private readonly RestClient _client;
|
||||
|
||||
internal string? sessionToken;
|
||||
|
||||
public event EventHandler? OnCurrentUserUpdate;
|
||||
|
||||
public string? SessionToken
|
||||
{
|
||||
get { return sessionToken; }
|
||||
set { sessionToken = value; }
|
||||
}
|
||||
|
||||
public string? ApiUri { get; private set; }
|
||||
|
||||
public User? CurrentUser
|
||||
{
|
||||
get { return user; }
|
||||
private set { user = value; }
|
||||
}
|
||||
|
||||
private readonly LoggingService _loggingService;
|
||||
private readonly CredentialService _credentialService;
|
||||
public ApiService(string apiUri, LoggingService loggingService, CredentialService credentialService)
|
||||
{
|
||||
ApiUri = apiUri;
|
||||
|
||||
_client = new RestClient(ApiUri);
|
||||
_loggingService = loggingService;
|
||||
_credentialService = credentialService;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<string>> PingServerAsync()
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<string>();
|
||||
|
||||
try
|
||||
{
|
||||
var request = new RestRequest("general/ping");
|
||||
var response = await _client.GetAsync<string>(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<ServiceResponse<List<UserInformationDto>>> GetAllUsersAsync()
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<List<UserInformationDto>>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var request = new RestRequest("users/all")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}");
|
||||
var response = await _client.GetAsync<ServiceResponse<List<UserInformationDto>>>(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 users.";
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<List<UserInformationDto>>> GetOnlineUsersAsync()
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<List<UserInformationDto>>();
|
||||
|
||||
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<ServiceResponse<List<UserInformationDto>>>(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<ServiceResponse<UserInformationDto>> GetUserInformationAsync(string id)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<UserInformationDto>();
|
||||
|
||||
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<ServiceResponse<UserInformationDto>>(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<ServiceResponse<UserInformationDto>> UpdateUserInformationAsync(UserUpdateInformationDto request)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<UserInformationDto>();
|
||||
|
||||
var restRequest = new RestRequest("users/update")
|
||||
.AddJsonBody(request)
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}");
|
||||
var response = await _client.PutAsync<ServiceResponse<UserInformationDto>>(restRequest);
|
||||
|
||||
if(response != null || response!.Data != null)
|
||||
{
|
||||
serviceResponse.Success = true;
|
||||
serviceResponse.Data = response.Data;
|
||||
|
||||
// anything that changes the user should tell the api service to set it again
|
||||
await SetCurrentUser();
|
||||
OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
|
||||
} else
|
||||
{
|
||||
serviceResponse.Success = false;
|
||||
serviceResponse.Message = "API never responded.";
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<string>> UpdateUserProfilePic(string filePath)
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<string>();
|
||||
|
||||
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<ServiceResponse<string>>(restRequest);
|
||||
|
||||
if (response != null && response.Success != false)
|
||||
{
|
||||
serviceResponse.Success = true;
|
||||
serviceResponse.Data = response.Data;
|
||||
|
||||
// anything that changes the user should tell the api service to set it again
|
||||
await SetCurrentUser();
|
||||
OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
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<ServiceResponse<byte[]>> GetUserProfilePic(string userId)
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<byte[]>();
|
||||
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<ServiceResponse<string>> LoginAsync(UserLoginDto userLoginDto)
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<string>();
|
||||
|
||||
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<ServiceResponse<string>>(request);
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
if (response.Data != null && response.Success)
|
||||
{
|
||||
SessionToken = response.Data;
|
||||
|
||||
var user = await SetCurrentUser();
|
||||
|
||||
serviceResponse.Success = true;
|
||||
if (response.Message != null) serviceResponse.Message = response.Message;
|
||||
serviceResponse.Data = response.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceResponse.Success = false;
|
||||
serviceResponse.Message = response.Message;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
serviceResponse.Success = false;
|
||||
serviceResponse.Message = ex.Message;
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<bool>> ResendVerificationEmail(string email)
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<bool>();
|
||||
|
||||
var restRequest = new RestRequest($"auth/resend-verification-email")
|
||||
.AddQueryParameter("email", email);
|
||||
var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
serviceResponse.Success = true;
|
||||
serviceResponse.Data = response.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceResponse.Success = false;
|
||||
serviceResponse.Message = "API never responded.";
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<bool>> SendPasswordResetEmail(string email)
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<bool>();
|
||||
|
||||
var restRequest = new RestRequest($"auth/request-password-reset")
|
||||
.AddQueryParameter("email", email);
|
||||
var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
serviceResponse.Success = true;
|
||||
serviceResponse.Data = response.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceResponse.Success = false;
|
||||
serviceResponse.Message = "API never responded.";
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<bool>> ResetPassword(UserPasswordResetDto request)
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<bool>();
|
||||
|
||||
var restRequest = new RestRequest($"auth/reset-password")
|
||||
.AddJsonBody(request);
|
||||
var response = await _client.PostAsync<ServiceResponse<bool>>(restRequest);
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
serviceResponse.Success = true;
|
||||
serviceResponse.Data = response.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceResponse.Success = false;
|
||||
serviceResponse.Message = "API never responded.";
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<User> SetCurrentUser()
|
||||
{
|
||||
var userRequest = new RestRequest("users/user-authorized")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}");
|
||||
var userResponse = await _client.GetAsync<ServiceResponse<User>>(userRequest);
|
||||
|
||||
if (userResponse != null && userResponse.Success && userResponse.Data != null)
|
||||
{
|
||||
user = userResponse.Data;
|
||||
|
||||
_loggingService.LogString($"Current User's Status Is {userResponse.Data.Status}");
|
||||
|
||||
return userResponse.Data;
|
||||
} else
|
||||
{
|
||||
throw new NullReferenceException("Current User could not be set.");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<User>> RefreshLogin(string refreshToken)
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<User>();
|
||||
|
||||
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<ServiceResponse<string>>(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<ServiceResponse<string>> RefreshSessionIfInvalid()
|
||||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var refToken = _credentialService.GetAccessToken(); // fuck CA1416, if this is being ran on linux it should just crash (theoretically)
|
||||
|
||||
if (refToken == null)
|
||||
{
|
||||
// treat as session expired
|
||||
return new ServiceResponse<string> { Success = false, Message = "Refresh Token Not Found. Session Expired." };
|
||||
}
|
||||
|
||||
JwtSecurityToken token = tokenHandler.ReadJwtToken(SessionToken);
|
||||
|
||||
if(DateTime.Compare(DateTime.UtcNow, token.ValidTo) > 0)
|
||||
{
|
||||
var result = await RefreshLogin(refToken);
|
||||
|
||||
if (result == null || result.Success == false)
|
||||
{
|
||||
return new ServiceResponse<string> { Success = false, Message = "Session Expired." }; // logging in again should overwrite old token
|
||||
} else return new ServiceResponse<string> { Success = true, Data = refToken };
|
||||
} else return new ServiceResponse<string> { Success = true, Data = refToken };
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<User>> RegisterAsync(UserDto userDto)
|
||||
{
|
||||
var serviceResponse = new ServiceResponse<User>();
|
||||
|
||||
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<ServiceResponse<User>>(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<ServiceResponse<Room>> CreateRoomAsync(RoomDto request)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<Room>();
|
||||
|
||||
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<ServiceResponse<Room>>(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<ServiceResponse<List<Room>>> GetAllRoomsAsync()
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<List<Room>>();
|
||||
|
||||
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<ServiceResponse<List<Room>>>(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<ServiceResponse<Room>> DeleteRoomAsync(string roomId)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<Room>();
|
||||
|
||||
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<ServiceResponse<Room>>(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<ServiceResponse<List<Contact>>> GetCurrentUserContacts()
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<List<Contact>>();
|
||||
|
||||
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<ServiceResponse<List<Contact>>>(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<ServiceResponse<Contact>> AddContactToCurrentUser(string userId)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<Contact>();
|
||||
|
||||
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<ServiceResponse<Contact>>(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<ServiceResponse<bool>> AcceptContactRequest(string userId)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<bool>();
|
||||
|
||||
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<ServiceResponse<bool>>(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<ServiceResponse<Contact>> RemoveContactFromCurrentUser(string userId)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<Contact>();
|
||||
|
||||
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<ServiceResponse<Contact>>(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<ServiceResponse<int>> AddCurrencyToCurrentUser(int amount, bool isSpinClaim)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<int>();
|
||||
|
||||
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<ServiceResponse<int>>(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;
|
||||
|
||||
// anything that changes the user should tell the api service to set it again
|
||||
await SetCurrentUser();
|
||||
OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<int>> GetCurrentStockPrice()
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<int>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("games/stock-market/current-price")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}");
|
||||
var response = await _client.GetAsync<ServiceResponse<int>>(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<ServiceResponse<UserStockActionResultDto>> BuyStock(int amount)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<UserStockActionResultDto>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("games/stock-market/buy-stock")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}")
|
||||
.AddQueryParameter("amount", amount);
|
||||
var response = await _client.PostAsync<ServiceResponse<UserStockActionResultDto>>(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;
|
||||
|
||||
// anything that changes the user should tell the api service to set it again
|
||||
await SetCurrentUser();
|
||||
OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<UserStockActionResultDto>> SellStock(int amount)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<UserStockActionResultDto>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("games/stock-market/sell-stock")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}")
|
||||
.AddQueryParameter("amount", amount);
|
||||
var response = await _client.PostAsync<ServiceResponse<UserStockActionResultDto>>(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;
|
||||
|
||||
// anything that changes the user should tell the api service to set it again
|
||||
await SetCurrentUser();
|
||||
OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<int>> GetRandomNumber()
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<int>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("games/number-guess/get-number")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}");
|
||||
var response = await _client.GetAsync<ServiceResponse<int>>(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<ServiceResponse<NumberGuessResult>> GuessRandomNumber(int original, int guess)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<NumberGuessResult>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("games/number-guess/guess-number")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}")
|
||||
.AddQueryParameter("original", original)
|
||||
.AddQueryParameter("guess", guess);
|
||||
var response = await _client.GetAsync<ServiceResponse<NumberGuessResult>>(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<ServiceResponse<List<StoreItem>>> GetStoreItems()
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<List<StoreItem>>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("store/all-items")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}");
|
||||
var response = await _client.GetAsync<ServiceResponse<List<StoreItem>>>(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<ServiceResponse<StoreItem>> GetStoreItem(int id)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<StoreItem>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("store/item")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}")
|
||||
.AddQueryParameter("id", id);
|
||||
var response = await _client.GetAsync<ServiceResponse<StoreItem>>(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<ServiceResponse<bool>> BuyStoreItem(int id)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<bool>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("store/buy-item")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}")
|
||||
.AddQueryParameter("id", id);
|
||||
var response = await _client.PostAsync<ServiceResponse<bool>>(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;
|
||||
|
||||
// anything that changes the user should tell the api service to set it again
|
||||
await SetCurrentUser();
|
||||
OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
return serviceResponse;
|
||||
}
|
||||
|
||||
public async Task<ServiceResponse<List<OwnedStoreItem>>> GetOwnedStoreItems()
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<List<OwnedStoreItem>>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("store/bought-items")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}");
|
||||
var response = await _client.GetAsync<ServiceResponse<List<OwnedStoreItem>>>(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<ServiceResponse<OwnedStoreItem>> GetOwnedStoreItem(int id)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<OwnedStoreItem>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("store/bought-item")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}")
|
||||
.AddQueryParameter("id", id);
|
||||
var response = await _client.GetAsync<ServiceResponse<OwnedStoreItem>>(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<ServiceResponse<User>> DeleteUserById(string id)
|
||||
{
|
||||
await RefreshSessionIfInvalid();
|
||||
|
||||
var serviceResponse = new ServiceResponse<User>();
|
||||
|
||||
if (SessionToken == null) throw new NullReferenceException("Function Was Called Before A Session Was Made.");
|
||||
|
||||
var restRequest = new RestRequest("users/delete-user")
|
||||
.AddHeader("Authorization", $"Bearer {SessionToken}")
|
||||
.AddQueryParameter("id", id);
|
||||
var response = await _client.DeleteAsync<ServiceResponse<User>>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
QtCNETAPI/Services/ApiService/IApiService.cs
Normal file
58
QtCNETAPI/Services/ApiService/IApiService.cs
Normal file
@ -0,0 +1,58 @@
|
||||
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;
|
||||
using QtCNETAPI.Enums;
|
||||
using QtCNETAPI.Schema;
|
||||
|
||||
namespace QtCNETAPI.Services.ApiService
|
||||
{
|
||||
public interface IApiService
|
||||
{
|
||||
public string? SessionToken { get; set; }
|
||||
public string? ApiUri { get; }
|
||||
public User? CurrentUser { get; }
|
||||
|
||||
public event EventHandler? OnCurrentUserUpdate;
|
||||
|
||||
public Task<ServiceResponse<string>> PingServerAsync();
|
||||
public Task<ServiceResponse<List<UserInformationDto>>> GetOnlineUsersAsync();
|
||||
public Task<ServiceResponse<List<UserInformationDto>>> GetAllUsersAsync();
|
||||
public Task<ServiceResponse<User>> DeleteUserById(string id);
|
||||
public Task<ServiceResponse<string>> LoginAsync(UserLoginDto userLoginDto);
|
||||
public Task<ServiceResponse<bool>> ResendVerificationEmail(string email);
|
||||
public Task<ServiceResponse<bool>> SendPasswordResetEmail(string email);
|
||||
public Task<ServiceResponse<bool>> ResetPassword(UserPasswordResetDto request);
|
||||
public Task<ServiceResponse<User>> RefreshLogin(string refreshToken);
|
||||
public Task<ServiceResponse<string>> RefreshSessionIfInvalid();
|
||||
public Task<User> SetCurrentUser();
|
||||
public Task<ServiceResponse<User>> RegisterAsync(UserDto userDto);
|
||||
public Task<ServiceResponse<UserInformationDto>> GetUserInformationAsync(string id);
|
||||
public Task<ServiceResponse<UserInformationDto>> UpdateUserInformationAsync(UserUpdateInformationDto request);
|
||||
public Task<ServiceResponse<string>> UpdateUserProfilePic(string filePath);
|
||||
public Task<ServiceResponse<byte[]>> GetUserProfilePic(string userId);
|
||||
public Task<ServiceResponse<Room>> CreateRoomAsync(RoomDto request);
|
||||
public Task<ServiceResponse<Room>> DeleteRoomAsync(string roomId);
|
||||
public Task<ServiceResponse<List<Room>>> GetAllRoomsAsync();
|
||||
public Task<ServiceResponse<List<Contact>>> GetCurrentUserContacts();
|
||||
public Task<ServiceResponse<Contact>> AddContactToCurrentUser(string userId);
|
||||
public Task<ServiceResponse<bool>> AcceptContactRequest(string userId);
|
||||
public Task<ServiceResponse<Contact>> RemoveContactFromCurrentUser(string userId);
|
||||
public Task<ServiceResponse<int>> AddCurrencyToCurrentUser(int amount, bool isSpinClaim);
|
||||
public Task<ServiceResponse<int>> GetCurrentStockPrice();
|
||||
public Task<ServiceResponse<UserStockActionResultDto>> BuyStock(int amount);
|
||||
public Task<ServiceResponse<UserStockActionResultDto>> SellStock(int amount);
|
||||
public Task<ServiceResponse<int>> GetRandomNumber();
|
||||
public Task<ServiceResponse<NumberGuessResult>> GuessRandomNumber(int original, int guess);
|
||||
public Task<ServiceResponse<List<StoreItem>>> GetStoreItems();
|
||||
public Task<ServiceResponse<StoreItem>> GetStoreItem(int id);
|
||||
public Task<ServiceResponse<bool>> BuyStoreItem(int id);
|
||||
public Task<ServiceResponse<List<OwnedStoreItem>>> GetOwnedStoreItems();
|
||||
public Task<ServiceResponse<OwnedStoreItem>> GetOwnedStoreItem(int id);
|
||||
}
|
||||
}
|
||||
42
QtCNETAPI/Services/CredentialService.cs
Normal file
42
QtCNETAPI/Services/CredentialService.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using Meziantou.Framework.Win32;
|
||||
|
||||
namespace QtCNETAPI.Services
|
||||
{
|
||||
public class CredentialService()
|
||||
{
|
||||
/*
|
||||
|
||||
* NOTE *
|
||||
This does not work on other platforms such as Linux or macOS.
|
||||
I will probably recode the legacy way of doing this for those other platforms.
|
||||
|
||||
*/
|
||||
|
||||
public void SaveAccessToken(string username, string accessToken)
|
||||
{
|
||||
string applicationName = "QtC.NET";
|
||||
if (System.Diagnostics.Debugger.IsAttached) applicationName = "QtC.NET.Development";
|
||||
|
||||
CredentialManager.WriteCredential(applicationName, username, accessToken, $"Access Token For User {username} On QtC.NET", CredentialPersistence.LocalMachine);
|
||||
}
|
||||
|
||||
public void DeleteAccessToken()
|
||||
{
|
||||
string applicationName = "QtC.NET";
|
||||
if (System.Diagnostics.Debugger.IsAttached) applicationName = "QtC.NET.Development";
|
||||
|
||||
CredentialManager.DeleteCredential(applicationName);
|
||||
}
|
||||
|
||||
public string? GetAccessToken()
|
||||
{
|
||||
string applicationName = "QtC.NET";
|
||||
if (System.Diagnostics.Debugger.IsAttached) applicationName = "QtC.NET.Development";
|
||||
|
||||
var credential = CredentialManager.ReadCredential(applicationName);
|
||||
if (credential == null) return null;
|
||||
|
||||
return credential.Password;
|
||||
}
|
||||
}
|
||||
}
|
||||
196
QtCNETAPI/Services/GatewayService/GatewayService.cs
Normal file
196
QtCNETAPI/Services/GatewayService/GatewayService.cs
Normal file
@ -0,0 +1,196 @@
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using QtCNETAPI.Dtos.User;
|
||||
using QtCNETAPI.Events;
|
||||
using QtCNETAPI.Models;
|
||||
using QtCNETAPI.Services.ApiService;
|
||||
|
||||
namespace QtCNETAPI.Services.GatewayService
|
||||
{
|
||||
public class GatewayService : IGatewayService, IAsyncDisposable
|
||||
{
|
||||
public Room? CurrentRoom { get; private set; }
|
||||
public HubConnection? HubConnection { get; private set; }
|
||||
public string? GWUri { get; private set; }
|
||||
|
||||
|
||||
public event EventHandler? OnRoomMessageReceived;
|
||||
public event EventHandler? OnRoomUserListReceived;
|
||||
public event EventHandler? OnGuestUserJoin;
|
||||
public event EventHandler? OnRefreshUserListsReceived;
|
||||
public event EventHandler? OnRefreshRoomListReceived;
|
||||
public event EventHandler? OnRoomDeleted;
|
||||
public event EventHandler? OnRefreshContactsListReceived;
|
||||
public event EventHandler? OnClientFunctionReceived;
|
||||
public event EventHandler? OnDirectMessageReceived;
|
||||
public event EventHandler? OnServerConfigReceived;
|
||||
public event EventHandler? OnServerDisconnect;
|
||||
public event EventHandler? OnServerReconnecting;
|
||||
public event EventHandler? OnServerReconnected;
|
||||
public event EventHandler? OnUserForceLogout;
|
||||
|
||||
private IApiService _apiService;
|
||||
private LoggingService _loggingService;
|
||||
public GatewayService(string gwUri, IApiService apiService, LoggingService loggingService)
|
||||
{
|
||||
GWUri = gwUri;
|
||||
_apiService = apiService;
|
||||
_loggingService = loggingService;
|
||||
}
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
// build connection
|
||||
var gwConBuilder = new HubConnectionBuilder()
|
||||
.WithAutomaticReconnect()
|
||||
.ConfigureLogging((builder) =>
|
||||
{
|
||||
builder.AddProvider(new LoggingServiceProvider(_loggingService));
|
||||
|
||||
if (System.Diagnostics.Debugger.IsAttached) builder.SetMinimumLevel(LogLevel.Debug);
|
||||
else builder.SetMinimumLevel(LogLevel.Error);
|
||||
})
|
||||
.WithUrl(GWUri!, options =>
|
||||
{
|
||||
options.AccessTokenProvider = async () =>
|
||||
{
|
||||
// this should hopefully refresh the session every time the gateway connection is used to prevent connection aborts
|
||||
await _apiService.RefreshSessionIfInvalid();
|
||||
return _apiService.SessionToken;
|
||||
};
|
||||
})
|
||||
.WithStatefulReconnect();
|
||||
HubConnection = gwConBuilder.Build();
|
||||
|
||||
// register events
|
||||
HubConnection.On<string>("RoomMessage", (serverMessage) => OnRoomMessageReceived?.Invoke(this, new ServerMessageEventArgs { Message = serverMessage }));
|
||||
HubConnection.On<string>("cf", (function) => OnClientFunctionReceived?.Invoke(this, new ClientFunctionEventArgs { Function = function }));
|
||||
HubConnection.On<Message, UserInformationDto>("ReceiveDirectMessage", (message, user) => OnDirectMessageReceived?.Invoke(this, new DirectMessageEventArgs { Message = message, User = user }));
|
||||
HubConnection.On("RefreshUserLists", () => OnRefreshUserListsReceived?.Invoke(this, EventArgs.Empty));
|
||||
HubConnection.On("RefreshRoomList", () => OnRefreshRoomListReceived?.Invoke(this, EventArgs.Empty));
|
||||
HubConnection.On("RefreshContactsList", () => OnRefreshContactsListReceived?.Invoke(this, EventArgs.Empty));
|
||||
HubConnection.On<ServerConfig>("ReceiveServerConfig", (serverConfig) => OnServerConfigReceived?.Invoke(this, new ServerConfigEventArgs { ServerConfig = serverConfig }));
|
||||
HubConnection.On<List<User>>("RoomUserList", (userList) => OnRoomUserListReceived?.Invoke(this, new RoomListEventArgs { UserList = userList }));
|
||||
HubConnection.On<string>("GuestJoin", (username) => OnGuestUserJoin?.Invoke(this, new GuestUserJoinEventArgs { Username = username }));
|
||||
HubConnection.On("RoomDeleted", () => OnRoomDeleted?.Invoke(this, EventArgs.Empty));
|
||||
HubConnection.On("ForceSignOut", () => OnUserForceLogout?.Invoke(this, EventArgs.Empty));
|
||||
|
||||
HubConnection.Closed += HubConnection_Closed;
|
||||
HubConnection.Reconnecting += HubConnection_Reconnecting;
|
||||
HubConnection.Reconnected += HubConnection_Reconnected;
|
||||
|
||||
// start connection
|
||||
try
|
||||
{
|
||||
await HubConnection.StartAsync();
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_loggingService.LogString($"Unable To Connect To SignalR.\n{ex.Message}\n{ex.StackTrace}");
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure current user is up to date (particularly status)
|
||||
await _apiService.SetCurrentUser();
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
{
|
||||
if (HubConnection != null && HubConnection.State == HubConnectionState.Connected)
|
||||
{
|
||||
await HubConnection.StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
async ValueTask IAsyncDisposable.DisposeAsync()
|
||||
{
|
||||
if (HubConnection != null && HubConnection.State == HubConnectionState.Disconnected)
|
||||
{
|
||||
await HubConnection.DisposeAsync();
|
||||
|
||||
HubConnection = null;
|
||||
CurrentRoom = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DisposeAsync()
|
||||
{
|
||||
if (HubConnection != null && HubConnection.State == HubConnectionState.Disconnected)
|
||||
{
|
||||
await HubConnection.DisposeAsync();
|
||||
|
||||
HubConnection = null;
|
||||
CurrentRoom = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task JoinRoomAsync(Room? room = null)
|
||||
{
|
||||
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
|
||||
|
||||
// assume user is trying to join lobby if room is null (does not have db entry)
|
||||
room ??= new Room
|
||||
{
|
||||
Id = "LOBBY",
|
||||
Name = "Lobby"
|
||||
};
|
||||
|
||||
if (CurrentRoom != null) await HubConnection.SendAsync("LeaveRoom", _apiService.CurrentUser, CurrentRoom);
|
||||
await HubConnection.SendAsync("JoinRoom", _apiService.CurrentUser, room);
|
||||
CurrentRoom = room;
|
||||
}
|
||||
|
||||
public async Task LeaveRoomAsync()
|
||||
{
|
||||
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
|
||||
|
||||
if (CurrentRoom != null) await HubConnection.SendAsync("LeaveRoom", _apiService.CurrentUser, CurrentRoom);
|
||||
CurrentRoom = null;
|
||||
}
|
||||
|
||||
public async Task PostMessageAsync(Message message)
|
||||
{
|
||||
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
|
||||
|
||||
await HubConnection.SendAsync("SendMessage", _apiService.CurrentUser, message, 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("SendDirectMessage", _apiService.CurrentUser, user, message);
|
||||
}
|
||||
|
||||
public async Task UpdateStatus(int status)
|
||||
{
|
||||
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
|
||||
|
||||
await HubConnection.SendAsync("UpdateStatus", _apiService.CurrentUser, status);
|
||||
|
||||
// anything that changes the user should tell the api service to set it again
|
||||
await _apiService.SetCurrentUser();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
161
QtCNETAPI/Services/GatewayService/IGatewayService.cs
Normal file
161
QtCNETAPI/Services/GatewayService/IGatewayService.cs
Normal file
@ -0,0 +1,161 @@
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// The Current Room The Current User Is In
|
||||
/// </summary>
|
||||
public Room? CurrentRoom { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Current Connection To The Gateway
|
||||
/// </summary>
|
||||
public HubConnection? HubConnection { get; }
|
||||
/// <summary>
|
||||
/// The URI in which the client will try to use for SignalR requests.
|
||||
/// </summary>
|
||||
public string? GWUri { get; }
|
||||
|
||||
// FUNCTIONS
|
||||
|
||||
/// <summary>
|
||||
/// The Function Used To Connect To The Gateway Server Asynchronously
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task StartAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Stops The Connection To The Gateway Server
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task StopAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Disposes Of The Gateway Connection And Clears Other Variables
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task DisposeAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Joins The Current User To A Room On The Server
|
||||
/// </summary>
|
||||
/// <param name="room">Room To Join</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException">Thrown if the function is called before the connection is established.</exception>
|
||||
public Task JoinRoomAsync(Room? room = null);
|
||||
|
||||
/// <summary>
|
||||
/// Leaves The Current Room The Current User Is In
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task LeaveRoomAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Posts A Message To Whatever Room The User Is In
|
||||
/// </summary>
|
||||
/// <param name="message">Message To Post</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException">Thrown if the function is called before the connection is established.</exception>
|
||||
public Task PostMessageAsync(Message message);
|
||||
|
||||
/// <summary>
|
||||
/// Sends A Direct Message To The Specified User
|
||||
/// </summary>
|
||||
/// <param name="user">The User You Wish To DM</param>
|
||||
/// <param name="currentUser">Yourself</param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public Task SendDirectMessageAsync(UserInformationDto user, Message message);
|
||||
|
||||
/// <summary>
|
||||
/// Updates The Status For The Current User
|
||||
/// </summary>
|
||||
/// <param name="status">The Status You Want To Set On The Current User</param>
|
||||
/// <returns></returns>
|
||||
public Task UpdateStatus(int status);
|
||||
|
||||
// EVENTS
|
||||
|
||||
/// <summary>
|
||||
/// When A Room Message Is Received, This Event Fires
|
||||
/// </summary>
|
||||
public event EventHandler OnRoomMessageReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Fires When The User List For A Room Is Received
|
||||
/// </summary>
|
||||
public event EventHandler OnRoomUserListReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Fires When The Room The User Is In Gets Deleted By An Admin
|
||||
/// </summary>
|
||||
public event EventHandler OnRoomDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// Fires When A Guest User Joins Your Room
|
||||
/// </summary>
|
||||
public event EventHandler OnGuestUserJoin;
|
||||
|
||||
/// <summary>
|
||||
/// When A Client Function/Event Is Received, This Event Fires
|
||||
/// </summary>
|
||||
public event EventHandler OnClientFunctionReceived;
|
||||
|
||||
/// <summary>
|
||||
/// When The Client Received A DM, This Event Fires
|
||||
/// </summary>
|
||||
public event EventHandler OnDirectMessageReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Fires When The Client Receives The Request To Refresh Its User List
|
||||
/// </summary>
|
||||
public event EventHandler OnRefreshUserListsReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Fires When The Client Receives The Request To Refresh Its Room List
|
||||
/// </summary>
|
||||
public event EventHandler OnRefreshRoomListReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Fires When The Client Receives The Request To Refresh Its Contacts List
|
||||
/// </summary>
|
||||
public event EventHandler OnRefreshContactsListReceived;
|
||||
|
||||
/// <summary>
|
||||
/// When The Server Config Is Received, This Event Fires
|
||||
/// </summary>
|
||||
public event EventHandler OnServerConfigReceived;
|
||||
|
||||
/// <summary>
|
||||
/// When The Connection To The Gateway Is Lost, This Event Fires
|
||||
/// </summary>
|
||||
public event EventHandler OnServerDisconnect;
|
||||
|
||||
/// <summary>
|
||||
/// When The Connection Attempts To Reconnect, This Event Fires
|
||||
/// </summary>
|
||||
public event EventHandler OnServerReconnecting;
|
||||
|
||||
/// <summary>
|
||||
/// When the Connection Reconnects, This Event Fires
|
||||
/// </summary>
|
||||
public event EventHandler OnServerReconnected;
|
||||
|
||||
/// <summary>
|
||||
/// Fires When The Current User Is Signed Out By The Server
|
||||
/// </summary>
|
||||
public event EventHandler OnUserForceLogout;
|
||||
}
|
||||
}
|
||||
93
QtCNETAPI/Services/LoggingService.cs
Normal file
93
QtCNETAPI/Services/LoggingService.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.IdentityModel.Abstractions;
|
||||
|
||||
namespace QtCNETAPI.Services
|
||||
{
|
||||
public class LoggingService : IDisposable, ILogger
|
||||
{
|
||||
private DateTime LogDate { get; set; }
|
||||
private string LogFilePath { get; set; }
|
||||
private StreamWriter LogFile { get; set; }
|
||||
public LoggingService()
|
||||
{
|
||||
LogDate = DateTime.Now;
|
||||
LogFilePath = $"./Logs/QtCClientLog_{LogDate:ddMMyyy-hhmm}.log";
|
||||
|
||||
// create log file
|
||||
|
||||
if (!Directory.Exists("./Logs")) Directory.CreateDirectory("./Logs");
|
||||
LogFile = new StreamWriter(File.Create(LogFilePath));
|
||||
|
||||
Debug.WriteLine($"Log File Created At {LogFilePath}");
|
||||
}
|
||||
|
||||
public void LogString(string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine($"({DateTime.Now.ToLocalTime():hh:mm}) {message}");
|
||||
LogFile.WriteLine($"({DateTime.Now.ToLocalTime():hh:mm}) {message}");
|
||||
} catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void LogModel<T>(T model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// serialize the model as json
|
||||
string modelSerialized = JsonSerializer.Serialize(model, options: new JsonSerializerOptions { WriteIndented = true });
|
||||
|
||||
// log it
|
||||
Debug.WriteLine($"({DateTime.Now.ToLocalTime():hh:mm}) {modelSerialized}");
|
||||
LogFile.WriteLine($"({DateTime.Now.ToLocalTime():hh:mm}) {modelSerialized}");
|
||||
} catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LogFile.WriteLine("--- END OF LOG ---");
|
||||
LogFile.Close();
|
||||
LogFile.Dispose();
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
||||
{
|
||||
try
|
||||
{
|
||||
// format message
|
||||
string message = $"({DateTime.Now.ToLocalTime():hh:mm}) [{logLevel}] {formatter(state, exception)}";
|
||||
|
||||
// log it
|
||||
Debug.WriteLine(message);
|
||||
LogFile.WriteLine(message);
|
||||
} catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel) => true;
|
||||
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => default!;
|
||||
}
|
||||
|
||||
public class LoggingServiceProvider(LoggingService? loggingService = null) : ILoggerProvider
|
||||
{
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
if (loggingService != null) return loggingService;
|
||||
else return new LoggingService();
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
4
qtcnet-client.slnx
Normal file
4
qtcnet-client.slnx
Normal file
@ -0,0 +1,4 @@
|
||||
<Solution>
|
||||
<Project Path="qtcnet-client/qtcnet-client.csproj" />
|
||||
<Project Path="QtCNETAPI/QtCNETAPI.csproj" />
|
||||
</Solution>
|
||||
62
qtcnet-client/Controls/BrandingControl.Designer.cs
generated
Normal file
62
qtcnet-client/Controls/BrandingControl.Designer.cs
generated
Normal file
@ -0,0 +1,62 @@
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
partial class BrandingControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
pictureBox1 = new PictureBox();
|
||||
((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
pictureBox1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
pictureBox1.Image = Properties.Resources.QtCNETIcon;
|
||||
pictureBox1.Location = new Point(0, 0);
|
||||
pictureBox1.Name = "pictureBox1";
|
||||
pictureBox1.Size = new Size(122, 110);
|
||||
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
|
||||
pictureBox1.TabIndex = 0;
|
||||
pictureBox1.TabStop = false;
|
||||
//
|
||||
// BrandingControl
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
BackColor = Color.Transparent;
|
||||
Controls.Add(pictureBox1);
|
||||
Name = "BrandingControl";
|
||||
Size = new Size(122, 110);
|
||||
((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private PictureBox pictureBox1;
|
||||
}
|
||||
}
|
||||
18
qtcnet-client/Controls/BrandingControl.cs
Normal file
18
qtcnet-client/Controls/BrandingControl.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
public partial class BrandingControl : UserControl
|
||||
{
|
||||
public BrandingControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Controls/BrandingControl.resx
Normal file
120
qtcnet-client/Controls/BrandingControl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
96
qtcnet-client/Controls/ContactControl.Designer.cs
generated
Normal file
96
qtcnet-client/Controls/ContactControl.Designer.cs
generated
Normal file
@ -0,0 +1,96 @@
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
partial class ContactControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
pbProfilePic = new PictureBox();
|
||||
lblUsername = new Label();
|
||||
lblStatus = new Label();
|
||||
((System.ComponentModel.ISupportInitialize)pbProfilePic).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// pbProfilePic
|
||||
//
|
||||
pbProfilePic.Image = Properties.Resources.DefaultPfp;
|
||||
pbProfilePic.Location = new Point(3, 3);
|
||||
pbProfilePic.Name = "pbProfilePic";
|
||||
pbProfilePic.Size = new Size(37, 35);
|
||||
pbProfilePic.SizeMode = PictureBoxSizeMode.Zoom;
|
||||
pbProfilePic.TabIndex = 0;
|
||||
pbProfilePic.TabStop = false;
|
||||
//
|
||||
// lblUsername
|
||||
//
|
||||
lblUsername.AutoSize = true;
|
||||
lblUsername.Font = new Font("Segoe UI", 8F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||
lblUsername.ForeColor = Color.Black;
|
||||
lblUsername.Location = new Point(44, 8);
|
||||
lblUsername.Name = "lblUsername";
|
||||
lblUsername.Size = new Size(59, 13);
|
||||
lblUsername.TabIndex = 1;
|
||||
lblUsername.Text = "Username";
|
||||
lblUsername.DoubleClick += lblUsername_DoubleClick;
|
||||
lblUsername.MouseLeave += lblUsername_MouseLeave;
|
||||
lblUsername.MouseHover += lblUsername_MouseHover;
|
||||
//
|
||||
// lblStatus
|
||||
//
|
||||
lblStatus.AutoSize = true;
|
||||
lblStatus.Font = new Font("Segoe UI Semibold", 7F, FontStyle.Bold | FontStyle.Italic, GraphicsUnit.Point, 0);
|
||||
lblStatus.ForeColor = SystemColors.AppWorkspace;
|
||||
lblStatus.Location = new Point(46, 21);
|
||||
lblStatus.Name = "lblStatus";
|
||||
lblStatus.Size = new Size(40, 12);
|
||||
lblStatus.TabIndex = 2;
|
||||
lblStatus.Text = "\"Status\"";
|
||||
//
|
||||
// ContactControl
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
BackColor = Color.Transparent;
|
||||
Controls.Add(lblUsername);
|
||||
Controls.Add(lblStatus);
|
||||
Controls.Add(pbProfilePic);
|
||||
DoubleBuffered = true;
|
||||
Name = "ContactControl";
|
||||
Size = new Size(150, 43);
|
||||
Load += ContactControl_Load;
|
||||
Paint += ContactControl_Paint;
|
||||
((System.ComponentModel.ISupportInitialize)pbProfilePic).EndInit();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private PictureBox pbProfilePic;
|
||||
private Label lblUsername;
|
||||
private Label lblStatus;
|
||||
}
|
||||
}
|
||||
94
qtcnet-client/Controls/ContactControl.cs
Normal file
94
qtcnet-client/Controls/ContactControl.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using qtcnet_client.Properties;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
public partial class ContactControl : UserControl
|
||||
{
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public string UserId { get; set; } = string.Empty; // only for distinction
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string Username { get; set; } = "Username";
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string TextStatus { get; set; } = "Status";
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public int Status { get; set; } = 0;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public Image ProfilePic { get; set; } = Resources.DefaultPfp;
|
||||
|
||||
public event EventHandler? OnContactDoubleClicked;
|
||||
|
||||
bool _isHovering = false;
|
||||
public ContactControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ContactControl_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
Rectangle bgBounds = ClientRectangle;
|
||||
|
||||
Color statusColor = Color.Transparent;
|
||||
switch (Status)
|
||||
{
|
||||
case 0:
|
||||
statusColor = Color.LightGray;
|
||||
break;
|
||||
case 1:
|
||||
statusColor = Color.LawnGreen;
|
||||
break;
|
||||
case 2:
|
||||
statusColor = Color.Gold;
|
||||
break;
|
||||
case 3:
|
||||
statusColor = Color.Red;
|
||||
break;
|
||||
}
|
||||
|
||||
// draw background based on contacts status
|
||||
using LinearGradientBrush lgb = new(bgBounds, statusColor, BackColor, LinearGradientMode.Horizontal);
|
||||
g.FillRectangle(lgb, bgBounds);
|
||||
}
|
||||
|
||||
private void ContactControl_Load(object sender, EventArgs e)
|
||||
{
|
||||
lblUsername.Text = Username;
|
||||
lblStatus.Text = $"'{TextStatus}'";
|
||||
pbProfilePic.Image = ProfilePic;
|
||||
|
||||
if (Status == 0)
|
||||
{
|
||||
lblStatus.Visible = false;
|
||||
lblUsername.Location = new(44, 15);
|
||||
}
|
||||
}
|
||||
|
||||
private void lblUsername_MouseHover(object sender, EventArgs e)
|
||||
{
|
||||
if (!_isHovering)
|
||||
{
|
||||
lblUsername.ForeColor = Color.White;
|
||||
_isHovering = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void lblUsername_MouseLeave(object sender, EventArgs e)
|
||||
{
|
||||
if (_isHovering)
|
||||
{
|
||||
lblUsername.ForeColor = Color.Black;
|
||||
_isHovering = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void lblUsername_DoubleClick(object sender, EventArgs e) => OnContactDoubleClicked?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Controls/ContactControl.resx
Normal file
120
qtcnet-client/Controls/ContactControl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
133
qtcnet-client/Controls/CurrentProfileControl.Designer.cs
generated
Normal file
133
qtcnet-client/Controls/CurrentProfileControl.Designer.cs
generated
Normal file
@ -0,0 +1,133 @@
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
partial class CurrentProfileControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
pbCurrentProfilePic = new PictureBox();
|
||||
llblSignOut = new LinkLabel();
|
||||
linkLabel1 = new LinkLabel();
|
||||
pictureBox1 = new PictureBox();
|
||||
lblUsername = new Label();
|
||||
lblCurrencyAmount = new Label();
|
||||
((System.ComponentModel.ISupportInitialize)pbCurrentProfilePic).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// pbCurrentProfilePic
|
||||
//
|
||||
pbCurrentProfilePic.Image = Properties.Resources.DefaultPfp;
|
||||
pbCurrentProfilePic.Location = new Point(3, 3);
|
||||
pbCurrentProfilePic.Name = "pbCurrentProfilePic";
|
||||
pbCurrentProfilePic.Size = new Size(69, 67);
|
||||
pbCurrentProfilePic.SizeMode = PictureBoxSizeMode.Zoom;
|
||||
pbCurrentProfilePic.TabIndex = 0;
|
||||
pbCurrentProfilePic.TabStop = false;
|
||||
//
|
||||
// llblSignOut
|
||||
//
|
||||
llblSignOut.AutoSize = true;
|
||||
llblSignOut.Location = new Point(75, 24);
|
||||
llblSignOut.Name = "llblSignOut";
|
||||
llblSignOut.Size = new Size(55, 15);
|
||||
llblSignOut.TabIndex = 2;
|
||||
llblSignOut.TabStop = true;
|
||||
llblSignOut.Text = "Not You?";
|
||||
//
|
||||
// linkLabel1
|
||||
//
|
||||
linkLabel1.AutoSize = true;
|
||||
linkLabel1.Location = new Point(130, 24);
|
||||
linkLabel1.Name = "linkLabel1";
|
||||
linkLabel1.Size = new Size(64, 15);
|
||||
linkLabel1.TabIndex = 3;
|
||||
linkLabel1.TabStop = true;
|
||||
linkLabel1.Text = "Edit Profile";
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
pictureBox1.Image = Properties.Resources.CurrencyIcon;
|
||||
pictureBox1.Location = new Point(79, 49);
|
||||
pictureBox1.Name = "pictureBox1";
|
||||
pictureBox1.Size = new Size(14, 14);
|
||||
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
|
||||
pictureBox1.TabIndex = 4;
|
||||
pictureBox1.TabStop = false;
|
||||
//
|
||||
// lblUsername
|
||||
//
|
||||
lblUsername.AutoSize = true;
|
||||
lblUsername.Font = new Font("Segoe UI", 9F, FontStyle.Bold | FontStyle.Italic);
|
||||
lblUsername.ForeColor = Color.Black;
|
||||
lblUsername.Location = new Point(76, 9);
|
||||
lblUsername.Name = "lblUsername";
|
||||
lblUsername.Size = new Size(94, 15);
|
||||
lblUsername.TabIndex = 1;
|
||||
lblUsername.Text = "Welcome, User!";
|
||||
//
|
||||
// lblCurrencyAmount
|
||||
//
|
||||
lblCurrencyAmount.AutoSize = true;
|
||||
lblCurrencyAmount.Font = new Font("Segoe UI", 9F, FontStyle.Bold);
|
||||
lblCurrencyAmount.ForeColor = Color.Black;
|
||||
lblCurrencyAmount.Location = new Point(94, 49);
|
||||
lblCurrencyAmount.Name = "lblCurrencyAmount";
|
||||
lblCurrencyAmount.Size = new Size(35, 15);
|
||||
lblCurrencyAmount.TabIndex = 5;
|
||||
lblCurrencyAmount.Text = "9999";
|
||||
//
|
||||
// CurrentProfileControl
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
AutoSize = true;
|
||||
BackColor = Color.Transparent;
|
||||
Controls.Add(lblCurrencyAmount);
|
||||
Controls.Add(pictureBox1);
|
||||
Controls.Add(linkLabel1);
|
||||
Controls.Add(llblSignOut);
|
||||
Controls.Add(lblUsername);
|
||||
Controls.Add(pbCurrentProfilePic);
|
||||
Name = "CurrentProfileControl";
|
||||
Size = new Size(197, 73);
|
||||
Load += CurrentProfileControl_Load;
|
||||
((System.ComponentModel.ISupportInitialize)pbCurrentProfilePic).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private PictureBox pbCurrentProfilePic;
|
||||
private LinkLabel llblSignOut;
|
||||
private LinkLabel linkLabel1;
|
||||
private PictureBox pictureBox1;
|
||||
private Label lblUsername;
|
||||
private Label lblCurrencyAmount;
|
||||
}
|
||||
}
|
||||
33
qtcnet-client/Controls/CurrentProfileControl.cs
Normal file
33
qtcnet-client/Controls/CurrentProfileControl.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using qtcnet_client.Properties;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
public partial class CurrentProfileControl : UserControl
|
||||
{
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string Username { get; set; } = "Username";
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public int CurrencyCount { get; set; } = 0;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public Image ProfileImage { get; set; } = Resources.DefaultPfp;
|
||||
|
||||
public CurrentProfileControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void CurrentProfileControl_Load(object sender, EventArgs e)
|
||||
{
|
||||
lblUsername.Text = $"Welcome, {Username}!";
|
||||
lblCurrencyAmount.Text = CurrencyCount.ToString();
|
||||
pbCurrentProfilePic.Image = ProfileImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Controls/CurrentProfileControl.resx
Normal file
120
qtcnet-client/Controls/CurrentProfileControl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
158
qtcnet-client/Controls/LoginControl.Designer.cs
generated
Normal file
158
qtcnet-client/Controls/LoginControl.Designer.cs
generated
Normal file
@ -0,0 +1,158 @@
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
partial class LoginControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
pbDefaultPfp = new Krypton.Toolkit.KryptonPictureBox();
|
||||
txtEmail = new Krypton.Toolkit.KryptonTextBox();
|
||||
lblEmail = new Label();
|
||||
lblPassword = new Label();
|
||||
cbRememberMe = new Krypton.Toolkit.KryptonCheckBox();
|
||||
llblForgotPassword = new Krypton.Toolkit.KryptonLinkLabel();
|
||||
llblRegister = new Krypton.Toolkit.KryptonLinkLabel();
|
||||
btnLogin = new Krypton.Toolkit.KryptonButton();
|
||||
txtPassword = new Krypton.Toolkit.KryptonTextBox();
|
||||
((System.ComponentModel.ISupportInitialize)pbDefaultPfp).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// pbDefaultPfp
|
||||
//
|
||||
pbDefaultPfp.Image = Properties.Resources.DefaultPfp;
|
||||
pbDefaultPfp.Location = new Point(11, 7);
|
||||
pbDefaultPfp.Name = "pbDefaultPfp";
|
||||
pbDefaultPfp.Size = new Size(128, 128);
|
||||
pbDefaultPfp.SizeMode = PictureBoxSizeMode.AutoSize;
|
||||
pbDefaultPfp.TabIndex = 0;
|
||||
pbDefaultPfp.TabStop = false;
|
||||
//
|
||||
// txtEmail
|
||||
//
|
||||
txtEmail.Location = new Point(187, 23);
|
||||
txtEmail.Name = "txtEmail";
|
||||
txtEmail.Size = new Size(375, 23);
|
||||
txtEmail.TabIndex = 1;
|
||||
//
|
||||
// lblEmail
|
||||
//
|
||||
lblEmail.AutoSize = true;
|
||||
lblEmail.ForeColor = Color.White;
|
||||
lblEmail.Location = new Point(145, 27);
|
||||
lblEmail.Name = "lblEmail";
|
||||
lblEmail.Size = new Size(36, 15);
|
||||
lblEmail.TabIndex = 2;
|
||||
lblEmail.Text = "Email";
|
||||
//
|
||||
// lblPassword
|
||||
//
|
||||
lblPassword.AutoSize = true;
|
||||
lblPassword.ForeColor = Color.White;
|
||||
lblPassword.Location = new Point(145, 57);
|
||||
lblPassword.Name = "lblPassword";
|
||||
lblPassword.Size = new Size(57, 15);
|
||||
lblPassword.TabIndex = 4;
|
||||
lblPassword.Text = "Password";
|
||||
//
|
||||
// cbRememberMe
|
||||
//
|
||||
cbRememberMe.Location = new Point(208, 81);
|
||||
cbRememberMe.Name = "cbRememberMe";
|
||||
cbRememberMe.PaletteMode = Krypton.Toolkit.PaletteMode.Office2007Silver;
|
||||
cbRememberMe.Size = new Size(171, 20);
|
||||
cbRememberMe.TabIndex = 3;
|
||||
cbRememberMe.Values.Text = "Remember Me For 30 Days";
|
||||
//
|
||||
// llblForgotPassword
|
||||
//
|
||||
llblForgotPassword.Location = new Point(450, 81);
|
||||
llblForgotPassword.Name = "llblForgotPassword";
|
||||
llblForgotPassword.Size = new Size(112, 20);
|
||||
llblForgotPassword.TabIndex = 4;
|
||||
llblForgotPassword.Values.Text = "Forgot Passsword?";
|
||||
//
|
||||
// llblRegister
|
||||
//
|
||||
llblRegister.Location = new Point(448, 97);
|
||||
llblRegister.Name = "llblRegister";
|
||||
llblRegister.Size = new Size(118, 20);
|
||||
llblRegister.TabIndex = 5;
|
||||
llblRegister.Values.Text = "New Here? Register";
|
||||
llblRegister.LinkClicked += llblRegister_LinkClicked;
|
||||
//
|
||||
// btnLogin
|
||||
//
|
||||
btnLogin.Location = new Point(484, 119);
|
||||
btnLogin.Name = "btnLogin";
|
||||
btnLogin.Size = new Size(90, 25);
|
||||
btnLogin.TabIndex = 6;
|
||||
btnLogin.Values.DropDownArrowColor = Color.Empty;
|
||||
btnLogin.Values.Text = "Login";
|
||||
btnLogin.Click += btnLogin_Click;
|
||||
//
|
||||
// txtPassword
|
||||
//
|
||||
txtPassword.Location = new Point(208, 52);
|
||||
txtPassword.Name = "txtPassword";
|
||||
txtPassword.PasswordChar = '●';
|
||||
txtPassword.Size = new Size(354, 23);
|
||||
txtPassword.TabIndex = 2;
|
||||
txtPassword.UseSystemPasswordChar = true;
|
||||
//
|
||||
// LoginControl
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
BackColor = Color.Transparent;
|
||||
Controls.Add(txtPassword);
|
||||
Controls.Add(btnLogin);
|
||||
Controls.Add(llblRegister);
|
||||
Controls.Add(llblForgotPassword);
|
||||
Controls.Add(cbRememberMe);
|
||||
Controls.Add(lblPassword);
|
||||
Controls.Add(lblEmail);
|
||||
Controls.Add(txtEmail);
|
||||
Controls.Add(pbDefaultPfp);
|
||||
Name = "LoginControl";
|
||||
Size = new Size(575, 146);
|
||||
((System.ComponentModel.ISupportInitialize)pbDefaultPfp).EndInit();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Krypton.Toolkit.KryptonPictureBox pbDefaultPfp;
|
||||
private Krypton.Toolkit.KryptonTextBox txtEmail;
|
||||
private Label lblEmail;
|
||||
private Label lblPassword;
|
||||
private Krypton.Toolkit.KryptonCheckBox cbRememberMe;
|
||||
private Krypton.Toolkit.KryptonLinkLabel llblForgotPassword;
|
||||
private Krypton.Toolkit.KryptonLinkLabel llblRegister;
|
||||
private Krypton.Toolkit.KryptonButton btnLogin;
|
||||
private Krypton.Toolkit.KryptonTextBox txtPassword;
|
||||
}
|
||||
}
|
||||
77
qtcnet-client/Controls/LoginControl.cs
Normal file
77
qtcnet-client/Controls/LoginControl.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using Krypton.Toolkit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
public partial class LoginControl : UserControl
|
||||
{
|
||||
public string Email { get; private set; } = string.Empty;
|
||||
public string Password { get; private set; } = string.Empty;
|
||||
public bool RememberMe { get; private set; } = false;
|
||||
|
||||
public event EventHandler? OnSuccessfulLogin;
|
||||
public event EventHandler? OnRegisterPressed;
|
||||
public LoginControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void btnLogin_Click(object sender, EventArgs e)
|
||||
{
|
||||
ToggleControls(false);
|
||||
|
||||
bool formComplete = !string.IsNullOrWhiteSpace(txtEmail.Text) || !string.IsNullOrWhiteSpace(txtPassword.Text);
|
||||
if (formComplete)
|
||||
{
|
||||
Email = txtEmail.Text;
|
||||
Password = txtPassword.Text;
|
||||
RememberMe = cbRememberMe.Checked;
|
||||
|
||||
OnSuccessfulLogin?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
KryptonMessageBox.Show("A Required Field Is Missing. Please Complete The Form.", "Oops.");
|
||||
ToggleControls(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void llblRegister_LinkClicked(object sender, EventArgs e)
|
||||
{
|
||||
ToggleControls(false);
|
||||
OnRegisterPressed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void ToggleControls(bool toggle)
|
||||
{
|
||||
SuspendLayout();
|
||||
|
||||
txtEmail.Enabled = toggle;
|
||||
txtPassword.Enabled = toggle;
|
||||
cbRememberMe.Enabled = toggle;
|
||||
llblForgotPassword.Enabled = toggle;
|
||||
llblRegister.Enabled = toggle;
|
||||
btnLogin.Enabled = toggle;
|
||||
|
||||
ResumeLayout();
|
||||
}
|
||||
|
||||
public void ClearControls()
|
||||
{
|
||||
SuspendLayout();
|
||||
|
||||
txtEmail.Clear();
|
||||
txtPassword.Clear();
|
||||
cbRememberMe.Checked = false;
|
||||
|
||||
ResumeLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Controls/LoginControl.resx
Normal file
120
qtcnet-client/Controls/LoginControl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
284
qtcnet-client/Controls/MainTabControl.Designer.cs
generated
Normal file
284
qtcnet-client/Controls/MainTabControl.Designer.cs
generated
Normal file
@ -0,0 +1,284 @@
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
partial class MainTabControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainTabControl));
|
||||
ListViewItem listViewItem1 = new ListViewItem("Stock Market", "StockMarket");
|
||||
ListViewItem listViewItem2 = new ListViewItem("Guess The Number", "NumberGuessGame");
|
||||
ListViewItem listViewItem3 = new ListViewItem("Tic-Tac-Toe (Multiplayer)", "TicTacToe");
|
||||
tcMain = new TabControl();
|
||||
tpContacts = new TabPage();
|
||||
tlpContactsList = new TableLayoutPanel();
|
||||
tpRooms = new TabPage();
|
||||
tlpRoomsList = new TableLayoutPanel();
|
||||
tpUsers = new TabPage();
|
||||
lvUserList = new ListView();
|
||||
ilStatusIcons = new ImageList(components);
|
||||
tpGames = new TabPage();
|
||||
lvGameList = new ListView();
|
||||
ilGameIcons = new ImageList(components);
|
||||
tpStore = new TabPage();
|
||||
listView1 = new ListView();
|
||||
ilTabIcons = new ImageList(components);
|
||||
ilStoreIcons = new ImageList(components);
|
||||
tcMain.SuspendLayout();
|
||||
tpContacts.SuspendLayout();
|
||||
tpRooms.SuspendLayout();
|
||||
tpUsers.SuspendLayout();
|
||||
tpGames.SuspendLayout();
|
||||
tpStore.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tcMain
|
||||
//
|
||||
tcMain.Controls.Add(tpContacts);
|
||||
tcMain.Controls.Add(tpRooms);
|
||||
tcMain.Controls.Add(tpUsers);
|
||||
tcMain.Controls.Add(tpGames);
|
||||
tcMain.Controls.Add(tpStore);
|
||||
tcMain.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||
tcMain.ImageList = ilTabIcons;
|
||||
tcMain.Location = new Point(0, 0);
|
||||
tcMain.Multiline = true;
|
||||
tcMain.Name = "tcMain";
|
||||
tcMain.SelectedIndex = 0;
|
||||
tcMain.Size = new Size(380, 577);
|
||||
tcMain.TabIndex = 0;
|
||||
//
|
||||
// tpContacts
|
||||
//
|
||||
tpContacts.BorderStyle = BorderStyle.Fixed3D;
|
||||
tpContacts.Controls.Add(tlpContactsList);
|
||||
tpContacts.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
tpContacts.ImageKey = "Contacts";
|
||||
tpContacts.Location = new Point(4, 24);
|
||||
tpContacts.Name = "tpContacts";
|
||||
tpContacts.Padding = new Padding(3);
|
||||
tpContacts.RightToLeft = RightToLeft.No;
|
||||
tpContacts.Size = new Size(372, 549);
|
||||
tpContacts.TabIndex = 1;
|
||||
tpContacts.Text = "Contacts";
|
||||
tpContacts.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tlpContactsList
|
||||
//
|
||||
tlpContactsList.ColumnCount = 1;
|
||||
tlpContactsList.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tlpContactsList.Dock = DockStyle.Fill;
|
||||
tlpContactsList.Location = new Point(3, 3);
|
||||
tlpContactsList.Name = "tlpContactsList";
|
||||
tlpContactsList.Padding = new Padding(0, 5, 0, 5);
|
||||
tlpContactsList.RowCount = 1;
|
||||
tlpContactsList.RowStyles.Add(new RowStyle());
|
||||
tlpContactsList.Size = new Size(362, 539);
|
||||
tlpContactsList.TabIndex = 0;
|
||||
//
|
||||
// tpRooms
|
||||
//
|
||||
tpRooms.BorderStyle = BorderStyle.Fixed3D;
|
||||
tpRooms.Controls.Add(tlpRoomsList);
|
||||
tpRooms.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
tpRooms.ImageKey = "Rooms";
|
||||
tpRooms.Location = new Point(4, 24);
|
||||
tpRooms.Name = "tpRooms";
|
||||
tpRooms.Padding = new Padding(3);
|
||||
tpRooms.RightToLeft = RightToLeft.No;
|
||||
tpRooms.Size = new Size(372, 549);
|
||||
tpRooms.TabIndex = 7;
|
||||
tpRooms.Text = "Rooms";
|
||||
tpRooms.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tlpRoomsList
|
||||
//
|
||||
tlpRoomsList.ColumnCount = 1;
|
||||
tlpRoomsList.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tlpRoomsList.Dock = DockStyle.Fill;
|
||||
tlpRoomsList.Location = new Point(3, 3);
|
||||
tlpRoomsList.Name = "tlpRoomsList";
|
||||
tlpRoomsList.Padding = new Padding(0, 3, 0, 3);
|
||||
tlpRoomsList.RowCount = 1;
|
||||
tlpRoomsList.RowStyles.Add(new RowStyle());
|
||||
tlpRoomsList.Size = new Size(362, 539);
|
||||
tlpRoomsList.TabIndex = 1;
|
||||
//
|
||||
// tpUsers
|
||||
//
|
||||
tpUsers.BorderStyle = BorderStyle.Fixed3D;
|
||||
tpUsers.Controls.Add(lvUserList);
|
||||
tpUsers.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
tpUsers.ImageKey = "Users";
|
||||
tpUsers.Location = new Point(4, 24);
|
||||
tpUsers.Name = "tpUsers";
|
||||
tpUsers.Size = new Size(372, 549);
|
||||
tpUsers.TabIndex = 3;
|
||||
tpUsers.Text = "Users";
|
||||
tpUsers.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// lvUserList
|
||||
//
|
||||
lvUserList.BorderStyle = BorderStyle.FixedSingle;
|
||||
lvUserList.Location = new Point(3, 3);
|
||||
lvUserList.MultiSelect = false;
|
||||
lvUserList.Name = "lvUserList";
|
||||
lvUserList.Size = new Size(364, 541);
|
||||
lvUserList.SmallImageList = ilStatusIcons;
|
||||
lvUserList.TabIndex = 0;
|
||||
lvUserList.UseCompatibleStateImageBehavior = false;
|
||||
lvUserList.View = View.List;
|
||||
//
|
||||
// ilStatusIcons
|
||||
//
|
||||
ilStatusIcons.ColorDepth = ColorDepth.Depth32Bit;
|
||||
ilStatusIcons.ImageStream = (ImageListStreamer)resources.GetObject("ilStatusIcons.ImageStream");
|
||||
ilStatusIcons.TransparentColor = Color.Transparent;
|
||||
ilStatusIcons.Images.SetKeyName(0, "Offline");
|
||||
ilStatusIcons.Images.SetKeyName(1, "Online");
|
||||
ilStatusIcons.Images.SetKeyName(2, "Away");
|
||||
ilStatusIcons.Images.SetKeyName(3, "DoNotDisturb");
|
||||
//
|
||||
// tpGames
|
||||
//
|
||||
tpGames.BorderStyle = BorderStyle.Fixed3D;
|
||||
tpGames.Controls.Add(lvGameList);
|
||||
tpGames.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
tpGames.ImageKey = "Games";
|
||||
tpGames.Location = new Point(4, 24);
|
||||
tpGames.Name = "tpGames";
|
||||
tpGames.Padding = new Padding(3);
|
||||
tpGames.Size = new Size(372, 549);
|
||||
tpGames.TabIndex = 5;
|
||||
tpGames.Text = "Games";
|
||||
tpGames.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// lvGameList
|
||||
//
|
||||
lvGameList.Dock = DockStyle.Fill;
|
||||
lvGameList.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||
listViewItem1.ToolTipText = "Stock Market";
|
||||
listViewItem2.ToolTipText = "Guess The Number";
|
||||
listViewItem3.ToolTipText = "Tic-Tac-Toe (Multiplayer)";
|
||||
lvGameList.Items.AddRange(new ListViewItem[] { listViewItem1, listViewItem2, listViewItem3 });
|
||||
lvGameList.LargeImageList = ilGameIcons;
|
||||
lvGameList.Location = new Point(3, 3);
|
||||
lvGameList.MultiSelect = false;
|
||||
lvGameList.Name = "lvGameList";
|
||||
lvGameList.Size = new Size(362, 539);
|
||||
lvGameList.SmallImageList = ilGameIcons;
|
||||
lvGameList.TabIndex = 0;
|
||||
lvGameList.UseCompatibleStateImageBehavior = false;
|
||||
//
|
||||
// ilGameIcons
|
||||
//
|
||||
ilGameIcons.ColorDepth = ColorDepth.Depth32Bit;
|
||||
ilGameIcons.ImageStream = (ImageListStreamer)resources.GetObject("ilGameIcons.ImageStream");
|
||||
ilGameIcons.TransparentColor = Color.Transparent;
|
||||
ilGameIcons.Images.SetKeyName(0, "StockMarket");
|
||||
ilGameIcons.Images.SetKeyName(1, "NumberGuessGame");
|
||||
ilGameIcons.Images.SetKeyName(2, "TicTacToe");
|
||||
//
|
||||
// tpStore
|
||||
//
|
||||
tpStore.BorderStyle = BorderStyle.Fixed3D;
|
||||
tpStore.Controls.Add(listView1);
|
||||
tpStore.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
tpStore.ImageKey = "Store";
|
||||
tpStore.Location = new Point(4, 24);
|
||||
tpStore.Name = "tpStore";
|
||||
tpStore.Padding = new Padding(3);
|
||||
tpStore.Size = new Size(372, 549);
|
||||
tpStore.TabIndex = 8;
|
||||
tpStore.Text = "Store";
|
||||
tpStore.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// listView1
|
||||
//
|
||||
listView1.Dock = DockStyle.Fill;
|
||||
listView1.Location = new Point(3, 3);
|
||||
listView1.MultiSelect = false;
|
||||
listView1.Name = "listView1";
|
||||
listView1.Size = new Size(362, 539);
|
||||
listView1.TabIndex = 0;
|
||||
listView1.UseCompatibleStateImageBehavior = false;
|
||||
//
|
||||
// ilTabIcons
|
||||
//
|
||||
ilTabIcons.ColorDepth = ColorDepth.Depth32Bit;
|
||||
ilTabIcons.ImageStream = (ImageListStreamer)resources.GetObject("ilTabIcons.ImageStream");
|
||||
ilTabIcons.TransparentColor = Color.Transparent;
|
||||
ilTabIcons.Images.SetKeyName(0, "Contacts");
|
||||
ilTabIcons.Images.SetKeyName(1, "Rooms");
|
||||
ilTabIcons.Images.SetKeyName(2, "Users");
|
||||
ilTabIcons.Images.SetKeyName(3, "Games");
|
||||
ilTabIcons.Images.SetKeyName(4, "Store");
|
||||
//
|
||||
// ilStoreIcons
|
||||
//
|
||||
ilStoreIcons.ColorDepth = ColorDepth.Depth32Bit;
|
||||
ilStoreIcons.ImageSize = new Size(32, 32);
|
||||
ilStoreIcons.TransparentColor = Color.Transparent;
|
||||
//
|
||||
// MainTabControl
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
AutoSize = true;
|
||||
BackColor = Color.Transparent;
|
||||
Controls.Add(tcMain);
|
||||
DoubleBuffered = true;
|
||||
Name = "MainTabControl";
|
||||
Size = new Size(383, 580);
|
||||
tcMain.ResumeLayout(false);
|
||||
tpContacts.ResumeLayout(false);
|
||||
tpRooms.ResumeLayout(false);
|
||||
tpUsers.ResumeLayout(false);
|
||||
tpGames.ResumeLayout(false);
|
||||
tpStore.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private TabControl tcMain;
|
||||
private TabPage tpContacts;
|
||||
private TabPage tpUsers;
|
||||
private ListView lvUserList;
|
||||
private TabPage tpGames;
|
||||
private ListView lvGameList;
|
||||
private ImageList ilTabIcons;
|
||||
private ImageList ilStatusIcons;
|
||||
private TableLayoutPanel tlpContactsList;
|
||||
private TabPage tpStore;
|
||||
private ListView listView1;
|
||||
private TabPage tpRooms;
|
||||
private TableLayoutPanel tlpRoomsList;
|
||||
private ImageList ilGameIcons;
|
||||
private ImageList ilStoreIcons;
|
||||
}
|
||||
}
|
||||
68
qtcnet-client/Controls/MainTabControl.cs
Normal file
68
qtcnet-client/Controls/MainTabControl.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using Krypton.Toolkit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
public partial class MainTabControl : UserControl
|
||||
{
|
||||
public event EventHandler? OnContactControlDoubleClicked;
|
||||
public event EventHandler? OnRoomControlDoubleClicked;
|
||||
|
||||
public MainTabControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void AddContacts(List<ContactControl> contactControls)
|
||||
{
|
||||
tlpContactsList.SuspendLayout();
|
||||
|
||||
foreach (ContactControl contactControl in contactControls)
|
||||
{
|
||||
contactControl.Width = tlpContactsList.ClientSize.Width;
|
||||
contactControl.OnContactDoubleClicked += ContactControl_OnContactDoubleClicked;
|
||||
}
|
||||
|
||||
tlpContactsList.Controls.Clear();
|
||||
tlpContactsList.Controls.AddRange([.. contactControls.DistinctBy(ctrl => ctrl.UserId)]);
|
||||
|
||||
tlpContactsList.ResumeLayout(true);
|
||||
}
|
||||
|
||||
private void ContactControl_OnContactDoubleClicked(object? sender, EventArgs e) => OnContactControlDoubleClicked?.Invoke(sender, e);
|
||||
|
||||
public void AddRooms(List<RoomControl> roomControls)
|
||||
{
|
||||
tlpRoomsList.SuspendLayout();
|
||||
|
||||
foreach (RoomControl roomControl in roomControls)
|
||||
{
|
||||
roomControl.Width = tlpRoomsList.ClientSize.Width;
|
||||
roomControl.OnRoomDoubleClicked += RoomControl_OnRoomDoubleClicked;
|
||||
}
|
||||
|
||||
tlpRoomsList.Controls.Clear();
|
||||
tlpRoomsList.Controls.AddRange([.. roomControls.DistinctBy(ctrl => ctrl.RoomId)]);
|
||||
|
||||
tlpRoomsList.ResumeLayout(true);
|
||||
}
|
||||
|
||||
private void RoomControl_OnRoomDoubleClicked(object? sender, EventArgs e) => OnRoomControlDoubleClicked?.Invoke(sender, e);
|
||||
|
||||
public void AddUsers(List<ListViewItem> users)
|
||||
{
|
||||
lvUserList.SuspendLayout();
|
||||
|
||||
lvUserList.Items.Clear();
|
||||
lvUserList.Items.AddRange([.. users.DistinctBy(lvi => lvi.Tag)]); // Tag = UserId here
|
||||
|
||||
lvUserList.ResumeLayout(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
515
qtcnet-client/Controls/MainTabControl.resx
Normal file
515
qtcnet-client/Controls/MainTabControl.resx
Normal file
@ -0,0 +1,515 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="ilStatusIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>121, 15</value>
|
||||
</metadata>
|
||||
<data name="ilStatusIcons.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
|
||||
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
|
||||
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAAhQAAAJNU0Z0AUkBTAIBAQQB
|
||||
AAGoAQABqAEAARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASD/
|
||||
AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AC4AAwYBBwM0AVQDUQGiA14B0gNaAekDYAHoA10B
|
||||
0QNQAZ8DMQFNAwUBBhgAAwYBBwM0AVQDUQGiA14B0gNaAekDYAHoA10B0QNQAZ8DMQFNAwUBBhgAAwYB
|
||||
BwM0AVQDUQGiA14B0gNaAekDYAHoA10B0QNQAZ8DMQFNAwUBBhgAAwYBBwM0AVQDUQGiA14B0gNaAekD
|
||||
YAHoA10B0QNQAZ8DMQFNAwUBBhQAAyABLQNUAasDWwHkA08B9QMkAfsDOQH+AzkB/gMkAfsDUwH0A2IB
|
||||
4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQBSAFaAUgB9QEhAVUBIQH7ARUBVQEVAf4BFQFVARUB/gEhAVUB
|
||||
IQH7A1MB9ANiAeEDUQGhAx4BKhAAAyABLQNUAasDWwHkAUgCWgH1ASECVQH7ARUCVQH+ARUCVQH+ASEC
|
||||
VQH7A1MB9ANiAeEDUQGhAx4BKhAAAyABLQNUAasDWwHkAkgBWgH1AiEBVQH7AhUBVQH+AhUBVQH+AiEB
|
||||
VQH7A1MB9ANiAeEDUQGhAx4BKgwAAxsBJQNYAb0DWgHyAz0B/gMwAf8DOQH/AzwB/wM2Af8DKgH/AyQB
|
||||
/wNAAf0DWwHwA1YBsgMaASMIAAMbASUDWAG9A1oB8gEVAV0BFQH+AQABVwEAAf8BAAFnAQAB/wEAAWwB
|
||||
AAH/AQABYQEAAf8BAAFMAQAB/wEAAUABAAH/ASoBQAEqAf0BVwFeAVcB8ANWAbIBGQEaARkBIwgAAxsB
|
||||
JQNYAb0DWgHyARUCXQH+AQACVwH/AQACZwH/AQACbAH/AQACYQH/AQACTAH/AQACQAH/ASoCQAH9AVcC
|
||||
XgHwA1YBsgEZAhoBIwgAAxsBJQNYAb0DWgHyAhUBXQH+AgABVwH/AgABZwH/AgABbAH/AgABYQH/AgAB
|
||||
TAH/AgABQAH/AioBQAH9AlcBXgHwA1YBsgIZARoBIwQAAwMBBANSAaUDYAHzA0kB/wNVAf8DZQH/A3EB
|
||||
/wN1Af8DcQH/A2QB/wNMAf8DMQH/AzkB/gNfAe4DUAGaAwMBBAMDAQQBUgFTAVIBpQFTAW8BUwHzAQAB
|
||||
ggEAAf8BAAGZAQAB/wEAAbYBAAH/AQABzAEAAf8BAAHTAQAB/wEAAcsBAAH/AQABswEAAf8BAAGIAQAB
|
||||
/wEAAVcBAAH/ARUBVQEVAf4BXAFiAVwB7gNQAZoDAwEEAwMBBAFSAlMBpQFTAm8B8wEAAoIB/wEAApkB
|
||||
/wEAArYB/wEAAswB/wEAAtMB/wEAAssB/wEAArMB/wEAAogB/wEAAlcB/wEVAlUB/gFcAmIB7gNQAZoD
|
||||
AwEEAwMBBAJSAVMBpQJTAW8B8wIAAYIB/wIAAZkB/wIAAbYB/wIAAcwB/wIAAdMB/wIAAcsB/wIAAbMB
|
||||
/wIAAYgB/wIAAVcB/wIVAVUB/gJcAWIB7gNQAZoDAwEEAy0BRANgAegDeAH+A24B/wN7Af8DhQH/A4oB
|
||||
/wOMAf8DigH/A4UB/wN2Af8DVwH/AzIB/wNAAf0DXgHdAyoBPwMtAUQBYAFpAWAB6AEVAYoBFQH+AQAB
|
||||
xgEAAf8BAAHcAQAB/wEAAe4BAAH/AQAB+AEAAf8BAAH7AQAB/wEAAfkBAAH/AQAB7wEAAf8BAAHUAQAB
|
||||
/wEAAZwBAAH/AQABWgEAAf8BKgFAASoB/QNeAd0DKgE/Ay0BRAFgAmkB6AEVAooB/gEAAsYB/wEAAtwB
|
||||
/wEAAu4B/wEAAvgB/wEAAvsB/wEAAvkB/wEAAu8B/wEAAtQB/wEAApwB/wEAAloB/wEqAkAB/QNeAd0D
|
||||
KgE/Ay0BRAJgAWkB6AIVAYoB/gIAAcYB/wIAAdwB/wIAAe4B/wIAAfgB/wIAAfsB/wIAAfkB/wIAAe8B
|
||||
/wIAAdQB/wIAAZwB/wIAAVoB/wIqAUAB/QNeAd0DKgE/A04BlQN3AfgDfwH/A4UB/wOKAf8DjQH/A44B
|
||||
/wOOAf8DjgH/A40B/wOJAf8DdwH/A00B/wMlAf8DWgHyA0oBiwNOAZUBPwGKAT8B+AEAAeUBAAH/AQAB
|
||||
7wEAAf8BAAH4AQAB/wEAAf0BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/gEAAf8BAAH2AQAB
|
||||
/wEAAdUBAAH/AQABiwEAAf8BAAFBAQAB/wNaAfIDSgGLA04BlQE/AooB+AEAAuUB/wEAAu8B/wEAAvgB
|
||||
/wEAAv0B/wEAA/8BAAP/AQAD/wEAAv4B/wEAAvYB/wEAAtUB/wEAAosB/wEAAkEB/wNaAfIDSgGLA04B
|
||||
lQI/AYoB+AIAAeUB/wIAAe8B/wIAAfgB/wIAAf0B/wIAAv8CAAL/AgAC/wIAAf4B/wIAAfYB/wIAAdUB
|
||||
/wIAAYsB/wIAAUEB/wNaAfIDSgGLA18B0wN+AfwDkwH/A44B/wONAf8DjgH/A44B/wOOAf8DjgH/A44B
|
||||
/wONAf8DhQH/A2cB/wM0Af8DQQH5A1oBxAFbAV8BWwHTASsBtgErAfwBDgH7AQ4B/wEDAf0BAwH/AQAB
|
||||
/gEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/QEAAf8BAAHvAQAB
|
||||
/wEAAbkBAAH/AQABXQEAAf8BPgFBAT4B+QNaAcQBWwJfAdMBKwK2AfwBDgL7Af8BAwL9Af8BAAL+Af8B
|
||||
AAP/AQAD/wEAA/8BAAP/AQAD/wEAAv0B/wEAAu8B/wEAArkB/wEAAl0B/wE+AkEB+QNaAcQCWwFfAdMC
|
||||
KwG2AfwCDgH7Af8CAwH9Af8CAAH+Af8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAf0B/wIAAe8B/wIAAbkB
|
||||
/wIAAV0B/wI+AUEB+QNaAcQDbgH1A4AB/gOfAf8DkwH/A48B/wOOAf8DjgH/A44B/wOOAf8DjgH/A44B
|
||||
/wOLAf8DdwH/A0gB/wNAAf0DYgHhAU0BfwFNAfUBOQHVATkB/gEnAf8BJwH/AQsB/wELAf8BAQH/AQEB
|
||||
/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAfkBAAH/AQAB
|
||||
1gEAAf8BAAGBAQAB/wEqAUABKgH9A2IB4QFNAn8B9QE5AtUB/gEnA/8BCwP/AQED/wEAA/8BAAP/AQAD
|
||||
/wEAA/8BAAP/AQAD/wEAAvkB/wEAAtYB/wEAAoEB/wEqAkAB/QNiAeECTQF/AfUCOQHVAf4CJwL/AgsC
|
||||
/wIBAv8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAv8CAAH5Af8CAAHWAf8CAAGBAf8CKgFAAf0DYgHhA3IB
|
||||
9gOEAf4DqwH/A5kB/wOQAf8DjgH/A44B/wOOAf8DjgH/A44B/wOOAf8DjQH/A38B/wNVAf8DQAH9A14B
|
||||
4gFIAX8BSAH2AVwB1QFcAf4BQgH/AUIB/wEZAf8BGQH/AQQB/wEEAf8BAAH/AQAB/wEAAf8BAAH/AQAB
|
||||
/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH9AQAB/wEAAeQBAAH/AQABmAEAAf8BKgFAASoB
|
||||
/QNeAeIBSAJ/AfYBXALVAf4BQgP/ARkD/wEEA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAA/8BAAL9Af8B
|
||||
AALkAf8BAAKYAf8BKgJAAf0DXgHiAkgBfwH2AlwB1QH+AkIC/wIZAv8CBAL/AgAC/wIAAv8CAAL/AgAC
|
||||
/wIAAv8CAAL/AgAB/QH/AgAB5AH/AgABmAH/AioBQAH9A14B4gNhAdYDgwH8A7gB/wOjAf8DkwH/A44B
|
||||
/wOOAf8DjgH/A44B/wOOAf8DjgH/A40B/wOCAf8DXAH/A00B+gNaAccBXAFhAVwB1gFkAboBZAH8AV8B
|
||||
/wFfAf8BLwH/AS8B/wEMAf8BDAH/AQEB/wEBAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
|
||||
/wEAAf8BAAH/AQAB/gEAAf8BAAHqAQAB/wEAAaUBAAH/ASkBTQEpAfoDWgHHAVwCYQHWAWQCugH8AV8D
|
||||
/wEvA/8BDAP/AQED/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAC/gH/AQAC6gH/AQACpQH/ASkCTQH6A1oB
|
||||
xwJcAWEB1gJkAboB/AJfAv8CLwL/AgwC/wIBAv8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAf4B/wIAAeoB
|
||||
/wIAAaUB/wIpAU0B+gNaAccDUAGaA4sB+QPFAf8DsgH/A5wB/wORAf8DjgH/A44B/wOOAf8DjgH/A48B
|
||||
/wOOAf8DgwH/A2AB/wNaAfIDTAGQA1ABmgFqAZkBagH5AXwB/wF8Af8BUQH/AVEB/wEfAf8BHwH/AQcB
|
||||
/wEHAf8BAQH/AQEB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wECAf8BAgH/AQIB/gECAf8BAAHrAQAB
|
||||
/wEAAa0BAAH/AVoBawFaAfIDTAGQA1ABmgFqApkB+QF8A/8BUQP/AR8D/wEHA/8BAQP/AQAD/wEAA/8B
|
||||
AAP/AQID/wECAv4B/wEAAusB/wEAAq0B/wFaAmsB8gNMAZADUAGaAmoBmQH5AnwC/wJRAv8CHwL/AgcC
|
||||
/wIBAv8CAAL/AgAC/wIAAv8CAgL/AgIB/gH/AgAB6wH/AgABrQH/AloBawHyA0wBkAMvAUkDbAHrA6YB
|
||||
/gPGAf8DrgH/A5wB/wOTAf8DkAH/A48B/wOQAf8DkwH/A5MB/wOFAf8DUQH9A2AB4AMtAUUDLwFJA2wB
|
||||
6wGAAdUBgAH+AX8B/wF/Af8BSQH/AUkB/wEfAf8BHwH/AQwB/wEMAf8BBQH/AQUB/wEDAf8BAwH/AQUB
|
||||
/wEFAf8BCgH/AQoB/wEKAf4BCgH/AQEB7QEBAf8BKgG2ASoB/QFgAWYBYAHgAy0BRQMvAUkDbAHrAYAC
|
||||
1QH+AX8D/wFJA/8BHwP/AQwD/wEFA/8BAwP/AQUD/wEKA/8BCgL+Af8BAQLtAf8BKgK2Af0BYAJmAeAD
|
||||
LQFFAy8BSQNsAesCgAHVAf4CfwL/AkkC/wIfAv8CDAL/AgUC/wIDAv8CBQL/AgoC/wIKAf4B/wIBAe0B
|
||||
/wIqAbYB/QJgAWYB4AMtAUUDAwEEA1YBrgN2AfUD2QH/A8sB/wO3Af8DpwH/A50B/wOaAf8DnAH/A58B
|
||||
/wObAf8DiQH/A2gB8ANSAaMDAwEEAwMBBANWAa4BbgF/AW4B9QGoAf8BqAH/AYkB/wGJAf8BXAH/AVwB
|
||||
/wE3Af8BNwH/ASIB/wEiAf8BGwH/ARsB/wEfAf8BHwH/ASYB/wEmAf8BHQH/AR0B/wEFAfMBBQH/AVcB
|
||||
aQFXAfADUgGjAwMBBAMDAQQDVgGuAW4CfwH1AagD/wGJA/8BXAP/ATcD/wEiA/8BGwP/AR8D/wEmA/8B
|
||||
HQP/AQUC8wH/AVcCaQHwA1IBowMDAQQDAwEEA1YBrgJuAX8B9QKoAv8CiQL/AlwC/wI3Av8CIgL/AhsC
|
||||
/wIfAv8CJgL/Ah0C/wIFAfMB/wJXAWkB8ANSAaMDAwEEBAADHAEnA10BxwN6AfYDtQH+A9cB/wPMAf8D
|
||||
wgH/A7sB/wO3Af8DsQH/A4AB/gNoAfQDWQG8AxsBJggAAxwBJwNdAccBdQF/AXUB9gGNAdUBjQH+AaUB
|
||||
/wGlAf8BiwH/AYsB/wF0Af8BdAH/AWYB/wFmAf8BXAH/AVwB/wFOAf8BTgH/AUUB1QFFAf4BUwF6AVMB
|
||||
9AFXAVkBVwG8AxsBJggAAxwBJwNdAccBdQJ/AfYBjQLVAf4BpQP/AYsD/wF0A/8BZgP/AVwD/wFOA/8B
|
||||
RQLVAf4BUwJ6AfQBVwJZAbwDGwEmCAADHAEnA10BxwJ1AX8B9gKNAdUB/gKlAv8CiwL/AnQC/wJmAv8C
|
||||
XAL/Ak4C/wJFAdUB/gJTAXoB9AJXAVkBvAMbASYMAAMhATADWQG2A2oB7gObAfoDvgH9A9QB/wPMAf8D
|
||||
vgH9A4cB+QNsAesDVQGsAx8BLBAAAyEBMANZAbYBaAFsAWgB7gGBAaUBgQH6Aa4BwAGuAf0BnwH/AZ8B
|
||||
/wGMAf8BjAH/AWEBwAFhAf0BaAGZAWgB+QFhAWwBYQHrA1UBrAMfASwQAAMhATADWQG2AWgCbAHuAYEC
|
||||
pQH6Aa4CwAH9AZ8D/wGMA/8BYQLAAf0BaAKZAfkBYQJsAesDVQGsAx8BLBAAAyEBMANZAbYCaAFsAe4C
|
||||
gQGlAfoCrgHAAf0CnwL/AowC/wJhAcAB/QJoAZkB+QJhAWwB6wNVAawDHwEsFAADBgEHAzYBWANVAawD
|
||||
ZgHlA6kB/AOWAfsDZQHiA1MBpwMzAVEDBgEHGAADBgEHAzYBWANVAawDZgHlAX4BugF+AfwBcwGqAXMB
|
||||
+wNlAeIDUwGnAzMBUQMGAQcYAAMGAQcDNgFYA1UBrANmAeUBfgK6AfwBcwKqAfsDZQHiA1MBpwMzAVED
|
||||
BgEHGAADBgEHAzYBWANVAawDZgHlAn4BugH8AnMBqgH7A2UB4gNTAacDMwFRAwYBBwwAAUIBTQE+BwAB
|
||||
PgMAASgDAAFAAwABIAMAAQEBAAEBBgABARYAA/+BAAHgAQcB4AEHAeABBwHgAQcBwAEDAcABAwHAAQMB
|
||||
wAEDAYABAQGAAQEBgAEBAYABAVAAAYABAQGAAQEBgAEBAYABAQHAAQMBwAEDAcABAwHAAQMB4AEHAeAB
|
||||
BwHgAQcB4AEHCw==
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="ilGameIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>241, 15</value>
|
||||
</metadata>
|
||||
<data name="ilGameIcons.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
|
||||
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
|
||||
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAiicAAAJNU0Z0AUkBTAIBAQMB
|
||||
AAEYAQABGAEAASABAAEgAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABgAMAASADAAEBAQABIAYAAUB6
|
||||
AAIxASwB5wEIAQoBAAH/AyoBQAwAAyoBQAM2AVcCQAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwC
|
||||
QAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwCQAE/AWwC
|
||||
QAE/AWwCOwE6AWIDMwFRAxgBIVQAA1UBogNhAcAgAANXAaYDXwG88AADIQEwAkYBRQGAFAABFQEfAQQB
|
||||
/wENARUBAAH/AQgBCgEAAf8BCAEKAQAB/wwAAUYBRQFDAXoBYQFWAU0BpwGMAWUBRAHPAYwBZQFEAc8B
|
||||
jAFlAUQBzwGMAWUBRAHPAYwBZQFEAc8BjAFlAUQBzwGMAWUBRAHPAYwBZQFEAc8BjAFlAUQBzwGMAWUB
|
||||
RAHPAYwBZQFEAc8BjAFlAUQBzwGMAWUBRAHPAYwBZQFEAc8BjAFlAUQBzwGMAWcBRQHOAXIBXAFKAbsB
|
||||
WQFSAUwBmwMqAUBUAANoAdADdQHuIAADagHUA3MB6eQAAkwBSgG/AQgBCgEAAf8BCAEKAQAB/wEIAQoB
|
||||
AAH/AQgBCgEAAf8BCAEKAQAB/wEIAQoBAAH/AQgBCgEAAf8CTAFKAb8CTAFKAb8BQwF0AQcB/wFHAXcB
|
||||
DAH/ASUBRwEAAf8BDgEZAQAB/wwAAU8BSwFJAYoBdAFfAUwBvQG+AW8BKAHqAb4BbwEoAeoBvgFvASgB
|
||||
6gG+AW8BKAHqAb4BbwEoAeoBvgFvASgB6gG+AW8BKAHqAb4BbwEoAeoBvgFvASgB6gG+AW8BKAHqAb4B
|
||||
bwEoAeoBvgFvASgB6gG+AW8BKAHqAb4BbwEoAeoBvgFvASgB6gG7AW8BKAHpAZIBZwFAAdMBZwFZAU0B
|
||||
rwEvAi4BSFQAA2gB0AN1Ae4gAANqAdQDcwHp4AABCAEKAQAB/wEQAR4BAAH/ASEBQQEAAf8BJwFLAQAB
|
||||
/wEmAUoBAAH/ASEBQQEAAf8BEAEeAQAB/wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB/wEpAU4BAAH/AVoB
|
||||
lgEQAf8BWgGcARAB/wFzAbYBJgH/ARgBLgEAAf8MAAFMAUoBRwGGAW8BXQFNAbcBrwFtATIB4wGvAW0B
|
||||
MgHjAa8BbQEyAeMBrwFtATIB4wG2AW8BLgHmAckBcQEiAe0B2gF1ARcB9AHwAXcBBgH8Af8BeAEAAv8B
|
||||
eAEAAf8B3gFxARQB9QG2AW8BLgHmAa8BbQEyAeMBrwFtATIB4wGvAW0BMgHjAa8BawEzAeIBiQFkAUQB
|
||||
zQFjAVcBTQGqAi4BLQFGVAADaAHQA3UB7iAAA2oB1ANzAencAAEIAQoBAAH/AT0BcQECAf8BTAGGAQcB
|
||||
/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BTAF/AQ8B/wE7AWcBCAH/ASEB
|
||||
NAEIAf8BUwGOAQsB/wFaAZwBEAH/AXIBswEnAf8BUwGBARsB/xAAAysBQQE3AjYBWQFBAUABPwFuAUEB
|
||||
QAE/AW4BQQFAAT8BbgFBAUABPwFuAUcBRQFEAXsBWwFTAUsBnwF9AWEBSQHFAcoBbwEhAe4B/wF4AQAC
|
||||
/wF4AQAB/wGDAWQBSAHJAUcBRgFEAXwBQQFAAT8BbgFBAUABPwFuAUEBQAE/AW4BQQFAAT8BbQE8AjsB
|
||||
YwMzAVIDGQEiVAADaAHQA3UB7iAAA2oB1ANzAenYAAEVASkBAAH/AUoBhAEEAf8BUgGMAQgB/wFSAYwB
|
||||
CAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB/wFSAYwBEAH/AVoBlAEQAf8B
|
||||
VgGQAQwB/wFaAZoBEAH/AVoBnAEQAf8BcgGpATAB/wEIAQoBAAH/AQgBCgEAAf8MAAMMARADEQEWAxUB
|
||||
HAMVARwDFQEcAxUBHAMhATABPwE+AT0BaQFeAVUBTAGlAbUBbgEwAeUB/wF4AQAC/wF4AQAB/wFjAVcB
|
||||
TQGqAyIBMQMVARwDFQEcAxUBHAMUARsDEwEZAxABFQMHAQlUAANoAdADdQHuIAADagHUA3MB6dQAARYB
|
||||
JwECAf8BSQGAAQcB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQsB
|
||||
/wFSAYwBEAH/AVIBjAEQAf8BWAGSARAB/wFaAZQBEAH/AVoBmwEQAf8BWgGcARAB/wFcAZ4BEgH/ATsB
|
||||
bQEDAf8BCAEKAQAB/wEIAQoBAAH/AQgBCgEAAf8IAAMFBAYECAEKAwgBCgMIAQoDCAEKAxcBHwI5ATgB
|
||||
XQFZAVIBTAGeAa8BbQEyAeMB/wF4AQAC/wF4AQAB/wFeAVUBTAGjAxgBIQMIAQoDCAEKAwgBCgMIAQoD
|
||||
BwEJAwYBBwMCAQNUAANoAdADdQHuIAADagHUA3MB6dAAAT0BQgE0Ad8BRwGAAQMB/wFSAYwBCAH/AVIB
|
||||
jAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBEAH/AVIBjAEQAf8BUgGMARAB
|
||||
/wFaAZQBEAH/AVoBlAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZgBEAH/ARYB
|
||||
KgEAAf8BCAEKAQAB/wEIAQoBAAH/HAADEgEXATYCNQFWAVgBUgFMAZoBqwFtATQB4QH/AXgBAAL/AXgB
|
||||
AAH/AVsBUwFLAZ8DEgEYcAADaAHQA3UB7iAAA2oB1ANzAenQAAEsAVABAAH/AUoBjAEAAf8BUgGMAQgB
|
||||
/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEOAf8BVQGSARAB/wFaAZwBEAH/AVoB
|
||||
nAEQAf8BWgGUARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGUARgB
|
||||
/wFYAZIBFgH/ARABHgEAAf8BCAEKAQAB/xwAAxIBFwE2AjUBVgFYAVIBTAGaAasBbQE0AeEB/wF4AQAC
|
||||
/wF4AQAB/wFbAVMBSwGfAxIBGHAAA2gB0AN1Ae4gAANqAdQDcwHp1AACSgFJAY8BMwFeAQAB/wFSAYwB
|
||||
CAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBEAH/AX8BwAEzAf8BXwGeARcB/wEgAT8BAAH/AQgBCgEAAf8B
|
||||
UgGMARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBlQEXAf8BWgGUARgB/wFaAZQB
|
||||
GAH/AVoBlAEYAf8BCAEKAQAB/wEIAQoBAAH/GAADEgEXATYCNQFWAVgBUgFMAZoBqwFtATQB4QH/AXgB
|
||||
AAL/AXgBAAH/AVsBUwFLAZ8DEgEYFAAEAQMDAQQDBgQHAQkDBwEJAwQBBQQCBAEUAAMRARYDIQEvAyEB
|
||||
LwMhAS8DIQEvAyEBLwMhAS8DIQEvAyEBLwMhAS8DagHZA3YB8QMhAS8DIQEvAyEBLwMhAS8DIQEvAyEB
|
||||
LwMhAS8DIQEvA20B3AN1Ae0DIQEvAyEBLwMhAS8DIQEvAyEBLwMhAS8DIQEvAyEBLwMhAS8DDQERuAAB
|
||||
QgF7AQAB/wFSAYwBCAH/AXsBxgEpAf8DMwFQBAADDAEQATkBawEAAf8BWgGcARAB/wFaAZwBEAH/AV0B
|
||||
lwETAf8BVgGUAQwB/wFaAZwBEAH/AVoBlAEYAf8BWgGUARgB/wFjAZwBGAH/AWMBpQEXAf8BKQFQAQAB
|
||||
/wEIAQoBAAH/GAADEgEXATYCNQFWAVgBUgFMAZoBqwFtATQB4QH/AXgBAAL/AXgBAAH/AVsBUwFLAZ8D
|
||||
EgEYFAAEAgMJAQwDDwEUAxMBGgMSARgDCgENAwQBBQQBFAADcwHoA38B/wN/Af8DfwH/A38B/wN/Af8D
|
||||
fwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8D
|
||||
fwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A2gBz7wAAQgBCgEAAf8MAAETASMB
|
||||
AAH/AVoBlAEQAf8BWgGcARAB/wGUAdYBSgH/AQ0BEQECAf8BMQFaAQAB/wFaAZQBEgH/AVoBlAEYAf8B
|
||||
WgGUARgB/wFjAZwBGAH/AWMBpQEXAf8BawGlASEB/wEQAR4BAAH/GAADEgEXATYCNQFWAVgBUgFMAZoB
|
||||
qwFtATQB4QH/AXgBAAL/AXgBAAH/AVsBUwFLAZ8DEgEYFAADBQEGAx0BKQMwAUoCOwE9AWUCOwE8AWQD
|
||||
KAE8AhUBFgEdAwYBCBQAAzwBZANNAY8DTQGPA00BjwNNAY8DTQGPA00BjwNNAY8DTQGPA00BjwNyAeoD
|
||||
fAH4A00BjwNNAY8DTQGPA00BjwNNAY8DTQGPA00BjwNNAY8DdQHsA3YB9QNNAY8DTQGPA00BjwNNAY8D
|
||||
TQGPA00BjwNNAY8DTQGPA00BjwM1AVaoAAI4ATQB3wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB/wEIAQoB
|
||||
AAH/AQgBCgEAAf8BCAEKAQAB/wMzAVADOgFgAUsBhQEHAf8BWgGUARAB/wFaAZwBEAH/ATkBawEAAf8D
|
||||
CQEMARABHgEAAf8BVAGOARIB/wFaAZQBGAH/AWMBnAEYAf8BYwGcARgB/wFjAaUBFwH/AXMBtAEpAf8B
|
||||
EAEeAQAB/xgAAxIBFwE2AjUBVgFYAVIBTAGaAasBbQE0AeEB/wF4AQAC/wF4AQAB/wFbAVMBSwGfAxIB
|
||||
GBQAAwkBDAMzAVACSgFSAZECSAGDAckCRgGFAcoCQwFGAXoDKQE9AwwBEDwAA2gB0AN1Ae4gAANqAdQD
|
||||
cwHpzAABCAEKAQAB/wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB/wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB
|
||||
/wEIAQoBAAH/AQgBCgEAAf8BMwFfAQIB/wFaAZQBEAH/AVoBnAEQAf8BrQHnAWMB/wEQAR4BAAH/AQgB
|
||||
CgEAAf8BFAEmAQAB/wFUAY4BEgH/AWIBmwEYAf8BYwGcARgB/wFjAaUBFwH/AWMBpQEXAf8BYwGcASEB
|
||||
/wEYAS4BAAH/GAADEgEXATYCNQFWAVgBUgFMAZoBqwFtATQB4QH/AXgBAAL/AXgBAAH/AVsBUwFLAZ8D
|
||||
EgEYFAADCQELAy4DRwFLAYQCSQF8AcMCRQGGAcsCRwFMAYUDLgFHAw8BEzwAA2gB0AN1Ae4gAANqAdQD
|
||||
cwHpyAABCAEKAQAB/wErAVIBAAH/AUEBcgEFAf8BSgGEAQYB/wFKAYQBBgH/AUoBhAEGAf8BQgFzAQYB
|
||||
/wEpAVABAAH/ARABHgEAAf8BHwE6AQAB/wFVAY8BCwH/AVoBlQEQAf8BWgGcARAB/wHWAf8BjAH/ARAB
|
||||
HgEAAf8BGAEuAQAB/wFCAXgBAwH/AVoBlAEYAf8BYgGbARgB/wFjAZwBGAH/AWMBpQEXAf8BYwGlARcB
|
||||
/wFzAbQBKQH/ARABHgEAAf8YAAMSARcBNgI1AVYBWAFSAUwBmgGrAW0BNAHhAf8BeAEAAv8BeAEAAf8B
|
||||
WwFTAUsBnwMSARgUAAMGAQgDJAE0AjwBPQFmAk0BYQGnAksBcAG4AkYBTAGDAzEBTQMPARQ8AANoAdAD
|
||||
dQHuIAADagHUA3MB6cQAASgBTQEAAf8BTgGIAQcB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwB
|
||||
CAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBEAH/AVIBjAEQAf8BUgGMARAB/wFaAZQBEAH/AVoBnAEQAf8B
|
||||
YwGlARcB/wFCAXsBAAH/AUoBhAEGAf8BUgGMAQgB/wFaAZgBFAH/AVoBlAEYAf8BYwGcARgB/wFjAaUB
|
||||
FwH/AWMBpQEXAf8BYwGlARcB/wGUAckBTQH/BAADEAEVAxoBJAMhAS8DEQEWBAIEAQMSARcBNgI1AVYB
|
||||
WAFSAUwBmgGrAW0BNAHhAf8BeAEAAv8BeAEAAf8BWwFTAUsBnwMSARgUAAMDAQQDEwEZAyUBNgI7ATwB
|
||||
ZAJBAUMBcgMzAVEDIQEvAwkBDDwAA2gB0AN1Ae4gAANqAdQDcwHpwAABKQFOAQIB/wFSAYwBCAH/AVIB
|
||||
jAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB
|
||||
/wFSAYwBEAH/AVoBlAEQAf8BWgGVARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwBEAH/AVoB
|
||||
lAEYAf8BWgGUARgB/wFjAZwBGAH/AWMBnAEYAf8BYwGlARcB/wFjAaUBFwH/AWMBpQEXAf8BZQGgASEB
|
||||
/wQAAx4BKwIxATABTAE8AjsBYwMiATEDBwEJAwQBBQMSARgDNgFXAVgBUgFMAZoBqwFtATQB4QH/AXgB
|
||||
AAL/AXgBAAH/AVsBUwFLAZ8DEgEYHAADBwEJAxwBJwMjATICGQEaASMDDwEUAwQBBTwAA2gB0AN1Ae4g
|
||||
AANqAdQDcwHpvAACRgFFAYABTgGIAQcB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIB
|
||||
jAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB/wFSAYwBEAH/AVoBlAEQAf8BWgGXARAB
|
||||
/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBlAEYAf8BWgGUARgB/wFjAZwBGAH/AWMB
|
||||
oQEYAf8BYwGlARcB/wFjAaUBFwH/AXgBugEsAf8BCAEKAQAB/wQAAyQBNAFHAUYBRAF8AW8BXQFNAbcB
|
||||
VQFQAUoBlAFBAUABPwFtAygBOwMfASwDOQFeAVgBUgFMAZoBqwFtATQB4QH/AXgBAAL/AXgBAAH/AVsB
|
||||
UwFLAZ8DEgEYHAADEgEXAjwBPQFmAkkBTgGJAkABQQFvAy4BRwMOARI8AANoAdADdQHuIAADagHUA3MB
|
||||
6bwAATUBXgEHAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8B
|
||||
UgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB/wFaAZQBEAH/AVoBlAEQAf8BWgGbARAB/wFaAZwB
|
||||
EAH/AVoBnAEQAf8BWgGcARAB/wFaAZYBFgH/AVoBlAEYAf8BXQGXARgB/wFjAZwBGAH/AWMBpQEXAf8B
|
||||
YwGlARcB/wFwAbMBIAH/ASsBUAEEAf8IAAMnAToBXQFUAUwBogHtAXIBCQH7AboBbgEsAecBfgFiAUgB
|
||||
xAFEAUMBQgF1AzEBTQFBAUABPwFuAVsBUwFLAZ8BrwFtATIB4wH/AXgBAAL/AXgBAAH/AVsBUwFLAZ8D
|
||||
EgEYHAADGQEiAksBVQGVAkQBiQHNAkwBagGyAkMBRgF6Ax0BKQMGAQgEAgQBMAADaAHQA3UB7iAAA2oB
|
||||
1ANzAem8AAFKAYQBBgH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFnAakB
|
||||
FwH/AVIBjAEIAf8BSgGEAQYB/wFKAYQBBgH/AVIBjAEQAf8BWgGUARAB/wFaAZcBEAH/AVoBnAEQAf8B
|
||||
WgGcARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGUARgB/wFaAZQBGAH/AV8BmAEYAf8BYwGeARgB/wFjAaUB
|
||||
FwH/AWsBqQEdAf8BKQFQAQAB/wwAAyIBMQFWAVABSwGYAdcBcgEaAfMBzQFwAR0B8AG2AW8BLgHmAXoB
|
||||
XwFJAcIBYwFXAU0BqgFhAVYBTQGnAXIBXgFKAbwBwgFyASkB6wH/AXgBAAL/AXgBAAH/AVsBUwFLAZ8D
|
||||
EgEYHAADFAEbAkMBRQF3AkwBbQG2AkQBiQHNAk0BawGzAj8BQAFsAyYBOAMMAQ8DAgEDCAADAgEDAw0B
|
||||
EQMNAREDDQERAw0BEQMNAREDDQERAw0BEQMNAREDDQERA2cB0wN1Ae8DDQERAw0BEQMNAREDDQERAw0B
|
||||
EQMNAREDDQERAw0BEQNqAdcDcwHqAw0BEQMNAREDDQERAw0BEQMNAREDDQERAw0BEQMNAREDDQERAwQB
|
||||
BZQAAUoBhAEGAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFpAaQBHgH/ASwBUAEDAf8B
|
||||
CAEKAQAB/wE3AWEBBwH/AVIBjAEOAf8BUgGMARAB/wF/AcEBMgH/AU8BXgFBAdMBWAFhAUoBvwEvAVkB
|
||||
AAH/AUQBegEFAf8BUAGKAQgB/wFaAZwBDgH/AVoBnAEQAf8BWgGcARAB/wFPAYYBEAH/AUQBdAEMAf8B
|
||||
TwFSAUoBvxAAAhoBGQEjAUcBRQFEAXsBhQFkAUYBygGeAWkBOwHaAbsBcAEqAegBygFxASAB7wHFAXEB
|
||||
JwHsAZgBaQE9AdYBmAFoAT0B2AHaAXUBFwH0Af8BeAEAAv8BeAEAAf8BWwFTAUsBnwMSARgcAAMPARMD
|
||||
NAFTAkoBUwGSAkQBjAHPAkEBkwHUAk0BYgGoAkEBQwFyAyYBOAMUARsDBgEIAwIBAwNhAcIDfwH/A38B
|
||||
/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B
|
||||
/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DfwH/A38B/wN/Af8DbgHclAAB
|
||||
SgGMAQAB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AWcBnQEnAf8BCAEKAQAB/wEKAQ8B
|
||||
AAH/AUIBdwEDAf8BUgGMARAB/wFaAZwBEAH/ASUBQQEFAf8EAAM6AWABCAEKAQAB/wEIAQoBAAH/BAAC
|
||||
RgFFAYACRgFFAYACRgFFAYAcAAMKAQ0DIgExAzQBVAFGAUQBQwF4AVsBUwFLAZ8BjAFlAUQBzwHJAXIB
|
||||
IgHtAcUBcQEnAewBzQFwAR0B8AHtAXIBCQH7Af8BeAEAAv8BeAEAAf8BWwFTAUsBnwMSARgcAAMGAQgD
|
||||
GAEhAzEBTQJKAVIBkQJMAXQBvQJCAY8B0QJJAXwBwwJMAV0BogI9AT4BZwIZARoBIwMMAQ8DQAFvA1oB
|
||||
rQNaAa0DWgGtA1oBrQNaAa0DWgGtA1oBrQNaAa0DWgGtA3YB8AN9AfoDWgGtA1oBrQNaAa0DWgGtA1oB
|
||||
rQNaAa0DWgGtA1oBrQN2AfEDfAH4A1oBrQNaAa0DWgGtA1oBrQNaAa0DWgGtA1oBrQNaAa0DWgGtA0cB
|
||||
gZQAATsBbQECAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFTAY4BEAH/AQ8BGwEAAf8B
|
||||
IwFDAQAB/wFSAYwBEAH/AVIBjAEQAf8BewG9ATAB/wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB/wEIAQoB
|
||||
AAH/AQgBCgEAAf8BCAEKAQAB/wEIAQoBAAH/KAADAwEEAwkBCwMiATEDOAFbAVYBUAFLAZcBhAFkAUcB
|
||||
yAG1AW4BMAHlAeQBcgEUAfcB9gF1AQYB/QH/AXgBAAL/AXgBAAH/AVsBUwFLAZ8DEgEYHAAEAQMCAQMD
|
||||
FQEcAjUBNgFWAkkBUQGPAkcBhAHIAjQBpgHfAjIBrwHjAkwBXgGlAzQBUwMcAScoAANoAdADdQHuIAAD
|
||||
agHUA3MB6bwAAQgBCgEAAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AU4B
|
||||
ggEPAf8BSgGEAQYB/wFSAYwBEAH/AWMBpQEXAf8BCAEKAQAB/wEIAQoBAAH/ARMBIwEAAf8BQgFzAQYB
|
||||
/wEgAT8BAAH/AQgBCgEAAf8BCAEKAQAB/wEIAQoBAAH/AQgBCgEAAf8BCAEKAQAB/yAABAEDAwEEAwwB
|
||||
EAMYASADKQE9AT8CPgFqAW0BWwFLArUBbgEwAeUB5AFyARQB9wH/AXgBAAL/AXgBAAH/AVsBUwFLAZ8D
|
||||
EgEYIAAEAQMHAQkDFAEbAyoBQAJCAUQBdgJNAWcBrwIoAbsB6QJCAY4B0AJLAVsBnwMzAVEoAANoAdAD
|
||||
dQHuIAADagHUA3MB6cAAAUIBcwEGAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwB
|
||||
CAH/AVIBjAEQAf8BUgGMARAB/wFKAYQBBgH/ARABHgEAAf8BMQFaAQAB/wFNAYQBDQH/AVoBnAEQAf8B
|
||||
WgGcARAB/wFSAYwBCAH/ARABHgEAAf8BCAEKAQAB/wEIAQoBAAH/AkYBRQGALAADAgEDAwsBDgMgAS4B
|
||||
RAFDAUIBdgFqAVoBTgGxAaoBbQE1AeAB3wF1ARQB9gHnAXIBDwH5AVkBUwFMAZwDEgEXDAAEAQMMARAD
|
||||
FwEfAx0BKAMdASgDDAEPCAADDwEUAiYBJwE5AkYBTAGDAjQBqwHhAiwBugHnAkABkAHSAj8BQQFuKAAD
|
||||
aAHQA3UB7iAAA2oB1ANzAenEAAFJAYkBAAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEIAf8B
|
||||
UgGMARAB/wFSAYwBEAH/AVIBjAEQAf8BUgGMARAB/wFaAZQBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwB
|
||||
EAH/AVoBnAEQAf8BWgGUARgB/wFCAXMBBgH/AQoBDgEAAf8wAAQBAwMBBAMMAQ8DHgEqATsCOgFhAXEB
|
||||
XQFLAbkBsAFrAS8B5AHKAW8BIQHuAVYBUAFLAZcDEgEXDAADAgEDAyEBLwI2ATcBWQJCAUQBdQJBAUMB
|
||||
cwMeASsIAAMEAQUDDAEPAjgBOQFcAkUBjAHOAicBxQHsAiABygHvAkUBSQF/KAADaAHQA3UB7iAAA2oB
|
||||
1ANzAenIAAE6AWsBAAH/AVIBjAEIAf8BUgGMAQgB/wFSAYwBCAH/AVIBjAEQAf8BUgGMARAB/wFaAZQB
|
||||
EAH/AVoBlAEQAf8BWgGcARAB/wFaAZwBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZQBGAH/AVoBlAEYAf8B
|
||||
YwGlARcB/wEZASwBAwH/OAADAgEDAwgBCgMgAS0BQgFBAUABcQFSAU0BSgGRAVgBUgFMAZoCOwE6AWID
|
||||
DAEPDAADAwEEAysBQQJDAUYBegJNAWEBpwJNAWUBrQM3AVoDGAEgAwkBCwMGAQcDDQERAjkBOgFfAkIB
|
||||
jwHRAiABygHvAhoB1wHzAkUBSQGBKAADaAHQA3UB7iAAA2oB1ANzAenMAAEsAVUBAAH/AVIBjAEIAf8B
|
||||
UgGMAQgB/wFSAYwBEAH/AVIBjAEQAf8BWgGUARAB/wFaAZQBEAH/AVoBnAEQAf8BWgGcARAB/wFaAZwB
|
||||
EAH/AVoBnAEQAf8BWgGUARgB/wFaAZQBGAH/ASEBQQEAAf9AAAQCAwcBCQMQBBUBHAIWARUBHQMPARMD
|
||||
AgEDDAADAwEEAzABSwJJAVEBjwJGAYUBygI4AaUB3gJKAVUBlAM0AVMDFQEcAw0BEQMeASsCQwFFAXcC
|
||||
NAGmAd8CHQHUAfECKAG7AekCRAFHAXsoAANoAdADdQHuIAADagHUA3MB6cgAARIBIgEAAf8BTAGGAQYB
|
||||
/wFSAYwBCAH/AVoBnAEQAf8BUAGKAQgB/wFSAYwBEAH/AVoBlAEQAf8BWgGcARAB/wFaAZwBEAH/AVoB
|
||||
nAEQAf8BWgGcARAB/wFaAZwBEQH/AWkBqwEfAf8BCAEKAQAB/2wAAwIBAwMhAS8COgE7AWECTQFlAa0C
|
||||
OwGeAdoCSgF3Ab8CSwFbAZ8CQwFGAXoCQQFDAXICRwFMAYUCTAFqAbICIgHJAe0COgGgAdsCTgFqAbED
|
||||
OAFbKAADaAHQA3UB7iAAA2oB1ANzAenIAAEQAR4BAAH/AUgBfQEHAf8BWQGTARMB/wFVAYgBGAH/CAAB
|
||||
IQFBAQAB/wFCAXsBAAH/AVIBjAEIAf8BVQGRAQgB/wE5AWYBBAH/ASoBMwEgAe94AAMGAQgDFwEfAkQB
|
||||
RwF7AkcBfwHGAi8BsAHkAhcB2gH0AiEBygHuAiEBygHuAh0B1AHxAhQB3wH2AgYB8AH8AksBdgG+Aj4B
|
||||
PwFrAyQBNCgAA2gB0AN1Ae4gAANqAdQDcwHp0AABHgE6AQAB/5wABAIDCQEMAyoDPwFBAW4CSgFVAZYC
|
||||
TQFrAbMCSQF5AcECRgGAAccCRgGAAccCSwFxAbkCTQFeAaQCQAFCAXEDJQE2AxMBGSgAA2gB0AN1Ae4g
|
||||
AANqAdQDcwHp/wB5AAQBAwsBDgMmATgDOQFeAkUBSAF9AkkBTwGLAkkBTgGJAj4BPwFrAyoBPwMXAR8D
|
||||
AgEDLAADVQGiA2EBvyAAA1cBpgNfAbuoAAFCAU0BPgcAAT4DAAEoAwABgAMAASADAAEBAQABAQYAAQIW
|
||||
AAP/AQAD/wHHAgABBwL/Ac8B8wH/BAAC/wHPAYcCAAEHAv8BzwHzAf8EAAH/Af4BAAEHAgABBwL/Ac8B
|
||||
8wH/BAAB/wH8AQABBwIAAQcC/wHPAfMB/wQAAf8B+AEAAQ8CAAEHAv8BzwHzAf8EAAH/AfABAAEHAgAB
|
||||
BwL/Ac8B8wH/BAAB/wHgAQABAwIAAQcC/wHPAfMB/wQAAf8BwAEAAQEB/AEDA/8BzwHzAf8EAAH/AcAB
|
||||
AAEBAfwBAwP/Ac8B8wH/BAAB/wHgAgAB/AEDAeABHwgAAf8B/AEgAQAB/AEDAeABHwgAAf8B/gHgAQAB
|
||||
/AEDAeABHwgAAf8BwAIAAfwBAwHgAR8B/wHPAfMB/wQAAf8BgAIAAfwBAwHgAR8B/wHPAfMB/wQAAf8D
|
||||
AAH8AQMB4AEfAf8BzwHzAf8EAAH+AgABAQEAAQMB4AEfAf8BzwHzAf8EAAH8AgABAQEAAQMB+AEfAf8B
|
||||
zwHzAf8EAAH4AgABAQEAAQMB+AEfAf8BzwHzAf8EAAH4AgABAwEAAQMB+AEDAf8BzwHzAf8EAAH4AgAB
|
||||
BwEAAQMB+AEDCAAB+AIAAQ8BAAEDAfgJAAH4AQABRAF/AQABAwH4CQAB+AEAAQEB/wGAAQMB+AEAAf8B
|
||||
zwHzAf8EAAH4AgABfwGAAQMB/AEAAf8BzwHzAf8EAAH8AgABfwHwAQMBgQGAAf8BzwHzAf8EAAH+AgAB
|
||||
/wHwAQMBgQGAAf8BzwHzAf8EAAH/AgAB/wH8AQMBgAEAAf8BzwHzAf8EAAH/AYABAQH/Af4BAwGAAQAB
|
||||
/wHPAfMB/wQAAf8BAAEDA/8BgAEAAf8BzwHzAf8EAAH/AQwBDwP/AcABAAH/Ac8B8wH/BAAB/wHfBP8B
|
||||
wAEAAf8BzwHzAf8EAAb/AfABAQH/Ac8B8wH/BAAL
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="ilTabIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<data name="ilTabIcons.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
|
||||
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
|
||||
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAHBkAAAJNU0Z0AUkBTAIBAQUB
|
||||
AAGwAQABsAEAARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASAa
|
||||
AAM3AVoDWAG4A2MB3wJjAV0B3wFiAl0B3wNdAd8DXQHfAWECXQHfA2MB3wNjAd8DVQGsAzABS8wAAzsB
|
||||
YgNdAcUBcwJoAfQBnwFlATEB/wGXAVMBFwH/AZYBSwEJAf8BkwFGAQEB/wGMAUMBAwH/AX0BQAELAf8B
|
||||
awFAARoB/wFuAVABNgH/A2gB8ANaAbcDNAFUxAADNQFVA10BxwFxAW4BWgH1AbgBZQEbAf8BuQFYAQIB
|
||||
/wHJAV8BAAH/AdgBZQEAAf8B3AFnAQAB/wHWAWQBAAH/AcMBXAEAAf8BogFMAQAB/wF8ATsBAwH/AW4B
|
||||
RgEjAf8DaAHwA1oBtwMwAUrAAANcAcQBkAF8AVwB+AHUAXEBGAH/AdcBZQEAAf8B5QFsAQAB/wHyAXIB
|
||||
AAH/AfoBdQEAAf8B/AF2AQAB/wH6AXYBAAH/AfMBcgEAAf8B4gFrAQAB/wG9AVkBAAH/AYcBQAEAAf8B
|
||||
cQFIASMB/wNoAfADVgGrwAAB/gHdAcEB/wHtAYABIAH/Ae0BcQECAf8B8wFzAQAB/wH6AXYBAAH/Af4B
|
||||
eAEAAv8BewEIAv8BiAEnAv8BogFTAf8B/gGBARcB/wH8AXgBBAH/AewBbwEAAf8BwQFbAQAB/wGGAUEB
|
||||
AwH/AXgBVgE2Af8DYwHfwAAB/wGyAW8B/wH9AYABEQH/AfwBdwEBAf8B/QF3AQAC/wF4AQAC/wF/AQ8C
|
||||
/wGSATsC/wGzAYMC/wHqAeAC/wGQAT0C/wF7AQoB/wH8AXcBAAH/AeUBbAEAAf8BsQFUAQAB/wGEAUsB
|
||||
GgH/A2MB38AAAf8BmgFCAv8BgwEVAf8B/gF6AQQC/wF4AQAC/wF4AQAC/wGVAT8C/wHKAa4C/wHaAcYC
|
||||
/wHtAeUC/wGWAUkC/wF8AQ0B/wH+AXgBAAH/AfQBcwEAAf8B0AFiAQAB/wGaAU4BCgH/AWMCXQHfwAAB
|
||||
/wGVATcC/wGJAR8C/wF9AQgC/wF4AQAC/wF4AQAC/wGoAVwC/wHgAc0C/wGhAWYC/wHYAcUC/wG5AZQC
|
||||
/wGHASMC/wF4AQAB/wH7AXYBAAH/AeIBagEAAf8BrwFUAQMB/wFjAl0B38AAAf8BoAFJAv8BkgExAv8B
|
||||
gQERAv8BeQEDAv8BeAEAAv8BqAFcAv8B4AHNAv8BoQFmAv8B2AHFAv8BwAGfAv8BiQEnAv8BeAEAAf8B
|
||||
/gF4AQAB/wHsAW8BAAH/Ab8BWgECAf8BYwJdAd/AAAH/AbMBbwL/AZ4BSAL/AYgBHgL/AXwBBwL/AXgB
|
||||
AAL/AZgBQwL/Ac4BtAL/AdcBwAL/AeoB4AL/AZ0BVwL/AX4BEQL/AXgBAAL/AXgBAAH/AfABcQEAAf8B
|
||||
ywFkAQkB/wFjAWEBXQHfwAAB/wHMAZ8C/wGsAWMC/wGTATMC/wGBAREC/wF5AQIC/wGCARYC/wGaAUsC
|
||||
/wGuAXgC/wGlAVcC/wGBARcC/wF5AQQC/wF4AQAC/wF4AQAB/wHwAXEBAAH/AdUBcQEXAf8CYwFdAd/A
|
||||
AAH/AekB1QL/AbwBgQL/AaQBVAL/AY4BKgL/AX8BDQL/AXkBAgL/AXsBCQL/AYIBHQL/AXgBAAL/AXgB
|
||||
AAL/AXgBAQL/AXoBBAL/AXoBAwH/AfMBdAEDAf8B4gGEATIB/wNjAd/AAANeAdIBlQGMAYMB+QH/AbsB
|
||||
fQL/AaMBUgL/AZABLAL/AYIBEwL/AX0BCAL/AXoBBAL/AXkBAgL/AXoBBAL/AX0BCQL/AYABDwL/AX8B
|
||||
DQH/AfgBhgEgAf8BeAFtAWgB9ANYAbjAAAM8AWYDYwHVAZUBhwF8AfgB/wG+AYUC/wGqAV8C/wGZAT4C
|
||||
/wGNAScC/wGGARoC/wGDARUC/wGFARkC/wGKASIC/wGNASgC/wGTATMB/wF8AW4BaAH1A10BxQM2AVnE
|
||||
AANCAXIDYwHVAZUBjgGIAfkB/wHJAZkC/wG8AX8C/wGuAWYC/wGkAVMC/wGfAUoC/wGfAUsC/wGjAVEC
|
||||
/wGnAVgB/wGVAX4BfAH4A10BxwM7AWLMAAM8AWUDXgHSAf8B7wHgAv8B3AG8Av8BzQGfAv8BwQGKAv8B
|
||||
uwF/Av8BvwGGAv8BzQGhAv8B6QHWAf8DXAHEAzUBVcgAA2cB7wJnAVkB7wFnAV0BWQHvAWcBWwFZAe8B
|
||||
ZwFbAVkB7wFnAlkB7wFnAWQBWQHvA2cB7wNnAe8DZwHvA2cB7wNnAe8DZwHvA2cB7wNnAe8DZwHvOAAD
|
||||
MwFRA3kB9QMHAQkDKgE/A0UBfANZAbsDYwHfA2gB9AOAAf4DgQH/A4EB/wOBAf8DgAH+A2gB9ANjAd8D
|
||||
WgG6A0QBegMnAToIAAM3AVoDWAG4A2MB3wJjAV0B3wFiAl0B3wNdAd8DXQHfAWECXQHfA2MB3wNjAd8D
|
||||
VQGsAzABSwgAA/gB/wG5AZUBPAH/AYMBfQFuAf8BhAF9AWwB/wGqAYQBJwH/AawBewEAAf8BzAG8AZQB
|
||||
/wN+Af8DfgH/A34B/wN+Af8DfgH/A34B/wN+Af8DfgH/A44B/zgAAxIBGAM/AW0DQwF1A10BzAN8AfgD
|
||||
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wN8AfgDVAGoBAADOwFiA10B
|
||||
xQFzAmgB9AGfAWUBMQH/AZcBUwEXAf8BlgFLAQkB/wGTAUYBAQH/AYwBQwEDAf8BfQFAAQsB/wFrAUAB
|
||||
GgH/AW4BUAE2Af8DaAHwA1oBtwM0AVQEAAT/AZcBiwFtAf8CgQGAAf8BggGBAYAB/wGYAYgBYAH/AcoB
|
||||
kAEAAf8B3QHMAZ8B/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A5MB/zQAA18B0wM9AWcE
|
||||
AANqAe0DfQH6A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB
|
||||
/wNVAa8DNQFVA10BxwFxAW4BWgH1AbgBZQEbAf8BuQFYAQIB/wHJAV8BAAH/AdgBZQEAAf8B3AFnAQAB
|
||||
/wHWAWQBAAH/AcMBXAEAAf8BogFMAQAB/wF8ATsBAwH/AW4BRgEjAf8DaAHwA1oBtwMwAUoE/wGGAYQB
|
||||
fQH/A4EB/wOBAf8BhwGDAXoB/wHPAZQBAAH/Ad4BzAGfAf8D4AH/A+AB/wPgAf8D4AH/A+AB/wPgAf8D
|
||||
4AH/A+AB/wO8Af80AANaAcIDNAFTBAADYwHfA24B9QOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
|
||||
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvA1wBxAGQAXwBXAH4AdQBcQEYAf8B1wFlAQAB/wHlAWwB
|
||||
AAH/AfIBcgEAAf8B+gF1AQAB/wH8AXYBAAH/AfoBdgEAAf8B8wFyAQAB/wHiAWsBAAH/Ab0BWQEAAf8B
|
||||
hwFAAQAB/wFxAUgBIwH/A2gB8ANWAasE/wGLAYYBegH/A4EB/wOBAf8BjgGGAXEB/wHPAZQBAAH/Ad4B
|
||||
zAGfIf8DygH/EAADDQERAz8BbANTAacBXAJZAb4BWAJWAbMBSAJHAYMDIQEwBAADcwHzAzoBYAgAAzYB
|
||||
WANbAcADbgH1A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DaAH0A1IB
|
||||
pAH+Ad0BwQH/Ae0BgAEgAf8B7QFxAQIB/wHzAXMBAAH/AfoBdgEAAf8B/gF4AQAC/wF7AQgC/wGIAScC
|
||||
/wGiAVMB/wH+AYEBFwH/AfwBeAEEAf8B7AFvAQAB/wHBAVsBAAH/AYYBQQEDAf8BeAFWATYB/wNjAd8E
|
||||
/wGsAZYBYAH/AYMBggF/Af8BhQGCAX0B/wGzAZMBRAH/Ac8BlAEAAf8B3gHMAZ8B/wOwAf8DsAH/A7AB
|
||||
/wOwAf8DsAH/A7AB/wOwAf8DsAH/A6gB/wgAAxoBJANSAaABZwFjAUgB9gGiAXMBAAH/Aa4BfAEAAf8B
|
||||
sAF9AQAB/wGoAXgBAAH/AZUBagEAAf8BgAFqARYB/gFcAlkBxgNXAbUDFgEeCAADAgEDAxoBIwM4AVwD
|
||||
VAGoA2IB1wNwAfEDgAH+A4EB/wOBAf8DgQH/A4EB/QNoAfADYQHUA1MBpQM2AVkDGAEgAf8BsgFvAf8B
|
||||
/QGAAREB/wH8AXcBAQH/Af0BdwEAAv8BeAEAAv8BfwEPAv8BkgE7Av8BswGDAv8B6gHgAv8BkAE9Av8B
|
||||
ewEKAf8B/AF3AQAB/wHlAWwBAAH/AbEBVAEAAf8BhAFLARoB/wNjAd8E/wHZAaoBNwH/Ab4BmAE4Af8B
|
||||
wAGYATYB/wHcAaIBFAH/Ac8BlAEAAf8B3gHMAZ8B/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
|
||||
gQH/A5MB/wQAAyABLQJjAVoB6QG/AYgBAAH/Ac0BlQEKAf8BsAGIAScB/wFzAWQBPwH/AU0BSwFHAf8B
|
||||
TgFLAUIB/wFmAVcBMQH/AZoBdAEXAf8BpAF2AQMB/wFwAU8BAAH/A0MBdgQBRAAB/wGaAUIC/wGDARUB
|
||||
/wH+AXoBBAL/AXgBAAL/AXgBAAL/AZUBPwL/AcoBrgL/AdoBxgL/Ae0B5QL/AZYBSQL/AXwBDQH/Af4B
|
||||
eAEAAf8B9AFzAQAB/wHQAWIBAAH/AZoBTgEKAf8BYwJdAd8E/wHhAa4BMQH/Ab0BlwE7Af8BwAGYATUB
|
||||
/wHjAaUBCgH/Ac8BlAEAAf8B3gHMAZ8B/wPAAf8DwAH/A8AB/wPAAf8DwAH/A8AB/wPAAf8DwAH/A68B
|
||||
/wQAAmMBWgHpAdkBmgEAAf8B2gGjARwB/wKOAYwB/wOKAf8DlwH/A5sB/wORAf8DdAH/A0gB/wFDAUIB
|
||||
PwH/AbUBgwEHAf8BegFXAQAB/wM2AVgMAAMCAQMDCAEKAyEBLwMxAU4DPQFoA0MBdgNEAXoDQwF1Az0B
|
||||
ZwMxAU0DIAEuAwcBCQQCBAAB/wGVATcC/wGJAR8C/wF9AQgC/wF4AQAC/wF4AQAC/wGoAVwC/wHgAc0C
|
||||
/wGhAWYC/wHYAcUC/wG5AZQC/wGHASMC/wF4AQAB/wH7AXYBAAH/AeIBagEAAf8BrwFUAQMB/wFjAl0B
|
||||
3wT/AbsBnQFTAf8BiAGEAXkB/wGMAYUBdAH/AcQBmQEwAf8BzwGUAQAB/wHeAcwBnyH/A8oB/wNDAXYB
|
||||
6QGnAQIB/wHpAasBEgH/AdABygG7Af8DrAH/A10B/wNMAf8DSwH/A0QB/wMPAf8DswH/A2YB/wFUAUwB
|
||||
OgH/Aa4BfQEEAf8DXQHMCAADEwEaAzkBXQNZAbwDZAHbA2oB7QNjAfYDXwH7A4EB/QNfAfsDYwH2A2UB
|
||||
7ANjAdoDWgG6AzgBXAMTARoB/wGgAUkC/wGSATEC/wGBAREC/wF5AQMC/wF4AQAC/wGoAVwC/wHgAc0C
|
||||
/wGhAWYC/wHYAcUC/wHAAZ8C/wGJAScC/wF4AQAB/wH+AXgBAAH/AewBbwEAAf8BvwFaAQIB/wFjAl0B
|
||||
3wT/AZQBigFzAf8DgQH/A4EB/wGaAYoBYwH/Ac8BlAEAAf8B3gHMAZ8B/wPQAf8D0AH/A9AB/wPQAf8D
|
||||
0AH/A9AB/wPQAf8D0AH/A7UB/wJqAWEB5gHtAa0BEAH/AfQB0AF2Af8D+gH/A/oB/wN9Af8DfwH/A4AB
|
||||
/wOAAf8DfgH/A4QB/wO7Af8DagH/AagBgAEcAf8BaQFjAUgB9gQAAxoBJANWAa4DaAH0A4EB/wOBAf8D
|
||||
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DawHyA1IBoQH/AbMBbwL/AZ4BSAL/AYgB
|
||||
HgL/AXwBBwL/AXgBAAL/AZgBQwL/Ac4BtAL/AdcBwAL/AeoB4AL/AZ0BVwL/AX4BEQL/AXgBAAL/AXgB
|
||||
AAH/AfABcQEAAf8BywFkAQkB/wFjAWEBXQHfBP8BhgGDAX4B/wOBAf8DgQH/AYYBgwF7Af8BzwGUAQAB
|
||||
/wHeAcwBnwH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DkwH/AWoBZwFiAe4B7wG0ASEB
|
||||
/wH3AdwBlwn/A5EB/wOIAf8DhwH/A4cB/wOBAf8DVwH/A+YB/wOjAf8BtgGRATYB/wGFAWoBQAH5BAAD
|
||||
VwGyA2UB5wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
|
||||
VQGvAf8BzAGfAv8BrAFjAv8BkwEzAv8BgQERAv8BeQECAv8BggEWAv8BmgFLAv8BrgF4Av8BpQFXAv8B
|
||||
gQEXAv8BeQEEAv8BeAEAAv8BeAEAAf8B8AFxAQAB/wHVAXEBFwH/AmMBXQHfBP8BiwGGAXkB/wOBAf8D
|
||||
gQH/AY4BhgFxAf8BzwGUAQAB/wHeAcwBnwH/A6EB/wOhAf8DoQH/A6EB/wOhAf8DoQH/A6EB/wOhAf8D
|
||||
oQH/A0sBjQHwAb4BPwH/AfQBzQFsIf8D+wH/A9AB/wHXAacBMQH/AmEBXQHRBAADbwHzA18B+wOBAf8D
|
||||
gQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DVQGvAf8B6QHVAv8B
|
||||
vAGBAv8BpAFUAv8BjgEqAv8BfwENAv8BeQECAv8BewEJAv8BggEdAv8BeAEAAv8BeAEAAv8BeAEBAv8B
|
||||
egEEAv8BegEDAf8B8wF0AQMB/wHiAYQBMgH/A2MB3wT/AacBlAFnAf8BgwGCAX8B/wGFAYMBfgH/AbAB
|
||||
lAFOAf8B0wGXAQIB/wHgAc4BnwH/A+cB/wPnAf8D5wH/A+cB/wPnAf8D5wH/A+cB/wPnAf8DwAH/AwcB
|
||||
CQFqAWgBYgHuAfEBvAE7Af8B+gHqAcIB/wPcAf8DdwH/A2gB/wNoAf8DaAH/AzIJ/wHyAd0BqQH/AeoB
|
||||
qQEIAf8DPgFqBAADZAHbA2gB9AOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
|
||||
gQH/A4EB/wOBAf8DVQGvA14B0gGVAYwBgwH5Af8BuwF9Av8BowFSAv8BkAEsAv8BggETAv8BfQEIAv8B
|
||||
egEEAv8BeQECAv8BegEEAv8BfQEJAv8BgAEPAv8BfwENAf8B+AGGASAB/wF4AW0BaAH0A1gBuAT/AdcB
|
||||
sQFSAf8BmgGPAXQB/wGgAZIBbQH/AeABrwE3Af8B5wGpARAB/wHrAdUBoAH/A4EB/wOBAf8DgQH/A4EB
|
||||
/wOBAf8DgQH/A4EB/wOBAf8DkwH/BAADMwFRAWoCaAHwAfMBxgFYAf8B+gHnAbgW/wH+AfsB/wH5AeIB
|
||||
qgH/Ae8BuAEtAf8DTgGWBAIEAAM8AWQDXwHJA30B+gOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wOBAf8D
|
||||
gQH/A4EB/wOBAf8DgQH/A30B+gNVAaoDPAFmA2MB1QGVAYcBfAH4Af8BvgGFAv8BqgFfAv8BmQE+Av8B
|
||||
jQEnAv8BhgEaAv8BgwEVAv8BhQEZAv8BigEiAv8BjQEoAv8BkwEzAf8BfAFuAWgB9QNdAcUDNgFZBP8B
|
||||
9AHNAWwB/wH0AcsBZgH/AfQBywFlAf8B9AHLAWUB/wHxAcEBSQH/AfkB4wGsAf8DiQH/A4kB/wOJAf8D
|
||||
iQH/A4kB/wOJAf8DiQH/A4kB/wOaAf8IAAMiATEDXwHJAaABigFnAfoB8wHKAWUB/wH5AeEBpgH/AfsB
|
||||
7QHMAf8B+wHsAcgB/wH4Ad0BmwH/AcYBmAFnAf4CZQFeAeIDPQFoBAEIAAMGAQgDMQFMA1ABmwNlAewD
|
||||
fQH6A4EB/wOBAf8DgQH/A4EB/wOBAf8DgQH/A4EB/wN9AfoDagHtA1ABmwMvAUkEAANCAXIDYwHVAZUB
|
||||
jgGIAfkB/wHJAZkC/wG8AX8C/wGuAWYC/wGkAVMC/wGfAUoC/wGfAUsC/wGjAVEC/wGnAVgB/wGVAX4B
|
||||
fAH4A10BxwM7AWIEAED/EAADDwETA0cBggNkAdsBtAGeAW8B/ANnAeoDVAGoAygBOxwAAwUBBgMSARcD
|
||||
OgFgA1EBnwNfAdMDZwHvA2MB9gNiAe4DXgHSA1EBngM5AV8DEQEWAwUBBgwAAzwBZQNeAdIB/wHvAeAC
|
||||
/wHcAbwC/wHNAZ8C/wHBAYoC/wG7AX8C/wG/AYYC/wHNAaEC/wHpAdYB/wNcAcQDNQFVCAABQgFNAT4H
|
||||
AAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEBFgAD/wEAAcABAwYAAYABAWYAAYABAQYAAcABAwgAAf8B
|
||||
/AIAAcABAwIAAf8B/AIAAYABAQIAAf8B+QYAAf8B+QYAAfABEwYAAcABAwYAAYABAQL/BAABgAEBAcAB
|
||||
AQUAAQEBgAYAAQEHAAEBBwABAQcAAQEGAAGAAQEGAAHAAQMCAAGAAQECAAHwAR8BwAEBAcABAws=
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="ilStoreIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>360, 15</value>
|
||||
</metadata>
|
||||
</root>
|
||||
92
qtcnet-client/Controls/MessageControl.Designer.cs
generated
Normal file
92
qtcnet-client/Controls/MessageControl.Designer.cs
generated
Normal file
@ -0,0 +1,92 @@
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
partial class MessageControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
pbProfileImage = new PictureBox();
|
||||
lblUsername = new Label();
|
||||
rtxtMessage = new RichTextBox();
|
||||
((System.ComponentModel.ISupportInitialize)pbProfileImage).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// pbProfileImage
|
||||
//
|
||||
pbProfileImage.Image = Properties.Resources.DefaultPfp;
|
||||
pbProfileImage.Location = new Point(4, 5);
|
||||
pbProfileImage.Name = "pbProfileImage";
|
||||
pbProfileImage.Size = new Size(40, 38);
|
||||
pbProfileImage.SizeMode = PictureBoxSizeMode.Zoom;
|
||||
pbProfileImage.TabIndex = 0;
|
||||
pbProfileImage.TabStop = false;
|
||||
//
|
||||
// lblUsername
|
||||
//
|
||||
lblUsername.AutoSize = true;
|
||||
lblUsername.Font = new Font("Segoe UI", 9F, FontStyle.Bold);
|
||||
lblUsername.Location = new Point(46, 5);
|
||||
lblUsername.Name = "lblUsername";
|
||||
lblUsername.Size = new Size(64, 15);
|
||||
lblUsername.TabIndex = 1;
|
||||
lblUsername.Text = "Username";
|
||||
//
|
||||
// rtxtMessage
|
||||
//
|
||||
rtxtMessage.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
|
||||
rtxtMessage.BackColor = Color.White;
|
||||
rtxtMessage.BorderStyle = BorderStyle.None;
|
||||
rtxtMessage.Location = new Point(50, 23);
|
||||
rtxtMessage.Name = "rtxtMessage";
|
||||
rtxtMessage.ReadOnly = true;
|
||||
rtxtMessage.Size = new Size(98, 22);
|
||||
rtxtMessage.TabIndex = 2;
|
||||
rtxtMessage.Text = "";
|
||||
rtxtMessage.ContentsResized += rtxtMessage_ContentsResized;
|
||||
//
|
||||
// MessageControl
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
BackColor = Color.Transparent;
|
||||
Controls.Add(rtxtMessage);
|
||||
Controls.Add(lblUsername);
|
||||
Controls.Add(pbProfileImage);
|
||||
Name = "MessageControl";
|
||||
Size = new Size(154, 48);
|
||||
Load += MessageControl_Load;
|
||||
((System.ComponentModel.ISupportInitialize)pbProfileImage).EndInit();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private PictureBox pbProfileImage;
|
||||
private Label lblUsername;
|
||||
private RichTextBox rtxtMessage;
|
||||
}
|
||||
}
|
||||
37
qtcnet-client/Controls/MessageControl.cs
Normal file
37
qtcnet-client/Controls/MessageControl.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using qtcnet_client.Properties;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
public partial class MessageControl : UserControl
|
||||
{
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string Username { get; set; } = "Username";
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string Message { get; set; } = "Message";
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public Image ProfileImage { get; set; } = Resources.DefaultPfp;
|
||||
public MessageControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MessageControl_Load(object sender, EventArgs e)
|
||||
{
|
||||
lblUsername.Text = Username;
|
||||
rtxtMessage.Text = Message;
|
||||
pbProfileImage.Image = ProfileImage;
|
||||
}
|
||||
|
||||
private void rtxtMessage_ContentsResized(object sender, ContentsResizedEventArgs e)
|
||||
{
|
||||
rtxtMessage.Height = e.NewRectangle.Height + 4;
|
||||
|
||||
int bottom =
|
||||
rtxtMessage.Bottom +
|
||||
Padding.Bottom;
|
||||
|
||||
Height = Math.Max(bottom, pbProfileImage.Bottom + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Controls/MessageControl.resx
Normal file
120
qtcnet-client/Controls/MessageControl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
245
qtcnet-client/Controls/RegisterControl.Designer.cs
generated
Normal file
245
qtcnet-client/Controls/RegisterControl.Designer.cs
generated
Normal file
@ -0,0 +1,245 @@
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
partial class RegisterControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
pbDefaultPfp = new Krypton.Toolkit.KryptonPictureBox();
|
||||
txtPassword = new Krypton.Toolkit.KryptonTextBox();
|
||||
lblPassword = new Label();
|
||||
lblEmail = new Label();
|
||||
txtEmail = new Krypton.Toolkit.KryptonTextBox();
|
||||
txtConfirmPassword = new Krypton.Toolkit.KryptonTextBox();
|
||||
lblConfirmPassword = new Label();
|
||||
lblConfirmEmail = new Label();
|
||||
txtConfirmEmail = new Krypton.Toolkit.KryptonTextBox();
|
||||
cbTOSAgree = new Krypton.Toolkit.KryptonCheckBox();
|
||||
btnRegister = new Krypton.Toolkit.KryptonButton();
|
||||
llblReshowLogin = new LinkLabel();
|
||||
label3 = new Label();
|
||||
txtUsername = new Krypton.Toolkit.KryptonTextBox();
|
||||
dtpDateOfBirth = new Krypton.Toolkit.KryptonDateTimePicker();
|
||||
lblDateOfBirth = new Label();
|
||||
((System.ComponentModel.ISupportInitialize)pbDefaultPfp).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// pbDefaultPfp
|
||||
//
|
||||
pbDefaultPfp.Image = Properties.Resources.DefaultPfp;
|
||||
pbDefaultPfp.Location = new Point(11, 15);
|
||||
pbDefaultPfp.Name = "pbDefaultPfp";
|
||||
pbDefaultPfp.Size = new Size(128, 128);
|
||||
pbDefaultPfp.SizeMode = PictureBoxSizeMode.AutoSize;
|
||||
pbDefaultPfp.TabIndex = 1;
|
||||
pbDefaultPfp.TabStop = false;
|
||||
//
|
||||
// txtPassword
|
||||
//
|
||||
txtPassword.Location = new Point(208, 76);
|
||||
txtPassword.Name = "txtPassword";
|
||||
txtPassword.PasswordChar = '●';
|
||||
txtPassword.Size = new Size(354, 23);
|
||||
txtPassword.TabIndex = 3;
|
||||
txtPassword.UseSystemPasswordChar = true;
|
||||
//
|
||||
// lblPassword
|
||||
//
|
||||
lblPassword.AutoSize = true;
|
||||
lblPassword.ForeColor = Color.White;
|
||||
lblPassword.Location = new Point(145, 81);
|
||||
lblPassword.Name = "lblPassword";
|
||||
lblPassword.Size = new Size(57, 15);
|
||||
lblPassword.TabIndex = 8;
|
||||
lblPassword.Text = "Password";
|
||||
//
|
||||
// lblEmail
|
||||
//
|
||||
lblEmail.AutoSize = true;
|
||||
lblEmail.ForeColor = Color.White;
|
||||
lblEmail.Location = new Point(145, 51);
|
||||
lblEmail.Name = "lblEmail";
|
||||
lblEmail.Size = new Size(36, 15);
|
||||
lblEmail.TabIndex = 7;
|
||||
lblEmail.Text = "Email";
|
||||
//
|
||||
// txtEmail
|
||||
//
|
||||
txtEmail.Location = new Point(187, 47);
|
||||
txtEmail.Name = "txtEmail";
|
||||
txtEmail.Size = new Size(375, 23);
|
||||
txtEmail.TabIndex = 2;
|
||||
//
|
||||
// txtConfirmPassword
|
||||
//
|
||||
txtConfirmPassword.Location = new Point(255, 134);
|
||||
txtConfirmPassword.Name = "txtConfirmPassword";
|
||||
txtConfirmPassword.PasswordChar = '●';
|
||||
txtConfirmPassword.Size = new Size(307, 23);
|
||||
txtConfirmPassword.TabIndex = 5;
|
||||
txtConfirmPassword.UseSystemPasswordChar = true;
|
||||
//
|
||||
// lblConfirmPassword
|
||||
//
|
||||
lblConfirmPassword.AutoSize = true;
|
||||
lblConfirmPassword.ForeColor = Color.White;
|
||||
lblConfirmPassword.Location = new Point(145, 138);
|
||||
lblConfirmPassword.Name = "lblConfirmPassword";
|
||||
lblConfirmPassword.Size = new Size(104, 15);
|
||||
lblConfirmPassword.TabIndex = 12;
|
||||
lblConfirmPassword.Text = "Confirm Password";
|
||||
//
|
||||
// lblConfirmEmail
|
||||
//
|
||||
lblConfirmEmail.AutoSize = true;
|
||||
lblConfirmEmail.ForeColor = Color.White;
|
||||
lblConfirmEmail.Location = new Point(145, 109);
|
||||
lblConfirmEmail.Name = "lblConfirmEmail";
|
||||
lblConfirmEmail.Size = new Size(83, 15);
|
||||
lblConfirmEmail.TabIndex = 11;
|
||||
lblConfirmEmail.Text = "Confirm Email";
|
||||
//
|
||||
// txtConfirmEmail
|
||||
//
|
||||
txtConfirmEmail.Location = new Point(234, 105);
|
||||
txtConfirmEmail.Name = "txtConfirmEmail";
|
||||
txtConfirmEmail.Size = new Size(328, 23);
|
||||
txtConfirmEmail.TabIndex = 4;
|
||||
//
|
||||
// cbTOSAgree
|
||||
//
|
||||
cbTOSAgree.Location = new Point(255, 190);
|
||||
cbTOSAgree.Name = "cbTOSAgree";
|
||||
cbTOSAgree.PaletteMode = Krypton.Toolkit.PaletteMode.Office2007Silver;
|
||||
cbTOSAgree.Size = new Size(354, 20);
|
||||
cbTOSAgree.TabIndex = 7;
|
||||
cbTOSAgree.Values.Text = "By Checking Me, You Agree To This Servers Terms Of Service";
|
||||
//
|
||||
// btnRegister
|
||||
//
|
||||
btnRegister.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
btnRegister.Location = new Point(502, 231);
|
||||
btnRegister.Name = "btnRegister";
|
||||
btnRegister.Size = new Size(90, 25);
|
||||
btnRegister.TabIndex = 9;
|
||||
btnRegister.Values.DropDownArrowColor = Color.Empty;
|
||||
btnRegister.Values.Text = "Register";
|
||||
btnRegister.Click += btnRegister_Click;
|
||||
//
|
||||
// llblReshowLogin
|
||||
//
|
||||
llblReshowLogin.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
llblReshowLogin.AutoSize = true;
|
||||
llblReshowLogin.Location = new Point(499, 210);
|
||||
llblReshowLogin.Name = "llblReshowLogin";
|
||||
llblReshowLogin.Size = new Size(95, 15);
|
||||
llblReshowLogin.TabIndex = 8;
|
||||
llblReshowLogin.TabStop = true;
|
||||
llblReshowLogin.Text = "Meant To Login?";
|
||||
llblReshowLogin.LinkClicked += llblReshowLogin_LinkClicked;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
label3.AutoSize = true;
|
||||
label3.ForeColor = Color.White;
|
||||
label3.Location = new Point(145, 22);
|
||||
label3.Name = "label3";
|
||||
label3.Size = new Size(60, 15);
|
||||
label3.TabIndex = 17;
|
||||
label3.Text = "Username";
|
||||
//
|
||||
// txtUsername
|
||||
//
|
||||
txtUsername.Location = new Point(211, 18);
|
||||
txtUsername.Name = "txtUsername";
|
||||
txtUsername.Size = new Size(351, 23);
|
||||
txtUsername.TabIndex = 1;
|
||||
//
|
||||
// dtpDateOfBirth
|
||||
//
|
||||
dtpDateOfBirth.Location = new Point(226, 163);
|
||||
dtpDateOfBirth.Name = "dtpDateOfBirth";
|
||||
dtpDateOfBirth.Size = new Size(336, 21);
|
||||
dtpDateOfBirth.TabIndex = 6;
|
||||
//
|
||||
// lblDateOfBirth
|
||||
//
|
||||
lblDateOfBirth.AutoSize = true;
|
||||
lblDateOfBirth.ForeColor = Color.White;
|
||||
lblDateOfBirth.Location = new Point(145, 165);
|
||||
lblDateOfBirth.Name = "lblDateOfBirth";
|
||||
lblDateOfBirth.Size = new Size(75, 15);
|
||||
lblDateOfBirth.TabIndex = 19;
|
||||
lblDateOfBirth.Text = "Date Of Birth";
|
||||
//
|
||||
// RegisterControl
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
BackColor = Color.Transparent;
|
||||
Controls.Add(lblDateOfBirth);
|
||||
Controls.Add(dtpDateOfBirth);
|
||||
Controls.Add(label3);
|
||||
Controls.Add(txtUsername);
|
||||
Controls.Add(llblReshowLogin);
|
||||
Controls.Add(btnRegister);
|
||||
Controls.Add(cbTOSAgree);
|
||||
Controls.Add(txtConfirmPassword);
|
||||
Controls.Add(lblConfirmPassword);
|
||||
Controls.Add(lblConfirmEmail);
|
||||
Controls.Add(txtConfirmEmail);
|
||||
Controls.Add(txtPassword);
|
||||
Controls.Add(lblPassword);
|
||||
Controls.Add(lblEmail);
|
||||
Controls.Add(txtEmail);
|
||||
Controls.Add(pbDefaultPfp);
|
||||
Name = "RegisterControl";
|
||||
Size = new Size(597, 260);
|
||||
((System.ComponentModel.ISupportInitialize)pbDefaultPfp).EndInit();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Krypton.Toolkit.KryptonPictureBox pbDefaultPfp;
|
||||
private Krypton.Toolkit.KryptonTextBox txtPassword;
|
||||
private Label lblPassword;
|
||||
private Label lblEmail;
|
||||
private Krypton.Toolkit.KryptonTextBox txtEmail;
|
||||
private Krypton.Toolkit.KryptonTextBox txtConfirmPassword;
|
||||
private Label lblConfirmPassword;
|
||||
private Label lblConfirmEmail;
|
||||
private Krypton.Toolkit.KryptonTextBox txtConfirmEmail;
|
||||
private Krypton.Toolkit.KryptonCheckBox cbTOSAgree;
|
||||
private Krypton.Toolkit.KryptonButton btnRegister;
|
||||
private LinkLabel llblReshowLogin;
|
||||
private Label label3;
|
||||
private Krypton.Toolkit.KryptonTextBox txtUsername;
|
||||
private Krypton.Toolkit.KryptonDateTimePicker dtpDateOfBirth;
|
||||
private Label lblDateOfBirth;
|
||||
}
|
||||
}
|
||||
74
qtcnet-client/Controls/RegisterControl.cs
Normal file
74
qtcnet-client/Controls/RegisterControl.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using Krypton.Toolkit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Formats.Cbor;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
public partial class RegisterControl : UserControl
|
||||
{
|
||||
public string Username { get; private set; } = string.Empty;
|
||||
public string Email { get; private set; } = string.Empty;
|
||||
public string Password { get; private set; } = string.Empty;
|
||||
public DateTime DateOfBirth { get; private set; } = DateTime.MinValue;
|
||||
|
||||
public event EventHandler? OnReshowLoginPressed;
|
||||
public event EventHandler? OnRegister;
|
||||
public RegisterControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void llblReshowLogin_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
ToggleControls(false);
|
||||
OnReshowLoginPressed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void btnRegister_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(ValidateForm())
|
||||
{
|
||||
ToggleControls(false);
|
||||
|
||||
Username = txtUsername.Text;
|
||||
Email = txtEmail.Text;
|
||||
Password = txtPassword.Text;
|
||||
DateOfBirth = dtpDateOfBirth.Value;
|
||||
OnRegister?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
KryptonMessageBox.Show("A Required Field Is Missing. Please Complete The Form.", "Oops.");
|
||||
ToggleControls(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleControls(bool toggle)
|
||||
{
|
||||
txtUsername.Enabled = toggle;
|
||||
txtEmail.Enabled = toggle;
|
||||
txtPassword.Enabled = toggle;
|
||||
txtConfirmEmail.Enabled = toggle;
|
||||
txtConfirmPassword.Enabled = toggle;
|
||||
cbTOSAgree.Enabled = toggle;
|
||||
dtpDateOfBirth.Enabled = toggle;
|
||||
llblReshowLogin.Enabled = toggle;
|
||||
btnRegister.Enabled = toggle;
|
||||
}
|
||||
|
||||
private bool ValidateForm()
|
||||
{
|
||||
return !string.IsNullOrEmpty(txtEmail.Text) &&
|
||||
!string.IsNullOrEmpty(txtPassword.Text) &&
|
||||
(txtConfirmEmail.Text == txtEmail.Text) &&
|
||||
(txtConfirmPassword.Text == txtPassword.Text) &&
|
||||
cbTOSAgree.Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Controls/RegisterControl.resx
Normal file
120
qtcnet-client/Controls/RegisterControl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
97
qtcnet-client/Controls/RoomControl.Designer.cs
generated
Normal file
97
qtcnet-client/Controls/RoomControl.Designer.cs
generated
Normal file
@ -0,0 +1,97 @@
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
partial class RoomControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
pbIcon = new PictureBox();
|
||||
lblRoomName = new Label();
|
||||
lblRoomUserCount = new Label();
|
||||
((System.ComponentModel.ISupportInitialize)pbIcon).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// pbIcon
|
||||
//
|
||||
pbIcon.Image = Properties.Resources.RoomsChatIcon;
|
||||
pbIcon.Location = new Point(3, 3);
|
||||
pbIcon.Name = "pbIcon";
|
||||
pbIcon.Size = new Size(40, 35);
|
||||
pbIcon.SizeMode = PictureBoxSizeMode.Zoom;
|
||||
pbIcon.TabIndex = 0;
|
||||
pbIcon.TabStop = false;
|
||||
//
|
||||
// lblRoomName
|
||||
//
|
||||
lblRoomName.AutoSize = true;
|
||||
lblRoomName.Font = new Font("Segoe UI", 8F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||
lblRoomName.Location = new Point(49, 14);
|
||||
lblRoomName.Name = "lblRoomName";
|
||||
lblRoomName.Size = new Size(38, 13);
|
||||
lblRoomName.TabIndex = 1;
|
||||
lblRoomName.Text = "Room";
|
||||
lblRoomName.DoubleClick += lblRoomName_DoubleClick;
|
||||
lblRoomName.MouseLeave += lblRoomName_MouseLeave;
|
||||
lblRoomName.MouseHover += lblRoomName_MouseHover;
|
||||
//
|
||||
// lblRoomUserCount
|
||||
//
|
||||
lblRoomUserCount.AutoSize = true;
|
||||
lblRoomUserCount.Dock = DockStyle.Right;
|
||||
lblRoomUserCount.Font = new Font("Segoe UI Semibold", 9F, FontStyle.Bold | FontStyle.Italic, GraphicsUnit.Point, 0);
|
||||
lblRoomUserCount.ForeColor = Color.Silver;
|
||||
lblRoomUserCount.Location = new Point(154, 0);
|
||||
lblRoomUserCount.Name = "lblRoomUserCount";
|
||||
lblRoomUserCount.Padding = new Padding(0, 15, 0, 0);
|
||||
lblRoomUserCount.Size = new Size(14, 30);
|
||||
lblRoomUserCount.TabIndex = 2;
|
||||
lblRoomUserCount.Text = "0";
|
||||
lblRoomUserCount.TextAlign = ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// RoomControl
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
BackColor = Color.Transparent;
|
||||
Controls.Add(lblRoomUserCount);
|
||||
Controls.Add(lblRoomName);
|
||||
Controls.Add(pbIcon);
|
||||
DoubleBuffered = true;
|
||||
Name = "RoomControl";
|
||||
Size = new Size(168, 42);
|
||||
Load += RoomControl_Load;
|
||||
((System.ComponentModel.ISupportInitialize)pbIcon).EndInit();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private PictureBox pbIcon;
|
||||
private Label lblRoomName;
|
||||
private Label lblRoomUserCount;
|
||||
}
|
||||
}
|
||||
61
qtcnet-client/Controls/RoomControl.cs
Normal file
61
qtcnet-client/Controls/RoomControl.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Controls
|
||||
{
|
||||
public partial class RoomControl : UserControl
|
||||
{
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public string RoomId { get; set; } = string.Empty;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string RoomName { get; set; } = "Room";
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public int UserCount { get; set; } = 0;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public bool IsUserCountVisible { get; set; } = true;
|
||||
|
||||
public event EventHandler? OnRoomDoubleClicked;
|
||||
|
||||
bool _isHovering = false;
|
||||
public RoomControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
AutoSize = false;
|
||||
Height = 59;
|
||||
}
|
||||
|
||||
private void RoomControl_Load(object sender, EventArgs e)
|
||||
{
|
||||
lblRoomName.Text = RoomName;
|
||||
lblRoomUserCount.Text = UserCount.ToString();
|
||||
lblRoomUserCount.Visible = IsUserCountVisible;
|
||||
}
|
||||
|
||||
private void lblRoomName_MouseHover(object sender, EventArgs e)
|
||||
{
|
||||
if (!_isHovering)
|
||||
{
|
||||
lblRoomName.ForeColor = Color.White;
|
||||
_isHovering = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void lblRoomName_MouseLeave(object sender, EventArgs e)
|
||||
{
|
||||
if (_isHovering)
|
||||
{
|
||||
lblRoomName.ForeColor = Color.Black;
|
||||
_isHovering = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void lblRoomName_DoubleClick(object sender, EventArgs e) => OnRoomDoubleClicked?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Controls/RoomControl.resx
Normal file
120
qtcnet-client/Controls/RoomControl.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
149
qtcnet-client/Forms/ChatRoomForm.Designer.cs
generated
Normal file
149
qtcnet-client/Forms/ChatRoomForm.Designer.cs
generated
Normal file
@ -0,0 +1,149 @@
|
||||
namespace qtcnet_client.Forms
|
||||
{
|
||||
partial class ChatRoomForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChatRoomForm));
|
||||
lblUsersOnline = new Label();
|
||||
rtxtChatbox = new RichTextBox();
|
||||
btnSend = new Button();
|
||||
lblRoomName = new Label();
|
||||
lvUsers = new ListView();
|
||||
flpMessages = new FlowLayoutPanel();
|
||||
ilStatusIcons = new ImageList(components);
|
||||
SuspendLayout();
|
||||
//
|
||||
// lblUsersOnline
|
||||
//
|
||||
lblUsersOnline.AutoSize = true;
|
||||
lblUsersOnline.Font = new Font("Segoe UI", 10F, FontStyle.Bold);
|
||||
lblUsersOnline.ForeColor = Color.White;
|
||||
lblUsersOnline.Location = new Point(12, 47);
|
||||
lblUsersOnline.Name = "lblUsersOnline";
|
||||
lblUsersOnline.Size = new Size(92, 19);
|
||||
lblUsersOnline.TabIndex = 1;
|
||||
lblUsersOnline.Text = "Users Online";
|
||||
//
|
||||
// rtxtChatbox
|
||||
//
|
||||
rtxtChatbox.Location = new Point(169, 318);
|
||||
rtxtChatbox.Name = "rtxtChatbox";
|
||||
rtxtChatbox.Size = new Size(508, 66);
|
||||
rtxtChatbox.TabIndex = 3;
|
||||
rtxtChatbox.Text = "";
|
||||
rtxtChatbox.KeyDown += rtxtChatbox_KeyDown;
|
||||
//
|
||||
// btnSend
|
||||
//
|
||||
btnSend.BackgroundImage = Properties.Resources.SendIcon;
|
||||
btnSend.BackgroundImageLayout = ImageLayout.Zoom;
|
||||
btnSend.FlatAppearance.BorderSize = 0;
|
||||
btnSend.FlatStyle = FlatStyle.Flat;
|
||||
btnSend.Location = new Point(683, 329);
|
||||
btnSend.Name = "btnSend";
|
||||
btnSend.Size = new Size(75, 44);
|
||||
btnSend.TabIndex = 4;
|
||||
btnSend.UseVisualStyleBackColor = true;
|
||||
btnSend.Click += btnSend_Click;
|
||||
//
|
||||
// lblRoomName
|
||||
//
|
||||
lblRoomName.AutoSize = true;
|
||||
lblRoomName.Font = new Font("Segoe UI", 20F, FontStyle.Bold | FontStyle.Italic);
|
||||
lblRoomName.ForeColor = Color.White;
|
||||
lblRoomName.Location = new Point(6, 4);
|
||||
lblRoomName.Name = "lblRoomName";
|
||||
lblRoomName.Size = new Size(91, 37);
|
||||
lblRoomName.TabIndex = 5;
|
||||
lblRoomName.Text = "Room";
|
||||
//
|
||||
// lvUsers
|
||||
//
|
||||
lvUsers.Location = new Point(12, 69);
|
||||
lvUsers.Name = "lvUsers";
|
||||
lvUsers.Size = new Size(151, 315);
|
||||
lvUsers.SmallImageList = ilStatusIcons;
|
||||
lvUsers.TabIndex = 6;
|
||||
lvUsers.UseCompatibleStateImageBehavior = false;
|
||||
lvUsers.View = View.List;
|
||||
//
|
||||
// flpMessages
|
||||
//
|
||||
flpMessages.AutoScroll = true;
|
||||
flpMessages.BackColor = Color.White;
|
||||
flpMessages.FlowDirection = FlowDirection.TopDown;
|
||||
flpMessages.Location = new Point(169, 69);
|
||||
flpMessages.Name = "flpMessages";
|
||||
flpMessages.Size = new Size(589, 243);
|
||||
flpMessages.TabIndex = 7;
|
||||
flpMessages.WrapContents = false;
|
||||
//
|
||||
// ilStatusIcons
|
||||
//
|
||||
ilStatusIcons.ColorDepth = ColorDepth.Depth32Bit;
|
||||
ilStatusIcons.ImageStream = (ImageListStreamer)resources.GetObject("ilStatusIcons.ImageStream");
|
||||
ilStatusIcons.TransparentColor = Color.Transparent;
|
||||
ilStatusIcons.Images.SetKeyName(0, "Offline");
|
||||
ilStatusIcons.Images.SetKeyName(1, "Online");
|
||||
ilStatusIcons.Images.SetKeyName(2, "Away");
|
||||
ilStatusIcons.Images.SetKeyName(3, "DoNotDisturb");
|
||||
//
|
||||
// ChatRoomForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
BackColor = Color.DodgerBlue;
|
||||
ClientSize = new Size(770, 396);
|
||||
Controls.Add(flpMessages);
|
||||
Controls.Add(lvUsers);
|
||||
Controls.Add(lblRoomName);
|
||||
Controls.Add(btnSend);
|
||||
Controls.Add(rtxtChatbox);
|
||||
Controls.Add(lblUsersOnline);
|
||||
FormBorderStyle = FormBorderStyle.FixedSingle;
|
||||
MaximizeBox = false;
|
||||
Name = "ChatRoomForm";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "QtC.NET Chat Room";
|
||||
FormClosed += ChatRoomForm_FormClosed;
|
||||
Load += ChatRoomForm_Load;
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
private Label lblUsersOnline;
|
||||
private RichTextBox rtxtChatbox;
|
||||
private Button btnSend;
|
||||
private Label lblRoomName;
|
||||
private ListView lvUsers;
|
||||
private FlowLayoutPanel flpMessages;
|
||||
private ImageList ilStatusIcons;
|
||||
}
|
||||
}
|
||||
105
qtcnet-client/Forms/ChatRoomForm.cs
Normal file
105
qtcnet-client/Forms/ChatRoomForm.cs
Normal file
@ -0,0 +1,105 @@
|
||||
using qtcnet_client.Controls;
|
||||
using QtCNETAPI.Dtos.User;
|
||||
using System.ComponentModel;
|
||||
namespace qtcnet_client.Forms
|
||||
{
|
||||
public partial class ChatRoomForm : Form
|
||||
{
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public string RoomId { get; set; } = string.Empty;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string RoomName { get; set; } = "Room";
|
||||
public string SentMessage { get; private set; } = string.Empty;
|
||||
|
||||
public event EventHandler? OnSend;
|
||||
public event EventHandler? OnClose;
|
||||
|
||||
public ChatRoomForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ChatRoomForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = $"QtC.NET Chat Room - {RoomName}";
|
||||
lblRoomName.Text = RoomName;
|
||||
}
|
||||
|
||||
private void rtxtChatbox_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Enter)
|
||||
{
|
||||
if (ValidateChatBox())
|
||||
{
|
||||
SentMessage = rtxtChatbox.Text;
|
||||
OnSend?.Invoke(this, EventArgs.Empty);
|
||||
rtxtChatbox.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnSend_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ValidateChatBox())
|
||||
{
|
||||
SentMessage = rtxtChatbox.Text;
|
||||
OnSend?.Invoke(this, EventArgs.Empty);
|
||||
rtxtChatbox.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void ChatRoomForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
OnClose?.Invoke(this, EventArgs.Empty);
|
||||
Close();
|
||||
}
|
||||
|
||||
public void AddUsersToRoomList(List<UserInformationDto> users)
|
||||
{
|
||||
lvUsers.SuspendLayout();
|
||||
|
||||
lvUsers.Items.Clear();
|
||||
|
||||
List<ListViewItem> lvis = [];
|
||||
foreach (UserInformationDto user in users)
|
||||
{
|
||||
lvis.Add(new ListViewItem
|
||||
{
|
||||
Tag = user.Id,
|
||||
Text = user.Username,
|
||||
ImageIndex = user.Status
|
||||
});
|
||||
}
|
||||
|
||||
lvUsers.Items.AddRange([.. lvis.DistinctBy(u => u.Tag)]);
|
||||
|
||||
lvUsers.ResumeLayout(true);
|
||||
}
|
||||
|
||||
public void AddUserToRoomList(UserInformationDto user)
|
||||
{
|
||||
ListViewItem lvi = new()
|
||||
{
|
||||
Tag = user.Id,
|
||||
Text = user.Username,
|
||||
ImageIndex = user.Status
|
||||
};
|
||||
|
||||
lvUsers.Items.Add(lvi);
|
||||
}
|
||||
|
||||
public void AddMessage(MessageControl messageCtrl)
|
||||
{
|
||||
messageCtrl.Width = flpMessages.ClientSize.Width - 10;
|
||||
messageCtrl.Margin = new Padding(0, 0, 0, 6);
|
||||
|
||||
flpMessages.Controls.Add(messageCtrl);
|
||||
flpMessages.ScrollControlIntoView(messageCtrl);
|
||||
}
|
||||
|
||||
private bool ValidateChatBox()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(rtxtChatbox.Text) || !string.IsNullOrEmpty(rtxtChatbox.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
216
qtcnet-client/Forms/ChatRoomForm.resx
Normal file
216
qtcnet-client/Forms/ChatRoomForm.resx
Normal file
@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="ilStatusIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>16, 13</value>
|
||||
</metadata>
|
||||
<data name="ilStatusIcons.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
|
||||
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
|
||||
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAGhQAAAJNU0Z0AUkBTAIBAQQB
|
||||
AAGYAQABmAEAARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABIAYAASD/
|
||||
AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AC4AAwYBBwM0AVQDUQGiA14B0gNaAekDYAHoA10B
|
||||
0QNQAZ8DMQFNAwUBBhgAAwYBBwM0AVQDUQGiA14B0gNaAekDYAHoA10B0QNQAZ8DMQFNAwUBBhgAAwYB
|
||||
BwM0AVQDUQGiA14B0gNaAekDYAHoA10B0QNQAZ8DMQFNAwUBBhgAAwYBBwM0AVQDUQGiA14B0gNaAekD
|
||||
YAHoA10B0QNQAZ8DMQFNAwUBBhQAAyABLQNUAasDWwHkA0wB9QMkAfsDNwH+AzcB/gMkAfsDUwH0A2IB
|
||||
4QNRAaEDHgEqEAADIAEtA1QBqwNbAeQBRgFYAUYB9QEhAVMBIQH7ARMBUwETAf4BEwFTARMB/gEhAVMB
|
||||
IQH7AU8BUwFPAfQDYgHhA1EBoQMeASoQAAMgAS0DVAGrA1sB5AFGAlgB9QEhAlMB+wETAlMB/gETAlMB
|
||||
/gEhAlMB+wFPAlMB9ANiAeEDUQGhAx4BKhAAAyABLQNUAasDWwHkAkYBWAH1AiEBUwH7AhMBUwH+AhMB
|
||||
UwH+AiEBUwH7Ak8BUwH0A2IB4QNRAaEDHgEqDAADGwElA1gBvQNaAfIDOwH+AzAB/wM5Af8DPAH/AzYB
|
||||
/wMqAf8DJAH/A0AB/QNZAfADVgGyAxoBIwgAAxsBJQNYAb0BVwFaAVcB8gETAVsBEwH+AQABVwEAAf8B
|
||||
AAFnAQAB/wEAAWwBAAH/AQABYQEAAf8BAAFMAQAB/wEAAUABAAH/ASYBQAEmAf0BVAFeAVQB8ANWAbIB
|
||||
GQEaARkBIwgAAxsBJQNYAb0BVwJaAfIBEwJbAf4BAAJXAf8BAAJnAf8BAAJsAf8BAAJhAf8BAAJMAf8B
|
||||
AAJAAf8BJgJAAf0BVAJeAfADVgGyARkCGgEjCAADGwElA1gBvQJXAVoB8gITAVsB/gIAAVcB/wIAAWcB
|
||||
/wIAAWwB/wIAAWEB/wIAAUwB/wIAAUAB/wImAUAB/QJUAV4B8ANWAbICGQEaASMEAAMDAQQDUgGlA18B
|
||||
8wNJAf8DVQH/A2UB/wNxAf8DdQH/A3EB/wNkAf8DTAH/AzEB/wM3Af4DXQHuA1ABmgMDAQQDAwEEAVIB
|
||||
UwFSAaUBUQFvAVEB8wEAAYIBAAH/AQABmQEAAf8BAAG2AQAB/wEAAcwBAAH/AQAB0wEAAf8BAAHLAQAB
|
||||
/wEAAbMBAAH/AQABiAEAAf8BAAFXAQAB/wETAVMBEwH+AVoBYQFaAe4DUAGaAwMBBAMDAQQBUgJTAaUB
|
||||
UQJvAfMBAAKCAf8BAAKZAf8BAAK2Af8BAALMAf8BAALTAf8BAALLAf8BAAKzAf8BAAKIAf8BAAJXAf8B
|
||||
EwJTAf4BWgJhAe4DUAGaAwMBBAMDAQQCUgFTAaUCUQFvAfMCAAGCAf8CAAGZAf8CAAG2Af8CAAHMAf8C
|
||||
AAHTAf8CAAHLAf8CAAGzAf8CAAGIAf8CAAFXAf8CEwFTAf4CWgFhAe4DUAGaAwMBBAMtAUQDYAHoA3YB
|
||||
/gNuAf8DewH/A4UB/wOKAf8DjAH/A4oB/wOFAf8DdgH/A1cB/wMyAf8DQAH9A14B3QMqAT8DLQFEAWAB
|
||||
aQFgAegBEwGOARMB/gEAAcYBAAH/AQAB3AEAAf8BAAHuAQAB/wEAAfgBAAH/AQAB+wEAAf8BAAH5AQAB
|
||||
/wEAAe8BAAH/AQAB1AEAAf8BAAGcAQAB/wEAAVoBAAH/ASYBQAEmAf0DXgHdAyoBPwMtAUQBYAJpAegB
|
||||
EwKOAf4BAALGAf8BAALcAf8BAALuAf8BAAL4Af8BAAL7Af8BAAL5Af8BAALvAf8BAALUAf8BAAKcAf8B
|
||||
AAJaAf8BJgJAAf0DXgHdAyoBPwMtAUQCYAFpAegCEwGOAf4CAAHGAf8CAAHcAf8CAAHuAf8CAAH4Af8C
|
||||
AAH7Af8CAAH5Af8CAAHvAf8CAAHUAf8CAAGcAf8CAAFaAf8CJgFAAf0DXgHdAyoBPwNOAZUDdwH4A38B
|
||||
/wOFAf8DigH/A40B/wOOAf8DjgH/A44B/wONAf8DiQH/A3cB/wNNAf8DJQH/A1oB8gNKAYsDTgGVAT0B
|
||||
kAE9AfgBAAHlAQAB/wEAAe8BAAH/AQAB+AEAAf8BAAH9AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
|
||||
/wEAAf4BAAH/AQAB9gEAAf8BAAHVAQAB/wEAAYsBAAH/AQABQQEAAf8BVwFaAVcB8gNKAYsDTgGVAT0C
|
||||
kAH4AQAC5QH/AQAC7wH/AQAC+AH/AQAC/QH/AQAD/wEAA/8BAAP/AQAC/gH/AQAC9gH/AQAC1QH/AQAC
|
||||
iwH/AQACQQH/AVcCWgHyA0oBiwNOAZUCPQGQAfgCAAHlAf8CAAHvAf8CAAH4Af8CAAH9Af8CAAL/AgAC
|
||||
/wIAAv8CAAH+Af8CAAH2Af8CAAHVAf8CAAGLAf8CAAFBAf8CVwFaAfIDSgGLA18B0wN+AfwDkwH/A44B
|
||||
/wONAf8DjgH/A44B/wOOAf8DjgH/A44B/wONAf8DhQH/A2cB/wM0Af8DQQH5A1oBxAFbAV8BWwHTASsB
|
||||
ugErAfwBDgH7AQ4B/wEDAf0BAwH/AQAB/gEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
|
||||
/wEAAf8BAAH/AQAB/QEAAf8BAAHvAQAB/wEAAbkBAAH/AQABXQEAAf8BOAFBATgB+QNaAcQBWwJfAdMB
|
||||
KwK6AfwBDgL7Af8BAwL9Af8BAAL+Af8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAAv0B/wEAAu8B/wEAArkB
|
||||
/wEAAl0B/wE4AkEB+QNaAcQCWwFfAdMCKwG6AfwCDgH7Af8CAwH9Af8CAAH+Af8CAAL/AgAC/wIAAv8C
|
||||
AAL/AgAC/wIAAf0B/wIAAe8B/wIAAbkB/wIAAV0B/wI4AUEB+QNaAcQDbgH1A4AB/gOfAf8DkwH/A48B
|
||||
/wOOAf8DjgH/A44B/wOOAf8DjgH/A44B/wOLAf8DdwH/A0gB/wNAAf0DYgHhAUsBgwFLAfUBNwHZATcB
|
||||
/gEnAf8BJwH/AQsB/wELAf8BAQH/AQEB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
|
||||
/wEAAf8BAAH/AQAB/wEAAfkBAAH/AQAB1gEAAf8BAAGBAQAB/wEmAUABJgH9A2IB4QFLAoMB9QE3AtkB
|
||||
/gEnA/8BCwP/AQED/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAD/wEAAvkB/wEAAtYB/wEAAoEB/wEmAkAB
|
||||
/QNiAeECSwGDAfUCNwHZAf4CJwL/AgsC/wIBAv8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAv8CAAH5Af8C
|
||||
AAHWAf8CAAGBAf8CJgFAAf0DYgHhA3QB9gOIAf4DqwH/A5kB/wOQAf8DjgH/A44B/wOOAf8DjgH/A44B
|
||||
/wOOAf8DjQH/A38B/wNVAf8DQAH9A14B4gFIAYcBSAH2AVoB2QFaAf4BQgH/AUIB/wEZAf8BGQH/AQQB
|
||||
/wEEAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH9AQAB
|
||||
/wEAAeQBAAH/AQABmAEAAf8BJgFAASYB/QNeAeIBSAKHAfYBWgLZAf4BQgP/ARkD/wEEA/8BAAP/AQAD
|
||||
/wEAA/8BAAP/AQAD/wEAA/8BAAL9Af8BAALkAf8BAAKYAf8BJgJAAf0DXgHiAkgBhwH2AloB2QH+AkIC
|
||||
/wIZAv8CBAL/AgAC/wIAAv8CAAL/AgAC/wIAAv8CAAL/AgAB/QH/AgAB5AH/AgABmAH/AiYBQAH9A14B
|
||||
4gNhAdYDiQH8A7gB/wOjAf8DkwH/A44B/wOOAf8DjgH/A44B/wOOAf8DjgH/A40B/wOCAf8DXAH/A00B
|
||||
+gNaAccBXAFhAVwB1gFkAb4BZAH8AV8B/wFfAf8BLwH/AS8B/wEMAf8BDAH/AQEB/wEBAf8BAAH/AQAB
|
||||
/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB/gEAAf8BAAHqAQAB/wEAAaUBAAH/AScB
|
||||
TQEnAfoDWgHHAVwCYQHWAWQCvgH8AV8D/wEvA/8BDAP/AQED/wEAA/8BAAP/AQAD/wEAA/8BAAP/AQAC
|
||||
/gH/AQAC6gH/AQACpQH/AScCTQH6A1oBxwJcAWEB1gJkAb4B/AJfAv8CLwL/AgwC/wIBAv8CAAL/AgAC
|
||||
/wIAAv8CAAL/AgAC/wIAAf4B/wIAAeoB/wIAAaUB/wInAU0B+gNaAccDUAGaA40B+QPFAf8DsgH/A5wB
|
||||
/wORAf8DjgH/A44B/wOOAf8DjgH/A48B/wOOAf8DgwH/A2AB/wNaAfIDTAGQA1ABmgFqAaEBagH5AXwB
|
||||
/wF8Af8BUQH/AVEB/wEfAf8BHwH/AQcB/wEHAf8BAQH/AQEB/wEAAf8BAAH/AQAB/wEAAf8BAAH/AQAB
|
||||
/wECAf8BAgH/AQIB/gECAf8BAAHrAQAB/wEAAa0BAAH/AVcBawFXAfIDTAGQA1ABmgFqAqEB+QF8A/8B
|
||||
UQP/AR8D/wEHA/8BAQP/AQAD/wEAA/8BAAP/AQID/wECAv4B/wEAAusB/wEAAq0B/wFXAmsB8gNMAZAD
|
||||
UAGaAmoBoQH5AnwC/wJRAv8CHwL/AgcC/wIBAv8CAAL/AgAC/wIAAv8CAgL/AgIB/gH/AgAB6wH/AgAB
|
||||
rQH/AlcBawHyA0wBkAMvAUkDbAHrA6oB/gPGAf8DrgH/A5wB/wOTAf8DkAH/A48B/wOQAf8DkwH/A5MB
|
||||
/wOFAf8DUwH9A2AB4AMtAUUDLwFJA2wB6wGAAdkBgAH+AX8B/wF/Af8BSQH/AUkB/wEfAf8BHwH/AQwB
|
||||
/wEMAf8BBQH/AQUB/wEDAf8BAwH/AQUB/wEFAf8BCgH/AQoB/wEKAf4BCgH/AQEB7QEBAf8BJgG2ASYB
|
||||
/QFgAWYBYAHgAy0BRQMvAUkDbAHrAYAC2QH+AX8D/wFJA/8BHwP/AQwD/wEFA/8BAwP/AQUD/wEKA/8B
|
||||
CgL+Af8BAQLtAf8BJgK2Af0BYAJmAeADLQFFAy8BSQNsAesCgAHZAf4CfwL/AkkC/wIfAv8CDAL/AgUC
|
||||
/wIDAv8CBQL/AgoC/wIKAf4B/wIBAe0B/wImAbYB/QJgAWYB4AMtAUUDAwEEA1YBrgN8AfUD2QH/A8sB
|
||||
/wO3Af8DpwH/A50B/wOaAf8DnAH/A58B/wObAf8DiQH/A2gB8ANSAaMDAwEEAwMBBANWAa4BbwGDAW8B
|
||||
9QGoAf8BqAH/AYkB/wGJAf8BXAH/AVwB/wE3Af8BNwH/ASIB/wEiAf8BGwH/ARsB/wEfAf8BHwH/ASYB
|
||||
/wEmAf8BHQH/AR0B/wEFAfMBBQH/AVQBawFUAfADUgGjAwMBBAMDAQQDVgGuAW8CgwH1AagD/wGJA/8B
|
||||
XAP/ATcD/wEiA/8BGwP/AR8D/wEmA/8BHQP/AQUC8wH/AVQCawHwA1IBowMDAQQDAwEEA1YBrgJvAYMB
|
||||
9QKoAv8CiQL/AlwC/wI3Av8CIgL/AhsC/wIfAv8CJgL/Ah0C/wIFAfMB/wJUAWsB8ANSAaMDAwEEBAAD
|
||||
HAEnA10BxwN9AfYDuQH+A9cB/wPMAf8DwgH/A7sB/wO3Af8DsQH/A4AB/gNpAfQDWQG8AxsBJggAAxwB
|
||||
JwNdAccBdwGHAXcB9gGRAdkBkQH+AaUB/wGlAf8BiwH/AYsB/wF0Af8BdAH/AWYB/wFmAf8BXAH/AVwB
|
||||
/wFOAf8BTgH/AUMB2QFDAf4BUgF9AVIB9AFXAVkBVwG8AxsBJggAAxwBJwNdAccBdwKHAfYBkQLZAf4B
|
||||
pQP/AYsD/wF0A/8BZgP/AVwD/wFOA/8BQwLZAf4BUgJ9AfQBVwJZAbwDGwEmCAADHAEnA10BxwJ3AYcB
|
||||
9gKRAdkB/gKlAv8CiwL/AnQC/wJmAv8CXAL/Ak4C/wJDAdkB/gJSAX0B9AJXAVkBvAMbASYMAAMhATAD
|
||||
WQG2A2wB7gOfAfoDvgH9A9QB/wPMAf8DvgH9A4kB+QNsAesDVQGsAx8BLBAAAyEBMANZAbYBagFuAWoB
|
||||
7gGHAakBhwH6Aa4BxgGuAf0BnwH/AZ8B/wGMAf8BjAH/AWMBxgFjAf0BaAGhAWgB+QFhAWwBYQHrA1UB
|
||||
rAMfASwQAAMhATADWQG2AWoCbgHuAYcCqQH6Aa4CxgH9AZ8D/wGMA/8BYwLGAf0BaAKhAfkBYQJsAesD
|
||||
VQGsAx8BLBAAAyEBMANZAbYCagFuAe4ChwGpAfoCrgHGAf0CnwL/AowC/wJjAcYB/QJoAaEB+QJhAWwB
|
||||
6wNVAawDHwEsFAADBgEHAzYBWANVAawDZgHlA60B/AOYAfsDZQHiA1MBpwMzAVEDBgEHGAADBgEHAzYB
|
||||
WANVAawDZgHlAX4BvgF+AfwBdwGyAXcB+wNlAeIDUwGnAzMBUQMGAQcYAAMGAQcDNgFYA1UBrANmAeUB
|
||||
fgK+AfwBdwKyAfsDZQHiA1MBpwMzAVEDBgEHGAADBgEHAzYBWANVAawDZgHlAn4BvgH8AncBsgH7A2UB
|
||||
4gNTAacDMwFRAwYBBwwAAUIBTQE+BwABPgMAASgDAAFAAwABIAMAAQEBAAEBBgABARYAA/+BAAHgAQcB
|
||||
4AEHAeABBwHgAQcBwAEDAcABAwHAAQMBwAEDAYABAQGAAQEBgAEBAYABAVAAAYABAQGAAQEBgAEBAYAB
|
||||
AQHAAQMBwAEDAcABAwHAAQMB4AEHAeABBwHgAQcB4AEHCw==
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
68
qtcnet-client/Forms/JackpotSpinForm.Designer.cs
generated
Normal file
68
qtcnet-client/Forms/JackpotSpinForm.Designer.cs
generated
Normal file
@ -0,0 +1,68 @@
|
||||
namespace qtcnet_client.Forms
|
||||
{
|
||||
partial class JackpotSpinForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
lblSpinAnim = new Label();
|
||||
SuspendLayout();
|
||||
//
|
||||
// lblSpinAnim
|
||||
//
|
||||
lblSpinAnim.Dock = DockStyle.Fill;
|
||||
lblSpinAnim.Font = new Font("Segoe UI", 15F, FontStyle.Bold);
|
||||
lblSpinAnim.ForeColor = Color.White;
|
||||
lblSpinAnim.Location = new Point(0, 0);
|
||||
lblSpinAnim.Name = "lblSpinAnim";
|
||||
lblSpinAnim.Size = new Size(150, 52);
|
||||
lblSpinAnim.TabIndex = 0;
|
||||
lblSpinAnim.Text = "9999 Q's Won";
|
||||
lblSpinAnim.TextAlign = ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// JackpotSpinForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
BackColor = Color.DodgerBlue;
|
||||
ClientSize = new Size(150, 52);
|
||||
Controls.Add(lblSpinAnim);
|
||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
MaximizeBox = false;
|
||||
MinimizeBox = false;
|
||||
Name = "JackpotSpinForm";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "Jackpot Spin";
|
||||
FormClosed += JackpotSpinForm_FormClosed;
|
||||
Load += JackpotSpinForm_Load;
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Label lblSpinAnim;
|
||||
}
|
||||
}
|
||||
83
qtcnet-client/Forms/JackpotSpinForm.cs
Normal file
83
qtcnet-client/Forms/JackpotSpinForm.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Forms
|
||||
{
|
||||
public partial class JackpotSpinForm : Form
|
||||
{
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public int CurrencyWon { get; set; } = 0;
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public double AnimationLengthMilliseconds { get; set; } = 1500;
|
||||
|
||||
private readonly System.Windows.Forms.Timer _animationTimer;
|
||||
private readonly System.Windows.Forms.Timer _stopTimer;
|
||||
private readonly Random _rndInt = new();
|
||||
private bool _allowClose = true;
|
||||
|
||||
public JackpotSpinForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
FormClosing += JackpotSpinForm_FormClosing;
|
||||
|
||||
_animationTimer = new()
|
||||
{
|
||||
Interval = 20
|
||||
};
|
||||
_animationTimer.Tick += AnimationTimer_Tick;
|
||||
|
||||
_stopTimer = new();
|
||||
_stopTimer.Tick += StopTimer_Tick;
|
||||
}
|
||||
|
||||
private void JackpotSpinForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
ExecuteAnimation();
|
||||
}
|
||||
|
||||
private void JackpotSpinForm_FormClosing(object? sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (!_allowClose)
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
||||
private void JackpotSpinForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
private void ExecuteAnimation()
|
||||
{
|
||||
DoubleBuffered = true;
|
||||
_allowClose = false;
|
||||
|
||||
// Start spinning numbers
|
||||
_animationTimer.Start();
|
||||
|
||||
// Schedule stop
|
||||
_stopTimer.Interval = (int)AnimationLengthMilliseconds;
|
||||
_stopTimer.Start();
|
||||
}
|
||||
|
||||
private void AnimationTimer_Tick(object? sender, EventArgs e)
|
||||
{
|
||||
if (!IsHandleCreated && IsDisposed)
|
||||
return;
|
||||
|
||||
lblSpinAnim.Text = $"{_rndInt.Next(999)} Q's Won";
|
||||
}
|
||||
|
||||
private void StopTimer_Tick(object? sender, EventArgs e)
|
||||
{
|
||||
_stopTimer.Stop();
|
||||
_animationTimer.Stop();
|
||||
|
||||
// Show final result
|
||||
lblSpinAnim.Text = $"{CurrencyWon} Q's Won";
|
||||
|
||||
_allowClose = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Forms/JackpotSpinForm.resx
Normal file
120
qtcnet-client/Forms/JackpotSpinForm.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
52
qtcnet-client/Forms/MainForm.Designer.cs
generated
Normal file
52
qtcnet-client/Forms/MainForm.Designer.cs
generated
Normal file
@ -0,0 +1,52 @@
|
||||
namespace qtcnet_client
|
||||
{
|
||||
partial class MainForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
SuspendLayout();
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(403, 672);
|
||||
DoubleBuffered = true;
|
||||
FormBorderStyle = FormBorderStyle.FixedSingle;
|
||||
MaximizeBox = false;
|
||||
Name = "MainForm";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "QtC.NET";
|
||||
Load += MainForm_Load;
|
||||
Paint += MainForm_Paint;
|
||||
Resize += MainForm_Resize;
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
586
qtcnet-client/Forms/MainForm.cs
Normal file
586
qtcnet-client/Forms/MainForm.cs
Normal file
@ -0,0 +1,586 @@
|
||||
using Krypton.Toolkit;
|
||||
using qtcnet_client.Controls;
|
||||
using qtcnet_client.Forms;
|
||||
using qtcnet_client.Model;
|
||||
using QtCNETAPI.Dtos.User;
|
||||
using QtCNETAPI.Models;
|
||||
using QtCNETAPI.Services;
|
||||
using QtCNETAPI.Services.ApiService;
|
||||
using QtCNETAPI.Services.GatewayService;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace qtcnet_client
|
||||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
private BrandingControl? BrandingControl;
|
||||
private LoginControl? LoginControl;
|
||||
private RegisterControl? RegisterControl;
|
||||
private CurrentProfileControl? CurrentProfileControl;
|
||||
private MainTabControl? MainTabControl;
|
||||
|
||||
private readonly List<ChatRoomForm> OpenChatRoomForms = [];
|
||||
private readonly List<ProfileForm> OpenProfileForms = [];
|
||||
|
||||
private Size LoggedOutSize = new(615, 702);
|
||||
private Size LoggedInSize = new(419, 715);
|
||||
|
||||
private readonly IApiService _apiService;
|
||||
private readonly IGatewayService _gatewayService;
|
||||
private readonly LoggingService _loggingService;
|
||||
private readonly CredentialService _credentialService;
|
||||
private readonly ClientConfig _config;
|
||||
|
||||
public MainForm(IApiService apiService, IGatewayService gatewayService, LoggingService loggingService, CredentialService credentialService, ClientConfig config)
|
||||
{
|
||||
_apiService = apiService;
|
||||
_gatewayService = gatewayService;
|
||||
_loggingService = loggingService;
|
||||
_credentialService = credentialService;
|
||||
_config = config;
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MainForm_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
Rectangle _formRect = ClientRectangle;
|
||||
|
||||
if (_formRect.IsEmpty)
|
||||
_formRect = e.ClipRectangle;
|
||||
|
||||
// draw gradient background
|
||||
using LinearGradientBrush b = new(_formRect, Color.White, Color.DodgerBlue, LinearGradientMode.Vertical);
|
||||
g.FillRectangle(b, _formRect);
|
||||
}
|
||||
|
||||
private void MainForm_Resize(object sender, EventArgs e) => Invalidate();
|
||||
|
||||
private async void MainForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
SuspendLayout();
|
||||
Size = LoggedOutSize;
|
||||
|
||||
// add branding control
|
||||
BrandingControl = new()
|
||||
{
|
||||
Location = new(-2, -17),
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left
|
||||
};
|
||||
|
||||
// add login control
|
||||
LoginControl = new()
|
||||
{
|
||||
Location = new(12, 233)
|
||||
};
|
||||
LoginControl.OnSuccessfulLogin += LoginControl_OnSuccessfulLogin;
|
||||
LoginControl.OnRegisterPressed += LoginControl_OnRegisterPressed;
|
||||
|
||||
Controls.Add(BrandingControl);
|
||||
Controls.Add(LoginControl);
|
||||
|
||||
ResumeLayout(true);
|
||||
|
||||
// ensure api is reachable before letting the user login
|
||||
LoginControl.ToggleControls(false);
|
||||
var _pingRes = await Task.Run(PingAPI);
|
||||
if (_pingRes)
|
||||
{
|
||||
// check for existing login in credential service
|
||||
var _token = _credentialService.GetAccessToken();
|
||||
if (_token != null)
|
||||
{
|
||||
// try it
|
||||
var _refreshRes = await _apiService.RefreshLogin(_token);
|
||||
if (_refreshRes.Success)
|
||||
OnSuccessfulLoginRefresh();
|
||||
}
|
||||
else
|
||||
LoginControl.ToggleControls(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
KryptonMessageBox.Show("The Server Is Unreachable. Ensure Your Config Is Correct. The Client Will Now Close", "Oops");
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoginControl_OnRegisterPressed(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is LoginControl _)
|
||||
{
|
||||
// pause ui
|
||||
SuspendLayout();
|
||||
|
||||
// remove and dispose login control
|
||||
Controls.Remove(LoginControl);
|
||||
LoginControl?.Dispose();
|
||||
LoginControl = null;
|
||||
|
||||
// create register control
|
||||
RegisterControl = new()
|
||||
{
|
||||
Location = new(1, 233)
|
||||
};
|
||||
RegisterControl.OnReshowLoginPressed += RegisterControl_OnReshowLoginPressed;
|
||||
RegisterControl.OnRegister += RegisterControl_OnRegister;
|
||||
|
||||
Controls.Add(RegisterControl);
|
||||
|
||||
ResumeLayout(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterControl_OnReshowLoginPressed(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is RegisterControl _)
|
||||
{
|
||||
// pause ui
|
||||
SuspendLayout();
|
||||
|
||||
// remove and dispose register control
|
||||
Controls.Remove(RegisterControl);
|
||||
RegisterControl?.Dispose();
|
||||
RegisterControl = null;
|
||||
|
||||
// add login control
|
||||
LoginControl = new()
|
||||
{
|
||||
Location = new(12, 233)
|
||||
};
|
||||
LoginControl.OnSuccessfulLogin += LoginControl_OnSuccessfulLogin;
|
||||
LoginControl.OnRegisterPressed += LoginControl_OnRegisterPressed;
|
||||
|
||||
Controls.Add(LoginControl);
|
||||
|
||||
ResumeLayout(true);
|
||||
}
|
||||
}
|
||||
|
||||
private async void RegisterControl_OnRegister(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is RegisterControl _senderCtrl)
|
||||
{
|
||||
// attempt registration
|
||||
var res = await _apiService.RegisterAsync(new()
|
||||
{
|
||||
Username = _senderCtrl.Username,
|
||||
Email = _senderCtrl.Email,
|
||||
Password = _senderCtrl.Password,
|
||||
DateOfBirth = _senderCtrl.DateOfBirth,
|
||||
});
|
||||
|
||||
|
||||
if (res.Success && res.Data != null)
|
||||
{
|
||||
KryptonMessageBox.Show("Registration Success!\n\nNote: Some Servers Require Email Verification, Check Your Email!\n\nYou May Now Login.", "Success!");
|
||||
|
||||
// pause ui
|
||||
SuspendLayout();
|
||||
|
||||
// remove and dispose register control
|
||||
Controls.Remove(RegisterControl);
|
||||
RegisterControl?.Dispose();
|
||||
RegisterControl = null;
|
||||
|
||||
// add login control
|
||||
LoginControl = new()
|
||||
{
|
||||
Location = new(12, 233)
|
||||
};
|
||||
LoginControl.OnSuccessfulLogin += LoginControl_OnSuccessfulLogin;
|
||||
LoginControl.OnRegisterPressed += LoginControl_OnRegisterPressed;
|
||||
|
||||
Controls.Add(LoginControl);
|
||||
|
||||
ResumeLayout(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
KryptonMessageBox.Show($"Sorry, Something Went Wrong Registering You. Please Try Again Later.\n\nServer Response = {res.Message}", "Uh Oh.",
|
||||
KryptonMessageBoxButtons.OK,
|
||||
KryptonMessageBoxIcon.Error);
|
||||
_senderCtrl.ToggleControls(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void LoginControl_OnSuccessfulLogin(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is LoginControl _senderCtrl)
|
||||
{
|
||||
// login using function
|
||||
var _loginRes = await OnSuccessfulLogin(new() { Email = _senderCtrl.Email, Password = _senderCtrl.Password, RememberMe = _senderCtrl.RememberMe });
|
||||
if(_loginRes)
|
||||
{
|
||||
// pause ui
|
||||
SuspendLayout();
|
||||
|
||||
// remove and dispose login and branding controls
|
||||
Controls.Remove(LoginControl);
|
||||
Controls.Remove(BrandingControl);
|
||||
|
||||
LoginControl?.Dispose();
|
||||
LoginControl = null;
|
||||
BrandingControl?.Dispose();
|
||||
BrandingControl = null;
|
||||
|
||||
// set size to logged in size
|
||||
Size = LoggedInSize;
|
||||
|
||||
// start gateway connection
|
||||
var _gwRes = await SetupGatewayConnection();
|
||||
|
||||
if(_gwRes)
|
||||
{
|
||||
// setup current profile control based on current user
|
||||
CurrentProfileControl = new()
|
||||
{
|
||||
Username = _apiService.CurrentUser!.Username,
|
||||
CurrencyCount = _apiService.CurrentUser.CurrencyAmount,
|
||||
Location = new(12, 12),
|
||||
};
|
||||
|
||||
// get profile image for the current user
|
||||
var _currentProfileImageRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id);
|
||||
if (_currentProfileImageRes.Success && _currentProfileImageRes.Data != null)
|
||||
{
|
||||
using MemoryStream ms = new(_currentProfileImageRes.Data);
|
||||
Image img = Image.FromStream(ms);
|
||||
CurrentProfileControl.ProfileImage = img;
|
||||
}
|
||||
|
||||
// setup main tab control
|
||||
MainTabControl = new()
|
||||
{
|
||||
Location = new(12, 91)
|
||||
};
|
||||
|
||||
// add controls to current form
|
||||
Controls.Add(CurrentProfileControl);
|
||||
Controls.Add(MainTabControl);
|
||||
|
||||
// get and set contacts
|
||||
var _currentUserContacts = await _apiService.GetCurrentUserContacts();
|
||||
if (_currentUserContacts.Success && _currentUserContacts.Data != null)
|
||||
await SetupContactsUI(_currentUserContacts.Data);
|
||||
|
||||
// get and set user directory
|
||||
var _currentUserDirectory = await _apiService.GetAllUsersAsync();
|
||||
if (_currentUserDirectory.Success && _currentUserDirectory.Data != null)
|
||||
await SetupDirectoryUI(_currentUserDirectory.Data);
|
||||
|
||||
ResumeLayout(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeLayout(true);
|
||||
KryptonMessageBox.Show("An Error Occured Trying To Connect To The Gateway. Please Try Again Later.", "Uh Oh.", KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Error);
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MainTabControl_OnRoomControlDoubleClicked(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is RoomControl _)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void Chat_OnSend(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is ChatRoomForm _)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void Chat_OnClose(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is ChatRoomForm chatRoom)
|
||||
{
|
||||
OpenChatRoomForms.Remove(chatRoom);
|
||||
chatRoom.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void MainTabControl_OnContactControlDoubleClicked(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is ContactControl _)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfileForm_OnClose(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender is ProfileForm profile)
|
||||
{
|
||||
OpenProfileForms.Remove(profile);
|
||||
profile.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void _apiService_OnCurrentUserUpdate(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private async Task<bool> PingAPI()
|
||||
{
|
||||
// ping it
|
||||
var res = await _apiService.PingServerAsync();
|
||||
|
||||
// return result
|
||||
return res.Success;
|
||||
}
|
||||
|
||||
private async Task<bool> SetupGatewayConnection()
|
||||
{
|
||||
// subscribe to gateway events
|
||||
//_gatewayService.OnServerReconnecting += _gatewayService_OnServerReconnecting;
|
||||
//_gatewayService.OnServerReconnected += _gatewayService_OnServerReconnected;
|
||||
//_gatewayService.OnServerDisconnect += _gatewayService_OnServerDisconnect;
|
||||
//_gatewayService.OnDirectMessageReceived += _gatewayService_OnDirectMessageReceived;
|
||||
//_gatewayService.OnRefreshUserListsReceived += _gatewayService_OnRefreshUserListReceived;
|
||||
//_gatewayService.OnRefreshRoomListReceived += _gatewayService_OnRefreshRoomListReceived;
|
||||
//_gatewayService.OnRefreshContactsListReceived += _gatewayService_OnRefreshContactsListReceived;
|
||||
//_gatewayService.OnServerConfigReceived += _gatewayService_OnServerConfigReceived;
|
||||
//_gatewayService.OnUserForceLogout += _gatewayService_OnUserForceLogout;
|
||||
|
||||
// start connection
|
||||
await _gatewayService.StartAsync();
|
||||
return _gatewayService.HubConnection != null && _gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected;
|
||||
}
|
||||
|
||||
private void _gatewayService_OnUserForceLogout(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void _gatewayService_OnServerConfigReceived(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void _gatewayService_OnRefreshContactsListReceived(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void _gatewayService_OnRefreshRoomListReceived(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void _gatewayService_OnRefreshUserListReceived(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void _gatewayService_OnServerDisconnect(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void _gatewayService_OnServerReconnected(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void _gatewayService_OnServerReconnecting(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void _gatewayService_OnDirectMessageReceived(object? sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private async Task SetupContactsUI(List<Contact> data)
|
||||
{
|
||||
// build ctrl list
|
||||
List<ContactControl> _contactCtrls = [];
|
||||
foreach (var contact in data)
|
||||
{
|
||||
var ctrl = await BuildContactControl(contact);
|
||||
if (ctrl != null)
|
||||
_contactCtrls.Add(ctrl);
|
||||
}
|
||||
|
||||
// add to control
|
||||
MainTabControl?.AddContacts(_contactCtrls);
|
||||
}
|
||||
|
||||
private async Task SetupDirectoryUI(List<UserInformationDto> data)
|
||||
{
|
||||
// build listviewitem list
|
||||
List<ListViewItem> _userViews = [];
|
||||
foreach(var user in data)
|
||||
{
|
||||
ListViewItem lvi = new()
|
||||
{
|
||||
Tag = user.Id,
|
||||
Text = user.Username,
|
||||
ImageIndex = user.Status,
|
||||
};
|
||||
_userViews.Add(lvi);
|
||||
}
|
||||
|
||||
// add to control
|
||||
MainTabControl?.AddUsers(_userViews);
|
||||
}
|
||||
|
||||
private async Task<ContactControl?> BuildContactControl(Contact contact)
|
||||
{
|
||||
if(_apiService.CurrentUser != null)
|
||||
{
|
||||
ServiceResponse<UserInformationDto> 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)
|
||||
{
|
||||
var ctrl = new ContactControl
|
||||
{
|
||||
Username = user.Data.Username,
|
||||
TextStatus = "NOT IMPLEMENTED",
|
||||
Status = user.Data.Status,
|
||||
};
|
||||
|
||||
if (contact.OwnerId == _apiService.CurrentUser.Id)
|
||||
{
|
||||
switch (contact.OwnerStatus)
|
||||
{
|
||||
case Contact.ContactStatus.AwaitingApprovalFromOther:
|
||||
ctrl.Username = $"{user.Data.Username} [Request Sent]";
|
||||
//await AddProfilePicToList(user.Data.Id);
|
||||
//ctrl.Avatar = ilProfilePics.Images[user.Data.Id] ?? ilProfilePics.Images[0];
|
||||
break;
|
||||
case Contact.ContactStatus.Accepted:
|
||||
ctrl.Username = user.Data.Username;
|
||||
//await AddProfilePicToList(user.Data.Id);
|
||||
//ctrl.Avatar = ilProfilePics.Images[user.Data.Id] ?? ilProfilePics.Images[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (contact.UserId == _apiService.CurrentUser.Id)
|
||||
{
|
||||
switch (contact.UserStatus)
|
||||
{
|
||||
case Contact.ContactStatus.AwaitingApprovalFromSelf:
|
||||
ctrl.Username = $"{user.Data.Username} [Contact Request]";
|
||||
//await AddProfilePicToList(user.Data.Id);
|
||||
//ctrl.Avatar = ilProfilePics.Images[user.Data.Id] ?? ilProfilePics.Images[0];
|
||||
//AudioService.PlaySoundEffect("sndContactRequest");
|
||||
break;
|
||||
case Contact.ContactStatus.Accepted:
|
||||
ctrl.Username = user.Data.Username;
|
||||
//await AddProfilePicToList(user.Data.Id);
|
||||
//ctrl.Avatar = ilProfilePics.Images[user.Data.Id] ?? ilProfilePics.Images[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// return the control
|
||||
return ctrl;
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private async Task<bool> OnSuccessfulLogin(UserLoginDto dto)
|
||||
{
|
||||
// attempt login
|
||||
var res = await _apiService.LoginAsync(dto);
|
||||
|
||||
if (res.Success && res.Data != null && _apiService.CurrentUser != null) // "CurrentUser" should not be null on successful login but checking anyways
|
||||
{
|
||||
// store refresh token in credential store
|
||||
_credentialService.SaveAccessToken(_apiService.CurrentUser.Username, res.Message);
|
||||
|
||||
// sub to currentuser updates
|
||||
_apiService.OnCurrentUserUpdate += _apiService_OnCurrentUserUpdate;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
KryptonMessageBox.Show(res.Message, "Login Error", KryptonMessageBoxButtons.OK, KryptonMessageBoxIcon.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnSuccessfulLoginRefresh()
|
||||
{
|
||||
if (_apiService.CurrentUser != null)
|
||||
{
|
||||
// remove and dispose login and branding controls
|
||||
Controls.Remove(LoginControl);
|
||||
Controls.Remove(BrandingControl);
|
||||
|
||||
LoginControl?.Dispose();
|
||||
LoginControl = null;
|
||||
BrandingControl?.Dispose();
|
||||
BrandingControl = null;
|
||||
|
||||
// set size to logged in size
|
||||
Size = LoggedInSize;
|
||||
|
||||
// start gateway connection
|
||||
var _gwRes = await SetupGatewayConnection();
|
||||
|
||||
if (_gwRes)
|
||||
{
|
||||
// setup current profile control based on current user
|
||||
CurrentProfileControl = new()
|
||||
{
|
||||
Username = _apiService.CurrentUser!.Username,
|
||||
CurrencyCount = _apiService.CurrentUser.CurrencyAmount,
|
||||
Location = new(12, 12),
|
||||
};
|
||||
|
||||
// get profile image for the current user
|
||||
var _currentProfileImageRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id);
|
||||
if (_currentProfileImageRes.Success && _currentProfileImageRes.Data != null)
|
||||
{
|
||||
using MemoryStream ms = new(_currentProfileImageRes.Data);
|
||||
Image img = Image.FromStream(ms);
|
||||
CurrentProfileControl.ProfileImage = img;
|
||||
}
|
||||
|
||||
// setup main tab control
|
||||
MainTabControl = new()
|
||||
{
|
||||
Location = new(12, 91)
|
||||
};
|
||||
|
||||
// add controls to current form
|
||||
Controls.Add(CurrentProfileControl);
|
||||
Controls.Add(MainTabControl);
|
||||
|
||||
// get and set contacts
|
||||
var _currentUserContacts = await _apiService.GetCurrentUserContacts();
|
||||
if (_currentUserContacts.Success && _currentUserContacts.Data != null)
|
||||
await SetupContactsUI(_currentUserContacts.Data);
|
||||
|
||||
// get and set user directory
|
||||
var _currentUserDirectory = await _apiService.GetAllUsersAsync();
|
||||
if (_currentUserDirectory.Success && _currentUserDirectory.Data != null)
|
||||
await SetupDirectoryUI(_currentUserDirectory.Data);
|
||||
|
||||
ResumeLayout(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Forms/MainForm.resx
Normal file
120
qtcnet-client/Forms/MainForm.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
166
qtcnet-client/Forms/ProfileForm.Designer.cs
generated
Normal file
166
qtcnet-client/Forms/ProfileForm.Designer.cs
generated
Normal file
@ -0,0 +1,166 @@
|
||||
namespace qtcnet_client.Forms
|
||||
{
|
||||
partial class ProfileForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
pbProfileImage = new PictureBox();
|
||||
lblStatus = new Label();
|
||||
rtxtBio = new RichTextBox();
|
||||
tlpActionButtons = new TableLayoutPanel();
|
||||
tlpUsernameTags = new TableLayoutPanel();
|
||||
lblUsername = new Label();
|
||||
tlpTagIcons = new TableLayoutPanel();
|
||||
((System.ComponentModel.ISupportInitialize)pbProfileImage).BeginInit();
|
||||
tlpUsernameTags.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// pbProfileImage
|
||||
//
|
||||
pbProfileImage.Image = Properties.Resources.DefaultPfp;
|
||||
pbProfileImage.Location = new Point(12, 12);
|
||||
pbProfileImage.Name = "pbProfileImage";
|
||||
pbProfileImage.Size = new Size(97, 99);
|
||||
pbProfileImage.SizeMode = PictureBoxSizeMode.Zoom;
|
||||
pbProfileImage.TabIndex = 0;
|
||||
pbProfileImage.TabStop = false;
|
||||
//
|
||||
// lblStatus
|
||||
//
|
||||
lblStatus.AutoEllipsis = true;
|
||||
lblStatus.Font = new Font("Segoe UI Semibold", 9F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||
lblStatus.ForeColor = Color.White;
|
||||
lblStatus.Location = new Point(12, 114);
|
||||
lblStatus.Name = "lblStatus";
|
||||
lblStatus.Padding = new Padding(0, 0, 0, 15);
|
||||
lblStatus.Size = new Size(97, 54);
|
||||
lblStatus.TabIndex = 2;
|
||||
lblStatus.Text = "Status";
|
||||
lblStatus.TextAlign = ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// rtxtBio
|
||||
//
|
||||
rtxtBio.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
rtxtBio.Location = new Point(115, 69);
|
||||
rtxtBio.Name = "rtxtBio";
|
||||
rtxtBio.ReadOnly = true;
|
||||
rtxtBio.Size = new Size(302, 340);
|
||||
rtxtBio.TabIndex = 4;
|
||||
rtxtBio.Text = "";
|
||||
//
|
||||
// tlpActionButtons
|
||||
//
|
||||
tlpActionButtons.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
tlpActionButtons.ColumnCount = 2;
|
||||
tlpActionButtons.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tlpActionButtons.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tlpActionButtons.Location = new Point(296, 415);
|
||||
tlpActionButtons.Name = "tlpActionButtons";
|
||||
tlpActionButtons.RowCount = 1;
|
||||
tlpActionButtons.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
|
||||
tlpActionButtons.Size = new Size(121, 42);
|
||||
tlpActionButtons.TabIndex = 5;
|
||||
//
|
||||
// tlpUsernameTags
|
||||
//
|
||||
tlpUsernameTags.AutoSize = true;
|
||||
tlpUsernameTags.ColumnCount = 2;
|
||||
tlpUsernameTags.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tlpUsernameTags.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tlpUsernameTags.Controls.Add(lblUsername, 0, 0);
|
||||
tlpUsernameTags.Controls.Add(tlpTagIcons, 1, 0);
|
||||
tlpUsernameTags.Location = new Point(115, 11);
|
||||
tlpUsernameTags.Name = "tlpUsernameTags";
|
||||
tlpUsernameTags.RowCount = 1;
|
||||
tlpUsernameTags.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
|
||||
tlpUsernameTags.Size = new Size(304, 55);
|
||||
tlpUsernameTags.TabIndex = 6;
|
||||
//
|
||||
// lblUsername
|
||||
//
|
||||
lblUsername.AutoSize = true;
|
||||
lblUsername.Dock = DockStyle.Left;
|
||||
lblUsername.Font = new Font("Segoe UI", 20F, FontStyle.Bold);
|
||||
lblUsername.ForeColor = Color.White;
|
||||
lblUsername.Location = new Point(3, 0);
|
||||
lblUsername.Name = "lblUsername";
|
||||
lblUsername.Size = new Size(146, 55);
|
||||
lblUsername.TabIndex = 0;
|
||||
lblUsername.Text = "Username";
|
||||
lblUsername.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// tlpTagIcons
|
||||
//
|
||||
tlpTagIcons.AutoSize = true;
|
||||
tlpTagIcons.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||
tlpTagIcons.ColumnCount = 1;
|
||||
tlpTagIcons.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tlpTagIcons.GrowStyle = TableLayoutPanelGrowStyle.AddColumns;
|
||||
tlpTagIcons.Location = new Point(155, 3);
|
||||
tlpTagIcons.MinimumSize = new Size(145, 49);
|
||||
tlpTagIcons.Name = "tlpTagIcons";
|
||||
tlpTagIcons.RowCount = 1;
|
||||
tlpTagIcons.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
|
||||
tlpTagIcons.Size = new Size(145, 49);
|
||||
tlpTagIcons.TabIndex = 1;
|
||||
//
|
||||
// ProfileForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
AutoSize = true;
|
||||
BackColor = Color.DodgerBlue;
|
||||
ClientSize = new Size(429, 463);
|
||||
Controls.Add(tlpUsernameTags);
|
||||
Controls.Add(tlpActionButtons);
|
||||
Controls.Add(rtxtBio);
|
||||
Controls.Add(lblStatus);
|
||||
Controls.Add(pbProfileImage);
|
||||
MaximizeBox = false;
|
||||
Name = "ProfileForm";
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "QtC.NET User Profile";
|
||||
FormClosed += ProfileForm_FormClosed;
|
||||
Load += ProfileForm_Load;
|
||||
((System.ComponentModel.ISupportInitialize)pbProfileImage).EndInit();
|
||||
tlpUsernameTags.ResumeLayout(false);
|
||||
tlpUsernameTags.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private PictureBox pbProfileImage;
|
||||
private Label lblStatus;
|
||||
private RichTextBox rtxtBio;
|
||||
private TableLayoutPanel tlpActionButtons;
|
||||
private TableLayoutPanel tlpUsernameTags;
|
||||
private Label lblUsername;
|
||||
private TableLayoutPanel tlpTagIcons;
|
||||
}
|
||||
}
|
||||
52
qtcnet-client/Forms/ProfileForm.cs
Normal file
52
qtcnet-client/Forms/ProfileForm.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using qtcnet_client.Properties;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace qtcnet_client.Forms
|
||||
{
|
||||
public partial class ProfileForm : Form
|
||||
{
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string Username { get; set; } = "Username";
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string Bio { get; set; } = string.Empty;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public int Status { get; set; } = 0;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string TextStatus { get; set; } = string.Empty;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public string[] Tags { get; set; } = [];
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public int ContactStatus { get; set; } = 0;
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
||||
public Image ProfileImage { get; set; } = Resources.DefaultPfp;
|
||||
|
||||
public event EventHandler? OnClose;
|
||||
public ProfileForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ProfileForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
Text = $"QtC.NET User Profile - {Username}";
|
||||
lblUsername.Text = Username;
|
||||
lblStatus.Text = TextStatus;
|
||||
rtxtBio.Text = Bio;
|
||||
pbProfileImage.Image = ProfileImage;
|
||||
|
||||
if (Status == 0) lblStatus.Visible = false;
|
||||
}
|
||||
|
||||
private void ProfileForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
OnClose?.Invoke(this, EventArgs.Empty);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
qtcnet-client/Forms/ProfileForm.resx
Normal file
120
qtcnet-client/Forms/ProfileForm.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
19
qtcnet-client/Model/ClientConfig.cs
Normal file
19
qtcnet-client/Model/ClientConfig.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace qtcnet_client.Model
|
||||
{
|
||||
public class ClientConfig
|
||||
{
|
||||
[JsonPropertyName("serverUri")]
|
||||
public string ServerBaseUri { get; set; } = "https://api.qtchat.net";
|
||||
[JsonPropertyName("startMinimized")]
|
||||
public bool StartMinimized { get; set; } = false;
|
||||
[JsonPropertyName("minimizeToTray")]
|
||||
public bool MinimizeToTray { get; set; } = false;
|
||||
[JsonPropertyName("enableDebugLogs")]
|
||||
public bool EnableDebugLogs { get; set; } = false;
|
||||
}
|
||||
}
|
||||
98
qtcnet-client/Program.cs
Normal file
98
qtcnet-client/Program.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using Krypton.Toolkit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using qtcnet_client.Model;
|
||||
using QtCNETAPI.Services;
|
||||
using QtCNETAPI.Services.ApiService;
|
||||
using QtCNETAPI.Services.GatewayService;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace qtcnet_client
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
// To customize application configuration such as set high DPI settings or default font,
|
||||
// see https://aka.ms/applicationconfiguration.
|
||||
ApplicationConfiguration.Initialize();
|
||||
|
||||
var host = CreateHostBuilder().Build();
|
||||
ServiceProvider = host.Services;
|
||||
|
||||
Application.Run(ServiceProvider.GetRequiredService<MainForm>());
|
||||
}
|
||||
|
||||
private static JsonSerializerOptions JsonSerializerOptions { get; } = new() { WriteIndented = true };
|
||||
public static IServiceProvider? ServiceProvider { get; private set; }
|
||||
static IHostBuilder CreateHostBuilder()
|
||||
{
|
||||
return Host.CreateDefaultBuilder()
|
||||
.ConfigureServices((context, service) =>
|
||||
{
|
||||
service.AddTransient<MainForm>();
|
||||
service.AddSingleton<LoggingService>();
|
||||
service.AddSingleton<CredentialService>();
|
||||
service.AddSingleton(provider => GetOrCreateClientConfig());
|
||||
service.AddSingleton<IApiService>(provider => new ApiService(provider.GetService<ClientConfig>()!.ServerBaseUri + "/api", provider.GetService<LoggingService>()!, provider.GetService<CredentialService>()!));
|
||||
service.AddSingleton<IGatewayService>(provider => new GatewayService(provider.GetService<ClientConfig>()!.ServerBaseUri + "/chat", provider.GetService<IApiService>()!, provider.GetService<LoggingService>()!));
|
||||
});
|
||||
}
|
||||
|
||||
static ClientConfig GetOrCreateClientConfig()
|
||||
{
|
||||
var _configPath = $"{Application.StartupPath}/config.json";
|
||||
try
|
||||
{
|
||||
if (!File.Exists(_configPath))
|
||||
{
|
||||
var _defaultConfig = new ClientConfig();
|
||||
|
||||
// create the config using the default config model
|
||||
string serializedModel = JsonSerializer.Serialize(_defaultConfig, JsonSerializerOptions);
|
||||
|
||||
// write it to a new file
|
||||
File.WriteAllText(_configPath, serializedModel);
|
||||
|
||||
// return it
|
||||
return _defaultConfig;
|
||||
}
|
||||
else
|
||||
{
|
||||
// deserialize the contents of config.json and return it
|
||||
ClientConfig? _deserializedConfig = JsonSerializer.Deserialize<ClientConfig>(File.ReadAllText(_configPath));
|
||||
if (_deserializedConfig != null)
|
||||
return _deserializedConfig;
|
||||
}
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
}
|
||||
|
||||
// if the functions gets here, inform the user their config is incorrect and create a new one if allowed
|
||||
var _diagResult = KryptonMessageBox.Show($"Your Config Is Incorrect. Would You Like To Create A New One?", "Uh Oh.", KryptonMessageBoxButtons.YesNo);
|
||||
if (_diagResult == DialogResult.Yes)
|
||||
{
|
||||
var _defaultConfig = new ClientConfig();
|
||||
|
||||
// create the config using the default config model
|
||||
string serializedModel = JsonSerializer.Serialize(_defaultConfig, JsonSerializerOptions);
|
||||
|
||||
// write it to a new file
|
||||
File.WriteAllText(_configPath, serializedModel);
|
||||
|
||||
// return it
|
||||
return _defaultConfig;
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.Exit();
|
||||
return default!; // application should exit before it can return this lol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
qtcnet-client/Properties/Resources.Designer.cs
generated
Normal file
113
qtcnet-client/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,113 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 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.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace qtcnet_client.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// 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", "18.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() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[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("qtcnet_client.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap CurrencyIcon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("CurrencyIcon", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap DefaultPfp {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("DefaultPfp", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap QtCNETIcon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("QtCNETIcon", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap RoomsChatIcon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("RoomsChatIcon", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap SendIcon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("SendIcon", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
136
qtcnet-client/Properties/Resources.resx
Normal file
136
qtcnet-client/Properties/Resources.resx
Normal file
@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="DefaultPfp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\DefaultPfp.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="QtCNETIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\QtCNETIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="CurrencyIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\CurrencyIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="RoomsChatIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\RoomsChatIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="SendIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\SendIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
BIN
qtcnet-client/Resources/CurrencyIcon.png
Normal file
BIN
qtcnet-client/Resources/CurrencyIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 649 B |
BIN
qtcnet-client/Resources/DefaultPfp.jpg
Normal file
BIN
qtcnet-client/Resources/DefaultPfp.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
qtcnet-client/Resources/QtCNETIcon.png
Normal file
BIN
qtcnet-client/Resources/QtCNETIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
qtcnet-client/Resources/RoomsChatIcon.png
Normal file
BIN
qtcnet-client/Resources/RoomsChatIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
qtcnet-client/Resources/SendIcon.png
Normal file
BIN
qtcnet-client/Resources/SendIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
37
qtcnet-client/qtcnet-client.csproj
Normal file
37
qtcnet-client/qtcnet-client.csproj
Normal file
@ -0,0 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net10.0-windows</TargetFramework>
|
||||
<RootNamespace>qtcnet_client</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Krypton.Toolkit" Version="100.25.11.328" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\QtCNETAPI\QtCNETAPI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Loading…
x
Reference in New Issue
Block a user