diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index 6af9498..77305c1 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -141,7 +141,7 @@ public class CompactUi : WindowMediatorSubscriberBase }, }; - _drawFolders = [.. GetDrawFolders()]; + _drawFolders = [.. DrawFolders]; #if DEBUG string dev = "Dev Build"; @@ -158,7 +158,7 @@ public class CompactUi : WindowMediatorSubscriberBase Mediator.Subscribe(this, (_) => UiSharedService_GposeEnd()); Mediator.Subscribe(this, (msg) => _currentDownloads[msg.DownloadId] = msg.DownloadStatus); Mediator.Subscribe(this, (msg) => _currentDownloads.TryRemove(msg.DownloadId, out _)); - Mediator.Subscribe(this, (msg) => _drawFolders = GetDrawFolders().ToList()); + Mediator.Subscribe(this, (msg) => _drawFolders = DrawFolders.ToList()); Flags |= ImGuiWindowFlags.NoDocking; @@ -612,164 +612,165 @@ public class CompactUi : WindowMediatorSubscriberBase } } - private IEnumerable GetDrawFolders() + private IEnumerable DrawFolders { - List drawFolders = []; - - var allPairs = _pairManager.PairsWithGroups - .ToDictionary(k => k.Key, k => k.Value); - var filteredPairs = allPairs - .Where(p => - { - if (_tabMenu.Filter.IsNullOrEmpty()) return true; - return p.Key.UserData.AliasOrUID.Contains(_tabMenu.Filter, StringComparison.OrdinalIgnoreCase) || - (p.Key.GetNote()?.Contains(_tabMenu.Filter, StringComparison.OrdinalIgnoreCase) ?? false) || - (p.Key.PlayerName?.Contains(_tabMenu.Filter, StringComparison.OrdinalIgnoreCase) ?? false); - }) - .ToDictionary(k => k.Key, k => k.Value); - - string? AlphabeticalSort(KeyValuePair> u) - => (_configService.Current.ShowCharacterNameInsteadOfNotesForVisible && !string.IsNullOrEmpty(u.Key.PlayerName) - ? (_configService.Current.PreferNotesOverNamesForVisible ? u.Key.GetNote() : u.Key.PlayerName) - : (u.Key.GetNote() ?? u.Key.UserData.AliasOrUID)); - bool FilterOnlineOrPausedSelf(KeyValuePair> u) - => (u.Key.IsOnline || (!u.Key.IsOnline && !_configService.Current.ShowOfflineUsersSeparately) - || u.Key.UserPair.OwnPermissions.IsPaused()); - Dictionary> BasicSortedDictionary(IEnumerable>> u) - => u.OrderByDescending(u => u.Key.IsVisible) - .ThenByDescending(u => u.Key.IsOnline) - .ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase) - .ToDictionary(u => u.Key, u => u.Value); - ImmutableList ImmutablePairList(IEnumerable>> u) - => u.Select(k => k.Key).ToImmutableList(); - 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.HasPairTag(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.HasAnyPairTag(u.Key.UserData.UID); - bool FilterNotTaggedSyncshells(GroupFullInfoDto group) - => !_tagHandler.HasAnySyncshellTag(group.GID) || _configService.Current.ShowGroupedSyncshellsInAll; - bool FilterOfflineUsers(KeyValuePair> u) - => ((u.Key.IsDirectlyPaired && _configService.Current.ShowSyncshellOfflineUsersSeparately) - || !_configService.Current.ShowSyncshellOfflineUsersSeparately) - && (!u.Key.IsOneSidedPair || u.Value.Any()) && !u.Key.IsOnline && !u.Key.UserPair.OwnPermissions.IsPaused(); - bool FilterOfflineSyncshellUsers(KeyValuePair> u) - => (!u.Key.IsDirectlyPaired && !u.Key.IsOnline && !u.Key.UserPair.OwnPermissions.IsPaused()); - - - if (_configService.Current.ShowVisibleUsersSeparately) + get { - var allVisiblePairs = ImmutablePairList(allPairs - .Where(FilterVisibleUsers)); - var filteredVisiblePairs = BasicSortedDictionary(filteredPairs - .Where(FilterVisibleUsers)); + var drawFolders = new List(); + var filter = _tabMenu.Filter; - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomVisibleTag, filteredVisiblePairs, allVisiblePairs)); - } + var allPairs = _pairManager.PairsWithGroups.ToDictionary(k => k.Key, k => k.Value); + var filteredPairs = allPairs.Where(p => PassesFilter(p.Key, filter)).ToDictionary(k => k.Key, k => k.Value); - List groupFolders = new(); - - foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) - { - GetGroups(allPairs, filteredPairs, group, out ImmutableList allGroupPairs, out Dictionary> filteredGroupPairs); - if (FilterNotTaggedSyncshells(group)) + //Filter of online/visible pairs + if (_configService.Current.ShowVisibleUsersSeparately) { - groupFolders.Add(_drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs)); + var allVisiblePairs = ImmutablePairList(allPairs.Where(p => FilterVisibleUsers(p.Key))); + var filteredVisiblePairs = BasicSortedDictionary(filteredPairs.Where(p => FilterVisibleUsers(p.Key))); + + drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomVisibleTag, filteredVisiblePairs, allVisiblePairs)); } - } - if (_configService.Current.GroupUpSyncshells) - drawFolders.Add(new DrawGroupedGroupFolder(groupFolders, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, "")); - else - drawFolders.AddRange(groupFolders); - - var tags = _tagHandler.GetAllPairTagsSorted(); - foreach (var tag in tags) - { - var allTagPairs = ImmutablePairList(allPairs - .Where(u => FilterTagUsers(u, tag))); - var filteredTagPairs = BasicSortedDictionary(filteredPairs - .Where(u => FilterTagUsers(u, tag) && FilterOnlineOrPausedSelf(u))); - - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(tag, filteredTagPairs, allTagPairs)); - } - - var syncshellTags = _tagHandler.GetAllSyncshellTagsSorted(); - foreach (var syncshelltag in syncshellTags) - { - List syncshellFolderTags = []; + //Filter of not foldered syncshells + var groupFolders = new List(); foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) { - if (_tagHandler.HasSyncshellTag(group.GID, syncshelltag)) + GetGroups(allPairs, filteredPairs, group, out ImmutableList allGroupPairs, out Dictionary> filteredGroupPairs); + + if (FilterNotTaggedSyncshells(group)) { - GetGroups(allPairs, filteredPairs, group, out ImmutableList allGroupPairs, out Dictionary> filteredGroupPairs); - syncshellFolderTags.Add(_drawEntityFactory.CreateDrawGroupFolder($"tag_{group.GID}", group, filteredGroupPairs, allGroupPairs)); + groupFolders.Add(_drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs)); } } - drawFolders.Add(new DrawGroupedGroupFolder(syncshellFolderTags, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, syncshelltag)); - } - var allOnlineNotTaggedPairs = ImmutablePairList(allPairs - .Where(FilterNotTaggedUsers)); - var onlineNotTaggedPairs = BasicSortedDictionary(filteredPairs - .Where(u => FilterNotTaggedUsers(u) && FilterOnlineOrPausedSelf(u))); + //Filter of grouped up syncshells (All Syncshells Folder) + if (_configService.Current.GroupUpSyncshells) + drawFolders.Add(new DrawGroupedGroupFolder(groupFolders, _tagHandler, _uiSharedService, + _selectSyncshellForTagUi, _renameSyncshellTagUi, "")); + else + drawFolders.AddRange(groupFolders); - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder((_configService.Current.ShowOfflineUsersSeparately ? TagHandler.CustomOnlineTag : TagHandler.CustomAllTag), - onlineNotTaggedPairs, allOnlineNotTaggedPairs)); - - if (_configService.Current.ShowOfflineUsersSeparately) - { - var allOfflinePairs = ImmutablePairList(allPairs - .Where(FilterOfflineUsers)); - var filteredOfflinePairs = BasicSortedDictionary(filteredPairs - .Where(FilterOfflineUsers)); - - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomOfflineTag, filteredOfflinePairs, allOfflinePairs)); - if (_configService.Current.ShowSyncshellOfflineUsersSeparately) + //Filter of grouped/foldered pairs + foreach (var tag in _tagHandler.GetAllPairTagsSorted()) { - var allOfflineSyncshellUsers = ImmutablePairList(allPairs - .Where(FilterOfflineSyncshellUsers)); - var filteredOfflineSyncshellUsers = BasicSortedDictionary(filteredPairs - .Where(FilterOfflineSyncshellUsers)); + var allTagPairs = ImmutablePairList(allPairs.Where(p => FilterTagUsers(p.Key, tag))); + var filteredTagPairs = BasicSortedDictionary(filteredPairs.Where(p => FilterTagUsers(p.Key, tag) && FilterOnlineOrPausedSelf(p.Key))); - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomOfflineSyncshellTag, - filteredOfflineSyncshellUsers, - allOfflineSyncshellUsers)); + drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(tag, filteredTagPairs, allTagPairs)); } - } - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomUnpairedTag, - BasicSortedDictionary(filteredPairs.Where(u => u.Key.IsOneSidedPair)), - 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 => + //Filter of grouped/foldered syncshells + foreach (var syncshellTag in _tagHandler.GetAllSyncshellTagsSorted()) + { + var syncshellFolderTags = new List(); + foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) { - 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 (_tagHandler.HasSyncshellTag(group.GID, syncshellTag)) { - if (info.IsModerator()) return 1; - if (info.IsPinned()) return 2; + GetGroups(allPairs, filteredPairs, group, + out ImmutableList allGroupPairs, + out Dictionary> filteredGroupPairs); + + syncshellFolderTags.Add(_drawEntityFactory.CreateDrawGroupFolder($"tag_{group.GID}", group, filteredGroupPairs, allGroupPairs)); } - return u.Key.IsVisible ? 3 : 4; - }) - .ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase) - .ToDictionary(k => k.Key, k => k.Value); + } + + drawFolders.Add(new DrawGroupedGroupFolder(syncshellFolderTags, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, syncshellTag)); + } + + //Filter of offline pairs + var allOnlineNotTaggedPairs = ImmutablePairList(allPairs.Where(p => FilterNotTaggedUsers(p.Key))); + var onlineNotTaggedPairs = BasicSortedDictionary(filteredPairs.Where(p => FilterNotTaggedUsers(p.Key) && FilterOnlineOrPausedSelf(p.Key))); + + drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder((_configService.Current.ShowOfflineUsersSeparately ? TagHandler.CustomOnlineTag : TagHandler.CustomAllTag), onlineNotTaggedPairs, allOnlineNotTaggedPairs)); + + if (_configService.Current.ShowOfflineUsersSeparately) + { + var allOfflinePairs = ImmutablePairList(allPairs.Where(p => FilterOfflineUsers(p.Key, p.Value))); + var filteredOfflinePairs = BasicSortedDictionary(filteredPairs.Where(p => FilterOfflineUsers(p.Key, p.Value))); + + drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomOfflineTag, filteredOfflinePairs, allOfflinePairs)); + + if (_configService.Current.ShowSyncshellOfflineUsersSeparately) + { + var allOfflineSyncshellUsers = ImmutablePairList(allPairs.Where(p => FilterOfflineSyncshellUsers(p.Key))); + var filteredOfflineSyncshellUsers = BasicSortedDictionary(filteredPairs.Where(p => FilterOfflineSyncshellUsers(p.Key))); + + drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomOfflineSyncshellTag, filteredOfflineSyncshellUsers, allOfflineSyncshellUsers)); + } + } + + drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomUnpairedTag, + BasicSortedDictionary(filteredPairs.Where(p => p.Key.IsOneSidedPair)), + ImmutablePairList(allPairs.Where(p => p.Key.IsOneSidedPair)))); + + return drawFolders; } } + private static bool PassesFilter(Pair pair, string filter) + { + if (string.IsNullOrEmpty(filter)) return true; + + return pair.UserData.AliasOrUID.Contains(filter, StringComparison.OrdinalIgnoreCase) || (pair.GetNote()?.Contains(filter, StringComparison.OrdinalIgnoreCase) ?? false) || (pair.PlayerName?.Contains(filter, StringComparison.OrdinalIgnoreCase) ?? false); + } + + private string AlphabeticalSortKey(Pair pair) + { + if (_configService.Current.ShowCharacterNameInsteadOfNotesForVisible && !string.IsNullOrEmpty(pair.PlayerName)) + { + return _configService.Current.PreferNotesOverNamesForVisible ? (pair.GetNote() ?? string.Empty) : pair.PlayerName; + } + + return pair.GetNote() ?? pair.UserData.AliasOrUID; + } + + private bool FilterOnlineOrPausedSelf(Pair pair) => pair.IsOnline || (!pair.IsOnline && !_configService.Current.ShowOfflineUsersSeparately) || pair.UserPair.OwnPermissions.IsPaused(); + + private bool FilterVisibleUsers(Pair pair) => pair.IsVisible && (_configService.Current.ShowSyncshellUsersInVisible || pair.IsDirectlyPaired); + + private bool FilterTagUsers(Pair pair, string tag) => pair.IsDirectlyPaired && !pair.IsOneSidedPair && _tagHandler.HasPairTag(pair.UserData.UID, tag); + + private static bool FilterGroupUsers(List groups, GroupFullInfoDto group) => groups.Exists(g => string.Equals(g.GID, group.GID, StringComparison.Ordinal)); + + private bool FilterNotTaggedUsers(Pair pair) => pair.IsDirectlyPaired && !pair.IsOneSidedPair && !_tagHandler.HasAnyPairTag(pair.UserData.UID); + + private bool FilterNotTaggedSyncshells(GroupFullInfoDto group) => !_tagHandler.HasAnySyncshellTag(group.GID) || _configService.Current.ShowGroupedSyncshellsInAll; + + private bool FilterOfflineUsers(Pair pair, List groups) => ((pair.IsDirectlyPaired && _configService.Current.ShowSyncshellOfflineUsersSeparately) || !_configService.Current.ShowSyncshellOfflineUsersSeparately) && (!pair.IsOneSidedPair || groups.Count != 0) && !pair.IsOnline && !pair.UserPair.OwnPermissions.IsPaused(); + + private static bool FilterOfflineSyncshellUsers(Pair pair) => !pair.IsDirectlyPaired && !pair.IsOnline && !pair.UserPair.OwnPermissions.IsPaused(); + + private Dictionary> BasicSortedDictionary(IEnumerable>> pairs) => pairs.OrderByDescending(u => u.Key.IsVisible).ThenByDescending(u => u.Key.IsOnline).ThenBy(u => AlphabeticalSortKey(u.Key), StringComparer.OrdinalIgnoreCase).ToDictionary(u => u.Key, u => u.Value); + + private static ImmutableList ImmutablePairList(IEnumerable>> pairs) => [.. pairs.Select(k => k.Key)]; + + private void GetGroups(Dictionary> allPairs, + Dictionary> filteredPairs, + GroupFullInfoDto group, + out ImmutableList allGroupPairs, + out Dictionary> filteredGroupPairs) + { + allGroupPairs = ImmutablePairList(allPairs + .Where(u => FilterGroupUsers(u.Value, group))); + + filteredGroupPairs = filteredPairs + .Where(u => FilterGroupUsers( u.Value, group) && FilterOnlineOrPausedSelf(u.Key)) + .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(u => AlphabeticalSortKey(u.Key), StringComparer.OrdinalIgnoreCase) + .ToDictionary(k => k.Key, k => k.Value); + } + private string GetServerError() { return _apiController.ServerState switch