Merge branch '1.12.0' into ui-redesign
This commit is contained in:
Submodule LightlessAPI updated: fd4cd52d2e...5bfd21aaa9
@@ -230,7 +230,7 @@ public sealed class Plugin : IDalamudPlugin
|
||||
s.GetRequiredService<LightlessProfileManager>(), s.GetRequiredService<PerformanceCollectorService>()));
|
||||
collection.AddScoped<WindowMediatorSubscriberBase, PopupHandler>();
|
||||
collection.AddScoped<WindowMediatorSubscriberBase, BroadcastUI>((s) => new BroadcastUI(s.GetRequiredService<ILogger<BroadcastUI>>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<PerformanceCollectorService>(), s.GetRequiredService<BroadcastService>(), s.GetRequiredService<LightlessConfigService>(), s.GetRequiredService<UiSharedService>(), s.GetRequiredService<ApiController>(), s.GetRequiredService<BroadcastScannerService>()));
|
||||
collection.AddScoped<WindowMediatorSubscriberBase, SyncshellFinderUI>((s) => new SyncshellFinderUI(s.GetRequiredService<ILogger<SyncshellFinderUI>>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<PerformanceCollectorService>(), s.GetRequiredService<BroadcastService>(), s.GetRequiredService<LightlessConfigService>(), s.GetRequiredService<UiSharedService>(), s.GetRequiredService<ApiController>(), s.GetRequiredService<BroadcastScannerService>()));
|
||||
collection.AddScoped<WindowMediatorSubscriberBase, SyncshellFinderUI>((s) => new SyncshellFinderUI(s.GetRequiredService<ILogger<SyncshellFinderUI>>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<PerformanceCollectorService>(), s.GetRequiredService<BroadcastService>(), s.GetRequiredService<UiSharedService>(), s.GetRequiredService<ApiController>(), s.GetRequiredService<BroadcastScannerService>(), s.GetRequiredService<PairManager>()));
|
||||
collection.AddScoped<IPopupHandler, BanUserPopupHandler>();
|
||||
collection.AddScoped<IPopupHandler, CensusPopupHandler>();
|
||||
collection.AddScoped<CacheCreationService>();
|
||||
|
||||
@@ -4,9 +4,7 @@ using LightlessSync.LightlessConfiguration;
|
||||
using LightlessSync.Services.Mediator;
|
||||
using LightlessSync.Utils;
|
||||
using LightlessSync.WebAPI;
|
||||
using LightlessSync.WebAPI.SignalR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -16,7 +14,6 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
||||
private readonly ILogger<BroadcastService> _logger;
|
||||
private readonly ApiController _apiController;
|
||||
private readonly LightlessMediator _mediator;
|
||||
private readonly HubFactory _hubFactory;
|
||||
private readonly LightlessConfigService _config;
|
||||
private readonly DalamudUtilService _dalamudUtil;
|
||||
public LightlessMediator Mediator => _mediator;
|
||||
@@ -29,35 +26,37 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
||||
private TimeSpan? _remainingTtl = null;
|
||||
private DateTime _lastTtlCheck = DateTime.MinValue;
|
||||
private DateTime _lastForcedDisableTime = DateTime.MinValue;
|
||||
private static readonly TimeSpan DisableCooldown = TimeSpan.FromSeconds(5);
|
||||
private static readonly TimeSpan _disableCooldown = TimeSpan.FromSeconds(5);
|
||||
public TimeSpan? RemainingTtl => _remainingTtl;
|
||||
public TimeSpan? RemainingCooldown
|
||||
{
|
||||
get
|
||||
{
|
||||
var elapsed = DateTime.UtcNow - _lastForcedDisableTime;
|
||||
if (elapsed >= DisableCooldown) return null;
|
||||
return DisableCooldown - elapsed;
|
||||
if (elapsed >= _disableCooldown) return null;
|
||||
return _disableCooldown - elapsed;
|
||||
}
|
||||
}
|
||||
public BroadcastService(ILogger<BroadcastService> logger, LightlessMediator mediator, HubFactory hubFactory, LightlessConfigService config, DalamudUtilService dalamudUtil, ApiController apiController)
|
||||
|
||||
public BroadcastService(ILogger<BroadcastService> logger, LightlessMediator mediator, LightlessConfigService config, DalamudUtilService dalamudUtil, ApiController apiController)
|
||||
{
|
||||
_logger = logger;
|
||||
_mediator = mediator;
|
||||
_hubFactory = hubFactory;
|
||||
_config = config;
|
||||
_dalamudUtil = dalamudUtil;
|
||||
_apiController = apiController;
|
||||
}
|
||||
|
||||
private async Task RequireConnectionAsync(string context, Func<Task> action)
|
||||
{
|
||||
if (!_apiController.IsConnected)
|
||||
{
|
||||
_logger.LogDebug($"{context} skipped, not connected");
|
||||
_logger.LogDebug(context + " skipped, not connected");
|
||||
return;
|
||||
}
|
||||
await action().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_mediator.Subscribe<EnableBroadcastMessage>(this, OnEnableBroadcast);
|
||||
@@ -65,7 +64,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
||||
_mediator.Subscribe<PriorityFrameworkUpdateMessage>(this, OnTick);
|
||||
|
||||
_apiController.OnConnected += () => _ = CheckLightfinderSupportAsync(cancellationToken);
|
||||
_ = CheckLightfinderSupportAsync(cancellationToken);
|
||||
//_ = CheckLightfinderSupportAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
@@ -86,13 +85,12 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var hub = _hubFactory.GetOrCreate(CancellationToken.None);
|
||||
var dummy = "0".PadLeft(64, '0');
|
||||
|
||||
await hub.InvokeAsync<BroadcastStatusInfoDto?>("IsUserBroadcasting", dummy, cancellationToken);
|
||||
await hub.InvokeAsync("SetBroadcastStatus", dummy, true, null, cancellationToken);
|
||||
await hub.InvokeAsync<TimeSpan?>("GetBroadcastTtl", dummy, cancellationToken);
|
||||
await hub.InvokeAsync<Dictionary<string, BroadcastStatusInfoDto?>>("AreUsersBroadcasting", new[] { dummy }, cancellationToken);
|
||||
await _apiController.IsUserBroadcasting(dummy).ConfigureAwait(false);
|
||||
await _apiController.SetBroadcastStatus(dummy, true, null).ConfigureAwait(false);
|
||||
await _apiController.GetBroadcastTtl(dummy).ConfigureAwait(false);
|
||||
await _apiController.AreUsersBroadcasting([dummy]).ConfigureAwait(false);
|
||||
|
||||
IsLightFinderAvailable = true;
|
||||
_logger.LogInformation("Lightfinder is available.");
|
||||
@@ -119,6 +117,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
||||
_config.Current.BroadcastEnabled = false;
|
||||
_config.Current.BroadcastTtl = DateTime.MinValue;
|
||||
_config.Save();
|
||||
|
||||
_mediator.Publish(new BroadcastStatusChangedMessage(false, null));
|
||||
}
|
||||
}
|
||||
@@ -157,7 +156,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
||||
|
||||
_waitingForTtlFetch = true;
|
||||
|
||||
var ttl = await GetBroadcastTtlAsync(msg.HashedCid).ConfigureAwait(false);
|
||||
TimeSpan? ttl = await GetBroadcastTtlAsync(msg.HashedCid).ConfigureAwait(false);
|
||||
|
||||
if (ttl is { } remaining && remaining > TimeSpan.Zero)
|
||||
{
|
||||
@@ -325,8 +324,8 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
||||
_syncedOnStartup = true;
|
||||
try
|
||||
{
|
||||
var hashedCid = (await _dalamudUtil.GetCIDAsync().ConfigureAwait(false)).ToString().GetHash256();
|
||||
var ttl = await GetBroadcastTtlAsync(hashedCid).ConfigureAwait(false);
|
||||
string hashedCid = (await _dalamudUtil.GetCIDAsync().ConfigureAwait(false)).ToString().GetHash256();
|
||||
TimeSpan? ttl = await GetBroadcastTtlAsync(hashedCid).ConfigureAwait(false);
|
||||
if (ttl is { }
|
||||
remaining && remaining > TimeSpan.Zero)
|
||||
{
|
||||
@@ -357,8 +356,8 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
||||
return;
|
||||
}
|
||||
|
||||
var expiry = _config.Current.BroadcastTtl;
|
||||
var remaining = expiry - DateTime.UtcNow;
|
||||
DateTime expiry = _config.Current.BroadcastTtl;
|
||||
TimeSpan remaining = expiry - DateTime.UtcNow;
|
||||
_remainingTtl = remaining > TimeSpan.Zero ? remaining : null;
|
||||
if (_remainingTtl == null)
|
||||
{
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace LightlessSync.UI
|
||||
|
||||
try
|
||||
{
|
||||
_allSyncshells = await _apiController.GroupsGetAll();
|
||||
_allSyncshells = await _apiController.GroupsGetAll().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -131,7 +131,7 @@ namespace LightlessSync.UI
|
||||
ImGuiHelpers.ScaledDummy(0.25f);
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabBar("##MyTabBar"))
|
||||
if (ImGui.BeginTabBar("##BroadcastTabs"))
|
||||
{
|
||||
if (ImGui.BeginTabItem("Lightfinder"))
|
||||
{
|
||||
|
||||
@@ -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<CutsceneEndMessage>(this, (_) => UiSharedService_GposeEnd());
|
||||
Mediator.Subscribe<DownloadStartedMessage>(this, (msg) => _currentDownloads[msg.DownloadId] = msg.DownloadStatus);
|
||||
Mediator.Subscribe<DownloadFinishedMessage>(this, (msg) => _currentDownloads.TryRemove(msg.DownloadId, out _));
|
||||
Mediator.Subscribe<RefreshUiMessage>(this, (msg) => _drawFolders = GetDrawFolders().ToList());
|
||||
Mediator.Subscribe<RefreshUiMessage>(this, (msg) => _drawFolders = DrawFolders.ToList());
|
||||
|
||||
Flags |= ImGuiWindowFlags.NoDocking;
|
||||
|
||||
@@ -561,6 +561,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
if ((isOverTriHold || isOverVRAMUsage) && _playerPerformanceConfig.Current.WarnOnExceedingThresholds)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosY(cursorY + 15f);
|
||||
_uiSharedService.IconText(FontAwesomeIcon.ExclamationTriangle, UIColors.Get("LightlessYellow"));
|
||||
|
||||
string warningMessage = "";
|
||||
@@ -611,152 +612,151 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IDrawFolder> GetDrawFolders()
|
||||
private IEnumerable<IDrawFolder> DrawFolders
|
||||
{
|
||||
List<IDrawFolder> drawFolders = [];
|
||||
|
||||
var allPairs = _pairManager.PairsWithGroups
|
||||
.ToDictionary(k => k.Key, k => k.Value);
|
||||
var filteredPairs = allPairs
|
||||
.Where(p =>
|
||||
get
|
||||
{
|
||||
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<Pair, List<GroupFullInfoDto>> 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<Pair, List<GroupFullInfoDto>> u)
|
||||
=> (u.Key.IsOnline || (!u.Key.IsOnline && !_configService.Current.ShowOfflineUsersSeparately)
|
||||
|| u.Key.UserPair.OwnPermissions.IsPaused());
|
||||
Dictionary<Pair, List<GroupFullInfoDto>> BasicSortedDictionary(IEnumerable<KeyValuePair<Pair, List<GroupFullInfoDto>>> u)
|
||||
=> u.OrderByDescending(u => u.Key.IsVisible)
|
||||
.ThenByDescending(u => u.Key.IsOnline)
|
||||
.ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(u => u.Key, u => u.Value);
|
||||
ImmutableList<Pair> ImmutablePairList(IEnumerable<KeyValuePair<Pair, List<GroupFullInfoDto>>> u)
|
||||
=> u.Select(k => k.Key).ToImmutableList();
|
||||
bool FilterVisibleUsers(KeyValuePair<Pair, List<GroupFullInfoDto>> u)
|
||||
=> u.Key.IsVisible
|
||||
&& (_configService.Current.ShowSyncshellUsersInVisible || !(!_configService.Current.ShowSyncshellUsersInVisible && !u.Key.IsDirectlyPaired));
|
||||
bool FilterTagUsers(KeyValuePair<Pair, List<GroupFullInfoDto>> u, string tag)
|
||||
=> u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && _tagHandler.HasPairTag(u.Key.UserData.UID, tag);
|
||||
bool FilterGroupUsers(KeyValuePair<Pair, List<GroupFullInfoDto>> u, GroupFullInfoDto group)
|
||||
=> u.Value.Exists(g => string.Equals(g.GID, group.GID, StringComparison.Ordinal));
|
||||
bool FilterNotTaggedUsers(KeyValuePair<Pair, List<GroupFullInfoDto>> u)
|
||||
=> u.Key.IsDirectlyPaired && !u.Key.IsOneSidedPair && !_tagHandler.HasAnyPairTag(u.Key.UserData.UID);
|
||||
bool FilterNotTaggedSyncshells(GroupFullInfoDto group)
|
||||
=> (!_tagHandler.HasAnySyncshellTag(group.GID) && !_configService.Current.ShowGroupedSyncshellsInAll) || true;
|
||||
bool FilterOfflineUsers(KeyValuePair<Pair, List<GroupFullInfoDto>> 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<Pair, List<GroupFullInfoDto>> u)
|
||||
=> (!u.Key.IsDirectlyPaired && !u.Key.IsOnline && !u.Key.UserPair.OwnPermissions.IsPaused());
|
||||
var drawFolders = new List<IDrawFolder>();
|
||||
var filter = _tabMenu.Filter;
|
||||
|
||||
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);
|
||||
|
||||
//Filter of online/visible pairs
|
||||
if (_configService.Current.ShowVisibleUsersSeparately)
|
||||
{
|
||||
var allVisiblePairs = ImmutablePairList(allPairs
|
||||
.Where(FilterVisibleUsers));
|
||||
var filteredVisiblePairs = BasicSortedDictionary(filteredPairs
|
||||
.Where(FilterVisibleUsers));
|
||||
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));
|
||||
}
|
||||
|
||||
List<IDrawFolder> groupFolders = new();
|
||||
|
||||
//Filter of not foldered syncshells
|
||||
var groupFolders = new List<IDrawFolder>();
|
||||
foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
GetGroups(allPairs, filteredPairs, group, out ImmutableList<Pair> allGroupPairs, out Dictionary<Pair, List<GroupFullInfoDto>> filteredGroupPairs);
|
||||
|
||||
if (FilterNotTaggedSyncshells(group))
|
||||
{
|
||||
groupFolders.Add(_drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs));
|
||||
}
|
||||
}
|
||||
|
||||
//Filter of grouped up syncshells (All Syncshells Folder)
|
||||
if (_configService.Current.GroupUpSyncshells)
|
||||
drawFolders.Add(new DrawGroupedGroupFolder(groupFolders, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, ""));
|
||||
drawFolders.Add(new DrawGroupedGroupFolder(groupFolders, _tagHandler, _uiSharedService,
|
||||
_selectSyncshellForTagUi, _renameSyncshellTagUi, ""));
|
||||
else
|
||||
drawFolders.AddRange(groupFolders);
|
||||
|
||||
var tags = _tagHandler.GetAllPairTagsSorted();
|
||||
foreach (var tag in tags)
|
||||
//Filter of grouped/foldered pairs
|
||||
foreach (var tag in _tagHandler.GetAllPairTagsSorted())
|
||||
{
|
||||
var allTagPairs = ImmutablePairList(allPairs
|
||||
.Where(u => FilterTagUsers(u, tag)));
|
||||
var filteredTagPairs = BasicSortedDictionary(filteredPairs
|
||||
.Where(u => FilterTagUsers(u, tag) && FilterOnlineOrPausedSelf(u)));
|
||||
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(tag, filteredTagPairs, allTagPairs));
|
||||
}
|
||||
|
||||
var syncshellTags = _tagHandler.GetAllSyncshellTagsSorted();
|
||||
foreach (var syncshelltag in syncshellTags)
|
||||
//Filter of grouped/foldered syncshells
|
||||
foreach (var syncshellTag in _tagHandler.GetAllSyncshellTagsSorted())
|
||||
{
|
||||
List<IDrawFolder> syncshellFolderTags = [];
|
||||
var syncshellFolderTags = new List<IDrawFolder>();
|
||||
foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
if (_tagHandler.HasSyncshellTag(group.GID, syncshelltag))
|
||||
if (_tagHandler.HasSyncshellTag(group.GID, syncshellTag))
|
||||
{
|
||||
GetGroups(allPairs, filteredPairs, group, out ImmutableList<Pair> allGroupPairs, out Dictionary<Pair, List<GroupFullInfoDto>> filteredGroupPairs);
|
||||
GetGroups(allPairs, filteredPairs, group,
|
||||
out ImmutableList<Pair> allGroupPairs,
|
||||
out Dictionary<Pair, List<GroupFullInfoDto>> filteredGroupPairs);
|
||||
|
||||
syncshellFolderTags.Add(_drawEntityFactory.CreateDrawGroupFolder($"tag_{group.GID}", group, filteredGroupPairs, allGroupPairs));
|
||||
}
|
||||
}
|
||||
|
||||
if (syncshellFolderTags.Count > 0)
|
||||
{
|
||||
drawFolders.Add(new DrawGroupedGroupFolder(syncshellFolderTags, _tagHandler, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, syncshelltag));
|
||||
}
|
||||
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 not grouped/foldered and 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));
|
||||
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));
|
||||
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(FilterOfflineSyncshellUsers));
|
||||
var filteredOfflineSyncshellUsers = BasicSortedDictionary(filteredPairs
|
||||
.Where(FilterOfflineSyncshellUsers));
|
||||
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.CustomOfflineSyncshellTag, filteredOfflineSyncshellUsers, allOfflineSyncshellUsers));
|
||||
}
|
||||
}
|
||||
|
||||
//Unpaired
|
||||
drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomUnpairedTag,
|
||||
BasicSortedDictionary(filteredPairs.Where(u => u.Key.IsOneSidedPair)),
|
||||
ImmutablePairList(allPairs.Where(u => u.Key.IsOneSidedPair))));
|
||||
BasicSortedDictionary(filteredPairs.Where(p => p.Key.IsOneSidedPair)),
|
||||
ImmutablePairList(allPairs.Where(p => p.Key.IsOneSidedPair))));
|
||||
|
||||
return drawFolders;
|
||||
}
|
||||
}
|
||||
|
||||
void GetGroups(Dictionary<Pair, List<GroupFullInfoDto>> allPairs, Dictionary<Pair, List<GroupFullInfoDto>> filteredPairs, GroupFullInfoDto group, out ImmutableList<Pair> allGroupPairs, out Dictionary<Pair, List<GroupFullInfoDto>> filteredGroupPairs)
|
||||
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<GroupFullInfoDto> 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<GroupFullInfoDto> 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<Pair, List<GroupFullInfoDto>> BasicSortedDictionary(IEnumerable<KeyValuePair<Pair, List<GroupFullInfoDto>>> 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<Pair> ImmutablePairList(IEnumerable<KeyValuePair<Pair, List<GroupFullInfoDto>>> pairs) => [.. pairs.Select(k => k.Key)];
|
||||
|
||||
private void GetGroups(Dictionary<Pair, List<GroupFullInfoDto>> allPairs,
|
||||
Dictionary<Pair, List<GroupFullInfoDto>> filteredPairs,
|
||||
GroupFullInfoDto group,
|
||||
out ImmutableList<Pair> allGroupPairs,
|
||||
out Dictionary<Pair, List<GroupFullInfoDto>> filteredGroupPairs)
|
||||
{
|
||||
allGroupPairs = ImmutablePairList(allPairs
|
||||
.Where(u => FilterGroupUsers(u, group)));
|
||||
.Where(u => FilterGroupUsers(u.Value, group)));
|
||||
|
||||
filteredGroupPairs = filteredPairs
|
||||
.Where(u => FilterGroupUsers(u, group) && FilterOnlineOrPausedSelf(u))
|
||||
.Where(u => FilterGroupUsers( u.Value, group) && FilterOnlineOrPausedSelf(u.Key))
|
||||
.OrderByDescending(u => u.Key.IsOnline)
|
||||
.ThenBy(u =>
|
||||
{
|
||||
@@ -768,10 +768,9 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
return u.Key.IsVisible ? 3 : 4;
|
||||
})
|
||||
.ThenBy(AlphabeticalSort, StringComparer.OrdinalIgnoreCase)
|
||||
.ThenBy(u => AlphabeticalSortKey(u.Key), StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(k => k.Key, k => k.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetServerError()
|
||||
{
|
||||
|
||||
@@ -34,8 +34,6 @@ public class DrawGroupedGroupFolder : IDrawFolder
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (!_groups.Any()) return;
|
||||
|
||||
string _id = "__folder_syncshells";
|
||||
if (_tag != "")
|
||||
{
|
||||
|
||||
@@ -4,14 +4,17 @@ using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using LightlessSync.API.Data;
|
||||
using LightlessSync.API.Dto.User;
|
||||
using LightlessSync.Services;
|
||||
using LightlessSync.Services.Mediator;
|
||||
using LightlessSync.Utils;
|
||||
using LightlessSync.WebAPI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System.Numerics;
|
||||
|
||||
namespace LightlessSync.UI;
|
||||
|
||||
@@ -30,6 +33,15 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
||||
private bool _showFileDialogError = false;
|
||||
private bool _wasOpen;
|
||||
|
||||
private bool vanityInitialized; // useless for now
|
||||
private bool textEnabled;
|
||||
private bool glowEnabled;
|
||||
private Vector4 textColor;
|
||||
private Vector4 glowColor;
|
||||
|
||||
private record VanityState(bool TextEnabled, bool GlowEnabled, Vector4 TextColor, Vector4 GlowColor);
|
||||
private VanityState _savedVanity;
|
||||
|
||||
public EditProfileUi(ILogger<EditProfileUi> logger, LightlessMediator mediator,
|
||||
ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager,
|
||||
LightlessProfileManager lightlessProfileManager, PerformanceCollectorService performanceCollectorService)
|
||||
@@ -38,8 +50,8 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
||||
IsOpen = false;
|
||||
this.SizeConstraints = new()
|
||||
{
|
||||
MinimumSize = new(768, 512),
|
||||
MaximumSize = new(768, 2000)
|
||||
MinimumSize = new(850, 640),
|
||||
MaximumSize = new(850, 700)
|
||||
};
|
||||
_apiController = apiController;
|
||||
_uiSharedService = uiSharedService;
|
||||
@@ -57,14 +69,61 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
||||
_pfpTextureWrap = null;
|
||||
}
|
||||
});
|
||||
Mediator.Subscribe<ConnectedMessage>(this, msg =>
|
||||
{
|
||||
LoadVanity();
|
||||
});
|
||||
}
|
||||
|
||||
void DrawNoteLine(string icon, Vector4 color, string text)
|
||||
{
|
||||
_uiSharedService.MediumText(icon, color);
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
|
||||
ImGui.TextWrapped(text);
|
||||
}
|
||||
|
||||
private void LoadVanity()
|
||||
{
|
||||
textEnabled = !string.IsNullOrEmpty(_apiController.TextColorHex);
|
||||
glowEnabled = !string.IsNullOrEmpty(_apiController.TextGlowColorHex);
|
||||
|
||||
textColor = textEnabled ? UIColors.HexToRgba(_apiController.TextColorHex!) : Vector4.One;
|
||||
glowColor = glowEnabled ? UIColors.HexToRgba(_apiController.TextGlowColorHex!) : Vector4.Zero;
|
||||
|
||||
_savedVanity = new VanityState(textEnabled, glowEnabled, textColor, glowColor);
|
||||
vanityInitialized = true;
|
||||
}
|
||||
|
||||
protected override void DrawInternal()
|
||||
{
|
||||
_uiSharedService.BigText("Current Profile (as saved on server)");
|
||||
_uiSharedService.UnderlinedBigText("Notes and Rules for Profiles", UIColors.Get("LightlessYellow"));
|
||||
ImGui.Dummy(new Vector2(5));
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(2, 2));
|
||||
|
||||
DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "All users that are paired and unpaused with you will be able to see your profile picture and description.");
|
||||
DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Other users have the possibility to report your profile for breaking the rules.");
|
||||
DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Anything as profile image that can be considered highly illegal or obscene (bestiality, anything that could be considered a sexual act with a minor (that includes Lalafells), etc.)");
|
||||
DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Slurs of any kind in the description that can be considered highly offensive");
|
||||
DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "In case of valid reports from other users this can lead to disabling your profile forever or terminating your Lightless account indefinitely.");
|
||||
DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Judgement of your profile validity from reports through staff is not up to debate and the decisions to disable your profile/account permanent.");
|
||||
DrawNoteLine("! ", UIColors.Get("LightlessBlue"), "If your profile picture or profile description could be considered NSFW, enable the toggle in profile settings.");
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
ImGui.Dummy(new Vector2(3));
|
||||
|
||||
var profile = _lightlessProfileManager.GetLightlessProfile(new UserData(_apiController.UID));
|
||||
|
||||
if (ImGui.BeginTabBar("##EditProfileTabs"))
|
||||
{
|
||||
if (ImGui.BeginTabItem("Current Profile"))
|
||||
{
|
||||
_uiSharedService.MediumText("Current Profile (as saved on server)", UIColors.Get("LightlessPurple"));
|
||||
ImGui.Dummy(new Vector2(5));
|
||||
|
||||
if (profile.IsFlagged)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(profile.Description, ImGuiColors.DalamudRed);
|
||||
@@ -119,18 +178,14 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
||||
ImGui.Checkbox("Is NSFW", ref nsfw);
|
||||
ImGui.EndDisabled();
|
||||
|
||||
ImGui.Separator();
|
||||
_uiSharedService.BigText("Notes and Rules for Profiles");
|
||||
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
ImGui.TextWrapped($"- All users that are paired and unpaused with you will be able to see your profile picture and description.{Environment.NewLine}" +
|
||||
$"- Other users have the possibility to report your profile for breaking the rules.{Environment.NewLine}" +
|
||||
$"- !!! AVOID: anything as profile image that can be considered highly illegal or obscene (bestiality, anything that could be considered a sexual act with a minor (that includes Lalafells), etc.){Environment.NewLine}" +
|
||||
$"- !!! AVOID: slurs of any kind in the description that can be considered highly offensive{Environment.NewLine}" +
|
||||
$"- In case of valid reports from other users this can lead to disabling your profile forever or terminating your Lightless account indefinitely.{Environment.NewLine}" +
|
||||
$"- Judgement of your profile validity from reports through staff is not up to debate and the decisions to disable your profile/account permanent.{Environment.NewLine}" +
|
||||
$"- If your profile picture or profile description could be considered NSFW, enable the toggle below.");
|
||||
ImGui.Separator();
|
||||
_uiSharedService.BigText("Profile Settings");
|
||||
if (ImGui.BeginTabItem("Profile Settings"))
|
||||
{
|
||||
_uiSharedService.MediumText("Profile Settings", UIColors.Get("LightlessPurple"));
|
||||
ImGui.Dummy(new Vector2(5));
|
||||
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture"))
|
||||
{
|
||||
@@ -223,6 +278,105 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
||||
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, ProfilePictureBase64: null, ""));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Clears your profile description text");
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem("Vanity Settings"))
|
||||
{
|
||||
_uiSharedService.MediumText("Supporter Vanity Settings", UIColors.Get("LightlessPurple"));
|
||||
ImGui.Dummy(new Vector2(4));
|
||||
DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "Must be a supporter through Patreon/Ko-fi to access these settings.");
|
||||
|
||||
var hasVanity = _apiController.HasVanity;
|
||||
|
||||
if (!hasVanity)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("You do not currently have vanity access. Become a supporter to unlock these features.", UIColors.Get("DimRed"));
|
||||
ImGui.Dummy(new Vector2(8));
|
||||
ImGui.BeginDisabled();
|
||||
}
|
||||
|
||||
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
|
||||
_uiSharedService.MediumText("Colored UID", UIColors.Get("LightlessPurple"));
|
||||
ImGui.Dummy(new Vector2(5));
|
||||
|
||||
var font = UiBuilder.MonoFont;
|
||||
var playerUID = _apiController.UID;
|
||||
var playerDisplay = _apiController.DisplayName;
|
||||
|
||||
var previewTextColor = textEnabled ? textColor : Vector4.One;
|
||||
var previewGlowColor = glowEnabled ? glowColor : Vector4.Zero;
|
||||
|
||||
var seString = SeStringUtils.BuildFormattedPlayerName(playerDisplay, previewTextColor, previewGlowColor);
|
||||
|
||||
using (ImRaii.PushFont(font))
|
||||
{
|
||||
var offsetX = 10f;
|
||||
var pos = ImGui.GetCursorScreenPos() + new Vector2(offsetX, 0);
|
||||
var size = ImGui.CalcTextSize(seString.TextValue);
|
||||
|
||||
var padding = new Vector2(6, 3);
|
||||
var rectMin = pos - padding;
|
||||
var rectMax = pos + size + padding;
|
||||
|
||||
var bgColor = new Vector4(0.15f, 0.15f, 0.15f, 1f);
|
||||
var borderColor = UIColors.Get("LightlessPurple");
|
||||
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
drawList.AddRectFilled(rectMin, rectMax, ImGui.GetColorU32(bgColor), 6.0f);
|
||||
drawList.AddRect(rectMin, rectMax, ImGui.GetColorU32(borderColor), 6.0f, ImDrawFlags.None, 1.5f);
|
||||
|
||||
SeStringUtils.RenderSeStringWithHitbox(seString, pos, font);
|
||||
}
|
||||
|
||||
const float colorPickAlign = 90f;
|
||||
|
||||
DrawNoteLine("- ", UIColors.Get("LightlessPurple"), "Text Color");
|
||||
ImGui.SameLine(colorPickAlign);
|
||||
ImGui.Checkbox("##toggleTextColor", ref textEnabled);
|
||||
ImGui.SameLine();
|
||||
ImGui.BeginDisabled(!textEnabled);
|
||||
ImGui.ColorEdit4($"##color_text", ref textColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf);
|
||||
ImGui.EndDisabled();
|
||||
|
||||
DrawNoteLine("- ", UIColors.Get("LightlessPurple"), "Glow Color");
|
||||
ImGui.SameLine(colorPickAlign);
|
||||
ImGui.Checkbox("##toggleGlowColor", ref glowEnabled);
|
||||
ImGui.SameLine();
|
||||
ImGui.BeginDisabled(!glowEnabled);
|
||||
ImGui.ColorEdit4($"##color_glow", ref glowColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf);
|
||||
ImGui.EndDisabled();
|
||||
|
||||
bool changed = !Equals(_savedVanity, new VanityState(textEnabled, glowEnabled, textColor, glowColor));
|
||||
|
||||
if (!changed)
|
||||
ImGui.BeginDisabled();
|
||||
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Changes"))
|
||||
{
|
||||
string? newText = textEnabled ? UIColors.RgbaToHex(textColor) : string.Empty;
|
||||
string? newGlow = glowEnabled ? UIColors.RgbaToHex(glowColor) : string.Empty;
|
||||
|
||||
_ = _apiController.UserUpdateVanityColors(new UserVanityColorsDto(newText, newGlow));
|
||||
|
||||
_savedVanity = new VanityState(textEnabled, glowEnabled, textColor, glowColor);
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
ImGui.EndDisabled();
|
||||
|
||||
ImGui.Dummy(new Vector2(5));
|
||||
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||
|
||||
if (!hasVanity)
|
||||
ImGui.EndDisabled();
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
||||
@@ -98,20 +98,21 @@ public class IdDisplayHandler
|
||||
|
||||
var font = UiBuilder.MonoFont;
|
||||
|
||||
var isAdmin = pair.UserData.IsAdmin;
|
||||
var isModerator = pair.UserData.IsModerator;
|
||||
Vector4? textColor = null;
|
||||
Vector4? glowColor = null;
|
||||
|
||||
Vector4? textColor = isAdmin
|
||||
? UIColors.Get("LightlessAdminText")
|
||||
: isModerator
|
||||
? UIColors.Get("LightlessModeratorText")
|
||||
: null;
|
||||
if (pair.UserData.HasVanity)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(pair.UserData.TextColorHex))
|
||||
{
|
||||
textColor = UIColors.HexToRgba(pair.UserData.TextColorHex);
|
||||
}
|
||||
|
||||
Vector4? glowColor = isAdmin
|
||||
? UIColors.Get("LightlessAdminGlow")
|
||||
: isModerator
|
||||
? UIColors.Get("LightlessModeratorGlow")
|
||||
: null;
|
||||
if (!string.IsNullOrWhiteSpace(pair.UserData.TextGlowColorHex))
|
||||
{
|
||||
glowColor = UIColors.HexToRgba(pair.UserData.TextGlowColorHex);
|
||||
}
|
||||
}
|
||||
|
||||
var seString = (textColor != null || glowColor != null)
|
||||
? SeStringUtils.BuildFormattedPlayerName(playerText, textColor, glowColor)
|
||||
|
||||
@@ -167,7 +167,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
else
|
||||
{
|
||||
UiSharedService.TextWrapped("To not unnecessary download files already present on your computer, Lightless Sync will have to scan your Penumbra mod directory. " +
|
||||
UiSharedService.TextWrapped("To not unnecessarily download files already present on your computer, Lightless Sync will have to scan your Penumbra mod directory. " +
|
||||
"Additionally, a local storage folder must be set where Lightless Sync will download other character files to. " +
|
||||
"Once the storage folder is set and the scan complete, this page will automatically forward to registration at a service.");
|
||||
UiSharedService.TextWrapped("Note: The initial scan, depending on the amount of mods you have, might take a while. Please wait until it is completed.");
|
||||
|
||||
@@ -63,7 +63,7 @@ internal class JoinSyncshellUI : WindowMediatorSubscriberBase
|
||||
"Joining a Syncshell will pair you implicitly with all existing users in the Syncshell." + Environment.NewLine +
|
||||
"All permissions to all users in the Syncshell will be set to the preferred Syncshell permissions on joining, excluding prior set preferred permissions.");
|
||||
ImGui.Separator();
|
||||
ImGui.TextUnformatted("Note: Syncshell ID and Password are case sensitive. MSS- is part of Syncshell IDs, unless using Vanity IDs.");
|
||||
ImGui.TextUnformatted("Note: Syncshell ID and Password are case sensitive. LLS- is part of Syncshell IDs, unless using Vanity IDs.");
|
||||
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted("Syncshell ID");
|
||||
|
||||
@@ -1152,12 +1152,12 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
_uiShared.DrawHelpText("This will group up all Syncshells in a special 'All Syncshells' folder in the main UI.");
|
||||
|
||||
//if (ImGui.Checkbox("Show grouped syncshells in main screen/all syncshells", ref groupedSyncshells))
|
||||
//{
|
||||
// _configService.Current.ShowGroupedSyncshellsInAll = groupedSyncshells;
|
||||
// _configService.Save();
|
||||
// Mediator.Publish(new RefreshUiMessage());
|
||||
//}
|
||||
if (ImGui.Checkbox("Show grouped syncshells in main screen/all syncshells", ref groupedSyncshells))
|
||||
{
|
||||
_configService.Current.ShowGroupedSyncshellsInAll = groupedSyncshells;
|
||||
_configService.Save();
|
||||
Mediator.Publish(new RefreshUiMessage());
|
||||
}
|
||||
_uiShared.DrawHelpText("This will show grouped syncshells in main screen or group 'All Syncshells'.");
|
||||
|
||||
if (ImGui.Checkbox("Show player name for visible players", ref showNameInsteadOfNotes))
|
||||
|
||||
@@ -336,7 +336,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
ImGui.Separator();
|
||||
|
||||
if (_uiSharedService.MediumTreeNode("Mass Cleanup", UIColors.Get("LightlessPurple")))
|
||||
if (_uiSharedService.MediumTreeNode("Mass Cleanup", UIColors.Get("DimRed")))
|
||||
{
|
||||
using (ImRaii.Disabled(!UiSharedService.CtrlPressed()))
|
||||
{
|
||||
@@ -348,6 +348,18 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
UiSharedService.AttachToolTip("This will remove all non-pinned, non-moderator users from the Syncshell."
|
||||
+ UiSharedService.TooltipSeparator + "Hold CTRL to enable this button");
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
using (ImRaii.Disabled(!UiSharedService.CtrlPressed()))
|
||||
{
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Brush, "Clear Lightfinder Users"))
|
||||
{
|
||||
_ = _apiController.GroupClearFinder(new(GroupFullInfo.Group));
|
||||
}
|
||||
}
|
||||
UiSharedService.AttachToolTip("This will remove all users that joined through Lightfinder from the Syncshell."
|
||||
+ UiSharedService.TooltipSeparator + "Hold CTRL to enable this button");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(2f);
|
||||
ImGui.Separator();
|
||||
ImGuiHelpers.ScaledDummy(2f);
|
||||
@@ -410,12 +422,12 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
UiSharedService.TextWrapped($"Syncshell was pruned and {_pruneTask.Result} inactive user(s) have been removed.");
|
||||
}
|
||||
}
|
||||
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||
_uiSharedService.ColoredSeparator(UIColors.Get("DimRed"), 1.5f);
|
||||
ImGui.TreePop();
|
||||
}
|
||||
ImGui.Separator();
|
||||
|
||||
if (_uiSharedService.MediumTreeNode("User Bans", UIColors.Get("LightlessPurple")))
|
||||
if (_uiSharedService.MediumTreeNode("User Bans", UIColors.Get("LightlessYellow")))
|
||||
{
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Retweet, "Refresh Banlist from Server"))
|
||||
{
|
||||
@@ -456,7 +468,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
ImGui.EndTable();
|
||||
}
|
||||
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
|
||||
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
|
||||
ImGui.TreePop();
|
||||
}
|
||||
ImGui.Separator();
|
||||
|
||||
@@ -4,15 +4,15 @@ using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using LightlessSync.API.Data.Enum;
|
||||
using LightlessSync.API.Data.Extensions;
|
||||
using LightlessSync.API.Dto;
|
||||
using LightlessSync.API.Dto.Group;
|
||||
using LightlessSync.LightlessConfiguration;
|
||||
using LightlessSync.PlayerData.Pairs;
|
||||
using LightlessSync.Services;
|
||||
using LightlessSync.Services.Mediator;
|
||||
using LightlessSync.Utils;
|
||||
using LightlessSync.WebAPI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using LightlessSync.API.Data.Extensions;
|
||||
using System.Numerics;
|
||||
|
||||
namespace LightlessSync.UI;
|
||||
@@ -20,12 +20,13 @@ namespace LightlessSync.UI;
|
||||
public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
{
|
||||
private readonly ApiController _apiController;
|
||||
private readonly LightlessConfigService _configService;
|
||||
private readonly BroadcastService _broadcastService;
|
||||
private readonly UiSharedService _uiSharedService;
|
||||
private readonly BroadcastScannerService _broadcastScannerService;
|
||||
private readonly PairManager _pairManager;
|
||||
|
||||
private readonly List<GroupJoinDto> _nearbySyncshells = new();
|
||||
private readonly List<GroupJoinDto> _nearbySyncshells = [];
|
||||
private List<GroupFullInfoDto> _currentSyncshells = [];
|
||||
private int _selectedNearbyIndex = -1;
|
||||
|
||||
private GroupJoinDto? _joinDto;
|
||||
@@ -37,17 +38,16 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
LightlessMediator mediator,
|
||||
PerformanceCollectorService performanceCollectorService,
|
||||
BroadcastService broadcastService,
|
||||
LightlessConfigService configService,
|
||||
UiSharedService uiShared,
|
||||
ApiController apiController,
|
||||
BroadcastScannerService broadcastScannerService
|
||||
) : base(logger, mediator, "Shellfinder###LightlessSyncshellFinderUI", performanceCollectorService)
|
||||
BroadcastScannerService broadcastScannerService,
|
||||
PairManager pairManager) : base(logger, mediator, "Shellfinder###LightlessSyncshellFinderUI", performanceCollectorService)
|
||||
{
|
||||
_broadcastService = broadcastService;
|
||||
_uiSharedService = uiShared;
|
||||
_configService = configService;
|
||||
_apiController = apiController;
|
||||
_broadcastScannerService = broadcastScannerService;
|
||||
_pairManager = pairManager;
|
||||
|
||||
IsOpen = false;
|
||||
SizeConstraints = new()
|
||||
@@ -56,14 +56,14 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
MaximumSize = new(600, 550)
|
||||
};
|
||||
|
||||
Mediator.Subscribe<SyncshellBroadcastsUpdatedMessage>(this, async _ => await RefreshSyncshellsAsync());
|
||||
Mediator.Subscribe<BroadcastStatusChangedMessage>(this, async _ => await RefreshSyncshellsAsync());
|
||||
Mediator.Subscribe<SyncshellBroadcastsUpdatedMessage>(this, async _ => await RefreshSyncshellsAsync().ConfigureAwait(false));
|
||||
Mediator.Subscribe<BroadcastStatusChangedMessage>(this, async _ => await RefreshSyncshellsAsync().ConfigureAwait(false));
|
||||
}
|
||||
|
||||
public override async void OnOpen()
|
||||
{
|
||||
_ownPermissions = _apiController.DefaultPermissions.DeepClone()!;
|
||||
await RefreshSyncshellsAsync();
|
||||
await RefreshSyncshellsAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected override void DrawInternal()
|
||||
@@ -107,10 +107,8 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
ImGui.TableSetupColumn("Join", ImGuiTableColumnFlags.WidthFixed, 80f * ImGuiHelpers.GlobalScale);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
for (int i = 0; i < _nearbySyncshells.Count; i++)
|
||||
foreach (var shell in _nearbySyncshells)
|
||||
{
|
||||
var shell = _nearbySyncshells[i];
|
||||
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(shell.Group.Alias ?? "(No Alias)");
|
||||
@@ -123,6 +121,10 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, UIColors.Get("LightlessGreen").WithAlpha(0.85f));
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, UIColors.Get("LightlessGreen").WithAlpha(0.75f));
|
||||
|
||||
if (!_currentSyncshells.Exists(g => string.Equals(g.GID, shell.GID, StringComparison.Ordinal)))
|
||||
{
|
||||
|
||||
|
||||
if (ImGui.Button(label))
|
||||
{
|
||||
_logger.LogInformation($"Join requested for Syncshell {shell.Group.GID} ({shell.Group.Alias})");
|
||||
@@ -156,8 +158,16 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
using (ImRaii.Disabled())
|
||||
{
|
||||
ImGui.Button(label);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Already a member or owner of this Syncshell.");
|
||||
}
|
||||
ImGui.PopStyleColor(3);
|
||||
}
|
||||
|
||||
@@ -169,6 +179,8 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
|
||||
private void DrawConfirmation()
|
||||
{
|
||||
if (_joinDto != null && _joinInfo != null)
|
||||
{
|
||||
ImGui.Separator();
|
||||
ImGui.TextUnformatted($"Join Syncshell: {_joinDto.Group.AliasOrGID} by {_joinInfo.OwnerAliasOrUID}");
|
||||
@@ -194,6 +206,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
_joinInfo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPermissionRow(string label, bool suggested, bool current, Action<bool> apply)
|
||||
{
|
||||
@@ -224,6 +237,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
private async Task RefreshSyncshellsAsync()
|
||||
{
|
||||
var syncshellBroadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
|
||||
_currentSyncshells = _pairManager.GroupPairs.Select(g => g.Key).ToList();
|
||||
|
||||
if (syncshellBroadcasts.Count == 0)
|
||||
{
|
||||
@@ -231,11 +245,11 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
return;
|
||||
}
|
||||
|
||||
List<GroupJoinDto> updatedList;
|
||||
List<GroupJoinDto> updatedList = [];
|
||||
try
|
||||
{
|
||||
var groups = await _apiController.GetBroadcastedGroups(syncshellBroadcasts);
|
||||
updatedList = groups?.ToList() ?? new();
|
||||
var groups = await _apiController.GetBroadcastedGroups(syncshellBroadcasts).ConfigureAwait(false);
|
||||
updatedList = groups?.ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -243,8 +257,8 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
return;
|
||||
}
|
||||
|
||||
var currentGids = _nearbySyncshells.Select(s => s.Group.GID).ToHashSet();
|
||||
var newGids = updatedList.Select(s => s.Group.GID).ToHashSet();
|
||||
var currentGids = _nearbySyncshells.Select(s => s.Group.GID).ToHashSet(StringComparer.Ordinal);
|
||||
var newGids = updatedList.Select(s => s.Group.GID).ToHashSet(StringComparer.Ordinal);
|
||||
|
||||
if (currentGids.SetEquals(newGids))
|
||||
return;
|
||||
@@ -256,7 +270,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
|
||||
if (previousGid != null)
|
||||
{
|
||||
var newIndex = _nearbySyncshells.FindIndex(s => s.Group.GID == previousGid);
|
||||
var newIndex = _nearbySyncshells.FindIndex(s => string.Equals(s.Group.GID, previousGid, StringComparison.Ordinal));
|
||||
if (newIndex >= 0)
|
||||
{
|
||||
_selectedNearbyIndex = newIndex;
|
||||
@@ -290,9 +304,4 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
|
||||
return _nearbySyncshells[_selectedNearbyIndex].Group.GID;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,12 @@ public partial class ApiController
|
||||
await _lightlessHub!.InvokeAsync(nameof(UserSetProfile), userDescription).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task UserUpdateVanityColors(UserVanityColorsDto dto)
|
||||
{
|
||||
if (!IsConnected) return;
|
||||
await _lightlessHub!.InvokeAsync(nameof(UserUpdateVanityColors), dto).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task UserUpdateDefaultPermissions(DefaultPermissionsDto defaultPermissionsDto)
|
||||
{
|
||||
CheckConnection();
|
||||
|
||||
@@ -277,6 +277,12 @@ public partial class ApiController
|
||||
_lightlessHub!.On(nameof(Client_GroupSendInfo), act);
|
||||
}
|
||||
|
||||
public void OnGroupUpdateProfile(Action<GroupProfileDto> act)
|
||||
{
|
||||
if (_initialized) return;
|
||||
_lightlessHub!.On(nameof(Client_GroupSendProfile), act);
|
||||
}
|
||||
|
||||
public void OnReceiveServerMessage(Action<MessageSeverity, string> act)
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
@@ -45,6 +45,11 @@ public partial class ApiController
|
||||
CheckConnection();
|
||||
await _lightlessHub!.SendAsync(nameof(GroupClear), group).ConfigureAwait(false);
|
||||
}
|
||||
public async Task GroupClearFinder(GroupDto group)
|
||||
{
|
||||
CheckConnection();
|
||||
await _lightlessHub!.SendAsync(nameof(GroupClearFinder), group).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<GroupJoinDto> GroupCreate()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using LightlessSync.API.Data;
|
||||
using LightlessSync.API.Data.Extensions;
|
||||
using LightlessSync.API.Dto;
|
||||
using LightlessSync.API.Dto.Group;
|
||||
using LightlessSync.API.Dto.User;
|
||||
using LightlessSync.API.SignalR;
|
||||
using LightlessSync.LightlessConfiguration;
|
||||
@@ -76,6 +77,10 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL
|
||||
public DefaultPermissionsDto? DefaultPermissions => _connectionDto?.DefaultPreferredPermissions ?? null;
|
||||
public string DisplayName => _connectionDto?.User.AliasOrUID ?? string.Empty;
|
||||
|
||||
public bool HasVanity => _connectionDto?.HasVanity ?? false;
|
||||
public string TextColorHex => _connectionDto?.TextColorHex ?? string.Empty;
|
||||
public string TextGlowColorHex => _connectionDto?.TextGlowColorHex ?? string.Empty;
|
||||
|
||||
public bool IsConnected => ServerState == ServerState.Connected;
|
||||
|
||||
public bool IsCurrentVersion => (Assembly.GetExecutingAssembly().GetName().Version ?? new Version(0, 0, 0, 0)) >= (_connectionDto?.CurrentClientVersion ?? new Version(0, 0, 0, 0));
|
||||
@@ -444,6 +449,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL
|
||||
OnGroupPairLeft((dto) => _ = Client_GroupPairLeft(dto));
|
||||
OnGroupSendFullInfo((dto) => _ = Client_GroupSendFullInfo(dto));
|
||||
OnGroupSendInfo((dto) => _ = Client_GroupSendInfo(dto));
|
||||
OnGroupUpdateProfile((dto) => _ = Client_GroupSendProfile(dto));
|
||||
OnGroupChangeUserPairPermissions((dto) => _ = Client_GroupChangeUserPairPermissions(dto));
|
||||
|
||||
OnGposeLobbyJoin((dto) => _ = Client_GposeLobbyJoin(dto));
|
||||
@@ -596,5 +602,20 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL
|
||||
|
||||
ServerState = state;
|
||||
}
|
||||
|
||||
public Task Client_GroupSendProfile(GroupProfileDto groupInfo)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<GroupProfileDto> GroupGetProfile(GroupDto dto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task GroupSetProfile(GroupProfileDto dto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
#pragma warning restore MA0040
|
||||
Reference in New Issue
Block a user