few changes:
- sending a successful pair request through context menu while a pending one exists in client clears it - adjustments to higlight coloring, preventing any text colors to blend with the highlight - some text adjustments - editing uid color in profile editor also previews the highlight
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState.Objects;
|
using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Interface.ImGuiFileDialog;
|
using Dalamud.Interface.ImGuiFileDialog;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
@@ -150,7 +150,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton(addonLifecycle);
|
collection.AddSingleton(addonLifecycle);
|
||||||
collection.AddSingleton(p => new ContextMenuService(contextMenu, pluginInterface, gameData,
|
collection.AddSingleton(p => new ContextMenuService(contextMenu, pluginInterface, gameData,
|
||||||
p.GetRequiredService<ILogger<ContextMenuService>>(), p.GetRequiredService<DalamudUtilService>(), p.GetRequiredService<ApiController>(), objectTable,
|
p.GetRequiredService<ILogger<ContextMenuService>>(), p.GetRequiredService<DalamudUtilService>(), p.GetRequiredService<ApiController>(), objectTable,
|
||||||
p.GetRequiredService<LightlessConfigService>(), p.GetRequiredService<PairManager>(), clientState));
|
p.GetRequiredService<LightlessConfigService>(), p.GetRequiredService<PairRequestService>(), p.GetRequiredService<PairManager>(), clientState));
|
||||||
collection.AddSingleton((s) => new IpcCallerPenumbra(s.GetRequiredService<ILogger<IpcCallerPenumbra>>(), pluginInterface,
|
collection.AddSingleton((s) => new IpcCallerPenumbra(s.GetRequiredService<ILogger<IpcCallerPenumbra>>(), pluginInterface,
|
||||||
s.GetRequiredService<DalamudUtilService>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<RedrawManager>()));
|
s.GetRequiredService<DalamudUtilService>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<RedrawManager>()));
|
||||||
collection.AddSingleton((s) => new IpcCallerGlamourer(s.GetRequiredService<ILogger<IpcCallerGlamourer>>(), pluginInterface,
|
collection.AddSingleton((s) => new IpcCallerGlamourer(s.GetRequiredService<ILogger<IpcCallerGlamourer>>(), pluginInterface,
|
||||||
@@ -277,4 +277,4 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
_host.StopAsync().GetAwaiter().GetResult();
|
_host.StopAsync().GetAwaiter().GetResult();
|
||||||
_host.Dispose();
|
_host.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||||
using Dalamud.Game.Gui.ContextMenu;
|
using Dalamud.Game.Gui.ContextMenu;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
@@ -21,6 +21,7 @@ internal class ContextMenuService : IHostedService
|
|||||||
private readonly DalamudUtilService _dalamudUtil;
|
private readonly DalamudUtilService _dalamudUtil;
|
||||||
private readonly IClientState _clientState;
|
private readonly IClientState _clientState;
|
||||||
private readonly PairManager _pairManager;
|
private readonly PairManager _pairManager;
|
||||||
|
private readonly PairRequestService _pairRequestService;
|
||||||
private readonly ApiController _apiController;
|
private readonly ApiController _apiController;
|
||||||
private readonly IObjectTable _objectTable;
|
private readonly IObjectTable _objectTable;
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ internal class ContextMenuService : IHostedService
|
|||||||
ApiController apiController,
|
ApiController apiController,
|
||||||
IObjectTable objectTable,
|
IObjectTable objectTable,
|
||||||
LightlessConfigService configService,
|
LightlessConfigService configService,
|
||||||
|
PairRequestService pairRequestService,
|
||||||
PairManager pairManager,
|
PairManager pairManager,
|
||||||
IClientState clientState)
|
IClientState clientState)
|
||||||
{
|
{
|
||||||
@@ -44,6 +46,7 @@ internal class ContextMenuService : IHostedService
|
|||||||
_apiController = apiController;
|
_apiController = apiController;
|
||||||
_objectTable = objectTable;
|
_objectTable = objectTable;
|
||||||
_pairManager = pairManager;
|
_pairManager = pairManager;
|
||||||
|
_pairRequestService = pairRequestService;
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +143,10 @@ internal class ContextMenuService : IHostedService
|
|||||||
|
|
||||||
_logger.LogInformation("Sending pair request: sender {SenderCid}, receiver {ReceiverCid}", senderCid, receiverCid);
|
_logger.LogInformation("Sending pair request: sender {SenderCid}, receiver {ReceiverCid}", senderCid, receiverCid);
|
||||||
await _apiController.TryPairWithContentId(receiverCid, senderCid).ConfigureAwait(false);
|
await _apiController.TryPairWithContentId(receiverCid, senderCid).ConfigureAwait(false);
|
||||||
|
if (!string.IsNullOrWhiteSpace(receiverCid))
|
||||||
|
{
|
||||||
|
_pairRequestService.RemoveRequest(receiverCid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -141,8 +141,8 @@ namespace LightlessSync.UI
|
|||||||
|
|
||||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, -2));
|
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, -2));
|
||||||
|
|
||||||
_uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "This lets other Lightless users know you use Lightless.");
|
_uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"),"This lets other Lightless users know you use Lightless. While enabled, you and others using Lightfinder can see each other identified as Lightless users.");
|
||||||
_uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "While enabled, you and other people using Lightfinder can see each other identified as Lightless users.");
|
|
||||||
ImGui.Indent(15f);
|
ImGui.Indent(15f);
|
||||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
|
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
|
||||||
ImGui.Text("- This is done using a 'Lightless' label above player nameplates.");
|
ImGui.Text("- This is done using a 'Lightless' label above player nameplates.");
|
||||||
@@ -183,15 +183,16 @@ namespace LightlessSync.UI
|
|||||||
new SeStringUtils.RichTextEntry(" and does not share any data with other users. All identifying information remains private to the server."));
|
new SeStringUtils.RichTextEntry(" and does not share any data with other users. All identifying information remains private to the server."));
|
||||||
|
|
||||||
_uiSharedService.DrawNoteLine("! ", UIColors.Get("DimRed"), "Pairing is intended as a mutual agreement between both parties. A pair request will not be visible to the recipient unless Lightfinder is enabled.");
|
_uiSharedService.DrawNoteLine("! ", UIColors.Get("DimRed"), "Pairing is intended as a mutual agreement between both parties. A pair request will not be visible to the recipient unless Lightfinder is enabled.");
|
||||||
ImGuiHelpers.ScaledDummy(3f);
|
|
||||||
|
ImGuiHelpers.ScaledDummy(5f);
|
||||||
|
|
||||||
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
||||||
ImGui.Text("Use Lightfinder only when you want to be visible.");
|
ImGui.TextWrapped("Use Lightfinder when you're okay with being visible to other users and understand that you are responsible for your own experience.");
|
||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
ImGui.PopStyleVar();
|
ImGui.PopStyleVar();
|
||||||
|
|
||||||
ImGuiHelpers.ScaledDummy(2.2f);
|
ImGuiHelpers.ScaledDummy(3f);
|
||||||
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
|
_uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f);
|
||||||
|
|
||||||
if (_configService.Current.BroadcastEnabled)
|
if (_configService.Current.BroadcastEnabled)
|
||||||
|
|||||||
@@ -512,7 +512,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
||||||
ImGui.Text("Use it only when you want to be visible.");
|
ImGui.TextWrapped("Use Lightfinder when you're okay with being visible to other users and understand that you are responsible for your own experience.");
|
||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
ImGuiHelpers.ScaledDummy(0.2f);
|
ImGuiHelpers.ScaledDummy(0.2f);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using LightlessSync.API.Data;
|
|||||||
using LightlessSync.API.Dto.User;
|
using LightlessSync.API.Dto.User;
|
||||||
using LightlessSync.Services;
|
using LightlessSync.Services;
|
||||||
using LightlessSync.Services.Mediator;
|
using LightlessSync.Services.Mediator;
|
||||||
|
using LightlessSync.UI.Style;
|
||||||
using LightlessSync.Utils;
|
using LightlessSync.Utils;
|
||||||
using LightlessSync.WebAPI;
|
using LightlessSync.WebAPI;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -33,6 +34,7 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
private bool _showFileDialogError = false;
|
private bool _showFileDialogError = false;
|
||||||
private bool _wasOpen;
|
private bool _wasOpen;
|
||||||
|
|
||||||
|
private Vector4 _currentBg = new(0.15f, 0.15f, 0.15f, 1f);
|
||||||
private bool vanityInitialized; // useless for now
|
private bool vanityInitialized; // useless for now
|
||||||
private bool textEnabled;
|
private bool textEnabled;
|
||||||
private bool glowEnabled;
|
private bool glowEnabled;
|
||||||
@@ -303,22 +305,37 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
using (ImRaii.PushFont(font))
|
using (ImRaii.PushFont(font))
|
||||||
{
|
{
|
||||||
var offsetX = 10f;
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
var pos = ImGui.GetCursorScreenPos() + new Vector2(offsetX, 0);
|
var textSize = ImGui.CalcTextSize(seString.TextValue);
|
||||||
var size = ImGui.CalcTextSize(seString.TextValue);
|
|
||||||
|
|
||||||
var padding = new Vector2(6, 3);
|
float minWidth = 150f * ImGuiHelpers.GlobalScale;
|
||||||
var rectMin = pos - padding;
|
float bgWidth = Math.Max(textSize.X + 20f, minWidth);
|
||||||
var rectMax = pos + size + padding;
|
|
||||||
|
float paddingY = 5f * ImGuiHelpers.GlobalScale;
|
||||||
|
|
||||||
|
var cursor = ImGui.GetCursorScreenPos();
|
||||||
|
|
||||||
|
var rectMin = cursor;
|
||||||
|
var rectMax = rectMin + new Vector2(bgWidth, textSize.Y + (paddingY * 2f));
|
||||||
|
|
||||||
|
float boost = Luminance.ComputeHighlight(previewTextColor, previewGlowColor);
|
||||||
|
|
||||||
|
var baseBg = new Vector4(0.15f + boost, 0.15f + boost, 0.15f + boost, 1f);
|
||||||
|
var bgColor = Luminance.BackgroundContrast(previewTextColor, previewGlowColor, baseBg, ref _currentBg);
|
||||||
|
|
||||||
var bgColor = new Vector4(0.15f, 0.15f, 0.15f, 1f);
|
|
||||||
var borderColor = UIColors.Get("LightlessPurple");
|
var borderColor = UIColors.Get("LightlessPurple");
|
||||||
|
|
||||||
var drawList = ImGui.GetWindowDrawList();
|
|
||||||
drawList.AddRectFilled(rectMin, rectMax, ImGui.GetColorU32(bgColor), 6.0f);
|
drawList.AddRectFilled(rectMin, rectMax, ImGui.GetColorU32(bgColor), 6.0f);
|
||||||
drawList.AddRect(rectMin, rectMax, ImGui.GetColorU32(borderColor), 6.0f, ImDrawFlags.None, 1.5f);
|
drawList.AddRect(rectMin, rectMax, ImGui.GetColorU32(borderColor), 6.0f, ImDrawFlags.None, 1.5f);
|
||||||
|
|
||||||
SeStringUtils.RenderSeStringWithHitbox(seString, pos, font);
|
var textPos = new Vector2(
|
||||||
|
rectMin.X + (bgWidth - textSize.X) * 0.5f,
|
||||||
|
rectMin.Y + paddingY
|
||||||
|
);
|
||||||
|
|
||||||
|
SeStringUtils.RenderSeStringWithHitbox(seString, textPos, font);
|
||||||
|
|
||||||
|
ImGui.Dummy(new Vector2(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
const float colorPickAlign = 90f;
|
const float colorPickAlign = 90f;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using LightlessSync.LightlessConfiguration;
|
|||||||
using LightlessSync.PlayerData.Pairs;
|
using LightlessSync.PlayerData.Pairs;
|
||||||
using LightlessSync.Services.Mediator;
|
using LightlessSync.Services.Mediator;
|
||||||
using LightlessSync.Services.ServerConfiguration;
|
using LightlessSync.Services.ServerConfiguration;
|
||||||
|
using LightlessSync.UI.Style;
|
||||||
using LightlessSync.Utils;
|
using LightlessSync.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@@ -26,6 +27,9 @@ public class IdDisplayHandler
|
|||||||
private bool _popupShown = false;
|
private bool _popupShown = false;
|
||||||
private DateTime? _popupTime;
|
private DateTime? _popupTime;
|
||||||
|
|
||||||
|
private Vector4 _currentBg = new(0.15f, 0.15f, 0.15f, 1f);
|
||||||
|
private float _highlightBoost;
|
||||||
|
|
||||||
public IdDisplayHandler(LightlessMediator mediator, ServerConfigurationManager serverManager, LightlessConfigService lightlessConfigService)
|
public IdDisplayHandler(LightlessMediator mediator, ServerConfigurationManager serverManager, LightlessConfigService lightlessConfigService)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
@@ -98,7 +102,7 @@ public class IdDisplayHandler
|
|||||||
{
|
{
|
||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
|
|
||||||
var font = UiBuilder.MonoFont;
|
var font = textIsUid ? UiBuilder.MonoFont : ImGui.GetFont();
|
||||||
|
|
||||||
Vector4? textColor = null;
|
Vector4? textColor = null;
|
||||||
Vector4? glowColor = null;
|
Vector4? glowColor = null;
|
||||||
@@ -127,10 +131,11 @@ public class IdDisplayHandler
|
|||||||
float highlightPadX = 0f;
|
float highlightPadX = 0f;
|
||||||
float highlightPadY = 0f;
|
float highlightPadY = 0f;
|
||||||
|
|
||||||
if (useVanityColors && textColor is Vector4 contrastColor)
|
if (useVanityColors)
|
||||||
{
|
{
|
||||||
var brightness = (0.299f * contrastColor.X) + (0.587f * contrastColor.Y) + (0.114f * contrastColor.Z);
|
float boost = Luminance.ComputeHighlight(textColor, glowColor);
|
||||||
if (brightness < 0.35f)
|
|
||||||
|
if (boost > 0f)
|
||||||
{
|
{
|
||||||
var style = ImGui.GetStyle();
|
var style = ImGui.GetStyle();
|
||||||
useHighlight = true;
|
useHighlight = true;
|
||||||
@@ -138,6 +143,12 @@ public class IdDisplayHandler
|
|||||||
highlightPadY = MathF.Max(style.FramePadding.Y * 0.55f, 1.25f * ImGuiHelpers.GlobalScale);
|
highlightPadY = MathF.Max(style.FramePadding.Y * 0.55f, 1.25f * ImGuiHelpers.GlobalScale);
|
||||||
drawList.ChannelsSplit(2);
|
drawList.ChannelsSplit(2);
|
||||||
drawList.ChannelsSetCurrent(1);
|
drawList.ChannelsSetCurrent(1);
|
||||||
|
|
||||||
|
_highlightBoost = boost;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_highlightBoost = 0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +160,7 @@ public class IdDisplayHandler
|
|||||||
SeStringUtils.RenderSeStringWithHitbox(seString, rowStart, font);
|
SeStringUtils.RenderSeStringWithHitbox(seString, rowStart, font);
|
||||||
itemMin = ImGui.GetItemRectMin();
|
itemMin = ImGui.GetItemRectMin();
|
||||||
itemMax = ImGui.GetItemRectMax();
|
itemMax = ImGui.GetItemRectMax();
|
||||||
textSize = itemMax - itemMin;
|
//textSize = itemMax - itemMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useHighlight)
|
if (useHighlight)
|
||||||
@@ -170,11 +181,14 @@ public class IdDisplayHandler
|
|||||||
highlightMin.Y = MathF.Max(highlightMin.Y, contentMin.Y);
|
highlightMin.Y = MathF.Max(highlightMin.Y, contentMin.Y);
|
||||||
highlightMax.Y = MathF.Min(highlightMax.Y, contentMax.Y);
|
highlightMax.Y = MathF.Min(highlightMax.Y, contentMax.Y);
|
||||||
|
|
||||||
var highlightColor = style.Colors[(int)ImGuiCol.TableRowBgAlt];
|
var highlightColor = new Vector4(
|
||||||
highlightColor.X = 0.25f;
|
0.25f + _highlightBoost,
|
||||||
highlightColor.Y = 0.25f;
|
0.25f + _highlightBoost,
|
||||||
highlightColor.Z = 0.25f;
|
0.25f + _highlightBoost,
|
||||||
highlightColor.W = 1f;
|
1f
|
||||||
|
);
|
||||||
|
|
||||||
|
highlightColor = Luminance.BackgroundContrast(textColor, glowColor, highlightColor, ref _currentBg);
|
||||||
|
|
||||||
float rounding = style.FrameRounding > 0f ? style.FrameRounding : 5f * ImGuiHelpers.GlobalScale;
|
float rounding = style.FrameRounding > 0f ? style.FrameRounding : 5f * ImGuiHelpers.GlobalScale;
|
||||||
drawList.ChannelsSetCurrent(0);
|
drawList.ChannelsSetCurrent(0);
|
||||||
|
|||||||
64
LightlessSync/UI/Style/Luminance.cs
Normal file
64
LightlessSync/UI/Style/Luminance.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace LightlessSync.UI.Style
|
||||||
|
{
|
||||||
|
internal static class Luminance
|
||||||
|
{
|
||||||
|
public static float BrightnessThreshold { get; set; } = 0.4f;
|
||||||
|
public static float HighlightBoostMax { get; set; } = 0.1f;
|
||||||
|
public static float SmoothFactor { get; set; } = 0.15f;
|
||||||
|
|
||||||
|
private static float Brightness(Vector4 color)
|
||||||
|
=> Math.Max(color.X, Math.Max(color.Y, color.Z));
|
||||||
|
|
||||||
|
public static float ComputeHighlight(Vector4? textColor, Vector4? glowColor)
|
||||||
|
{
|
||||||
|
float brightnessText = textColor.HasValue ? Brightness(textColor.Value) : 1f;
|
||||||
|
float brightnessGlow = glowColor.HasValue ? Brightness(glowColor.Value) : 1f;
|
||||||
|
|
||||||
|
if (brightnessText >= BrightnessThreshold || brightnessGlow >= BrightnessThreshold)
|
||||||
|
return 0f;
|
||||||
|
|
||||||
|
float deficit = Math.Min(BrightnessThreshold - brightnessText,
|
||||||
|
BrightnessThreshold - brightnessGlow);
|
||||||
|
|
||||||
|
float factor = Math.Clamp(deficit / BrightnessThreshold, 0f, 1f);
|
||||||
|
factor = MathF.Pow(factor, 2.0f);
|
||||||
|
|
||||||
|
return factor * HighlightBoostMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector4 BackgroundContrast(Vector4? textColor, Vector4? glowColor, Vector4 backgroundColor, ref Vector4 currentBg)
|
||||||
|
{
|
||||||
|
if (!textColor.HasValue && !glowColor.HasValue)
|
||||||
|
return backgroundColor;
|
||||||
|
|
||||||
|
float brightnessText = textColor.HasValue ? Brightness(textColor.Value) : 0f;
|
||||||
|
float brightnessGlow = glowColor.HasValue ? Brightness(glowColor.Value) : 0f;
|
||||||
|
|
||||||
|
float fgBrightness = Math.Max(brightnessText, brightnessGlow);
|
||||||
|
float bgBrightness = Brightness(backgroundColor);
|
||||||
|
float diff = Math.Abs(bgBrightness - fgBrightness);
|
||||||
|
|
||||||
|
bool shouldBeDark = fgBrightness > 0.5f;
|
||||||
|
Vector4 targetBg;
|
||||||
|
|
||||||
|
if (diff >= BrightnessThreshold)
|
||||||
|
{
|
||||||
|
targetBg = backgroundColor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetBg = shouldBeDark
|
||||||
|
? new Vector4(0.05f, 0.05f, 0.05f, backgroundColor.W)
|
||||||
|
: new Vector4(0.95f, 0.95f, 0.95f, backgroundColor.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
float t = Math.Clamp(SmoothFactor, 0f, 1f);
|
||||||
|
currentBg = t <= 0f ? targetBg : Vector4.Lerp(currentBg, targetBg, t);
|
||||||
|
|
||||||
|
return currentBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user