Fix User Status Being Lagged Behind The Server (requires server update)

This commit is contained in:
Alan Moon 2025-12-11 16:04:17 -08:00
parent 3f75aab27d
commit 2bfbf7b204
9 changed files with 168 additions and 50 deletions

View File

@ -0,0 +1,14 @@
using QtCNETAPI.Dtos.User;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QtCNETAPI.Events
{
public class UserStatusUpdatedEventArgs : EventArgs
{
public UserStatusDto? StatusDto { get; set; }
}
}

View File

@ -159,10 +159,6 @@ namespace QtCNETAPI.Services.ApiService
{ {
serviceResponse.Success = true; serviceResponse.Success = true;
serviceResponse.Data = response.Data; 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 } else
{ {
serviceResponse.Success = false; serviceResponse.Success = false;
@ -188,10 +184,6 @@ namespace QtCNETAPI.Services.ApiService
{ {
serviceResponse.Success = true; serviceResponse.Success = true;
serviceResponse.Data = response.Data; 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 else
{ {
@ -370,6 +362,7 @@ namespace QtCNETAPI.Services.ApiService
_loggingService.LogString($"Current User's Status Is {userResponse.Data.Status}"); _loggingService.LogString($"Current User's Status Is {userResponse.Data.Status}");
OnCurrentUserUpdate?.Invoke(this, EventArgs.Empty);
return userResponse.Data; return userResponse.Data;
} else } else
{ {
@ -680,10 +673,6 @@ namespace QtCNETAPI.Services.ApiService
{ {
serviceResponse.Success = true; serviceResponse.Success = true;
serviceResponse.Data = response.Data; 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; return serviceResponse;
@ -731,10 +720,6 @@ namespace QtCNETAPI.Services.ApiService
{ {
serviceResponse.Success = true; serviceResponse.Success = true;
serviceResponse.Data = response.Data; 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; return serviceResponse;
@ -759,10 +744,6 @@ namespace QtCNETAPI.Services.ApiService
{ {
serviceResponse.Success = true; serviceResponse.Success = true;
serviceResponse.Data = response.Data; 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; return serviceResponse;
@ -882,10 +863,6 @@ namespace QtCNETAPI.Services.ApiService
{ {
serviceResponse.Success = true; serviceResponse.Success = true;
serviceResponse.Data = response.Data; 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; return serviceResponse;

View File

@ -74,6 +74,7 @@ namespace QtCNETAPI.Services.GatewayService
HubConnection.On<string>("GuestJoin", (username) => OnGuestUserJoin?.Invoke(this, new GuestUserJoinEventArgs { Username = username })); HubConnection.On<string>("GuestJoin", (username) => OnGuestUserJoin?.Invoke(this, new GuestUserJoinEventArgs { Username = username }));
HubConnection.On("RoomDeleted", () => OnRoomDeleted?.Invoke(this, EventArgs.Empty)); HubConnection.On("RoomDeleted", () => OnRoomDeleted?.Invoke(this, EventArgs.Empty));
HubConnection.On("ForceSignOut", () => OnUserForceLogout?.Invoke(this, EventArgs.Empty)); HubConnection.On("ForceSignOut", () => OnUserForceLogout?.Invoke(this, EventArgs.Empty));
HubConnection.On("UpdateCurrentUser", async () => await _apiService.SetCurrentUser());
HubConnection.Closed += HubConnection_Closed; HubConnection.Closed += HubConnection_Closed;
HubConnection.Reconnecting += HubConnection_Reconnecting; HubConnection.Reconnecting += HubConnection_Reconnecting;
@ -89,9 +90,6 @@ namespace QtCNETAPI.Services.GatewayService
_loggingService.LogString($"Unable To Connect To SignalR.\n{ex.Message}\n{ex.StackTrace}"); _loggingService.LogString($"Unable To Connect To SignalR.\n{ex.Message}\n{ex.StackTrace}");
return; return;
} }
// ensure current user is up to date (particularly status (its still busted lol))
await _apiService.SetCurrentUser();
} }
public async Task StopAsync() public async Task StopAsync()
@ -172,9 +170,6 @@ namespace QtCNETAPI.Services.GatewayService
if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made."); if (HubConnection == null || HubConnection.State != HubConnectionState.Connected) throw new InvalidOperationException("Function was called before connection was made.");
await HubConnection.SendAsync("UpdateStatus", _apiService.CurrentUser, status); await HubConnection.SendAsync("UpdateStatus", _apiService.CurrentUser, status);
// anything that changes the user should tell the api service to set it again
await _apiService.SetCurrentUser();
} }

View File

@ -28,19 +28,26 @@
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
components = new System.ComponentModel.Container();
pbCurrentProfilePic = new PictureBox(); pbCurrentProfilePic = new PictureBox();
ctxStatus = new ContextMenuStrip(components);
tsiStatusOnline = new ToolStripMenuItem();
tsiStatusAway = new ToolStripMenuItem();
tsiStatusDND = new ToolStripMenuItem();
tsiStatusOffline = new ToolStripMenuItem();
llblSignOut = new LinkLabel(); llblSignOut = new LinkLabel();
llblEditProfile = new LinkLabel(); llblEditProfile = new LinkLabel();
pictureBox1 = new PictureBox(); pictureBox1 = new PictureBox();
lblUsername = new Label(); lblUsername = new Label();
lblCurrencyAmount = new Label(); lblCurrencyAmount = new Label();
((System.ComponentModel.ISupportInitialize)pbCurrentProfilePic).BeginInit(); ((System.ComponentModel.ISupportInitialize)pbCurrentProfilePic).BeginInit();
ctxStatus.SuspendLayout();
((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit(); ((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();
SuspendLayout(); SuspendLayout();
// //
// pbCurrentProfilePic // pbCurrentProfilePic
// //
pbCurrentProfilePic.Cursor = Cursors.Hand; pbCurrentProfilePic.ContextMenuStrip = ctxStatus;
pbCurrentProfilePic.Image = Properties.Resources.DefaultPfp; pbCurrentProfilePic.Image = Properties.Resources.DefaultPfp;
pbCurrentProfilePic.Location = new Point(3, 3); pbCurrentProfilePic.Location = new Point(3, 3);
pbCurrentProfilePic.Name = "pbCurrentProfilePic"; pbCurrentProfilePic.Name = "pbCurrentProfilePic";
@ -49,6 +56,45 @@
pbCurrentProfilePic.TabIndex = 0; pbCurrentProfilePic.TabIndex = 0;
pbCurrentProfilePic.TabStop = false; pbCurrentProfilePic.TabStop = false;
// //
// ctxStatus
//
ctxStatus.Items.AddRange(new ToolStripItem[] { tsiStatusOnline, tsiStatusAway, tsiStatusDND, tsiStatusOffline });
ctxStatus.Name = "ctxStatus";
ctxStatus.Size = new Size(181, 114);
ctxStatus.ItemClicked += ctxStatus_ItemClicked;
//
// tsiStatusOnline
//
tsiStatusOnline.Image = Properties.Resources.OnlineIcon;
tsiStatusOnline.Name = "tsiStatusOnline";
tsiStatusOnline.Size = new Size(180, 22);
tsiStatusOnline.Tag = "Online";
tsiStatusOnline.Text = "Online";
//
// tsiStatusAway
//
tsiStatusAway.Image = Properties.Resources.AwayIcon;
tsiStatusAway.Name = "tsiStatusAway";
tsiStatusAway.Size = new Size(180, 22);
tsiStatusAway.Tag = "Away";
tsiStatusAway.Text = "Away";
//
// tsiStatusDND
//
tsiStatusDND.Image = Properties.Resources.DNDIcon;
tsiStatusDND.Name = "tsiStatusDND";
tsiStatusDND.Size = new Size(180, 22);
tsiStatusDND.Tag = "DoNotDisturb";
tsiStatusDND.Text = "Do Not Disturb";
//
// tsiStatusOffline
//
tsiStatusOffline.Image = Properties.Resources.OfflineIcon;
tsiStatusOffline.Name = "tsiStatusOffline";
tsiStatusOffline.Size = new Size(180, 22);
tsiStatusOffline.Tag = "Invisible";
tsiStatusOffline.Text = "Invisible";
//
// llblSignOut // llblSignOut
// //
llblSignOut.AutoSize = true; llblSignOut.AutoSize = true;
@ -119,6 +165,7 @@
Size = new Size(197, 73); Size = new Size(197, 73);
Load += CurrentProfileControl_Load; Load += CurrentProfileControl_Load;
((System.ComponentModel.ISupportInitialize)pbCurrentProfilePic).EndInit(); ((System.ComponentModel.ISupportInitialize)pbCurrentProfilePic).EndInit();
ctxStatus.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit(); ((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();
ResumeLayout(false); ResumeLayout(false);
PerformLayout(); PerformLayout();
@ -132,5 +179,10 @@
private PictureBox pictureBox1; private PictureBox pictureBox1;
private Label lblUsername; private Label lblUsername;
private Label lblCurrencyAmount; private Label lblCurrencyAmount;
private ContextMenuStrip ctxStatus;
private ToolStripMenuItem tsiStatusOnline;
private ToolStripMenuItem tsiStatusAway;
private ToolStripMenuItem tsiStatusDND;
private ToolStripMenuItem tsiStatusOffline;
} }
} }

View File

@ -17,9 +17,12 @@ namespace qtcnet_client.Controls
public int CurrencyCount { get; set; } = 0; public int CurrencyCount { get; set; } = 0;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Image ProfileImage { get; set; } = Resources.DefaultPfp; public Image ProfileImage { get; set; } = Resources.DefaultPfp;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int SelectedStatus { get; set; } = 1;
public event EventHandler? OnEditProfileClicked; public event EventHandler? OnEditProfileClicked;
public event EventHandler? OnSignOutClicked; public event EventHandler? OnSignOutClicked;
public event EventHandler? OnStatusChanged;
public CurrentProfileControl() public CurrentProfileControl()
{ {
@ -35,13 +38,50 @@ namespace qtcnet_client.Controls
public void RefreshInfo() public void RefreshInfo()
{ {
lblUsername.Text = $"Welcome, {Username}!"; if (InvokeRequired)
lblCurrencyAmount.Text = CurrencyCount.ToString(); {
pbCurrentProfilePic.Image = ProfileImage; Invoke(() =>
{
lblUsername.Text = $"Welcome, {Username}!";
lblCurrencyAmount.Text = CurrencyCount.ToString();
pbCurrentProfilePic.Image = ProfileImage;
});
} else
{
lblUsername.Text = $"Welcome, {Username}!";
lblCurrencyAmount.Text = CurrencyCount.ToString();
pbCurrentProfilePic.Image = ProfileImage;
}
} }
private void llblEditProfile_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) => OnEditProfileClicked?.Invoke(this, EventArgs.Empty); private void llblEditProfile_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) => OnEditProfileClicked?.Invoke(this, EventArgs.Empty);
private void llblSignOut_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) => OnSignOutClicked?.Invoke(this, EventArgs.Empty); private void llblSignOut_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) => OnSignOutClicked?.Invoke(this, EventArgs.Empty);
private async void ctxStatus_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
int status = 0;
if(e.ClickedItem?.Tag is string _statusTag)
{
switch(_statusTag)
{
case "Invisible":
status = 0;
break;
case "Online":
status = 1;
break;
case "Away":
status = 2;
break;
case "DoNotDisturb":
status = 3;
break;
}
SelectedStatus = status;
OnStatusChanged?.Invoke(this, EventArgs.Empty);
}
}
} }
} }

View File

@ -117,4 +117,7 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<metadata name="ctxStatus.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root> </root>

View File

@ -12,6 +12,7 @@ using QtCNETAPI.Services;
using QtCNETAPI.Services.ApiService; using QtCNETAPI.Services.ApiService;
using QtCNETAPI.Services.GatewayService; using QtCNETAPI.Services.GatewayService;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Threading.Tasks;
namespace qtcnet_client namespace qtcnet_client
{ {
@ -492,15 +493,37 @@ namespace qtcnet_client
private void _gatewayService_OnServerReconnected(object? sender, EventArgs e) private void _gatewayService_OnServerReconnected(object? sender, EventArgs e)
{ {
// reenable interactive controls // reenable interactive controls
CurrentProfileControl?.Enabled = true; if (InvokeRequired)
MainTabControl?.Enabled = true; {
Invoke(() =>
{
CurrentProfileControl?.Enabled = true;
MainTabControl?.Enabled = true;
});
}
else
{
CurrentProfileControl?.Enabled = true;
MainTabControl?.Enabled = true;
}
} }
private void _gatewayService_OnServerReconnecting(object? sender, EventArgs e) private void _gatewayService_OnServerReconnecting(object? sender, EventArgs e)
{ {
// disable interactive controls // disable interactive controls
CurrentProfileControl?.Enabled = false; if(InvokeRequired)
MainTabControl?.Enabled = false; {
Invoke(() =>
{
CurrentProfileControl?.Enabled = false;
MainTabControl?.Enabled = false;
});
}
else
{
CurrentProfileControl?.Enabled = false;
MainTabControl?.Enabled = false;
}
} }
private void _gatewayService_OnDirectMessageReceived(object? sender, EventArgs e) private void _gatewayService_OnDirectMessageReceived(object? sender, EventArgs e)
@ -583,9 +606,6 @@ namespace qtcnet_client
if (_res) if (_res)
{ {
if (_apiService.CurrentUser.Status == 0)
await _gatewayService.UpdateStatus(1);
// setup current profile control based on current user // setup current profile control based on current user
CurrentProfileControl = new() CurrentProfileControl = new()
{ {
@ -596,6 +616,7 @@ namespace qtcnet_client
CurrentProfileControl.OnEditProfileClicked += CurrentProfileControl_OnEditProfileClicked; CurrentProfileControl.OnEditProfileClicked += CurrentProfileControl_OnEditProfileClicked;
CurrentProfileControl.OnSignOutClicked += CurrentProfileControl_OnSignOutClicked; CurrentProfileControl.OnSignOutClicked += CurrentProfileControl_OnSignOutClicked;
CurrentProfileControl.OnStatusChanged += CurrentProfileControl_OnStatusChanged;
// get profile image for the current user // get profile image for the current user
CurrentProfileControl.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser.Id, _apiService.CurrentUser.Status, _apiService.CurrentUser.ActiveProfileCosmetic); CurrentProfileControl.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser.Id, _apiService.CurrentUser.Status, _apiService.CurrentUser.ActiveProfileCosmetic);
@ -703,6 +724,23 @@ namespace qtcnet_client
} }
} }
private async void _gatewayService_OnUserStatusUpdated(object? sender, EventArgs e)
{
if(e is UserStatusUpdatedEventArgs _args)
{
CurrentProfileControl?.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser!.Id, _args.StatusDto!.Status, _apiService.CurrentUser!.ActiveProfileCosmetic);
}
}
private async void CurrentProfileControl_OnStatusChanged(object? sender, EventArgs e)
{
if(sender is CurrentProfileControl _ctrl)
{
// set status based on selected
await _gatewayService.UpdateStatus(_ctrl.SelectedStatus);
}
}
private void MainTabControl_OnGameItemDoubleClicked(object? sender, EventArgs e) private void MainTabControl_OnGameItemDoubleClicked(object? sender, EventArgs e)
{ {
if(sender is MainTabControl _ctrl) if(sender is MainTabControl _ctrl)

View File

@ -30,6 +30,7 @@
{ {
components = new System.ComponentModel.Container(); components = new System.ComponentModel.Container();
pbProfileImage = new PictureBox(); pbProfileImage = new PictureBox();
ctxBoughtItems = new ContextMenuStrip(components);
lblStatus = new Label(); lblStatus = new Label();
rtxtBio = new RichTextBox(); rtxtBio = new RichTextBox();
tlpActionButtons = new TableLayoutPanel(); tlpActionButtons = new TableLayoutPanel();
@ -39,7 +40,6 @@
lblUsername = new Label(); lblUsername = new Label();
tlpTagIcons = new TableLayoutPanel(); tlpTagIcons = new TableLayoutPanel();
btnSaveProfile = new Button(); btnSaveProfile = new Button();
ctxBoughtItems = new ContextMenuStrip(components);
((System.ComponentModel.ISupportInitialize)pbProfileImage).BeginInit(); ((System.ComponentModel.ISupportInitialize)pbProfileImage).BeginInit();
tlpActionButtons.SuspendLayout(); tlpActionButtons.SuspendLayout();
tlpUsernameTags.SuspendLayout(); tlpUsernameTags.SuspendLayout();
@ -47,7 +47,6 @@
// //
// pbProfileImage // pbProfileImage
// //
pbProfileImage.ContextMenuStrip = ctxBoughtItems;
pbProfileImage.Image = Properties.Resources.DefaultPfp; pbProfileImage.Image = Properties.Resources.DefaultPfp;
pbProfileImage.Location = new Point(12, 12); pbProfileImage.Location = new Point(12, 12);
pbProfileImage.Name = "pbProfileImage"; pbProfileImage.Name = "pbProfileImage";
@ -55,10 +54,15 @@
pbProfileImage.SizeMode = PictureBoxSizeMode.Zoom; pbProfileImage.SizeMode = PictureBoxSizeMode.Zoom;
pbProfileImage.TabIndex = 0; pbProfileImage.TabIndex = 0;
pbProfileImage.TabStop = false; pbProfileImage.TabStop = false;
pbProfileImage.Click += pbProfileImage_Click; pbProfileImage.MouseClick += pbProfileImage_Click;
pbProfileImage.MouseEnter += pbProfileImage_MouseEnter; pbProfileImage.MouseEnter += pbProfileImage_MouseEnter;
pbProfileImage.MouseLeave += pbProfileImage_MouseLeave; pbProfileImage.MouseLeave += pbProfileImage_MouseLeave;
// //
// ctxBoughtItems
//
ctxBoughtItems.Name = "ctxBoughtItems";
ctxBoughtItems.Size = new Size(61, 4);
//
// lblStatus // lblStatus
// //
lblStatus.AutoEllipsis = true; lblStatus.AutoEllipsis = true;
@ -175,11 +179,6 @@
btnSaveProfile.Visible = false; btnSaveProfile.Visible = false;
btnSaveProfile.Click += btnSaveProfile_Click; btnSaveProfile.Click += btnSaveProfile_Click;
// //
// ctxBoughtItems
//
ctxBoughtItems.Name = "ctxBoughtItems";
ctxBoughtItems.Size = new Size(61, 4);
//
// ProfileForm // ProfileForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(7F, 15F);

View File

@ -281,7 +281,7 @@ namespace qtcnet_client.Forms
KryptonMessageBox.Show("Profile Update Failed. Please Try Again Later.", "Oops."); KryptonMessageBox.Show("Profile Update Failed. Please Try Again Later.", "Oops.");
} }
private void pbProfileImage_Click(object sender, EventArgs e) private void pbProfileImage_Click(object sender, MouseEventArgs e)
{ {
if(UserId == _apiService.CurrentUser?.Id) if(UserId == _apiService.CurrentUser?.Id)
{ {