added chat report functionality and some other random stuff
This commit is contained in:
@@ -29,9 +29,12 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
private const string ChatDisabledStatus = "Chat services disabled";
|
||||
private const string SettingsPopupId = "zone_chat_settings_popup";
|
||||
private const string ReportPopupId = "Report Message##zone_chat_report_popup";
|
||||
private const float DefaultWindowOpacity = .97f;
|
||||
private const float MinWindowOpacity = 0.05f;
|
||||
private const float MaxWindowOpacity = 1f;
|
||||
private const int ReportReasonMaxLength = 500;
|
||||
private const int ReportContextMaxLength = 1000;
|
||||
|
||||
private readonly UiSharedService _uiSharedService;
|
||||
private readonly ZoneChatService _zoneChatService;
|
||||
@@ -50,6 +53,15 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
private float? _pendingChannelScroll;
|
||||
private float _channelScroll;
|
||||
private float _channelScrollMax;
|
||||
private ChatChannelSnapshot? _reportTargetChannel;
|
||||
private ChatMessageEntry? _reportTargetMessage;
|
||||
private string _reportReason = string.Empty;
|
||||
private string _reportAdditionalContext = string.Empty;
|
||||
private bool _reportPopupOpen;
|
||||
private bool _reportPopupRequested;
|
||||
private bool _reportSubmitting;
|
||||
private string? _reportError;
|
||||
private ChatReportResult? _reportSubmissionResult;
|
||||
|
||||
public ZoneChatUi(
|
||||
ILogger<ZoneChatUi> logger,
|
||||
@@ -112,6 +124,7 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
DrawConnectionControls();
|
||||
|
||||
var channels = _zoneChatService.GetChannelsSnapshot();
|
||||
DrawReportPopup();
|
||||
|
||||
if (channels.Count == 0)
|
||||
{
|
||||
@@ -482,6 +495,221 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
private void DrawReportPopup()
|
||||
{
|
||||
if (!_reportPopupOpen)
|
||||
return;
|
||||
|
||||
var desiredPopupSize = new Vector2(520f * ImGuiHelpers.GlobalScale, 0f);
|
||||
ImGui.SetNextWindowSize(desiredPopupSize, ImGuiCond.Always);
|
||||
if (_reportPopupRequested)
|
||||
{
|
||||
ImGui.OpenPopup(ReportPopupId);
|
||||
_reportPopupRequested = false;
|
||||
}
|
||||
else if (!ImGui.IsPopupOpen(ReportPopupId, ImGuiPopupFlags.AnyPopupLevel))
|
||||
{
|
||||
ImGui.OpenPopup(ReportPopupId);
|
||||
}
|
||||
|
||||
var popupFlags = UiSharedService.PopupWindowFlags | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoSavedSettings;
|
||||
if (!ImGui.BeginPopupModal(ReportPopupId, popupFlags))
|
||||
return;
|
||||
|
||||
if (_reportTargetChannel is not { } channel || _reportTargetMessage is not { } message)
|
||||
{
|
||||
CloseReportPopup();
|
||||
ImGui.EndPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_reportSubmissionResult is { } pendingResult)
|
||||
{
|
||||
_reportSubmissionResult = null;
|
||||
_reportSubmitting = false;
|
||||
|
||||
if (pendingResult.Success)
|
||||
{
|
||||
Mediator.Publish(new NotificationMessage("Zone Chat", "Report submitted for moderator review.", NotificationType.Info, TimeSpan.FromSeconds(3)));
|
||||
CloseReportPopup();
|
||||
ImGui.EndPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
_reportError = pendingResult.ErrorMessage ?? "Failed to submit report. Please try again.";
|
||||
}
|
||||
|
||||
var channelPrefix = channel.Type == ChatChannelType.Zone ? "Zone" : "Syncshell";
|
||||
var channelLabel = $"{channelPrefix}: {channel.DisplayName}";
|
||||
if (channel.Type == ChatChannelType.Zone && channel.Descriptor.WorldId != 0)
|
||||
{
|
||||
channelLabel += $" (World #{channel.Descriptor.WorldId})";
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted(channelLabel);
|
||||
ImGui.TextUnformatted($"Sender: {message.DisplayName}");
|
||||
ImGui.TextUnformatted($"Sent: {message.Payload.SentAtUtc.ToLocalTime().ToString("g", CultureInfo.CurrentCulture)}");
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.PushTextWrapPos(ImGui.GetWindowContentRegionMax().X);
|
||||
ImGui.TextWrapped(message.Payload.Message);
|
||||
ImGui.PopTextWrapPos();
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.TextUnformatted("Reason (required)");
|
||||
if (ImGui.InputTextMultiline("##chat_report_reason", ref _reportReason, ReportReasonMaxLength, new Vector2(-1, 80f * ImGuiHelpers.GlobalScale)))
|
||||
{
|
||||
if (_reportReason.Length > ReportReasonMaxLength)
|
||||
{
|
||||
_reportReason = _reportReason[..(int)ReportReasonMaxLength];
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3);
|
||||
ImGui.TextUnformatted($"{_reportReason.Length}/{ReportReasonMaxLength}");
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
ImGui.Spacing();
|
||||
ImGui.TextUnformatted("Additional context (optional)");
|
||||
if (ImGui.InputTextMultiline("##chat_report_context", ref _reportAdditionalContext, ReportContextMaxLength, new Vector2(-1, 120f * ImGuiHelpers.GlobalScale)))
|
||||
{
|
||||
if (_reportAdditionalContext.Length > ReportContextMaxLength)
|
||||
{
|
||||
_reportAdditionalContext = _reportAdditionalContext[..(int)ReportContextMaxLength];
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3);
|
||||
ImGui.TextUnformatted($"{_reportAdditionalContext.Length}/{ReportContextMaxLength}");
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if (!string.IsNullOrEmpty(_reportError))
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed"));
|
||||
ImGui.TextWrapped(_reportError);
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
if (_reportSubmitting)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3);
|
||||
ImGui.TextUnformatted("Submitting report...");
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
var style = ImGui.GetStyle();
|
||||
var availableWidth = Math.Max(0f, ImGui.GetContentRegionAvail().X);
|
||||
var buttonWidth = Math.Max(100f * ImGuiHelpers.GlobalScale, (availableWidth - style.ItemSpacing.X) / 2f);
|
||||
var canSubmit = !_reportSubmitting && _reportReason.Trim().Length > 0;
|
||||
|
||||
using (ImRaii.Disabled(!canSubmit))
|
||||
{
|
||||
if (ImGui.Button("Submit Report", new Vector2(buttonWidth, 0f)) && canSubmit)
|
||||
{
|
||||
BeginReportSubmission(channel, message);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Cancel", new Vector2(buttonWidth, 0f)))
|
||||
{
|
||||
CloseReportPopup();
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
private void OpenReportPopup(ChatChannelSnapshot channel, ChatMessageEntry message)
|
||||
{
|
||||
_reportTargetChannel = channel;
|
||||
_reportTargetMessage = message;
|
||||
_logger.LogDebug("Opening report popup for channel {ChannelKey}, message {MessageId}", channel.Key, message.Payload.MessageId);
|
||||
_reportReason = string.Empty;
|
||||
_reportAdditionalContext = string.Empty;
|
||||
_reportError = null;
|
||||
_reportSubmissionResult = null;
|
||||
_reportSubmitting = false;
|
||||
_reportPopupOpen = true;
|
||||
_reportPopupRequested = true;
|
||||
}
|
||||
|
||||
private void BeginReportSubmission(ChatChannelSnapshot channel, ChatMessageEntry message)
|
||||
{
|
||||
if (_reportSubmitting)
|
||||
return;
|
||||
|
||||
var trimmedReason = _reportReason.Trim();
|
||||
if (trimmedReason.Length == 0)
|
||||
{
|
||||
_reportError = "Please describe the issue before submitting.";
|
||||
return;
|
||||
}
|
||||
|
||||
var trimmedContext = string.IsNullOrWhiteSpace(_reportAdditionalContext)
|
||||
? null
|
||||
: _reportAdditionalContext.Trim();
|
||||
|
||||
_reportSubmitting = true;
|
||||
_reportError = null;
|
||||
_reportSubmissionResult = null;
|
||||
|
||||
var descriptor = channel.Descriptor;
|
||||
var messageId = message.Payload.MessageId;
|
||||
if (string.IsNullOrWhiteSpace(messageId))
|
||||
{
|
||||
_reportSubmitting = false;
|
||||
_reportError = "Unable to report this message.";
|
||||
_logger.LogWarning("Report submission aborted: missing message id for channel {ChannelKey}", channel.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogDebug("Submitting chat report for channel {ChannelKey}, message {MessageId}", channel.Key, messageId);
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
ChatReportResult result;
|
||||
try
|
||||
{
|
||||
result = await _zoneChatService.ReportMessageAsync(descriptor, messageId, trimmedReason, trimmedContext).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to submit chat report");
|
||||
result = new ChatReportResult(false, "Failed to submit report. Please try again.");
|
||||
}
|
||||
|
||||
_reportSubmissionResult = result;
|
||||
if (result.Success)
|
||||
{
|
||||
_logger.LogInformation("Chat report submitted successfully for channel {ChannelKey}, message {MessageId}", channel.Key, messageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Chat report submission failed for channel {ChannelKey}, message {MessageId}: {Error}", channel.Key, messageId, result.ErrorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void CloseReportPopup()
|
||||
{
|
||||
_reportPopupOpen = false;
|
||||
_reportPopupRequested = false;
|
||||
ResetReportPopupState();
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
private void ResetReportPopupState()
|
||||
{
|
||||
_reportTargetChannel = null;
|
||||
_reportTargetMessage = null;
|
||||
_reportReason = string.Empty;
|
||||
_reportAdditionalContext = string.Empty;
|
||||
_reportError = null;
|
||||
_reportSubmissionResult = null;
|
||||
_reportSubmitting = false;
|
||||
_reportPopupRequested = false;
|
||||
}
|
||||
|
||||
private bool TrySendDraft(ChatChannelSnapshot channel, string draft)
|
||||
{
|
||||
var trimmed = draft.Trim();
|
||||
@@ -513,6 +741,11 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
{
|
||||
yield return viewProfile;
|
||||
}
|
||||
|
||||
if (TryCreateReportMessageAction(channel, message, out var reportAction))
|
||||
{
|
||||
yield return reportAction;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryCreateCopyMessageAction(ChatMessageEntry message, out ChatMessageContextAction action)
|
||||
@@ -578,6 +811,23 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryCreateReportMessageAction(ChatChannelSnapshot channel, ChatMessageEntry message, out ChatMessageContextAction action)
|
||||
{
|
||||
action = default;
|
||||
if (message.FromSelf)
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(message.Payload.MessageId))
|
||||
return false;
|
||||
|
||||
action = new ChatMessageContextAction(
|
||||
"Report Message",
|
||||
true,
|
||||
() => OpenReportPopup(channel, message));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Task OpenStandardProfileAsync(UserData user)
|
||||
{
|
||||
_profileManager.GetLightlessProfile(user);
|
||||
|
||||
Reference in New Issue
Block a user