From b6fdf673682de83548f66244041d4ea71fc0d23a Mon Sep 17 00:00:00 2001 From: Anna Date: Sun, 18 Feb 2024 12:23:04 -0500 Subject: [PATCH] feat: start adding database tab --- Command.cs | 6 +- Database.cs | 7 +- PenumbraIpc.cs | 3 +- ScreenshotMetadata.cs | 4 -- Ui/PluginUi.cs | 139 ++++++--------------------------------- Ui/Tabs/DatabaseTab.cs | 72 ++++++++++++++++++++ Ui/Tabs/ITab.cs | 7 ++ Ui/Tabs/SettingsTab.cs | 146 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 256 insertions(+), 128 deletions(-) create mode 100644 Ui/Tabs/DatabaseTab.cs create mode 100644 Ui/Tabs/ITab.cs create mode 100644 Ui/Tabs/SettingsTab.cs diff --git a/Command.cs b/Command.cs index d45c1cb..0c2ecd4 100644 --- a/Command.cs +++ b/Command.cs @@ -66,6 +66,7 @@ internal class Command : IDisposable { return; } + // TODO: use TagLib-Sharp to embed metadata into the image string hash; var (inner, path) = this.OpenFile(ext, meta); await using (var stream = new Blake3Stream(inner)) { @@ -82,8 +83,8 @@ internal class Command : IDisposable { this.Plugin.Database.Execute( """ insert into screenshots - (hash, path, active_character, location, location_sub, area, area_sub, territory_type, world, world_id, captured_at_local, captured_at_utc, eorzea_time, weather, ward, plot, visible_characters) - values ($hash, $path, json($active_character), $location, $location_sub, $area, $area_sub, $territory_type, $world, $world_id, $captured_at_local, $captured_at_utc, $eorzea_time, $weather, $ward, $plot, json($visible_characters)) + (hash, path, active_character, location, location_sub, area, area_sub, territory_type, world, world_id, captured_at_local, captured_at_utc, eorzea_time, weather, ward, plot, visible_characters, mods_in_use) + values ($hash, $path, json($active_character), $location, $location_sub, $area, $area_sub, $territory_type, $world, $world_id, $captured_at_local, $captured_at_utc, $eorzea_time, $weather, $ward, $plot, json($visible_characters), json($mods_in_use)) """, new Dictionary { ["$hash"] = saved.Blake3Hash, @@ -103,6 +104,7 @@ internal class Command : IDisposable { ["$ward"] = saved.Metadata.Ward, ["$plot"] = saved.Metadata.Plot, ["$visible_characters"] = JsonConvert.SerializeObject(saved.Metadata.VisibleCharacters), + ["$mods_in_use"] = JsonConvert.SerializeObject(saved.Metadata.ModsInUse), } ); diff --git a/Database.cs b/Database.cs index f5a169a..6f6182f 100644 --- a/Database.cs +++ b/Database.cs @@ -51,13 +51,14 @@ internal class Database : IDisposable { territory_type int not null, world text, world_id int not null, - captured_at_local timestamp, - captured_at_utc timestamp, + captured_at_local timestamp not null, + captured_at_utc timestamp not null, eorzea_time text not null, weather text, ward int, plot int, - visible_characters jsonb not null + visible_characters jsonb not null, + mods_in_use jsonb not null ) """; this.Execute(migrationOne); diff --git a/PenumbraIpc.cs b/PenumbraIpc.cs index e319c94..f102320 100644 --- a/PenumbraIpc.cs +++ b/PenumbraIpc.cs @@ -1,5 +1,6 @@ using Penumbra.Api.Helpers; -using Screenie; + +namespace Screenie; internal class PenumbraIpc { private Plugin Plugin { get; } diff --git a/ScreenshotMetadata.cs b/ScreenshotMetadata.cs index 18d76d2..e210245 100644 --- a/ScreenshotMetadata.cs +++ b/ScreenshotMetadata.cs @@ -141,10 +141,6 @@ public class ScreenshotMetadata { } } - foreach (var mod in modsInUse.OrderBy(mod => mod.Name)) { - Plugin.Log.Info($"{mod.Name} at {mod.Path}"); - } - return new ScreenshotMetadata { ActiveCharacter = active, Location = map?.PlaceName.Value?.Name.ToDalamudString().TextValue.WhitespaceToNull() diff --git a/Ui/PluginUi.cs b/Ui/PluginUi.cs index c00edd6..6050159 100644 --- a/Ui/PluginUi.cs +++ b/Ui/PluginUi.cs @@ -1,28 +1,22 @@ -using System.Diagnostics; using System.Numerics; -using Dalamud.Interface; -using Dalamud.Interface.Components; -using Dalamud.Interface.ImGuiFileDialog; -using Dalamud.Interface.Utility; using ImGuiNET; +using Screenie.Ui.Tabs; using Screenie.Util; namespace Screenie.Ui; internal class PluginUi : IDisposable { private Plugin Plugin { get; } - private FileDialogManager FileDialogManager { get; } - private ScreenshotMetadata Metadata { get; set; } + private List Tabs { get; } = []; internal bool Visible; - private const int RefreshSeconds = 5; - private readonly Stopwatch _metaUpdate = Stopwatch.StartNew(); - internal PluginUi(Plugin plugin) { this.Plugin = plugin; - this.FileDialogManager = new FileDialogManager(); - this.Metadata = ScreenshotMetadata.Capture(this.Plugin); + this.Tabs.AddRange([ + new SettingsTab(this.Plugin), + new DatabaseTab(this.Plugin), + ]); this.Plugin.Interface.UiBuilder.Draw += this.Draw; this.Plugin.Interface.UiBuilder.OpenConfigUi += this.OpenConfigUi; @@ -31,6 +25,10 @@ internal class PluginUi : IDisposable { public void Dispose() { this.Plugin.Interface.UiBuilder.OpenConfigUi -= this.OpenConfigUi; this.Plugin.Interface.UiBuilder.Draw -= this.Draw; + + foreach (var tab in this.Tabs) { + tab.Dispose(); + } } private void OpenConfigUi() { @@ -38,22 +36,10 @@ internal class PluginUi : IDisposable { } private void Draw() { - try { - this.FileDialogManager.Draw(); - } catch (Exception e) { - Plugin.Log.Error(e, "Error in FileDialogManager.Draw"); - } - if (!this.Visible) { return; } - if (this._metaUpdate.Elapsed >= TimeSpan.FromSeconds(RefreshSeconds)) { - this.Metadata = ScreenshotMetadata.Capture(this.Plugin); - - this._metaUpdate.Restart(); - } - using var end = new OnDispose(ImGui.End); ImGui.SetNextWindowSize(new Vector2(420, 500), ImGuiCond.FirstUseEver); @@ -64,106 +50,23 @@ internal class PluginUi : IDisposable { ImGui.PushTextWrapPos(); using var popTextWrapPos = new OnDispose(ImGui.PopTextWrapPos); - var anyChanged = false; - anyChanged |= this.DrawScreenshotsFolderInput(); + if (!ImGui.BeginTabBar("##screenie-tabbar")) { + return; + } - ImGui.TextUnformatted("Save format"); - ImGui.SetNextItemWidth(-1); - if (ImGui.BeginCombo("##file-format", this.Plugin.Config.SaveFormat.Name())) { - using var endCombo = new OnDispose(ImGui.EndCombo); - foreach (var format in Enum.GetValues()) { - if (ImGui.Selectable(format.Name(), this.Plugin.Config.SaveFormat == format)) { - this.Plugin.Config.SaveFormat = format; - anyChanged = true; - } + using var endTabBar = new OnDispose(ImGui.EndTabBar); + + foreach (var tab in this.Tabs) { + if (!ImGui.BeginTabItem(tab.Label)) { + continue; } - } - var label = this.Plugin.Config.SaveFormat switch { - Format.Jpg => "Quality", - Format.WebpLossless => null, - Format.WebpLossy => "Quality", - Format.Png => "Compression level", - _ => "Unknown", - }; - - if (label != null) { - ImGui.TextUnformatted(label); - ImGui.SetNextItemWidth(-1); - anyChanged |= ImGui.SliderInt("##format-data", ref this.Plugin.Config.SaveFormatData, 0, 100); - } - - ImGui.TextUnformatted("Filename format"); - ImGui.SetNextItemWidth(-1); - ImGui.PushFont(UiBuilder.MonoFont); - using (new OnDispose(ImGui.PopFont)) { - anyChanged |= ImGui.InputTextMultiline( - "##filename-format", - ref this.Plugin.Config.SaveFileNameFormat, - 2048, - new Vector2(-1, 150) - ); - } - - var template = this.Plugin.Config.SaveFileNameTemplate; - if (template.HasErrors) { - ImGui.TextUnformatted("Invalid template"); - foreach (var error in template.Messages) { - ImGui.Bullet(); - ImGui.SameLine(); - ImGui.TextUnformatted(error.Message); - } - } else { + using var endTabItem = new OnDispose(ImGui.EndTabItem); try { - ImGui.TextUnformatted(this.Plugin.Config.SaveFileNameTemplate.Render(this.Metadata).ReplaceLineEndings(" ")); + tab.Draw(); } catch (Exception ex) { - ImGui.TextUnformatted($"Failed to evaluate: {ex.Message}"); + Plugin.Log.Error(ex, $"Error drawing tab \"{tab.Label}\""); } } - - ImGui.ProgressBar( - (float) (TimeSpan.FromSeconds(RefreshSeconds) - this._metaUpdate.Elapsed).TotalSeconds / RefreshSeconds, - new Vector2(-1, 1) - ); - - if (anyChanged) { - this.Plugin.SaveConfig(); - } - } - - private bool DrawScreenshotsFolderInput() { - ImGui.TextUnformatted("Screenshots folder"); - - var changed = false; - ImGui.PushFont(UiBuilder.IconFont); - Vector2 size; - using (new OnDispose(ImGui.PopFont)) { - size = ImGuiHelpers.GetButtonSize(FontAwesomeIcon.Folder.ToIconString()); - } - - var availWidth = ImGui.GetContentRegionAvail().X; - ImGui.SetNextItemWidth(availWidth - size.X - ImGui.GetStyle().ItemSpacing.X); - if (ImGui.InputText("##save-directory", ref this.Plugin.Config.SaveDirectory, 1024, ImGuiInputTextFlags.EnterReturnsTrue)) { - changed = true; - } - - ImGui.SameLine(); - - if (ImGuiComponents.IconButton("browse-save-dir", FontAwesomeIcon.Folder)) { - this.FileDialogManager.OpenFolderDialog( - "Choose screenshots folder", - (b, s) => { - if (!b) { - return; - } - - this.Plugin.Config.SaveDirectory = s; - this.Plugin.SaveConfig(); - }, - Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) - ); - } - - return changed; } } diff --git a/Ui/Tabs/DatabaseTab.cs b/Ui/Tabs/DatabaseTab.cs new file mode 100644 index 0000000..ec0c027 --- /dev/null +++ b/Ui/Tabs/DatabaseTab.cs @@ -0,0 +1,72 @@ +using ImGuiNET; +using Newtonsoft.Json; + +namespace Screenie.Ui.Tabs; + +internal class DatabaseTab : ITab { + public string Label => "Database"; + + private Plugin Plugin { get; } + private List Screenshots { get; } = []; + + internal DatabaseTab(Plugin plugin) { + this.Plugin = plugin; + + this.Update(); + } + + public void Dispose() { + } + + public void Draw() { + if (ImGui.Button("update")) { + this.Update(); + } + + foreach (var meta in this.Screenshots) { + ImGui.TextUnformatted(meta.Path); + } + } + + private void Update() { + using var reader = this.Plugin.Database.Query( + """ + select * from screenshots order by captured_at_utc desc + """ + ); + + this.Screenshots.Clear(); + while (reader.Read()) { + var meta = new SavedMetadata { + Blake3Hash = reader.GetFieldValue(0), + Path = reader.GetFieldValue(1), + Metadata = new ScreenshotMetadata { + ActiveCharacter = JsonConvert.DeserializeObject( + reader.GetFieldValue(2) + ), + Location = reader.GetFieldValue(3), + LocationSub = reader.GetFieldValue(4), + Area = reader.GetFieldValue(5), + AreaSub = reader.GetFieldValue(6), + TerritoryType = (uint) reader.GetFieldValue(7), + World = reader.GetFieldValue(8), + WorldId = (uint) reader.GetFieldValue(9), + CapturedAtLocal = reader.GetFieldValue(10), + CapturedAtUtc = reader.GetFieldValue(11), + EorzeaTime = reader.GetFieldValue(12), + Weather = reader.GetFieldValue(13), + Ward = (uint?) reader.GetFieldValue(14), + Plot = (uint?) reader.GetFieldValue(15), + VisibleCharacters = JsonConvert.DeserializeObject( + reader.GetFieldValue(16) + ) ?? [], + ModsInUse = JsonConvert.DeserializeObject( + reader.GetFieldValue(17) + ) ?? [], + }, + }; + + this.Screenshots.Add(meta); + } + } +} diff --git a/Ui/Tabs/ITab.cs b/Ui/Tabs/ITab.cs new file mode 100644 index 0000000..cf731d8 --- /dev/null +++ b/Ui/Tabs/ITab.cs @@ -0,0 +1,7 @@ +namespace Screenie.Ui.Tabs; + +interface ITab : IDisposable { + public string Label { get; } + + public void Draw(); +} diff --git a/Ui/Tabs/SettingsTab.cs b/Ui/Tabs/SettingsTab.cs new file mode 100644 index 0000000..91eca0e --- /dev/null +++ b/Ui/Tabs/SettingsTab.cs @@ -0,0 +1,146 @@ +using System.Diagnostics; +using System.Numerics; +using Dalamud.Interface; +using Dalamud.Interface.Components; +using Dalamud.Interface.ImGuiFileDialog; +using Dalamud.Interface.Utility; +using ImGuiNET; +using Screenie.Util; + +namespace Screenie.Ui.Tabs; + +internal class SettingsTab : ITab { + public string Label => "Settings"; + + private Plugin Plugin { get; } + private FileDialogManager FileDialogManager { get; } + private ScreenshotMetadata Metadata { get; set; } + + private const int RefreshSeconds = 5; + private readonly Stopwatch _metaUpdate = Stopwatch.StartNew(); + + internal SettingsTab(Plugin plugin) { + this.Plugin = plugin; + this.FileDialogManager = new FileDialogManager(); + this.Metadata = ScreenshotMetadata.Capture(this.Plugin); + } + + public void Dispose() { + } + + public void Draw() { + try { + this.FileDialogManager.Draw(); + } catch (Exception e) { + Plugin.Log.Error(e, "Error in FileDialogManager.Draw"); + } + + if (this._metaUpdate.Elapsed >= TimeSpan.FromSeconds(RefreshSeconds)) { + this.Metadata = ScreenshotMetadata.Capture(this.Plugin); + + this._metaUpdate.Restart(); + } + + var anyChanged = false; + anyChanged |= this.DrawScreenshotsFolderInput(); + + ImGui.TextUnformatted("Save format"); + ImGui.SetNextItemWidth(-1); + if (ImGui.BeginCombo("##file-format", this.Plugin.Config.SaveFormat.Name())) { + using var endCombo = new OnDispose(ImGui.EndCombo); + foreach (var format in Enum.GetValues()) { + if (ImGui.Selectable(format.Name(), this.Plugin.Config.SaveFormat == format)) { + this.Plugin.Config.SaveFormat = format; + anyChanged = true; + } + } + } + + var label = this.Plugin.Config.SaveFormat switch { + Format.Jpg => "Quality", + Format.WebpLossless => null, + Format.WebpLossy => "Quality", + Format.Png => "Compression level", + _ => "Unknown", + }; + + if (label != null) { + ImGui.TextUnformatted(label); + ImGui.SetNextItemWidth(-1); + anyChanged |= ImGui.SliderInt("##format-data", ref this.Plugin.Config.SaveFormatData, 0, 100); + } + + ImGui.TextUnformatted("Filename format"); + ImGui.SetNextItemWidth(-1); + ImGui.PushFont(UiBuilder.MonoFont); + using (new OnDispose(ImGui.PopFont)) { + anyChanged |= ImGui.InputTextMultiline( + "##filename-format", + ref this.Plugin.Config.SaveFileNameFormat, + 2048, + new Vector2(-1, 150) + ); + } + + var template = this.Plugin.Config.SaveFileNameTemplate; + if (template.HasErrors) { + ImGui.TextUnformatted("Invalid template"); + foreach (var error in template.Messages) { + ImGui.Bullet(); + ImGui.SameLine(); + ImGui.TextUnformatted(error.Message); + } + } else { + try { + ImGui.TextUnformatted(this.Plugin.Config.SaveFileNameTemplate.Render(this.Metadata).ReplaceLineEndings(" ")); + } catch (Exception ex) { + ImGui.TextUnformatted($"Failed to evaluate: {ex.Message}"); + } + } + + ImGui.ProgressBar( + (float) (TimeSpan.FromSeconds(RefreshSeconds) - this._metaUpdate.Elapsed).TotalSeconds / RefreshSeconds, + new Vector2(-1, 1) + ); + + if (anyChanged) { + this.Plugin.SaveConfig(); + } + } + + private bool DrawScreenshotsFolderInput() { + ImGui.TextUnformatted("Screenshots folder"); + + var changed = false; + ImGui.PushFont(UiBuilder.IconFont); + Vector2 size; + using (new OnDispose(ImGui.PopFont)) { + size = ImGuiHelpers.GetButtonSize(FontAwesomeIcon.Folder.ToIconString()); + } + + var availWidth = ImGui.GetContentRegionAvail().X; + ImGui.SetNextItemWidth(availWidth - size.X - ImGui.GetStyle().ItemSpacing.X); + if (ImGui.InputText("##save-directory", ref this.Plugin.Config.SaveDirectory, 1024, ImGuiInputTextFlags.EnterReturnsTrue)) { + changed = true; + } + + ImGui.SameLine(); + + if (ImGuiComponents.IconButton("browse-save-dir", FontAwesomeIcon.Folder)) { + this.FileDialogManager.OpenFolderDialog( + "Choose screenshots folder", + (b, s) => { + if (!b) { + return; + } + + this.Plugin.Config.SaveDirectory = s; + this.Plugin.SaveConfig(); + }, + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + ); + } + + return changed; + } +}