feat: start adding database tab

This commit is contained in:
Anna 2024-02-18 12:23:04 -05:00
parent 085b1c3edb
commit b6fdf67368
Signed by: anna
GPG Key ID: D0943384CD9F87D1
8 changed files with 256 additions and 128 deletions

View File

@ -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<string, object?> {
["$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),
}
);

View File

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

View File

@ -1,5 +1,6 @@
using Penumbra.Api.Helpers;
using Screenie;
namespace Screenie;
internal class PenumbraIpc {
private Plugin Plugin { get; }

View File

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

View File

@ -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<ITab> 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<Format>()) {
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;
}
}

72
Ui/Tabs/DatabaseTab.cs Normal file
View File

@ -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<SavedMetadata> 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<string>(0),
Path = reader.GetFieldValue<string>(1),
Metadata = new ScreenshotMetadata {
ActiveCharacter = JsonConvert.DeserializeObject<Character>(
reader.GetFieldValue<string>(2)
),
Location = reader.GetFieldValue<string?>(3),
LocationSub = reader.GetFieldValue<string?>(4),
Area = reader.GetFieldValue<string?>(5),
AreaSub = reader.GetFieldValue<string?>(6),
TerritoryType = (uint) reader.GetFieldValue<long>(7),
World = reader.GetFieldValue<string?>(8),
WorldId = (uint) reader.GetFieldValue<long>(9),
CapturedAtLocal = reader.GetFieldValue<DateTime>(10),
CapturedAtUtc = reader.GetFieldValue<DateTime>(11),
EorzeaTime = reader.GetFieldValue<string>(12),
Weather = reader.GetFieldValue<string?>(13),
Ward = (uint?) reader.GetFieldValue<long?>(14),
Plot = (uint?) reader.GetFieldValue<long?>(15),
VisibleCharacters = JsonConvert.DeserializeObject<Character[]>(
reader.GetFieldValue<string>(16)
) ?? [],
ModsInUse = JsonConvert.DeserializeObject<PenumbraMod[]>(
reader.GetFieldValue<string>(17)
) ?? [],
},
};
this.Screenshots.Add(meta);
}
}
}

7
Ui/Tabs/ITab.cs Normal file
View File

@ -0,0 +1,7 @@
namespace Screenie.Ui.Tabs;
interface ITab : IDisposable {
public string Label { get; }
public void Draw();
}

146
Ui/Tabs/SettingsTab.cs Normal file
View File

@ -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<Format>()) {
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;
}
}