added chat report functionality and some other random stuff

This commit is contained in:
2025-11-30 19:59:37 +09:00
parent cab13874d8
commit 91393bf4a1
10 changed files with 417 additions and 53 deletions

View File

@@ -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);