From 46a8fc72cb96aebb58358c20b50ca3fa5ac244e8 Mon Sep 17 00:00:00 2001 From: cake Date: Tue, 2 Dec 2025 18:19:15 +0100 Subject: [PATCH] Changed profile opening to use GroupData instead of full info, Added opening of syncshell profile from finder. --- LightlessSync/Services/Mediator/Messages.cs | 2 +- LightlessSync/Services/UiFactory.cs | 2 +- LightlessSync/Services/UiService.cs | 2 +- .../UI/Components/DrawFolderGroup.cs | 2 +- LightlessSync/UI/EditProfileUi.Group.cs | 4 +- LightlessSync/UI/EditProfileUi.cs | 4 +- LightlessSync/UI/Handlers/IdDisplayHandler.cs | 2 +- LightlessSync/UI/StandaloneProfileUi.cs | 341 +++++++++--------- LightlessSync/UI/SyncshellAdminUI.cs | 2 +- LightlessSync/UI/SyncshellFinderUI.cs | 10 +- LightlessSync/UI/Tags/ProfileTagService.cs | 4 +- 11 files changed, 192 insertions(+), 183 deletions(-) diff --git a/LightlessSync/Services/Mediator/Messages.cs b/LightlessSync/Services/Mediator/Messages.cs index 756874b..33dd062 100644 --- a/LightlessSync/Services/Mediator/Messages.cs +++ b/LightlessSync/Services/Mediator/Messages.cs @@ -84,7 +84,7 @@ public record PauseMessage(UserData UserData) : MessageBase; public record ProfilePopoutToggle(Pair? Pair) : MessageBase; public record CompactUiChange(Vector2 Size, Vector2 Position) : MessageBase; public record ProfileOpenStandaloneMessage(Pair Pair) : MessageBase; -public record GroupProfileOpenStandaloneMessage(GroupFullInfoDto Group) : MessageBase; +public record GroupProfileOpenStandaloneMessage(GroupData Group) : MessageBase; public record OpenGroupProfileEditorMessage(GroupFullInfoDto Group) : MessageBase; public record CloseGroupProfilePreviewMessage(GroupFullInfoDto Group) : MessageBase; public record ActiveServerChangedMessage(string ServerUrl) : MessageBase; diff --git a/LightlessSync/Services/UiFactory.cs b/LightlessSync/Services/UiFactory.cs index 72681f7..7237936 100644 --- a/LightlessSync/Services/UiFactory.cs +++ b/LightlessSync/Services/UiFactory.cs @@ -113,7 +113,7 @@ public class UiFactory _performanceCollectorService); } - public StandaloneProfileUi CreateStandaloneGroupProfileUi(GroupFullInfoDto groupInfo) + public StandaloneProfileUi CreateStandaloneGroupProfileUi(GroupData groupInfo) { return new StandaloneProfileUi( _loggerFactory.CreateLogger(), diff --git a/LightlessSync/Services/UiService.cs b/LightlessSync/Services/UiService.cs index 4951bec..16f0f4f 100644 --- a/LightlessSync/Services/UiService.cs +++ b/LightlessSync/Services/UiService.cs @@ -64,7 +64,7 @@ public sealed class UiService : DisposableMediatorSubscriberBase var existingWindow = _createdWindows.Find(p => p is StandaloneProfileUi ui && ui.IsGroupProfile && ui.ProfileGroupData is not null - && string.Equals(ui.ProfileGroupData.GID, msg.Group.Group.GID, StringComparison.Ordinal)); + && string.Equals(ui.ProfileGroupData.GID, msg.Group.GID, StringComparison.Ordinal)); if (existingWindow is StandaloneProfileUi existing) { diff --git a/LightlessSync/UI/Components/DrawFolderGroup.cs b/LightlessSync/UI/Components/DrawFolderGroup.cs index 4e8a6a1..c39326c 100644 --- a/LightlessSync/UI/Components/DrawFolderGroup.cs +++ b/LightlessSync/UI/Components/DrawFolderGroup.cs @@ -91,7 +91,7 @@ public class DrawFolderGroup : DrawFolderBase if (_uiSharedService.IconTextButton(FontAwesomeIcon.AddressCard, "Open Syncshell Profile", menuWidth, true)) { ImGui.CloseCurrentPopup(); - _lightlessMediator.Publish(new GroupProfileOpenStandaloneMessage(_groupFullInfoDto)); + _lightlessMediator.Publish(new GroupProfileOpenStandaloneMessage(_groupFullInfoDto.Group)); } UiSharedService.AttachToolTip("Opens the profile for this syncshell in a new window."); diff --git a/LightlessSync/UI/EditProfileUi.Group.cs b/LightlessSync/UI/EditProfileUi.Group.cs index c2724fb..cae1eeb 100644 --- a/LightlessSync/UI/EditProfileUi.Group.cs +++ b/LightlessSync/UI/EditProfileUi.Group.cs @@ -40,7 +40,7 @@ public partial class EditProfileUi var viewport = ImGui.GetMainViewport(); ProfileEditorLayoutCoordinator.Enable(groupInfo.Group.GID); ProfileEditorLayoutCoordinator.EnsureAnchor(viewport.WorkPos, scale); - Mediator.Publish(new GroupProfileOpenStandaloneMessage(groupInfo)); + Mediator.Publish(new GroupProfileOpenStandaloneMessage(groupInfo.Group)); IsOpen = true; _wasOpen = true; @@ -246,7 +246,7 @@ public partial class EditProfileUi ImGui.Dummy(new Vector2(0f, 4f * scale)); ImGui.TextColored(UIColors.Get("LightlessBlue"), "Saved Tags"); - var savedTags = _profileTagService.ResolveTags(_profileTagIds); + var savedTags = ProfileTagService.ResolveTags(_profileTagIds); if (savedTags.Count == 0) { ImGui.TextDisabled("-- No tags set --"); diff --git a/LightlessSync/UI/EditProfileUi.cs b/LightlessSync/UI/EditProfileUi.cs index 7c55775..3c9b8ae 100644 --- a/LightlessSync/UI/EditProfileUi.cs +++ b/LightlessSync/UI/EditProfileUi.cs @@ -434,7 +434,7 @@ public partial class EditProfileUi : WindowMediatorSubscriberBase ImGui.Dummy(new Vector2(0f, 4f * scale)); ImGui.TextColored(UIColors.Get("LightlessBlue"), "Saved Tags"); - var savedTags = _profileTagService.ResolveTags(_profileTagIds); + var savedTags = ProfileTagService.ResolveTags(_profileTagIds); if (savedTags.Count == 0) { ImGui.TextDisabled("-- No tags set --"); @@ -675,7 +675,7 @@ public partial class EditProfileUi : WindowMediatorSubscriberBase bool sortPayloadBeforeSubmit, Action? onPayloadPrepared = null) { - var tagLibrary = _profileTagService.GetTagLibrary(); + var tagLibrary = ProfileTagService.GetTagLibrary(); if (tagLibrary.Count == 0) { ImGui.TextDisabled("No profile tags are available."); diff --git a/LightlessSync/UI/Handlers/IdDisplayHandler.cs b/LightlessSync/UI/Handlers/IdDisplayHandler.cs index b3f90d0..28f3053 100644 --- a/LightlessSync/UI/Handlers/IdDisplayHandler.cs +++ b/LightlessSync/UI/Handlers/IdDisplayHandler.cs @@ -91,7 +91,7 @@ public class IdDisplayHandler if (ImGui.IsItemClicked(ImGuiMouseButton.Middle)) { - _mediator.Publish(new GroupProfileOpenStandaloneMessage(group)); + _mediator.Publish(new GroupProfileOpenStandaloneMessage(group.Group)); } } else diff --git a/LightlessSync/UI/StandaloneProfileUi.cs b/LightlessSync/UI/StandaloneProfileUi.cs index 2332387..e42bde8 100644 --- a/LightlessSync/UI/StandaloneProfileUi.cs +++ b/LightlessSync/UI/StandaloneProfileUi.cs @@ -24,7 +24,6 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase private readonly ProfileTagService _profileTagService; private readonly UiSharedService _uiSharedService; private readonly UserData? _userData; - private readonly GroupFullInfoDto? _groupInfo; private readonly GroupData? _groupData; private readonly bool _isGroupProfile; private readonly bool _isLightfinderContext; @@ -55,11 +54,11 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase PairUiService pairUiService, Pair? pair, UserData? userData, - GroupFullInfoDto? groupInfo, + GroupData? groupData, bool isLightfinderContext, string? lightfinderCid, PerformanceCollectorService performanceCollector) - : base(logger, mediator, BuildWindowTitle(userData, groupInfo, isLightfinderContext), performanceCollector) + : base(logger, mediator, BuildWindowTitle(userData, groupData, isLightfinderContext), performanceCollector) { _uiSharedService = uiBuilder; _serverManager = serverManager; @@ -68,9 +67,8 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase Pair = pair; _pairUiService = pairUiService; _userData = userData; - _groupInfo = groupInfo; - _groupData = groupInfo?.Group; - _isGroupProfile = groupInfo is not null; + _groupData = groupData; + _isGroupProfile = groupData is not null; _isLightfinderContext = isLightfinderContext; _lightfinderCid = lightfinderCid; @@ -117,12 +115,12 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase return fallback; } - private static string BuildWindowTitle(UserData? userData, GroupFullInfoDto? groupInfo, bool isLightfinderContext) + private static string BuildWindowTitle(UserData? userData, GroupData? groupData, bool isLightfinderContext) { - if (groupInfo is not null) + if (groupData is not null) { - var alias = groupInfo.GroupAliasOrGID; - return $"Syncshell Profile of {alias}##LightlessSyncStandaloneGroupProfileUI{groupInfo.Group.GID}"; + var alias = groupData.AliasOrGID; + return $"Syncshell Profile of {alias}##LightlessSyncStandaloneGroupProfileUI{groupData.GID}"; } if (userData is null) @@ -185,7 +183,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase var profile = _lightlessProfileManager.GetLightlessProfile(userData); IReadOnlyList profileTags = profile.Tags.Count > 0 - ? _profileTagService.ResolveTags(profile.Tags) + ? ProfileTagService.ResolveTags(profile.Tags) : Array.Empty(); if (_textureWrap == null || !profile.ImageData.Value.SequenceEqual(_lastProfilePicture)) @@ -705,7 +703,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase private void DrawGroupProfileWindow() { - if (_groupInfo is null || _groupData is null) + if (_groupData is null) return; var scale = ImGuiHelpers.GlobalScale; @@ -745,7 +743,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase var profile = _lightlessProfileManager.GetLightlessGroupProfile(_groupData); IReadOnlyList profileTags = profile.Tags.Count > 0 - ? _profileTagService.ResolveTags(profile.Tags) + ? ProfileTagService.ResolveTags(profile.Tags) : Array.Empty(); if (_textureWrap == null || !profile.ProfileImageData.Value.SequenceEqual(_lastProfilePicture)) @@ -787,8 +785,8 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase int memberCount = 0; List? groupMembers = null; var snapshot = _pairUiService.GetSnapshot(); - var groupInfo = _groupInfo; - if (groupInfo is not null && snapshot.GroupsByGid.TryGetValue(groupInfo.GID, out var refreshedGroupInfo)) + GroupFullInfoDto groupInfo = null; + if (_groupData is not null && snapshot.GroupsByGid.TryGetValue(_groupData.GID, out var refreshedGroupInfo)) { groupInfo = refreshedGroupInfo; } @@ -912,172 +910,175 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase bool useVanityColors = false; Vector4? vanityTextColor = null; Vector4? vanityGlowColor = null; - string primaryHeaderText = _groupInfo.GroupAliasOrGID; - - List<(string Text, bool UseVanityColor, bool Disabled)> secondaryHeaderLines = new() + if (_groupData is not null && groupInfo is not null) { + string primaryHeaderText = _groupData.AliasOrGID; + + List<(string Text, bool UseVanityColor, bool Disabled)> secondaryHeaderLines = + [ (_groupData.GID, false, true) - }; + ]; - if (_groupInfo.Owner is not null) - secondaryHeaderLines.Add(($"Owner: {_groupInfo.Owner.AliasOrUID}", false, true)); + if (groupInfo.Owner is not null) + secondaryHeaderLines.Add(($"Owner: {groupInfo.Owner.AliasOrUID}", false, true)); - var infoStartY = MathF.Max(contentStartY, bannerHeight + style.WindowPadding.Y); - var aliasColumnX = infoOffsetX + 18f * scale; - ImGui.SetCursorPos(new Vector2(aliasColumnX, infoStartY)); + var infoStartY = MathF.Max(contentStartY, bannerHeight + style.WindowPadding.Y); + var aliasColumnX = infoOffsetX + 18f * scale; + ImGui.SetCursorPos(new Vector2(aliasColumnX, infoStartY)); - ImGui.BeginGroup(); - using (_uiSharedService.UidFont.Push()) - { - ImGui.TextUnformatted(primaryHeaderText); - } - - foreach (var (text, useColor, disabled) in secondaryHeaderLines) - { - if (useColor && useVanityColors) + ImGui.BeginGroup(); + using (_uiSharedService.UidFont.Push()) { - var seString = SeStringUtils.BuildFormattedPlayerName(text, vanityTextColor, vanityGlowColor); - SeStringUtils.RenderSeStringWithHitbox(seString, ImGui.GetCursorScreenPos(), ImGui.GetFont()); + ImGui.TextUnformatted(primaryHeaderText); + } + + foreach (var (text, useColor, disabled) in secondaryHeaderLines) + { + if (useColor && useVanityColors) + { + var seString = SeStringUtils.BuildFormattedPlayerName(text, vanityTextColor, vanityGlowColor); + SeStringUtils.RenderSeStringWithHitbox(seString, ImGui.GetCursorScreenPos(), ImGui.GetFont()); + } + else + { + if (disabled) + ImGui.TextDisabled(text); + else + ImGui.TextUnformatted(text); + } + } + ImGui.EndGroup(); + var namesEnd = ImGui.GetCursorPos(); + + var aliasGroupRectMin = ImGui.GetItemRectMin(); + var aliasGroupRectMax = ImGui.GetItemRectMax(); + var aliasGroupLocalMin = aliasGroupRectMin - windowPos; + var aliasGroupLocalMax = aliasGroupRectMax - windowPos; + + var tagsStartLocal = new Vector2(aliasGroupLocalMax.X + style.ItemSpacing.X + 25f * scale, aliasGroupLocalMin.Y + style.FramePadding.Y + 2f * scale); + ImGui.SetCursorPos(tagsStartLocal); + if (profileTags.Count > 0) + RenderProfileTags(profileTags, scale); + else + ImGui.TextDisabled("-- No tags set --"); + var tagsEndLocal = ImGui.GetCursorPos(); + var tagsBlockBottom = windowPos.Y + tagsEndLocal.Y; + var aliasBlockBottom = windowPos.Y + aliasGroupLocalMax.Y; + var aliasAndTagsBottomLocal = MathF.Max(aliasGroupLocalMax.Y, tagsEndLocal.Y); + var aliasAndTagsBlockBottom = MathF.Max(aliasBlockBottom, tagsBlockBottom); + + var descriptionSeparatorSpacing = style.ItemSpacing.Y * 0.35f; + var descriptionSeparatorThickness = MathF.Max(1f, scale); + var descriptionExtraOffset = groupInfo.Owner is not null ? style.ItemSpacing.Y * 0.6f : 0f; + var descriptionStartLocal = new Vector2(aliasColumnX, aliasAndTagsBottomLocal + descriptionSeparatorSpacing + descriptionExtraOffset); + var horizontalInset = style.ItemSpacing.X * 0.5f; + var descriptionSeparatorStart = windowPos + new Vector2(aliasColumnX - horizontalInset, descriptionStartLocal.Y); + var descriptionSeparatorEnd = new Vector2(windowPos.X + windowSize.X - style.WindowPadding.X + horizontalInset, descriptionSeparatorStart.Y); + drawList.AddLine(descriptionSeparatorStart, descriptionSeparatorEnd, ImGui.GetColorU32(portraitFrameBorder), descriptionSeparatorThickness); + + var descriptionContentStartLocal = new Vector2(aliasColumnX, descriptionStartLocal.Y + descriptionSeparatorThickness + descriptionSeparatorSpacing + style.FramePadding.Y * 0.75f); + ImGui.SetCursorPos(descriptionContentStartLocal); + ImGui.TextDisabled("Description"); + ImGui.SetCursorPosX(aliasColumnX); + var descriptionRegionWidth = ImGui.GetContentRegionAvail().X; + if (descriptionRegionWidth <= 0f) + descriptionRegionWidth = 1f; + var measurementWrapWidth = MathF.Max(1f, descriptionRegionWidth - style.WindowPadding.X * 2f); + var hasDescription = !string.IsNullOrWhiteSpace(profile.Description); + float descriptionContentHeight; + float lineHeightWithSpacing; + using (_uiSharedService.GameFont.Push()) + { + lineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing(); + var measurementText = hasDescription + ? NormalizeDescriptionForMeasurement(profile.Description!) + : GroupDescriptionPlaceholder; + if (string.IsNullOrWhiteSpace(measurementText)) + measurementText = GroupDescriptionPlaceholder; + + descriptionContentHeight = ImGui.CalcTextSize(measurementText, wrapWidth: measurementWrapWidth).Y; + if (descriptionContentHeight <= 0f) + descriptionContentHeight = lineHeightWithSpacing; + } + + var maxDescriptionHeight = lineHeightWithSpacing * DescriptionMaxVisibleLines; + var descriptionChildHeight = Math.Clamp(descriptionContentHeight, lineHeightWithSpacing, maxDescriptionHeight); + + RenderDescriptionChild( + "##StandaloneGroupDescription", + new Vector2(descriptionRegionWidth, descriptionChildHeight), + hasDescription ? profile.Description : null, + GroupDescriptionPlaceholder); + var descriptionEndLocal = ImGui.GetCursorPos(); + var descriptionBlockBottom = windowPos.Y + descriptionEndLocal.Y; + aliasAndTagsBottomLocal = MathF.Max(aliasAndTagsBottomLocal, descriptionEndLocal.Y); + aliasAndTagsBlockBottom = MathF.Max(aliasAndTagsBlockBottom, descriptionBlockBottom); + + var presenceLabelSpacing = style.ItemSpacing.Y * 0.35f; + var presenceAnchorY = MathF.Max(portraitFrameLocalMax.Y, aliasGroupLocalMax.Y); + var presenceStartLocal = new Vector2(portraitFrameLocalMin.X, presenceAnchorY + presenceLabelSpacing); + ImGui.SetCursorPos(presenceStartLocal); + ImGui.TextDisabled("Presence"); + ImGui.SetCursorPosX(portraitFrameLocalMin.X); + if (presenceTokens.Count > 0) + { + var presenceColumnWidth = MathF.Max(1f, aliasColumnX - portraitFrameLocalMin.X - style.ItemSpacing.X); + RenderPresenceTokens(presenceTokens, scale, presenceColumnWidth); } else { - if (disabled) - ImGui.TextDisabled(text); - else - ImGui.TextUnformatted(text); + ImGui.TextDisabled("-- No status flags --"); + ImGui.Dummy(new Vector2(0f, style.ItemSpacing.Y * 0.25f)); } + + var presenceContentEnd = ImGui.GetCursorPos(); + var separatorSpacing = style.ItemSpacing.Y * 0.2f; + var separatorThickness = MathF.Max(1f, scale); + var separatorStartLocal = new Vector2(portraitFrameLocalMin.X, presenceContentEnd.Y + separatorSpacing); + var separatorStart = windowPos + separatorStartLocal; + var separatorEnd = new Vector2(portraitFrameMax.X, separatorStart.Y); + drawList.AddLine(separatorStart, separatorEnd, ImGui.GetColorU32(portraitFrameBorder), separatorThickness); + var afterSeparatorLocal = separatorStartLocal + new Vector2(0f, separatorThickness + separatorSpacing * 0.75f); + + var columnStartLocalY = afterSeparatorLocal.Y; + var leftColumnX = portraitFrameLocalMin.X; + ImGui.SetCursorPos(new Vector2(leftColumnX, columnStartLocalY)); + float leftColumnEndY = columnStartLocalY; + + if (!string.IsNullOrEmpty(noteText)) + { + ImGui.TextDisabled("Notes"); + ImGui.SetCursorPosX(leftColumnX); + ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X); + ImGui.TextUnformatted(noteText); + ImGui.PopTextWrapPos(); + ImGui.SetCursorPos(new Vector2(leftColumnX, ImGui.GetCursorPosY() + style.ItemSpacing.Y * 0.5f)); + leftColumnEndY = ImGui.GetCursorPosY(); + } + + leftColumnEndY = MathF.Max(leftColumnEndY, ImGui.GetCursorPosY()); + + var columnsBottomLocal = leftColumnEndY; + var columnsBottom = windowPos.Y + columnsBottomLocal; + var topAreaBase = windowPos.Y + topAreaStart.Y; + var contentBlockBottom = MathF.Max(columnsBottom, aliasAndTagsBlockBottom); + var leftBlockBottom = MathF.Max(portraitBlockBottom, contentBlockBottom); + var topAreaHeight = leftBlockBottom - topAreaBase; + if (topAreaHeight < 0f) + topAreaHeight = 0f; + + ImGui.SetCursorPos(new Vector2(leftColumnX, topAreaStart.Y + topAreaHeight + style.ItemSpacing.Y)); + + var finalCursorY = ImGui.GetCursorPosY(); + var paddingY = ImGui.GetStyle().WindowPadding.Y; + var computedHeight = finalCursorY + paddingY; + var adjustedHeight = Math.Clamp(computedHeight, minHeight, maxAllowedHeight); + _lastComputedWindowHeight = adjustedHeight; + + var finalSize = new Vector2(baseWidth, adjustedHeight); + Size = finalSize; + ImGui.SetWindowSize(finalSize, ImGuiCond.Always); } - ImGui.EndGroup(); - var namesEnd = ImGui.GetCursorPos(); - - var aliasGroupRectMin = ImGui.GetItemRectMin(); - var aliasGroupRectMax = ImGui.GetItemRectMax(); - var aliasGroupLocalMin = aliasGroupRectMin - windowPos; - var aliasGroupLocalMax = aliasGroupRectMax - windowPos; - - var tagsStartLocal = new Vector2(aliasGroupLocalMax.X + style.ItemSpacing.X + 25f * scale, aliasGroupLocalMin.Y + style.FramePadding.Y + 2f * scale); - ImGui.SetCursorPos(tagsStartLocal); - if (profileTags.Count > 0) - RenderProfileTags(profileTags, scale); - else - ImGui.TextDisabled("-- No tags set --"); - var tagsEndLocal = ImGui.GetCursorPos(); - var tagsBlockBottom = windowPos.Y + tagsEndLocal.Y; - var aliasBlockBottom = windowPos.Y + aliasGroupLocalMax.Y; - var aliasAndTagsBottomLocal = MathF.Max(aliasGroupLocalMax.Y, tagsEndLocal.Y); - var aliasAndTagsBlockBottom = MathF.Max(aliasBlockBottom, tagsBlockBottom); - - var descriptionSeparatorSpacing = style.ItemSpacing.Y * 0.35f; - var descriptionSeparatorThickness = MathF.Max(1f, scale); - var descriptionExtraOffset = _groupInfo.Owner is not null ? style.ItemSpacing.Y * 0.6f : 0f; - var descriptionStartLocal = new Vector2(aliasColumnX, aliasAndTagsBottomLocal + descriptionSeparatorSpacing + descriptionExtraOffset); - var horizontalInset = style.ItemSpacing.X * 0.5f; - var descriptionSeparatorStart = windowPos + new Vector2(aliasColumnX - horizontalInset, descriptionStartLocal.Y); - var descriptionSeparatorEnd = new Vector2(windowPos.X + windowSize.X - style.WindowPadding.X + horizontalInset, descriptionSeparatorStart.Y); - drawList.AddLine(descriptionSeparatorStart, descriptionSeparatorEnd, ImGui.GetColorU32(portraitFrameBorder), descriptionSeparatorThickness); - - var descriptionContentStartLocal = new Vector2(aliasColumnX, descriptionStartLocal.Y + descriptionSeparatorThickness + descriptionSeparatorSpacing + style.FramePadding.Y * 0.75f); - ImGui.SetCursorPos(descriptionContentStartLocal); - ImGui.TextDisabled("Description"); - ImGui.SetCursorPosX(aliasColumnX); - var descriptionRegionWidth = ImGui.GetContentRegionAvail().X; - if (descriptionRegionWidth <= 0f) - descriptionRegionWidth = 1f; - var measurementWrapWidth = MathF.Max(1f, descriptionRegionWidth - style.WindowPadding.X * 2f); - var hasDescription = !string.IsNullOrWhiteSpace(profile.Description); - float descriptionContentHeight; - float lineHeightWithSpacing; - using (_uiSharedService.GameFont.Push()) - { - lineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing(); - var measurementText = hasDescription - ? NormalizeDescriptionForMeasurement(profile.Description!) - : GroupDescriptionPlaceholder; - if (string.IsNullOrWhiteSpace(measurementText)) - measurementText = GroupDescriptionPlaceholder; - - descriptionContentHeight = ImGui.CalcTextSize(measurementText, wrapWidth: measurementWrapWidth).Y; - if (descriptionContentHeight <= 0f) - descriptionContentHeight = lineHeightWithSpacing; - } - - var maxDescriptionHeight = lineHeightWithSpacing * DescriptionMaxVisibleLines; - var descriptionChildHeight = Math.Clamp(descriptionContentHeight, lineHeightWithSpacing, maxDescriptionHeight); - - RenderDescriptionChild( - "##StandaloneGroupDescription", - new Vector2(descriptionRegionWidth, descriptionChildHeight), - hasDescription ? profile.Description : null, - GroupDescriptionPlaceholder); - var descriptionEndLocal = ImGui.GetCursorPos(); - var descriptionBlockBottom = windowPos.Y + descriptionEndLocal.Y; - aliasAndTagsBottomLocal = MathF.Max(aliasAndTagsBottomLocal, descriptionEndLocal.Y); - aliasAndTagsBlockBottom = MathF.Max(aliasAndTagsBlockBottom, descriptionBlockBottom); - - var presenceLabelSpacing = style.ItemSpacing.Y * 0.35f; - var presenceAnchorY = MathF.Max(portraitFrameLocalMax.Y, aliasGroupLocalMax.Y); - var presenceStartLocal = new Vector2(portraitFrameLocalMin.X, presenceAnchorY + presenceLabelSpacing); - ImGui.SetCursorPos(presenceStartLocal); - ImGui.TextDisabled("Presence"); - ImGui.SetCursorPosX(portraitFrameLocalMin.X); - if (presenceTokens.Count > 0) - { - var presenceColumnWidth = MathF.Max(1f, aliasColumnX - portraitFrameLocalMin.X - style.ItemSpacing.X); - RenderPresenceTokens(presenceTokens, scale, presenceColumnWidth); - } - else - { - ImGui.TextDisabled("-- No status flags --"); - ImGui.Dummy(new Vector2(0f, style.ItemSpacing.Y * 0.25f)); - } - - var presenceContentEnd = ImGui.GetCursorPos(); - var separatorSpacing = style.ItemSpacing.Y * 0.2f; - var separatorThickness = MathF.Max(1f, scale); - var separatorStartLocal = new Vector2(portraitFrameLocalMin.X, presenceContentEnd.Y + separatorSpacing); - var separatorStart = windowPos + separatorStartLocal; - var separatorEnd = new Vector2(portraitFrameMax.X, separatorStart.Y); - drawList.AddLine(separatorStart, separatorEnd, ImGui.GetColorU32(portraitFrameBorder), separatorThickness); - var afterSeparatorLocal = separatorStartLocal + new Vector2(0f, separatorThickness + separatorSpacing * 0.75f); - - var columnStartLocalY = afterSeparatorLocal.Y; - var leftColumnX = portraitFrameLocalMin.X; - ImGui.SetCursorPos(new Vector2(leftColumnX, columnStartLocalY)); - float leftColumnEndY = columnStartLocalY; - - if (!string.IsNullOrEmpty(noteText)) - { - ImGui.TextDisabled("Notes"); - ImGui.SetCursorPosX(leftColumnX); - ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X); - ImGui.TextUnformatted(noteText); - ImGui.PopTextWrapPos(); - ImGui.SetCursorPos(new Vector2(leftColumnX, ImGui.GetCursorPosY() + style.ItemSpacing.Y * 0.5f)); - leftColumnEndY = ImGui.GetCursorPosY(); - } - - leftColumnEndY = MathF.Max(leftColumnEndY, ImGui.GetCursorPosY()); - - var columnsBottomLocal = leftColumnEndY; - var columnsBottom = windowPos.Y + columnsBottomLocal; - var topAreaBase = windowPos.Y + topAreaStart.Y; - var contentBlockBottom = MathF.Max(columnsBottom, aliasAndTagsBlockBottom); - var leftBlockBottom = MathF.Max(portraitBlockBottom, contentBlockBottom); - var topAreaHeight = leftBlockBottom - topAreaBase; - if (topAreaHeight < 0f) - topAreaHeight = 0f; - - ImGui.SetCursorPos(new Vector2(leftColumnX, topAreaStart.Y + topAreaHeight + style.ItemSpacing.Y)); - - var finalCursorY = ImGui.GetCursorPosY(); - var paddingY = ImGui.GetStyle().WindowPadding.Y; - var computedHeight = finalCursorY + paddingY; - var adjustedHeight = Math.Clamp(computedHeight, minHeight, maxAllowedHeight); - _lastComputedWindowHeight = adjustedHeight; - - var finalSize = new Vector2(baseWidth, adjustedHeight); - Size = finalSize; - ImGui.SetWindowSize(finalSize, ImGuiCond.Always); } private IDalamudTextureWrap? GetBannerTexture(byte[] bannerBytes) diff --git a/LightlessSync/UI/SyncshellAdminUI.cs b/LightlessSync/UI/SyncshellAdminUI.cs index e190193..0eef2e5 100644 --- a/LightlessSync/UI/SyncshellAdminUI.cs +++ b/LightlessSync/UI/SyncshellAdminUI.cs @@ -235,7 +235,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase if (_uiSharedService.IconTextButton(FontAwesomeIcon.AddressCard, "Open Syncshell Profile")) { - Mediator.Publish(new GroupProfileOpenStandaloneMessage(GroupFullInfo)); + Mediator.Publish(new GroupProfileOpenStandaloneMessage(GroupFullInfo.Group)); } UiSharedService.AttachToolTip("Opens the standalone Syncshell profile window for this group."); diff --git a/LightlessSync/UI/SyncshellFinderUI.cs b/LightlessSync/UI/SyncshellFinderUI.cs index b550b41..310d79e 100644 --- a/LightlessSync/UI/SyncshellFinderUI.cs +++ b/LightlessSync/UI/SyncshellFinderUI.cs @@ -220,11 +220,19 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase float rightTxtW = ImGui.CalcTextSize(broadcasterName).X; _uiSharedService.MediumText(displayName, UIColors.Get("LightlessPurple")); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Click to open profile."); + if (ImGui.IsItemClicked()) + { + Mediator.Publish(new GroupProfileOpenStandaloneMessage(shell.Group)); + } float rightX = startX + regionW - rightTxtW - style.ItemSpacing.X; ImGui.SameLine(); ImGui.SetCursorPosX(rightX); ImGui.TextUnformatted(broadcasterName); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Broadcaster of the syncshell."); UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault")); @@ -293,7 +301,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase ImGui.SetTooltip("Click to open profile."); if (ImGui.IsItemClicked()) { - //open profile of syncshell + Mediator.Publish(new GroupProfileOpenStandaloneMessage(shell.Group)); } ImGui.SameLine(); diff --git a/LightlessSync/UI/Tags/ProfileTagService.cs b/LightlessSync/UI/Tags/ProfileTagService.cs index 6f9a3ff..45f18dd 100644 --- a/LightlessSync/UI/Tags/ProfileTagService.cs +++ b/LightlessSync/UI/Tags/ProfileTagService.cs @@ -9,10 +9,10 @@ public sealed class ProfileTagService { private static readonly IReadOnlyDictionary TagLibrary = CreateTagLibrary(); - public IReadOnlyDictionary GetTagLibrary() + public static IReadOnlyDictionary GetTagLibrary() => TagLibrary; - public IReadOnlyList ResolveTags(IReadOnlyList? tagIds) + public static IReadOnlyList ResolveTags(IReadOnlyList? tagIds) { if (tagIds is null || tagIds.Count == 0) return Array.Empty();