From 099cc1b8dc2fb63a4012e44411a6a60fe06ddd17 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Tue, 9 Sep 2025 06:10:08 +0200 Subject: [PATCH] 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)