Initialize migration. (#88)

Co-authored-by: defnotken <itsdefnotken@gmail.com>
Co-authored-by: cake <admin@cakeandbanana.nl>
Reviewed-on: #88
Reviewed-by: cake <cake@noreply.git.lightless-sync.org>
Co-authored-by: defnotken <defnotken@noreply.git.lightless-sync.org>
Co-committed-by: defnotken <defnotken@noreply.git.lightless-sync.org>
This commit was merged in pull request #88.
This commit is contained in:
2025-11-29 18:02:39 +01:00
committed by cake
parent 9e12725f89
commit 740b58afc4
63 changed files with 1720 additions and 1005 deletions

View File

@@ -2,6 +2,7 @@ using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
using Dalamud.Utility;
using LightlessSync.API.Dto.Group;
using LightlessSync.LightlessConfiguration;
using LightlessSync.Services;
@@ -21,7 +22,7 @@ namespace LightlessSync.UI
private readonly UiSharedService _uiSharedService;
private readonly BroadcastScannerService _broadcastScannerService;
private IReadOnlyList<GroupFullInfoDto> _allSyncshells;
private IReadOnlyList<GroupFullInfoDto> _allSyncshells = Array.Empty<GroupFullInfoDto>();
private string _userUid = string.Empty;
private readonly List<(string Label, string? GID, bool IsAvailable)> _syncshellOptions = new();
@@ -191,7 +192,7 @@ namespace LightlessSync.UI
ImGui.PopStyleVar();
ImGuiHelpers.ScaledDummy(3f);
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
if (_configService.Current.BroadcastEnabled)
{
@@ -287,7 +288,7 @@ namespace LightlessSync.UI
_uiSharedService.MediumText("Syncshell Finder", UIColors.Get("PairBlue"));
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
ImGui.PushTextWrapPos();
ImGui.Text("Allow your owned Syncshell to be indexed by the Nearby Syncshell Finder.");
@@ -295,7 +296,7 @@ namespace LightlessSync.UI
ImGui.PopTextWrapPos();
ImGuiHelpers.ScaledDummy(0.2f);
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
bool ShellFinderEnabled = _configService.Current.SyncshellFinderEnabled;
bool isBroadcasting = _broadcastService.IsBroadcasting;

View File

@@ -13,13 +13,15 @@ internal sealed partial class CharaDataHubUi
AccessTypeDto.AllPairs => "All Pairs",
AccessTypeDto.ClosePairs => "Direct Pairs",
AccessTypeDto.Individuals => "Specified",
AccessTypeDto.Public => "Everyone"
AccessTypeDto.Public => "Everyone",
_ => throw new NotSupportedException()
};
private static string GetShareTypeString(ShareTypeDto dto) => dto switch
{
ShareTypeDto.Private => "Code Only",
ShareTypeDto.Shared => "Shared"
ShareTypeDto.Shared => "Shared",
_ => throw new NotSupportedException()
};
private static string GetWorldDataTooltipText(PoseEntryExtended poseEntry)
@@ -31,7 +33,7 @@ internal sealed partial class CharaDataHubUi
private void GposeMetaInfoAction(Action<CharaDataMetaInfoExtendedDto?> gposeActionDraw, string actionDescription, CharaDataMetaInfoExtendedDto? dto, bool hasValidGposeTarget, bool isSpawning)
{
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.AppendLine(actionDescription);
bool isDisabled = false;

View File

@@ -406,7 +406,7 @@ internal sealed partial class CharaDataHubUi
{
_uiSharedService.BigText("Poses");
var poseCount = updateDto.PoseList.Count();
using (ImRaii.Disabled(poseCount >= maxPoses))
using (ImRaii.Disabled(poseCount >= _maxPoses))
{
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "Add new Pose"))
{
@@ -414,8 +414,8 @@ internal sealed partial class CharaDataHubUi
}
}
ImGui.SameLine();
using (ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("LightlessYellow"), poseCount == maxPoses))
ImGui.TextUnformatted($"{poseCount}/{maxPoses} poses attached");
using (ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("LightlessYellow"), poseCount == _maxPoses))
ImGui.TextUnformatted($"{poseCount}/{_maxPoses} poses attached");
ImGuiHelpers.ScaledDummy(5);
using var indent = ImRaii.PushIndent(10f);
@@ -463,12 +463,16 @@ internal sealed partial class CharaDataHubUi
else
{
var desc = pose.Description;
if (ImGui.InputTextWithHint("##description", "Description", ref desc, 100))
if (desc != null)
{
pose.Description = desc;
updateDto.UpdatePoseList();
if (ImGui.InputTextWithHint("##description", "Description", ref desc, 100))
{
pose.Description = desc;
updateDto.UpdatePoseList();
}
ImGui.SameLine();
}
ImGui.SameLine();
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete"))
{
updateDto.RemovePose(pose);

View File

@@ -21,7 +21,7 @@ namespace LightlessSync.UI;
internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
{
private const int maxPoses = 10;
private const int _maxPoses = 10;
private readonly CharaDataManager _charaDataManager;
private readonly CharaDataNearbyManager _charaDataNearbyManager;
private readonly CharaDataConfigService _configService;
@@ -33,7 +33,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
private readonly UiSharedService _uiSharedService;
private CancellationTokenSource _closalCts = new();
private bool _disableUI = false;
private CancellationTokenSource _disposalCts = new();
private readonly CancellationTokenSource _disposalCts = new();
private string _exportDescription = string.Empty;
private string _filterCodeNote = string.Empty;
private string _filterDescription = string.Empty;
@@ -145,6 +145,8 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
{
_closalCts.CancelDispose();
_disposalCts.CancelDispose();
_disposalCts.Dispose();
_closalCts.Dispose();
}
base.Dispose(disposing);

View File

@@ -27,6 +27,7 @@ using System.Collections.Immutable;
using System.Globalization;
using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
namespace LightlessSync.UI;
@@ -310,7 +311,7 @@ public class CompactUi : WindowMediatorSubscriberBase
private void DrawPairs()
{
var ySize = _transferPartHeight == 0
float ySize = Math.Abs(_transferPartHeight) < 0.0001f
? 1
: (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y
+ ImGui.GetTextLineHeight() - ImGui.GetStyle().WindowPadding.Y - ImGui.GetStyle().WindowBorderSize) - _transferPartHeight - ImGui.GetCursorPosY();
@@ -510,6 +511,7 @@ public class CompactUi : WindowMediatorSubscriberBase
return new DownloadSummary(totalFiles, transferredFiles, transferredBytes, totalBytes);
}
[StructLayout(LayoutKind.Auto)]
private readonly record struct DownloadSummary(int TotalFiles, int TransferredFiles, long TransferredBytes, long TotalBytes)
{
public bool HasDownloads => TotalFiles > 0 || TotalBytes > 0;
@@ -590,7 +592,7 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.PopStyleColor();
ImGuiHelpers.ScaledDummy(0.2f);
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
if (_configService.Current.BroadcastEnabled)
{

View File

@@ -119,6 +119,7 @@ public class DrawFolderGroup : DrawFolderBase
if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleLeft, "Leave Syncshell", menuWidth, true) && UiSharedService.CtrlPressed())
{
_ = _apiController.GroupLeave(_groupFullInfoDto);
_lightlessMediator.Publish(new UserLeftSyncshell(_groupFullInfoDto.GID));
ImGui.CloseCurrentPopup();
}
UiSharedService.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (!string.Equals(_groupFullInfoDto.OwnerUID, _apiController.UID, StringComparison.Ordinal)

View File

@@ -5,6 +5,7 @@ using LightlessSync.LightlessConfiguration.Models;
using LightlessSync.PlayerData.Handlers;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
using LightlessSync.Services.PairProcessing;
using LightlessSync.WebAPI.Files;
using LightlessSync.WebAPI.Files.Models;
using Microsoft.Extensions.Logging;
@@ -22,6 +23,7 @@ public class DownloadUi : WindowMediatorSubscriberBase
private readonly UiSharedService _uiShared;
private readonly PairProcessingLimiter _pairProcessingLimiter;
private readonly ConcurrentDictionary<GameObjectHandler, bool> _uploadingPlayers = new();
private readonly Dictionary<GameObjectHandler, Vector2> _smoothed = [];
private bool _notificationDismissed = true;
private int _lastDownloadStateHash = 0;
@@ -203,8 +205,18 @@ public class DownloadUi : WindowMediatorSubscriberBase
foreach (var transfer in _currentDownloads.ToList())
{
var screenPos = _dalamudUtilService.WorldToScreen(transfer.Key.GetGameObject());
if (screenPos == Vector2.Zero) continue;
var transferKey = transfer.Key;
var rawPos = _dalamudUtilService.WorldToScreen(transferKey.GetGameObject());
//If RawPos is zero, remove it from smoothed dictionary
if (rawPos == Vector2.Zero)
{
_smoothed.Remove(transferKey);
continue;
}
//Smoothing out the movement and fix jitter around the position.
Vector2 screenPos = _smoothed.TryGetValue(transferKey, out var lastPos) ? (rawPos - lastPos).Length() < 4f ? lastPos : rawPos : rawPos;
_smoothed[transferKey] = screenPos;
var totalBytes = transfer.Value.Sum(c => c.Value.TotalBytes);
var transferredBytes = transfer.Value.Sum(c => c.Value.TransferredBytes);

View File

@@ -347,7 +347,7 @@ public sealed class DtrEntry : IDisposable, IHostedService
try
{
var cid = _dalamudUtilService.GetCIDAsync().GetAwaiter().GetResult();
var hashedCid = cid.ToString().GetHash256();
var hashedCid = cid.ToString().GetBlake3Hash();
_localHashedCid = hashedCid;
_localHashedCidFetchedAt = now;
return hashedCid;
@@ -445,7 +445,7 @@ public sealed class DtrEntry : IDisposable, IHostedService
return ($"{icon} OFF", colors, tooltip.ToString());
}
private (string, Colors, string) FormatTooltip(string title, IEnumerable<string> names, string icon, Colors color)
private static (string, Colors, string) FormatTooltip(string title, IEnumerable<string> names, string icon, Colors color)
{
var list = names.Where(x => !string.IsNullOrEmpty(x)).ToList();
var tooltip = new StringBuilder()

View File

@@ -9,6 +9,7 @@ using LightlessSync.API.Data;
using LightlessSync.API.Dto.Group;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
using LightlessSync.Services.Profiles;
using LightlessSync.UI.Tags;
using LightlessSync.Utils;
using Microsoft.Extensions.Logging;

View File

@@ -25,6 +25,7 @@ using System.IO;
using System.Numerics;
using System.Threading.Tasks;
using System.Linq;
using LightlessSync.Services.Profiles;
namespace LightlessSync.UI;
@@ -91,14 +92,13 @@ public partial class EditProfileUi : WindowMediatorSubscriberBase
private bool _wasOpen;
private Vector4 _currentBg = new(0.15f, 0.15f, 0.15f, 1f);
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;
private sealed 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,
@@ -161,7 +161,6 @@ public partial class EditProfileUi : WindowMediatorSubscriberBase
glowColor = glowEnabled ? UIColors.HexToRgba(_apiController.TextGlowColorHex!) : Vector4.Zero;
_savedVanity = new VanityState(textEnabled, glowEnabled, textColor, glowColor);
vanityInitialized = true;
}
public override async void OnOpen()

View File

@@ -177,13 +177,11 @@ public class IdDisplayHandler
Vector2 itemMin;
Vector2 itemMax;
Vector2 textSize;
using (ImRaii.PushFont(font, textIsUid))
{
SeStringUtils.RenderSeStringWithHitbox(seString, rowStart, font, pair.UserData.UID);
itemMin = ImGui.GetItemRectMin();
itemMax = ImGui.GetItemRectMax();
//textSize = itemMax - itemMin;
}
if (useHighlight)
@@ -227,7 +225,7 @@ public class IdDisplayHandler
var nameRectMax = ImGui.GetItemRectMax();
if (ImGui.IsItemHovered())
{
if (!string.Equals(_lastMouseOverUid, id))
if (!string.Equals(_lastMouseOverUid, id, StringComparison.Ordinal))
{
_popupTime = DateTime.UtcNow.AddSeconds(_lightlessConfigService.Current.ProfileDelay);
}
@@ -248,7 +246,7 @@ public class IdDisplayHandler
}
else
{
if (string.Equals(_lastMouseOverUid, id))
if (string.Equals(_lastMouseOverUid, id, StringComparison.Ordinal))
{
_mediator.Publish(new ProfilePopoutToggle(Pair: null));
_lastMouseOverUid = string.Empty;

View File

@@ -267,7 +267,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
{
UiSharedService.ColorTextWrapped("Your secret key must be exactly 64 characters long. Don't enter your Lodestone auth here.", ImGuiColors.DalamudRed);
}
else if (_secretKey.Length == 64 && !HexRegex().IsMatch(_secretKey))
else if (_secretKey.Length == 64 && !SecretRegex().IsMatch(_secretKey))
{
UiSharedService.ColorTextWrapped("Your secret key can only contain ABCDEF and the numbers 0-9.", ImGuiColors.DalamudRed);
}
@@ -360,6 +360,6 @@ public partial class IntroUi : WindowMediatorSubscriberBase
_tosParagraphs = [Strings.ToS.Paragraph1, Strings.ToS.Paragraph2, Strings.ToS.Paragraph3, Strings.ToS.Paragraph4, Strings.ToS.Paragraph5, Strings.ToS.Paragraph6];
}
[GeneratedRegex("^([A-F0-9]{2})+")]
private static partial Regex HexRegex();
[GeneratedRegex("^[A-F0-9]{64}$", RegexOptions.Compiled | RegexOptions.CultureInvariant)]
private static partial Regex SecretRegex();
}

View File

@@ -1,5 +1,4 @@
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using LightlessSync.API.Data.Enum;
@@ -174,6 +173,7 @@ internal class JoinSyncshellUI : WindowMediatorSubscriberBase
joinPermissions.SetDisableAnimations(_ownPermissions.DisableGroupAnimations);
joinPermissions.SetDisableVFX(_ownPermissions.DisableGroupVFX);
_ = _apiController.GroupJoinFinalize(new GroupJoinDto(_groupJoinInfo.Group, _previousPassword, joinPermissions));
Mediator.Publish(new UserJoinedSyncshell(_groupJoinInfo.Group.GID));
IsOpen = false;
}
}

View File

@@ -1,8 +1,6 @@
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using LightlessSync.LightlessConfiguration;
using LightlessSync.LightlessConfiguration.Models;
using LightlessSync.Services;
@@ -27,11 +25,11 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
private const float _titleMessageSpacing = 4f;
private const float _actionButtonSpacing = 8f;
private readonly List<LightlessNotification> _notifications = new();
private readonly List<LightlessNotification> _notifications = [];
private readonly object _notificationLock = new();
private readonly LightlessConfigService _configService;
private readonly Dictionary<string, float> _notificationYOffsets = new();
private readonly Dictionary<string, float> _notificationTargetYOffsets = new();
private readonly Dictionary<string, float> _notificationYOffsets = [];
private readonly Dictionary<string, float> _notificationTargetYOffsets = [];
public LightlessNotificationUi(ILogger<LightlessNotificationUi> logger, LightlessMediator mediator, PerformanceCollectorService performanceCollector, LightlessConfigService configService)
: base(logger, mediator, "Lightless Notifications##LightlessNotifications", performanceCollector)
@@ -45,7 +43,6 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
ImGuiWindowFlags.NoNav |
ImGuiWindowFlags.NoBackground |
ImGuiWindowFlags.NoCollapse |
ImGuiWindowFlags.NoInputs |
ImGuiWindowFlags.NoTitleBar |
ImGuiWindowFlags.NoScrollbar |
ImGuiWindowFlags.AlwaysAutoResize;
@@ -68,7 +65,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
{
lock (_notificationLock)
{
var existingNotification = _notifications.FirstOrDefault(n => n.Id == notification.Id);
var existingNotification = _notifications.FirstOrDefault(n => string.Equals(n.Id, notification.Id, StringComparison.Ordinal));
if (existingNotification != null)
{
UpdateExistingNotification(existingNotification, notification);
@@ -103,7 +100,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
{
lock (_notificationLock)
{
var notification = _notifications.FirstOrDefault(n => n.Id == id);
var notification = _notifications.FirstOrDefault(n => string.Equals(n.Id, id, StringComparison.Ordinal));
if (notification != null)
{
StartOutAnimation(notification);
@@ -122,13 +119,13 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
}
}
private void StartOutAnimation(LightlessNotification notification)
private static void StartOutAnimation(LightlessNotification notification)
{
notification.IsAnimatingOut = true;
notification.IsAnimatingIn = false;
}
private bool ShouldRemoveNotification(LightlessNotification notification) =>
private static bool ShouldRemoveNotification(LightlessNotification notification) =>
notification.IsAnimatingOut && notification.AnimationProgress <= 0.01f;
protected override void DrawInternal()
@@ -185,7 +182,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
ImGui.SetCursorPosY(startY + yOffset);
}
DrawNotification(notification, i);
DrawNotification(notification);
}
}
@@ -304,7 +301,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
return corner == NotificationCorner.Left ? new Vector2(-distance, 0) : new Vector2(distance, 0);
}
private void DrawNotification(LightlessNotification notification, int index)
private void DrawNotification(LightlessNotification notification)
{
var alpha = notification.AnimationProgress;
if (alpha <= 0f) return;
@@ -339,7 +336,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
var bgColor = CalculateBackgroundColor(alpha, ImGui.IsWindowHovered());
var accentColor = GetNotificationAccentColor(notification.Type);
accentColor.W *= alpha;
DrawShadow(drawList, windowPos, windowSize, alpha);
HandleClickToDismiss(notification);
DrawBackground(drawList, windowPos, windowSize, bgColor);
@@ -370,7 +367,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
return bgColor;
}
private void DrawShadow(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, float alpha)
private static void DrawShadow(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, float alpha)
{
var shadowOffset = new Vector2(1f, 1f);
var shadowColor = new Vector4(0f, 0f, 0f, 0.4f * alpha);
@@ -384,9 +381,13 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
private void HandleClickToDismiss(LightlessNotification notification)
{
if (ImGui.IsWindowHovered() &&
var pos = ImGui.GetWindowPos();
var size = ImGui.GetWindowSize();
bool hovered = ImGui.IsMouseHoveringRect(pos, new Vector2(pos.X + size.X, pos.Y + size.Y));
if ((hovered || ImGui.IsWindowHovered()) &&
_configService.Current.DismissNotificationOnClick &&
!notification.Actions.Any() &&
notification.Actions.Count == 0 &&
ImGui.IsMouseClicked(ImGuiMouseButton.Left))
{
notification.IsDismissed = true;
@@ -394,7 +395,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
}
}
private void DrawBackground(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 bgColor)
private static void DrawBackground(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 bgColor)
{
drawList.AddRectFilled(
windowPos,
@@ -431,14 +432,14 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
);
}
private void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
private static void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
{
var progress = CalculateDurationProgress(notification);
var progressBarColor = UIColors.Get("LightlessBlue");
var progressHeight = 2f;
var progressY = windowPos.Y + windowSize.Y - progressHeight;
var progressWidth = windowSize.X * progress;
DrawProgressBackground(drawList, windowPos, windowSize, progressY, progressHeight, progressBarColor, alpha);
if (progress > 0)
@@ -447,7 +448,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
}
}
private void DrawDownloadProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
private static void DrawDownloadProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
{
var progress = Math.Clamp(notification.Progress, 0f, 1f);
var progressBarColor = UIColors.Get("LightlessGreen");
@@ -455,7 +456,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
// Position above the duration bar (2px duration bar + 1px spacing)
var progressY = windowPos.Y + windowSize.Y - progressHeight - 3f;
var progressWidth = windowSize.X * progress;
DrawProgressBackground(drawList, windowPos, windowSize, progressY, progressHeight, progressBarColor, alpha);
if (progress > 0)
@@ -464,14 +465,14 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
}
}
private float CalculateDurationProgress(LightlessNotification notification)
private static float CalculateDurationProgress(LightlessNotification notification)
{
// Calculate duration timer progress
var elapsed = DateTime.UtcNow - notification.CreatedAt;
return Math.Min(1.0f, (float)(elapsed.TotalSeconds / notification.Duration.TotalSeconds));
}
private void DrawProgressBackground(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, float progressY, float progressHeight, Vector4 progressBarColor, float alpha)
private static void DrawProgressBackground(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, float progressY, float progressHeight, Vector4 progressBarColor, float alpha)
{
var bgProgressColor = new Vector4(progressBarColor.X * 0.3f, progressBarColor.Y * 0.3f, progressBarColor.Z * 0.3f, 0.5f * alpha);
drawList.AddRectFilled(
@@ -482,7 +483,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
);
}
private void DrawProgressForeground(ImDrawListPtr drawList, Vector2 windowPos, float progressY, float progressHeight, float progressWidth, Vector4 progressBarColor, float alpha)
private static void DrawProgressForeground(ImDrawListPtr drawList, Vector2 windowPos, float progressY, float progressHeight, float progressWidth, Vector4 progressBarColor, float alpha)
{
var progressColor = progressBarColor;
progressColor.W *= alpha;
@@ -512,13 +513,13 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
}
}
private float CalculateContentWidth(float windowWidth) =>
private static float CalculateContentWidth(float windowWidth) =>
windowWidth - (_contentPaddingX * 2);
private bool HasActions(LightlessNotification notification) =>
private static bool HasActions(LightlessNotification notification) =>
notification.Actions.Count > 0;
private void PositionActionsAtBottom(float windowHeight)
private static void PositionActionsAtBottom(float windowHeight)
{
var actionHeight = ImGui.GetFrameHeight();
var bottomY = windowHeight - _contentPaddingY - actionHeight;
@@ -546,7 +547,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
return $"[{timestamp}] {notification.Title}";
}
private float DrawWrappedText(string text, float wrapWidth)
private static float DrawWrappedText(string text, float wrapWidth)
{
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + wrapWidth);
var startY = ImGui.GetCursorPosY();
@@ -556,7 +557,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
return height;
}
private void DrawMessage(LightlessNotification notification, Vector2 contentPos, float contentWidth, float titleHeight, float alpha)
private static void DrawMessage(LightlessNotification notification, Vector2 contentPos, float contentWidth, float titleHeight, float alpha)
{
if (string.IsNullOrEmpty(notification.Message)) return;
@@ -591,13 +592,13 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
}
}
private float CalculateActionButtonWidth(int actionCount, float availableWidth)
private static float CalculateActionButtonWidth(int actionCount, float availableWidth)
{
var totalSpacing = (actionCount - 1) * _actionButtonSpacing;
return (availableWidth - totalSpacing) / actionCount;
}
private void PositionActionButton(int index, float startX, float buttonWidth)
private static void PositionActionButton(int index, float startX, float buttonWidth)
{
var xPosition = startX + index * (buttonWidth + _actionButtonSpacing);
ImGui.SetCursorPosX(xPosition);
@@ -625,7 +626,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
if (action.Icon != FontAwesomeIcon.None)
{
buttonPressed = DrawIconTextButton(action.Icon, action.Label, buttonWidth, alpha);
buttonPressed = DrawIconTextButton(action.Icon, action.Label, buttonWidth);
}
else
{
@@ -650,10 +651,10 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
}
}
private bool DrawIconTextButton(FontAwesomeIcon icon, string text, float width, float alpha)
private static bool DrawIconTextButton(FontAwesomeIcon icon, string text, float width)
{
var drawList = ImGui.GetWindowDrawList();
var cursorPos = ImGui.GetCursorScreenPos();
ImGui.GetCursorScreenPos();
var frameHeight = ImGui.GetFrameHeight();
Vector2 iconSize;
@@ -729,7 +730,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
return ImGui.CalcTextSize(titleText, true, contentWidth).Y;
}
private float CalculateMessageHeight(LightlessNotification notification, float contentWidth)
private static float CalculateMessageHeight(LightlessNotification notification, float contentWidth)
{
if (string.IsNullOrEmpty(notification.Message)) return 0f;
@@ -737,7 +738,7 @@ public class LightlessNotificationUi : WindowMediatorSubscriberBase
return 4f + messageHeight;
}
private Vector4 GetNotificationAccentColor(NotificationType type)
private static Vector4 GetNotificationAccentColor(NotificationType type)
{
return type switch
{

View File

@@ -1,43 +0,0 @@
namespace LightlessSync.UI.Models
{
public class ChangelogFile
{
public string Tagline { get; init; } = string.Empty;
public string Subline { get; init; } = string.Empty;
public List<ChangelogEntry> Changelog { get; init; } = new();
public List<CreditCategory>? Credits { get; init; }
}
public class ChangelogEntry
{
public string Name { get; init; } = string.Empty;
public string Date { get; init; } = string.Empty;
public string Tagline { get; init; } = string.Empty;
public bool? IsCurrent { get; init; }
public string? Message { get; init; }
public List<ChangelogVersion>? Versions { get; init; }
}
public class ChangelogVersion
{
public string Number { get; init; } = string.Empty;
public List<string> Items { get; init; } = new();
}
public class CreditCategory
{
public string Category { get; init; } = string.Empty;
public List<CreditItem> Items { get; init; } = new();
}
public class CreditItem
{
public string Name { get; init; } = string.Empty;
public string Role { get; init; } = string.Empty;
}
public class CreditsFile
{
public List<CreditCategory> Credits { get; init; } = new();
}
}

View File

@@ -0,0 +1,12 @@
namespace LightlessSync.UI.Models
{
public class ChangelogEntry
{
public string Name { get; init; } = string.Empty;
public string Date { get; init; } = string.Empty;
public string Tagline { get; init; } = string.Empty;
public bool? IsCurrent { get; init; }
public string? Message { get; init; }
public List<ChangelogVersion>? Versions { get; init; }
}
}

View File

@@ -0,0 +1,10 @@
namespace LightlessSync.UI.Models
{
public class ChangelogFile
{
public string Tagline { get; init; } = string.Empty;
public string Subline { get; init; } = string.Empty;
public List<ChangelogEntry> Changelog { get; init; } = new();
public List<CreditCategory>? Credits { get; init; }
}
}

View File

@@ -0,0 +1,8 @@
namespace LightlessSync.UI.Models
{
public class ChangelogVersion
{
public string Number { get; init; } = string.Empty;
public List<string> Items { get; init; } = [];
}
}

View File

@@ -0,0 +1,8 @@
namespace LightlessSync.UI.Models
{
public class CreditCategory
{
public string Category { get; init; } = string.Empty;
public List<CreditItem> Items { get; init; } = [];
}
}

View File

@@ -0,0 +1,8 @@
namespace LightlessSync.UI.Models
{
public class CreditItem
{
public string Name { get; init; } = string.Empty;
public string Role { get; init; } = string.Empty;
}
}

View File

@@ -0,0 +1,7 @@
namespace LightlessSync.UI.Models
{
public class CreditsFile
{
public List<CreditCategory> Credits { get; init; } = [];
}
}

View File

@@ -1,7 +1,7 @@
using Dalamud.Interface;
using LightlessSync.LightlessConfiguration.Models;
using System.Numerics;
namespace LightlessSync.UI.Models;
public class LightlessNotification
{
public string Id { get; set; } = Guid.NewGuid().ToString();
@@ -20,13 +20,3 @@ public class LightlessNotification
public bool IsAnimatingOut { get; set; } = false;
public uint? SoundEffectId { get; set; } = null;
}
public class LightlessNotificationAction
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Label { get; set; } = string.Empty;
public FontAwesomeIcon Icon { get; set; } = FontAwesomeIcon.None;
public Vector4 Color { get; set; } = Vector4.One;
public Action<LightlessNotification> OnClick { get; set; } = _ => { };
public bool IsPrimary { get; set; } = false;
public bool IsDestructive { get; set; } = false;
}

View File

@@ -0,0 +1,15 @@
using Dalamud.Interface;
using System.Numerics;
namespace LightlessSync.UI.Models;
public class LightlessNotificationAction
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Label { get; set; } = string.Empty;
public FontAwesomeIcon Icon { get; set; } = FontAwesomeIcon.None;
public Vector4 Color { get; set; } = Vector4.One;
public Action<LightlessNotification> OnClick { get; set; } = _ => { };
public bool IsPrimary { get; set; } = false;
public bool IsDestructive { get; set; } = false;
}

