Added tags in the shell finder, button is red when not joinable. Fixed some null errors.
This commit is contained in:
@@ -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.Data.Extensions;
|
||||
using LightlessSync.API.Dto.Group;
|
||||
using LightlessSync.LightlessConfiguration;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using LightlessSync.API.Data;
|
||||
@@ -8,14 +9,16 @@ using LightlessSync.API.Data.Enum;
|
||||
using LightlessSync.API.Data.Extensions;
|
||||
using LightlessSync.API.Dto;
|
||||
using LightlessSync.API.Dto.Group;
|
||||
using LightlessSync.API.Dto.User;
|
||||
using LightlessSync.Services;
|
||||
using LightlessSync.Services.LightFinder;
|
||||
using LightlessSync.Services.Mediator;
|
||||
using LightlessSync.UI.Services;
|
||||
using LightlessSync.UI.Tags;
|
||||
using LightlessSync.Utils;
|
||||
using LightlessSync.WebAPI;
|
||||
using LightlessSync.UI.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Numerics;
|
||||
using LightlessSync.Services.LightFinder;
|
||||
|
||||
namespace LightlessSync.UI;
|
||||
|
||||
@@ -28,6 +31,10 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
private readonly PairUiService _pairUiService;
|
||||
private readonly DalamudUtilService _dalamudUtilService;
|
||||
|
||||
private Vector4 _tagBackgroundColor = new(0.18f, 0.18f, 0.18f, 0.95f);
|
||||
private Vector4 _tagBorderColor = new(0.35f, 0.35f, 0.35f, 0.4f);
|
||||
|
||||
private readonly List<SeStringUtils.SeStringSegment> _seResolvedSegments = new();
|
||||
private readonly List<GroupJoinDto> _nearbySyncshells = [];
|
||||
private List<GroupFullInfoDto> _currentSyncshells = [];
|
||||
private int _selectedNearbyIndex = -1;
|
||||
@@ -40,6 +47,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
private bool _useTestSyncshells = false;
|
||||
|
||||
private bool _compactView = false;
|
||||
private readonly LightlessProfileManager _lightlessProfileManager;
|
||||
|
||||
public SyncshellFinderUI(
|
||||
ILogger<SyncshellFinderUI> logger,
|
||||
@@ -50,7 +58,8 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
ApiController apiController,
|
||||
LightFinderScannerService broadcastScannerService,
|
||||
PairUiService pairUiService,
|
||||
DalamudUtilService dalamudUtilService) : base(logger, mediator, "Shellfinder###LightlessSyncshellFinderUI", performanceCollectorService)
|
||||
DalamudUtilService dalamudUtilService,
|
||||
LightlessProfileManager lightlessProfileManager) : base(logger, mediator, "Shellfinder###LightlessSyncshellFinderUI", performanceCollectorService)
|
||||
{
|
||||
_broadcastService = broadcastService;
|
||||
_uiSharedService = uiShared;
|
||||
@@ -58,16 +67,18 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
_broadcastScannerService = broadcastScannerService;
|
||||
_pairUiService = pairUiService;
|
||||
_dalamudUtilService = dalamudUtilService;
|
||||
_lightlessProfileManager = lightlessProfileManager;
|
||||
|
||||
IsOpen = false;
|
||||
WindowBuilder.For(this)
|
||||
.SetSizeConstraints(new Vector2(600, 400), new Vector2(600, 550))
|
||||
.Apply();
|
||||
.SetSizeConstraints(new Vector2(600, 400), new Vector2(600, 550))
|
||||
.Apply();
|
||||
|
||||
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()
|
||||
@@ -80,7 +91,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
{
|
||||
ImGui.BeginGroup();
|
||||
_uiSharedService.MediumText("Nearby Syncshells", UIColors.Get("LightlessPurple"));
|
||||
|
||||
|
||||
#if DEBUG
|
||||
if (ImGui.SmallButton("Show test syncshells"))
|
||||
{
|
||||
@@ -92,7 +103,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
|
||||
string checkboxLabel = "Compact view";
|
||||
float availWidth = ImGui.GetContentRegionAvail().X;
|
||||
float checkboxWidth = ImGui.CalcTextSize(checkboxLabel).X + ImGui.GetFrameHeight();
|
||||
float checkboxWidth = ImGui.CalcTextSize(checkboxLabel).X + ImGui.GetFrameHeight();
|
||||
|
||||
float rightX = ImGui.GetCursorPosX() + availWidth - checkboxWidth - 4.0f;
|
||||
ImGui.SetCursorPosX(rightX);
|
||||
@@ -130,13 +141,17 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
return;
|
||||
}
|
||||
|
||||
var broadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts() ?? [];
|
||||
|
||||
var cardData = new List<(GroupJoinDto Shell, string BroadcasterName)>();
|
||||
var broadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
|
||||
|
||||
foreach (var shell in _nearbySyncshells)
|
||||
{
|
||||
string broadcasterName;
|
||||
|
||||
if (shell?.Group == null || string.IsNullOrEmpty(shell.Group.GID))
|
||||
continue;
|
||||
|
||||
if (_useTestSyncshells)
|
||||
{
|
||||
var displayName = !string.IsNullOrEmpty(shell.Group.Alias)
|
||||
@@ -206,7 +221,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
var (shell, broadcasterName) = listData[index];
|
||||
|
||||
ImGui.PushID(shell.Group.GID);
|
||||
float rowHeight = 90f * ImGuiHelpers.GlobalScale;
|
||||
float rowHeight = 74f * ImGuiHelpers.GlobalScale;
|
||||
|
||||
ImGui.BeginChild($"ShellRow##{shell.Group.GID}", new Vector2(-1, rowHeight), border: true);
|
||||
|
||||
@@ -234,10 +249,48 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
|
||||
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"));
|
||||
|
||||
ImGui.Dummy(new Vector2(0, 6 * ImGuiHelpers.GlobalScale));
|
||||
var groupProfile = _lightlessProfileManager.GetLightlessGroupProfile(shell.Group);
|
||||
|
||||
IReadOnlyList<ProfileTagDefinition> groupTags =
|
||||
groupProfile != null && groupProfile.Tags.Count > 0
|
||||
? ProfileTagService.ResolveTags(groupProfile.Tags)
|
||||
: [];
|
||||
|
||||
var limitedTags = groupTags.Count > 3
|
||||
? [.. groupTags.Take(3)]
|
||||
: groupTags;
|
||||
|
||||
float tagScale = ImGuiHelpers.GlobalScale * 0.9f;
|
||||
|
||||
Vector2 rowStartLocal = ImGui.GetCursorPos();
|
||||
|
||||
float tagsWidth = 0f;
|
||||
float tagsHeight = 0f;
|
||||
|
||||
if (limitedTags.Count > 0)
|
||||
{
|
||||
(tagsWidth, tagsHeight) = RenderProfileTagsSingleRow(limitedTags, tagScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.SetCursorPosX(startX);
|
||||
ImGui.TextDisabled("-- No tags set --");
|
||||
ImGui.Dummy(new Vector2(0, 4 * ImGuiHelpers.GlobalScale));
|
||||
}
|
||||
|
||||
float btnBaselineY = rowStartLocal.Y;
|
||||
float joinX = rowStartLocal.X + (tagsWidth > 0 ? tagsWidth + style.ItemSpacing.X : 0f);
|
||||
|
||||
ImGui.SetCursorPos(new Vector2(joinX, btnBaselineY));
|
||||
DrawJoinButton(shell);
|
||||
|
||||
float btnHeight = ImGui.GetFrameHeightWithSpacing();
|
||||
float rowHeightUsed = MathF.Max(tagsHeight, btnHeight);
|
||||
|
||||
ImGui.SetCursorPos(new Vector2(
|
||||
rowStartLocal.X,
|
||||
rowStartLocal.Y + rowHeightUsed));
|
||||
|
||||
ImGui.EndChild();
|
||||
ImGui.PopID();
|
||||
|
||||
@@ -311,10 +364,39 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
ImGui.SetTooltip("Broadcaster of the syncshell.");
|
||||
|
||||
ImGui.EndGroup();
|
||||
|
||||
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"));
|
||||
|
||||
ImGui.Dummy(new Vector2(0, 6 * ImGuiHelpers.GlobalScale));
|
||||
|
||||
var groupProfile = _lightlessProfileManager.GetLightlessGroupProfile(shell.Group);
|
||||
|
||||
IReadOnlyList<ProfileTagDefinition> groupTags =
|
||||
groupProfile != null && groupProfile.Tags.Count > 0
|
||||
? ProfileTagService.ResolveTags(groupProfile.Tags)
|
||||
: [];
|
||||
|
||||
float tagScale = ImGuiHelpers.GlobalScale * 0.9f;
|
||||
|
||||
if (groupTags.Count > 0)
|
||||
{
|
||||
var limitedTags = groupTags.Count > 2
|
||||
? [.. groupTags.Take(2)]
|
||||
: groupTags;
|
||||
|
||||
ImGui.SetCursorPosX(startX);
|
||||
|
||||
var (_, tagsHeight) = RenderProfileTagsSingleRow(limitedTags, tagScale);
|
||||
|
||||
ImGui.Dummy(new Vector2(0, 4 * ImGuiHelpers.GlobalScale));
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.SetCursorPosX(startX);
|
||||
ImGui.TextDisabled("-- No tags set --");
|
||||
ImGui.Dummy(new Vector2(0, 4 * ImGuiHelpers.GlobalScale));
|
||||
}
|
||||
|
||||
var buttonHeight = ImGui.GetFrameHeightWithSpacing();
|
||||
var remainingY = ImGui.GetContentRegionAvail().Y - buttonHeight;
|
||||
if (remainingY > 0)
|
||||
@@ -338,7 +420,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
{
|
||||
if (totalPages > 1)
|
||||
{
|
||||
UiSharedService.ColoredSeparator(UIColors.Get("PairBlue"));
|
||||
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"));
|
||||
|
||||
var style = ImGui.GetStyle();
|
||||
string pageLabel = $"Page {_syncshellPageIndex + 1}/{totalPages}";
|
||||
@@ -371,10 +453,6 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
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);
|
||||
|
||||
@@ -386,7 +464,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
var textSize = ImGui.CalcTextSize(visibleLabel);
|
||||
|
||||
var width = textSize.X + style.FramePadding.X * 20f;
|
||||
buttonSize = new Vector2(width, 0);
|
||||
buttonSize = new Vector2(width, 30f);
|
||||
|
||||
float availX = ImGui.GetContentRegionAvail().X;
|
||||
float curX = ImGui.GetCursorPosX();
|
||||
@@ -400,6 +478,9 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
|
||||
if (!isAlreadyMember && !isRecentlyJoined)
|
||||
{
|
||||
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));
|
||||
if (ImGui.Button(label, buttonSize))
|
||||
{
|
||||
_logger.LogInformation($"Join requested for Syncshell {shell.Group.GID} ({shell.Group.Alias})");
|
||||
@@ -436,6 +517,10 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("DimRed"));
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, UIColors.Get("DimRed").WithAlpha(0.85f));
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, UIColors.Get("DimRed").WithAlpha(0.75f));
|
||||
|
||||
using (ImRaii.Disabled())
|
||||
{
|
||||
ImGui.Button(label, buttonSize);
|
||||
@@ -446,6 +531,72 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
|
||||
ImGui.PopStyleColor(3);
|
||||
}
|
||||
|
||||
private (float widthUsed, float rowHeight) RenderProfileTagsSingleRow(IReadOnlyList<ProfileTagDefinition> tags, float scale)
|
||||
{
|
||||
if (tags == null || tags.Count == 0)
|
||||
return (0f, 0f);
|
||||
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
var style = ImGui.GetStyle();
|
||||
var defaultTextColorU32 = ImGui.GetColorU32(ImGuiCol.Text);
|
||||
|
||||
var baseLocal = ImGui.GetCursorPos();
|
||||
var baseScreen = ImGui.GetCursorScreenPos();
|
||||
float availableWidth = ImGui.GetContentRegionAvail().X;
|
||||
if (availableWidth <= 0f)
|
||||
availableWidth = 1f;
|
||||
|
||||
float cursorLocalX = baseLocal.X;
|
||||
float cursorScreenX = baseScreen.X;
|
||||
float rowHeight = 0f;
|
||||
|
||||
for (int i = 0; i < tags.Count; i++)
|
||||
{
|
||||
var tag = tags[i];
|
||||
if (!tag.HasContent)
|
||||
continue;
|
||||
|
||||
var tagSize = ProfileTagRenderer.MeasureTag(tag, scale, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _seResolvedSegments, GetIconWrap, _logger);
|
||||
|
||||
float tagWidth = tagSize.X;
|
||||
float tagHeight = tagSize.Y;
|
||||
|
||||
if (cursorLocalX > baseLocal.X && cursorLocalX + tagWidth > baseLocal.X + availableWidth)
|
||||
break;
|
||||
|
||||
var tagScreenPos = new Vector2(cursorScreenX, baseScreen.Y);
|
||||
ImGui.SetCursorScreenPos(tagScreenPos);
|
||||
ImGui.InvisibleButton($"##profileTagInline_{i}", tagSize);
|
||||
|
||||
ProfileTagRenderer.RenderTag(tag, tagScreenPos, scale, drawList, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _seResolvedSegments, GetIconWrap, _logger);
|
||||
|
||||
cursorLocalX += tagWidth + style.ItemSpacing.X;
|
||||
cursorScreenX += tagWidth + style.ItemSpacing.X;
|
||||
rowHeight = MathF.Max(rowHeight, tagHeight);
|
||||
}
|
||||
|
||||
ImGui.SetCursorPos(new Vector2(baseLocal.X, baseLocal.Y + rowHeight));
|
||||
|
||||
float widthUsed = cursorLocalX - baseLocal.X;
|
||||
return (widthUsed, rowHeight);
|
||||
}
|
||||
|
||||
private IDalamudTextureWrap? GetIconWrap(uint iconId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_uiSharedService.TryGetIcon(iconId, out var wrap) && wrap != null)
|
||||
return wrap;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug(ex, "Failed to resolve icon {IconId} for profile tags", iconId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void DrawConfirmation()
|
||||
{
|
||||
if (_joinDto != null && _joinInfo != null)
|
||||
@@ -470,9 +621,9 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
||||
finalPermissions.SetDisableVFX(_ownPermissions.DisableGroupVFX);
|
||||
|
||||
_ = _apiController.GroupJoinFinalize(new GroupJoinDto(_joinDto.Group, _joinDto.Password, finalPermissions));
|
||||
|
||||
|
||||
_recentlyJoined.Add(_joinDto.Group.GID);
|
||||
|
||||
|
||||
_joinDto = null;
|
||||
_joinInfo = null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user