Files
UmbraClient/MareSynchronos/UI/Components/DrawGroupPair.cs
2025-09-21 17:01:12 +02:00

408 lines
20 KiB
C#

using System;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Utility;
using MareSynchronos.API.Data.Enum;
using MareSynchronos.API.Data.Extensions;
using MareSynchronos.API.Dto.Group;
using MareSynchronos.API.Dto.User;
using MareSynchronos.PlayerData.Pairs;
using MareSynchronos.Services;
using MareSynchronos.Services.Mediator;
using MareSynchronos.UI.Handlers;
using MareSynchronos.WebAPI;
using MareSynchronos.Localization;
namespace MareSynchronos.UI.Components;
public class DrawGroupPair : DrawPairBase
{
protected readonly MareMediator _mediator;
private readonly GroupPairFullInfoDto _fullInfoDto;
private readonly GroupFullInfoDto _group;
private readonly CharaDataManager _charaDataManager;
private static string L(string key, string fallback, params object[] args)
{
var safeArgs = args ?? Array.Empty<object>();
return LocalizationService.Instance?.GetString(key, fallback, safeArgs)
?? string.Format(System.Globalization.CultureInfo.CurrentCulture, fallback, safeArgs);
}
public DrawGroupPair(string id, Pair entry, ApiController apiController,
MareMediator mareMediator, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto,
UidDisplayHandler handler, UiSharedService uiSharedService, CharaDataManager charaDataManager)
: base(id, entry, apiController, handler, uiSharedService)
{
_group = group;
_fullInfoDto = fullInfoDto;
_mediator = mareMediator;
_charaDataManager = charaDataManager;
}
protected override void DrawLeftSide(float textPosY, float originalY)
{
var entryUID = _pair.UserData.AliasOrUID;
var entryIsMod = _fullInfoDto.GroupPairStatusInfo.IsModerator();
var entryIsOwner = string.Equals(_pair.UserData.UID, _group.OwnerUID, StringComparison.Ordinal);
var entryIsPinned = _fullInfoDto.GroupPairStatusInfo.IsPinned();
var presenceIcon = _pair.IsVisible ? FontAwesomeIcon.Eye : FontAwesomeIcon.CloudMoon;
var presenceColor = (_pair.IsOnline || _pair.IsVisible) ? new Vector4(0.63f, 0.25f, 1f, 1f) : ImGuiColors.DalamudGrey;
var presenceText = L("GroupPair.Presence.Offline", "{0} is offline", entryUID);
ImGui.SetCursorPosY(textPosY);
bool drewPrefixIcon = false;
if (_pair.IsPaused)
{
presenceText = L("GroupPair.Presence.Paused", "{0} online status is unknown (paused)", entryUID);
ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(FontAwesomeIcon.PauseCircle.ToIconString(), ImGuiColors.DalamudYellow);
ImGui.PopFont();
UiSharedService.AttachToolTip(L("GroupPair.Tooltip.Paused", "Pairing status with {0} is paused", entryUID));
drewPrefixIcon = true;
}
else
{
bool individuallyPaired = _pair.UserPair != null;
var violet = new Vector4(0.63f, 0.25f, 1f, 1f);
if (individuallyPaired && (_pair.IsOnline || _pair.IsVisible))
{
ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(FontAwesomeIcon.Moon.ToIconString(), violet);
ImGui.PopFont();
UiSharedService.AttachToolTip(L("GroupPair.Tooltip.IndividuallyPaired", "You are individually paired with {0}", entryUID));
drewPrefixIcon = true;
}
}
if (drewPrefixIcon)
ImGui.SameLine();
ImGui.SetCursorPosY(textPosY);
ImGui.PushFont(UiBuilder.IconFont);
UiSharedService.ColorText(presenceIcon.ToIconString(), presenceColor);
ImGui.PopFont();
if (_pair.IsOnline && !_pair.IsVisible)
presenceText = L("GroupPair.Presence.Online", "{0} is online", entryUID);
else if (_pair.IsOnline && _pair.IsVisible)
presenceText = L("GroupPair.Presence.Visible", "{0} is visible: {1}\nClick to target this player", entryUID, _pair.PlayerName);
if (_pair.IsVisible)
{
if (ImGui.IsItemClicked())
{
_mediator.Publish(new TargetPairMessage(_pair));
}
if (_pair.LastAppliedDataBytes >= 0)
{
presenceText += UiSharedService.TooltipSeparator;
presenceText += (!_pair.IsVisible ? L("GroupPair.Presence.LastPrefix", "(Last) ") : string.Empty)
+ L("GroupPair.Presence.ModsInfo", "Mods Info") + Environment.NewLine;
presenceText += L("GroupPair.Presence.FilesSize", "Files Size: {0}", UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true));
if (_pair.LastAppliedApproximateVRAMBytes >= 0)
{
presenceText += Environment.NewLine + L("GroupPair.Presence.Vram", "Approx. VRAM Usage: {0}", UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true));
}
if (_pair.LastAppliedDataTris >= 0)
{
var trisValue = _pair.LastAppliedDataTris > 1000
? (_pair.LastAppliedDataTris / 1000d).ToString("0.0'k'", System.Globalization.CultureInfo.CurrentCulture)
: _pair.LastAppliedDataTris.ToString(System.Globalization.CultureInfo.CurrentCulture);
presenceText += Environment.NewLine + L("GroupPair.Presence.Tris", "Triangle Count (excl. Vanilla): {0}", trisValue);
}
}
}
UiSharedService.AttachToolTip(presenceText);
if (entryIsOwner)
{
ImGui.SameLine();
ImGui.SetCursorPosY(textPosY);
ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.Crown.ToIconString());
ImGui.PopFont();
UiSharedService.AttachToolTip(L("GroupPair.Tooltip.Owner", "User is owner of this Syncshell"));
}
else if (entryIsMod)
{
ImGui.SameLine();
ImGui.SetCursorPosY(textPosY);
ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.UserShield.ToIconString());
ImGui.PopFont();
UiSharedService.AttachToolTip(L("GroupPair.Tooltip.Moderator", "User is moderator of this Syncshell"));
}
else if (entryIsPinned)
{
ImGui.SameLine();
ImGui.SetCursorPosY(textPosY);
ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextUnformatted(FontAwesomeIcon.Thumbtack.ToIconString());
ImGui.PopFont();
UiSharedService.AttachToolTip(L("GroupPair.Tooltip.Pinned", "User is pinned in this Syncshell"));
}
}
protected override float DrawRightSide(float textPosY, float originalY)
{
var entryUID = _fullInfoDto.UserAliasOrUID;
var entryIsMod = _fullInfoDto.GroupPairStatusInfo.IsModerator();
var entryIsOwner = string.Equals(_pair.UserData.UID, _group.OwnerUID, StringComparison.Ordinal);
var entryIsPinned = _fullInfoDto.GroupPairStatusInfo.IsPinned();
var userIsOwner = string.Equals(_group.OwnerUID, _apiController.UID, StringComparison.OrdinalIgnoreCase);
var userIsModerator = _group.GroupUserInfo.IsModerator();
var soundsDisabled = _fullInfoDto.GroupUserPermissions.IsDisableSounds();
var animDisabled = _fullInfoDto.GroupUserPermissions.IsDisableAnimations();
var vfxDisabled = _fullInfoDto.GroupUserPermissions.IsDisableVFX();
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
var individualAnimDisabled = (_pair.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
bool showShared = _charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData);
bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled);
bool showPlus = _pair.UserPair == null;
bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused;
var spacing = ImGui.GetStyle().ItemSpacing.X;
var permIcon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) ? FontAwesomeIcon.ExclamationTriangle
: ((soundsDisabled || animDisabled || vfxDisabled) ? FontAwesomeIcon.InfoCircle : FontAwesomeIcon.None);
var runningIconWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X;
var infoIconWidth = UiSharedService.GetIconSize(permIcon).X;
var plusButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
var pos = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() + spacing
- (showShared ? (runningIconWidth + spacing) : 0)
- (showInfo ? (infoIconWidth + spacing) : 0)
- (showPlus ? (plusButtonWidth + spacing) : 0)
- (showBars ? (barButtonWidth + spacing) : 0);
ImGui.SameLine(pos);
if (showShared)
{
_uiSharedService.IconText(FontAwesomeIcon.Running);
UiSharedService.AttachToolTip(L("GroupPair.Tooltip.SharedData", "This user has shared {0} Character Data Sets with you.", sharedData!.Count)
+ UiSharedService.TooltipSeparator
+ L("GroupPair.Tooltip.SharedData.OpenHub", "Click to open the Character Data Hub and show the entries."));
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
_mediator.Publish(new OpenCharaDataHubWithFilterMessage(_pair.UserData));
}
ImGui.SameLine();
}
if (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled)
{
ImGui.SetCursorPosY(textPosY);
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow);
_uiSharedService.IconText(permIcon);
ImGui.PopStyleColor();
if (ImGui.IsItemHovered())
{
ImGui.BeginTooltip();
ImGui.TextUnformatted(L("GroupPair.Tooltip.IndividualHeader", "Individual User permissions"));
if (individualSoundsDisabled)
{
var userSoundsText = L("GroupPair.Tooltip.SoundWith", "Sound sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.VolumeOff);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userSoundsText);
ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(L("GroupPair.Tooltip.YouThey", "You: {0}, They: {1}",
_pair.UserPair!.OwnPermissions.IsDisableSounds() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled"),
_pair.UserPair!.OtherPermissions.IsDisableSounds() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled")));
}
if (individualAnimDisabled)
{
var userAnimText = L("GroupPair.Tooltip.AnimWith", "Animation sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Stop);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userAnimText);
ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(L("GroupPair.Tooltip.YouThey", "You: {0}, They: {1}",
_pair.UserPair!.OwnPermissions.IsDisableAnimations() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled"),
_pair.UserPair!.OtherPermissions.IsDisableAnimations() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled")));
}
if (individualVFXDisabled)
{
var userVFXText = L("GroupPair.Tooltip.VfxWith", "VFX sync disabled with {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Circle);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userVFXText);
ImGui.NewLine();
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(L("GroupPair.Tooltip.YouThey", "You: {0}, They: {1}",
_pair.UserPair!.OwnPermissions.IsDisableVFX() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled"),
_pair.UserPair!.OtherPermissions.IsDisableVFX() ? L("GroupPair.Toggle.Disabled", "Disabled") : L("GroupPair.Toggle.Enabled", "Enabled")));
}
ImGui.EndTooltip();
}
ImGui.SameLine();
}
else if ((animDisabled || soundsDisabled || vfxDisabled))
{
ImGui.SetCursorPosY(textPosY);
_uiSharedService.IconText(permIcon);
if (ImGui.IsItemHovered())
{
ImGui.BeginTooltip();
ImGui.TextUnformatted(L("GroupPair.Tooltip.SyncshellHeader", "Syncshell User permissions"));
if (soundsDisabled)
{
var userSoundsText = L("GroupPair.Tooltip.SoundBy", "Sound sync disabled by {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.VolumeOff);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userSoundsText);
}
if (animDisabled)
{
var userAnimText = L("GroupPair.Tooltip.AnimBy", "Animation sync disabled by {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Stop);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userAnimText);
}
if (vfxDisabled)
{
var userVFXText = L("GroupPair.Tooltip.VfxBy", "VFX sync disabled by {0}", _pair.UserData.AliasOrUID);
_uiSharedService.IconText(FontAwesomeIcon.Circle);
ImGui.SameLine(40 * ImGuiHelpers.GlobalScale);
ImGui.TextUnformatted(userVFXText);
}
ImGui.EndTooltip();
}
ImGui.SameLine();
}
if (showPlus)
{
ImGui.SetCursorPosY(originalY);
if (_uiSharedService.IconButton(FontAwesomeIcon.Plus))
{
_ = _apiController.UserAddPair(new UserDto(new(_pair.UserData.UID)));
}
UiSharedService.AttachToolTip(L("GroupPair.Popup.PairIndividually", "Pair with {0} individually", entryUID));
ImGui.SameLine();
}
if (showBars)
{
ImGui.SetCursorPosY(originalY);
if (_uiSharedService.IconButton(FontAwesomeIcon.Bars))
{
ImGui.OpenPopup("Popup");
}
}
if (ImGui.BeginPopup("Popup"))
{
if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner))
{
var pinText = entryIsPinned ? "Unpin user" : "Pin user";
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Thumbtack, pinText))
{
ImGui.CloseCurrentPopup();
var userInfo = _fullInfoDto.GroupPairStatusInfo ^ GroupUserInfo.IsPinned;
_ = _apiController.GroupSetUserInfo(new GroupPairUserInfoDto(_fullInfoDto.Group, _fullInfoDto.User, userInfo));
}
UiSharedService.AttachToolTip("Pin this user to the Syncshell. Pinned users will not be deleted in case of a manually initiated Syncshell clean");
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Remove user") && UiSharedService.CtrlPressed())
{
ImGui.CloseCurrentPopup();
_ = _apiController.GroupRemoveUser(_fullInfoDto);
}
UiSharedService.AttachToolTip("Hold CTRL and click to remove user " + (_pair.UserData.AliasOrUID) + " from Syncshell");
if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserSlash, "Ban User"))
{
ImGui.CloseCurrentPopup();
_mediator.Publish(new OpenBanUserPopupMessage(_pair, _group));
}
UiSharedService.AttachToolTip("Ban user from this Syncshell");
}
if (userIsOwner)
{
string modText = entryIsMod ? "Demod user" : "Mod user";
if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserShield, modText) && UiSharedService.CtrlPressed())
{
ImGui.CloseCurrentPopup();
var userInfo = _fullInfoDto.GroupPairStatusInfo ^ GroupUserInfo.IsModerator;
_ = _apiController.GroupSetUserInfo(new GroupPairUserInfoDto(_fullInfoDto.Group, _fullInfoDto.User, userInfo));
}
UiSharedService.AttachToolTip("Hold CTRL to change the moderator status for " + (_fullInfoDto.UserAliasOrUID) + Environment.NewLine +
"Moderators can kick, ban/unban, pin/unpin users and clear the Syncshell.");
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Crown, "Transfer Ownership") && UiSharedService.CtrlPressed() && UiSharedService.ShiftPressed())
{
ImGui.CloseCurrentPopup();
_ = _apiController.GroupChangeOwnership(_fullInfoDto);
}
UiSharedService.AttachToolTip("Hold CTRL and SHIFT and click to transfer ownership of this Syncshell to " + (_fullInfoDto.UserAliasOrUID) + Environment.NewLine + "WARNING: This action is irreversible.");
}
if (userIsOwner || (userIsModerator && !(entryIsMod || entryIsOwner)))
ImGui.Separator();
if (_pair.IsVisible)
{
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Eye, "Target player"))
{
_mediator.Publish(new TargetPairMessage(_pair));
ImGui.CloseCurrentPopup();
}
}
if (!_pair.IsPaused)
{
if (_uiSharedService.IconTextButton(FontAwesomeIcon.User, "Open Profile"))
{
_displayHandler.OpenProfile(_pair);
ImGui.CloseCurrentPopup();
}
}
if (_pair.IsVisible)
{
#if DEBUG
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, "Open Analysis"))
{
_displayHandler.OpenAnalysis(_pair);
ImGui.CloseCurrentPopup();
}
#endif
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Sync, "Reload last data"))
{
_pair.ApplyLastReceivedData(forced: true);
ImGui.CloseCurrentPopup();
}
UiSharedService.AttachToolTip("This reapplies the last received character data to this character");
}
ImGui.EndPopup();
}
return pos - spacing;
}
}