View File

@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using LightlessSync.API.Dto.Group;
using LightlessSync.PlayerData.Factories;
using LightlessSync.PlayerData.Pairs;

View File

@@ -612,7 +612,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
}
private bool DrawStyleResetButton(string key, bool hasOverride, string? tooltipOverride = null)
private static bool DrawStyleResetButton(string key, bool hasOverride, string? tooltipOverride = null)
{
using var id = ImRaii.PushId($"reset-{key}");
using var disabled = ImRaii.Disabled(!hasOverride);
@@ -736,7 +736,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawHelpText("Controls how many uploads can run at once.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
if (ImGui.Checkbox("Enable Pair Download Limiter", ref limitPairApplications))
{
@@ -783,7 +783,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.TextColored(ImGuiColors.DalamudGrey, "Pair apply limiter is disabled.");
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
if (ImGui.Checkbox("Use Alternative Upload Method", ref useAlternativeUpload))
{
@@ -899,13 +899,10 @@ public class SettingsUi : WindowMediatorSubscriberBase
using var tree = ImRaii.TreeNode("Speed Test to Servers");
if (tree)
{
if (_downloadServersTask == null || ((_downloadServersTask?.IsCompleted ?? false) &&
(!_downloadServersTask?.IsCompletedSuccessfully ?? false)))
if ((_downloadServersTask == null || ((_downloadServersTask?.IsCompleted ?? false) &&
(!_downloadServersTask?.IsCompletedSuccessfully ?? false))) && _uiShared.IconTextButton(FontAwesomeIcon.GroupArrowsRotate, "Update Download Server List"))
{
if (_uiShared.IconTextButton(FontAwesomeIcon.GroupArrowsRotate, "Update Download Server List"))
{
_downloadServersTask = GetDownloadServerList();
}
_downloadServersTask = GetDownloadServerList();
}
if (_downloadServersTask != null && _downloadServersTask.IsCompleted &&
@@ -1136,9 +1133,9 @@ public class SettingsUi : WindowMediatorSubscriberBase
.DeserializeAsync<List<string>>(await result.Content.ReadAsStreamAsync().ConfigureAwait(false))
.ConfigureAwait(false);
}
catch (Exception ex)
catch (Exception)
{
_logger.LogWarning(ex, "Failed to get download server list");
_logger.LogWarning("Failed to get download server list");
throw;
}
}
@@ -1219,7 +1216,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
UiSharedService.TooltipSeparator
+ "Keeping LOD enabled can lead to more crashes. Use at your own risk.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessYellow"), 2f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"), 2f);
}
private void DrawFileStorageSettings()
@@ -1421,7 +1418,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
ImGui.TreePop();
}
@@ -1453,7 +1450,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
catch (IOException ex)
{
_logger.LogWarning(ex, $"Could not delete file {file} because it is in use.");
_logger.LogWarning(ex, "Could not delete file {file} because it is in use.", file);
}
}
@@ -1487,7 +1484,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndDisabled();
ImGui.Unindent();
_uiShared.ColoredSeparator(UIColors.Get("DimRed"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("DimRed"), 1.5f);
ImGui.TreePop();
}
}
@@ -1500,8 +1497,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
_lastTab = "General";
//UiSharedService.FontText("Experimental", _uiShared.UidFont);
//ImGui.Separator();
_uiShared.UnderlinedBigText("General Settings", UIColors.Get("LightlessBlue"));
ImGui.Dummy(new Vector2(10));
@@ -1539,7 +1534,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGuiColors.DalamudRed);
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -1567,7 +1562,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawHelpText(
"This will automatically populate user notes using the first encountered player name if the note was not set prior");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -1635,7 +1630,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -1675,7 +1670,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
_uiShared.DrawHelpText("When enabled, Lightfinder will automatically turn on after reconnecting to the Lightless server.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
ImGui.TextUnformatted("Lightfinder Nameplate Colors");
if (ImGui.BeginTable("##LightfinderColorTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit))
@@ -1731,7 +1726,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Spacing();
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
ImGui.TextUnformatted("Lightfinder Info Bar");
if (ImGui.Checkbox("Show Lightfinder status in Server info bar", ref showLightfinderInDtr))
@@ -1827,7 +1822,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
ImGui.EndDisabled();
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
ImGui.TextUnformatted("Alignment");
ImGui.BeginDisabled(autoAlign);
@@ -1952,7 +1947,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
ImGui.TextUnformatted("Visibility");
var showOwn = _configService.Current.LightfinderLabelShowOwn;
@@ -1990,7 +1985,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
_uiShared.DrawHelpText("Toggles Lightfinder label when no nameplate(s) is visible.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
ImGui.TextUnformatted("Label");
var useIcon = _configService.Current.LightfinderLabelUseIcon;
@@ -2096,7 +2091,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_lightfinderIconPresetIndex = -1;
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -2184,7 +2179,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Spacing();
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
ImGui.TextUnformatted("Server Info Bar Colors");
@@ -2236,7 +2231,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Spacing();
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
ImGui.TextUnformatted("Nameplate Colors");
@@ -2281,7 +2276,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Spacing();
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
ImGui.TextUnformatted("UI Theme");
@@ -2303,7 +2298,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
DrawThemeOverridesSection();
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -2401,7 +2396,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_configService.Save();
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -2444,7 +2439,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawHelpText("Will show profiles that have the NSFW tag enabled");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
ImGui.Separator();
@@ -2542,7 +2537,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
+ "Default: 165 thousand");
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -2646,7 +2641,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
+ "Default: 250 thousand");
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -2726,7 +2721,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Dummy(new Vector2(5));
_uiShared.ColoredSeparator(UIColors.Get("DimRed"), 3f);
UiSharedService.ColoredSeparator(UIColors.Get("DimRed"), 3f);
var onlyUncompressed = textureConfig.OnlyDownscaleUncompressedTextures;
if (ImGui.Checkbox("Only downscale uncompressed textures", ref onlyUncompressed))
{
@@ -2734,7 +2729,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_playerPerformanceConfigService.Save();
}
_uiShared.DrawHelpText("If disabled, compressed textures will be targeted for downscaling too.");
_uiShared.ColoredSeparator(UIColors.Get("DimRed"), 3f);
UiSharedService.ColoredSeparator(UIColors.Get("DimRed"), 3f);
ImGui.Dummy(new Vector2(5));
@@ -2742,7 +2737,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Dummy(new Vector2(5));
_uiShared.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
ImGui.TreePop();
}
@@ -2890,7 +2885,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndPopup();
}
_uiShared.ColoredSeparator(UIColors.Get("DimRed"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("DimRed"), 1.5f);
ImGui.TreePop();
}
@@ -3468,15 +3463,13 @@ public class SettingsUi : WindowMediatorSubscriberBase
private int _lastSelectedServerIndex = -1;
private Task<(bool Success, bool PartialSuccess, string Result)>? _secretKeysConversionTask = null;
private CancellationTokenSource _secretKeysConversionCts = new CancellationTokenSource();
private CancellationTokenSource _secretKeysConversionCts = new();
private async Task<(bool Success, bool partialSuccess, string Result)> ConvertSecretKeysToUIDs(
ServerStorage serverStorage, CancellationToken token)
{
List<Authentication> failedConversions = serverStorage.Authentications
.Where(u => u.SecretKeyIdx == -1 && string.IsNullOrEmpty(u.UID)).ToList();
List<Authentication> conversionsToAttempt = serverStorage.Authentications
.Where(u => u.SecretKeyIdx != -1 && string.IsNullOrEmpty(u.UID)).ToList();
List<Authentication> failedConversions = [.. serverStorage.Authentications.Where(u => u.SecretKeyIdx == -1 && string.IsNullOrEmpty(u.UID))];
List<Authentication> conversionsToAttempt = [.. serverStorage.Authentications.Where(u => u.SecretKeyIdx != -1 && string.IsNullOrEmpty(u.UID))];
List<Authentication> successfulConversions = [];
Dictionary<string, List<Authentication>> secretKeyMapping = new(StringComparer.Ordinal);
foreach (var authEntry in conversionsToAttempt)
@@ -3546,6 +3539,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
sb.Append(string.Join(", ", failedConversions.Select(k => k.CharacterName)));
}
_secretKeysConversionCts.Dispose();
return (true, failedConversions.Count != 0, sb.ToString());
}
@@ -3914,7 +3908,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Unindent();
}
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -3956,7 +3950,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawHelpText("Click anywhere on a notification to dismiss it. Notifications with action buttons (like pair requests) are excluded.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -4119,7 +4113,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.SetTooltip("Right click to reset to default (3).");
_uiShared.DrawHelpText("Width of the colored accent bar on the left side.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
}
@@ -4214,7 +4208,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Right click to reset to default (20).");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -4229,7 +4223,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawHelpText(
"Configure which sounds play for each notification type. Use the play button to preview sounds.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -4277,7 +4271,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
"Only show online notifications for pairs where you have set an individual note.");
ImGui.Unindent();
_uiShared.ColoredSeparator(UIColors.Get("LightlessGreen"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessGreen"), 1.5f);
ImGui.TreePop();
}
@@ -4293,7 +4287,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawHelpText(
"When you receive a pair request, show Accept/Decline buttons in the notification.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
@@ -4309,7 +4303,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawHelpText(
"When a player exceeds performance thresholds or is auto-paused, show Pause/Unpause buttons in the notification.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessOrange"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessOrange"), 1.5f);
ImGui.TreePop();
}
@@ -4324,7 +4318,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawHelpText("Disable warning notifications for missing optional plugins.");
_uiShared.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
ImGui.TreePop();
}
@@ -4334,32 +4328,32 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
}
private NotificationLocation[] GetLightlessNotificationLocations()
private static NotificationLocation[] GetLightlessNotificationLocations()
{
return new[]
{
return
[
NotificationLocation.LightlessUi, NotificationLocation.Chat, NotificationLocation.ChatAndLightlessUi, NotificationLocation.Nowhere
};
];
}
private NotificationLocation[] GetDownloadNotificationLocations()
private static NotificationLocation[] GetDownloadNotificationLocations()
{
return new[]
{
return
[
NotificationLocation.LightlessUi, NotificationLocation.TextOverlay, NotificationLocation.Nowhere
};
];
}
private NotificationLocation[] GetClassicNotificationLocations()
private static NotificationLocation[] GetClassicNotificationLocations()
{
return new[]
{
return
[
NotificationLocation.Toast, NotificationLocation.Chat, NotificationLocation.Both,
NotificationLocation.Nowhere
};
];
}
private string GetNotificationLocationLabel(NotificationLocation location)
private static string GetNotificationLocationLabel(NotificationLocation location)
{
return location switch
{
@@ -4374,7 +4368,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
};
}
private string GetNotificationCornerLabel(NotificationCorner corner)
private static string GetNotificationCornerLabel(NotificationCorner corner)
{
return corner switch
{

View File

@@ -1,18 +1,20 @@
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
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.Enum;
using LightlessSync.API.Data.Extensions;
using LightlessSync.API.Dto.Group;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
using LightlessSync.PlayerData.Pairs;
using LightlessSync.WebAPI;
using LightlessSync.Services.Profiles;
using LightlessSync.UI.Services;
using LightlessSync.WebAPI;
using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp;
using System.Globalization;
namespace LightlessSync.UI;
@@ -23,12 +25,12 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
private readonly bool _isModerator = false;
private readonly bool _isOwner = false;
private readonly List<string> _oneTimeInvites = [];
private readonly PairUiService _pairUiService;
private readonly LightlessProfileManager _lightlessProfileManager;
private readonly FileDialogManager _fileDialogManager;
private readonly UiSharedService _uiSharedService;
private readonly PairUiService _pairUiService;
private List<BannedGroupUserDto> _bannedUsers = [];
private LightlessGroupProfileData? _profileData = null;
private IDalamudTextureWrap? _pfpTextureWrap;
private string _profileDescription = string.Empty;
private int _multiInvites;
private string _newPassword;
@@ -38,27 +40,34 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
private int _pruneDays = 14;
public SyncshellAdminUI(ILogger<SyncshellAdminUI> logger, LightlessMediator mediator, ApiController apiController,
UiSharedService uiSharedService, PairUiService pairUiService, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService, LightlessProfileManager lightlessProfileManager, FileDialogManager fileDialogManager)
UiSharedService uiSharedService, PairUiService pairUiService, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService, LightlessProfileManager lightlessProfileManager)
: base(logger, mediator, "Syncshell Admin Panel (" + groupFullInfo.GroupAliasOrGID + ")", performanceCollectorService)
{
GroupFullInfo = groupFullInfo;
_apiController = apiController;
_uiSharedService = uiSharedService;
_pairUiService = pairUiService;
_lightlessProfileManager = lightlessProfileManager;
_fileDialogManager = fileDialogManager;
_pairUiService = pairUiService;
_isOwner = string.Equals(GroupFullInfo.OwnerUID, _apiController.UID, StringComparison.Ordinal);
_isModerator = GroupFullInfo.GroupUserInfo.IsModerator();
_newPassword = string.Empty;
_multiInvites = 30;
_pwChangeSuccess = true;
IsOpen = true;
Mediator.Subscribe<ClearProfileGroupDataMessage>(this, (msg) =>
{
if (msg.GroupData == null || string.Equals(msg.GroupData.AliasOrGID, GroupFullInfo.Group.AliasOrGID, StringComparison.Ordinal))
{
_pfpTextureWrap?.Dispose();
_pfpTextureWrap = null;
}
});
SizeConstraints = new WindowSizeConstraints()
{
MinimumSize = new(700, 500),
MaximumSize = new(700, 2000),
};
_pairUiService = pairUiService;
}
public GroupFullInfoDto GroupFullInfo { get; private set; }
@@ -84,7 +93,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
var perm = GroupFullInfo.GroupPermissions;
using var tabbar = ImRaii.TabBar("syncshell_tab_" + GroupFullInfo.GID);
if (tabbar)
{
DrawInvites(perm);
@@ -92,7 +101,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
DrawManagement();
DrawPermission(perm);
DrawProfile();
}
}
@@ -193,6 +202,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
ownerTab.Dispose();
}
}
private void DrawProfile()
{
var profileTab = ImRaii.TabItem("Profile");
@@ -220,7 +230,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
ImGui.BulletText(_profileData.IsDisabled ? "Profile disabled for viewers" : "Profile active");
ImGuiHelpers.ScaledDummy(2f);
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGuiHelpers.ScaledDummy(2f);
UiSharedService.TextWrapped("Open the syncshell profile editor to update images, description, tags, and visibility settings.");
@@ -395,7 +405,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
}
}
}
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
ImGui.Separator();
@@ -486,7 +496,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
UiSharedService.TextWrapped($"Syncshell was pruned and {_pruneTask.Result} inactive user(s) have been removed.");
}
}
_uiSharedService.ColoredSeparator(UIColors.Get("DimRed"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("DimRed"), 1.5f);
ImGui.TreePop();
}
ImGui.Separator();
@@ -532,7 +542,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
}
ImGui.EndTable();
}
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
UiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f);
ImGui.TreePop();
}
ImGui.Separator();
@@ -584,8 +594,10 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
}
inviteTab.Dispose();
}
public override void OnClose()
{
Mediator.Publish(new RemoveWindowMessage(this));
_pfpTextureWrap?.Dispose();
}
}

