From 806a4baf1a7e5371b5e695f3f329b8369df02a06 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Sun, 7 Sep 2025 15:28:19 +0200 Subject: [PATCH 1/8] Seperated pair tags and syncshell tags, added function to be able to add syncshell tags. --- .../Models/ServerTagStorage.cs | 1 + ...nfigService.cs => PairTagConfigService.cs} | 4 +- .../SyncshellTagConfigService.cs | 14 +++++++ LightlessSync/Plugin.cs | 6 ++- .../ServerConfigurationManager.cs | 40 +++++++++++++------ LightlessSync/UI/CompactUI.cs | 15 ++++++- LightlessSync/UI/Components/RenameTagUi.cs | 2 +- .../UI/Components/SelectTagForPairUi.cs | 4 +- LightlessSync/UI/Handlers/TagHandler.cs | 24 +++++------ 9 files changed, 75 insertions(+), 35 deletions(-) rename LightlessSync/LightlessConfiguration/{ServerTagConfigService.cs => PairTagConfigService.cs} (62%) create mode 100644 LightlessSync/LightlessConfiguration/SyncshellTagConfigService.cs diff --git a/LightlessSync/LightlessConfiguration/Models/ServerTagStorage.cs b/LightlessSync/LightlessConfiguration/Models/ServerTagStorage.cs index 75d3f46..d656214 100644 --- a/LightlessSync/LightlessConfiguration/Models/ServerTagStorage.cs +++ b/LightlessSync/LightlessConfiguration/Models/ServerTagStorage.cs @@ -5,5 +5,6 @@ public class ServerTagStorage { public HashSet OpenPairTags { get; set; } = new(StringComparer.Ordinal); public HashSet ServerAvailablePairTags { get; set; } = new(StringComparer.Ordinal); + public HashSet ServerAvailableSyncshellTags { get; set; } = new(StringComparer.Ordinal); public Dictionary> UidServerPairedUserTags { get; set; } = new(StringComparer.Ordinal); } diff --git a/LightlessSync/LightlessConfiguration/ServerTagConfigService.cs b/LightlessSync/LightlessConfiguration/PairTagConfigService.cs similarity index 62% rename from LightlessSync/LightlessConfiguration/ServerTagConfigService.cs rename to LightlessSync/LightlessConfiguration/PairTagConfigService.cs index b31e746..07cb72a 100644 --- a/LightlessSync/LightlessConfiguration/ServerTagConfigService.cs +++ b/LightlessSync/LightlessConfiguration/PairTagConfigService.cs @@ -2,11 +2,11 @@ namespace LightlessSync.LightlessConfiguration; -public class ServerTagConfigService : ConfigurationServiceBase +public class PairTagConfigService : ConfigurationServiceBase { public const string ConfigName = "servertags.json"; - public ServerTagConfigService(string configDir) : base(configDir) + public PairTagConfigService(string configDir) : base(configDir) { } diff --git a/LightlessSync/LightlessConfiguration/SyncshellTagConfigService.cs b/LightlessSync/LightlessConfiguration/SyncshellTagConfigService.cs new file mode 100644 index 0000000..6fc7f6a --- /dev/null +++ b/LightlessSync/LightlessConfiguration/SyncshellTagConfigService.cs @@ -0,0 +1,14 @@ +using LightlessSync.LightlessConfiguration.Configurations; + +namespace LightlessSync.LightlessConfiguration; + +public class SyncshellTagConfigService : ConfigurationServiceBase +{ + public const string ConfigName = "serversyncshelltags.json"; + + public SyncshellTagConfigService(string configDir) : base(configDir) + { + } + + public override string ConfigurationName => ConfigName; +} \ No newline at end of file diff --git a/LightlessSync/Plugin.cs b/LightlessSync/Plugin.cs index 7e00038..cf9b41c 100644 --- a/LightlessSync/Plugin.cs +++ b/LightlessSync/Plugin.cs @@ -175,7 +175,8 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton((s) => new LightlessConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new NotesConfigService(pluginInterface.ConfigDirectory.FullName)); - collection.AddSingleton((s) => new ServerTagConfigService(pluginInterface.ConfigDirectory.FullName)); + collection.AddSingleton((s) => new PairTagConfigService(pluginInterface.ConfigDirectory.FullName)); + collection.AddSingleton((s) => new SyncshellTagConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new TransientConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new XivDataStorageService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new PlayerPerformanceConfigService(pluginInterface.ConfigDirectory.FullName)); @@ -183,7 +184,8 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); - collection.AddSingleton>(s => s.GetRequiredService()); + collection.AddSingleton>(s => s.GetRequiredService()); + collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); diff --git a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs index 8bff7f9..487a1e3 100644 --- a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -23,15 +23,17 @@ public class ServerConfigurationManager private readonly ILogger _logger; private readonly LightlessMediator _lightlessMediator; private readonly NotesConfigService _notesConfig; - private readonly ServerTagConfigService _serverTagConfig; + private readonly PairTagConfigService _pairTagConfig; + private readonly SyncshellTagConfigService _syncshellTagConfig; public ServerConfigurationManager(ILogger logger, ServerConfigService configService, - ServerTagConfigService serverTagConfig, NotesConfigService notesConfig, DalamudUtilService dalamudUtil, + PairTagConfigService pairTagConfig, SyncshellTagConfigService syncshellTagConfig, NotesConfigService notesConfig, DalamudUtilService dalamudUtil, LightlessConfigService lightlessConfigService, HttpClient httpClient, LightlessMediator lightlessMediator) { _logger = logger; _configService = configService; - _serverTagConfig = serverTagConfig; + _pairTagConfig = pairTagConfig; + _syncshellTagConfig = syncshellTagConfig; _notesConfig = notesConfig; _dalamudUtil = dalamudUtil; _lightlessConfigService = lightlessConfigService; @@ -285,7 +287,7 @@ public class ServerConfigurationManager internal void AddOpenPairTag(string tag) { CurrentServerTagStorage().OpenPairTags.Add(tag); - _serverTagConfig.Save(); + _pairTagConfig.Save(); } internal void AddServer(ServerStorage serverStorage) @@ -294,10 +296,17 @@ public class ServerConfigurationManager Save(); } - internal void AddTag(string tag) + internal void AddPairTag(string tag) { CurrentServerTagStorage().ServerAvailablePairTags.Add(tag); - _serverTagConfig.Save(); + _pairTagConfig.Save(); + _lightlessMediator.Publish(new RefreshUiMessage()); + } + + internal void AddSyncshellTag(string tag) + { + CurrentServerTagStorage().ServerAvailableSyncshellTags.Add(tag); + _pairTagConfig.Save(); _lightlessMediator.Publish(new RefreshUiMessage()); } @@ -313,7 +322,7 @@ public class ServerConfigurationManager CurrentServerTagStorage().UidServerPairedUserTags[uid] = [tagName]; } - _serverTagConfig.Save(); + _pairTagConfig.Save(); } internal bool ContainsOpenPairTag(string tag) @@ -369,6 +378,11 @@ public class ServerConfigurationManager return CurrentServerTagStorage().ServerAvailablePairTags; } + internal HashSet GetServerAvailableSyncshellTags() + { + return CurrentServerTagStorage().ServerAvailableSyncshellTags; + } + internal Dictionary> GetUidServerPairedUserTags() { return CurrentServerTagStorage().UidServerPairedUserTags; @@ -399,7 +413,7 @@ public class ServerConfigurationManager internal void RemoveOpenPairTag(string tag) { CurrentServerTagStorage().OpenPairTags.Remove(tag); - _serverTagConfig.Save(); + _pairTagConfig.Save(); } internal void RemoveTag(string tag) @@ -409,7 +423,7 @@ public class ServerConfigurationManager { RemoveTagForUid(uid, tag, save: false); } - _serverTagConfig.Save(); + _pairTagConfig.Save(); _lightlessMediator.Publish(new RefreshUiMessage()); } @@ -421,7 +435,7 @@ public class ServerConfigurationManager if (save) { - _serverTagConfig.Save(); + _pairTagConfig.Save(); _lightlessMediator.Publish(new RefreshUiMessage()); } } @@ -479,7 +493,7 @@ public class ServerConfigurationManager private ServerTagStorage CurrentServerTagStorage() { TryCreateCurrentServerTagStorage(); - return _serverTagConfig.Current.ServerTagStorage[CurrentApiUrl]; + return _pairTagConfig.Current.ServerTagStorage[CurrentApiUrl]; } private void EnsureMainExists() @@ -501,9 +515,9 @@ public class ServerConfigurationManager private void TryCreateCurrentServerTagStorage() { - if (!_serverTagConfig.Current.ServerTagStorage.ContainsKey(CurrentApiUrl)) + if (!_pairTagConfig.Current.ServerTagStorage.ContainsKey(CurrentApiUrl)) { - _serverTagConfig.Current.ServerTagStorage[CurrentApiUrl] = new(); + _pairTagConfig.Current.ServerTagStorage[CurrentApiUrl] = new(); } } diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index 5c1ae53..02d5975 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -516,7 +516,8 @@ public class CompactUi : WindowMediatorSubscriberBase else drawFolders.AddRange(groupFolders); - var tags = _tagHandler.GetAllTagsSorted(); + var tags = _tagHandler.GetAllPairTagsSorted(); + _logger.LogInformation($"Loading {tags.Count} pair tags"); foreach (var tag in tags) { var allTagPairs = ImmutablePairList(allPairs @@ -527,6 +528,18 @@ public class CompactUi : WindowMediatorSubscriberBase drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(tag, filteredTagPairs, allTagPairs)); } + var syncshellTags = _tagHandler.GetAllSyncshellTagsSorted(); + _logger.LogInformation($"Loading {syncshellTags.Count} syncshell tags"); + foreach (var syncshelltag in syncshellTags) + { + var allTagPairs = ImmutablePairList(allPairs + .Where(u => FilterTagusers(u, syncshelltag))); + var filteredTagPairs = BasicSortedDictionary(filteredPairs + .Where(u => FilterTagusers(u, syncshelltag) && FilterOnlineOrPausedSelf(u))); + + drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(syncshelltag, filteredTagPairs, allTagPairs)); + } + var allOnlineNotTaggedPairs = ImmutablePairList(allPairs .Where(FilterNotTaggedUsers)); var onlineNotTaggedPairs = BasicSortedDictionary(filteredPairs diff --git a/LightlessSync/UI/Components/RenameTagUi.cs b/LightlessSync/UI/Components/RenameTagUi.cs index 1d71f64..139353a 100644 --- a/LightlessSync/UI/Components/RenameTagUi.cs +++ b/LightlessSync/UI/Components/RenameTagUi.cs @@ -80,7 +80,7 @@ public class RenameTagUi _tagHandler.RemoveTag(oldTag); //Creation of new tag and adding of old group pairs in new one. - _tagHandler.AddTag(newTag); + _tagHandler.AddPairTag(newTag); foreach (Pair pair in pairs) { var isInTag = _peopleInGroup.Contains(pair.UserData.UID); diff --git a/LightlessSync/UI/Components/SelectTagForPairUi.cs b/LightlessSync/UI/Components/SelectTagForPairUi.cs index e258f9c..c9ee5fa 100644 --- a/LightlessSync/UI/Components/SelectTagForPairUi.cs +++ b/LightlessSync/UI/Components/SelectTagForPairUi.cs @@ -59,7 +59,7 @@ public class SelectTagForPairUi if (ImGui.BeginPopup(popupName)) { - var tags = _tagHandler.GetAllTagsSorted(); + var tags = _tagHandler.GetAllPairTagsSorted(); var childHeight = tags.Count != 0 ? tags.Count * 25 : 1; var childSize = new Vector2(0, childHeight > 100 ? 100 : childHeight) * ImGuiHelpers.GlobalScale; @@ -120,7 +120,7 @@ public class SelectTagForPairUi { if (!_tagNameToAdd.IsNullOrWhitespace() && _tagNameToAdd is not (TagHandler.CustomOfflineTag or TagHandler.CustomOnlineTag or TagHandler.CustomVisibleTag)) { - _tagHandler.AddTag(_tagNameToAdd); + _tagHandler.AddPairTag(_tagNameToAdd); if (_pair != null) { _tagHandler.AddTagToPairedUid(_pair.UserData.UID, _tagNameToAdd); diff --git a/LightlessSync/UI/Handlers/TagHandler.cs b/LightlessSync/UI/Handlers/TagHandler.cs index f721508..69d0f28 100644 --- a/LightlessSync/UI/Handlers/TagHandler.cs +++ b/LightlessSync/UI/Handlers/TagHandler.cs @@ -17,25 +17,21 @@ public class TagHandler _serverConfigurationManager = serverConfigurationManager; } - public void AddTag(string tag) - { - _serverConfigurationManager.AddTag(tag); - } + public void AddPairTag(string tag) => _serverConfigurationManager.AddPairTag(tag); + public void AddSyncshellTag(string tag) => _serverConfigurationManager.AddSyncshellTag(tag); + public void AddTagToPairedUid(string uid, string tagName) => _serverConfigurationManager.AddTagForUid(uid, tagName); - public void AddTagToPairedUid(string uid, string tagName) - { - _serverConfigurationManager.AddTagForUid(uid, tagName); - } - - public List GetAllTagsSorted() - { - return - [ + public List GetAllPairTagsSorted() => [ .. _serverConfigurationManager.GetServerAvailablePairTags() .OrderBy(s => s, StringComparer.OrdinalIgnoreCase) , ]; - } + + public List GetAllSyncshellTagsSorted() => [ + .. _serverConfigurationManager.GetServerAvailableSyncshellTags() + .OrderBy(s => s, StringComparer.OrdinalIgnoreCase) +, + ]; public HashSet GetOtherUidsForTag(string tag) { -- 2.49.1 From 75d23021ef37a0499858892b1e26cd4f14e7f72b Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Mon, 8 Sep 2025 06:49:40 +0200 Subject: [PATCH 2/8] Added all functions required for the syncshell folder system --- .../Configurations/PairTagStorage.cs | 7 + .../Configurations/ServerTagConfig.cs | 9 - .../Configurations/SyncshellTagStorage.cs | 7 + ...{ServerTagStorage.cs => PairTagStorage.cs} | 3 +- .../Models/SyncshellTagStorage.cs | 9 + .../PairTagConfigService.cs | 2 +- .../SyncshellTagConfigService.cs | 4 +- .../ServerConfigurationManager.cs | 169 ++++++++++++++---- LightlessSync/UI/CompactUI.cs | 16 +- LightlessSync/UI/Components/DrawFolderTag.cs | 2 +- LightlessSync/UI/Components/RenameTagUi.cs | 4 +- .../UI/Components/SelectPairForTagUi.cs | 2 +- .../UI/Components/SelectTagForPairUi.cs | 6 +- LightlessSync/UI/Handlers/IdDisplayHandler.cs | 4 +- LightlessSync/UI/Handlers/TagHandler.cs | 139 +++++++++++--- 15 files changed, 290 insertions(+), 93 deletions(-) create mode 100644 LightlessSync/LightlessConfiguration/Configurations/PairTagStorage.cs delete mode 100644 LightlessSync/LightlessConfiguration/Configurations/ServerTagConfig.cs create mode 100644 LightlessSync/LightlessConfiguration/Configurations/SyncshellTagStorage.cs rename LightlessSync/LightlessConfiguration/Models/{ServerTagStorage.cs => PairTagStorage.cs} (73%) create mode 100644 LightlessSync/LightlessConfiguration/Models/SyncshellTagStorage.cs diff --git a/LightlessSync/LightlessConfiguration/Configurations/PairTagStorage.cs b/LightlessSync/LightlessConfiguration/Configurations/PairTagStorage.cs new file mode 100644 index 0000000..37d1966 --- /dev/null +++ b/LightlessSync/LightlessConfiguration/Configurations/PairTagStorage.cs @@ -0,0 +1,7 @@ +namespace LightlessSync.LightlessConfiguration.Configurations; + +public class PairTagStorage : ILightlessConfiguration +{ + public Dictionary ServerTagStorage { get; set; } = new(StringComparer.OrdinalIgnoreCase); + public int Version { get; set; } = 0; +} \ No newline at end of file diff --git a/LightlessSync/LightlessConfiguration/Configurations/ServerTagConfig.cs b/LightlessSync/LightlessConfiguration/Configurations/ServerTagConfig.cs deleted file mode 100644 index bdfe68f..0000000 --- a/LightlessSync/LightlessConfiguration/Configurations/ServerTagConfig.cs +++ /dev/null @@ -1,9 +0,0 @@ -using LightlessSync.LightlessConfiguration.Models; - -namespace LightlessSync.LightlessConfiguration.Configurations; - -public class ServerTagConfig : ILightlessConfiguration -{ - public Dictionary ServerTagStorage { get; set; } = new(StringComparer.OrdinalIgnoreCase); - public int Version { get; set; } = 0; -} \ No newline at end of file diff --git a/LightlessSync/LightlessConfiguration/Configurations/SyncshellTagStorage.cs b/LightlessSync/LightlessConfiguration/Configurations/SyncshellTagStorage.cs new file mode 100644 index 0000000..73cc9ec --- /dev/null +++ b/LightlessSync/LightlessConfiguration/Configurations/SyncshellTagStorage.cs @@ -0,0 +1,7 @@ +namespace LightlessSync.LightlessConfiguration.Configurations; + +public class SyncshellTagStorage : ILightlessConfiguration +{ + public Dictionary ServerTagStorage { get; set; } = new(StringComparer.OrdinalIgnoreCase); + public int Version { get; set; } = 0; +} \ No newline at end of file diff --git a/LightlessSync/LightlessConfiguration/Models/ServerTagStorage.cs b/LightlessSync/LightlessConfiguration/Models/PairTagStorage.cs similarity index 73% rename from LightlessSync/LightlessConfiguration/Models/ServerTagStorage.cs rename to LightlessSync/LightlessConfiguration/Models/PairTagStorage.cs index d656214..b8edeb8 100644 --- a/LightlessSync/LightlessConfiguration/Models/ServerTagStorage.cs +++ b/LightlessSync/LightlessConfiguration/Models/PairTagStorage.cs @@ -1,10 +1,9 @@ namespace LightlessSync.LightlessConfiguration.Models; [Serializable] -public class ServerTagStorage +public class PairTagStorage { public HashSet OpenPairTags { get; set; } = new(StringComparer.Ordinal); public HashSet ServerAvailablePairTags { get; set; } = new(StringComparer.Ordinal); - public HashSet ServerAvailableSyncshellTags { get; set; } = new(StringComparer.Ordinal); public Dictionary> UidServerPairedUserTags { get; set; } = new(StringComparer.Ordinal); } diff --git a/LightlessSync/LightlessConfiguration/Models/SyncshellTagStorage.cs b/LightlessSync/LightlessConfiguration/Models/SyncshellTagStorage.cs new file mode 100644 index 0000000..725621b --- /dev/null +++ b/LightlessSync/LightlessConfiguration/Models/SyncshellTagStorage.cs @@ -0,0 +1,9 @@ +namespace LightlessSync.LightlessConfiguration.Models; + +[Serializable] +public class SyncshellTagStorage +{ + public HashSet OpenSyncshellTags { get; set; } = new(StringComparer.Ordinal); + public HashSet ServerAvailableSyncshellTags { get; set; } = new(StringComparer.Ordinal); + public Dictionary> SyncshellPairedTags { get; set; } = new(StringComparer.Ordinal); +} diff --git a/LightlessSync/LightlessConfiguration/PairTagConfigService.cs b/LightlessSync/LightlessConfiguration/PairTagConfigService.cs index 07cb72a..cc4c559 100644 --- a/LightlessSync/LightlessConfiguration/PairTagConfigService.cs +++ b/LightlessSync/LightlessConfiguration/PairTagConfigService.cs @@ -2,7 +2,7 @@ namespace LightlessSync.LightlessConfiguration; -public class PairTagConfigService : ConfigurationServiceBase +public class PairTagConfigService : ConfigurationServiceBase { public const string ConfigName = "servertags.json"; diff --git a/LightlessSync/LightlessConfiguration/SyncshellTagConfigService.cs b/LightlessSync/LightlessConfiguration/SyncshellTagConfigService.cs index 6fc7f6a..b62bf7c 100644 --- a/LightlessSync/LightlessConfiguration/SyncshellTagConfigService.cs +++ b/LightlessSync/LightlessConfiguration/SyncshellTagConfigService.cs @@ -2,9 +2,9 @@ namespace LightlessSync.LightlessConfiguration; -public class SyncshellTagConfigService : ConfigurationServiceBase +public class SyncshellTagConfigService : ConfigurationServiceBase { - public const string ConfigName = "serversyncshelltags.json"; + public const string ConfigName = "syncshelltags.json"; public SyncshellTagConfigService(string configDir) : base(configDir) { diff --git a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs index 487a1e3..fa586f5 100644 --- a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -3,6 +3,7 @@ using LightlessSync.API.Routes; using LightlessSync.LightlessConfiguration; using LightlessSync.LightlessConfiguration.Models; using LightlessSync.Services.Mediator; +using LightlessSync.UI.Components; using LightlessSync.WebAPI; using Microsoft.AspNetCore.Http.Connections; using Microsoft.Extensions.Logging; @@ -260,7 +261,7 @@ public class ServerConfigurationManager { if (serverSelectionIndex == -1) serverSelectionIndex = CurrentServerIndex; var server = GetServerByIndex(serverSelectionIndex); - if (server.Authentications.Any(c => string.Equals(c.CharacterName, _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult(), StringComparison.Ordinal) + if (server.Authentications.Exists(c => string.Equals(c.CharacterName, _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult(), StringComparison.Ordinal) && c.WorldId == _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult())) return; @@ -279,17 +280,23 @@ public class ServerConfigurationManager var server = GetServerByIndex(serverSelectionIndex); server.Authentications.Add(new Authentication() { - SecretKeyIdx = server.SecretKeys.Any() ? server.SecretKeys.First().Key : -1, + SecretKeyIdx = server.SecretKeys.Count != 0 ? server.SecretKeys.First().Key : -1, }); Save(); } internal void AddOpenPairTag(string tag) { - CurrentServerTagStorage().OpenPairTags.Add(tag); + CurrentPairTagStorage().OpenPairTags.Add(tag); _pairTagConfig.Save(); } + internal void AddOpenSyncshellTag(string tag) + { + CurrentSyncshellTagStorage().OpenSyncshellTags.Add(tag); + _syncshellTagConfig.Save(); + } + internal void AddServer(ServerStorage serverStorage) { _configService.Current.ServerStorage.Add(serverStorage); @@ -298,41 +305,66 @@ public class ServerConfigurationManager internal void AddPairTag(string tag) { - CurrentServerTagStorage().ServerAvailablePairTags.Add(tag); + CurrentPairTagStorage().ServerAvailablePairTags.Add(tag); _pairTagConfig.Save(); _lightlessMediator.Publish(new RefreshUiMessage()); } internal void AddSyncshellTag(string tag) { - CurrentServerTagStorage().ServerAvailableSyncshellTags.Add(tag); - _pairTagConfig.Save(); + CurrentSyncshellTagStorage().ServerAvailableSyncshellTags.Add(tag); + _syncshellTagConfig.Save(); _lightlessMediator.Publish(new RefreshUiMessage()); } internal void AddTagForUid(string uid, string tagName) { - if (CurrentServerTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags)) + if (CurrentPairTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags)) { tags.Add(tagName); _lightlessMediator.Publish(new RefreshUiMessage()); } else { - CurrentServerTagStorage().UidServerPairedUserTags[uid] = [tagName]; + CurrentPairTagStorage().UidServerPairedUserTags[uid] = [tagName]; } _pairTagConfig.Save(); } - internal bool ContainsOpenPairTag(string tag) + internal void AddTagForSyncshell(string syncshellName, string tagName) { - return CurrentServerTagStorage().OpenPairTags.Contains(tag); + if (CurrentSyncshellTagStorage().SyncshellPairedTags.TryGetValue(syncshellName, out var tags)) + { + tags.Add(tagName); + _lightlessMediator.Publish(new RefreshUiMessage()); + } + else + { + CurrentPairTagStorage().UidServerPairedUserTags[syncshellName] = [tagName]; + } + + _syncshellTagConfig.Save(); } - internal bool ContainsTag(string uid, string tag) + internal bool ContainsOpenPairTag(string tag) { - if (CurrentServerTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags)) + return CurrentPairTagStorage().OpenPairTags.Contains(tag); + } + + internal bool ContainsPairTag(string uid, string tag) + { + if (CurrentPairTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags)) + { + return tags.Contains(tag, StringComparer.Ordinal); + } + + return false; + } + + internal bool ContainsSyncshellTag(string name, string tag) + { + if (CurrentSyncshellTagStorage().SyncshellPairedTags.TryGetValue(name, out var tags)) { return tags.Contains(tag, StringComparer.Ordinal); } @@ -375,32 +407,37 @@ public class ServerConfigurationManager internal HashSet GetServerAvailablePairTags() { - return CurrentServerTagStorage().ServerAvailablePairTags; + return CurrentPairTagStorage().ServerAvailablePairTags; } internal HashSet GetServerAvailableSyncshellTags() { - return CurrentServerTagStorage().ServerAvailableSyncshellTags; + return CurrentSyncshellTagStorage().ServerAvailableSyncshellTags; } internal Dictionary> GetUidServerPairedUserTags() { - return CurrentServerTagStorage().UidServerPairedUserTags; + return CurrentPairTagStorage().UidServerPairedUserTags; } - internal HashSet GetUidsForTag(string tag) + internal HashSet GetUidsForPairTag(string tag) { - return CurrentServerTagStorage().UidServerPairedUserTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); + return CurrentPairTagStorage().UidServerPairedUserTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); } - internal bool HasTags(string uid) + internal HashSet GetNamesForSyncshellTag(string tag) { - if (CurrentServerTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags)) - { - return tags.Any(); - } + return CurrentPairTagStorage().UidServerPairedUserTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); + } - return false; + internal bool HasPairTags(string uid) + { + return CurrentPairTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags) && tags.Count != 0; + } + + internal bool HasSyncshellTags(string name) + { + return CurrentSyncshellTagStorage().SyncshellPairedTags.TryGetValue(name, out var tags) && tags.Count != 0; } internal void RemoveCharacterFromServer(int serverSelectionIndex, Authentication item) @@ -412,24 +449,42 @@ public class ServerConfigurationManager internal void RemoveOpenPairTag(string tag) { - CurrentServerTagStorage().OpenPairTags.Remove(tag); + CurrentPairTagStorage().OpenPairTags.Remove(tag); _pairTagConfig.Save(); } - internal void RemoveTag(string tag) + internal void RemoveOpenSyncshellTag(string tag) { - CurrentServerTagStorage().ServerAvailablePairTags.Remove(tag); - foreach (var uid in GetUidsForTag(tag)) - { - RemoveTagForUid(uid, tag, save: false); - } + CurrentSyncshellTagStorage().OpenSyncshellTags.Remove(tag); + _syncshellTagConfig.Save(); + } + + internal void RemovePairTag(string tag) + { + RemoveTag(CurrentPairTagStorage().ServerAvailablePairTags, tag); _pairTagConfig.Save(); _lightlessMediator.Publish(new RefreshUiMessage()); } + internal void RemoveSyncshellTag(string tag) + { + RemoveTag(CurrentSyncshellTagStorage().ServerAvailableSyncshellTags, tag); + _syncshellTagConfig.Save(); + _lightlessMediator.Publish(new RefreshUiMessage()); + } + + internal void RemoveTag(HashSet storage, string tag) + { + CurrentPairTagStorage().ServerAvailablePairTags.Remove(tag); + foreach (var uid in GetUidsForPairTag(tag)) + { + RemoveTagForUid(uid, tag, save: false); + } + } + internal void RemoveTagForUid(string uid, string tagName, bool save = true) { - if (CurrentServerTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags)) + if (CurrentPairTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags)) { tags.Remove(tagName); @@ -441,11 +496,35 @@ public class ServerConfigurationManager } } - internal void RenameTag(string oldName, string newName) + internal void RemoveTagForSyncshell(string name, string tagName, bool save = true) { - CurrentServerTagStorage().ServerAvailablePairTags.Remove(oldName); - CurrentServerTagStorage().ServerAvailablePairTags.Add(newName); - foreach (var existingTags in CurrentServerTagStorage().UidServerPairedUserTags.Select(k => k.Value)) + if (CurrentSyncshellTagStorage().SyncshellPairedTags.TryGetValue(name, out var tags)) + { + tags.Remove(tagName); + + if (save) + { + _syncshellTagConfig.Save(); + _lightlessMediator.Publish(new RefreshUiMessage()); + } + } + } + + internal void RenamePairTag(string oldName, string newName) + { + RenameTag(CurrentPairTagStorage().UidServerPairedUserTags, CurrentPairTagStorage().ServerAvailablePairTags, oldName, newName); + } + + internal void RenameSyncshellTag(string oldName, string newName) + { + RenameTag(CurrentSyncshellTagStorage().SyncshellPairedTags, CurrentSyncshellTagStorage().ServerAvailableSyncshellTags, oldName, newName); + } + + internal static void RenameTag(Dictionary> tags, HashSet storage, string oldName, string newName) + { + storage.Remove(oldName); + storage.Add(newName); + foreach (var existingTags in tags.Select(k => k.Value)) { if (existingTags.Remove(oldName)) existingTags.Add(newName); @@ -490,12 +569,18 @@ public class ServerConfigurationManager return _notesConfig.Current.ServerNotes[CurrentApiUrl]; } - private ServerTagStorage CurrentServerTagStorage() + private PairTagStorage CurrentPairTagStorage() { - TryCreateCurrentServerTagStorage(); + TryCreateCurrentPairTagStorage(); return _pairTagConfig.Current.ServerTagStorage[CurrentApiUrl]; } + private SyncshellTagStorage CurrentSyncshellTagStorage() + { + TryCreateCurrentSyncshellTagStorage(); + return _syncshellTagConfig.Current.ServerTagStorage[CurrentApiUrl]; + } + private void EnsureMainExists() { if (_configService.Current.ServerStorage.Count == 0 || !string.Equals(_configService.Current.ServerStorage[0].ServerUri, ApiController.MainServiceUri, StringComparison.OrdinalIgnoreCase)) @@ -513,7 +598,7 @@ public class ServerConfigurationManager } } - private void TryCreateCurrentServerTagStorage() + private void TryCreateCurrentPairTagStorage() { if (!_pairTagConfig.Current.ServerTagStorage.ContainsKey(CurrentApiUrl)) { @@ -521,6 +606,14 @@ public class ServerConfigurationManager } } + private void TryCreateCurrentSyncshellTagStorage() + { + if (!_pairTagConfig.Current.ServerTagStorage.ContainsKey(CurrentApiUrl)) + { + _syncshellTagConfig.Current.ServerTagStorage[CurrentApiUrl] = new(); + } + } + public async Task> GetUIDsWithDiscordToken(string serverUri, string token) { try diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index 02d5975..62af359 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -462,12 +462,14 @@ public class CompactUi : WindowMediatorSubscriberBase bool FilterVisibleUsers(KeyValuePair> u) => u.Key.IsVisible && (_configService.Current.ShowSyncshellUsersInVisible || !(!_configService.Current.ShowSyncshellUsersInVisible && !u.Key.IsDirectlyPaired)); - bool FilterTagusers(KeyValuePair> u, string tag) - => u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && _tagHandler.HasTag(u.Key.UserData.UID, tag); + bool FilterTagUsers(KeyValuePair> u, string tag) + => u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && _tagHandler.HasPairTag(u.Key.UserData.UID, tag); + bool FilterTagSyncshells(KeyValuePair> u, string tag) + => u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && _tagHandler.HasSyncshellTag(u.Key.UserData.UID, tag); bool FilterGroupUsers(KeyValuePair> u, GroupFullInfoDto group) => u.Value.Exists(g => string.Equals(g.GID, group.GID, StringComparison.Ordinal)); bool FilterNotTaggedUsers(KeyValuePair> u) - => u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && !_tagHandler.HasAnyTag(u.Key.UserData.UID); + => u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && !_tagHandler.HasAnyPairTag(u.Key.UserData.UID); bool FilterOfflineUsers(KeyValuePair> u) => ((u.Key.IsDirectlyPaired && _configService.Current.ShowSyncshellOfflineUsersSeparately) || !_configService.Current.ShowSyncshellOfflineUsersSeparately) @@ -521,9 +523,9 @@ public class CompactUi : WindowMediatorSubscriberBase foreach (var tag in tags) { var allTagPairs = ImmutablePairList(allPairs - .Where(u => FilterTagusers(u, tag))); + .Where(u => FilterTagUsers(u, tag))); var filteredTagPairs = BasicSortedDictionary(filteredPairs - .Where(u => FilterTagusers(u, tag) && FilterOnlineOrPausedSelf(u))); + .Where(u => FilterTagUsers(u, tag) && FilterOnlineOrPausedSelf(u))); drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(tag, filteredTagPairs, allTagPairs)); } @@ -533,9 +535,9 @@ public class CompactUi : WindowMediatorSubscriberBase foreach (var syncshelltag in syncshellTags) { var allTagPairs = ImmutablePairList(allPairs - .Where(u => FilterTagusers(u, syncshelltag))); + .Where(u => FilterTagUsers(u, syncshelltag))); var filteredTagPairs = BasicSortedDictionary(filteredPairs - .Where(u => FilterTagusers(u, syncshelltag) && FilterOnlineOrPausedSelf(u))); + .Where(u => FilterTagUsers(u, syncshelltag) && FilterOnlineOrPausedSelf(u))); drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(syncshelltag, filteredTagPairs, allTagPairs)); } diff --git a/LightlessSync/UI/Components/DrawFolderTag.cs b/LightlessSync/UI/Components/DrawFolderTag.cs index 79ec3c0..3dd4195 100644 --- a/LightlessSync/UI/Components/DrawFolderTag.cs +++ b/LightlessSync/UI/Components/DrawFolderTag.cs @@ -112,7 +112,7 @@ public class DrawFolderTag : DrawFolderBase } if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Pair Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) { - _tagHandler.RemoveTag(_id); + _tagHandler.RemovePairTag(_id); } UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently." + Environment.NewLine + "Note: this will not unpair with users in this Group."); diff --git a/LightlessSync/UI/Components/RenameTagUi.cs b/LightlessSync/UI/Components/RenameTagUi.cs index 139353a..aa67a7b 100644 --- a/LightlessSync/UI/Components/RenameTagUi.cs +++ b/LightlessSync/UI/Components/RenameTagUi.cs @@ -77,7 +77,7 @@ public class RenameTagUi public void RenameTag(List pairs, string oldTag, string newTag) { //Removal of old tag - _tagHandler.RemoveTag(oldTag); + _tagHandler.RemovePairTag(oldTag); //Creation of new tag and adding of old group pairs in new one. _tagHandler.AddPairTag(newTag); @@ -86,7 +86,7 @@ public class RenameTagUi var isInTag = _peopleInGroup.Contains(pair.UserData.UID); if (isInTag) { - _tagHandler.AddTagToPairedUid(pair.UserData.UID, newTag); + _tagHandler.AddPairTagToPairedUid(pair.UserData.UID, newTag); } } } diff --git a/LightlessSync/UI/Components/SelectPairForTagUi.cs b/LightlessSync/UI/Components/SelectPairForTagUi.cs index 58caf91..89db40e 100644 --- a/LightlessSync/UI/Components/SelectPairForTagUi.cs +++ b/LightlessSync/UI/Components/SelectPairForTagUi.cs @@ -60,7 +60,7 @@ public class SelectPairForTagUi { if (isInGroup) { - _tagHandler.AddTagToPairedUid(item.UserData.UID, _tag); + _tagHandler.AddPairTagToPairedUid(item.UserData.UID, _tag); _peopleInGroup.Add(item.UserData.UID); } else diff --git a/LightlessSync/UI/Components/SelectTagForPairUi.cs b/LightlessSync/UI/Components/SelectTagForPairUi.cs index c9ee5fa..4c840fb 100644 --- a/LightlessSync/UI/Components/SelectTagForPairUi.cs +++ b/LightlessSync/UI/Components/SelectTagForPairUi.cs @@ -101,13 +101,13 @@ public class SelectTagForPairUi private void DrawGroupName(Pair pair, string name) { - var hasTagBefore = _tagHandler.HasTag(pair.UserData.UID, name); + var hasTagBefore = _tagHandler.HasPairTag(pair.UserData.UID, name); var hasTag = hasTagBefore; if (ImGui.Checkbox(name, ref hasTag)) { if (hasTag) { - _tagHandler.AddTagToPairedUid(pair.UserData.UID, name); + _tagHandler.AddPairTagToPairedUid(pair.UserData.UID, name); } else { @@ -123,7 +123,7 @@ public class SelectTagForPairUi _tagHandler.AddPairTag(_tagNameToAdd); if (_pair != null) { - _tagHandler.AddTagToPairedUid(_pair.UserData.UID, _tagNameToAdd); + _tagHandler.AddPairTagToPairedUid(_pair.UserData.UID, _tagNameToAdd); } _tagNameToAdd = string.Empty; } diff --git a/LightlessSync/UI/Handlers/IdDisplayHandler.cs b/LightlessSync/UI/Handlers/IdDisplayHandler.cs index 2683489..e77093b 100644 --- a/LightlessSync/UI/Handlers/IdDisplayHandler.cs +++ b/LightlessSync/UI/Handlers/IdDisplayHandler.cs @@ -43,9 +43,9 @@ public class IdDisplayHandler if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) { var prevState = textIsUid; - if (_showIdForEntry.ContainsKey(group.GID)) + if (_showIdForEntry.TryGetValue(group.GID, out bool value)) { - prevState = _showIdForEntry[group.GID]; + prevState = value; } _showIdForEntry[group.GID] = !prevState; } diff --git a/LightlessSync/UI/Handlers/TagHandler.cs b/LightlessSync/UI/Handlers/TagHandler.cs index 69d0f28..9790d89 100644 --- a/LightlessSync/UI/Handlers/TagHandler.cs +++ b/LightlessSync/UI/Handlers/TagHandler.cs @@ -17,57 +17,146 @@ public class TagHandler _serverConfigurationManager = serverConfigurationManager; } + /// + /// Creation of an pair tag + /// + /// Name of the tag public void AddPairTag(string tag) => _serverConfigurationManager.AddPairTag(tag); - public void AddSyncshellTag(string tag) => _serverConfigurationManager.AddSyncshellTag(tag); - public void AddTagToPairedUid(string uid, string tagName) => _serverConfigurationManager.AddTagForUid(uid, tagName); + /// + /// Creation of an syncshell tag + /// + /// Name of the tag + public void AddSyncshellTag(string tag) => _serverConfigurationManager.AddSyncshellTag(tag); + + /// + /// Add pair to tag + /// + /// UID that will be added to tag/param> + /// Name of the tag + public void AddPairTagToPairedUid(string uid, string tagName) => _serverConfigurationManager.AddTagForUid(uid, tagName); + + /// + /// Add syncshell to tag + /// + /// Syncshell that will be added to tag/param> + /// Name of the tag + public void AddTagToSyncshell(string name, string tagName) => _serverConfigurationManager.AddTagForSyncshell(name, tagName); + + /// + /// Get all pair tags + /// public List GetAllPairTagsSorted() => [ .. _serverConfigurationManager.GetServerAvailablePairTags() - .OrderBy(s => s, StringComparer.OrdinalIgnoreCase) + .Order(StringComparer.OrdinalIgnoreCase) , ]; + /// + /// Get all syncshell tags + /// public List GetAllSyncshellTagsSorted() => [ .. _serverConfigurationManager.GetServerAvailableSyncshellTags() - .OrderBy(s => s, StringComparer.OrdinalIgnoreCase) + .Order(StringComparer.OrdinalIgnoreCase) , ]; - public HashSet GetOtherUidsForTag(string tag) - { - return _serverConfigurationManager.GetUidsForTag(tag); - } + /// + /// Get all UIDs bound to an given tag + /// + /// Name of the tag + public HashSet GetOtherUidsForTag(string tag) => _serverConfigurationManager.GetUidsForPairTag(tag); - public bool HasAnyTag(string uid) - { - return _serverConfigurationManager.HasTags(uid); - } + /// + /// Get all syncshells bound to an given tag + /// + /// Name of the tag + public HashSet GetOtherSyncshellsForTag(string tag) => _serverConfigurationManager.GetNamesForSyncshellTag(tag); - public bool HasTag(string uid, string tagName) - { - return _serverConfigurationManager.ContainsTag(uid, tagName); - } + /// + /// Checking if the UID is connected to any tag + /// + /// Syncshell that needs to be checked + public bool HasAnyPairTag(string uid) => _serverConfigurationManager.HasPairTags(uid); + + /// + /// Checking if the syncshell is connected to the tag + /// + /// Syncshell that needs to be checked + public bool HasAnySyncshellTag(string name) => _serverConfigurationManager.HasSyncshellTags(name); + + /// + /// Checking if the UID is connected to the tag + /// + /// UID that needs to be checked + /// Name of the tag + public bool HasPairTag(string uid, string tagName) => _serverConfigurationManager.ContainsPairTag(uid, tagName); + + /// + /// Checking if the syncshell is connected to the tag + /// + /// Syncshell that needs to be checked + /// Name of the tag + public bool HasSyncshellTag(string name, string tagName) => _serverConfigurationManager.ContainsSyncshellTag(name, tagName); /// /// Is this tag opened in the paired clients UI? /// /// the tag /// open true/false - public bool IsTagOpen(string tag) + public bool IsTagOpen(string tag) => _serverConfigurationManager.ContainsOpenPairTag(tag); + + /// + /// Removal of Pair Tags from Storage + /// + /// Name of the tag + public void RemovePairTag(string tag) => _serverConfigurationManager.RemovePairTag(tag); + + /// + /// Removal of Syncshell Tags from Storage + /// + /// Name of the tag + public void RemoveSyncshellTag(string tag) => _serverConfigurationManager.RemoveSyncshellTag(tag); + + /// + /// Removal of UID in a Tag + /// + /// UID of user thats bound to the tag + /// Name of the tag + public void RemoveTagFromPairedUid(string uid, string tagName) => _serverConfigurationManager.RemoveTagForUid(uid, tagName); + + /// + /// Removal of Syncshell in a Tag + /// + /// Syncshell thats bound to the tag + /// Name of the tag + public void RemoveTagFromSyncshell(string name, string tagName) => _serverConfigurationManager.RemoveTagForSyncshell(name, tagName); + + /// + /// Rename of a pair tag + /// + /// Old pair tag name + /// New pair tag name + public void RenamePairTag(string oldName, string newName) { - return _serverConfigurationManager.ContainsOpenPairTag(tag); + _serverConfigurationManager.RenamePairTag(oldName, newName); } - public void RemoveTag(string tag) + /// + /// Rename of a syncshell tag + /// + /// Old syncshell tag name + /// New syncshell tag name + public void RenameSyncshellTag(string oldName, string newName) { - _serverConfigurationManager.RemoveTag(tag); - } - - public void RemoveTagFromPairedUid(string uid, string tagName) - { - _serverConfigurationManager.RemoveTagForUid(uid, tagName); + _serverConfigurationManager.RenameSyncshellTag(oldName, newName); } + /// + /// Changes the tag to open/close + /// + /// The Tag that will be modified + /// True/False public void SetTagOpen(string tag, bool open) { if (open) -- 2.49.1 From 900af91013e04c6d3cf7b8502c6df073a912af34 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Mon, 8 Sep 2025 18:27:05 +0200 Subject: [PATCH 3/8] Added UI elements for syncshell folders --- LightlessSync.sln | 8 +- LightlessSync/Plugin.cs | 5 +- .../ServerConfigurationManager.cs | 4 +- LightlessSync/UI/CompactUI.cs | 55 ++++-- .../UI/Components/DrawFolderGroup.cs | 180 +++++++++++------- LightlessSync/UI/Components/DrawFolderTag.cs | 4 +- .../{RenameTagUi.cs => RenamePairTagUi.cs} | 30 +-- .../UI/Components/RenameSyncshellTagUi.cs | 79 ++++++++ .../UI/Components/SelectSyncshellForTagUi.cs | 86 +++++++++ .../UI/Components/SelectTagForSyncshellUi.cs | 132 +++++++++++++ LightlessSync/UI/DrawEntityFactory.cs | 28 ++- 11 files changed, 489 insertions(+), 122 deletions(-) rename LightlessSync/UI/Components/{RenameTagUi.cs => RenamePairTagUi.cs} (68%) create mode 100644 LightlessSync/UI/Components/RenameSyncshellTagUi.cs create mode 100644 LightlessSync/UI/Components/SelectSyncshellForTagUi.cs create mode 100644 LightlessSync/UI/Components/SelectTagForSyncshellUi.cs diff --git a/LightlessSync.sln b/LightlessSync.sln index 5b7ca3c..f24f6b2 100644 --- a/LightlessSync.sln +++ b/LightlessSync.sln @@ -22,16 +22,16 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.ActiveCfg = Release|x64 - {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.Build.0 = Release|x64 + {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.ActiveCfg = Debug|x64 + {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.Build.0 = Debug|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|x64.ActiveCfg = Debug|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|x64.Build.0 = Debug|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|Any CPU.ActiveCfg = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|Any CPU.Build.0 = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|x64.ActiveCfg = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|x64.Build.0 = Release|x64 - {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.ActiveCfg = Release|Any CPU - {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.Build.0 = Release|Any CPU + {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.Build.0 = Debug|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|x64.ActiveCfg = Debug|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|x64.Build.0 = Debug|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/LightlessSync/Plugin.cs b/LightlessSync/Plugin.cs index cf9b41c..239c784 100644 --- a/LightlessSync/Plugin.cs +++ b/LightlessSync/Plugin.cs @@ -130,7 +130,9 @@ public sealed class Plugin : IDalamudPlugin s.GetRequiredService(), s.GetRequiredService())); collection.AddSingleton(); - collection.AddSingleton(); + collection.AddSingleton(); + collection.AddSingleton(); + collection.AddSingleton(); collection.AddSingleton((s) => new EventAggregator(pluginInterface.ConfigDirectory.FullName, s.GetRequiredService>(), s.GetRequiredService())); collection.AddSingleton((s) => new DalamudUtilService(s.GetRequiredService>(), @@ -200,6 +202,7 @@ public sealed class Plugin : IDalamudPlugin collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); + collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); diff --git a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs index fa586f5..2ffdeb7 100644 --- a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -341,7 +341,7 @@ public class ServerConfigurationManager } else { - CurrentPairTagStorage().UidServerPairedUserTags[syncshellName] = [tagName]; + CurrentSyncshellTagStorage().SyncshellPairedTags[syncshellName] = [tagName]; } _syncshellTagConfig.Save(); @@ -608,7 +608,7 @@ public class ServerConfigurationManager private void TryCreateCurrentSyncshellTagStorage() { - if (!_pairTagConfig.Current.ServerTagStorage.ContainsKey(CurrentApiUrl)) + if (!_syncshellTagConfig.Current.ServerTagStorage.ContainsKey(CurrentApiUrl)) { _syncshellTagConfig.Current.ServerTagStorage[CurrentApiUrl] = new(); } diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index 62af359..c15b8d4 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -1,6 +1,5 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; -using Dalamud.Interface.Colors; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Utility; @@ -36,9 +35,12 @@ public class CompactUi : WindowMediatorSubscriberBase private readonly DrawEntityFactory _drawEntityFactory; private readonly FileUploadManager _fileTransferManager; private readonly PairManager _pairManager; - private readonly SelectTagForPairUi _selectGroupForPairUi; + private readonly SelectTagForPairUi _selectTagForPairUi; + private readonly SelectTagForSyncshellUi _selectTagForSyncshellUi; + private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; + private readonly RenameSyncshellTagUi _renameSyncshellTagUi; private readonly SelectPairForTagUi _selectPairsForGroupUi; - private readonly RenameTagUi _renameTagUi; + private readonly RenamePairTagUi _renamePairTagUi; private readonly IpcManager _ipcManager; private readonly ServerConfigurationManager _serverManager; private readonly TopTabMenu _tabMenu; @@ -57,7 +59,9 @@ public class CompactUi : WindowMediatorSubscriberBase public CompactUi(ILogger logger, UiSharedService uiShared, LightlessConfigService configService, ApiController apiController, PairManager pairManager, ServerConfigurationManager serverManager, LightlessMediator mediator, FileUploadManager fileTransferManager, - TagHandler tagHandler, DrawEntityFactory drawEntityFactory, SelectTagForPairUi selectTagForPairUi, SelectPairForTagUi selectPairForTagUi, RenameTagUi renameTagUi, + TagHandler tagHandler, DrawEntityFactory drawEntityFactory, + SelectTagForPairUi selectTagForPairUi, SelectPairForTagUi selectPairForTagUi, RenamePairTagUi renameTagUi, + SelectTagForSyncshellUi selectTagForSyncshellUi, SelectSyncshellForTagUi selectSyncshellForTagUi, RenameSyncshellTagUi renameSyncshellTagUi, PerformanceCollectorService performanceCollectorService, IpcManager ipcManager) : base(logger, mediator, "###LightlessSyncMainUI", performanceCollectorService) { @@ -69,9 +73,12 @@ public class CompactUi : WindowMediatorSubscriberBase _fileTransferManager = fileTransferManager; _tagHandler = tagHandler; _drawEntityFactory = drawEntityFactory; - _selectGroupForPairUi = selectTagForPairUi; + _selectTagForPairUi = selectTagForPairUi; + _selectTagForSyncshellUi = selectTagForSyncshellUi; + _selectSyncshellForTagUi = selectSyncshellForTagUi; + _renameSyncshellTagUi = renameSyncshellTagUi; _selectPairsForGroupUi = selectPairForTagUi; - _renameTagUi = renameTagUi; + _renamePairTagUi = renameTagUi; _ipcManager = ipcManager; _tabMenu = new TopTabMenu(Mediator, _apiController, _pairManager, _uiSharedService); @@ -199,9 +206,12 @@ public class CompactUi : WindowMediatorSubscriberBase float pairlistEnd = ImGui.GetCursorPosY(); using (ImRaii.PushId("transfers")) DrawTransfers(); _transferPartHeight = ImGui.GetCursorPosY() - pairlistEnd - ImGui.GetTextLineHeight(); - using (ImRaii.PushId("group-user-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs); - using (ImRaii.PushId("group-user-edit")) _renameTagUi.Draw(_pairManager.DirectPairs); - using (ImRaii.PushId("grouping-popup")) _selectGroupForPairUi.Draw(); + using (ImRaii.PushId("group-pair-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs); + using (ImRaii.PushId("group-syncshell-popup")) _selectSyncshellForTagUi.Draw(_pairManager.Groups.Values.ToList()); + using (ImRaii.PushId("group-pair-edit")) _renamePairTagUi.Draw(); + using (ImRaii.PushId("group-syncshell-edit")) _renameSyncshellTagUi.Draw(); + using (ImRaii.PushId("grouping-pair-popup")) _selectTagForPairUi.Draw(); + using (ImRaii.PushId("grouping-syncshell-popup")) _selectTagForSyncshellUi.Draw(); } if (_configService.Current.OpenPopupOnAdd && _pairManager.LastAddedUser != null) @@ -534,12 +544,29 @@ public class CompactUi : WindowMediatorSubscriberBase _logger.LogInformation($"Loading {syncshellTags.Count} syncshell tags"); foreach (var syncshelltag in syncshellTags) { - var allTagPairs = ImmutablePairList(allPairs - .Where(u => FilterTagUsers(u, syncshelltag))); - var filteredTagPairs = BasicSortedDictionary(filteredPairs - .Where(u => FilterTagUsers(u, syncshelltag) && FilterOnlineOrPausedSelf(u))); + foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) + { + var allGroupPairs = ImmutablePairList(allPairs + .Where(u => FilterTagSyncshells(u, syncshelltag))); - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(syncshelltag, filteredTagPairs, allTagPairs)); + var filteredGroupPairs = filteredPairs + .Where(u => FilterTagSyncshells(u, syncshelltag) && FilterOnlineOrPausedSelf(u)) + .OrderByDescending(u => u.Key.IsOnline) + .ThenBy(u => + { + if (string.Equals(u.Key.UserData.UID, group.OwnerUID, StringComparison.Ordinal)) return 0; + if (group.GroupPairUserInfos.TryGetValue(u.Key.UserData.UID, out var info)) + { + if (info.IsModerator()) return 1; + if (info.IsPinned()) return 2; + } + return u.Key.IsVisible ? 3 : 4; + }) + .ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase) + .ToDictionary(k => k.Key, k => k.Value); + + groupFolders.Add(_drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs, syncshelltag)); + } } var allOnlineNotTaggedPairs = ImmutablePairList(allPairs diff --git a/LightlessSync/UI/Components/DrawFolderGroup.cs b/LightlessSync/UI/Components/DrawFolderGroup.cs index d6e5b04..a3e9644 100644 --- a/LightlessSync/UI/Components/DrawFolderGroup.cs +++ b/LightlessSync/UI/Components/DrawFolderGroup.cs @@ -19,16 +19,26 @@ public class DrawFolderGroup : DrawFolderBase private readonly GroupFullInfoDto _groupFullInfoDto; private readonly IdDisplayHandler _idDisplayHandler; private readonly LightlessMediator _lightlessMediator; + private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; + private readonly RenameSyncshellTagUi _renameTagUi; + private readonly SelectTagForSyncshellUi _selectTagForSyncshellUi; + private readonly bool _isTag; public DrawFolderGroup(string id, GroupFullInfoDto groupFullInfoDto, ApiController apiController, IImmutableList drawPairs, IImmutableList allPairs, TagHandler tagHandler, IdDisplayHandler idDisplayHandler, - LightlessMediator lightlessMediator, UiSharedService uiSharedService) : + LightlessMediator lightlessMediator, UiSharedService uiSharedService, + SelectSyncshellForTagUi selectSyncshellForTagUi, RenameSyncshellTagUi renameTagUi, SelectTagForSyncshellUi selectTagForSyncshellUi, + bool isTag) : base(id, drawPairs, allPairs, tagHandler, uiSharedService) { _groupFullInfoDto = groupFullInfoDto; _apiController = apiController; _idDisplayHandler = idDisplayHandler; _lightlessMediator = lightlessMediator; + _selectSyncshellForTagUi = selectSyncshellForTagUi; + _renameTagUi = renameTagUi; + _selectTagForSyncshellUi = selectTagForSyncshellUi; + _isTag = isTag; } protected override bool RenderIfEmpty => true; @@ -81,81 +91,109 @@ public class DrawFolderGroup : DrawFolderBase protected override void DrawMenu(float menuWidth) { - ImGui.TextUnformatted("Syncshell Menu (" + _groupFullInfoDto.GroupAliasOrGID + ")"); - ImGui.Separator(); - - ImGui.TextUnformatted("General Syncshell Actions"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Copy, "Copy ID", menuWidth, true)) - { - ImGui.CloseCurrentPopup(); - ImGui.SetClipboardText(_groupFullInfoDto.GroupAliasOrGID); - } - UiSharedService.AttachToolTip("Copy Syncshell ID to Clipboard"); - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.StickyNote, "Copy Notes", menuWidth, true)) - { - ImGui.CloseCurrentPopup(); - ImGui.SetClipboardText(UiSharedService.GetNotes(DrawPairs.Select(k => k.Pair).ToList())); - } - UiSharedService.AttachToolTip("Copies all your notes for all users in this Syncshell to the clipboard." + Environment.NewLine + "They can be imported via Settings -> General -> Notes -> Import notes from clipboard"); - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleLeft, "Leave Syncshell", menuWidth, true) && UiSharedService.CtrlPressed()) - { - _ = _apiController.GroupLeave(_groupFullInfoDto); - ImGui.CloseCurrentPopup(); - } - UiSharedService.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (!string.Equals(_groupFullInfoDto.OwnerUID, _apiController.UID, StringComparison.Ordinal) - ? string.Empty : Environment.NewLine + "WARNING: This action is irreversible" + Environment.NewLine + "Leaving an owned Syncshell will transfer the ownership to a random person in the Syncshell.")); - - ImGui.Separator(); - ImGui.TextUnformatted("Permission Settings"); - var perm = _groupFullInfoDto.GroupUserPermissions; - bool disableSounds = perm.IsDisableSounds(); - bool disableAnims = perm.IsDisableAnimations(); - bool disableVfx = perm.IsDisableVFX(); - - if ((_groupFullInfoDto.GroupPermissions.IsPreferDisableAnimations() != disableAnims - || _groupFullInfoDto.GroupPermissions.IsPreferDisableSounds() != disableSounds - || _groupFullInfoDto.GroupPermissions.IsPreferDisableVFX() != disableVfx) - && _uiSharedService.IconTextButton(FontAwesomeIcon.Check, "Align with suggested permissions", menuWidth, true)) - { - perm.SetDisableVFX(_groupFullInfoDto.GroupPermissions.IsPreferDisableVFX()); - perm.SetDisableSounds(_groupFullInfoDto.GroupPermissions.IsPreferDisableSounds()); - perm.SetDisableAnimations(_groupFullInfoDto.GroupPermissions.IsPreferDisableAnimations()); - _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); - ImGui.CloseCurrentPopup(); - } - - if (_uiSharedService.IconTextButton(disableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeOff, disableSounds ? "Enable Sound Sync" : "Disable Sound Sync", menuWidth, true)) - { - perm.SetDisableSounds(!disableSounds); - _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); - ImGui.CloseCurrentPopup(); - } - - if (_uiSharedService.IconTextButton(disableAnims ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop, disableAnims ? "Enable Animation Sync" : "Disable Animation Sync", menuWidth, true)) - { - perm.SetDisableAnimations(!disableAnims); - _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); - ImGui.CloseCurrentPopup(); - } - - if (_uiSharedService.IconTextButton(disableVfx ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle, disableVfx ? "Enable VFX Sync" : "Disable VFX Sync", menuWidth, true)) - { - perm.SetDisableVFX(!disableVfx); - _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); - ImGui.CloseCurrentPopup(); - } - - if (IsModerator || IsOwner) + if (!_isTag) { + ImGui.TextUnformatted("Syncshell Menu (" + _groupFullInfoDto.GroupAliasOrGID + ")"); ImGui.Separator(); - ImGui.TextUnformatted("Syncshell Admin Functions"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Cog, "Open Admin Panel", menuWidth, true)) + + ImGui.TextUnformatted("General Syncshell Actions"); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Copy, "Copy ID", menuWidth, true)) { ImGui.CloseCurrentPopup(); - _lightlessMediator.Publish(new OpenSyncshellAdminPanel(_groupFullInfoDto)); + ImGui.SetClipboardText(_groupFullInfoDto.GroupAliasOrGID); } + UiSharedService.AttachToolTip("Copy Syncshell ID to Clipboard"); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.StickyNote, "Copy Notes", menuWidth, true)) + { + ImGui.CloseCurrentPopup(); + ImGui.SetClipboardText(UiSharedService.GetNotes(DrawPairs.Select(k => k.Pair).ToList())); + } + UiSharedService.AttachToolTip("Copies all your notes for all users in this Syncshell to the clipboard." + Environment.NewLine + "They can be imported via Settings -> General -> Notes -> Import notes from clipboard"); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Folder, "Syncshell Groups", menuWidth, true)) + { + ImGui.CloseCurrentPopup(); + _selectTagForSyncshellUi.Open(_groupFullInfoDto); + } + UiSharedService.AttachToolTip("Choose syncshell groups for " + _groupFullInfoDto.GID); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleLeft, "Leave Syncshell", menuWidth, true) && UiSharedService.CtrlPressed()) + { + _ = _apiController.GroupLeave(_groupFullInfoDto); + ImGui.CloseCurrentPopup(); + } + UiSharedService.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (!string.Equals(_groupFullInfoDto.OwnerUID, _apiController.UID, StringComparison.Ordinal) + ? string.Empty : Environment.NewLine + "WARNING: This action is irreversible" + Environment.NewLine + "Leaving an owned Syncshell will transfer the ownership to a random person in the Syncshell.")); + + ImGui.Separator(); + ImGui.TextUnformatted("Permission Settings"); + var perm = _groupFullInfoDto.GroupUserPermissions; + bool disableSounds = perm.IsDisableSounds(); + bool disableAnims = perm.IsDisableAnimations(); + bool disableVfx = perm.IsDisableVFX(); + + if ((_groupFullInfoDto.GroupPermissions.IsPreferDisableAnimations() != disableAnims + || _groupFullInfoDto.GroupPermissions.IsPreferDisableSounds() != disableSounds + || _groupFullInfoDto.GroupPermissions.IsPreferDisableVFX() != disableVfx) + && _uiSharedService.IconTextButton(FontAwesomeIcon.Check, "Align with suggested permissions", menuWidth, true)) + { + perm.SetDisableVFX(_groupFullInfoDto.GroupPermissions.IsPreferDisableVFX()); + perm.SetDisableSounds(_groupFullInfoDto.GroupPermissions.IsPreferDisableSounds()); + perm.SetDisableAnimations(_groupFullInfoDto.GroupPermissions.IsPreferDisableAnimations()); + _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); + ImGui.CloseCurrentPopup(); + } + + if (_uiSharedService.IconTextButton(disableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeOff, disableSounds ? "Enable Sound Sync" : "Disable Sound Sync", menuWidth, true)) + { + perm.SetDisableSounds(!disableSounds); + _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); + ImGui.CloseCurrentPopup(); + } + + if (_uiSharedService.IconTextButton(disableAnims ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop, disableAnims ? "Enable Animation Sync" : "Disable Animation Sync", menuWidth, true)) + { + perm.SetDisableAnimations(!disableAnims); + _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); + ImGui.CloseCurrentPopup(); + } + + if (_uiSharedService.IconTextButton(disableVfx ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle, disableVfx ? "Enable VFX Sync" : "Disable VFX Sync", menuWidth, true)) + { + perm.SetDisableVFX(!disableVfx); + _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); + ImGui.CloseCurrentPopup(); + } + + if (IsModerator || IsOwner) + { + ImGui.Separator(); + ImGui.TextUnformatted("Syncshell Admin Functions"); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Cog, "Open Admin Panel", menuWidth, true)) + { + ImGui.CloseCurrentPopup(); + _lightlessMediator.Publish(new OpenSyncshellAdminPanel(_groupFullInfoDto)); + } + } + } + else + { + ImGui.TextUnformatted("Group Menu"); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Syncshells", menuWidth, isInPopup: true)) + { + _selectSyncshellForTagUi.Open(_id); + } + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Syncshell Group", menuWidth, isInPopup: true)) + { + _renameTagUi.Open(_id); + } + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) + { + _tagHandler.RemoveSyncshellTag(_id); + } + UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently." + Environment.NewLine + + "Note: this will not unpair the Group."); } } diff --git a/LightlessSync/UI/Components/DrawFolderTag.cs b/LightlessSync/UI/Components/DrawFolderTag.cs index 3dd4195..0c114e1 100644 --- a/LightlessSync/UI/Components/DrawFolderTag.cs +++ b/LightlessSync/UI/Components/DrawFolderTag.cs @@ -13,10 +13,10 @@ public class DrawFolderTag : DrawFolderBase { private readonly ApiController _apiController; private readonly SelectPairForTagUi _selectPairForTagUi; - private readonly RenameTagUi _renameTagUi; + private readonly RenamePairTagUi _renameTagUi; public DrawFolderTag(string id, IImmutableList drawPairs, IImmutableList allPairs, - TagHandler tagHandler, ApiController apiController, SelectPairForTagUi selectPairForTagUi, RenameTagUi renameTagUi, UiSharedService uiSharedService) + TagHandler tagHandler, ApiController apiController, SelectPairForTagUi selectPairForTagUi, RenamePairTagUi renameTagUi, UiSharedService uiSharedService) : base(id, drawPairs, allPairs, tagHandler, uiSharedService) { _apiController = apiController; diff --git a/LightlessSync/UI/Components/RenameTagUi.cs b/LightlessSync/UI/Components/RenamePairTagUi.cs similarity index 68% rename from LightlessSync/UI/Components/RenameTagUi.cs rename to LightlessSync/UI/Components/RenamePairTagUi.cs index aa67a7b..aa77783 100644 --- a/LightlessSync/UI/Components/RenameTagUi.cs +++ b/LightlessSync/UI/Components/RenamePairTagUi.cs @@ -1,36 +1,34 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; -using LightlessSync.PlayerData.Pairs; using LightlessSync.UI.Handlers; using System.Numerics; namespace LightlessSync.UI.Components; -public class RenameTagUi +public class RenamePairTagUi { private readonly TagHandler _tagHandler; private readonly UiSharedService _uiSharedService; private string _desiredName = string.Empty; private bool _opened = false; - private HashSet _peopleInGroup = new(StringComparer.Ordinal); private bool _show = false; private string _tag = string.Empty; - public RenameTagUi(TagHandler tagHandler, UiSharedService uiSharedService) + public RenamePairTagUi(TagHandler tagHandler, UiSharedService uiSharedService) { _tagHandler = tagHandler; _uiSharedService = uiSharedService; } - public void Draw(List pairs) + public void Draw() { var workHeight = ImGui.GetMainViewport().WorkSize.Y / ImGuiHelpers.GlobalScale; var minSize = new Vector2(300, workHeight < 110 ? workHeight : 110) * ImGuiHelpers.GlobalScale; var maxSize = new Vector2(300, 110) * ImGuiHelpers.GlobalScale; - var popupName = $"Renaming Group {_tag}"; + var popupName = $"Renaming Pair Group {_tag}"; if (!_show) { @@ -55,7 +53,7 @@ public class RenameTagUi { if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.Plus, "Rename Group")) { - RenameTag(pairs, _tag, _desiredName); + RenameTag(_tag, _desiredName); _show = false; } } @@ -69,25 +67,13 @@ public class RenameTagUi public void Open(string tag) { - _peopleInGroup = _tagHandler.GetOtherUidsForTag(tag); _tag = tag; _desiredName = ""; _show = true; } - public void RenameTag(List pairs, string oldTag, string newTag) - { - //Removal of old tag - _tagHandler.RemovePairTag(oldTag); - //Creation of new tag and adding of old group pairs in new one. - _tagHandler.AddPairTag(newTag); - foreach (Pair pair in pairs) - { - var isInTag = _peopleInGroup.Contains(pair.UserData.UID); - if (isInTag) - { - _tagHandler.AddPairTagToPairedUid(pair.UserData.UID, newTag); - } - } + public void RenameTag(string oldTag, string newTag) + { + _tagHandler.RenamePairTag(oldTag, newTag); } } \ No newline at end of file diff --git a/LightlessSync/UI/Components/RenameSyncshellTagUi.cs b/LightlessSync/UI/Components/RenameSyncshellTagUi.cs new file mode 100644 index 0000000..a4edcde --- /dev/null +++ b/LightlessSync/UI/Components/RenameSyncshellTagUi.cs @@ -0,0 +1,79 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using LightlessSync.UI.Handlers; + +using System.Numerics; + +namespace LightlessSync.UI.Components; + +public class RenameSyncshellTagUi +{ + private readonly TagHandler _tagHandler; + private readonly UiSharedService _uiSharedService; + private string _desiredName = string.Empty; + private bool _opened = false; + private bool _show = false; + private string _tag = string.Empty; + + public RenameSyncshellTagUi(TagHandler tagHandler, UiSharedService uiSharedService) + { + _tagHandler = tagHandler; + _uiSharedService = uiSharedService; + } + + public void Draw() + { + var workHeight = ImGui.GetMainViewport().WorkSize.Y / ImGuiHelpers.GlobalScale; + var minSize = new Vector2(300, workHeight < 110 ? workHeight : 110) * ImGuiHelpers.GlobalScale; + var maxSize = new Vector2(300, 110) * ImGuiHelpers.GlobalScale; + + var popupName = $"Renaming Pair Group {_tag}"; + + if (!_show) + { + _opened = false; + } + + if (_show && !_opened) + { + ImGui.SetNextWindowSize(minSize); + UiSharedService.CenterNextWindow(minSize.X, minSize.Y, ImGuiCond.Always); + ImGui.OpenPopup(popupName); + _opened = true; + } + + ImGui.SetNextWindowSizeConstraints(minSize, maxSize); + if (ImGui.BeginPopupModal(popupName, ref _show, ImGuiWindowFlags.Popup | ImGuiWindowFlags.Modal)) + { + ImGui.TextUnformatted($"Renaming {_tag}"); + + ImGui.InputTextWithHint("##desiredname", "Enter new group name", ref _desiredName, 255, ImGuiInputTextFlags.None); + using (ImRaii.Disabled(string.IsNullOrEmpty(_desiredName))) + { + if (_uiSharedService.IconTextButton(Dalamud.Interface.FontAwesomeIcon.Plus, "Rename Group")) + { + RenameTag(_tag, _desiredName); + _show = false; + } + } + ImGui.EndPopup(); + } + else + { + _show = false; + } + } + + public void Open(string tag) + { + _tag = tag; + _desiredName = ""; + _show = true; + } + + public void RenameTag(string oldTag, string newTag) + { + _tagHandler.RenamePairTag(oldTag, newTag); + } +} \ No newline at end of file diff --git a/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs b/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs new file mode 100644 index 0000000..288776c --- /dev/null +++ b/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs @@ -0,0 +1,86 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Interface.Utility; +using LightlessSync.API.Dto.Group; +using LightlessSync.UI.Handlers; + +using System.Numerics; + +namespace LightlessSync.UI.Components; + +public class SelectSyncshellForTagUi +{ + private readonly TagHandler _tagHandler; + private string _filter = string.Empty; + private bool _opened = false; + private HashSet _syncshellsInGroup = new(StringComparer.Ordinal); + private bool _show = false; + private string _tag = string.Empty; + + public SelectSyncshellForTagUi(TagHandler tagHandler) + { + _tagHandler = tagHandler; + } + + public void Draw(List groups) + { + var workHeight = ImGui.GetMainViewport().WorkSize.Y / ImGuiHelpers.GlobalScale; + var minSize = new Vector2(300, workHeight < 400 ? workHeight : 400) * ImGuiHelpers.GlobalScale; + var maxSize = new Vector2(300, 1000) * ImGuiHelpers.GlobalScale; + + var popupName = $"Choose Syncshells for Group {_tag}"; + + if (!_show) + { + _opened = false; + } + + if (_show && !_opened) + { + ImGui.SetNextWindowSize(minSize); + UiSharedService.CenterNextWindow(minSize.X, minSize.Y, ImGuiCond.Always); + ImGui.OpenPopup(popupName); + _opened = true; + } + + ImGui.SetNextWindowSizeConstraints(minSize, maxSize); + if (ImGui.BeginPopupModal(popupName, ref _show, ImGuiWindowFlags.Popup | ImGuiWindowFlags.Modal)) + { + ImGui.TextUnformatted($"Select syncshells for group {_tag}"); + + ImGui.InputTextWithHint("##filter", "Filter", ref _filter, 255, ImGuiInputTextFlags.None); + foreach (var group in groups + .Where(g => string.IsNullOrEmpty(_filter) || g.GID.Contains(_filter, StringComparison.OrdinalIgnoreCase)) + .OrderBy(g => g.GID, StringComparer.OrdinalIgnoreCase) + .ToList()) + { + var isInGroup = _syncshellsInGroup.Contains(group.GID); + if (ImGui.Checkbox(group.GID, ref isInGroup)) + { + if (isInGroup) + { + _tagHandler.AddTagToSyncshell(group.GID, _tag); + _syncshellsInGroup.Add(group.GID); + } + else + { + _tagHandler.RemoveTagFromSyncshell(group.GID, _tag); + _syncshellsInGroup.Remove(group.GID); + } + } + } + ImGui.EndPopup(); + } + else + { + _filter = string.Empty; + _show = false; + } + } + + public void Open(string tag) + { + _syncshellsInGroup = _tagHandler.GetOtherSyncshellsForTag(tag); + _tag = tag; + _show = true; + } +} \ No newline at end of file diff --git a/LightlessSync/UI/Components/SelectTagForSyncshellUi.cs b/LightlessSync/UI/Components/SelectTagForSyncshellUi.cs new file mode 100644 index 0000000..5473263 --- /dev/null +++ b/LightlessSync/UI/Components/SelectTagForSyncshellUi.cs @@ -0,0 +1,132 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Utility; +using LightlessSync.API.Dto.Group; +using LightlessSync.UI.Handlers; + +using System.Numerics; + +namespace LightlessSync.UI.Components; + +public class SelectTagForSyncshellUi +{ + private readonly TagHandler _tagHandler; + private readonly UiSharedService _uiSharedService; + + /// + /// The group UI is always open for a specific pair. This defines which pair the UI is open for. + /// + /// + private GroupFullInfoDto? _group; + + /// + /// Should the panel show, yes/no + /// + private bool _show; + + /// + /// For the add category option, this stores the currently typed in tag name + /// + private string _tagNameToAdd = ""; + + public SelectTagForSyncshellUi(TagHandler tagHandler, UiSharedService uiSharedService) + { + _show = false; + _group = null; + _tagHandler = tagHandler; + _uiSharedService = uiSharedService; + } + + public void Draw() + { + if (_group == null) + { + return; + } + + var name = _group.GID; + var popupName = $"Choose Groups for {_group.GID}"; + // Is the popup supposed to show but did not open yet? Open it + if (_show) + { + ImGui.OpenPopup(popupName); + _show = false; + } + + if (ImGui.BeginPopup(popupName)) + { + var tags = _tagHandler.GetAllSyncshellTagsSorted(); + var childHeight = tags.Count != 0 ? tags.Count * 25 : 1; + var childSize = new Vector2(0, childHeight > 100 ? 100 : childHeight) * ImGuiHelpers.GlobalScale; + + ImGui.TextUnformatted($"Select the groups you want {name} to be in."); + if (ImGui.BeginChild(name + "##listGroups", childSize)) + { + foreach (var tag in tags) + { + using (ImRaii.PushId($"groups-syncshell-{_group.GID}-{tag}")) DrawGroupName(_group, tag); + } + ImGui.EndChild(); + } + + ImGui.Separator(); + ImGui.TextUnformatted($"Create a new group for {name}."); + if (_uiSharedService.IconButton(FontAwesomeIcon.Plus)) + { + HandleAddTag(); + } + ImGui.SameLine(); + ImGui.InputTextWithHint("##category_name", "New Group", ref _tagNameToAdd, 40); + if (ImGui.IsKeyDown(ImGuiKey.Enter)) + { + HandleAddTag(); + } + ImGui.EndPopup(); + } + } + + public void Open(GroupFullInfoDto group) + { + _group = group; + // Using "_show" here to de-couple the opening of the popup + // The popup name is derived from the name the user currently sees, which is + // based on the showUidForEntry dictionary. + // We'd have to derive the name here to open it popup modal here, when the Open() is called + _show = true; + } + + private void DrawGroupName(GroupFullInfoDto group, string name) + { + var hasTag = _tagHandler.HasSyncshellTag(group.GID, name); + if (ImGui.Checkbox(name, ref hasTag)) + { + if (hasTag) + { + _tagHandler.AddTagToSyncshell(group.GID, name); + } + else + { + _tagHandler.RemoveTagFromSyncshell(group.GID, name); + } + } + } + + private void HandleAddTag() + { + if (!_tagNameToAdd.IsNullOrWhitespace()) + { + _tagHandler.AddSyncshellTag(_tagNameToAdd); + if (_group != null) + { + _tagHandler.AddTagToSyncshell(_group.GID, _tagNameToAdd); + } + _tagNameToAdd = string.Empty; + } + else + { + _tagNameToAdd = string.Empty; + } + } +} \ No newline at end of file diff --git a/LightlessSync/UI/DrawEntityFactory.cs b/LightlessSync/UI/DrawEntityFactory.cs index 01b6738..625d660 100644 --- a/LightlessSync/UI/DrawEntityFactory.cs +++ b/LightlessSync/UI/DrawEntityFactory.cs @@ -23,21 +23,25 @@ public class DrawEntityFactory private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; private readonly CharaDataManager _charaDataManager; private readonly SelectTagForPairUi _selectTagForPairUi; - private readonly RenameTagUi _renameTagUi; + private readonly RenamePairTagUi _renamePairTagUi; + private readonly SelectTagForSyncshellUi _selectTagForSyncshellUi; + private readonly RenameSyncshellTagUi _renameSyncshellTagUi; + private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; private readonly TagHandler _tagHandler; private readonly IdDisplayHandler _uidDisplayHandler; public DrawEntityFactory(ILogger logger, ApiController apiController, IdDisplayHandler uidDisplayHandler, - SelectTagForPairUi selectTagForPairUi, RenameTagUi renameTagUi, LightlessMediator mediator, + SelectTagForPairUi selectTagForPairUi, RenamePairTagUi renamePairTagUi, LightlessMediator mediator, TagHandler tagHandler, SelectPairForTagUi selectPairForTagUi, ServerConfigurationManager serverConfigurationManager, UiSharedService uiSharedService, - PlayerPerformanceConfigService playerPerformanceConfigService, CharaDataManager charaDataManager) + PlayerPerformanceConfigService playerPerformanceConfigService, CharaDataManager charaDataManager, + SelectTagForSyncshellUi selectTagForSyncshellUi, RenameSyncshellTagUi renameSyncshellTagUi, SelectSyncshellForTagUi selectSyncshellForTagUi) { _logger = logger; _apiController = apiController; _uidDisplayHandler = uidDisplayHandler; _selectTagForPairUi = selectTagForPairUi; - _renameTagUi = renameTagUi; + _renamePairTagUi = renamePairTagUi; _mediator = mediator; _tagHandler = tagHandler; _selectPairForTagUi = selectPairForTagUi; @@ -45,6 +49,9 @@ public class DrawEntityFactory _uiSharedService = uiSharedService; _playerPerformanceConfigService = playerPerformanceConfigService; _charaDataManager = charaDataManager; + _selectTagForSyncshellUi = selectTagForSyncshellUi; + _renameSyncshellTagUi = renameSyncshellTagUi; + _selectSyncshellForTagUi = selectSyncshellForTagUi; } public DrawFolderGroup CreateDrawGroupFolder(GroupFullInfoDto groupFullInfoDto, @@ -53,7 +60,16 @@ public class DrawEntityFactory { return new DrawFolderGroup(groupFullInfoDto.Group.GID, groupFullInfoDto, _apiController, filteredPairs.Select(p => CreateDrawPair(groupFullInfoDto.Group.GID + p.Key.UserData.UID, p.Key, p.Value, groupFullInfoDto)).ToImmutableList(), - allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService); + allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, _selectTagForSyncshellUi, false); + } + + public DrawFolderGroup CreateDrawGroupFolder(GroupFullInfoDto groupFullInfoDto, + Dictionary> filteredPairs, + IImmutableList allPairs, string tag) + { + return new DrawFolderGroup(tag, groupFullInfoDto, _apiController, + filteredPairs.Select(p => CreateDrawPair(tag, p.Key, p.Value, groupFullInfoDto)).ToImmutableList(), + allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, _selectTagForSyncshellUi, true); } public DrawFolderTag CreateDrawTagFolder(string tag, @@ -61,7 +77,7 @@ public class DrawEntityFactory IImmutableList allPairs) { return new(tag, filteredPairs.Select(u => CreateDrawPair(tag, u.Key, u.Value, currentGroup: null)).ToImmutableList(), - allPairs, _tagHandler, _apiController, _selectPairForTagUi, _renameTagUi, _uiSharedService); + allPairs, _tagHandler, _apiController, _selectPairForTagUi, _renamePairTagUi, _uiSharedService); } public DrawUserPair CreateDrawPair(string id, Pair user, List groups, GroupFullInfoDto? currentGroup) -- 2.49.1 From 08e3b19f41fde58a32fad0e4838b55e7fa5e143f Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Mon, 8 Sep 2025 22:21:36 +0200 Subject: [PATCH 4/8] Added new folder type for syncshells, changes in factory --- LightlessSync/UI/CompactUI.cs | 46 +++-- .../UI/Components/DrawFolderGroup.cs | 185 ++++++++---------- .../DrawGroupedSyncshellTagFolder.cs | 81 ++++++++ .../UI/Components/SelectTagForSyncshellUi.cs | 4 +- LightlessSync/UI/DrawEntityFactory.cs | 11 +- 5 files changed, 189 insertions(+), 138 deletions(-) create mode 100644 LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index c15b8d4..659f542 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -7,6 +7,7 @@ using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto.Group; using LightlessSync.Interop.Ipc; using LightlessSync.LightlessConfiguration; +using LightlessSync.LightlessConfiguration.Configurations; using LightlessSync.PlayerData.Handlers; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; @@ -474,8 +475,6 @@ public class CompactUi : WindowMediatorSubscriberBase && (_configService.Current.ShowSyncshellUsersInVisible || !(!_configService.Current.ShowSyncshellUsersInVisible && !u.Key.IsDirectlyPaired)); bool FilterTagUsers(KeyValuePair> u, string tag) => u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && _tagHandler.HasPairTag(u.Key.UserData.UID, tag); - bool FilterTagSyncshells(KeyValuePair> u, string tag) - => u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && _tagHandler.HasSyncshellTag(u.Key.UserData.UID, tag); bool FilterGroupUsers(KeyValuePair> u, GroupFullInfoDto group) => u.Value.Exists(g => string.Equals(g.GID, group.GID, StringComparison.Ordinal)); bool FilterNotTaggedUsers(KeyValuePair> u) @@ -499,6 +498,7 @@ public class CompactUi : WindowMediatorSubscriberBase } List groupFolders = new(); + foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) { var allGroupPairs = ImmutablePairList(allPairs @@ -544,28 +544,36 @@ public class CompactUi : WindowMediatorSubscriberBase _logger.LogInformation($"Loading {syncshellTags.Count} syncshell tags"); foreach (var syncshelltag in syncshellTags) { + List syncshellFolderTags = new(); foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) { - var allGroupPairs = ImmutablePairList(allPairs - .Where(u => FilterTagSyncshells(u, syncshelltag))); + if (_tagHandler.HasSyncshellTag(group.GID, syncshelltag)) + { + var allGroupPairs = ImmutablePairList(allPairs + .Where(u => FilterGroupUsers(u, group))); - var filteredGroupPairs = filteredPairs - .Where(u => FilterTagSyncshells(u, syncshelltag) && FilterOnlineOrPausedSelf(u)) - .OrderByDescending(u => u.Key.IsOnline) - .ThenBy(u => - { - if (string.Equals(u.Key.UserData.UID, group.OwnerUID, StringComparison.Ordinal)) return 0; - if (group.GroupPairUserInfos.TryGetValue(u.Key.UserData.UID, out var info)) + var filteredGroupPairs = filteredPairs + .Where(u => FilterOnlineOrPausedSelf(u)) + .OrderByDescending(u => u.Key.IsOnline) + .ThenBy(u => { - if (info.IsModerator()) return 1; - if (info.IsPinned()) return 2; - } - return u.Key.IsVisible ? 3 : 4; - }) - .ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase) - .ToDictionary(k => k.Key, k => k.Value); + if (string.Equals(u.Key.UserData.UID, group.OwnerUID, StringComparison.Ordinal)) return 0; + if (group.GroupPairUserInfos.TryGetValue(u.Key.UserData.UID, out var info)) + { + if (info.IsModerator()) return 1; + if (info.IsPinned()) return 2; + } + return u.Key.IsVisible ? 3 : 4; + }) + .ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase) + .ToDictionary(k => k.Key, k => k.Value); + syncshellFolderTags.Add(_drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs)); + } + } - groupFolders.Add(_drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs, syncshelltag)); + if (syncshellFolderTags.Count > 0) + { + drawFolders.Add(new DrawGroupedSyncshellTagFolder(syncshelltag, syncshellFolderTags, _tagHandler, _uiSharedService)); } } diff --git a/LightlessSync/UI/Components/DrawFolderGroup.cs b/LightlessSync/UI/Components/DrawFolderGroup.cs index a3e9644..58d0a64 100644 --- a/LightlessSync/UI/Components/DrawFolderGroup.cs +++ b/LightlessSync/UI/Components/DrawFolderGroup.cs @@ -19,26 +19,18 @@ public class DrawFolderGroup : DrawFolderBase private readonly GroupFullInfoDto _groupFullInfoDto; private readonly IdDisplayHandler _idDisplayHandler; private readonly LightlessMediator _lightlessMediator; - private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; - private readonly RenameSyncshellTagUi _renameTagUi; private readonly SelectTagForSyncshellUi _selectTagForSyncshellUi; - private readonly bool _isTag; public DrawFolderGroup(string id, GroupFullInfoDto groupFullInfoDto, ApiController apiController, IImmutableList drawPairs, IImmutableList allPairs, TagHandler tagHandler, IdDisplayHandler idDisplayHandler, - LightlessMediator lightlessMediator, UiSharedService uiSharedService, - SelectSyncshellForTagUi selectSyncshellForTagUi, RenameSyncshellTagUi renameTagUi, SelectTagForSyncshellUi selectTagForSyncshellUi, - bool isTag) : + LightlessMediator lightlessMediator, UiSharedService uiSharedService, SelectTagForSyncshellUi selectTagForSyncshellUi) : base(id, drawPairs, allPairs, tagHandler, uiSharedService) { _groupFullInfoDto = groupFullInfoDto; _apiController = apiController; _idDisplayHandler = idDisplayHandler; _lightlessMediator = lightlessMediator; - _selectSyncshellForTagUi = selectSyncshellForTagUi; - _renameTagUi = renameTagUi; _selectTagForSyncshellUi = selectTagForSyncshellUi; - _isTag = isTag; } protected override bool RenderIfEmpty => true; @@ -91,109 +83,88 @@ public class DrawFolderGroup : DrawFolderBase protected override void DrawMenu(float menuWidth) { - if (!_isTag) + ImGui.TextUnformatted("Syncshell Menu (" + _groupFullInfoDto.GroupAliasOrGID + ")"); + ImGui.Separator(); + + ImGui.TextUnformatted("General Syncshell Actions"); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Copy, "Copy ID", menuWidth, true)) { - ImGui.TextUnformatted("Syncshell Menu (" + _groupFullInfoDto.GroupAliasOrGID + ")"); - ImGui.Separator(); + ImGui.CloseCurrentPopup(); + ImGui.SetClipboardText(_groupFullInfoDto.GroupAliasOrGID); + } + UiSharedService.AttachToolTip("Copy Syncshell ID to Clipboard"); - ImGui.TextUnformatted("General Syncshell Actions"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Copy, "Copy ID", menuWidth, true)) - { - ImGui.CloseCurrentPopup(); - ImGui.SetClipboardText(_groupFullInfoDto.GroupAliasOrGID); - } - UiSharedService.AttachToolTip("Copy Syncshell ID to Clipboard"); - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.StickyNote, "Copy Notes", menuWidth, true)) - { - ImGui.CloseCurrentPopup(); - ImGui.SetClipboardText(UiSharedService.GetNotes(DrawPairs.Select(k => k.Pair).ToList())); - } - UiSharedService.AttachToolTip("Copies all your notes for all users in this Syncshell to the clipboard." + Environment.NewLine + "They can be imported via Settings -> General -> Notes -> Import notes from clipboard"); - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Folder, "Syncshell Groups", menuWidth, true)) - { - ImGui.CloseCurrentPopup(); - _selectTagForSyncshellUi.Open(_groupFullInfoDto); - } - UiSharedService.AttachToolTip("Choose syncshell groups for " + _groupFullInfoDto.GID); - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleLeft, "Leave Syncshell", menuWidth, true) && UiSharedService.CtrlPressed()) - { - _ = _apiController.GroupLeave(_groupFullInfoDto); - ImGui.CloseCurrentPopup(); - } - UiSharedService.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (!string.Equals(_groupFullInfoDto.OwnerUID, _apiController.UID, StringComparison.Ordinal) - ? string.Empty : Environment.NewLine + "WARNING: This action is irreversible" + Environment.NewLine + "Leaving an owned Syncshell will transfer the ownership to a random person in the Syncshell.")); - - ImGui.Separator(); - ImGui.TextUnformatted("Permission Settings"); - var perm = _groupFullInfoDto.GroupUserPermissions; - bool disableSounds = perm.IsDisableSounds(); - bool disableAnims = perm.IsDisableAnimations(); - bool disableVfx = perm.IsDisableVFX(); - - if ((_groupFullInfoDto.GroupPermissions.IsPreferDisableAnimations() != disableAnims - || _groupFullInfoDto.GroupPermissions.IsPreferDisableSounds() != disableSounds - || _groupFullInfoDto.GroupPermissions.IsPreferDisableVFX() != disableVfx) - && _uiSharedService.IconTextButton(FontAwesomeIcon.Check, "Align with suggested permissions", menuWidth, true)) - { - perm.SetDisableVFX(_groupFullInfoDto.GroupPermissions.IsPreferDisableVFX()); - perm.SetDisableSounds(_groupFullInfoDto.GroupPermissions.IsPreferDisableSounds()); - perm.SetDisableAnimations(_groupFullInfoDto.GroupPermissions.IsPreferDisableAnimations()); - _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); - ImGui.CloseCurrentPopup(); - } - - if (_uiSharedService.IconTextButton(disableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeOff, disableSounds ? "Enable Sound Sync" : "Disable Sound Sync", menuWidth, true)) - { - perm.SetDisableSounds(!disableSounds); - _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); - ImGui.CloseCurrentPopup(); - } - - if (_uiSharedService.IconTextButton(disableAnims ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop, disableAnims ? "Enable Animation Sync" : "Disable Animation Sync", menuWidth, true)) - { - perm.SetDisableAnimations(!disableAnims); - _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); - ImGui.CloseCurrentPopup(); - } - - if (_uiSharedService.IconTextButton(disableVfx ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle, disableVfx ? "Enable VFX Sync" : "Disable VFX Sync", menuWidth, true)) - { - perm.SetDisableVFX(!disableVfx); - _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); - ImGui.CloseCurrentPopup(); - } - - if (IsModerator || IsOwner) - { - ImGui.Separator(); - ImGui.TextUnformatted("Syncshell Admin Functions"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Cog, "Open Admin Panel", menuWidth, true)) - { - ImGui.CloseCurrentPopup(); - _lightlessMediator.Publish(new OpenSyncshellAdminPanel(_groupFullInfoDto)); - } - } - } - else + if (_uiSharedService.IconTextButton(FontAwesomeIcon.StickyNote, "Copy Notes", menuWidth, true)) { - ImGui.TextUnformatted("Group Menu"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Syncshells", menuWidth, isInPopup: true)) + ImGui.CloseCurrentPopup(); + ImGui.SetClipboardText(UiSharedService.GetNotes(DrawPairs.Select(k => k.Pair).ToList())); + } + UiSharedService.AttachToolTip("Copies all your notes for all users in this Syncshell to the clipboard." + Environment.NewLine + "They can be imported via Settings -> General -> Notes -> Import notes from clipboard"); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Folder, "Syncshell Groups", menuWidth, true)) + { + ImGui.CloseCurrentPopup(); + _selectTagForSyncshellUi.Open(_groupFullInfoDto); + } + UiSharedService.AttachToolTip("Choose syncshell groups for " + _groupFullInfoDto.GID); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleLeft, "Leave Syncshell", menuWidth, true) && UiSharedService.CtrlPressed()) + { + _ = _apiController.GroupLeave(_groupFullInfoDto); + ImGui.CloseCurrentPopup(); + } + UiSharedService.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (!string.Equals(_groupFullInfoDto.OwnerUID, _apiController.UID, StringComparison.Ordinal) + ? string.Empty : Environment.NewLine + "WARNING: This action is irreversible" + Environment.NewLine + "Leaving an owned Syncshell will transfer the ownership to a random person in the Syncshell.")); + + ImGui.Separator(); + ImGui.TextUnformatted("Permission Settings"); + var perm = _groupFullInfoDto.GroupUserPermissions; + bool disableSounds = perm.IsDisableSounds(); + bool disableAnims = perm.IsDisableAnimations(); + bool disableVfx = perm.IsDisableVFX(); + + if ((_groupFullInfoDto.GroupPermissions.IsPreferDisableAnimations() != disableAnims + || _groupFullInfoDto.GroupPermissions.IsPreferDisableSounds() != disableSounds + || _groupFullInfoDto.GroupPermissions.IsPreferDisableVFX() != disableVfx) + && _uiSharedService.IconTextButton(FontAwesomeIcon.Check, "Align with suggested permissions", menuWidth, true)) + { + perm.SetDisableVFX(_groupFullInfoDto.GroupPermissions.IsPreferDisableVFX()); + perm.SetDisableSounds(_groupFullInfoDto.GroupPermissions.IsPreferDisableSounds()); + perm.SetDisableAnimations(_groupFullInfoDto.GroupPermissions.IsPreferDisableAnimations()); + _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); + ImGui.CloseCurrentPopup(); + } + + if (_uiSharedService.IconTextButton(disableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeOff, disableSounds ? "Enable Sound Sync" : "Disable Sound Sync", menuWidth, true)) + { + perm.SetDisableSounds(!disableSounds); + _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); + ImGui.CloseCurrentPopup(); + } + + if (_uiSharedService.IconTextButton(disableAnims ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop, disableAnims ? "Enable Animation Sync" : "Disable Animation Sync", menuWidth, true)) + { + perm.SetDisableAnimations(!disableAnims); + _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); + ImGui.CloseCurrentPopup(); + } + + if (_uiSharedService.IconTextButton(disableVfx ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle, disableVfx ? "Enable VFX Sync" : "Disable VFX Sync", menuWidth, true)) + { + perm.SetDisableVFX(!disableVfx); + _ = _apiController.GroupChangeIndividualPermissionState(new(_groupFullInfoDto.Group, new(_apiController.UID), perm)); + ImGui.CloseCurrentPopup(); + } + + if (IsModerator || IsOwner) + { + ImGui.Separator(); + ImGui.TextUnformatted("Syncshell Admin Functions"); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Cog, "Open Admin Panel", menuWidth, true)) { - _selectSyncshellForTagUi.Open(_id); + ImGui.CloseCurrentPopup(); + _lightlessMediator.Publish(new OpenSyncshellAdminPanel(_groupFullInfoDto)); } - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Syncshell Group", menuWidth, isInPopup: true)) - { - _renameTagUi.Open(_id); - } - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) - { - _tagHandler.RemoveSyncshellTag(_id); - } - UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently." + Environment.NewLine + - "Note: this will not unpair the Group."); } } diff --git a/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs b/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs new file mode 100644 index 0000000..85559ac --- /dev/null +++ b/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs @@ -0,0 +1,81 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using Dalamud.Interface.Utility.Raii; +using LightlessSync.UI.Handlers; +using System.Collections.Immutable; +using System.Numerics; + +namespace LightlessSync.UI.Components; + +public class DrawGroupedSyncshellTagFolder : IDrawFolder +{ + private readonly string _tag; + private readonly IEnumerable _groups; + private readonly TagHandler _tagHandler; + private readonly UiSharedService _uiSharedService; + private bool _wasHovered = false; + + public IImmutableList DrawPairs => throw new NotSupportedException(); + public int OnlinePairs => _groups.SelectMany(g => g.DrawPairs).Where(g => g.Pair.IsOnline).DistinctBy(g => g.Pair.UserData.UID).Count(); + public int TotalPairs => _groups.Sum(g => g.TotalPairs); + + public DrawGroupedSyncshellTagFolder(string tag, IEnumerable groups, TagHandler tagHandler, UiSharedService uiSharedService) + { + _tag = tag; + _groups = groups; + _tagHandler = tagHandler; + _uiSharedService = uiSharedService; + } + + public void Draw() + { + if (!_groups.Any()) return; + + string _id = $"__folder_{_tag}"; + using var id = ImRaii.PushId(_id); + var color = ImRaii.PushColor(ImGuiCol.ChildBg, ImGui.GetColorU32(ImGuiCol.FrameBgHovered), _wasHovered); + using (ImRaii.Child("folder__" + _id, new System.Numerics.Vector2(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX(), ImGui.GetFrameHeight()))) + { + ImGui.Dummy(new Vector2(0f, ImGui.GetFrameHeight())); + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(0f, 0f))) + ImGui.SameLine(); + + var icon = _tagHandler.IsTagOpen(_id) ? FontAwesomeIcon.CaretDown : FontAwesomeIcon.CaretRight; + ImGui.AlignTextToFramePadding(); + + _uiSharedService.IconText(icon); + if (ImGui.IsItemClicked()) + { + _tagHandler.SetTagOpen(_id, !_tagHandler.IsTagOpen(_id)); + } + + ImGui.SameLine(); + ImGui.AlignTextToFramePadding(); + _uiSharedService.IconText(FontAwesomeIcon.UsersRectangle); + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemSpacing.X / 2f })) + { + ImGui.SameLine(); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted("[" + OnlinePairs.ToString() + "]"); + } + UiSharedService.AttachToolTip(OnlinePairs + " online in all of your joined syncshells" + Environment.NewLine + + TotalPairs + " pairs combined in all of your joined syncshells"); + ImGui.SameLine(); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted(_tag); + } + color.Dispose(); + _wasHovered = ImGui.IsItemHovered(); + + ImGui.Separator(); + + if (_tagHandler.IsTagOpen(_id)) + { + using var indent = ImRaii.PushIndent(20f); + foreach (var entry in _groups) + { + entry.Draw(); + } + } + } +} diff --git a/LightlessSync/UI/Components/SelectTagForSyncshellUi.cs b/LightlessSync/UI/Components/SelectTagForSyncshellUi.cs index 5473263..f9947e9 100644 --- a/LightlessSync/UI/Components/SelectTagForSyncshellUi.cs +++ b/LightlessSync/UI/Components/SelectTagForSyncshellUi.cs @@ -46,8 +46,8 @@ public class SelectTagForSyncshellUi return; } - var name = _group.GID; - var popupName = $"Choose Groups for {_group.GID}"; + var name = _group.GroupAliasOrGID; + var popupName = $"Choose Groups for {_group.GroupAliasOrGID}"; // Is the popup supposed to show but did not open yet? Open it if (_show) { diff --git a/LightlessSync/UI/DrawEntityFactory.cs b/LightlessSync/UI/DrawEntityFactory.cs index 625d660..ec5d368 100644 --- a/LightlessSync/UI/DrawEntityFactory.cs +++ b/LightlessSync/UI/DrawEntityFactory.cs @@ -60,16 +60,7 @@ public class DrawEntityFactory { return new DrawFolderGroup(groupFullInfoDto.Group.GID, groupFullInfoDto, _apiController, filteredPairs.Select(p => CreateDrawPair(groupFullInfoDto.Group.GID + p.Key.UserData.UID, p.Key, p.Value, groupFullInfoDto)).ToImmutableList(), - allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, _selectTagForSyncshellUi, false); - } - - public DrawFolderGroup CreateDrawGroupFolder(GroupFullInfoDto groupFullInfoDto, - Dictionary> filteredPairs, - IImmutableList allPairs, string tag) - { - return new DrawFolderGroup(tag, groupFullInfoDto, _apiController, - filteredPairs.Select(p => CreateDrawPair(tag, p.Key, p.Value, groupFullInfoDto)).ToImmutableList(), - allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, _selectTagForSyncshellUi, true); + allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectTagForSyncshellUi); } public DrawFolderTag CreateDrawTagFolder(string tag, -- 2.49.1 From 099cc1b8dc2fb63a4012e44411a6a60fe06ddd17 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Tue, 9 Sep 2025 06:10:08 +0200 Subject: [PATCH 5/8] Fixed some issues with syncshell saving, fetching of tags and spacing issues. Added button for rename/select/remove. --- .../ServerConfigurationManager.cs | 5 +- LightlessSync/UI/CompactUI.cs | 72 ++++++++----------- .../DrawGroupedSyncshellTagFolder.cs | 57 +++++++++++++-- .../UI/Components/RenameSyncshellTagUi.cs | 4 +- .../UI/Components/SelectSyncshellForTagUi.cs | 4 +- LightlessSync/UI/DrawEntityFactory.cs | 9 +++ 6 files changed, 98 insertions(+), 53 deletions(-) diff --git a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs index 2ffdeb7..205b517 100644 --- a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -427,7 +427,7 @@ public class ServerConfigurationManager internal HashSet GetNamesForSyncshellTag(string tag) { - return CurrentPairTagStorage().UidServerPairedUserTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); + return CurrentSyncshellTagStorage().SyncshellPairedTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); } internal bool HasPairTags(string uid) @@ -520,7 +520,7 @@ public class ServerConfigurationManager RenameTag(CurrentSyncshellTagStorage().SyncshellPairedTags, CurrentSyncshellTagStorage().ServerAvailableSyncshellTags, oldName, newName); } - internal static void RenameTag(Dictionary> tags, HashSet storage, string oldName, string newName) + internal void RenameTag(Dictionary> tags, HashSet storage, string oldName, string newName) { storage.Remove(oldName); storage.Add(newName); @@ -529,6 +529,7 @@ public class ServerConfigurationManager if (existingTags.Remove(oldName)) existingTags.Add(newName); } + _lightlessMediator.Publish(new RefreshUiMessage()); } internal void SaveNotes() diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index 659f542..93785a1 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -208,7 +208,7 @@ public class CompactUi : WindowMediatorSubscriberBase using (ImRaii.PushId("transfers")) DrawTransfers(); _transferPartHeight = ImGui.GetCursorPosY() - pairlistEnd - ImGui.GetTextLineHeight(); using (ImRaii.PushId("group-pair-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs); - using (ImRaii.PushId("group-syncshell-popup")) _selectSyncshellForTagUi.Draw(_pairManager.Groups.Values.ToList()); + using (ImRaii.PushId("group-syncshell-popup")) _selectSyncshellForTagUi.Draw([.. _pairManager.Groups.Values]); using (ImRaii.PushId("group-pair-edit")) _renamePairTagUi.Draw(); using (ImRaii.PushId("group-syncshell-edit")) _renameSyncshellTagUi.Draw(); using (ImRaii.PushId("grouping-pair-popup")) _selectTagForPairUi.Draw(); @@ -501,25 +501,7 @@ public class CompactUi : WindowMediatorSubscriberBase foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) { - var allGroupPairs = ImmutablePairList(allPairs - .Where(u => FilterGroupUsers(u, group))); - - var filteredGroupPairs = filteredPairs - .Where(u => FilterGroupUsers(u, group) && FilterOnlineOrPausedSelf(u)) - .OrderByDescending(u => u.Key.IsOnline) - .ThenBy(u => - { - if (string.Equals(u.Key.UserData.UID, group.OwnerUID, StringComparison.Ordinal)) return 0; - if (group.GroupPairUserInfos.TryGetValue(u.Key.UserData.UID, out var info)) - { - if (info.IsModerator()) return 1; - if (info.IsPinned()) return 2; - } - return u.Key.IsVisible ? 3 : 4; - }) - .ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase) - .ToDictionary(k => k.Key, k => k.Value); - + GetGroups(allPairs, filteredPairs, group, out ImmutableList allGroupPairs, out Dictionary> filteredGroupPairs); groupFolders.Add(_drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs)); } @@ -529,7 +511,7 @@ public class CompactUi : WindowMediatorSubscriberBase drawFolders.AddRange(groupFolders); var tags = _tagHandler.GetAllPairTagsSorted(); - _logger.LogInformation($"Loading {tags.Count} pair tags"); + _logger.LogDebug($"Loading {tags.Count} pair tags"); foreach (var tag in tags) { var allTagPairs = ImmutablePairList(allPairs @@ -541,39 +523,22 @@ public class CompactUi : WindowMediatorSubscriberBase } var syncshellTags = _tagHandler.GetAllSyncshellTagsSorted(); - _logger.LogInformation($"Loading {syncshellTags.Count} syncshell tags"); + _logger.LogDebug($"Loading {syncshellTags.Count} syncshell tags"); foreach (var syncshelltag in syncshellTags) { - List syncshellFolderTags = new(); + List syncshellFolderTags = []; foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) { if (_tagHandler.HasSyncshellTag(group.GID, syncshelltag)) { - var allGroupPairs = ImmutablePairList(allPairs - .Where(u => FilterGroupUsers(u, group))); - - var filteredGroupPairs = filteredPairs - .Where(u => FilterOnlineOrPausedSelf(u)) - .OrderByDescending(u => u.Key.IsOnline) - .ThenBy(u => - { - if (string.Equals(u.Key.UserData.UID, group.OwnerUID, StringComparison.Ordinal)) return 0; - if (group.GroupPairUserInfos.TryGetValue(u.Key.UserData.UID, out var info)) - { - if (info.IsModerator()) return 1; - if (info.IsPinned()) return 2; - } - return u.Key.IsVisible ? 3 : 4; - }) - .ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase) - .ToDictionary(k => k.Key, k => k.Value); - syncshellFolderTags.Add(_drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs)); + GetGroups(allPairs, filteredPairs, group, out ImmutableList allGroupPairs, out Dictionary> filteredGroupPairs); + syncshellFolderTags.Add(_drawEntityFactory.CreateDrawGroupFolder($"tag_{group.GID}", group, filteredGroupPairs, allGroupPairs)); } } if (syncshellFolderTags.Count > 0) { - drawFolders.Add(new DrawGroupedSyncshellTagFolder(syncshelltag, syncshellFolderTags, _tagHandler, _uiSharedService)); + drawFolders.Add(new DrawGroupedSyncshellTagFolder(syncshelltag, syncshellFolderTags, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi)); } } @@ -611,6 +576,27 @@ public class CompactUi : WindowMediatorSubscriberBase ImmutablePairList(allPairs.Where(u => u.Key.IsOneSidedPair)))); return drawFolders; + + void GetGroups(Dictionary> allPairs, Dictionary> filteredPairs, GroupFullInfoDto group, out ImmutableList allGroupPairs, out Dictionary> filteredGroupPairs) + { + allGroupPairs = ImmutablePairList(allPairs + .Where(u => FilterGroupUsers(u, group))); + filteredGroupPairs = filteredPairs + .Where(u => FilterGroupUsers(u, group) && FilterOnlineOrPausedSelf(u)) + .OrderByDescending(u => u.Key.IsOnline) + .ThenBy(u => + { + if (string.Equals(u.Key.UserData.UID, group.OwnerUID, StringComparison.Ordinal)) return 0; + if (group.GroupPairUserInfos.TryGetValue(u.Key.UserData.UID, out var info)) + { + if (info.IsModerator()) return 1; + if (info.IsPinned()) return 2; + } + return u.Key.IsVisible ? 3 : 4; + }) + .ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase) + .ToDictionary(k => k.Key, k => k.Value); + } } private string GetServerError() diff --git a/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs b/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs index 85559ac..221f453 100644 --- a/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs +++ b/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs @@ -13,18 +13,24 @@ public class DrawGroupedSyncshellTagFolder : IDrawFolder private readonly IEnumerable _groups; private readonly TagHandler _tagHandler; private readonly UiSharedService _uiSharedService; + private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; + private readonly RenameSyncshellTagUi _renameSyncshellTagUi; private bool _wasHovered = false; + private float _menuWidth = -1; public IImmutableList DrawPairs => throw new NotSupportedException(); public int OnlinePairs => _groups.SelectMany(g => g.DrawPairs).Where(g => g.Pair.IsOnline).DistinctBy(g => g.Pair.UserData.UID).Count(); public int TotalPairs => _groups.Sum(g => g.TotalPairs); - public DrawGroupedSyncshellTagFolder(string tag, IEnumerable groups, TagHandler tagHandler, UiSharedService uiSharedService) + public DrawGroupedSyncshellTagFolder(string tag, IEnumerable groups, TagHandler tagHandler, UiSharedService uiSharedService, + SelectSyncshellForTagUi selectSyncshellForTagUi, RenameSyncshellTagUi renameSyncshellTagUi) { _tag = tag; _groups = groups; _tagHandler = tagHandler; _uiSharedService = uiSharedService; + _selectSyncshellForTagUi = selectSyncshellForTagUi; + _renameSyncshellTagUi = renameSyncshellTagUi; } public void Draw() @@ -51,7 +57,7 @@ public class DrawGroupedSyncshellTagFolder : IDrawFolder ImGui.SameLine(); ImGui.AlignTextToFramePadding(); - _uiSharedService.IconText(FontAwesomeIcon.UsersRectangle); + _uiSharedService.IconText(FontAwesomeIcon.FolderPlus); using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemSpacing.X / 2f })) { ImGui.SameLine(); @@ -63,12 +69,14 @@ public class DrawGroupedSyncshellTagFolder : IDrawFolder ImGui.SameLine(); ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(_tag); + + ImGui.SameLine(); + ImGui.AlignTextToFramePadding(); + DrawMenu(); } color.Dispose(); _wasHovered = ImGui.IsItemHovered(); - ImGui.Separator(); - if (_tagHandler.IsTagOpen(_id)) { using var indent = ImRaii.PushIndent(20f); @@ -78,4 +86,45 @@ public class DrawGroupedSyncshellTagFolder : IDrawFolder } } } + + protected void DrawMenu() + { + var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.EllipsisV); + var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth(); + + ImGui.SameLine(windowEndX - barButtonSize.X); + if (_uiSharedService.IconButton(FontAwesomeIcon.EllipsisV)) + { + ImGui.OpenPopup("User Flyout Menu"); + } + if (ImGui.BeginPopup("User Flyout Menu")) + { + using (ImRaii.PushId($"buttons-syncshell-{_tag}")) GroupMenu(_menuWidth); + _menuWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; + ImGui.EndPopup(); + } + else + { + _menuWidth = 0; + } + } + + protected void GroupMenu(float menuWidth) + { + ImGui.TextUnformatted("Syncshell Group Menu"); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Syncshells", menuWidth, isInPopup: true)) + { + _selectSyncshellForTagUi.Open(_tag); + } + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Syncshell Group", menuWidth, isInPopup: true)) + { + _renameSyncshellTagUi.Open(_tag); + } + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) + { + _tagHandler.RemovePairTag(_tag); + } + UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently." + Environment.NewLine + + "Note: this will not unpair with users in this Group."); + } } diff --git a/LightlessSync/UI/Components/RenameSyncshellTagUi.cs b/LightlessSync/UI/Components/RenameSyncshellTagUi.cs index a4edcde..b92870c 100644 --- a/LightlessSync/UI/Components/RenameSyncshellTagUi.cs +++ b/LightlessSync/UI/Components/RenameSyncshellTagUi.cs @@ -28,7 +28,7 @@ public class RenameSyncshellTagUi var minSize = new Vector2(300, workHeight < 110 ? workHeight : 110) * ImGuiHelpers.GlobalScale; var maxSize = new Vector2(300, 110) * ImGuiHelpers.GlobalScale; - var popupName = $"Renaming Pair Group {_tag}"; + var popupName = $"Renaming Syncshell Group {_tag}"; if (!_show) { @@ -74,6 +74,6 @@ public class RenameSyncshellTagUi public void RenameTag(string oldTag, string newTag) { - _tagHandler.RenamePairTag(oldTag, newTag); + _tagHandler.RenameSyncshellTag(oldTag, newTag); } } \ No newline at end of file diff --git a/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs b/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs index 288776c..62dd1d6 100644 --- a/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs +++ b/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs @@ -50,11 +50,11 @@ public class SelectSyncshellForTagUi ImGui.InputTextWithHint("##filter", "Filter", ref _filter, 255, ImGuiInputTextFlags.None); foreach (var group in groups .Where(g => string.IsNullOrEmpty(_filter) || g.GID.Contains(_filter, StringComparison.OrdinalIgnoreCase)) - .OrderBy(g => g.GID, StringComparer.OrdinalIgnoreCase) + .OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase) .ToList()) { var isInGroup = _syncshellsInGroup.Contains(group.GID); - if (ImGui.Checkbox(group.GID, ref isInGroup)) + if (ImGui.Checkbox(group.GroupAliasOrGID, ref isInGroup)) { if (isInGroup) { diff --git a/LightlessSync/UI/DrawEntityFactory.cs b/LightlessSync/UI/DrawEntityFactory.cs index ec5d368..d1410ad 100644 --- a/LightlessSync/UI/DrawEntityFactory.cs +++ b/LightlessSync/UI/DrawEntityFactory.cs @@ -63,6 +63,15 @@ public class DrawEntityFactory allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectTagForSyncshellUi); } + public DrawFolderGroup CreateDrawGroupFolder(string id, GroupFullInfoDto groupFullInfoDto, + Dictionary> filteredPairs, + IImmutableList allPairs) + { + return new DrawFolderGroup(id, groupFullInfoDto, _apiController, + filteredPairs.Select(p => CreateDrawPair(groupFullInfoDto.Group.GID + p.Key.UserData.UID, p.Key, p.Value, groupFullInfoDto)).ToImmutableList(), + allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectTagForSyncshellUi); + } + public DrawFolderTag CreateDrawTagFolder(string tag, Dictionary> filteredPairs, IImmutableList allPairs) -- 2.49.1 From abe5505734601fbc7e9d71f5c38508c3768de50b Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Tue, 9 Sep 2025 06:25:11 +0200 Subject: [PATCH 6/8] Fixed deleting of syncshell tags --- .../ServerConfigurationManager.cs | 76 +++++++------------ .../DrawGroupedSyncshellTagFolder.cs | 7 +- 2 files changed, 30 insertions(+), 53 deletions(-) diff --git a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs index 205b517..1aebde3 100644 --- a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -347,10 +347,7 @@ public class ServerConfigurationManager _syncshellTagConfig.Save(); } - internal bool ContainsOpenPairTag(string tag) - { - return CurrentPairTagStorage().OpenPairTags.Contains(tag); - } + internal bool ContainsOpenPairTag(string tag) => CurrentPairTagStorage().OpenPairTags.Contains(tag); internal bool ContainsPairTag(string uid, string tag) { @@ -405,40 +402,19 @@ public class ServerConfigurationManager return null; } - internal HashSet GetServerAvailablePairTags() - { - return CurrentPairTagStorage().ServerAvailablePairTags; - } + internal HashSet GetServerAvailablePairTags() => CurrentPairTagStorage().ServerAvailablePairTags; - internal HashSet GetServerAvailableSyncshellTags() - { - return CurrentSyncshellTagStorage().ServerAvailableSyncshellTags; - } + internal HashSet GetServerAvailableSyncshellTags() => CurrentSyncshellTagStorage().ServerAvailableSyncshellTags; - internal Dictionary> GetUidServerPairedUserTags() - { - return CurrentPairTagStorage().UidServerPairedUserTags; - } + internal Dictionary> GetUidServerPairedUserTags() => CurrentPairTagStorage().UidServerPairedUserTags; - internal HashSet GetUidsForPairTag(string tag) - { - return CurrentPairTagStorage().UidServerPairedUserTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); - } + internal HashSet GetUidsForPairTag(string tag) => CurrentPairTagStorage().UidServerPairedUserTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); - internal HashSet GetNamesForSyncshellTag(string tag) - { - return CurrentSyncshellTagStorage().SyncshellPairedTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); - } + internal HashSet GetNamesForSyncshellTag(string tag) => CurrentSyncshellTagStorage().SyncshellPairedTags.Where(p => p.Value.Contains(tag, StringComparer.Ordinal)).Select(p => p.Key).ToHashSet(StringComparer.Ordinal); - internal bool HasPairTags(string uid) - { - return CurrentPairTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags) && tags.Count != 0; - } + internal bool HasPairTags(string uid) => CurrentPairTagStorage().UidServerPairedUserTags.TryGetValue(uid, out var tags) && tags.Count != 0; - internal bool HasSyncshellTags(string name) - { - return CurrentSyncshellTagStorage().SyncshellPairedTags.TryGetValue(name, out var tags) && tags.Count != 0; - } + internal bool HasSyncshellTags(string name) => CurrentSyncshellTagStorage().SyncshellPairedTags.TryGetValue(name, out var tags) && tags.Count != 0; internal void RemoveCharacterFromServer(int serverSelectionIndex, Authentication item) { @@ -468,18 +444,29 @@ public class ServerConfigurationManager internal void RemoveSyncshellTag(string tag) { - RemoveTag(CurrentSyncshellTagStorage().ServerAvailableSyncshellTags, tag); + RemoveTag(CurrentSyncshellTagStorage().ServerAvailableSyncshellTags, tag, true); _syncshellTagConfig.Save(); _lightlessMediator.Publish(new RefreshUiMessage()); } - internal void RemoveTag(HashSet storage, string tag) + internal void RemoveTag(HashSet storage, string tag, bool syncshell = false) { - CurrentPairTagStorage().ServerAvailablePairTags.Remove(tag); - foreach (var uid in GetUidsForPairTag(tag)) + storage.Remove(tag); + if (syncshell) { - RemoveTagForUid(uid, tag, save: false); + foreach (var uid in GetNamesForSyncshellTag(tag)) + { + RemoveTagForSyncshell(uid, tag, save: false); + } } + else + { + foreach (var uid in GetUidsForPairTag(tag)) + { + RemoveTagForUid(uid, tag, save: false); + } + } + } internal void RemoveTagForUid(string uid, string tagName, bool save = true) @@ -510,15 +497,9 @@ public class ServerConfigurationManager } } - internal void RenamePairTag(string oldName, string newName) - { - RenameTag(CurrentPairTagStorage().UidServerPairedUserTags, CurrentPairTagStorage().ServerAvailablePairTags, oldName, newName); - } + internal void RenamePairTag(string oldName, string newName) => RenameTag(CurrentPairTagStorage().UidServerPairedUserTags, CurrentPairTagStorage().ServerAvailablePairTags, oldName, newName); - internal void RenameSyncshellTag(string oldName, string newName) - { - RenameTag(CurrentSyncshellTagStorage().SyncshellPairedTags, CurrentSyncshellTagStorage().ServerAvailableSyncshellTags, oldName, newName); - } + internal void RenameSyncshellTag(string oldName, string newName) => RenameTag(CurrentSyncshellTagStorage().SyncshellPairedTags, CurrentSyncshellTagStorage().ServerAvailableSyncshellTags, oldName, newName); internal void RenameTag(Dictionary> tags, HashSet storage, string oldName, string newName) { @@ -532,10 +513,7 @@ public class ServerConfigurationManager _lightlessMediator.Publish(new RefreshUiMessage()); } - internal void SaveNotes() - { - _notesConfig.Save(); - } + internal void SaveNotes() => _notesConfig.Save(); internal void SetNoteForGid(string gid, string note, bool save = true) { diff --git a/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs b/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs index 221f453..8401e9a 100644 --- a/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs +++ b/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs @@ -40,7 +40,7 @@ public class DrawGroupedSyncshellTagFolder : IDrawFolder string _id = $"__folder_{_tag}"; using var id = ImRaii.PushId(_id); var color = ImRaii.PushColor(ImGuiCol.ChildBg, ImGui.GetColorU32(ImGuiCol.FrameBgHovered), _wasHovered); - using (ImRaii.Child("folder__" + _id, new System.Numerics.Vector2(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX(), ImGui.GetFrameHeight()))) + using (ImRaii.Child("folder__" + _id, new Vector2(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX(), ImGui.GetFrameHeight()))) { ImGui.Dummy(new Vector2(0f, ImGui.GetFrameHeight())); using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(0f, 0f))) @@ -122,9 +122,8 @@ public class DrawGroupedSyncshellTagFolder : IDrawFolder } if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) { - _tagHandler.RemovePairTag(_tag); + _tagHandler.RemoveSyncshellTag(_tag); } - UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently." + Environment.NewLine + - "Note: this will not unpair with users in this Group."); + UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently."); } } -- 2.49.1 From 4cf122934c7803bd2bd33d7191855aa9594f60c0 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Tue, 9 Sep 2025 23:19:00 +0200 Subject: [PATCH 7/8] Removed syncshelltagfolder, adding new parameters for group folder to support it in there. --- LightlessSync.sln | 8 +- LightlessSync/UI/CompactUI.cs | 6 +- .../UI/Components/DrawGroupedGroupFolder.cs | 80 ++++++++++- .../DrawGroupedSyncshellTagFolder.cs | 129 ------------------ 4 files changed, 79 insertions(+), 144 deletions(-) delete mode 100644 LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs diff --git a/LightlessSync.sln b/LightlessSync.sln index f24f6b2..5b7ca3c 100644 --- a/LightlessSync.sln +++ b/LightlessSync.sln @@ -22,16 +22,16 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.ActiveCfg = Debug|x64 - {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.Build.0 = Debug|x64 + {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.ActiveCfg = Release|x64 + {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.Build.0 = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|x64.ActiveCfg = Debug|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|x64.Build.0 = Debug|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|Any CPU.ActiveCfg = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|Any CPU.Build.0 = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|x64.ActiveCfg = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|x64.Build.0 = Release|x64 - {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.Build.0 = Release|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|x64.ActiveCfg = Debug|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|x64.Build.0 = Debug|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index 93785a1..7d0bfb0 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -506,12 +506,11 @@ public class CompactUi : WindowMediatorSubscriberBase } if (_configService.Current.GroupUpSyncshells) - drawFolders.Add(new DrawGroupedGroupFolder(groupFolders, _tagHandler, _uiSharedService)); + drawFolders.Add(new DrawGroupedGroupFolder(groupFolders, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, "")); else drawFolders.AddRange(groupFolders); var tags = _tagHandler.GetAllPairTagsSorted(); - _logger.LogDebug($"Loading {tags.Count} pair tags"); foreach (var tag in tags) { var allTagPairs = ImmutablePairList(allPairs @@ -523,7 +522,6 @@ public class CompactUi : WindowMediatorSubscriberBase } var syncshellTags = _tagHandler.GetAllSyncshellTagsSorted(); - _logger.LogDebug($"Loading {syncshellTags.Count} syncshell tags"); foreach (var syncshelltag in syncshellTags) { List syncshellFolderTags = []; @@ -538,7 +536,7 @@ public class CompactUi : WindowMediatorSubscriberBase if (syncshellFolderTags.Count > 0) { - drawFolders.Add(new DrawGroupedSyncshellTagFolder(syncshelltag, syncshellFolderTags, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi)); + drawFolders.Add(new DrawGroupedGroupFolder(syncshellFolderTags, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, syncshelltag)); } } diff --git a/LightlessSync/UI/Components/DrawGroupedGroupFolder.cs b/LightlessSync/UI/Components/DrawGroupedGroupFolder.cs index 5410554..d1876ac 100644 --- a/LightlessSync/UI/Components/DrawGroupedGroupFolder.cs +++ b/LightlessSync/UI/Components/DrawGroupedGroupFolder.cs @@ -9,20 +9,27 @@ namespace LightlessSync.UI.Components; public class DrawGroupedGroupFolder : IDrawFolder { + private readonly string _tag; private readonly IEnumerable _groups; private readonly TagHandler _tagHandler; private readonly UiSharedService _uiSharedService; + private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; + private readonly RenameSyncshellTagUi _renameSyncshellTagUi; private bool _wasHovered = false; + private float _menuWidth; public IImmutableList DrawPairs => throw new NotSupportedException(); public int OnlinePairs => _groups.SelectMany(g => g.DrawPairs).Where(g => g.Pair.IsOnline).DistinctBy(g => g.Pair.UserData.UID).Count(); public int TotalPairs => _groups.Sum(g => g.TotalPairs); - public DrawGroupedGroupFolder(IEnumerable groups, TagHandler tagHandler, UiSharedService uiSharedService) + public DrawGroupedGroupFolder(IEnumerable groups, TagHandler tagHandler, UiSharedService uiSharedService, SelectSyncshellForTagUi selectSyncshellForTagUi, RenameSyncshellTagUi renameSyncshellTagUi, string tag) { _groups = groups; _tagHandler = tagHandler; _uiSharedService = uiSharedService; + _selectSyncshellForTagUi = selectSyncshellForTagUi; + _renameSyncshellTagUi = renameSyncshellTagUi; + _tag = tag; } public void Draw() @@ -30,6 +37,11 @@ public class DrawGroupedGroupFolder : IDrawFolder if (!_groups.Any()) return; string _id = "__folder_syncshells"; + if (_tag != "") + { + _id = $"__folder_{_tag}"; + } + using var id = ImRaii.PushId(_id); var color = ImRaii.PushColor(ImGuiCol.ChildBg, ImGui.GetColorU32(ImGuiCol.FrameBgHovered), _wasHovered); using (ImRaii.Child("folder__" + _id, new System.Numerics.Vector2(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX(), ImGui.GetFrameHeight()))) @@ -49,18 +61,36 @@ public class DrawGroupedGroupFolder : IDrawFolder ImGui.SameLine(); ImGui.AlignTextToFramePadding(); - _uiSharedService.IconText(FontAwesomeIcon.UsersRectangle); - using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemSpacing.X / 2f })) + + if (_tag != "") { - ImGui.SameLine(); - ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted("[" + OnlinePairs.ToString() + "]"); + _uiSharedService.IconText(FontAwesomeIcon.FolderPlus); + } + else + { + _uiSharedService.IconText(FontAwesomeIcon.UsersRectangle); } + + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemSpacing.X / 2f })) + { + ImGui.SameLine(); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted("[" + OnlinePairs.ToString() + "]"); + } UiSharedService.AttachToolTip(OnlinePairs + " online in all of your joined syncshells" + Environment.NewLine + TotalPairs + " pairs combined in all of your joined syncshells"); ImGui.SameLine(); ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted("All Syncshells"); + if (_tag != "") + { + ImGui.TextUnformatted(_tag); + + ImGui.SameLine(); + DrawMenu(); + } else + { + ImGui.TextUnformatted("All Syncshells"); + } } color.Dispose(); _wasHovered = ImGui.IsItemHovered(); @@ -76,4 +106,40 @@ public class DrawGroupedGroupFolder : IDrawFolder } } } + + protected void DrawMenu() + { + var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.EllipsisV); + var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth(); + + ImGui.SameLine(windowEndX - barButtonSize.X); + if (_uiSharedService.IconButton(FontAwesomeIcon.EllipsisV)) + { + ImGui.OpenPopup("User Flyout Menu"); + } + if (ImGui.BeginPopup("User Flyout Menu")) + { + using (ImRaii.PushId($"buttons-syncshell-{_tag}")) GroupMenu(_menuWidth); + _menuWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; + ImGui.EndPopup(); + } + } + + protected void GroupMenu(float menuWidth) + { + ImGui.TextUnformatted("Syncshell Group Menu"); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Syncshells", menuWidth, isInPopup: true)) + { + _selectSyncshellForTagUi.Open(_tag); + } + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Syncshell Group", menuWidth, isInPopup: true)) + { + _renameSyncshellTagUi.Open(_tag); + } + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) + { + _tagHandler.RemoveSyncshellTag(_tag); + } + UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently."); + } } diff --git a/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs b/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs deleted file mode 100644 index 8401e9a..0000000 --- a/LightlessSync/UI/Components/DrawGroupedSyncshellTagFolder.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Dalamud.Bindings.ImGui; -using Dalamud.Interface; -using Dalamud.Interface.Utility.Raii; -using LightlessSync.UI.Handlers; -using System.Collections.Immutable; -using System.Numerics; - -namespace LightlessSync.UI.Components; - -public class DrawGroupedSyncshellTagFolder : IDrawFolder -{ - private readonly string _tag; - private readonly IEnumerable _groups; - private readonly TagHandler _tagHandler; - private readonly UiSharedService _uiSharedService; - private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; - private readonly RenameSyncshellTagUi _renameSyncshellTagUi; - private bool _wasHovered = false; - private float _menuWidth = -1; - - public IImmutableList DrawPairs => throw new NotSupportedException(); - public int OnlinePairs => _groups.SelectMany(g => g.DrawPairs).Where(g => g.Pair.IsOnline).DistinctBy(g => g.Pair.UserData.UID).Count(); - public int TotalPairs => _groups.Sum(g => g.TotalPairs); - - public DrawGroupedSyncshellTagFolder(string tag, IEnumerable groups, TagHandler tagHandler, UiSharedService uiSharedService, - SelectSyncshellForTagUi selectSyncshellForTagUi, RenameSyncshellTagUi renameSyncshellTagUi) - { - _tag = tag; - _groups = groups; - _tagHandler = tagHandler; - _uiSharedService = uiSharedService; - _selectSyncshellForTagUi = selectSyncshellForTagUi; - _renameSyncshellTagUi = renameSyncshellTagUi; - } - - public void Draw() - { - if (!_groups.Any()) return; - - string _id = $"__folder_{_tag}"; - using var id = ImRaii.PushId(_id); - var color = ImRaii.PushColor(ImGuiCol.ChildBg, ImGui.GetColorU32(ImGuiCol.FrameBgHovered), _wasHovered); - using (ImRaii.Child("folder__" + _id, new Vector2(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX(), ImGui.GetFrameHeight()))) - { - ImGui.Dummy(new Vector2(0f, ImGui.GetFrameHeight())); - using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(0f, 0f))) - ImGui.SameLine(); - - var icon = _tagHandler.IsTagOpen(_id) ? FontAwesomeIcon.CaretDown : FontAwesomeIcon.CaretRight; - ImGui.AlignTextToFramePadding(); - - _uiSharedService.IconText(icon); - if (ImGui.IsItemClicked()) - { - _tagHandler.SetTagOpen(_id, !_tagHandler.IsTagOpen(_id)); - } - - ImGui.SameLine(); - ImGui.AlignTextToFramePadding(); - _uiSharedService.IconText(FontAwesomeIcon.FolderPlus); - using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemSpacing.X / 2f })) - { - ImGui.SameLine(); - ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted("[" + OnlinePairs.ToString() + "]"); - } - UiSharedService.AttachToolTip(OnlinePairs + " online in all of your joined syncshells" + Environment.NewLine + - TotalPairs + " pairs combined in all of your joined syncshells"); - ImGui.SameLine(); - ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted(_tag); - - ImGui.SameLine(); - ImGui.AlignTextToFramePadding(); - DrawMenu(); - } - color.Dispose(); - _wasHovered = ImGui.IsItemHovered(); - - if (_tagHandler.IsTagOpen(_id)) - { - using var indent = ImRaii.PushIndent(20f); - foreach (var entry in _groups) - { - entry.Draw(); - } - } - } - - protected void DrawMenu() - { - var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.EllipsisV); - var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth(); - - ImGui.SameLine(windowEndX - barButtonSize.X); - if (_uiSharedService.IconButton(FontAwesomeIcon.EllipsisV)) - { - ImGui.OpenPopup("User Flyout Menu"); - } - if (ImGui.BeginPopup("User Flyout Menu")) - { - using (ImRaii.PushId($"buttons-syncshell-{_tag}")) GroupMenu(_menuWidth); - _menuWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; - ImGui.EndPopup(); - } - else - { - _menuWidth = 0; - } - } - - protected void GroupMenu(float menuWidth) - { - ImGui.TextUnformatted("Syncshell Group Menu"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Syncshells", menuWidth, isInPopup: true)) - { - _selectSyncshellForTagUi.Open(_tag); - } - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Syncshell Group", menuWidth, isInPopup: true)) - { - _renameSyncshellTagUi.Open(_tag); - } - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) - { - _tagHandler.RemoveSyncshellTag(_tag); - } - UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently."); - } -} -- 2.49.1 From 367068480ee879404b574346c7c91014231247e5 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Tue, 9 Sep 2025 23:25:41 +0200 Subject: [PATCH 8/8] Removal of OpenSyncshellTags, not used in anyway for syncshell folders. --- .../Models/SyncshellTagStorage.cs | 1 - .../ServerConfigurationManager.cs | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/LightlessSync/LightlessConfiguration/Models/SyncshellTagStorage.cs b/LightlessSync/LightlessConfiguration/Models/SyncshellTagStorage.cs index 725621b..7a3d409 100644 --- a/LightlessSync/LightlessConfiguration/Models/SyncshellTagStorage.cs +++ b/LightlessSync/LightlessConfiguration/Models/SyncshellTagStorage.cs @@ -3,7 +3,6 @@ [Serializable] public class SyncshellTagStorage { - public HashSet OpenSyncshellTags { get; set; } = new(StringComparer.Ordinal); public HashSet ServerAvailableSyncshellTags { get; set; } = new(StringComparer.Ordinal); public Dictionary> SyncshellPairedTags { get; set; } = new(StringComparer.Ordinal); } diff --git a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs index 1aebde3..6b2ac42 100644 --- a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -291,12 +291,6 @@ public class ServerConfigurationManager _pairTagConfig.Save(); } - internal void AddOpenSyncshellTag(string tag) - { - CurrentSyncshellTagStorage().OpenSyncshellTags.Add(tag); - _syncshellTagConfig.Save(); - } - internal void AddServer(ServerStorage serverStorage) { _configService.Current.ServerStorage.Add(serverStorage); @@ -429,12 +423,6 @@ public class ServerConfigurationManager _pairTagConfig.Save(); } - internal void RemoveOpenSyncshellTag(string tag) - { - CurrentSyncshellTagStorage().OpenSyncshellTags.Remove(tag); - _syncshellTagConfig.Save(); - } - internal void RemovePairTag(string tag) { RemoveTag(CurrentPairTagStorage().ServerAvailablePairTags, tag); -- 2.49.1