Added new shellfinder ui
This commit is contained in:
@@ -68,7 +68,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var cid = await _dalamudUtil.GetCIDAsync().ConfigureAwait(false);
|
var cid = await _dalamudUtil.GetCIDAsync().ConfigureAwait(false);
|
||||||
return cid.ToString().GetBlake3Hash();
|
return cid.ToString().GetHash256();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public sealed class XivDataAnalyzer
|
|||||||
if (handle->FileName.Length > 1024) continue;
|
if (handle->FileName.Length > 1024) continue;
|
||||||
var skeletonName = handle->FileName.ToString();
|
var skeletonName = handle->FileName.ToString();
|
||||||
if (string.IsNullOrEmpty(skeletonName)) continue;
|
if (string.IsNullOrEmpty(skeletonName)) continue;
|
||||||
outputIndices[skeletonName] = new();
|
outputIndices[skeletonName] = [];
|
||||||
for (ushort boneIdx = 0; boneIdx < curBones; boneIdx++)
|
for (ushort boneIdx = 0; boneIdx < curBones; boneIdx++)
|
||||||
{
|
{
|
||||||
var boneName = handle->HavokSkeleton->Bones[boneIdx].Name.String;
|
var boneName = handle->HavokSkeleton->Bones[boneIdx].Name.String;
|
||||||
@@ -70,7 +70,7 @@ public sealed class XivDataAnalyzer
|
|||||||
var cacheEntity = _fileCacheManager.GetFileCacheByHash(hash);
|
var cacheEntity = _fileCacheManager.GetFileCacheByHash(hash);
|
||||||
if (cacheEntity == null) return null;
|
if (cacheEntity == null) return null;
|
||||||
|
|
||||||
using BinaryReader reader = new BinaryReader(File.Open(cacheEntity.ResolvedFilepath, FileMode.Open, FileAccess.Read, FileShare.Read));
|
using BinaryReader reader = new(File.Open(cacheEntity.ResolvedFilepath, FileMode.Open, FileAccess.Read, FileShare.Read));
|
||||||
|
|
||||||
// most of this shit is from vfxeditor, surely nothing will change in the pap format :copium:
|
// most of this shit is from vfxeditor, surely nothing will change in the pap format :copium:
|
||||||
reader.ReadInt32(); // ignore
|
reader.ReadInt32(); // ignore
|
||||||
@@ -177,17 +177,18 @@ public sealed class XivDataAnalyzer
|
|||||||
}
|
}
|
||||||
|
|
||||||
long tris = 0;
|
long tris = 0;
|
||||||
for (int i = 0; i < file.LodCount; i++)
|
foreach (var lod in file.Lods)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var meshIdx = file.Lods[i].MeshIndex;
|
var meshIdx = lod.MeshIndex;
|
||||||
var meshCnt = file.Lods[i].MeshCount;
|
var meshCnt = lod.MeshCount;
|
||||||
|
|
||||||
tris = file.Meshes.Skip(meshIdx).Take(meshCnt).Sum(p => p.IndexCount) / 3;
|
tris = file.Meshes.Skip(meshIdx).Take(meshCnt).Sum(p => p.IndexCount) / 3;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogDebug(ex, "Could not load lod mesh {mesh} from path {path}", i, filePath);
|
_logger.LogDebug(ex, "Could not load lod mesh {mesh} from path {path}", lod.MeshIndex, filePath);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Dalamud.Interface;
|
|||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Dalamud.Interface.Utility.Raii;
|
||||||
|
using LightlessSync.API.Data;
|
||||||
using LightlessSync.API.Data.Enum;
|
using LightlessSync.API.Data.Enum;
|
||||||
using LightlessSync.API.Data.Extensions;
|
using LightlessSync.API.Data.Extensions;
|
||||||
using LightlessSync.API.Dto;
|
using LightlessSync.API.Dto;
|
||||||
@@ -29,11 +30,15 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
private readonly List<GroupJoinDto> _nearbySyncshells = [];
|
private readonly List<GroupJoinDto> _nearbySyncshells = [];
|
||||||
private List<GroupFullInfoDto> _currentSyncshells = [];
|
private List<GroupFullInfoDto> _currentSyncshells = [];
|
||||||
private int _selectedNearbyIndex = -1;
|
private int _selectedNearbyIndex = -1;
|
||||||
|
private int _syncshellPageIndex = 0;
|
||||||
private readonly HashSet<string> _recentlyJoined = new(StringComparer.Ordinal);
|
private readonly HashSet<string> _recentlyJoined = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
private GroupJoinDto? _joinDto;
|
private GroupJoinDto? _joinDto;
|
||||||
private GroupJoinInfoDto? _joinInfo;
|
private GroupJoinInfoDto? _joinInfo;
|
||||||
private DefaultPermissionsDto _ownPermissions = null!;
|
private DefaultPermissionsDto _ownPermissions = null!;
|
||||||
|
private const bool UseTestSyncshells = true;
|
||||||
|
|
||||||
|
private bool _compactView = false;
|
||||||
|
|
||||||
public SyncshellFinderUI(
|
public SyncshellFinderUI(
|
||||||
ILogger<SyncshellFinderUI> logger,
|
ILogger<SyncshellFinderUI> logger,
|
||||||
@@ -72,9 +77,21 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
protected override void DrawInternal()
|
protected override void DrawInternal()
|
||||||
{
|
{
|
||||||
|
ImGui.BeginGroup();
|
||||||
_uiSharedService.MediumText("Nearby Syncshells", UIColors.Get("PairBlue"));
|
_uiSharedService.MediumText("Nearby Syncshells", UIColors.Get("PairBlue"));
|
||||||
UiSharedService.ColoredSeparator(UIColors.Get("PairBlue"));
|
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;
|
||||||
|
ImGui.SetCursorPosX(rightX);
|
||||||
|
ImGui.Checkbox(checkboxLabel, ref _compactView);
|
||||||
|
ImGui.EndGroup();
|
||||||
|
|
||||||
|
UiSharedService.ColoredSeparator(UIColors.Get("PairBlue"));
|
||||||
|
ImGui.Dummy(new Vector2(0, 2 * ImGuiHelpers.GlobalScale));
|
||||||
if (_nearbySyncshells.Count == 0)
|
if (_nearbySyncshells.Count == 0)
|
||||||
{
|
{
|
||||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "No nearby syncshells are being broadcasted.");
|
ImGui.TextColored(ImGuiColors.DalamudGrey, "No nearby syncshells are being broadcasted.");
|
||||||
@@ -104,106 +121,299 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawSyncshellTable();
|
// Build card data (same as you had)
|
||||||
|
var cardData = new List<(GroupJoinDto Shell, string BroadcasterName)>();
|
||||||
|
var broadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
|
||||||
|
|
||||||
|
foreach (var shell in _nearbySyncshells)
|
||||||
|
{
|
||||||
|
string broadcasterName;
|
||||||
|
|
||||||
|
if (UseTestSyncshells)
|
||||||
|
{
|
||||||
|
// Fake broadcaster for test mode
|
||||||
|
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)
|
if (_joinDto != null && _joinInfo != null && _joinInfo.Success)
|
||||||
DrawConfirmation();
|
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);
|
var (shell, broadcasterName) = listData[index];
|
||||||
ImGui.TableSetupColumn("Broadcaster", ImGuiTableColumnFlags.WidthStretch);
|
|
||||||
ImGui.TableSetupColumn("Join", ImGuiTableColumnFlags.WidthFixed, 80f * ImGuiHelpers.GlobalScale);
|
|
||||||
ImGui.TableHeadersRow();
|
|
||||||
|
|
||||||
foreach (var shell in _nearbySyncshells)
|
ImGui.PushID(shell.Group.GID);
|
||||||
{
|
float rowHeight = 90f * ImGuiHelpers.GlobalScale;
|
||||||
// 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));
|
|
||||||
|
|
||||||
if (broadcast == null)
|
ImGui.BeginChild($"ShellRow##{shell.Group.GID}", new Vector2(-1, rowHeight), border: true);
|
||||||
continue; // no active broadcasts
|
|
||||||
|
|
||||||
var (Name, Address) = _dalamudUtilService.FindPlayerByNameHash(broadcast.HashedCID);
|
var displayName = !string.IsNullOrEmpty(shell.Group.Alias) ? shell.Group.Alias : shell.Group.GID;
|
||||||
if (string.IsNullOrEmpty(Name))
|
|
||||||
continue; // broadcaster not found in area, skipping
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
var style = ImGui.GetStyle();
|
||||||
ImGui.TableNextColumn();
|
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;
|
_uiSharedService.MediumText(displayName, UIColors.Get("PairBlue"));
|
||||||
ImGui.TextUnformatted(displayName);
|
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
float rightX = startX + regionW - rightTxtW - style.ItemSpacing.X;
|
||||||
var worldName = _dalamudUtilService.GetWorldNameFromPlayerAddress(Address);
|
ImGui.SameLine();
|
||||||
var broadcasterName = !string.IsNullOrEmpty(worldName) ? $"{Name} ({worldName})" : Name;
|
ImGui.SetCursorPosX(rightX);
|
||||||
ImGui.TextUnformatted(broadcasterName);
|
ImGui.TextUnformatted(broadcasterName);
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
UiSharedService.ColoredSeparator(UIColors.Get("PairBlue"));
|
||||||
|
|
||||||
var label = $"Join##{shell.Group.GID}";
|
ImGui.Dummy(new Vector2(0, 6 * ImGuiHelpers.GlobalScale));
|
||||||
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));
|
DrawJoinButton(shell);
|
||||||
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})");
|
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
ImGui.EndChild();
|
||||||
{
|
ImGui.PopID();
|
||||||
try
|
|
||||||
{
|
|
||||||
var info = await _apiController.GroupJoinHashed(new GroupJoinHashedDto(
|
|
||||||
shell.Group,
|
|
||||||
shell.Password,
|
|
||||||
shell.GroupUserPreferredPermissions
|
|
||||||
)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (info != null && info.Success)
|
ImGui.Dummy(new Vector2(0, 2 * ImGuiHelpers.GlobalScale));
|
||||||
{
|
}
|
||||||
_joinDto = new GroupJoinDto(shell.Group, shell.Password, shell.GroupUserPreferredPermissions);
|
|
||||||
_joinInfo = info;
|
|
||||||
_ownPermissions = _apiController.DefaultPermissions.DeepClone()!;
|
|
||||||
|
|
||||||
_logger.LogInformation($"Fetched join info for {shell.Group.GID}");
|
ImGui.PopStyleVar(2);
|
||||||
}
|
|
||||||
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.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),
|
||||||
|
true);
|
||||||
|
|
||||||
|
var displayName = !string.IsNullOrEmpty(shell.Group.Alias)
|
||||||
|
? shell.Group.Alias
|
||||||
|
: shell.Group.GID;
|
||||||
|
|
||||||
|
_uiSharedService.MediumText(displayName + "(200/250)", UIColors.Get("PairBlue"));
|
||||||
|
UiSharedService.ColoredSeparator(UIColors.Get("PairBlue"));
|
||||||
|
|
||||||
|
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()
|
private void DrawConfirmation()
|
||||||
{
|
{
|
||||||
if (_joinDto != null && _joinInfo != null)
|
if (_joinDto != null && _joinInfo != null)
|
||||||
@@ -267,48 +477,89 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
var syncshellBroadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
|
var syncshellBroadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts();
|
||||||
_currentSyncshells = [.. _pairManager.GroupPairs.Select(g => g.Key)];
|
_currentSyncshells = [.. _pairManager.GroupPairs.Select(g => g.Key)];
|
||||||
|
|
||||||
_recentlyJoined.RemoveWhere(gid => _currentSyncshells.Any(s => string.Equals(s.GID, gid, StringComparison.Ordinal)));
|
|
||||||
|
|
||||||
if (syncshellBroadcasts.Count == 0)
|
_recentlyJoined.RemoveWhere(gid =>
|
||||||
|
_currentSyncshells.Any(s => string.Equals(s.GID, gid, StringComparison.Ordinal)));
|
||||||
|
|
||||||
|
List<GroupJoinDto>? updatedList = [];
|
||||||
|
|
||||||
|
if (UseTestSyncshells)
|
||||||
|
{
|
||||||
|
// ---- TEST DATA PATH ----
|
||||||
|
updatedList = BuildTestSyncshells();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ---- NORMAL BEHAVIOUR ----
|
||||||
|
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();
|
ClearSyncshells();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GroupJoinDto>? updatedList = [];
|
var previousGid = GetSelectedGid();
|
||||||
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)
|
_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();
|
if (newIndex >= 0)
|
||||||
_nearbySyncshells.AddRange(updatedList);
|
|
||||||
|
|
||||||
if (previousGid != null)
|
|
||||||
{
|
{
|
||||||
var newIndex = _nearbySyncshells.FindIndex(s => string.Equals(s.Group.GID, previousGid, StringComparison.Ordinal));
|
_selectedNearbyIndex = newIndex;
|
||||||
if (newIndex >= 0)
|
return;
|
||||||
{
|
|
||||||
_selectedNearbyIndex = newIndex;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearSelection();
|
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()
|
private void ClearSyncshells()
|
||||||
{
|
{
|
||||||
if (_nearbySyncshells.Count == 0)
|
if (_nearbySyncshells.Count == 0)
|
||||||
@@ -321,6 +572,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase
|
|||||||
private void ClearSelection()
|
private void ClearSelection()
|
||||||
{
|
{
|
||||||
_selectedNearbyIndex = -1;
|
_selectedNearbyIndex = -1;
|
||||||
|
_syncshellPageIndex = 0;
|
||||||
_joinDto = null;
|
_joinDto = null;
|
||||||
_joinInfo = null;
|
_joinInfo = null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user