diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index 2ebfe8667..3305c9949 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -22,6 +22,7 @@ using Dalamud.IoC.Internal; using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Ipc.Internal; +using Dalamud.Support; using HarmonyLib; using Serilog; using Serilog.Core; diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs index bb8fc38ea..fe7c2e792 100644 --- a/Dalamud/EntryPoint.cs +++ b/Dalamud/EntryPoint.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Dalamud.Configuration.Internal; using Dalamud.Logging.Internal; +using Dalamud.Support; using Newtonsoft.Json; using PInvoke; using Serilog; diff --git a/Dalamud/Interface/Colors/ImGuiColors.cs b/Dalamud/Interface/Colors/ImGuiColors.cs index 0e6ac69f5..341460efe 100644 --- a/Dalamud/Interface/Colors/ImGuiColors.cs +++ b/Dalamud/Interface/Colors/ImGuiColors.cs @@ -10,51 +10,51 @@ namespace Dalamud.Interface.Colors /// /// Gets red used in dalamud. /// - public static Vector4 DalamudRed { get; } = new Vector4(1f, 0f, 0f, 1f); + public static Vector4 DalamudRed { get; internal set; } = new Vector4(1f, 0f, 0f, 1f); /// /// Gets grey used in dalamud. /// - public static Vector4 DalamudGrey { get; } = new Vector4(0.7f, 0.7f, 0.7f, 1f); + public static Vector4 DalamudGrey { get; internal set; } = new Vector4(0.7f, 0.7f, 0.7f, 1f); /// /// Gets grey used in dalamud. /// - public static Vector4 DalamudGrey2 { get; } = new Vector4(0.7f, 0.7f, 0.7f, 1f); + public static Vector4 DalamudGrey2 { get; internal set; } = new Vector4(0.7f, 0.7f, 0.7f, 1f); /// /// Gets grey used in dalamud. /// - public static Vector4 DalamudGrey3 { get; } = new Vector4(0.5f, 0.5f, 0.5f, 1f); + public static Vector4 DalamudGrey3 { get; internal set; } = new Vector4(0.5f, 0.5f, 0.5f, 1f); /// /// Gets white used in dalamud. /// - public static Vector4 DalamudWhite { get; } = new Vector4(1f, 1f, 1f, 1f); + public static Vector4 DalamudWhite { get; internal set; } = new Vector4(1f, 1f, 1f, 1f); /// /// Gets white used in dalamud. /// - public static Vector4 DalamudWhite2 { get; } = new Vector4(0.878f, 0.878f, 0.878f, 1f); + public static Vector4 DalamudWhite2 { get; internal set; } = new Vector4(0.878f, 0.878f, 0.878f, 1f); /// /// Gets orange used in dalamud. /// - public static Vector4 DalamudOrange { get; } = new Vector4(1f, 0.709f, 0f, 1f); + public static Vector4 DalamudOrange { get; internal set; } = new Vector4(1f, 0.709f, 0f, 1f); /// /// Gets tank blue (UIColor37). /// - public static Vector4 TankBlue { get; } = new Vector4(0f, 0.6f, 1f, 1f); + public static Vector4 TankBlue { get; internal set; } = new Vector4(0f, 0.6f, 1f, 1f); /// /// Gets healer green (UIColor504). /// - public static Vector4 HealerGreen { get; } = new Vector4(0f, 0.8f, 0.1333333f, 1f); + public static Vector4 HealerGreen { get; internal set; } = new Vector4(0f, 0.8f, 0.1333333f, 1f); /// /// Gets dps red (UIColor545). /// - public static Vector4 DPSRed { get; } = new Vector4(0.7058824f, 0f, 0f, 1f); + public static Vector4 DPSRed { get; internal set; } = new Vector4(0.7058824f, 0f, 0f, 1f); } } diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs index f663cd168..7b001a4bd 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs @@ -22,6 +22,7 @@ using Dalamud.Plugin; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal.Exceptions; using Dalamud.Plugin.Internal.Types; +using Dalamud.Support; using Dalamud.Utility; using ImGuiNET; using ImGuiScene; @@ -67,6 +68,12 @@ namespace Dalamud.Interface.Internal.Windows private bool errorModalOnNextFrame = false; private string errorModalMessage = string.Empty; + private bool feedbackModalDrawing = true; + private bool feedbackModalOnNextFrame = false; + private string feedbackModalBody = string.Empty; + private string feedbackModalContact = string.Empty; + private PluginManifest? feedbackPlugin = null; + private int updatePluginCount = 0; private List? updatedPlugins; @@ -186,6 +193,7 @@ namespace Dalamud.Interface.Internal.Windows this.DrawPluginTabBar(); this.DrawFooter(); this.DrawErrorModal(); + this.DrawFeedbackModal(); } /// @@ -448,6 +456,65 @@ namespace Dalamud.Interface.Internal.Windows { ImGui.OpenPopup(modalTitle); this.errorModalOnNextFrame = false; + this.errorModalDrawing = true; + } + } + + private void DrawFeedbackModal() + { + var modalTitle = Locs.FeedbackModal_Title; + + if (ImGui.BeginPopupModal(modalTitle, ref this.feedbackModalDrawing, ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoScrollbar)) + { + ImGui.Text(Locs.FeedbackModal_Text); + ImGui.Spacing(); + + ImGui.InputTextMultiline("Feedback Content", ref this.feedbackModalBody, 1000, new Vector2(400, 200)); + + ImGui.Spacing(); + + ImGui.InputText("Contact Information", ref this.feedbackModalContact, 100); + + ImGui.Spacing(); + + ImGui.TextColored(ImGuiColors.DalamudGrey, Locs.FeedbackModal_Hint); + + var buttonWidth = 120f; + ImGui.SetCursorPosX((ImGui.GetWindowWidth() - buttonWidth) / 2); + + if (ImGui.Button(Locs.ErrorModalButton_Ok, new Vector2(buttonWidth, 40))) + { + if (this.feedbackPlugin != null) + { + Task.Run(async () => await BugBait.SendFeedback(this.feedbackPlugin, this.feedbackModalBody, this.feedbackModalContact)) + .ContinueWith( + t => + { + var notif = Service.Get(); + if (t.IsCanceled || t.IsFaulted) + notif.AddNotification(Locs.FeedbackModal_NotificationError, Locs.FeedbackModal_Title, NotificationType.Error); + else + notif.AddNotification(Locs.FeedbackModal_NotificationSuccess, Locs.FeedbackModal_Title, NotificationType.Success); + }); + } + else + { + Log.Error("FeedbackPlugin was null."); + } + + ImGui.CloseCurrentPopup(); + } + + ImGui.EndPopup(); + } + + if (this.feedbackModalOnNextFrame) + { + ImGui.OpenPopup(modalTitle); + this.feedbackModalOnNextFrame = false; + this.feedbackModalDrawing = true; + this.feedbackModalBody = string.Empty; + this.feedbackModalContact = string.Empty; } } @@ -1037,6 +1104,11 @@ namespace Dalamud.Interface.Internal.Windows this.DrawVisitRepoUrlButton(manifest.RepoUrl); + if (!manifest.SourceRepo.IsThirdParty) + { + this.DrawSendFeedbackButton(manifest); + } + ImGuiHelpers.ScaledDummy(5); if (this.DrawPluginImages(null, manifest, isThirdParty, index)) @@ -1261,6 +1333,11 @@ namespace Dalamud.Interface.Internal.Windows this.DrawDeletePluginButton(plugin); this.DrawVisitRepoUrlButton(plugin.Manifest.RepoUrl); + if (!isThirdParty) + { + this.DrawSendFeedbackButton(plugin.Manifest); + } + if (availablePluginUpdate != default) this.DrawUpdateSinglePluginButton(availablePluginUpdate); @@ -1465,6 +1542,21 @@ namespace Dalamud.Interface.Internal.Windows } } + private void DrawSendFeedbackButton(PluginManifest manifest) + { + ImGui.SameLine(); + if (ImGuiComponents.IconButton(FontAwesomeIcon.Comment)) + { + this.feedbackPlugin = manifest; + this.feedbackModalOnNextFrame = true; + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Locs.FeedbackModal_Title); + } + } + private void DrawDevPluginButtons(LocalPlugin localPlugin) { var configuration = Service.Get(); @@ -2165,6 +2257,20 @@ namespace Dalamud.Interface.Internal.Windows #endregion + #region Feedback Modal + + public static string FeedbackModal_Title => Loc.Localize("InstallerFeedback", "Send Feedback"); + + public static string FeedbackModal_Text => Loc.Localize("InstallerFeedbackInfo", "You can send feedback to the developer of this plugin here.\nYou can include your Discord tag or email address if you wish to give them the opportunity to answer."); + + public static string FeedbackModal_Hint => Loc.Localize("InstallerFeedbackHint", "All plugin developers will be able to see your feedback.\nPlease never include any personal or revealing information.\nThe collected feedback is not stored and immediately relayed to Discord."); + + public static string FeedbackModal_NotificationSuccess => Loc.Localize("InstallerFeedbackNotificationSuccess", "Your feedback was sent successfully!"); + + public static string FeedbackModal_NotificationError => Loc.Localize("InstallerFeedbackNotificationSuccess", "Your feedback could not be sent."); + + #endregion + #region Plugin Update chatbox public static string PluginUpdateHeader_Chatbox => Loc.Localize("DalamudPluginUpdates", "Updates:"); diff --git a/Dalamud/Support/BugBait.cs b/Dalamud/Support/BugBait.cs new file mode 100644 index 000000000..149c76617 --- /dev/null +++ b/Dalamud/Support/BugBait.cs @@ -0,0 +1,61 @@ +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +using Dalamud.Plugin.Internal.Types; +using Dalamud.Utility; +using Newtonsoft.Json; + +namespace Dalamud.Support +{ + /// + /// Class responsible for sending feedback. + /// + internal static class BugBait + { + private const string BugBaitUrl = "https://dalamud-bugbait.goatsoft.workers.dev/feedback"; + + /// + /// Send feedback to Discord. + /// + /// The plugin to send feedback about. + /// The content of the feedback. + /// The reporter name. + /// A representing the asynchronous operation. + public static async Task SendFeedback(PluginManifest plugin, string content, string reporter) + { + if (content.IsNullOrWhitespace()) + return; + + using var client = new HttpClient(); + + var model = new FeedbackModel + { + Content = content, + Reporter = reporter, + Name = plugin.InternalName, + Version = plugin.AssemblyVersion.ToString(), + }; + + var postContent = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json"); + var response = await client.PostAsync(BugBaitUrl, postContent); + + response.EnsureSuccessStatusCode(); + } + + private class FeedbackModel + { + [JsonProperty("content")] + public string? Content { get; set; } + + [JsonProperty("name")] + public string? Name { get; set; } + + [JsonProperty("version")] + public string? Version { get; set; } + + [JsonProperty("reporter")] + public string? Reporter { get; set; } + } + } +} diff --git a/Dalamud/Troubleshooting.cs b/Dalamud/Support/Troubleshooting.cs similarity index 99% rename from Dalamud/Troubleshooting.cs rename to Dalamud/Support/Troubleshooting.cs index 97b88c591..3417a9696 100644 --- a/Dalamud/Troubleshooting.cs +++ b/Dalamud/Support/Troubleshooting.cs @@ -12,7 +12,7 @@ using Dalamud.Utility; using Newtonsoft.Json; using Serilog; -namespace Dalamud +namespace Dalamud.Support { /// /// Class responsible for printing troubleshooting information to the log.