View File

@@ -3,6 +3,7 @@ using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using LightlessSync.API.Data;
using LightlessSync.API.Data.Enum;
using LightlessSync.API.Data.Extensions;
using LightlessSync.API.Dto;
@@ -29,11 +30,15 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
private readonly List<GroupJoinDto> _nearbySyncshells = [];
private List<GroupFullInfoDto> _currentSyncshells = [];
private int _selectedNearbyIndex = -1;
private int _syncshellPageIndex = 0;
private readonly HashSet<string> _recentlyJoined = new(StringComparer.Ordinal);
private GroupJoinDto? _joinDto;
private GroupJoinInfoDto? _joinInfo;
private DefaultPermissionsDto _ownPermissions = null!;
private const bool _useTestSyncshells = false;
private bool _compactView = false;
public SyncshellFinderUI(
ILogger<SyncshellFinderUI> logger,
@@ -62,6 +67,8 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
Mediator.Subscribe<SyncshellBroadcastsUpdatedMessage>(this, async _ => await RefreshSyncshellsAsync().ConfigureAwait(false));
Mediator.Subscribe<BroadcastStatusChangedMessage>(this, async _ => await RefreshSyncshellsAsync().ConfigureAwait(false));
Mediator.Subscribe<UserLeftSyncshell>(this, async _ => await RefreshSyncshellsAsync(_.gid).ConfigureAwait(false));
Mediator.Subscribe<UserJoinedSyncshell>(this, async _ => await RefreshSyncshellsAsync(_.gid).ConfigureAwait(false));
}
public override async void OnOpen()
@@ -72,9 +79,21 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
protected override void DrawInternal()
{
_uiSharedService.MediumText("Nearby Syncshells", UIColors.Get("PairBlue"));
_uiSharedService.ColoredSeparator(UIColors.Get("PairBlue"));
ImGui.BeginGroup();
_uiSharedService.MediumText("Nearby Syncshells", UIColors.Get("LightlessPurple"));
ImGui.SameLine();
string checkboxLabel = "Compact view";
float availWidth = ImGui.GetContentRegionAvail().X;
float checkboxWidth = ImGui.CalcTextSize(checkboxLabel).X + ImGui.GetFrameHeight();
float rightX = ImGui.GetCursorPosX() + availWidth - checkboxWidth - 4.0f;
ImGui.SetCursorPosX(rightX);
ImGui.Checkbox(checkboxLabel, ref _compactView);
ImGui.EndGroup();
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"));
ImGui.Dummy(new Vector2(0, 2 * ImGuiHelpers.GlobalScale));
if (_nearbySyncshells.Count == 0)
{
ImGui.TextColored(ImGuiColors.DalamudGrey, "No nearby syncshells are being broadcasted.");
@@ -82,13 +101,13 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
if (!_broadcastService.IsBroadcasting)
{
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"));
UiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"));
ImGui.TextColored(UIColors.Get("LightlessYellow"), "Lightfinder is currently disabled, to locate nearby syncshells, Lightfinder must be active.");
ImGuiHelpers.ScaledDummy(0.5f);
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 10.0f);
ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("PairBlue"));
ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("LightlessPurple"));
if (ImGui.Button("Open Lightfinder", new Vector2(200 * ImGuiHelpers.GlobalScale, 0)))
{
@@ -104,106 +123,295 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
return;
}
DrawSyncshellTable();
var cardData = new List<(GroupJoinDto Shell, string BroadcasterName)>();
var broadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
foreach (var shell in _nearbySyncshells)
{
string broadcasterName;
if (_useTestSyncshells)
{
var displayName = !string.IsNullOrEmpty(shell.Group.Alias)
? shell.Group.Alias
: shell.Group.GID;
broadcasterName = $"Tester of {displayName}";
}
else
{
var broadcast = broadcasts
.FirstOrDefault(b => string.Equals(b.GID, shell.Group.GID, StringComparison.Ordinal));
if (broadcast == null)
continue;
var (name, address) = _dalamudUtilService.FindPlayerByNameHash(broadcast.HashedCID);
if (string.IsNullOrEmpty(name))
continue;
var worldName = _dalamudUtilService.GetWorldNameFromPlayerAddress(address);
broadcasterName = !string.IsNullOrEmpty(worldName)
? $"{name} ({worldName})"
: name;
}
cardData.Add((shell, broadcasterName));
}
if (cardData.Count == 0)
{
ImGui.TextColored(ImGuiColors.DalamudGrey, "No nearby syncshells are being broadcasted.");
return;
}
if (_compactView)
{
DrawSyncshellGrid(cardData);
}
else
{
DrawSyncshellList(cardData);
}
if (_joinDto != null && _joinInfo != null && _joinInfo.Success)
DrawConfirmation();
}
private void DrawSyncshellTable()
private void DrawSyncshellList(List<(GroupJoinDto Shell, string BroadcasterName)> listData)
{
if (ImGui.BeginTable("##NearbySyncshellsTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg))
const int shellsPerPage = 3;
var totalPages = (int)Math.Ceiling(listData.Count / (float)shellsPerPage);
if (totalPages <= 0)
totalPages = 1;
_syncshellPageIndex = Math.Clamp(_syncshellPageIndex, 0, totalPages - 1);
var firstIndex = _syncshellPageIndex * shellsPerPage;
var lastExclusive = Math.Min(firstIndex + shellsPerPage, listData.Count);
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 8.0f);
ImGui.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 1.0f);
for (int index = firstIndex; index < lastExclusive; index++)
{
ImGui.TableSetupColumn("Syncshell", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Broadcaster", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Join", ImGuiTableColumnFlags.WidthFixed, 80f * ImGuiHelpers.GlobalScale);
ImGui.TableHeadersRow();
var (shell, broadcasterName) = listData[index];
foreach (var shell in _nearbySyncshells)
{
// Check if there is an active broadcast for this syncshell, if not, skipping this syncshell
var broadcast = _broadcastScannerService.GetActiveSyncshellBroadcasts()
.FirstOrDefault(b => string.Equals(b.GID, shell.Group.GID, StringComparison.Ordinal));
ImGui.PushID(shell.Group.GID);
float rowHeight = 90f * ImGuiHelpers.GlobalScale;
if (broadcast == null)
continue; // no active broadcasts
ImGui.BeginChild($"ShellRow##{shell.Group.GID}", new Vector2(-1, rowHeight), border: true);
var (Name, Address) = _dalamudUtilService.FindPlayerByNameHash(broadcast.HashedCID);
if (string.IsNullOrEmpty(Name))
continue; // broadcaster not found in area, skipping
var displayName = !string.IsNullOrEmpty(shell.Group.Alias) ? shell.Group.Alias : shell.Group.GID;
ImGui.TableNextRow();
ImGui.TableNextColumn();
var style = ImGui.GetStyle();
float startX = ImGui.GetCursorPosX();
float regionW = ImGui.GetContentRegionAvail().X;
float rightTxtW = ImGui.CalcTextSize(broadcasterName).X;
var displayName = !string.IsNullOrEmpty(shell.Group.Alias) ? shell.Group.Alias : shell.Group.GID;
ImGui.TextUnformatted(displayName);
_uiSharedService.MediumText(displayName, UIColors.Get("LightlessPurple"));
ImGui.TableNextColumn();
var worldName = _dalamudUtilService.GetWorldNameFromPlayerAddress(Address);
var broadcasterName = !string.IsNullOrEmpty(worldName) ? $"{Name} ({worldName})" : Name;
ImGui.TextUnformatted(broadcasterName);
float rightX = startX + regionW - rightTxtW - style.ItemSpacing.X;
ImGui.SameLine();
ImGui.SetCursorPosX(rightX);
ImGui.TextUnformatted(broadcasterName);
ImGui.TableNextColumn();
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"));
var label = $"Join##{shell.Group.GID}";
ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("LightlessGreen"));
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, UIColors.Get("LightlessGreen").WithAlpha(0.85f));
ImGui.PushStyleColor(ImGuiCol.ButtonActive, UIColors.Get("LightlessGreen").WithAlpha(0.75f));
ImGui.Dummy(new Vector2(0, 6 * ImGuiHelpers.GlobalScale));
var isAlreadyMember = _currentSyncshells.Exists(g => string.Equals(g.GID, shell.GID, StringComparison.Ordinal));
var isRecentlyJoined = _recentlyJoined.Contains(shell.GID);
if (!isAlreadyMember && !isRecentlyJoined)
{
if (ImGui.Button(label))
{
_logger.LogInformation($"Join requested for Syncshell {shell.Group.GID} ({shell.Group.Alias})");
DrawJoinButton(shell);
_ = Task.Run(async () =>
{
try
{
var info = await _apiController.GroupJoinHashed(new GroupJoinHashedDto(
shell.Group,
shell.Password,
shell.GroupUserPreferredPermissions
)).ConfigureAwait(false);
ImGui.EndChild();
ImGui.PopID();
if (info != null && info.Success)
{
_joinDto = new GroupJoinDto(shell.Group, shell.Password, shell.GroupUserPreferredPermissions);
_joinInfo = info;
_ownPermissions = _apiController.DefaultPermissions.DeepClone()!;
ImGui.Dummy(new Vector2(0, 2 * ImGuiHelpers.GlobalScale));
}
_logger.LogInformation($"Fetched join info for {shell.Group.GID}");
}
else
{
_logger.LogWarning($"Failed to join {shell.Group.GID}: info was null or unsuccessful");
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"Join failed for {shell.Group.GID}");
}
});
}
}
else
{
using (ImRaii.Disabled())
{
ImGui.Button(label);
}
UiSharedService.AttachToolTip("Already a member or owner of this Syncshell.");
}
ImGui.PopStyleColor(3);
}
ImGui.PopStyleVar(2);
ImGui.EndTable();
DrawPagination(totalPages);
}
private void DrawSyncshellGrid(List<(GroupJoinDto Shell, string BroadcasterName)> cardData)
{
const int shellsPerPage = 4;
var totalPages = (int)Math.Ceiling(cardData.Count / (float)shellsPerPage);
if (totalPages <= 0)
totalPages = 1;
_syncshellPageIndex = Math.Clamp(_syncshellPageIndex, 0, totalPages - 1);
var firstIndex = _syncshellPageIndex * shellsPerPage;
var lastExclusive = Math.Min(firstIndex + shellsPerPage, cardData.Count);
var avail = ImGui.GetContentRegionAvail();
var spacing = ImGui.GetStyle().ItemSpacing;
var cardWidth = (avail.X - spacing.X) / 2.0f;
var cardHeight = (avail.Y - spacing.Y - (ImGui.GetFrameHeightWithSpacing() * 2.0f)) / 2.0f;
cardHeight = MathF.Max(110f * ImGuiHelpers.GlobalScale, cardHeight);
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 8.0f);
ImGui.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 1.0f);
for (int index = firstIndex; index < lastExclusive; index++)
{
var localIndex = index - firstIndex;
var (shell, broadcasterName) = cardData[index];
if (localIndex % 2 != 0)
ImGui.SameLine();
ImGui.PushID(shell.Group.GID);
ImGui.BeginGroup();
_ = ImGui.BeginChild("ShellCard##" + shell.Group.GID, new Vector2(cardWidth, cardHeight), border: true);
var displayName = !string.IsNullOrEmpty(shell.Group.Alias)
? shell.Group.Alias
: shell.Group.GID;
_uiSharedService.MediumText(displayName, UIColors.Get("LightlessPurple"));
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"));
ImGui.TextColored(ImGuiColors.DalamudGrey, "Broadcaster");
ImGui.TextUnformatted(broadcasterName);
ImGui.Dummy(new Vector2(0, 6 * ImGuiHelpers.GlobalScale));
var buttonHeight = ImGui.GetFrameHeightWithSpacing();
var remainingY = ImGui.GetContentRegionAvail().Y - buttonHeight;
if (remainingY > 0)
ImGui.Dummy(new Vector2(0, remainingY));
DrawJoinButton(shell);
ImGui.EndChild();
ImGui.EndGroup();
ImGui.PopID();
}
ImGui.Dummy(new Vector2(0, 2 * ImGuiHelpers.GlobalScale));
ImGui.PopStyleVar(2);
DrawPagination(totalPages);
}
private void DrawPagination(int totalPages)
{
if (totalPages > 1)
{
UiSharedService.ColoredSeparator(UIColors.Get("PairBlue"));
var style = ImGui.GetStyle();
string pageLabel = $"Page {_syncshellPageIndex + 1}/{totalPages}";
float prevWidth = ImGui.CalcTextSize("<").X + style.FramePadding.X * 2;
float nextWidth = ImGui.CalcTextSize(">").X + style.FramePadding.X * 2;
float textWidth = ImGui.CalcTextSize(pageLabel).X;
float totalWidth = prevWidth + textWidth + nextWidth + style.ItemSpacing.X * 2;
float availWidth = ImGui.GetContentRegionAvail().X;
float offsetX = (availWidth - totalWidth) * 0.5f;
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + offsetX);
if (ImGui.Button("<##PrevSyncshellPage") && _syncshellPageIndex > 0)
_syncshellPageIndex--;
ImGui.SameLine();
ImGui.Text(pageLabel);
ImGui.SameLine();
if (ImGui.Button(">##NextSyncshellPage") && _syncshellPageIndex < totalPages - 1)
_syncshellPageIndex++;
}
}
private void DrawJoinButton(dynamic shell)
{
const string visibleLabel = "Join";
var label = $"{visibleLabel}##{shell.Group.GID}";
ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("LightlessGreen"));
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, UIColors.Get("LightlessGreen").WithAlpha(0.85f));
ImGui.PushStyleColor(ImGuiCol.ButtonActive, UIColors.Get("LightlessGreen").WithAlpha(0.75f));
var isAlreadyMember = _currentSyncshells.Exists(g => string.Equals(g.GID, shell.GID, StringComparison.Ordinal));
var isRecentlyJoined = _recentlyJoined.Contains(shell.GID);
Vector2 buttonSize;
if (!_compactView)
{
var style = ImGui.GetStyle();
var textSize = ImGui.CalcTextSize(visibleLabel);
var width = textSize.X + style.FramePadding.X * 20f;
buttonSize = new Vector2(width, 0);
float availX = ImGui.GetContentRegionAvail().X;
float curX = ImGui.GetCursorPosX();
float newX = curX + (availX - buttonSize.X);
ImGui.SetCursorPosX(newX);
}
else
{
buttonSize = new Vector2(-1, 0);
}
if (!isAlreadyMember && !isRecentlyJoined)
{
if (ImGui.Button(label, buttonSize))
{
_logger.LogInformation($"Join requested for Syncshell {shell.Group.GID} ({shell.Group.Alias})");
_ = Task.Run(async () =>
{
try
{
var info = await _apiController.GroupJoinHashed(new GroupJoinHashedDto(
shell.Group,
shell.Password,
shell.GroupUserPreferredPermissions
)).ConfigureAwait(false);
if (info != null && info.Success)
{
_joinDto = new GroupJoinDto(shell.Group, shell.Password, shell.GroupUserPreferredPermissions);
_joinInfo = info;
_ownPermissions = _apiController.DefaultPermissions.DeepClone()!;
_logger.LogInformation($"Fetched join info for {shell.Group.GID}");
}
else
{
_logger.LogWarning($"Failed to join {shell.Group.GID}: info was null or unsuccessful");
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"Join failed for {shell.Group.GID}");
}
});
}
}
else
{
using (ImRaii.Disabled())
{
ImGui.Button(label, buttonSize);
}
UiSharedService.AttachToolTip("Already a member or owner of this Syncshell.");
}
ImGui.PopStyleColor(3);
}
private void DrawConfirmation()
{
if (_joinDto != null && _joinInfo != null)
@@ -263,53 +471,97 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
ImGui.NewLine();
}
private async Task RefreshSyncshellsAsync()
private async Task RefreshSyncshellsAsync(string? gid = null)
{
var syncshellBroadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
var snapshot = _pairUiService.GetSnapshot();
_currentSyncshells = snapshot.GroupPairs.Keys.ToList();
_recentlyJoined.RemoveWhere(gid => _currentSyncshells.Any(s => string.Equals(s.GID, gid, StringComparison.Ordinal)));
_currentSyncshells = [.. snapshot.GroupPairs.Keys];
if (syncshellBroadcasts.Count == 0)
_recentlyJoined.RemoveWhere(gid =>
_currentSyncshells.Exists(s => string.Equals(s.GID, gid, StringComparison.Ordinal)));
List<GroupJoinDto>? updatedList = [];
if (_useTestSyncshells)
{
updatedList = BuildTestSyncshells();
}
else
{
if (syncshellBroadcasts.Count == 0)
{
ClearSyncshells();
return;
}
try
{
var groups = await _apiController.GetBroadcastedGroups(syncshellBroadcasts)
.ConfigureAwait(false);
updatedList = groups?.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to refresh broadcasted syncshells.");
return;
}
}
if (updatedList == null || updatedList.Count == 0)
{
ClearSyncshells();
return;
}
List<GroupJoinDto>? updatedList = [];
try
if (gid != null && _recentlyJoined.Contains(gid))
{
var groups = await _apiController.GetBroadcastedGroups(syncshellBroadcasts).ConfigureAwait(false);
updatedList = groups?.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to refresh broadcasted syncshells.");
return;
_recentlyJoined.Clear();
}
if (updatedList != null)
var previousGid = GetSelectedGid();
_nearbySyncshells.Clear();
_nearbySyncshells.AddRange(updatedList);
if (previousGid != null)
{
var previousGid = GetSelectedGid();
var newIndex = _nearbySyncshells.FindIndex(s =>
string.Equals(s.Group.GID, previousGid, StringComparison.Ordinal));
_nearbySyncshells.Clear();
_nearbySyncshells.AddRange(updatedList);
if (previousGid != null)
if (newIndex >= 0)
{
var newIndex = _nearbySyncshells.FindIndex(s => string.Equals(s.Group.GID, previousGid, StringComparison.Ordinal));
if (newIndex >= 0)
{
_selectedNearbyIndex = newIndex;
return;
}
_selectedNearbyIndex = newIndex;
return;
}
}
ClearSelection();
}
private List<GroupJoinDto> BuildTestSyncshells()
{
var testGroup1 = new GroupData("TEST-ALPHA", "Alpha Shell");
var testGroup2 = new GroupData("TEST-BETA", "Beta Shell");
var testGroup3 = new GroupData("TEST-GAMMA", "Gamma Shell");
var testGroup4 = new GroupData("TEST-DELTA", "Delta Shell");
var testGroup5 = new GroupData("TEST-CHARLIE", "Charlie Shell");
var testGroup6 = new GroupData("TEST-OMEGA", "Omega Shell");
var testGroup7 = new GroupData("TEST-POINT", "Point Shell");
var testGroup8 = new GroupData("TEST-HOTEL", "Hotel Shell");
return
[
new(testGroup1, "", GroupUserPreferredPermissions.NoneSet),
new(testGroup2, "", GroupUserPreferredPermissions.NoneSet),
new(testGroup3, "", GroupUserPreferredPermissions.NoneSet),
new(testGroup4, "", GroupUserPreferredPermissions.NoneSet),
new(testGroup5, "", GroupUserPreferredPermissions.NoneSet),
new(testGroup6, "", GroupUserPreferredPermissions.NoneSet),
new(testGroup7, "", GroupUserPreferredPermissions.NoneSet),
new(testGroup8, "", GroupUserPreferredPermissions.NoneSet),
];
}
private void ClearSyncshells()
{
if (_nearbySyncshells.Count == 0)
@@ -322,6 +574,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
private void ClearSelection()
{
_selectedNearbyIndex = -1;
_syncshellPageIndex = 0;
_joinDto = null;
_joinInfo = null;
}

View File

@@ -123,133 +123,133 @@ public class TopTabMenu
}
UiSharedService.AttachToolTip("Individual Pair Menu");
using (ImRaii.PushFont(UiBuilder.IconFont))
{
var x = ImGui.GetCursorScreenPos();
if (ImGui.Button(FontAwesomeIcon.Users.ToIconString(), buttonSize))
using (ImRaii.PushFont(UiBuilder.IconFont))
{
TabSelection = TabSelection == SelectedTab.Syncshell ? SelectedTab.None : SelectedTab.Syncshell;
var x = ImGui.GetCursorScreenPos();
if (ImGui.Button(FontAwesomeIcon.Users.ToIconString(), buttonSize))
{
TabSelection = TabSelection == SelectedTab.Syncshell ? SelectedTab.None : SelectedTab.Syncshell;
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
}
ImGui.SameLine();
var xAfter = ImGui.GetCursorScreenPos();
if (TabSelection == SelectedTab.Syncshell)
drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
underlineColor, 2);
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
UiSharedService.AttachToolTip("Syncshell Menu");
using (ImRaii.PushFont(UiBuilder.IconFont))
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
if (ImGui.Button(FontAwesomeIcon.Comments.ToIconString(), buttonSize))
{
_lightlessMediator.Publish(new UiToggleMessage(typeof(ZoneChatUi)));
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
}
}
UiSharedService.AttachToolTip("Zone Chat");
ImGui.SameLine();
var xAfter = ImGui.GetCursorScreenPos();
if (TabSelection == SelectedTab.Syncshell)
drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
underlineColor, 2);
}
UiSharedService.AttachToolTip("Syncshell Menu");
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button(FontAwesomeIcon.Comments.ToIconString(), buttonSize))
{
_lightlessMediator.Publish(new UiToggleMessage(typeof(ZoneChatUi)));
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
}
}
UiSharedService.AttachToolTip("Zone Chat");
ImGui.SameLine();
ImGui.SameLine();
using (ImRaii.PushFont(UiBuilder.IconFont))
{
var x = ImGui.GetCursorScreenPos();
if (ImGui.Button(FontAwesomeIcon.Compass.ToIconString(), buttonSize))
{
TabSelection = TabSelection == SelectedTab.Lightfinder ? SelectedTab.None : SelectedTab.Lightfinder;
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
}
ImGui.SameLine();
var xAfter = ImGui.GetCursorScreenPos();
if (TabSelection == SelectedTab.Lightfinder)
drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
underlineColor, 2);
}
UiSharedService.AttachToolTip("Lightfinder");
using (ImRaii.PushFont(UiBuilder.IconFont))
{
var x = ImGui.GetCursorScreenPos();
if (ImGui.Button(FontAwesomeIcon.Compass.ToIconString(), buttonSize))
{
TabSelection = TabSelection == SelectedTab.Lightfinder ? SelectedTab.None : SelectedTab.Lightfinder;
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
}
ImGui.SameLine();
using (ImRaii.PushFont(UiBuilder.IconFont))
{
var x = ImGui.GetCursorScreenPos();
if (ImGui.Button(FontAwesomeIcon.UserCog.ToIconString(), buttonSize))
{
TabSelection = TabSelection == SelectedTab.UserConfig ? SelectedTab.None : SelectedTab.UserConfig;
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
ImGui.SameLine();
var xAfter = ImGui.GetCursorScreenPos();
if (TabSelection == SelectedTab.Lightfinder)
drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
underlineColor, 2);
}
UiSharedService.AttachToolTip("Lightfinder");
ImGui.SameLine();
var xAfter = ImGui.GetCursorScreenPos();
if (TabSelection == SelectedTab.UserConfig)
drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
underlineColor, 2);
}
UiSharedService.AttachToolTip("Your User Menu");
using (ImRaii.PushFont(UiBuilder.IconFont))
{
var x = ImGui.GetCursorScreenPos();
if (ImGui.Button(FontAwesomeIcon.UserCog.ToIconString(), buttonSize))
{
TabSelection = TabSelection == SelectedTab.UserConfig ? SelectedTab.None : SelectedTab.UserConfig;
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
}
ImGui.SameLine();
using (ImRaii.PushFont(UiBuilder.IconFont))
{
var x = ImGui.GetCursorScreenPos();
if (ImGui.Button(FontAwesomeIcon.Cog.ToIconString(), buttonSize))
{
_lightlessMediator.Publish(new UiToggleMessage(typeof(SettingsUi)));
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
ImGui.SameLine();
var xAfter = ImGui.GetCursorScreenPos();
if (TabSelection == SelectedTab.UserConfig)
drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
underlineColor, 2);
}
UiSharedService.AttachToolTip("Your User Menu");
ImGui.SameLine();
using (ImRaii.PushFont(UiBuilder.IconFont))
{
var x = ImGui.GetCursorScreenPos();
if (ImGui.Button(FontAwesomeIcon.Cog.ToIconString(), buttonSize))
{
_lightlessMediator.Publish(new UiToggleMessage(typeof(SettingsUi)));
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
{
Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
}
ImGui.SameLine();
}
UiSharedService.AttachToolTip("Open Lightless Settings");
ImGui.NewLine();
btncolor.Dispose();
ImGuiHelpers.ScaledDummy(spacing);
if (TabSelection == SelectedTab.Individual)
{
DrawAddPair(availableWidth, spacing.X);
DrawGlobalIndividualButtons(availableWidth, spacing.X);
}
else if (TabSelection == SelectedTab.Syncshell)
{
DrawSyncshellMenu(availableWidth, spacing.X);
DrawGlobalSyncshellButtons(availableWidth, spacing.X);
}
else if (TabSelection == SelectedTab.Lightfinder)
{
DrawLightfinderMenu(availableWidth, spacing.X);
}
else if (TabSelection == SelectedTab.UserConfig)
{
DrawUserConfig(availableWidth, spacing.X);
}
if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f);
DrawIncomingPairRequests(availableWidth);
ImGui.Separator();
DrawFilter(availableWidth, spacing.X);
}
UiSharedService.AttachToolTip("Open Lightless Settings");
ImGui.NewLine();
btncolor.Dispose();
ImGuiHelpers.ScaledDummy(spacing);
if (TabSelection == SelectedTab.Individual)
{
DrawAddPair(availableWidth, spacing.X);
DrawGlobalIndividualButtons(availableWidth, spacing.X);
}
else if (TabSelection == SelectedTab.Syncshell)
{
DrawSyncshellMenu(availableWidth, spacing.X);
DrawGlobalSyncshellButtons(availableWidth, spacing.X);
}
else if (TabSelection == SelectedTab.Lightfinder)
{
DrawLightfinderMenu(availableWidth, spacing.X);
}
else if (TabSelection == SelectedTab.UserConfig)
{
DrawUserConfig(availableWidth, spacing.X);
}
if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f);
DrawIncomingPairRequests(availableWidth);
ImGui.Separator();
DrawFilter(availableWidth, spacing.X);
}
finally
{
_currentSnapshot = null;

View File

@@ -45,7 +45,7 @@ namespace LightlessSync.UI
return HexToRgba(customColorHex);
if (!DefaultHexColors.TryGetValue(name, out var hex))
throw new ArgumentException($"Color '{name}' not found in UIColors.");
throw new ArgumentException($"Color '{name}' not found in UIColors.", nameof(name));
return HexToRgba(hex);
}
@@ -53,7 +53,7 @@ namespace LightlessSync.UI
public static void Set(string name, Vector4 color)
{
if (!DefaultHexColors.ContainsKey(name))
throw new ArgumentException($"Color '{name}' not found in UIColors.");
throw new ArgumentException($"Color '{name}' not found in UIColors.", nameof(name));
if (_configService != null)
{
@@ -83,7 +83,7 @@ namespace LightlessSync.UI
public static Vector4 GetDefault(string name)
{
if (!DefaultHexColors.TryGetValue(name, out var hex))
throw new ArgumentException($"Color '{name}' not found in UIColors.");
throw new ArgumentException($"Color '{name}' not found in UIColors.", nameof(name));
return HexToRgba(hex);
}
@@ -101,10 +101,10 @@ namespace LightlessSync.UI
public static Vector4 HexToRgba(string hexColor)
{
hexColor = hexColor.TrimStart('#');
int r = int.Parse(hexColor.Substring(0, 2), NumberStyles.HexNumber);
int g = int.Parse(hexColor.Substring(2, 2), NumberStyles.HexNumber);
int b = int.Parse(hexColor.Substring(4, 2), NumberStyles.HexNumber);
int a = hexColor.Length == 8 ? int.Parse(hexColor.Substring(6, 2), NumberStyles.HexNumber) : 255;
int r = int.Parse(hexColor[..2], NumberStyles.HexNumber);
int g = int.Parse(hexColor[2..4], NumberStyles.HexNumber);
int b = int.Parse(hexColor[4..6], NumberStyles.HexNumber);
int a = hexColor.Length == 8 ? int.Parse(hexColor[6..8], NumberStyles.HexNumber) : 255;
return new Vector4(r / 255f, g / 255f, b / 255f, a / 255f);
}

View File

@@ -71,7 +71,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
private bool _isOneDrive = false;
private bool _isPenumbraDirectory = false;
private bool _moodlesExists = false;
private Dictionary<string, DateTime> _oauthTokenExpiry = new();
private readonly Dictionary<string, DateTime> _oauthTokenExpiry = [];
private bool _penumbraExists = false;
private bool _petNamesExists = false;
private int _serverSelectionIndex = -1;
@@ -487,7 +487,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
);
}
public void ColoredSeparator(Vector4? color = null, float thickness = 1f, float indent = 0f)
public static void ColoredSeparator(Vector4? color = null, float thickness = 1f, float indent = 0f)
{
var drawList = ImGui.GetWindowDrawList();
var min = ImGui.GetCursorScreenPos();
@@ -1080,7 +1080,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
{
using (ImRaii.Disabled(_discordOAuthUIDs == null))
{
var aliasPairs = _discordOAuthUIDs?.Result?.Select(t => new UIDAliasPair(t.Key, t.Value)).ToList() ?? [new UIDAliasPair(item.UID ?? null, null)];
var aliasPairs = _discordOAuthUIDs?.Result?.Select(t => new UidAliasPair(t.Key, t.Value)).ToList() ?? [new UidAliasPair(item.UID ?? null, null)];
var uidComboName = "UID###" + item.CharacterName + item.WorldId + serverUri + indexOffset + aliasPairs.Count;
DrawCombo(uidComboName, aliasPairs,
(v) =>
@@ -1360,6 +1360,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
UidFont.Dispose();
GameFont.Dispose();
MediumFont.Dispose();
_discordOAuthGetCts.Dispose();
}
private static void CenterWindow(float width, float height, ImGuiCond cond = ImGuiCond.None)
@@ -1443,6 +1444,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
return result;
}
public sealed record IconScaleData(Vector2 IconSize, Vector2 NormalizedIconScale, float OffsetX, float IconScaling);
private record UIDAliasPair(string? UID, string? Alias);
private sealed record UidAliasPair(string? UID, string? Alias);
}

View File

@@ -25,7 +25,6 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase
private ChangelogFile _changelog = new();
private CreditsFile _credits = new();
private bool _scrollToTop;
private int _selectedTab;
private bool _hasInitializedCollapsingHeaders;
private struct Particle
@@ -160,7 +159,7 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase
DrawParticleEffects(headerStart, extendedParticleSize);
}
private void DrawGradientBackground(Vector2 headerStart, Vector2 headerEnd)
private static void DrawGradientBackground(Vector2 headerStart, Vector2 headerEnd)
{
var drawList = ImGui.GetWindowDrawList();
@@ -188,7 +187,7 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase
}
}
private void DrawBottomGradient(Vector2 headerStart, Vector2 headerEnd, float width)
private static void DrawBottomGradient(Vector2 headerStart, Vector2 headerEnd, float width)
{
var drawList = ImGui.GetWindowDrawList();
var gradientHeight = 60f;
@@ -513,7 +512,6 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase
{
if (changelogTab)
{
_selectedTab = 0;
DrawChangelog();
}
}
@@ -524,7 +522,6 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase
{
if (creditsTab)
{
_selectedTab = 1;
DrawCredits();
}
}
@@ -558,7 +555,7 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase
}
}
private void DrawCreditCategory(CreditCategory category)
private static void DrawCreditCategory(CreditCategory category)
{
DrawFeatureSection(category.Category, UIColors.Get("LightlessBlue"));
@@ -745,7 +742,7 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase
using var changelogStream = assembly.GetManifestResourceStream("LightlessSync.Changelog.changelog.yaml");
if (changelogStream != null)
{
using var reader = new StreamReader(changelogStream, Encoding.UTF8, true, 128);
using var reader = new StreamReader(changelogStream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, 128);
var yaml = reader.ReadToEnd();
_changelog = deserializer.Deserialize<ChangelogFile>(yaml) ?? new();
}
@@ -754,7 +751,7 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase
using var creditsStream = assembly.GetManifestResourceStream("LightlessSync.Changelog.credits.yaml");
if (creditsStream != null)
{
using var reader = new StreamReader(creditsStream, Encoding.UTF8, true, 128);
using var reader = new StreamReader(creditsStream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, 128);
var yaml = reader.ReadToEnd();
_credits = deserializer.Deserialize<CreditsFile>(yaml) ?? new();
}