From 98c3a2c7f8e67ca61daf84144216c4cf9902ce70 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Fri, 10 Oct 2025 06:42:59 +0200 Subject: [PATCH] Added syncshell profile related items. --- LightlessSync/PlayerData/Pairs/PairManager.cs | 8 +-- .../Services/LightlessGroupProfileData.cs | 6 ++ .../Services/LightlessProfileManager.cs | 67 ++++++++++++++----- ...ileData.cs => LightlessUserProfileData.cs} | 2 +- LightlessSync/Services/Mediator/Messages.cs | 3 +- LightlessSync/Services/UiFactory.cs | 2 +- LightlessSync/UI/EditProfileUi.cs | 8 +-- LightlessSync/UI/PopoutProfileUi.cs | 2 +- LightlessSync/UI/SettingsUi.cs | 4 +- LightlessSync/UI/StandaloneProfileUi.cs | 2 +- .../ApiController.Functions.Callbacks.cs | 8 ++- .../SignalR/ApiController.Functions.Groups.cs | 11 +++ LightlessSync/WebAPI/SignalR/ApiController.cs | 10 --- 13 files changed, 91 insertions(+), 42 deletions(-) create mode 100644 LightlessSync/Services/LightlessGroupProfileData.cs rename LightlessSync/Services/{LightlessProfileData.cs => LightlessUserProfileData.cs} (68%) diff --git a/LightlessSync/PlayerData/Pairs/PairManager.cs b/LightlessSync/PlayerData/Pairs/PairManager.cs index 512c7ad..2044db0 100644 --- a/LightlessSync/PlayerData/Pairs/PairManager.cs +++ b/LightlessSync/PlayerData/Pairs/PairManager.cs @@ -138,7 +138,7 @@ public sealed class PairManager : DisposableMediatorSubscriberBase { if (_allClientPairs.TryGetValue(user, out var pair)) { - Mediator.Publish(new ClearProfileDataMessage(pair.UserData)); + Mediator.Publish(new ClearProfileUserDataMessage(pair.UserData)); pair.MarkOffline(); } @@ -149,7 +149,7 @@ public sealed class PairManager : DisposableMediatorSubscriberBase { if (!_allClientPairs.ContainsKey(dto.User)) throw new InvalidOperationException("No user found for " + dto); - Mediator.Publish(new ClearProfileDataMessage(dto.User)); + Mediator.Publish(new ClearProfileUserDataMessage(dto.User)); var pair = _allClientPairs[dto.User]; if (pair.HasCachedPlayer) @@ -254,7 +254,7 @@ public sealed class PairManager : DisposableMediatorSubscriberBase if (pair.UserPair.OtherPermissions.IsPaused() != dto.Permissions.IsPaused()) { - Mediator.Publish(new ClearProfileDataMessage(dto.User)); + Mediator.Publish(new ClearProfileUserDataMessage(dto.User)); } pair.UserPair.OtherPermissions = dto.Permissions; @@ -280,7 +280,7 @@ public sealed class PairManager : DisposableMediatorSubscriberBase if (pair.UserPair.OwnPermissions.IsPaused() != dto.Permissions.IsPaused()) { - Mediator.Publish(new ClearProfileDataMessage(dto.User)); + Mediator.Publish(new ClearProfileUserDataMessage(dto.User)); } pair.UserPair.OwnPermissions = dto.Permissions; diff --git a/LightlessSync/Services/LightlessGroupProfileData.cs b/LightlessSync/Services/LightlessGroupProfileData.cs new file mode 100644 index 0000000..5a4c01a --- /dev/null +++ b/LightlessSync/Services/LightlessGroupProfileData.cs @@ -0,0 +1,6 @@ +namespace LightlessSync.Services; + +public record LightlessGroupProfileData(string Base64ProfilePicture, string Description, string Tags) +{ + public Lazy ImageData { get; } = new Lazy(Convert.FromBase64String(Base64ProfilePicture)); +} diff --git a/LightlessSync/Services/LightlessProfileManager.cs b/LightlessSync/Services/LightlessProfileManager.cs index f880a6a..8da01b4 100644 --- a/LightlessSync/Services/LightlessProfileManager.cs +++ b/LightlessSync/Services/LightlessProfileManager.cs @@ -18,11 +18,14 @@ public class LightlessProfileManager : MediatorSubscriberBase private const string _nsfw = "Profile not displayed - NSFW"; private readonly ApiController _apiController; private readonly LightlessConfigService _lightlessConfigService; - private readonly ConcurrentDictionary _lightlessProfiles = new(UserDataComparer.Instance); + private readonly ConcurrentDictionary _lightlessUserProfiles = new(UserDataComparer.Instance); + private readonly ConcurrentDictionary _lightlessGroupProfiles = new(GroupDataComparer.Instance); - private readonly LightlessProfileData _defaultProfileData = new(IsFlagged: false, IsNSFW: false, _lightlessLogo, string.Empty, _noDescription); - private readonly LightlessProfileData _loadingProfileData = new(IsFlagged: false, IsNSFW: false, _lightlessLogoLoading, string.Empty, "Loading Data from server..."); - private readonly LightlessProfileData _nsfwProfileData = new(IsFlagged: false, IsNSFW: false, _lightlessLogoNsfw, string.Empty, _nsfw); + private readonly LightlessUserProfileData _defaultProfileUserData = new(IsFlagged: false, IsNSFW: false, _lightlessLogo, string.Empty, _noDescription); + private readonly LightlessUserProfileData _loadingProfileUserData = new(IsFlagged: false, IsNSFW: false, _lightlessLogoLoading, string.Empty, "Loading User Profile Data from server..."); + private readonly LightlessGroupProfileData _loadingProfileGroupData = new(_lightlessLogoLoading, "Loading Group Profile Data from server...", string.Empty); + private readonly LightlessGroupProfileData _defaultProfileGroupData = new(_lightlessLogo, _noDescription, string.Empty); + private readonly LightlessUserProfileData _nsfwProfileData = new(IsFlagged: false, IsNSFW: false, _lightlessLogoNsfw, string.Empty, _nsfw); public LightlessProfileManager(ILogger logger, LightlessConfigService lightlessConfigService, LightlessMediator mediator, ApiController apiController) : base(logger, mediator) @@ -30,22 +33,33 @@ public class LightlessProfileManager : MediatorSubscriberBase _lightlessConfigService = lightlessConfigService; _apiController = apiController; - Mediator.Subscribe(this, (msg) => + Mediator.Subscribe(this, (msg) => { if (msg.UserData != null) - _lightlessProfiles.Remove(msg.UserData, out _); + _lightlessUserProfiles.Remove(msg.UserData, out _); else - _lightlessProfiles.Clear(); + _lightlessUserProfiles.Clear(); }); - Mediator.Subscribe(this, (_) => _lightlessProfiles.Clear()); + Mediator.Subscribe(this, (_) => _lightlessUserProfiles.Clear()); } - public LightlessProfileData GetLightlessProfile(UserData data) + public LightlessUserProfileData GetLightlessUserProfile(UserData data) { - if (!_lightlessProfiles.TryGetValue(data, out var profile)) + if (!_lightlessUserProfiles.TryGetValue(data, out var profile)) { _ = Task.Run(() => GetLightlessProfileFromService(data)); - return (_loadingProfileData); + return (_loadingProfileUserData); + } + + return (profile); + } + + public LightlessGroupProfileData GetLightlessGroupProfile(GroupData data) + { + if (!_lightlessGroupProfiles.TryGetValue(data, out var profile)) + { + _ = Task.Run(() => GetLightlessProfileFromService(data)); + return (_loadingProfileGroupData); } return (profile); @@ -55,26 +69,47 @@ public class LightlessProfileManager : MediatorSubscriberBase { try { - _lightlessProfiles[data] = _loadingProfileData; + _lightlessUserProfiles[data] = _loadingProfileUserData; var profile = await _apiController.UserGetProfile(new API.Dto.User.UserDto(data)).ConfigureAwait(false); - LightlessProfileData profileData = new(profile.Disabled, profile.IsNSFW ?? false, + LightlessUserProfileData profileData = new(profile.Disabled, profile.IsNSFW ?? false, string.IsNullOrEmpty(profile.ProfilePictureBase64) ? _lightlessLogo : profile.ProfilePictureBase64, !string.IsNullOrEmpty(data.Alias) && !string.Equals(data.Alias, data.UID, StringComparison.Ordinal) ? _lightlessSupporter : string.Empty, string.IsNullOrEmpty(profile.Description) ? _noDescription : profile.Description); if (profileData.IsNSFW && !_lightlessConfigService.Current.ProfilesAllowNsfw && !string.Equals(_apiController.UID, data.UID, StringComparison.Ordinal)) { - _lightlessProfiles[data] = _nsfwProfileData; + _lightlessUserProfiles[data] = _nsfwProfileData; } else { - _lightlessProfiles[data] = profileData; + _lightlessUserProfiles[data] = profileData; } } catch (Exception ex) { // if fails save DefaultProfileData to dict Logger.LogWarning(ex, "Failed to get Profile from service for user {user}", data); - _lightlessProfiles[data] = _defaultProfileData; + _lightlessUserProfiles[data] = _defaultProfileUserData; + } + } + + private async Task GetLightlessProfileFromService(GroupData data) + { + try + { + _lightlessGroupProfiles[data] = _loadingProfileGroupData; + var profile = await _apiController.GroupGetProfile(new API.Dto.Group.GroupDto(data)).ConfigureAwait(false); + LightlessGroupProfileData profileData = new( + string.IsNullOrEmpty(profile.PictureBase64) ? _lightlessLogo : profile.PictureBase64, + !string.IsNullOrEmpty(data.Alias) && !string.Equals(data.Alias, data.GID, StringComparison.Ordinal) ? _lightlessSupporter : string.Empty, + string.IsNullOrEmpty(profile.Description) ? _noDescription : profile.Description); + + _lightlessGroupProfiles[data] = profileData; + } + catch (Exception ex) + { + // if fails save DefaultProfileData to dict + Logger.LogWarning(ex, "Failed to get Profile from service for group {group}", data); + _lightlessGroupProfiles[data] = _defaultProfileGroupData; } } } \ No newline at end of file diff --git a/LightlessSync/Services/LightlessProfileData.cs b/LightlessSync/Services/LightlessUserProfileData.cs similarity index 68% rename from LightlessSync/Services/LightlessProfileData.cs rename to LightlessSync/Services/LightlessUserProfileData.cs index a6f0053..3319043 100644 --- a/LightlessSync/Services/LightlessProfileData.cs +++ b/LightlessSync/Services/LightlessUserProfileData.cs @@ -1,6 +1,6 @@ namespace LightlessSync.Services; -public record LightlessProfileData(bool IsFlagged, bool IsNSFW, string Base64ProfilePicture, string Base64SupporterPicture, string Description) +public record LightlessUserProfileData(bool IsFlagged, bool IsNSFW, string Base64ProfilePicture, string Base64SupporterPicture, string Description) { public Lazy ImageData { get; } = new Lazy(Convert.FromBase64String(Base64ProfilePicture)); public Lazy SupporterImageData { get; } = new Lazy(string.IsNullOrEmpty(Base64SupporterPicture) ? [] : Convert.FromBase64String(Base64SupporterPicture)); diff --git a/LightlessSync/Services/Mediator/Messages.cs b/LightlessSync/Services/Mediator/Messages.cs index 963bcbf..064e6fb 100644 --- a/LightlessSync/Services/Mediator/Messages.cs +++ b/LightlessSync/Services/Mediator/Messages.cs @@ -64,7 +64,8 @@ public record DownloadStartedMessage(GameObjectHandler DownloadId, Dictionary(), _lightlessMediator, - _apiController, _uiSharedService, _pairManager, dto, _performanceCollectorService); + _apiController, _uiSharedService, _pairManager, dto, _performanceCollectorService, _lightlessProfileManager); } public StandaloneProfileUi CreateStandaloneProfileUi(Pair pair) diff --git a/LightlessSync/UI/EditProfileUi.cs b/LightlessSync/UI/EditProfileUi.cs index 72e8d33..d9db33b 100644 --- a/LightlessSync/UI/EditProfileUi.cs +++ b/LightlessSync/UI/EditProfileUi.cs @@ -25,8 +25,8 @@ public class EditProfileUi : WindowMediatorSubscriberBase private readonly FileDialogManager _fileDialogManager; private readonly LightlessProfileManager _lightlessProfileManager; private readonly UiSharedService _uiSharedService; - private bool _adjustedForScollBarsLocalProfile = false; - private bool _adjustedForScollBarsOnlineProfile = false; + private bool _adjustedForScollBarsLocalProfile = false; + private bool _adjustedForScollBarsOnlineProfile = false; private string _descriptionText = string.Empty; private IDalamudTextureWrap? _pfpTextureWrap; private string _profileDescription = string.Empty; @@ -63,7 +63,7 @@ public class EditProfileUi : WindowMediatorSubscriberBase Mediator.Subscribe(this, (_) => { _wasOpen = IsOpen; IsOpen = false; }); Mediator.Subscribe(this, (_) => IsOpen = _wasOpen); Mediator.Subscribe(this, (_) => IsOpen = false); - Mediator.Subscribe(this, (msg) => + Mediator.Subscribe(this, (msg) => { if (msg.UserData == null || string.Equals(msg.UserData.UID, _apiController.UID, StringComparison.Ordinal)) { @@ -108,7 +108,7 @@ public class EditProfileUi : WindowMediatorSubscriberBase ImGui.Dummy(new Vector2(3)); - var profile = _lightlessProfileManager.GetLightlessProfile(new UserData(_apiController.UID)); + var profile = _lightlessProfileManager.GetLightlessUserProfile(new UserData(_apiController.UID)); if (ImGui.BeginTabBar("##EditProfileTabs")) { diff --git a/LightlessSync/UI/PopoutProfileUi.cs b/LightlessSync/UI/PopoutProfileUi.cs index 5a6557c..1737214 100644 --- a/LightlessSync/UI/PopoutProfileUi.cs +++ b/LightlessSync/UI/PopoutProfileUi.cs @@ -85,7 +85,7 @@ public class PopoutProfileUi : WindowMediatorSubscriberBase { var spacing = ImGui.GetStyle().ItemSpacing; - var lightlessProfile = _lightlessProfileManager.GetLightlessProfile(_pair.UserData); + var lightlessProfile = _lightlessProfileManager.GetLightlessUserProfile(_pair.UserData); if (_textureWrap == null || !lightlessProfile.ImageData.Value.SequenceEqual(_lastProfilePicture)) { diff --git a/LightlessSync/UI/SettingsUi.cs b/LightlessSync/UI/SettingsUi.cs index 84e4e94..bb851ed 100644 --- a/LightlessSync/UI/SettingsUi.cs +++ b/LightlessSync/UI/SettingsUi.cs @@ -1599,7 +1599,7 @@ public class SettingsUi : WindowMediatorSubscriberBase { if (ImGui.Checkbox("Show Lightless Profiles on Hover", ref showProfiles)) { - Mediator.Publish(new ClearProfileDataMessage()); + Mediator.Publish(new ClearProfileUserDataMessage()); _configService.Current.ProfilesShow = showProfiles; _configService.Save(); } @@ -1623,7 +1623,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.Unindent(); if (ImGui.Checkbox("Show profiles marked as NSFW", ref showNsfwProfiles)) { - Mediator.Publish(new ClearProfileDataMessage()); + Mediator.Publish(new ClearProfileUserDataMessage()); _configService.Current.ProfilesAllowNsfw = showNsfwProfiles; _configService.Save(); } diff --git a/LightlessSync/UI/StandaloneProfileUi.cs b/LightlessSync/UI/StandaloneProfileUi.cs index ca7d779..6ef21d5 100644 --- a/LightlessSync/UI/StandaloneProfileUi.cs +++ b/LightlessSync/UI/StandaloneProfileUi.cs @@ -51,7 +51,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase { var spacing = ImGui.GetStyle().ItemSpacing; - var lightlessProfile = _lightlessProfileManager.GetLightlessProfile(Pair.UserData); + var lightlessProfile = _lightlessProfileManager.GetLightlessUserProfile(Pair.UserData); if (_textureWrap == null || !lightlessProfile.ImageData.Value.SequenceEqual(_lastProfilePicture)) { diff --git a/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs b/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs index 263c87a..6f71ee9 100644 --- a/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs +++ b/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs @@ -192,7 +192,7 @@ public partial class ApiController public Task Client_UserUpdateProfile(UserDto dto) { Logger.LogDebug("Client_UserUpdateProfile: {dto}", dto); - ExecuteSafely(() => Mediator.Publish(new ClearProfileDataMessage(dto.User))); + ExecuteSafely(() => Mediator.Publish(new ClearProfileUserDataMessage(dto.User))); return Task.CompletedTask; } @@ -377,6 +377,12 @@ public partial class ApiController _lightlessHub!.On(nameof(Client_UserUpdateProfile), act); } + public void ClientGroupSendProfile(Action act) + { + if (_initialized) return; + _lightlessHub!.On(nameof(Client_GroupSendProfile), act); + } + public void OnUserUpdateSelfPairPermissions(Action act) { if (_initialized) return; diff --git a/LightlessSync/WebAPI/SignalR/ApiController.Functions.Groups.cs b/LightlessSync/WebAPI/SignalR/ApiController.Functions.Groups.cs index c7581d1..79de11e 100644 --- a/LightlessSync/WebAPI/SignalR/ApiController.Functions.Groups.cs +++ b/LightlessSync/WebAPI/SignalR/ApiController.Functions.Groups.cs @@ -115,6 +115,17 @@ public partial class ApiController CheckConnection(); return await _lightlessHub!.InvokeAsync(nameof(GroupPrune), group, days, execute).ConfigureAwait(false); } + public async Task GroupGetProfile(GroupDto dto) + { + if (!IsConnected) return new GroupProfileDto(Group: dto.Group, Description: null, Tags: null, PictureBase64: null); + return await _lightlessHub!.InvokeAsync(nameof(GroupGetProfile), dto).ConfigureAwait(false); + } + + public async Task GroupSetProfile(GroupProfileDto dto) + { + if (!IsConnected) return; + await _lightlessHub!.InvokeAsync(nameof(GroupSetProfile), dto).ConfigureAwait(false); + } public async Task> GroupsGetAll() { diff --git a/LightlessSync/WebAPI/SignalR/ApiController.cs b/LightlessSync/WebAPI/SignalR/ApiController.cs index 90be67f..d9b8001 100644 --- a/LightlessSync/WebAPI/SignalR/ApiController.cs +++ b/LightlessSync/WebAPI/SignalR/ApiController.cs @@ -610,15 +610,5 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL { throw new NotImplementedException(); } - - public Task GroupGetProfile(GroupDto dto) - { - throw new NotImplementedException(); - } - - public Task GroupSetProfile(GroupProfileDto dto) - { - throw new NotImplementedException(); - } } #pragma warning restore MA0040 \ No newline at end of file