Update UI & Syncshell Public & MCDF Share
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using MareSynchronos.API.Dto.Group;
|
||||
using MareSynchronos.MareConfiguration;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
@@ -29,11 +31,16 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
||||
private readonly PairManager _pairManager;
|
||||
private List<Services.Mediator.NearbyEntry> _entries;
|
||||
private readonly HashSet<string> _acceptInFlight = new(StringComparer.Ordinal);
|
||||
private readonly SyncshellDiscoveryService _syncshellDiscoveryService;
|
||||
private List<SyncshellDiscoveryEntryDto> _syncshellEntries = [];
|
||||
private bool _syncshellInitialized;
|
||||
private readonly HashSet<string> _syncshellJoinInFlight = new(StringComparer.OrdinalIgnoreCase);
|
||||
private string? _syncshellLastError;
|
||||
|
||||
public AutoDetectUi(ILogger<AutoDetectUi> logger, MareMediator mediator,
|
||||
MareConfigService configService, DalamudUtilService dalamudUtilService,
|
||||
AutoDetectRequestService requestService, NearbyPendingService pendingService, PairManager pairManager,
|
||||
NearbyDiscoveryService discoveryService,
|
||||
NearbyDiscoveryService discoveryService, SyncshellDiscoveryService syncshellDiscoveryService,
|
||||
PerformanceCollectorService performanceCollectorService)
|
||||
: base(logger, mediator, "AutoDetect", performanceCollectorService)
|
||||
{
|
||||
@@ -43,7 +50,9 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
||||
_pendingService = pendingService;
|
||||
_pairManager = pairManager;
|
||||
_discoveryService = discoveryService;
|
||||
_syncshellDiscoveryService = syncshellDiscoveryService;
|
||||
Mediator.Subscribe<Services.Mediator.DiscoveryListUpdated>(this, OnDiscoveryUpdated);
|
||||
Mediator.Subscribe<SyncshellDiscoveryUpdated>(this, OnSyncshellDiscoveryUpdated);
|
||||
_entries = _discoveryService.SnapshotEntries();
|
||||
|
||||
Flags |= ImGuiWindowFlags.NoScrollbar;
|
||||
@@ -81,14 +90,7 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
||||
});
|
||||
|
||||
DrawStyledTab("Proximité", accent, inactiveTab, hoverTab, DrawNearbyTab);
|
||||
|
||||
using (ImRaii.Disabled(true))
|
||||
{
|
||||
DrawStyledTab("Syncshell", accent, inactiveTab, hoverTab, () =>
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Disponible prochainement.", ImGuiColors.DalamudGrey3);
|
||||
}, true);
|
||||
}
|
||||
DrawStyledTab("Syncshell", accent, inactiveTab, hoverTab, DrawSyncshellTab);
|
||||
}
|
||||
|
||||
public void DrawInline()
|
||||
@@ -221,6 +223,7 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
||||
|
||||
var sourceEntries = _entries.Count > 0 ? _entries : _discoveryService.SnapshotEntries();
|
||||
var orderedEntries = sourceEntries
|
||||
.Where(e => e.IsMatch)
|
||||
.OrderBy(e => float.IsNaN(e.Distance) ? float.MaxValue : e.Distance)
|
||||
.ToList();
|
||||
|
||||
@@ -245,10 +248,9 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
||||
for (int i = 0; i < orderedEntries.Count; i++)
|
||||
{
|
||||
var entry = orderedEntries[i];
|
||||
bool isMatch = entry.IsMatch;
|
||||
bool alreadyPaired = IsAlreadyPairedByUidOrAlias(entry);
|
||||
bool overDistance = !float.IsNaN(entry.Distance) && entry.Distance > maxDist;
|
||||
bool canRequest = isMatch && entry.AcceptPairRequests && !string.IsNullOrEmpty(entry.Token) && !alreadyPaired;
|
||||
bool canRequest = entry.AcceptPairRequests && !string.IsNullOrEmpty(entry.Token) && !alreadyPaired;
|
||||
|
||||
string displayName = entry.DisplayName ?? entry.Name;
|
||||
string worldName = entry.WorldId == 0
|
||||
@@ -260,13 +262,11 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
||||
? "Déjà appairé"
|
||||
: overDistance
|
||||
? $"Hors portée (> {maxDist} m)"
|
||||
: !isMatch
|
||||
? "Umbra non activé"
|
||||
: !entry.AcceptPairRequests
|
||||
? "Invitations refusées"
|
||||
: string.IsNullOrEmpty(entry.Token)
|
||||
? "Indisponible"
|
||||
: "Disponible";
|
||||
: !entry.AcceptPairRequests
|
||||
? "Invitations refusées"
|
||||
: string.IsNullOrEmpty(entry.Token)
|
||||
? "Indisponible"
|
||||
: "Disponible";
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(displayName);
|
||||
@@ -297,13 +297,11 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
||||
? "Vous êtes déjà appairé avec ce joueur."
|
||||
: overDistance
|
||||
? $"Ce joueur est au-delà de la distance maximale configurée ({maxDist} m)."
|
||||
: !isMatch
|
||||
? "Ce joueur n'utilise pas UmbraSync ou ne s'est pas rendu détectable."
|
||||
: !entry.AcceptPairRequests
|
||||
? "Ce joueur a désactivé la réception automatique des invitations."
|
||||
: string.IsNullOrEmpty(entry.Token)
|
||||
? "Impossible d'obtenir un jeton d'invitation pour ce joueur."
|
||||
: string.Empty;
|
||||
: !entry.AcceptPairRequests
|
||||
? "Ce joueur a désactivé la réception automatique des invitations."
|
||||
: string.IsNullOrEmpty(entry.Token)
|
||||
? "Impossible d'obtenir un jeton d'invitation pour ce joueur."
|
||||
: string.Empty;
|
||||
|
||||
ImGui.TextDisabled(status);
|
||||
if (!string.IsNullOrEmpty(reason))
|
||||
@@ -317,11 +315,147 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
|
||||
ImGui.EndTable();
|
||||
}
|
||||
|
||||
private async Task JoinSyncshellAsync(SyncshellDiscoveryEntryDto entry)
|
||||
{
|
||||
if (!_syncshellJoinInFlight.Add(entry.GID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var joined = await _syncshellDiscoveryService.JoinAsync(entry.GID, CancellationToken.None).ConfigureAwait(false);
|
||||
if (joined)
|
||||
{
|
||||
Mediator.Publish(new NotificationMessage("AutoDetect Syncshell", $"Rejoint {entry.Alias ?? entry.GID}.", NotificationType.Info, TimeSpan.FromSeconds(5)));
|
||||
await _syncshellDiscoveryService.RefreshAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_syncshellLastError = $"Impossible de rejoindre {entry.Alias ?? entry.GID}.";
|
||||
Mediator.Publish(new NotificationMessage("AutoDetect Syncshell", _syncshellLastError, NotificationType.Warning, TimeSpan.FromSeconds(5)));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_syncshellLastError = $"Erreur lors de l'adhésion : {ex.Message}";
|
||||
Mediator.Publish(new NotificationMessage("AutoDetect Syncshell", _syncshellLastError, NotificationType.Error, TimeSpan.FromSeconds(5)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_syncshellJoinInFlight.Remove(entry.GID);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSyncshellTab()
|
||||
{
|
||||
if (!_syncshellInitialized)
|
||||
{
|
||||
_syncshellInitialized = true;
|
||||
_ = _syncshellDiscoveryService.RefreshAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
bool isRefreshing = _syncshellDiscoveryService.IsRefreshing;
|
||||
var serviceError = _syncshellDiscoveryService.LastError;
|
||||
|
||||
if (ImGui.Button("Actualiser la liste"))
|
||||
{
|
||||
_ = _syncshellDiscoveryService.RefreshAsync(CancellationToken.None);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Met à jour la liste des Syncshells ayant activé l'AutoDetect.");
|
||||
|
||||
if (isRefreshing)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.TextDisabled("Actualisation...");
|
||||
}
|
||||
|
||||
ImGuiHelpers.ScaledDummy(4);
|
||||
UiSharedService.TextWrapped("Les Syncshells affichées ont temporairement désactivé leur mot de passe pour permettre un accès direct via AutoDetect. Rejoignez-les uniquement si vous faites confiance aux administrateurs.");
|
||||
|
||||
if (!string.IsNullOrEmpty(serviceError))
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(serviceError, ImGuiColors.DalamudRed);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(_syncshellLastError))
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(_syncshellLastError!, ImGuiColors.DalamudOrange);
|
||||
}
|
||||
|
||||
var entries = _syncshellEntries.Count > 0 ? _syncshellEntries : _syncshellDiscoveryService.Entries.ToList();
|
||||
if (entries.Count == 0)
|
||||
{
|
||||
ImGuiHelpers.ScaledDummy(4);
|
||||
UiSharedService.ColorTextWrapped("Aucune Syncshell n'est actuellement visible dans AutoDetect.", ImGuiColors.DalamudGrey3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ImGui.BeginTable("autodetect-syncshells", 5, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.RowBg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.TableSetupColumn("Nom");
|
||||
ImGui.TableSetupColumn("Propriétaire");
|
||||
ImGui.TableSetupColumn("Membres");
|
||||
ImGui.TableSetupColumn("Invitations");
|
||||
ImGui.TableSetupColumn("Action");
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
foreach (var entry in entries.OrderBy(e => e.Alias ?? e.GID, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
bool alreadyMember = _pairManager.Groups.Keys.Any(g => string.Equals(g.GID, entry.GID, StringComparison.OrdinalIgnoreCase));
|
||||
bool joining = _syncshellJoinInFlight.Contains(entry.GID);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(string.IsNullOrEmpty(entry.Alias) ? entry.GID : $"{entry.Alias} ({entry.GID})");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(string.IsNullOrEmpty(entry.OwnerAlias) ? entry.OwnerUID : $"{entry.OwnerAlias} ({entry.OwnerUID})");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(entry.MemberCount.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
string inviteMode = entry.AutoAcceptPairs ? "Auto" : "Manuel";
|
||||
ImGui.TextUnformatted(inviteMode);
|
||||
if (!entry.AutoAcceptPairs)
|
||||
{
|
||||
UiSharedService.AttachToolTip("L'administrateur doit approuver manuellement les nouveaux membres.");
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.Disabled(alreadyMember || joining))
|
||||
{
|
||||
if (alreadyMember)
|
||||
{
|
||||
ImGui.TextDisabled("Déjà membre");
|
||||
}
|
||||
else if (joining)
|
||||
{
|
||||
ImGui.TextDisabled("Connexion...");
|
||||
}
|
||||
else if (ImGui.Button("Rejoindre"))
|
||||
{
|
||||
_syncshellLastError = null;
|
||||
_ = JoinSyncshellAsync(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
|
||||
private void OnDiscoveryUpdated(Services.Mediator.DiscoveryListUpdated msg)
|
||||
{
|
||||
_entries = msg.Entries;
|
||||
}
|
||||
|
||||
private void OnSyncshellDiscoveryUpdated(SyncshellDiscoveryUpdated msg)
|
||||
{
|
||||
_syncshellEntries = msg.Entries;
|
||||
}
|
||||
|
||||
private bool IsAlreadyPairedByUidOrAlias(Services.Mediator.NearbyEntry e)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Text;
|
||||
|
||||
namespace MareSynchronos.UI;
|
||||
|
||||
internal sealed partial class CharaDataHubUi
|
||||
public sealed partial class CharaDataHubUi
|
||||
{
|
||||
private static string GetAccessTypeString(AccessTypeDto dto) => dto switch
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ using MareSynchronos.Services.CharaData.Models;
|
||||
|
||||
namespace MareSynchronos.UI;
|
||||
|
||||
internal sealed partial class CharaDataHubUi
|
||||
public sealed partial class CharaDataHubUi
|
||||
{
|
||||
private string _joinLobbyId = string.Empty;
|
||||
private void DrawGposeTogether()
|
||||
@@ -90,7 +90,7 @@ internal sealed partial class CharaDataHubUi
|
||||
if (!_uiSharedService.IsInGpose)
|
||||
{
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Assigning users to characters is only available in GPose.", ImGuiColors.DalamudYellow, 300);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Assigning users to characters is only available in GPose.", UiSharedService.AccentColor, 300);
|
||||
}
|
||||
UiSharedService.DistanceSeparator();
|
||||
ImGui.TextUnformatted("Users In Lobby");
|
||||
@@ -104,7 +104,7 @@ internal sealed partial class CharaDataHubUi
|
||||
|
||||
if (!_charaDataGposeTogetherManager.UsersInLobby.Any() && !string.IsNullOrEmpty(_charaDataGposeTogetherManager.CurrentGPoseLobbyId))
|
||||
{
|
||||
UiSharedService.DrawGroupedCenteredColorText("No other users in current GPose lobby", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.DrawGroupedCenteredColorText("No other users in current GPose lobby", UiSharedService.AccentColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Numerics;
|
||||
|
||||
namespace MareSynchronos.UI;
|
||||
|
||||
internal sealed partial class CharaDataHubUi
|
||||
public sealed partial class CharaDataHubUi
|
||||
{
|
||||
private void DrawEditCharaData(CharaDataFullExtendedDto? dataDto)
|
||||
{
|
||||
@@ -18,7 +18,7 @@ internal sealed partial class CharaDataHubUi
|
||||
if (dataDto == null)
|
||||
{
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Select an entry above to edit its data.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Select an entry above to edit its data.", UiSharedService.AccentColor);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ internal sealed partial class CharaDataHubUi
|
||||
|
||||
if (updateDto == null)
|
||||
{
|
||||
UiSharedService.DrawGroupedCenteredColorText("Something went awfully wrong and there's no update DTO. Try updating Character Data via the button above.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Something went awfully wrong and there's no update DTO. Try updating Character Data via the button above.", UiSharedService.AccentColor);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ internal sealed partial class CharaDataHubUi
|
||||
}
|
||||
if (_charaDataManager.CharaUpdateTask != null && !_charaDataManager.CharaUpdateTask.IsCompleted)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Updating data on server, please wait.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped("Updating data on server, please wait.", UiSharedService.AccentColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ internal sealed partial class CharaDataHubUi
|
||||
{
|
||||
if (_charaDataManager.UploadProgress != null)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(_charaDataManager.UploadProgress.Value ?? string.Empty, ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped(_charaDataManager.UploadProgress.Value ?? string.Empty, UiSharedService.AccentColor);
|
||||
}
|
||||
if ((!_charaDataManager.UploadTask?.IsCompleted ?? false) && _uiSharedService.IconTextButton(FontAwesomeIcon.Ban, "Cancel Upload"))
|
||||
{
|
||||
@@ -230,7 +230,7 @@ internal sealed partial class CharaDataHubUi
|
||||
ImGui.SameLine();
|
||||
ImGuiHelpers.ScaledDummy(20, 1);
|
||||
ImGui.SameLine();
|
||||
UiSharedService.ColorTextWrapped("New data was set. It may contain files that require to be uploaded (will happen on Saving to server)", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped("New data was set. It may contain files that require to be uploaded (will happen on Saving to server)", UiSharedService.AccentColor);
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted("Contains Manipulation Data");
|
||||
@@ -385,7 +385,7 @@ internal sealed partial class CharaDataHubUi
|
||||
}
|
||||
}
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, poseCount == maxPoses))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, UiSharedService.AccentColor, poseCount == maxPoses))
|
||||
ImGui.TextUnformatted($"{poseCount}/{maxPoses} poses attached");
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
|
||||
@@ -395,7 +395,7 @@ internal sealed partial class CharaDataHubUi
|
||||
if (!_uiSharedService.IsInGpose && _charaDataManager.BrioAvailable)
|
||||
{
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
UiSharedService.DrawGroupedCenteredColorText("To attach pose and world data you need to be in GPose.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.DrawGroupedCenteredColorText("To attach pose and world data you need to be in GPose.", UiSharedService.AccentColor);
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
}
|
||||
else if (!_charaDataManager.BrioAvailable)
|
||||
@@ -414,7 +414,7 @@ internal sealed partial class CharaDataHubUi
|
||||
if (pose.Id == null)
|
||||
{
|
||||
ImGui.SameLine(50);
|
||||
_uiSharedService.IconText(FontAwesomeIcon.Plus, ImGuiColors.DalamudYellow);
|
||||
_uiSharedService.IconText(FontAwesomeIcon.Plus, UiSharedService.AccentColor);
|
||||
UiSharedService.AttachToolTip("This pose has not been added to the server yet. Save changes to upload this Pose data.");
|
||||
}
|
||||
|
||||
@@ -422,14 +422,14 @@ internal sealed partial class CharaDataHubUi
|
||||
if (poseHasChanges)
|
||||
{
|
||||
ImGui.SameLine(50);
|
||||
_uiSharedService.IconText(FontAwesomeIcon.ExclamationTriangle, ImGuiColors.DalamudYellow);
|
||||
_uiSharedService.IconText(FontAwesomeIcon.ExclamationTriangle, UiSharedService.AccentColor);
|
||||
UiSharedService.AttachToolTip("This pose has changes that have not been saved to the server yet.");
|
||||
}
|
||||
|
||||
ImGui.SameLine(75);
|
||||
if (pose.Description == null && pose.WorldData == null && pose.PoseData == null)
|
||||
{
|
||||
UiSharedService.ColorText("Pose scheduled for deletion", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorText("Pose scheduled for deletion", UiSharedService.AccentColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -586,7 +586,7 @@ internal sealed partial class CharaDataHubUi
|
||||
var idText = entry.FullId;
|
||||
if (uDto?.HasChanges ?? false)
|
||||
{
|
||||
UiSharedService.ColorText(idText, ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorText(idText, UiSharedService.AccentColor);
|
||||
UiSharedService.AttachToolTip("This entry has unsaved changes");
|
||||
}
|
||||
else
|
||||
@@ -641,7 +641,7 @@ internal sealed partial class CharaDataHubUi
|
||||
FontAwesomeIcon eIcon = FontAwesomeIcon.None;
|
||||
if (!Equals(DateTime.MaxValue, entry.ExpiryDate))
|
||||
eIcon = FontAwesomeIcon.Clock;
|
||||
_uiSharedService.IconText(eIcon, ImGuiColors.DalamudYellow);
|
||||
_uiSharedService.IconText(eIcon, UiSharedService.AccentColor);
|
||||
if (ImGui.IsItemClicked()) SelectedDtoId = entry.Id;
|
||||
if (eIcon != FontAwesomeIcon.None)
|
||||
{
|
||||
@@ -677,13 +677,13 @@ internal sealed partial class CharaDataHubUi
|
||||
if (_charaDataManager.OwnCharaData.Count == _charaDataManager.MaxCreatableCharaData)
|
||||
{
|
||||
ImGui.AlignTextToFramePadding();
|
||||
UiSharedService.ColorTextWrapped("You have reached the maximum Character Data entries and cannot create more.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped("You have reached the maximum Character Data entries and cannot create more.", UiSharedService.AccentColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (_charaDataManager.DataCreationTask != null && !_charaDataManager.DataCreationTask.IsCompleted)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Creating new character data entry on server...", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped("Creating new character data entry on server...", UiSharedService.AccentColor);
|
||||
}
|
||||
else if (_charaDataManager.DataCreationTask != null && _charaDataManager.DataCreationTask.IsCompleted)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Numerics;
|
||||
|
||||
namespace MareSynchronos.UI;
|
||||
|
||||
internal partial class CharaDataHubUi
|
||||
public sealed partial class CharaDataHubUi
|
||||
{
|
||||
private void DrawNearbyPoses()
|
||||
{
|
||||
@@ -86,7 +86,7 @@ internal partial class CharaDataHubUi
|
||||
if (!_uiSharedService.IsInGpose)
|
||||
{
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Spawning and applying pose data is only available in GPose.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Spawning and applying pose data is only available in GPose.", UiSharedService.AccentColor);
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ internal partial class CharaDataHubUi
|
||||
using var indent = ImRaii.PushIndent(5f);
|
||||
if (_charaDataNearbyManager.NearbyData.Count == 0)
|
||||
{
|
||||
UiSharedService.DrawGroupedCenteredColorText("No Shared World Poses found nearby.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.DrawGroupedCenteredColorText("No Shared World Poses found nearby.", UiSharedService.AccentColor);
|
||||
}
|
||||
|
||||
bool wasAnythingHovered = false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
@@ -16,10 +17,13 @@ using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
using MareSynchronos.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace MareSynchronos.UI;
|
||||
|
||||
internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
public sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
private const int maxPoses = 10;
|
||||
private readonly CharaDataManager _charaDataManager;
|
||||
@@ -31,6 +35,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
private readonly CharaDataGposeTogetherManager _charaDataGposeTogetherManager;
|
||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly UiSharedService _uiSharedService;
|
||||
private readonly McdfShareManager _mcdfShareManager;
|
||||
private CancellationTokenSource? _closalCts = new();
|
||||
private bool _disableUI = false;
|
||||
private CancellationTokenSource? _disposalCts = new();
|
||||
@@ -63,6 +68,15 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static string SanitizeFileName(string? candidate, string fallback)
|
||||
{
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
if (string.IsNullOrWhiteSpace(candidate)) return fallback;
|
||||
|
||||
var sanitized = new string(candidate.Select(ch => invalidChars.Contains(ch) ? '_' : ch).ToArray()).Trim('_');
|
||||
return string.IsNullOrWhiteSpace(sanitized) ? fallback : sanitized;
|
||||
}
|
||||
private string _selectedSpecificUserIndividual = string.Empty;
|
||||
private string _selectedSpecificGroupIndividual = string.Empty;
|
||||
private string _sharedWithYouDescriptionFilter = string.Empty;
|
||||
@@ -74,12 +88,21 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
private string? _openComboHybridId = null;
|
||||
private (string Id, string? Alias, string AliasOrId, string? Note)[]? _openComboHybridEntries = null;
|
||||
private bool _comboHybridUsedLastFrame = false;
|
||||
private bool _mcdfShareInitialized;
|
||||
private string _mcdfShareDescription = string.Empty;
|
||||
private readonly List<string> _mcdfShareAllowedIndividuals = new();
|
||||
private readonly List<string> _mcdfShareAllowedSyncshells = new();
|
||||
private string _mcdfShareIndividualDropdownSelection = string.Empty;
|
||||
private string _mcdfShareIndividualInput = string.Empty;
|
||||
private string _mcdfShareSyncshellDropdownSelection = string.Empty;
|
||||
private string _mcdfShareSyncshellInput = string.Empty;
|
||||
private int _mcdfShareExpireDays;
|
||||
|
||||
public CharaDataHubUi(ILogger<CharaDataHubUi> logger, MareMediator mediator, PerformanceCollectorService performanceCollectorService,
|
||||
CharaDataManager charaDataManager, CharaDataNearbyManager charaDataNearbyManager, CharaDataConfigService configService,
|
||||
UiSharedService uiSharedService, ServerConfigurationManager serverConfigurationManager,
|
||||
DalamudUtilService dalamudUtilService, FileDialogManager fileDialogManager, PairManager pairManager,
|
||||
CharaDataGposeTogetherManager charaDataGposeTogetherManager)
|
||||
CharaDataGposeTogetherManager charaDataGposeTogetherManager, McdfShareManager mcdfShareManager)
|
||||
: base(logger, mediator, "Umbra Character Data Hub###UmbraCharaDataUI", performanceCollectorService)
|
||||
{
|
||||
SetWindowSizeConstraints();
|
||||
@@ -93,6 +116,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
_fileDialogManager = fileDialogManager;
|
||||
_pairManager = pairManager;
|
||||
_charaDataGposeTogetherManager = charaDataGposeTogetherManager;
|
||||
_mcdfShareManager = mcdfShareManager;
|
||||
Mediator.Subscribe<GposeStartMessage>(this, (_) => IsOpen |= _configService.Current.OpenMareHubOnGposeStart);
|
||||
Mediator.Subscribe<OpenCharaDataHubWithFilterMessage>(this, (msg) =>
|
||||
{
|
||||
@@ -158,6 +182,19 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
|
||||
protected override void DrawInternal()
|
||||
{
|
||||
DrawHubContent();
|
||||
}
|
||||
|
||||
public void DrawInline()
|
||||
{
|
||||
using (ImRaii.PushId("CharaDataHubInline"))
|
||||
{
|
||||
DrawHubContent();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawHubContent()
|
||||
{
|
||||
if (!_comboHybridUsedLastFrame)
|
||||
{
|
||||
@@ -198,7 +235,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
if (!string.IsNullOrEmpty(_charaDataManager.DataApplicationProgress))
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(_charaDataManager.DataApplicationProgress, ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped(_charaDataManager.DataApplicationProgress, UiSharedService.AccentColor);
|
||||
}
|
||||
if (_charaDataManager.DataApplicationTask != null)
|
||||
{
|
||||
@@ -208,115 +245,140 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
});
|
||||
|
||||
using var tabs = ImRaii.TabBar("TabsTopLevel");
|
||||
bool smallUi = false;
|
||||
|
||||
_isHandlingSelf = _charaDataManager.HandledCharaData.Any(c => c.Value.IsSelf);
|
||||
if (_isHandlingSelf) _openMcdOnlineOnNextRun = false;
|
||||
|
||||
using (var gposeTogetherTabItem = ImRaii.TabItem("GPose Together"))
|
||||
using (var topTabColor = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.AccentColor))
|
||||
using (var topTabHoverColor = ImRaii.PushColor(ImGuiCol.TabHovered, UiSharedService.AccentHoverColor))
|
||||
using (var topTabActiveColor = ImRaii.PushColor(ImGuiCol.TabActive, UiSharedService.AccentActiveColor))
|
||||
{
|
||||
if (gposeTogetherTabItem)
|
||||
using var tabs = ImRaii.TabBar("TabsTopLevel");
|
||||
|
||||
_isHandlingSelf = _charaDataManager.HandledCharaData.Any(c => c.Value.IsSelf);
|
||||
if (_isHandlingSelf) _openMcdOnlineOnNextRun = false;
|
||||
|
||||
using (var gposeTogetherTabItem = ImRaii.TabItem("GPose Together"))
|
||||
{
|
||||
smallUi = true;
|
||||
|
||||
DrawGposeTogether();
|
||||
}
|
||||
}
|
||||
|
||||
using (var applicationTabItem = ImRaii.TabItem("Data Application", _openDataApplicationShared ? ImGuiTabItemFlags.SetSelected : ImGuiTabItemFlags.None))
|
||||
{
|
||||
if (applicationTabItem)
|
||||
{
|
||||
smallUi = true;
|
||||
using var appTabs = ImRaii.TabBar("TabsApplicationLevel");
|
||||
|
||||
using (ImRaii.Disabled(!_uiSharedService.IsInGpose))
|
||||
if (gposeTogetherTabItem)
|
||||
{
|
||||
using (var gposeTabItem = ImRaii.TabItem("GPose Actors"))
|
||||
smallUi = true;
|
||||
|
||||
DrawGposeTogether();
|
||||
}
|
||||
}
|
||||
|
||||
using (var applicationTabItem = ImRaii.TabItem("Data Application", _openDataApplicationShared ? ImGuiTabItemFlags.SetSelected : ImGuiTabItemFlags.None))
|
||||
{
|
||||
if (applicationTabItem)
|
||||
{
|
||||
smallUi = true;
|
||||
using (var appTabColor = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.AccentColor))
|
||||
using (var appTabHoverColor = ImRaii.PushColor(ImGuiCol.TabHovered, UiSharedService.AccentHoverColor))
|
||||
using (var appTabActiveColor = ImRaii.PushColor(ImGuiCol.TabActive, UiSharedService.AccentActiveColor))
|
||||
{
|
||||
if (gposeTabItem)
|
||||
using var appTabs = ImRaii.TabBar("TabsApplicationLevel");
|
||||
|
||||
using (ImRaii.Disabled(!_uiSharedService.IsInGpose))
|
||||
{
|
||||
using var id = ImRaii.PushId("gposeControls");
|
||||
DrawGposeControls();
|
||||
using (var gposeTabItem = ImRaii.TabItem("GPose Actors"))
|
||||
{
|
||||
if (gposeTabItem)
|
||||
{
|
||||
using var id = ImRaii.PushId("gposeControls");
|
||||
DrawGposeControls();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!_uiSharedService.IsInGpose)
|
||||
UiSharedService.AttachToolTip("Only available in GPose");
|
||||
|
||||
using (var nearbyPosesTabItem = ImRaii.TabItem("Poses Nearby"))
|
||||
{
|
||||
if (nearbyPosesTabItem)
|
||||
{
|
||||
using var id = ImRaii.PushId("nearbyPoseControls");
|
||||
_charaDataNearbyManager.ComputeNearbyData = true;
|
||||
|
||||
DrawNearbyPoses();
|
||||
}
|
||||
else
|
||||
{
|
||||
_charaDataNearbyManager.ComputeNearbyData = false;
|
||||
}
|
||||
}
|
||||
|
||||
using (var gposeTabItem = ImRaii.TabItem("Apply Data", _openDataApplicationShared ? ImGuiTabItemFlags.SetSelected : ImGuiTabItemFlags.None))
|
||||
{
|
||||
if (gposeTabItem)
|
||||
{
|
||||
smallUi |= true;
|
||||
using var id = ImRaii.PushId("applyData");
|
||||
DrawDataApplication();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!_uiSharedService.IsInGpose)
|
||||
UiSharedService.AttachToolTip("Only available in GPose");
|
||||
|
||||
using (var nearbyPosesTabItem = ImRaii.TabItem("Poses Nearby"))
|
||||
else
|
||||
{
|
||||
if (nearbyPosesTabItem)
|
||||
{
|
||||
using var id = ImRaii.PushId("nearbyPoseControls");
|
||||
_charaDataNearbyManager.ComputeNearbyData = true;
|
||||
|
||||
DrawNearbyPoses();
|
||||
}
|
||||
else
|
||||
{
|
||||
_charaDataNearbyManager.ComputeNearbyData = false;
|
||||
}
|
||||
}
|
||||
|
||||
using (var gposeTabItem = ImRaii.TabItem("Apply Data", _openDataApplicationShared ? ImGuiTabItemFlags.SetSelected : ImGuiTabItemFlags.None))
|
||||
{
|
||||
if (gposeTabItem)
|
||||
{
|
||||
smallUi |= true;
|
||||
using var id = ImRaii.PushId("applyData");
|
||||
DrawDataApplication();
|
||||
}
|
||||
_charaDataNearbyManager.ComputeNearbyData = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_charaDataNearbyManager.ComputeNearbyData = false;
|
||||
}
|
||||
}
|
||||
|
||||
using (ImRaii.Disabled(_isHandlingSelf))
|
||||
{
|
||||
ImGuiTabItemFlags flagsTopLevel = ImGuiTabItemFlags.None;
|
||||
if (_openMcdOnlineOnNextRun)
|
||||
using (ImRaii.Disabled(_isHandlingSelf))
|
||||
{
|
||||
flagsTopLevel = ImGuiTabItemFlags.SetSelected;
|
||||
_openMcdOnlineOnNextRun = false;
|
||||
}
|
||||
|
||||
using (var creationTabItem = ImRaii.TabItem("Data Creation", flagsTopLevel))
|
||||
{
|
||||
if (creationTabItem)
|
||||
ImGuiTabItemFlags flagsTopLevel = ImGuiTabItemFlags.None;
|
||||
if (_openMcdOnlineOnNextRun)
|
||||
{
|
||||
using var creationTabs = ImRaii.TabBar("TabsCreationLevel");
|
||||
flagsTopLevel = ImGuiTabItemFlags.SetSelected;
|
||||
_openMcdOnlineOnNextRun = false;
|
||||
}
|
||||
|
||||
ImGuiTabItemFlags flags = ImGuiTabItemFlags.None;
|
||||
if (_openMcdOnlineOnNextRun)
|
||||
using (var creationTabItem = ImRaii.TabItem("Data Creation", flagsTopLevel))
|
||||
{
|
||||
if (creationTabItem)
|
||||
{
|
||||
flags = ImGuiTabItemFlags.SetSelected;
|
||||
_openMcdOnlineOnNextRun = false;
|
||||
}
|
||||
using (var mcdOnlineTabItem = ImRaii.TabItem("Online Data", flags))
|
||||
{
|
||||
if (mcdOnlineTabItem)
|
||||
using (var creationTabColor = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.AccentColor))
|
||||
using (var creationTabHoverColor = ImRaii.PushColor(ImGuiCol.TabHovered, UiSharedService.AccentHoverColor))
|
||||
using (var creationTabActiveColor = ImRaii.PushColor(ImGuiCol.TabActive, UiSharedService.AccentActiveColor))
|
||||
{
|
||||
using var id = ImRaii.PushId("mcdOnline");
|
||||
DrawMcdOnline();
|
||||
}
|
||||
}
|
||||
using var creationTabs = ImRaii.TabBar("TabsCreationLevel");
|
||||
|
||||
using (var mcdfTabItem = ImRaii.TabItem("MCDF Export"))
|
||||
{
|
||||
if (mcdfTabItem)
|
||||
{
|
||||
using var id = ImRaii.PushId("mcdfExport");
|
||||
DrawMcdfExport();
|
||||
ImGuiTabItemFlags flags = ImGuiTabItemFlags.None;
|
||||
if (_openMcdOnlineOnNextRun)
|
||||
{
|
||||
flags = ImGuiTabItemFlags.SetSelected;
|
||||
_openMcdOnlineOnNextRun = false;
|
||||
}
|
||||
using (var mcdOnlineTabItem = ImRaii.TabItem("Online Data", flags))
|
||||
{
|
||||
if (mcdOnlineTabItem)
|
||||
{
|
||||
using var id = ImRaii.PushId("mcdOnline");
|
||||
DrawMcdOnline();
|
||||
}
|
||||
}
|
||||
|
||||
using (var mcdfTabItem = ImRaii.TabItem("MCDF Export"))
|
||||
{
|
||||
if (mcdfTabItem)
|
||||
{
|
||||
using var id = ImRaii.PushId("mcdfExport");
|
||||
DrawMcdfExport();
|
||||
}
|
||||
}
|
||||
|
||||
using (var mcdfShareTabItem = ImRaii.TabItem("Partage MCDF"))
|
||||
{
|
||||
if (mcdfShareTabItem)
|
||||
{
|
||||
using var id = ImRaii.PushId("mcdfShare");
|
||||
DrawMcdfShare();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_isHandlingSelf)
|
||||
{
|
||||
UiSharedService.AttachToolTip("Cannot use creation tools while having Character Data applied to self.");
|
||||
@@ -444,14 +506,18 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
if (!_hasValidGposeTarget)
|
||||
{
|
||||
ImGuiHelpers.ScaledDummy(3);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Applying data is only available in GPose with a valid selected GPose target.", ImGuiColors.DalamudYellow, 350);
|
||||
UiSharedService.DrawGroupedCenteredColorText("Applying data is only available in GPose with a valid selected GPose target.", UiSharedService.AccentColor, 350);
|
||||
}
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
using var tabs = ImRaii.TabBar("Tabs");
|
||||
using (var applyTabColor = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.AccentColor))
|
||||
using (var applyTabHoverColor = ImRaii.PushColor(ImGuiCol.TabHovered, UiSharedService.AccentHoverColor))
|
||||
using (var applyTabActiveColor = ImRaii.PushColor(ImGuiCol.TabActive, UiSharedService.AccentActiveColor))
|
||||
{
|
||||
using var tabs = ImRaii.TabBar("Tabs");
|
||||
|
||||
using (var byFavoriteTabItem = ImRaii.TabItem("Favorites"))
|
||||
using (var byFavoriteTabItem = ImRaii.TabItem("Favorites"))
|
||||
{
|
||||
if (byFavoriteTabItem)
|
||||
{
|
||||
@@ -603,7 +669,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
|
||||
if (_configService.Current.FavoriteCodes.Count == 0)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("You have no favorites added. Add Favorites through the other tabs before you can use this tab.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped("You have no favorites added. Add Favorites through the other tabs before you can use this tab.", UiSharedService.AccentColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -652,7 +718,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
ImGui.NewLine();
|
||||
if (!_charaDataManager.DownloadMetaInfoTask?.IsCompleted ?? false)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Downloading meta info. Please wait.", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped("Downloading meta info. Please wait.", UiSharedService.AccentColor);
|
||||
}
|
||||
if ((_charaDataManager.DownloadMetaInfoTask?.IsCompleted ?? false) && !_charaDataManager.DownloadMetaInfoTask.Result.Success)
|
||||
{
|
||||
@@ -859,15 +925,16 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
UiSharedService.ColorTextWrapped("Failure to read MCDF file. MCDF file is possibly corrupt. Re-export the MCDF file and try again.",
|
||||
UiSharedService.AccentColor);
|
||||
UiSharedService.ColorTextWrapped("Note: if this is your MCDF, try redrawing yourself, wait and re-export the file. " +
|
||||
"If you received it from someone else have them do the same.", ImGuiColors.DalamudYellow);
|
||||
"If you received it from someone else have them do the same.", UiSharedService.AccentColor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Loading Character...", ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorTextWrapped("Loading Character...", UiSharedService.AccentColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMcdfExport()
|
||||
@@ -892,7 +959,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
string defaultFileName = string.IsNullOrEmpty(_exportDescription)
|
||||
? "export.mcdf"
|
||||
: string.Join('_', $"{_exportDescription}.mcdf".Split(Path.GetInvalidFileNameChars()));
|
||||
: SanitizeFileName(_exportDescription, "export") + ".mcdf";
|
||||
_uiSharedService.FileDialogManager.SaveFileDialog("Export Character to file", ".mcdf", defaultFileName, ".mcdf", (success, path) =>
|
||||
{
|
||||
if (!success) return;
|
||||
@@ -905,12 +972,418 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
||||
}, Directory.Exists(_configService.Current.LastSavedCharaDataLocation) ? _configService.Current.LastSavedCharaDataLocation : null);
|
||||
}
|
||||
UiSharedService.ColorTextWrapped("Note: For best results make sure you have everything you want to be shared as well as the correct character appearance" +
|
||||
" equipped and redraw your character before exporting.", ImGuiColors.DalamudYellow);
|
||||
" equipped and redraw your character before exporting.", UiSharedService.AccentColor);
|
||||
|
||||
ImGui.Unindent();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMcdfShare()
|
||||
{
|
||||
if (!_mcdfShareInitialized && !_mcdfShareManager.IsBusy)
|
||||
{
|
||||
_mcdfShareInitialized = true;
|
||||
_ = _mcdfShareManager.RefreshAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
if (_mcdfShareManager.IsBusy)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Traitement en cours...", ImGuiColors.DalamudYellow);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_mcdfShareManager.LastError))
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(_mcdfShareManager.LastError!, ImGuiColors.DalamudRed);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(_mcdfShareManager.LastSuccess))
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(_mcdfShareManager.LastSuccess!, ImGuiColors.HealerGreen);
|
||||
}
|
||||
|
||||
if (ImGui.Button("Actualiser les partages"))
|
||||
{
|
||||
_ = _mcdfShareManager.RefreshAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
_uiSharedService.BigText("Créer un partage MCDF");
|
||||
|
||||
ImGui.InputTextWithHint("##mcdfShareDescription", "Description", ref _mcdfShareDescription, 128);
|
||||
ImGui.InputInt("Expiration (jours, 0 = jamais)", ref _mcdfShareExpireDays);
|
||||
|
||||
DrawMcdfShareIndividualDropdown();
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(220f);
|
||||
if (ImGui.InputTextWithHint("##mcdfShareUidInput", "UID ou vanity", ref _mcdfShareIndividualInput, 32))
|
||||
{
|
||||
_mcdfShareIndividualDropdownSelection = string.Empty;
|
||||
}
|
||||
ImGui.SameLine();
|
||||
var normalizedUid = NormalizeUidCandidate(_mcdfShareIndividualInput);
|
||||
using (ImRaii.Disabled(string.IsNullOrEmpty(normalizedUid)
|
||||
|| _mcdfShareAllowedIndividuals.Any(p => string.Equals(p, normalizedUid, StringComparison.OrdinalIgnoreCase))))
|
||||
{
|
||||
if (ImGui.SmallButton("Ajouter"))
|
||||
{
|
||||
_mcdfShareAllowedIndividuals.Add(normalizedUid);
|
||||
_mcdfShareIndividualInput = string.Empty;
|
||||
_mcdfShareIndividualDropdownSelection = string.Empty;
|
||||
}
|
||||
}
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("UID synchronisé à ajouter");
|
||||
_uiSharedService.DrawHelpText("Choisissez un pair synchronisé dans la liste ou saisissez un UID. Les utilisateurs listés pourront récupérer ce partage MCDF.");
|
||||
|
||||
foreach (var uid in _mcdfShareAllowedIndividuals.ToArray())
|
||||
{
|
||||
using (ImRaii.PushId("mcdfShareUid" + uid))
|
||||
{
|
||||
ImGui.BulletText(FormatPairLabel(uid));
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Retirer"))
|
||||
{
|
||||
_mcdfShareAllowedIndividuals.Remove(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawMcdfShareSyncshellDropdown();
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(220f);
|
||||
if (ImGui.InputTextWithHint("##mcdfShareSyncshellInput", "GID ou alias", ref _mcdfShareSyncshellInput, 32))
|
||||
{
|
||||
_mcdfShareSyncshellDropdownSelection = string.Empty;
|
||||
}
|
||||
ImGui.SameLine();
|
||||
var normalizedSyncshell = NormalizeSyncshellCandidate(_mcdfShareSyncshellInput);
|
||||
using (ImRaii.Disabled(string.IsNullOrEmpty(normalizedSyncshell)
|
||||
|| _mcdfShareAllowedSyncshells.Any(p => string.Equals(p, normalizedSyncshell, StringComparison.OrdinalIgnoreCase))))
|
||||
{
|
||||
if (ImGui.SmallButton("Ajouter"))
|
||||
{
|
||||
_mcdfShareAllowedSyncshells.Add(normalizedSyncshell);
|
||||
_mcdfShareSyncshellInput = string.Empty;
|
||||
_mcdfShareSyncshellDropdownSelection = string.Empty;
|
||||
}
|
||||
}
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("Syncshell à ajouter");
|
||||
_uiSharedService.DrawHelpText("Sélectionnez une syncshell synchronisée ou saisissez un identifiant. Les syncshells listées auront accès au partage.");
|
||||
|
||||
foreach (var shell in _mcdfShareAllowedSyncshells.ToArray())
|
||||
{
|
||||
using (ImRaii.PushId("mcdfShareShell" + shell))
|
||||
{
|
||||
ImGui.BulletText(FormatSyncshellLabel(shell));
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Retirer"))
|
||||
{
|
||||
_mcdfShareAllowedSyncshells.Remove(shell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (ImRaii.Disabled(_mcdfShareManager.IsBusy))
|
||||
{
|
||||
if (ImGui.Button("Créer"))
|
||||
{
|
||||
DateTime? expiresAt = _mcdfShareExpireDays <= 0 ? null : DateTime.UtcNow.AddDays(_mcdfShareExpireDays);
|
||||
_ = _mcdfShareManager.CreateShareAsync(_mcdfShareDescription, _mcdfShareAllowedIndividuals.ToList(), _mcdfShareAllowedSyncshells.ToList(), expiresAt, CancellationToken.None);
|
||||
_mcdfShareDescription = string.Empty;
|
||||
_mcdfShareAllowedIndividuals.Clear();
|
||||
_mcdfShareAllowedSyncshells.Clear();
|
||||
_mcdfShareIndividualInput = string.Empty;
|
||||
_mcdfShareIndividualDropdownSelection = string.Empty;
|
||||
_mcdfShareSyncshellInput = string.Empty;
|
||||
_mcdfShareSyncshellDropdownSelection = string.Empty;
|
||||
_mcdfShareExpireDays = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
_uiSharedService.BigText("Mes partages : ");
|
||||
|
||||
if (_mcdfShareManager.OwnShares.Count == 0)
|
||||
{
|
||||
ImGui.TextDisabled("Aucun partage MCDF créé.");
|
||||
}
|
||||
else if (ImGui.BeginTable("mcdf-own-shares", 6, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersOuter))
|
||||
{
|
||||
ImGui.TableSetupColumn("Description");
|
||||
ImGui.TableSetupColumn("Créé le");
|
||||
ImGui.TableSetupColumn("Expire");
|
||||
ImGui.TableSetupColumn("Téléchargements");
|
||||
ImGui.TableSetupColumn("Accès");
|
||||
ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 220f);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
foreach (var entry in _mcdfShareManager.OwnShares)
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(string.IsNullOrEmpty(entry.Description) ? entry.Id.ToString() : entry.Description);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(entry.CreatedUtc.ToLocalTime().ToString("g"));
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(entry.ExpiresAtUtc.HasValue ? entry.ExpiresAtUtc.Value.ToLocalTime().ToString("g") : "Jamais");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(entry.DownloadCount.ToString());
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted($"UID : {entry.AllowedIndividuals.Count}, Syncshells : {entry.AllowedSyncshells.Count}");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.PushId("ownShare" + entry.Id))
|
||||
{
|
||||
if (ImGui.SmallButton("Appliquer en GPose"))
|
||||
{
|
||||
_ = _mcdfShareManager.ApplyShareAsync(entry.Id, CancellationToken.None);
|
||||
}
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Enregistrer"))
|
||||
{
|
||||
var baseName = SanitizeFileName(entry.Description, entry.Id.ToString());
|
||||
var defaultName = baseName + ".mcdf";
|
||||
_fileDialogManager.SaveFileDialog("Enregistrer le partage MCDF", ".mcdf", defaultName, ".mcdf", async (success, path) =>
|
||||
{
|
||||
if (!success || string.IsNullOrEmpty(path)) return;
|
||||
await _mcdfShareManager.ExportShareAsync(entry.Id, path, CancellationToken.None).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Supprimer"))
|
||||
{
|
||||
_ = _mcdfShareManager.DeleteShareAsync(entry.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
_uiSharedService.BigText("Partagés avec moi : ");
|
||||
|
||||
if (_mcdfShareManager.SharedShares.Count == 0)
|
||||
{
|
||||
ImGui.TextDisabled("Aucun partage MCDF reçu.");
|
||||
}
|
||||
else if (ImGui.BeginTable("mcdf-shared-shares", 5, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersOuter))
|
||||
{
|
||||
ImGui.TableSetupColumn("Description");
|
||||
ImGui.TableSetupColumn("Propriétaire");
|
||||
ImGui.TableSetupColumn("Expire");
|
||||
ImGui.TableSetupColumn("Téléchargements");
|
||||
ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 180f);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
foreach (var entry in _mcdfShareManager.SharedShares)
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(string.IsNullOrEmpty(entry.Description) ? entry.Id.ToString() : entry.Description);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(string.IsNullOrEmpty(entry.OwnerAlias) ? entry.OwnerUid : entry.OwnerAlias);
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(entry.ExpiresAtUtc.HasValue ? entry.ExpiresAtUtc.Value.ToLocalTime().ToString("g") : "Jamais");
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.TextUnformatted(entry.DownloadCount.ToString());
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.PushId("sharedShare" + entry.Id))
|
||||
{
|
||||
if (ImGui.SmallButton("Appliquer"))
|
||||
{
|
||||
_ = _mcdfShareManager.ApplyShareAsync(entry.Id, CancellationToken.None);
|
||||
}
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Enregistrer"))
|
||||
{
|
||||
var baseName = SanitizeFileName(entry.Description, entry.Id.ToString());
|
||||
var defaultName = baseName + ".mcdf";
|
||||
_fileDialogManager.SaveFileDialog("Enregistrer le partage MCDF", ".mcdf", defaultName, ".mcdf", async (success, path) =>
|
||||
{
|
||||
if (!success || string.IsNullOrEmpty(path)) return;
|
||||
await _mcdfShareManager.ExportShareAsync(entry.Id, path, CancellationToken.None).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMcdfShareIndividualDropdown()
|
||||
{
|
||||
ImGui.SetNextItemWidth(220f);
|
||||
var previewSource = string.IsNullOrEmpty(_mcdfShareIndividualDropdownSelection)
|
||||
? _mcdfShareIndividualInput
|
||||
: _mcdfShareIndividualDropdownSelection;
|
||||
var previewLabel = string.IsNullOrEmpty(previewSource)
|
||||
? "Sélectionner un pair synchronisé..."
|
||||
: FormatPairLabel(previewSource);
|
||||
|
||||
using var combo = ImRaii.Combo("##mcdfShareUidDropdown", previewLabel, ImGuiComboFlags.None);
|
||||
if (!combo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var pair in _pairManager.DirectPairs
|
||||
.OrderBy(p => p.GetNoteOrName() ?? p.UserData.AliasOrUID, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
var normalized = pair.UserData.UID;
|
||||
var display = FormatPairLabel(normalized);
|
||||
bool selected = string.Equals(normalized, _mcdfShareIndividualDropdownSelection, StringComparison.OrdinalIgnoreCase);
|
||||
if (ImGui.Selectable(display, selected))
|
||||
{
|
||||
_mcdfShareIndividualDropdownSelection = normalized;
|
||||
_mcdfShareIndividualInput = normalized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMcdfShareSyncshellDropdown()
|
||||
{
|
||||
ImGui.SetNextItemWidth(220f);
|
||||
var previewSource = string.IsNullOrEmpty(_mcdfShareSyncshellDropdownSelection)
|
||||
? _mcdfShareSyncshellInput
|
||||
: _mcdfShareSyncshellDropdownSelection;
|
||||
var previewLabel = string.IsNullOrEmpty(previewSource)
|
||||
? "Sélectionner une syncshell..."
|
||||
: FormatSyncshellLabel(previewSource);
|
||||
|
||||
using var combo = ImRaii.Combo("##mcdfShareSyncshellDropdown", previewLabel, ImGuiComboFlags.None);
|
||||
if (!combo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var group in _pairManager.Groups.Values
|
||||
.OrderBy(g => _serverConfigurationManager.GetNoteForGid(g.GID) ?? g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
var gid = group.GID;
|
||||
var display = FormatSyncshellLabel(gid);
|
||||
bool selected = string.Equals(gid, _mcdfShareSyncshellDropdownSelection, StringComparison.OrdinalIgnoreCase);
|
||||
if (ImGui.Selectable(display, selected))
|
||||
{
|
||||
_mcdfShareSyncshellDropdownSelection = gid;
|
||||
_mcdfShareSyncshellInput = gid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string NormalizeUidCandidate(string candidate)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(candidate))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var trimmed = candidate.Trim();
|
||||
|
||||
foreach (var pair in _pairManager.DirectPairs)
|
||||
{
|
||||
var alias = pair.UserData.Alias;
|
||||
var aliasOrUid = pair.UserData.AliasOrUID;
|
||||
var note = pair.GetNoteOrName();
|
||||
|
||||
if (string.Equals(pair.UserData.UID, trimmed, StringComparison.OrdinalIgnoreCase)
|
||||
|| (!string.IsNullOrEmpty(alias) && string.Equals(alias, trimmed, StringComparison.OrdinalIgnoreCase))
|
||||
|| string.Equals(aliasOrUid, trimmed, StringComparison.OrdinalIgnoreCase)
|
||||
|| (!string.IsNullOrEmpty(note) && string.Equals(note, trimmed, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return pair.UserData.UID;
|
||||
}
|
||||
}
|
||||
|
||||
return trimmed.ToUpperInvariant();
|
||||
}
|
||||
|
||||
private string NormalizeSyncshellCandidate(string candidate)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(candidate))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var trimmed = candidate.Trim();
|
||||
|
||||
foreach (var group in _pairManager.Groups.Values)
|
||||
{
|
||||
var alias = group.GroupAlias;
|
||||
var aliasOrGid = group.GroupAliasOrGID;
|
||||
var note = _serverConfigurationManager.GetNoteForGid(group.GID);
|
||||
|
||||
if (string.Equals(group.GID, trimmed, StringComparison.OrdinalIgnoreCase)
|
||||
|| (!string.IsNullOrEmpty(alias) && string.Equals(alias, trimmed, StringComparison.OrdinalIgnoreCase))
|
||||
|| string.Equals(aliasOrGid, trimmed, StringComparison.OrdinalIgnoreCase)
|
||||
|| (!string.IsNullOrEmpty(note) && string.Equals(note, trimmed, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return group.GID;
|
||||
}
|
||||
}
|
||||
|
||||
return trimmed.ToUpperInvariant();
|
||||
}
|
||||
|
||||
private string FormatPairLabel(string candidate)
|
||||
{
|
||||
if (string.IsNullOrEmpty(candidate))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
foreach (var pair in _pairManager.DirectPairs)
|
||||
{
|
||||
var alias = pair.UserData.Alias;
|
||||
var aliasOrUid = pair.UserData.AliasOrUID;
|
||||
var note = pair.GetNoteOrName();
|
||||
|
||||
if (string.Equals(pair.UserData.UID, candidate, StringComparison.OrdinalIgnoreCase)
|
||||
|| (!string.IsNullOrEmpty(alias) && string.Equals(alias, candidate, StringComparison.OrdinalIgnoreCase))
|
||||
|| string.Equals(aliasOrUid, candidate, StringComparison.OrdinalIgnoreCase)
|
||||
|| (!string.IsNullOrEmpty(note) && string.Equals(note, candidate, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return string.IsNullOrEmpty(note) ? aliasOrUid : $"{note} ({aliasOrUid})";
|
||||
}
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private string FormatSyncshellLabel(string candidate)
|
||||
{
|
||||
if (string.IsNullOrEmpty(candidate))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
foreach (var group in _pairManager.Groups.Values)
|
||||
{
|
||||
var alias = group.GroupAlias;
|
||||
var aliasOrGid = group.GroupAliasOrGID;
|
||||
var note = _serverConfigurationManager.GetNoteForGid(group.GID);
|
||||
|
||||
if (string.Equals(group.GID, candidate, StringComparison.OrdinalIgnoreCase)
|
||||
|| (!string.IsNullOrEmpty(alias) && string.Equals(alias, candidate, StringComparison.OrdinalIgnoreCase))
|
||||
|| string.Equals(aliasOrGid, candidate, StringComparison.OrdinalIgnoreCase)
|
||||
|| (!string.IsNullOrEmpty(note) && string.Equals(note, candidate, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return string.IsNullOrEmpty(note) ? aliasOrGid : $"{note} ({aliasOrGid})";
|
||||
}
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private void DrawMetaInfoData(string selectedGposeActor, bool hasValidGposeTarget, CharaDataMetaInfoExtendedDto data, bool canOpen = false)
|
||||
{
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
|
||||
@@ -14,6 +14,7 @@ using MareSynchronos.Services;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.Services.ServerConfiguration;
|
||||
using MareSynchronos.Services.AutoDetect;
|
||||
using MareSynchronos.Services.Notifications;
|
||||
using MareSynchronos.UI.Components;
|
||||
using MareSynchronos.UI.Handlers;
|
||||
using MareSynchronos.WebAPI;
|
||||
@@ -28,6 +29,7 @@ using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace MareSynchronos.UI;
|
||||
@@ -57,6 +59,8 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
private readonly SettingsUi _settingsUi;
|
||||
private readonly AutoDetectUi _autoDetectUi;
|
||||
private readonly DataAnalysisUi _dataAnalysisUi;
|
||||
private readonly CharaDataHubUi _charaDataHubUi;
|
||||
private readonly NotificationTracker _notificationTracker;
|
||||
private bool _buttonState;
|
||||
private string _characterOrCommentFilter = string.Empty;
|
||||
private Pair? _lastAddedUser;
|
||||
@@ -71,6 +75,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
private bool _visibleOpen = true;
|
||||
private bool _selfAnalysisOpen = false;
|
||||
private List<Services.Mediator.NearbyEntry> _nearbyEntries = new();
|
||||
private int _notificationCount;
|
||||
private const long SelfAnalysisSizeWarningThreshold = 300L * 1024 * 1024;
|
||||
private const long SelfAnalysisTriangleWarningThreshold = 150_000;
|
||||
private CompactUiSection _activeSection = CompactUiSection.VisiblePairs;
|
||||
@@ -84,6 +89,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
private enum CompactUiSection
|
||||
{
|
||||
VisiblePairs,
|
||||
Notifications,
|
||||
IndividualPairs,
|
||||
Syncshells,
|
||||
AutoDetect,
|
||||
@@ -108,7 +114,9 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
EditProfileUi editProfileUi,
|
||||
SettingsUi settingsUi,
|
||||
AutoDetectUi autoDetectUi,
|
||||
DataAnalysisUi dataAnalysisUi)
|
||||
DataAnalysisUi dataAnalysisUi,
|
||||
CharaDataHubUi charaDataHubUi,
|
||||
NotificationTracker notificationTracker)
|
||||
: base(logger, mediator, "###UmbraSyncMainUI", performanceCollectorService)
|
||||
{
|
||||
_uiSharedService = uiShared;
|
||||
@@ -126,6 +134,8 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
_settingsUi = settingsUi;
|
||||
_autoDetectUi = autoDetectUi;
|
||||
_dataAnalysisUi = dataAnalysisUi;
|
||||
_charaDataHubUi = charaDataHubUi;
|
||||
_notificationTracker = notificationTracker;
|
||||
var tagHandler = new TagHandler(_serverManager);
|
||||
|
||||
_groupPanel = new(this, uiShared, _pairManager, chatService, uidDisplayHandler, _serverManager, _charaDataManager, _autoDetectRequestService);
|
||||
@@ -162,6 +172,8 @@ public class CompactUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
}
|
||||
});
|
||||
Mediator.Subscribe<NotificationStateChanged>(this, msg => _notificationCount = msg.TotalCount);
|
||||
_notificationCount = _notificationTracker.Count;
|
||||
|
||||
Flags |= ImGuiWindowFlags.NoDocking;
|
||||
|
||||
@@ -706,7 +718,7 @@ if (showNearby && pendingInvites > 0)
|
||||
|
||||
if (!showVisibleCard && !showNearbyCard)
|
||||
{
|
||||
const string calmMessage = "C'est bien trop calme ici... Il n'y a rien pour le moment.";
|
||||
const string calmMessage = "C'est bien trop calme ici... Il n'y a personne pour le moment.";
|
||||
using (_uiSharedService.UidFont.Push())
|
||||
{
|
||||
var regionMin = ImGui.GetWindowContentRegionMin();
|
||||
@@ -898,6 +910,8 @@ if (showNearby && pendingInvites > 0)
|
||||
ImGuiHelpers.ScaledDummy(6f);
|
||||
DrawConnectionIcon();
|
||||
ImGuiHelpers.ScaledDummy(12f);
|
||||
DrawSidebarButton(FontAwesomeIcon.Bell, "Notifications", CompactUiSection.Notifications, true, _notificationCount > 0, _notificationCount, null, ImGuiColors.DalamudOrange);
|
||||
ImGuiHelpers.ScaledDummy(3f);
|
||||
|
||||
DrawSidebarButton(FontAwesomeIcon.Eye, "Visible pairs", CompactUiSection.VisiblePairs, isConnected);
|
||||
ImGuiHelpers.ScaledDummy(3f);
|
||||
@@ -912,15 +926,9 @@ if (showNearby && pendingInvites > 0)
|
||||
: "AutoDetect";
|
||||
DrawSidebarButton(FontAwesomeIcon.BroadcastTower, autoDetectTooltip, CompactUiSection.AutoDetect, isConnected, highlightAutoDetect, pendingInvites);
|
||||
ImGuiHelpers.ScaledDummy(3f);
|
||||
DrawSidebarButton(FontAwesomeIcon.PersonCircleQuestion, "Character Analysis", CompactUiSection.CharacterAnalysis, isConnected, _dataAnalysisUi.IsOpen, 0, () =>
|
||||
{
|
||||
Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
|
||||
});
|
||||
DrawSidebarButton(FontAwesomeIcon.PersonCircleQuestion, "Character Analysis", CompactUiSection.CharacterAnalysis, isConnected);
|
||||
ImGuiHelpers.ScaledDummy(3f);
|
||||
DrawSidebarButton(FontAwesomeIcon.Running, "Character Data Hub", CompactUiSection.CharacterDataHub, isConnected, false, 0, () =>
|
||||
{
|
||||
Mediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi)));
|
||||
});
|
||||
DrawSidebarButton(FontAwesomeIcon.Running, "Character Data Hub", CompactUiSection.CharacterDataHub, isConnected);
|
||||
ImGuiHelpers.ScaledDummy(12f);
|
||||
DrawSidebarButton(FontAwesomeIcon.UserCircle, "Edit Profile", CompactUiSection.EditProfile, isConnected);
|
||||
ImGuiHelpers.ScaledDummy(3f);
|
||||
@@ -930,7 +938,7 @@ if (showNearby && pendingInvites > 0)
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawSidebarButton(FontAwesomeIcon icon, string tooltip, CompactUiSection section, bool enabled = true, bool highlight = false, int badgeCount = 0, Action? onClick = null)
|
||||
private void DrawSidebarButton(FontAwesomeIcon icon, string tooltip, CompactUiSection section, bool enabled = true, bool highlight = false, int badgeCount = 0, Action? onClick = null, Vector4? highlightColor = null)
|
||||
{
|
||||
using var id = ImRaii.PushId((int)section);
|
||||
float regionWidth = ImGui.GetContentRegionAvail().X;
|
||||
@@ -940,7 +948,7 @@ if (showNearby && pendingInvites > 0)
|
||||
|
||||
bool isActive = _activeSection == section;
|
||||
|
||||
if (DrawSidebarSquareButton(icon, isActive, highlight, enabled, badgeCount))
|
||||
if (DrawSidebarSquareButton(icon, isActive, highlight, enabled, badgeCount, highlightColor))
|
||||
{
|
||||
if (onClick != null)
|
||||
{
|
||||
@@ -970,7 +978,7 @@ if (showNearby && pendingInvites > 0)
|
||||
|
||||
bool isTogglingDisabled = !hasServer || state is ServerState.Reconnecting or ServerState.Disconnecting;
|
||||
|
||||
if (DrawSidebarSquareButton(icon, isLinked, false, !isTogglingDisabled, 0) && !isTogglingDisabled)
|
||||
if (DrawSidebarSquareButton(icon, isLinked, false, !isTogglingDisabled, 0, null) && !isTogglingDisabled)
|
||||
{
|
||||
ToggleConnection();
|
||||
}
|
||||
@@ -988,7 +996,7 @@ if (showNearby && pendingInvites > 0)
|
||||
}
|
||||
}
|
||||
|
||||
private bool DrawSidebarSquareButton(FontAwesomeIcon icon, bool isActive, bool highlight, bool enabled, int badgeCount)
|
||||
private bool DrawSidebarSquareButton(FontAwesomeIcon icon, bool isActive, bool highlight, bool enabled, int badgeCount, Vector4? highlightColor)
|
||||
{
|
||||
float size = SidebarIconSize * ImGuiHelpers.GlobalScale;
|
||||
|
||||
@@ -1021,9 +1029,14 @@ if (showNearby && pendingInvites > 0)
|
||||
start.Y + (size - iconSize.Y) / 2f);
|
||||
uint iconColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.85f, 0.85f, 0.9f, 1f));
|
||||
if (highlight)
|
||||
iconColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.45f, 0.85f, 0.45f, 1f));
|
||||
{
|
||||
var color = highlightColor ?? new Vector4(0.45f, 0.85f, 0.45f, 1f);
|
||||
iconColor = ImGui.ColorConvertFloat4ToU32(color);
|
||||
}
|
||||
else if (isActive)
|
||||
{
|
||||
iconColor = ImGui.GetColorU32(ImGuiCol.Text);
|
||||
}
|
||||
ImGui.GetWindowDrawList().AddText(textPos, iconColor, iconText);
|
||||
}
|
||||
|
||||
@@ -1093,6 +1106,9 @@ if (showNearby && pendingInvites > 0)
|
||||
case CompactUiSection.VisiblePairs:
|
||||
DrawPairSection(PairContentMode.VisibleOnly);
|
||||
break;
|
||||
case CompactUiSection.Notifications:
|
||||
DrawNotificationsSection();
|
||||
break;
|
||||
case CompactUiSection.IndividualPairs:
|
||||
DrawPairSection(PairContentMode.All);
|
||||
break;
|
||||
@@ -1102,6 +1118,14 @@ if (showNearby && pendingInvites > 0)
|
||||
case CompactUiSection.AutoDetect:
|
||||
DrawAutoDetectSection();
|
||||
break;
|
||||
case CompactUiSection.CharacterAnalysis:
|
||||
if (_dataAnalysisUi.IsOpen) _dataAnalysisUi.IsOpen = false;
|
||||
_dataAnalysisUi.DrawInline();
|
||||
break;
|
||||
case CompactUiSection.CharacterDataHub:
|
||||
if (_charaDataHubUi.IsOpen) _charaDataHubUi.IsOpen = false;
|
||||
_charaDataHubUi.DrawInline();
|
||||
break;
|
||||
}
|
||||
|
||||
DrawNewUserNoteModal();
|
||||
@@ -1133,6 +1157,98 @@ if (showNearby && pendingInvites > 0)
|
||||
using (ImRaii.PushId("autodetect-inline")) _autoDetectUi.DrawInline();
|
||||
}
|
||||
|
||||
private void DrawNotificationsSection()
|
||||
{
|
||||
var notifications = _notificationTracker.GetEntries();
|
||||
if (notifications.Count == 0)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Aucune notification en attente.", ImGuiColors.DalamudGrey3);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var notification in notifications.OrderByDescending(n => n.CreatedAt))
|
||||
{
|
||||
switch (notification.Category)
|
||||
{
|
||||
case NotificationCategory.AutoDetect:
|
||||
DrawAutoDetectNotification(notification);
|
||||
break;
|
||||
default:
|
||||
UiSharedService.DrawCard($"notification-{notification.Category}-{notification.Id}", () =>
|
||||
{
|
||||
ImGui.TextUnformatted(notification.Title);
|
||||
if (!string.IsNullOrEmpty(notification.Description))
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3);
|
||||
ImGui.TextUnformatted(notification.Description);
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
}, stretchWidth: true);
|
||||
break;
|
||||
}
|
||||
|
||||
ImGuiHelpers.ScaledDummy(4f);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAutoDetectNotification(NotificationEntry notification)
|
||||
{
|
||||
UiSharedService.DrawCard($"notification-autodetect-{notification.Id}", () =>
|
||||
{
|
||||
var label = _nearbyPending.Pending.TryGetValue(notification.Id, out var displayName)
|
||||
? displayName
|
||||
: notification.Title;
|
||||
|
||||
ImGui.TextUnformatted(label);
|
||||
if (!string.IsNullOrEmpty(notification.Description))
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3);
|
||||
ImGui.TextWrapped(notification.Description);
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
ImGuiHelpers.ScaledDummy(3f);
|
||||
|
||||
bool hasPending = _nearbyPending.Pending.ContainsKey(notification.Id);
|
||||
using (ImRaii.PushId(notification.Id))
|
||||
{
|
||||
using (ImRaii.Disabled(!hasPending))
|
||||
{
|
||||
if (ImGui.Button("Accepter"))
|
||||
{
|
||||
TriggerAcceptAutoDetectNotification(notification.Id);
|
||||
}
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Refuser"))
|
||||
{
|
||||
_nearbyPending.Remove(notification.Id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPending)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Effacer"))
|
||||
{
|
||||
_notificationTracker.Remove(NotificationCategory.AutoDetect, notification.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, stretchWidth: true);
|
||||
}
|
||||
|
||||
private void TriggerAcceptAutoDetectNotification(string uid)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
bool accepted = await _nearbyPending.AcceptAsync(uid).ConfigureAwait(false);
|
||||
if (!accepted)
|
||||
{
|
||||
Mediator.Publish(new NotificationMessage("AutoDetect", $"Impossible d'accepter l'invitation {uid}.", NotificationType.Warning, TimeSpan.FromSeconds(5)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawNewUserNoteModal()
|
||||
{
|
||||
if (_configService.Current.OpenPopupOnAdd && _pairManager.LastAddedUser != null)
|
||||
@@ -1171,9 +1287,12 @@ if (showNearby && pendingInvites > 0)
|
||||
private static bool RequiresServerConnection(CompactUiSection section)
|
||||
{
|
||||
return section is CompactUiSection.VisiblePairs
|
||||
or CompactUiSection.Notifications
|
||||
or CompactUiSection.IndividualPairs
|
||||
or CompactUiSection.Syncshells
|
||||
or CompactUiSection.AutoDetect;
|
||||
or CompactUiSection.AutoDetect
|
||||
or CompactUiSection.CharacterAnalysis
|
||||
or CompactUiSection.CharacterDataHub;
|
||||
}
|
||||
|
||||
private bool IsAlreadyPairedQuickMenu(Services.Mediator.NearbyEntry entry)
|
||||
@@ -1288,37 +1407,61 @@ if (showNearby && pendingInvites > 0)
|
||||
|
||||
var originalPos = ImGui.GetCursorPos();
|
||||
UiSharedService.SetFontScale(1.5f);
|
||||
Vector2 buttonSize = Vector2.Zero;
|
||||
float spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||
|
||||
if (_apiController.ServerState is ServerState.Connected)
|
||||
{
|
||||
buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Copy);
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
|
||||
ImGui.SetCursorPosY(originalPos.Y + uidTextSize.Y / 2f - buttonSize.Y / 2f);
|
||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Copy))
|
||||
{
|
||||
ImGui.SetClipboardText(_apiController.DisplayName);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Copy your UID to clipboard");
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.SetCursorPos(originalPos);
|
||||
UiSharedService.SetFontScale(1f);
|
||||
|
||||
float referenceHeight = buttonSize.Y > 0f ? buttonSize.Y : ImGui.GetFrameHeight();
|
||||
ImGui.SetCursorPosY(originalPos.Y + referenceHeight / 2f - uidTextSize.Y / 2f - spacingX / 2f);
|
||||
float contentMin = ImGui.GetWindowContentRegionMin().X;
|
||||
float contentMax = ImGui.GetWindowContentRegionMax().X;
|
||||
float availableWidth = contentMax - contentMin;
|
||||
float center = contentMin + availableWidth / 2f;
|
||||
ImGui.SetCursorPosX(center - uidTextSize.X / 2f);
|
||||
|
||||
bool isConnected = _apiController.ServerState is ServerState.Connected;
|
||||
float buttonSize = 18f * ImGuiHelpers.GlobalScale;
|
||||
float textPosY = originalPos.Y + MathF.Max(buttonSize, uidTextSize.Y) / 2f - uidTextSize.Y / 2f;
|
||||
float textPosX = center - uidTextSize.X / 2f;
|
||||
|
||||
if (isConnected)
|
||||
{
|
||||
float buttonX = textPosX - spacingX - buttonSize;
|
||||
float buttonVerticalOffset = 7f * ImGuiHelpers.GlobalScale;
|
||||
float buttonY = textPosY + uidTextSize.Y - buttonSize + buttonVerticalOffset;
|
||||
ImGui.SetCursorPos(new Vector2(buttonX, buttonY));
|
||||
if (ImGui.Button("##copy", new Vector2(buttonSize, buttonSize)))
|
||||
{
|
||||
ImGui.SetClipboardText(_apiController.DisplayName);
|
||||
}
|
||||
var buttonMin = ImGui.GetItemRectMin();
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
using (_uiSharedService.IconFont.Push())
|
||||
{
|
||||
string iconText = FontAwesomeIcon.Copy.ToIconString();
|
||||
var baseSize = ImGui.CalcTextSize(iconText);
|
||||
float maxDimension = MathF.Max(MathF.Max(baseSize.X, baseSize.Y), 1f);
|
||||
float available = buttonSize - 4f;
|
||||
float scale = MathF.Min(1f, available / maxDimension);
|
||||
float iconWidth = baseSize.X * scale;
|
||||
float iconHeight = baseSize.Y * scale;
|
||||
var iconPos = new Vector2(
|
||||
buttonMin.X + (buttonSize - iconWidth) / 2f,
|
||||
buttonMin.Y + (buttonSize - iconHeight) / 2f);
|
||||
var font = ImGui.GetFont();
|
||||
float fontSize = ImGui.GetFontSize() * scale;
|
||||
drawList.AddText(font, fontSize, iconPos, ImGui.GetColorU32(ImGuiCol.Text), iconText);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Copy your UID to clipboard");
|
||||
ImGui.SameLine(0f, spacingX);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.SetCursorPos(originalPos);
|
||||
}
|
||||
|
||||
ImGui.SetCursorPos(new Vector2(textPosX, textPosY));
|
||||
|
||||
using (_uiSharedService.UidFont.Push())
|
||||
ImGui.TextColored(GetUidColor(), uidText);
|
||||
|
||||
if (_apiController.ServerState is not ServerState.Connected)
|
||||
UiSharedService.SetFontScale(1f);
|
||||
|
||||
if (!isConnected)
|
||||
UiSharedService.ColorTextWrapped(GetServerError(), GetUidColor());
|
||||
{
|
||||
if (_apiController.ServerState is ServerState.NoSecretKey)
|
||||
|
||||
@@ -65,6 +65,19 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
|
||||
protected override void DrawInternal()
|
||||
{
|
||||
DrawAnalysisContent();
|
||||
}
|
||||
|
||||
public void DrawInline()
|
||||
{
|
||||
using (ImRaii.PushId("CharacterAnalysisInline"))
|
||||
{
|
||||
DrawAnalysisContent();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAnalysisContent()
|
||||
{
|
||||
if (_conversionTask != null && !_conversionTask.IsCompleted)
|
||||
{
|
||||
@@ -116,7 +129,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
||||
if (isAnalyzing)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped($"Analyzing {_characterAnalyzer.CurrentFile}/{_characterAnalyzer.TotalFiles}",
|
||||
ImGuiColors.DalamudYellow);
|
||||
UiSharedService.AccentColor);
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel analysis"))
|
||||
{
|
||||
_characterAnalyzer.CancelAnalyze();
|
||||
@@ -127,7 +140,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
||||
if (needAnalysis)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Some entries in the analysis have file size not determined yet, press the button below to analyze your current data",
|
||||
ImGuiColors.DalamudYellow);
|
||||
UiSharedService.AccentColor);
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start analysis (missing entries)"))
|
||||
{
|
||||
_ = _characterAnalyzer.ComputeAnalysis(print: false);
|
||||
@@ -166,7 +179,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.OriginalSize))));
|
||||
ImGui.TextUnformatted("Total size (download size):");
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, needAnalysis))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, UiSharedService.AccentColor, needAnalysis))
|
||||
{
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.CompressedSize))));
|
||||
if (needAnalysis && !isAnalyzing)
|
||||
@@ -180,140 +193,149 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
||||
ImGui.TextUnformatted($"Total modded model triangles: {UiSharedService.TrisToString(_cachedAnalysis.Sum(c => c.Value.Sum(f => f.Value.Triangles)))}");
|
||||
ImGui.Separator();
|
||||
|
||||
using var tabbar = ImRaii.TabBar("objectSelection");
|
||||
foreach (var kvp in _cachedAnalysis)
|
||||
{
|
||||
using var id = ImRaii.PushId(kvp.Key.ToString());
|
||||
string tabText = kvp.Key.ToString();
|
||||
using var tab = ImRaii.TabItem(tabText + "###" + kvp.Key.ToString());
|
||||
if (tab.Success)
|
||||
using var objectTabColor = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.AccentColor);
|
||||
using var objectTabHoverColor = ImRaii.PushColor(ImGuiCol.TabHovered, UiSharedService.AccentHoverColor);
|
||||
using var objectTabActiveColor = ImRaii.PushColor(ImGuiCol.TabActive, UiSharedService.AccentActiveColor);
|
||||
using var tabbar = ImRaii.TabBar("objectSelection");
|
||||
foreach (var kvp in _cachedAnalysis)
|
||||
{
|
||||
var groupedfiles = kvp.Value.Select(v => v.Value).GroupBy(f => f.FileType, StringComparer.Ordinal)
|
||||
.OrderBy(k => k.Key, StringComparer.Ordinal).ToList();
|
||||
using var id = ImRaii.PushId(kvp.Key.ToString());
|
||||
string tabText = kvp.Key.ToString();
|
||||
using var tab = ImRaii.TabItem(tabText + "###" + kvp.Key.ToString());
|
||||
if (tab.Success)
|
||||
{
|
||||
var groupedfiles = kvp.Value.Select(v => v.Value).GroupBy(f => f.FileType, StringComparer.Ordinal)
|
||||
.OrderBy(k => k.Key, StringComparer.Ordinal).ToList();
|
||||
|
||||
ImGui.TextUnformatted("Files for " + kvp.Key);
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(kvp.Value.Count.ToString());
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("Files for " + kvp.Key);
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(kvp.Value.Count.ToString());
|
||||
ImGui.SameLine();
|
||||
|
||||
using (var font = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString());
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
string text = "";
|
||||
text = string.Join(Environment.NewLine, groupedfiles
|
||||
.Select(f => f.Key + ": " + f.Count() + " files, size: " + UiSharedService.ByteToString(f.Sum(v => v.OriginalSize))
|
||||
+ ", compressed: " + UiSharedService.ByteToString(f.Sum(v => v.CompressedSize))));
|
||||
ImGui.SetTooltip(text);
|
||||
}
|
||||
ImGui.TextUnformatted($"{kvp.Key} size (actual):");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.OriginalSize)));
|
||||
ImGui.TextUnformatted($"{kvp.Key} size (download size):");
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, needAnalysis))
|
||||
{
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.CompressedSize)));
|
||||
if (needAnalysis && !isAnalyzing)
|
||||
using (var font = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString());
|
||||
UiSharedService.AttachToolTip("Click \"Start analysis\" to calculate download size");
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString());
|
||||
}
|
||||
}
|
||||
ImGui.TextUnformatted($"{kvp.Key} VRAM usage:");
|
||||
ImGui.SameLine();
|
||||
var vramUsage = groupedfiles.SingleOrDefault(v => string.Equals(v.Key, "tex", StringComparison.Ordinal));
|
||||
if (vramUsage != null)
|
||||
{
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(vramUsage.Sum(f => f.OriginalSize)));
|
||||
}
|
||||
ImGui.TextUnformatted($"{kvp.Key} modded model triangles: {UiSharedService.TrisToString(kvp.Value.Sum(f => f.Value.Triangles))}");
|
||||
|
||||
ImGui.Separator();
|
||||
if (_selectedObjectTab != kvp.Key)
|
||||
{
|
||||
_selectedHash = string.Empty;
|
||||
_selectedObjectTab = kvp.Key;
|
||||
_selectedFileTypeTab = string.Empty;
|
||||
_enableBc7ConversionMode = false;
|
||||
_texturesToConvert.Clear();
|
||||
}
|
||||
|
||||
using var fileTabBar = ImRaii.TabBar("fileTabs");
|
||||
|
||||
foreach (IGrouping<string, CharacterAnalyzer.FileDataEntry>? fileGroup in groupedfiles)
|
||||
{
|
||||
string fileGroupText = fileGroup.Key + " [" + fileGroup.Count() + "]";
|
||||
var requiresCompute = fileGroup.Any(k => !k.IsComputed);
|
||||
using var tabcol = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.Color(ImGuiColors.DalamudYellow), requiresCompute);
|
||||
ImRaii.IEndObject fileTab;
|
||||
using (var textcol = ImRaii.PushColor(ImGuiCol.Text, UiSharedService.Color(new(0, 0, 0, 1)),
|
||||
requiresCompute && !string.Equals(_selectedFileTypeTab, fileGroup.Key, StringComparison.Ordinal)))
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
fileTab = ImRaii.TabItem(fileGroupText + "###" + fileGroup.Key);
|
||||
string text = "";
|
||||
text = string.Join(Environment.NewLine, groupedfiles
|
||||
.Select(f => f.Key + ": " + f.Count() + " files, size: " + UiSharedService.ByteToString(f.Sum(v => v.OriginalSize))
|
||||
+ ", compressed: " + UiSharedService.ByteToString(f.Sum(v => v.CompressedSize))));
|
||||
ImGui.SetTooltip(text);
|
||||
}
|
||||
|
||||
if (!fileTab) { fileTab.Dispose(); continue; }
|
||||
|
||||
if (!string.Equals(fileGroup.Key, _selectedFileTypeTab, StringComparison.Ordinal))
|
||||
ImGui.TextUnformatted($"{kvp.Key} size (actual):");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.OriginalSize)));
|
||||
ImGui.TextUnformatted($"{kvp.Key} size (download size):");
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, UiSharedService.AccentColor, needAnalysis))
|
||||
{
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.CompressedSize)));
|
||||
if (needAnalysis && !isAnalyzing)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString());
|
||||
UiSharedService.AttachToolTip("Click \"Start analysis\" to calculate download size");
|
||||
}
|
||||
}
|
||||
ImGui.TextUnformatted($"{kvp.Key} VRAM usage:");
|
||||
ImGui.SameLine();
|
||||
var vramUsage = groupedfiles.SingleOrDefault(v => string.Equals(v.Key, "tex", StringComparison.Ordinal));
|
||||
if (vramUsage != null)
|
||||
{
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(vramUsage.Sum(f => f.OriginalSize)));
|
||||
}
|
||||
ImGui.TextUnformatted($"{kvp.Key} modded model triangles: {UiSharedService.TrisToString(kvp.Value.Sum(f => f.Value.Triangles))}");
|
||||
|
||||
ImGui.Separator();
|
||||
if (_selectedObjectTab != kvp.Key)
|
||||
{
|
||||
_selectedFileTypeTab = fileGroup.Key;
|
||||
_selectedHash = string.Empty;
|
||||
_selectedObjectTab = kvp.Key;
|
||||
_selectedFileTypeTab = string.Empty;
|
||||
_enableBc7ConversionMode = false;
|
||||
_texturesToConvert.Clear();
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted($"{fileGroup.Key} files");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(fileGroup.Count().ToString());
|
||||
using var fileTabColor = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.AccentColor);
|
||||
using var fileTabHoverColor = ImRaii.PushColor(ImGuiCol.TabHovered, UiSharedService.AccentHoverColor);
|
||||
using var fileTabActiveColor = ImRaii.PushColor(ImGuiCol.TabActive, UiSharedService.AccentActiveColor);
|
||||
using var fileTabBar = ImRaii.TabBar("fileTabs");
|
||||
|
||||
ImGui.TextUnformatted($"{fileGroup.Key} files size (actual):");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.OriginalSize)));
|
||||
|
||||
ImGui.TextUnformatted($"{fileGroup.Key} files size (download size):");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.CompressedSize)));
|
||||
|
||||
if (string.Equals(_selectedFileTypeTab, "tex", StringComparison.Ordinal))
|
||||
foreach (IGrouping<string, CharacterAnalyzer.FileDataEntry>? fileGroup in groupedfiles)
|
||||
{
|
||||
ImGui.Checkbox("Enable BC7 Conversion Mode", ref _enableBc7ConversionMode);
|
||||
if (_enableBc7ConversionMode)
|
||||
string fileGroupText = fileGroup.Key + " [" + fileGroup.Count() + "]";
|
||||
var requiresCompute = fileGroup.Any(k => !k.IsComputed);
|
||||
ImRaii.IEndObject fileTab;
|
||||
using (var textcol = ImRaii.PushColor(ImGuiCol.Text, UiSharedService.Color(Vector4.One),
|
||||
requiresCompute && !string.Equals(_selectedFileTypeTab, fileGroup.Key, StringComparison.Ordinal)))
|
||||
{
|
||||
UiSharedService.ColorText("WARNING BC7 CONVERSION:", ImGuiColors.DalamudYellow);
|
||||
ImGui.SameLine();
|
||||
UiSharedService.ColorText("Converting textures to BC7 is irreversible!", UiSharedService.AccentColor);
|
||||
UiSharedService.ColorTextWrapped("- Converting textures to BC7 will reduce their size (compressed and uncompressed) drastically. It is recommended to be used for large (4k+) textures." +
|
||||
Environment.NewLine + "- Some textures, especially ones utilizing colorsets, might not be suited for BC7 conversion and might produce visual artifacts." +
|
||||
Environment.NewLine + "- Before converting textures, make sure to have the original files of the mod you are converting so you can reimport it in case of issues." +
|
||||
Environment.NewLine + "- Conversion will convert all found texture duplicates (entries with more than 1 file path) automatically." +
|
||||
Environment.NewLine + "- Converting textures to BC7 is a very expensive operation and, depending on the amount of textures to convert, will take a while to complete."
|
||||
, ImGuiColors.DalamudYellow);
|
||||
if (_texturesToConvert.Count > 0 && _uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start conversion of " + _texturesToConvert.Count + " texture(s)"))
|
||||
fileTab = ImRaii.TabItem(fileGroupText + "###" + fileGroup.Key);
|
||||
}
|
||||
|
||||
if (!fileTab) { fileTab.Dispose(); continue; }
|
||||
|
||||
if (!string.Equals(fileGroup.Key, _selectedFileTypeTab, StringComparison.Ordinal))
|
||||
{
|
||||
_selectedFileTypeTab = fileGroup.Key;
|
||||
_selectedHash = string.Empty;
|
||||
_enableBc7ConversionMode = false;
|
||||
_texturesToConvert.Clear();
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted($"{fileGroup.Key} files");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(fileGroup.Count().ToString());
|
||||
|
||||
ImGui.TextUnformatted($"{fileGroup.Key} files size (actual):");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.OriginalSize)));
|
||||
|
||||
ImGui.TextUnformatted($"{fileGroup.Key} files size (download size):");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.CompressedSize)));
|
||||
|
||||
if (string.Equals(_selectedFileTypeTab, "tex", StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.Checkbox("Enable BC7 Conversion Mode", ref _enableBc7ConversionMode);
|
||||
if (_enableBc7ConversionMode)
|
||||
{
|
||||
var conversionCts = EnsureFreshCts(ref _conversionCancellationTokenSource);
|
||||
_conversionTask = _ipcManager.Penumbra.ConvertTextureFiles(_logger, _texturesToConvert, _conversionProgress, conversionCts.Token);
|
||||
UiSharedService.ColorText("WARNING BC7 CONVERSION:", UiSharedService.AccentColor);
|
||||
ImGui.SameLine();
|
||||
UiSharedService.ColorText("Converting textures to BC7 is irreversible!", UiSharedService.AccentColor);
|
||||
UiSharedService.ColorTextWrapped("- Converting textures to BC7 will reduce their size (compressed and uncompressed) drastically. It is recommended to be used for large (4k+) textures." +
|
||||
Environment.NewLine + "- Some textures, especially ones utilizing colorsets, might not be suited for BC7 conversion and might produce visual artifacts." +
|
||||
Environment.NewLine + "- Before converting textures, make sure to have the original files of the mod you are converting so you can reimport it in case of issues." +
|
||||
Environment.NewLine + "- Conversion will convert all found texture duplicates (entries with more than 1 file path) automatically." +
|
||||
Environment.NewLine + "- Converting textures to BC7 is a very expensive operation and, depending on the amount of textures to convert, will take a while to complete."
|
||||
, UiSharedService.AccentColor);
|
||||
if (_texturesToConvert.Count > 0 && _uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start conversion of " + _texturesToConvert.Count + " texture(s)"))
|
||||
{
|
||||
var conversionCts = EnsureFreshCts(ref _conversionCancellationTokenSource);
|
||||
_conversionTask = _ipcManager.Penumbra.ConvertTextureFiles(_logger, _texturesToConvert, _conversionProgress, conversionCts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
DrawTable(fileGroup);
|
||||
|
||||
fileTab.Dispose();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
DrawTable(fileGroup);
|
||||
|
||||
fileTab.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.TextUnformatted("Selected file:");
|
||||
ImGui.SameLine();
|
||||
UiSharedService.ColorText(_selectedHash, ImGuiColors.DalamudYellow);
|
||||
UiSharedService.ColorText(_selectedHash, UiSharedService.AccentColor);
|
||||
|
||||
if (_cachedAnalysis[_selectedObjectTab].TryGetValue(_selectedHash, out CharacterAnalyzer.FileDataEntry? item))
|
||||
{
|
||||
@@ -440,8 +462,8 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
||||
ImGui.TableNextColumn();
|
||||
if (string.Equals(_selectedHash, item.Hash, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, UiSharedService.Color(ImGuiColors.DalamudYellow));
|
||||
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, UiSharedService.Color(ImGuiColors.DalamudYellow));
|
||||
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, UiSharedService.Color(UiSharedService.AccentColor));
|
||||
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, UiSharedService.Color(UiSharedService.AccentColor));
|
||||
}
|
||||
ImGui.TextUnformatted(item.Hash);
|
||||
if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
|
||||
@@ -455,7 +477,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(item.OriginalSize));
|
||||
if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
|
||||
ImGui.TableNextColumn();
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, !item.IsComputed))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, UiSharedService.AccentColor, !item.IsComputed))
|
||||
ImGui.TextUnformatted(UiSharedService.ByteToString(item.CompressedSize));
|
||||
if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
|
||||
if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal))
|
||||
|
||||
@@ -3,15 +3,19 @@ using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using System;
|
||||
using MareSynchronos.API.Data.Enum;
|
||||
using MareSynchronos.API.Data.Extensions;
|
||||
using MareSynchronos.API.Dto.Group;
|
||||
using MareSynchronos.PlayerData.Pairs;
|
||||
using MareSynchronos.Services;
|
||||
using MareSynchronos.Services.AutoDetect;
|
||||
using MareSynchronos.Services.Mediator;
|
||||
using MareSynchronos.WebAPI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MareSynchronos.UI.Components.Popup;
|
||||
|
||||
@@ -23,6 +27,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
private readonly List<string> _oneTimeInvites = [];
|
||||
private readonly PairManager _pairManager;
|
||||
private readonly UiSharedService _uiSharedService;
|
||||
private readonly SyncshellDiscoveryService _syncshellDiscoveryService;
|
||||
private List<BannedGroupUserDto> _bannedUsers = [];
|
||||
private int _multiInvites;
|
||||
private string _newPassword;
|
||||
@@ -30,20 +35,31 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
private Task<int>? _pruneTestTask;
|
||||
private Task<int>? _pruneTask;
|
||||
private int _pruneDays = 14;
|
||||
private bool _autoDetectStateInitialized;
|
||||
private bool _autoDetectStateLoading;
|
||||
private bool _autoDetectToggleInFlight;
|
||||
private bool _autoDetectVisible;
|
||||
private bool _autoDetectPasswordDisabled;
|
||||
private string? _autoDetectMessage;
|
||||
|
||||
public SyncshellAdminUI(ILogger<SyncshellAdminUI> logger, MareMediator mediator, ApiController apiController,
|
||||
UiSharedService uiSharedService, PairManager pairManager, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService)
|
||||
UiSharedService uiSharedService, PairManager pairManager, SyncshellDiscoveryService syncshellDiscoveryService,
|
||||
GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService)
|
||||
: base(logger, mediator, "Syncshell Admin Panel (" + groupFullInfo.GroupAliasOrGID + ")", performanceCollectorService)
|
||||
{
|
||||
GroupFullInfo = groupFullInfo;
|
||||
_apiController = apiController;
|
||||
_uiSharedService = uiSharedService;
|
||||
_pairManager = pairManager;
|
||||
_syncshellDiscoveryService = syncshellDiscoveryService;
|
||||
_isOwner = string.Equals(GroupFullInfo.OwnerUID, _apiController.UID, StringComparison.Ordinal);
|
||||
_isModerator = GroupFullInfo.GroupUserInfo.IsModerator();
|
||||
_newPassword = string.Empty;
|
||||
_multiInvites = 30;
|
||||
_pwChangeSuccess = true;
|
||||
_autoDetectVisible = groupFullInfo.AutoDetectVisible;
|
||||
_autoDetectPasswordDisabled = groupFullInfo.PasswordTemporarilyDisabled;
|
||||
Mediator.Subscribe<SyncshellAutoDetectStateChanged>(this, OnSyncshellAutoDetectStateChanged);
|
||||
IsOpen = true;
|
||||
SizeConstraints = new WindowSizeConstraints()
|
||||
{
|
||||
@@ -59,6 +75,11 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
if (!_isModerator && !_isOwner) return;
|
||||
|
||||
GroupFullInfo = _pairManager.Groups[GroupFullInfo.Group];
|
||||
if (!_autoDetectToggleInFlight && !_autoDetectStateLoading)
|
||||
{
|
||||
_autoDetectVisible = GroupFullInfo.AutoDetectVisible;
|
||||
_autoDetectPasswordDisabled = GroupFullInfo.PasswordTemporarilyDisabled;
|
||||
}
|
||||
|
||||
using var id = ImRaii.PushId("syncshell_admin_" + GroupFullInfo.GID);
|
||||
|
||||
@@ -363,6 +384,13 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
mgmtTab.Dispose();
|
||||
|
||||
var discoveryTab = ImRaii.TabItem("AutoDetect");
|
||||
if (discoveryTab)
|
||||
{
|
||||
DrawAutoDetectTab();
|
||||
}
|
||||
discoveryTab.Dispose();
|
||||
|
||||
var permissionTab = ImRaii.TabItem("Permissions");
|
||||
if (permissionTab)
|
||||
{
|
||||
@@ -448,6 +476,128 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAutoDetectTab()
|
||||
{
|
||||
if (!_autoDetectStateInitialized && !_autoDetectStateLoading)
|
||||
{
|
||||
_autoDetectStateInitialized = true;
|
||||
_autoDetectStateLoading = true;
|
||||
_ = EnsureAutoDetectStateAsync();
|
||||
}
|
||||
|
||||
UiSharedService.TextWrapped("Activer l'affichage AutoDetect rend la Syncshell visible dans l'onglet AutoDetect et désactive temporairement le mot de passe.");
|
||||
ImGuiHelpers.ScaledDummy(4);
|
||||
|
||||
if (_autoDetectStateLoading)
|
||||
{
|
||||
ImGui.TextDisabled("Chargement de l'état en cours...");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_autoDetectMessage))
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(_autoDetectMessage!, ImGuiColors.DalamudYellow);
|
||||
}
|
||||
|
||||
bool desiredVisibility = _autoDetectVisible;
|
||||
using (ImRaii.Disabled(_autoDetectToggleInFlight || _autoDetectStateLoading))
|
||||
{
|
||||
if (ImGui.Checkbox("Afficher cette Syncshell dans l'AutoDetect", ref desiredVisibility))
|
||||
{
|
||||
_ = ToggleAutoDetectAsync(desiredVisibility);
|
||||
}
|
||||
}
|
||||
_uiSharedService.DrawHelpText("Quand cette option est activée, le mot de passe devient inactif tant que la visibilité est maintenue.");
|
||||
|
||||
if (_autoDetectPasswordDisabled && _autoDetectVisible)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Le mot de passe est actuellement désactivé pendant la visibilité AutoDetect.", ImGuiColors.DalamudYellow);
|
||||
}
|
||||
|
||||
ImGuiHelpers.ScaledDummy(6);
|
||||
if (ImGui.Button("Recharger l'état"))
|
||||
{
|
||||
_autoDetectStateLoading = true;
|
||||
_ = EnsureAutoDetectStateAsync(true);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task EnsureAutoDetectStateAsync(bool force = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var state = await _syncshellDiscoveryService.GetStateAsync(GroupFullInfo.GID, CancellationToken.None).ConfigureAwait(false);
|
||||
if (state != null)
|
||||
{
|
||||
ApplyAutoDetectState(state.AutoDetectVisible, state.PasswordTemporarilyDisabled, true);
|
||||
_autoDetectMessage = null;
|
||||
}
|
||||
else if (force)
|
||||
{
|
||||
_autoDetectMessage = "Impossible de récupérer l'état AutoDetect.";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_autoDetectMessage = force ? $"Erreur lors du rafraîchissement : {ex.Message}" : _autoDetectMessage;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_autoDetectStateLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ToggleAutoDetectAsync(bool desiredVisibility)
|
||||
{
|
||||
if (_autoDetectToggleInFlight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_autoDetectToggleInFlight = true;
|
||||
_autoDetectMessage = null;
|
||||
|
||||
try
|
||||
{
|
||||
var success = await _syncshellDiscoveryService.SetVisibilityAsync(GroupFullInfo.GID, desiredVisibility, CancellationToken.None).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
_autoDetectMessage = "Impossible de mettre à jour la visibilité AutoDetect.";
|
||||
return;
|
||||
}
|
||||
|
||||
await EnsureAutoDetectStateAsync(true).ConfigureAwait(false);
|
||||
_autoDetectMessage = desiredVisibility
|
||||
? "La Syncshell est désormais visible dans AutoDetect."
|
||||
: "La Syncshell n'est plus visible dans AutoDetect.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_autoDetectMessage = $"Erreur lors de la mise à jour AutoDetect : {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
_autoDetectToggleInFlight = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyAutoDetectState(bool visible, bool passwordDisabled, bool fromServer)
|
||||
{
|
||||
_autoDetectVisible = visible;
|
||||
_autoDetectPasswordDisabled = passwordDisabled;
|
||||
if (fromServer)
|
||||
{
|
||||
GroupFullInfo.AutoDetectVisible = visible;
|
||||
GroupFullInfo.PasswordTemporarilyDisabled = passwordDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSyncshellAutoDetectStateChanged(SyncshellAutoDetectStateChanged msg)
|
||||
{
|
||||
if (!string.Equals(msg.Gid, GroupFullInfo.GID, StringComparison.OrdinalIgnoreCase)) return;
|
||||
ApplyAutoDetectState(msg.Visible, msg.PasswordTemporarilyDisabled, true);
|
||||
_autoDetectMessage = null;
|
||||
}
|
||||
|
||||
public override void OnClose()
|
||||
{
|
||||
Mediator.Publish(new RemoveWindowMessage(this));
|
||||
|
||||
@@ -124,7 +124,11 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
||||
e.OnPreBuild(tk => tk.AddDalamudAssetFont(Dalamud.DalamudAsset.NotoSansJpMedium, new()
|
||||
{
|
||||
SizePx = 27,
|
||||
GlyphRanges = [0x20, 0x7E, 0]
|
||||
GlyphRanges = [
|
||||
0x0020, 0x007E,
|
||||
0x00A0, 0x017F,
|
||||
0
|
||||
]
|
||||
}));
|
||||
});
|
||||
GameFont = _pluginInterface.UiBuilder.FontAtlas.NewGameFontHandle(new(GameFontFamilyAndSize.Axis12));
|
||||
|
||||
Reference in New Issue
Block a user