From d520c4cb11e3366e059c5bda42529945714d5545 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Fri, 20 Sep 2024 00:35:33 +0200 Subject: [PATCH] Add import/export functionality to priority window --- Questionable/Controller/CommandHandler.cs | 4 +- Questionable/Windows/PriorityWindow.cs | 81 ++++++++++++++++++++++- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Questionable/Controller/CommandHandler.cs b/Questionable/Controller/CommandHandler.cs index d532b0ea5..4f80f53b5 100644 --- a/Questionable/Controller/CommandHandler.cs +++ b/Questionable/Controller/CommandHandler.cs @@ -14,8 +14,8 @@ namespace Questionable.Controller; internal sealed class CommandHandler : IDisposable { - private const string MessageTag = "Questionable"; - private const ushort TagColor = 576; + public const string MessageTag = "Questionable"; + public const ushort TagColor = 576; private readonly ICommandManager _commandManager; private readonly IChatGui _chatGui; diff --git a/Questionable/Windows/PriorityWindow.cs b/Questionable/Windows/PriorityWindow.cs index 346ca0eb5..912d7b6d5 100644 --- a/Questionable/Windows/PriorityWindow.cs +++ b/Questionable/Windows/PriorityWindow.cs @@ -1,11 +1,14 @@ using System; +using System.Buffers.Text; using System.Collections.Generic; using System.Linq; using System.Numerics; +using System.Text; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Components; using Dalamud.Plugin; +using Dalamud.Plugin.Services; using ImGuiNET; using LLib.ImGui; using Questionable.Controller; @@ -18,18 +21,23 @@ namespace Questionable.Windows; internal sealed class PriorityWindow : LWindow { + private const string ClipboardPrefix = "qst:v1:"; + private const char ClipboardSeparator = ';'; + private readonly QuestController _questController; private readonly QuestRegistry _questRegistry; private readonly QuestFunctions _questFunctions; private readonly QuestTooltipComponent _questTooltipComponent; private readonly UiUtils _uiUtils; + private readonly IChatGui _chatGui; private readonly IDalamudPluginInterface _pluginInterface; private string _searchString = string.Empty; private ElementId? _draggedItem; public PriorityWindow(QuestController questController, QuestRegistry questRegistry, QuestFunctions questFunctions, - QuestTooltipComponent questTooltipComponent, UiUtils uiUtils, IDalamudPluginInterface pluginInterface) + QuestTooltipComponent questTooltipComponent, UiUtils uiUtils, IChatGui chatGui, + IDalamudPluginInterface pluginInterface) : base("Quest Priority###QuestionableQuestPriority") { _questController = questController; @@ -37,6 +45,7 @@ internal sealed class PriorityWindow : LWindow _questFunctions = questFunctions; _questTooltipComponent = questTooltipComponent; _uiUtils = uiUtils; + _chatGui = chatGui; _pluginInterface = pluginInterface; Size = new Vector2(400, 400); @@ -53,6 +62,18 @@ internal sealed class PriorityWindow : LWindow ImGui.Text("Quests to do first:"); DrawQuestFilter(); DrawQuestList(); + + List clipboardItems = ParseClipboardItems(); + ImGui.BeginDisabled(clipboardItems.Count == 0); + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Download, "Import from Clipboard")) + ImportFromClipboard(clipboardItems); + ImGui.EndDisabled(); + ImGui.SameLine(); + ImGui.BeginDisabled(_questController.ManualPriorityQuests.Count == 0); + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Upload, "Export to Clibpoard")) + ExportToClipboard(); + ImGui.EndDisabled(); + ImGui.Spacing(); ImGui.Separator(); @@ -221,4 +242,62 @@ internal sealed class PriorityWindow : LWindow priorityQuests.Insert(indexToAdd, itemToAdd); } } + + private List ParseClipboardItems() + { + List clipboardItems = new List(); + try + { + string? clipboardText = GetClipboardText(); + if (clipboardText != null && clipboardText.StartsWith(ClipboardPrefix, StringComparison.InvariantCulture)) + { + clipboardText = clipboardText.Substring(ClipboardPrefix.Length); + string text = Encoding.UTF8.GetString(Convert.FromBase64String(clipboardText)); + foreach (string part in text.Split(ClipboardSeparator)) + { + ElementId elementId = ElementId.FromString(part); + clipboardItems.Add(elementId); + } + } + } + catch (Exception) + { + clipboardItems.Clear(); + } + + return clipboardItems; + } + + private void ExportToClipboard() + { + string clipboardText = ClipboardPrefix + Convert.ToBase64String(Encoding.UTF8.GetBytes( + string.Join(ClipboardSeparator, _questController.ManualPriorityQuests.Select(x => x.Id.ToString())))); + ImGui.SetClipboardText(clipboardText); + _chatGui.Print("Copied quests to clipboard.", CommandHandler.MessageTag, CommandHandler.TagColor); + } + + private void ImportFromClipboard(List clipboardItems) + { + foreach (ElementId elementId in clipboardItems) + { + if (_questRegistry.TryGetQuest(elementId, out Quest? quest) && + !_questController.ManualPriorityQuests.Contains(quest)) + _questController.ManualPriorityQuests.Add(quest); + } + } + + /// + /// The default implementation for throws an NullReferenceException if the clipboard is empty, maybe also if it doesn't contain text. + /// + private unsafe string? GetClipboardText() + { + byte* ptr = ImGuiNative.igGetClipboardText(); + if (ptr == null) + return null; + + int byteCount = 0; + while (ptr[byteCount] != 0) + ++byteCount; + return Encoding.UTF8.GetString(ptr, byteCount); + } }