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

View File

@ -74,6 +74,7 @@ namespace QtCNETAPI.Services.GatewayService
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.On("UpdateCurrentUser", async () => await _apiService.SetCurrentUser());
HubConnection.Closed += HubConnection_Closed;
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}");
return;
}
// ensure current user is up to date (particularly status (its still busted lol))
await _apiService.SetCurrentUser();
}
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.");
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>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
pbCurrentProfilePic = new PictureBox();
ctxStatus = new ContextMenuStrip(components);
tsiStatusOnline = new ToolStripMenuItem();
tsiStatusAway = new ToolStripMenuItem();
tsiStatusDND = new ToolStripMenuItem();
tsiStatusOffline = new ToolStripMenuItem();
llblSignOut = new LinkLabel();
llblEditProfile = new LinkLabel();
pictureBox1 = new PictureBox();
lblUsername = new Label();
lblCurrencyAmount = new Label();
((System.ComponentModel.ISupportInitialize)pbCurrentProfilePic).BeginInit();
ctxStatus.SuspendLayout();
((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();
SuspendLayout();
//
// pbCurrentProfilePic
//
pbCurrentProfilePic.Cursor = Cursors.Hand;
pbCurrentProfilePic.ContextMenuStrip = ctxStatus;
pbCurrentProfilePic.Image = Properties.Resources.DefaultPfp;
pbCurrentProfilePic.Location = new Point(3, 3);
pbCurrentProfilePic.Name = "pbCurrentProfilePic";
@ -49,6 +56,45 @@
pbCurrentProfilePic.TabIndex = 0;
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.AutoSize = true;
@ -119,6 +165,7 @@
Size = new Size(197, 73);
Load += CurrentProfileControl_Load;
((System.ComponentModel.ISupportInitialize)pbCurrentProfilePic).EndInit();
ctxStatus.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();
ResumeLayout(false);
PerformLayout();
@ -132,5 +179,10 @@
private PictureBox pictureBox1;
private Label lblUsername;
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;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Image ProfileImage { get; set; } = Resources.DefaultPfp;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int SelectedStatus { get; set; } = 1;
public event EventHandler? OnEditProfileClicked;
public event EventHandler? OnSignOutClicked;
public event EventHandler? OnStatusChanged;
public CurrentProfileControl()
{
@ -35,13 +38,50 @@ namespace qtcnet_client.Controls
public void RefreshInfo()
{
lblUsername.Text = $"Welcome, {Username}!";
lblCurrencyAmount.Text = CurrencyCount.ToString();
pbCurrentProfilePic.Image = ProfileImage;
if (InvokeRequired)
{
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 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">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</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>

View File

@ -12,6 +12,7 @@ using QtCNETAPI.Services;
using QtCNETAPI.Services.ApiService;
using QtCNETAPI.Services.GatewayService;
using System.Drawing.Drawing2D;
using System.Threading.Tasks;
namespace qtcnet_client
{
@ -492,15 +493,37 @@ namespace qtcnet_client
private void _gatewayService_OnServerReconnected(object? sender, EventArgs e)
{
// reenable interactive controls
CurrentProfileControl?.Enabled = true;
MainTabControl?.Enabled = true;
if (InvokeRequired)
{
Invoke(() =>
{
CurrentProfileControl?.Enabled = true;
MainTabControl?.Enabled = true;
});
}
else
{
CurrentProfileControl?.Enabled = true;
MainTabControl?.Enabled = true;
}
}
private void _gatewayService_OnServerReconnecting(object? sender, EventArgs e)
{
// disable interactive controls
CurrentProfileControl?.Enabled = false;
MainTabControl?.Enabled = false;
if(InvokeRequired)
{
Invoke(() =>
{
CurrentProfileControl?.Enabled = false;
MainTabControl?.Enabled = false;
});
}
else
{
CurrentProfileControl?.Enabled = false;
MainTabControl?.Enabled = false;
}
}
private void _gatewayService_OnDirectMessageReceived(object? sender, EventArgs e)
@ -583,9 +606,6 @@ namespace qtcnet_client
if (_res)
{
if (_apiService.CurrentUser.Status == 0)
await _gatewayService.UpdateStatus(1);
// setup current profile control based on current user
CurrentProfileControl = new()
{
@ -596,6 +616,7 @@ namespace qtcnet_client
CurrentProfileControl.OnEditProfileClicked += CurrentProfileControl_OnEditProfileClicked;
CurrentProfileControl.OnSignOutClicked += CurrentProfileControl_OnSignOutClicked;
CurrentProfileControl.OnStatusChanged += CurrentProfileControl_OnStatusChanged;
// get profile image for the current user
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)
{
if(sender is MainTabControl _ctrl)

View File

@ -30,6 +30,7 @@
{
components = new System.ComponentModel.Container();
pbProfileImage = new PictureBox();
ctxBoughtItems = new ContextMenuStrip(components);
lblStatus = new Label();
rtxtBio = new RichTextBox();
tlpActionButtons = new TableLayoutPanel();
@ -39,7 +40,6 @@
lblUsername = new Label();
tlpTagIcons = new TableLayoutPanel();
btnSaveProfile = new Button();
ctxBoughtItems = new ContextMenuStrip(components);
((System.ComponentModel.ISupportInitialize)pbProfileImage).BeginInit();
tlpActionButtons.SuspendLayout();
tlpUsernameTags.SuspendLayout();
@ -47,7 +47,6 @@
//
// pbProfileImage
//
pbProfileImage.ContextMenuStrip = ctxBoughtItems;
pbProfileImage.Image = Properties.Resources.DefaultPfp;
pbProfileImage.Location = new Point(12, 12);
pbProfileImage.Name = "pbProfileImage";
@ -55,10 +54,15 @@
pbProfileImage.SizeMode = PictureBoxSizeMode.Zoom;
pbProfileImage.TabIndex = 0;
pbProfileImage.TabStop = false;
pbProfileImage.Click += pbProfileImage_Click;
pbProfileImage.MouseClick += pbProfileImage_Click;
pbProfileImage.MouseEnter += pbProfileImage_MouseEnter;
pbProfileImage.MouseLeave += pbProfileImage_MouseLeave;
//
// ctxBoughtItems
//
ctxBoughtItems.Name = "ctxBoughtItems";
ctxBoughtItems.Size = new Size(61, 4);
//
// lblStatus
//
lblStatus.AutoEllipsis = true;
@ -175,11 +179,6 @@
btnSaveProfile.Visible = false;
btnSaveProfile.Click += btnSaveProfile_Click;
//
// ctxBoughtItems
//
ctxBoughtItems.Name = "ctxBoughtItems";
ctxBoughtItems.Size = new Size(61, 4);
//
// ProfileForm
//
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.");
}
private void pbProfileImage_Click(object sender, EventArgs e)
private void pbProfileImage_Click(object sender, MouseEventArgs e)
{
if(UserId == _apiService.CurrentUser?.Id)
{