feat: start adding database tab
This commit is contained in:
parent
085b1c3edb
commit
b6fdf67368
|
@ -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),
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Penumbra.Api.Helpers;
|
||||
using Screenie;
|
||||
|
||||
namespace Screenie;
|
||||
|
||||
internal class PenumbraIpc {
|
||||
private Plugin Plugin { get; }
|
||||
|
|
|
@ -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()
|
||||
|
|
139
Ui/PluginUi.cs
139
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<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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace Screenie.Ui.Tabs;
|
||||
|
||||
interface ITab : IDisposable {
|
||||
public string Label { get; }
|
||||
|
||||
public void Draw();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue