Screenie/Ui/Tabs/DatabaseTab.cs

279 lines
9.3 KiB
C#

using System.Data;
using System.Diagnostics;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility;
using ImGuiNET;
using Newtonsoft.Json;
using Screenie.Util;
namespace Screenie.Ui.Tabs;
internal class DatabaseTab : ITab {
public string Label => "Database";
private Plugin Plugin { get; }
private List<SavedMetadata> Screenshots { get; } = [];
private LinkedList<GroupBy> GroupBys { get; } = new();
private GroupBy _selectedGroupBy = GroupBy.Character;
private enum GroupBy {
Character,
World,
Year,
Month,
Day,
Location,
}
internal DatabaseTab(Plugin plugin) {
this.Plugin = plugin;
this.GroupBys.AddLast(GroupBy.Character);
this.Update();
}
public void Dispose() {
}
public void Draw() {
if (ImGui.Button("update")) {
this.Update();
}
var first = true;
GroupBy? remove = null;
foreach (var groupBy in this.GroupBys) {
ImGui.TextUnformatted(
first
? $"Group by {Enum.GetName(groupBy)}"
: $"then by {Enum.GetName(groupBy)}"
);
ImGui.SameLine();
if (ImGuiComponents.IconButton($"remove-{groupBy}", FontAwesomeIcon.Times)) {
remove = groupBy;
}
first = false;
}
if (remove != null) {
this.GroupBys.Remove(remove.Value);
}
Vector2 buttonSize;
ImGui.PushFont(UiBuilder.IconFont);
using (new OnDispose(ImGui.PopFont)) {
buttonSize = ImGuiHelpers.GetButtonSize(FontAwesomeIcon.Plus.ToIconString());
}
var comboSize = ImGui.GetContentRegionAvail().X
- buttonSize.X
- ImGui.GetStyle().ItemSpacing.X;
ImGui.SetNextItemWidth(comboSize);
if (ImGui.BeginCombo("##then-by", Enum.GetName(this._selectedGroupBy))) {
using var endCombo = new OnDispose(ImGui.EndCombo);
foreach (var groupBy in Enum.GetValues<GroupBy>()) {
var contained = this.GroupBys.Contains(groupBy);
using (ImGuiHelper.WithDisabled(contained)) {
if (ImGui.Selectable(Enum.GetName(groupBy), this._selectedGroupBy == groupBy)) {
this._selectedGroupBy = groupBy;
}
}
}
}
ImGui.SameLine();
var contains = this.GroupBys.Contains(this._selectedGroupBy);
using (ImGuiHelper.WithDisabled(contains)) {
if (ImGuiComponents.IconButton("add-group-by", FontAwesomeIcon.Plus) && !contains) {
this.GroupBys.AddLast(this._selectedGroupBy);
}
}
if (this.GroupBys.First == null) {
this.DrawShots(this.Screenshots);
} else {
this.DrawGroup(this.GroupBys.First, this.Screenshots);
}
}
private void DrawGroup(LinkedListNode<GroupBy> groupBy, IEnumerable<SavedMetadata> shots) {
var grouped = shots.GroupBy(shot => {
switch (groupBy.Value) {
case GroupBy.Character: {
var chara = shot.Metadata.ActiveCharacter;
if (chara == null) {
return null;
}
return $"{chara.Name} ({chara.HomeWorld})";
}
case GroupBy.World: {
return shot.Metadata.World;
}
case GroupBy.Year: {
return shot.Metadata
.CapturedAtUtc
.ToLocalTime()
.ToString("yyyy");
}
case GroupBy.Month: {
return shot.Metadata
.CapturedAtUtc
.ToLocalTime()
.ToString("MMMM");
}
case GroupBy.Day: {
return shot.Metadata
.CapturedAtUtc
.ToLocalTime()
.ToString("dd");
}
case GroupBy.Location: {
return shot.Metadata.Location;
}
default: {
return null;
}
}
});
foreach (var grouping in grouped) {
var label = grouping.Key;
ImGui.PushID($"{Enum.GetName(groupBy.Value)}-{label}");
using var popId = new OnDispose(ImGui.PopID);
if (!ImGui.TreeNodeEx(label ?? "<unknown>")) {
continue;
}
using var treePop = new OnDispose(ImGui.TreePop);
if (groupBy.Next == null) {
this.DrawShots(grouping);
} else {
this.DrawGroup(groupBy.Next, grouping);
}
}
}
private void DrawShots(IEnumerable<SavedMetadata> shots) {
foreach (var shot in shots) {
this.DrawShot(shot);
}
}
private void DrawShot(SavedMetadata shot) {
var fileName = Path.GetFileName(shot.Path);
if (!ImGui.TreeNodeEx($"{fileName}##shot-{shot.Path}-{shot.Blake3Hash}")) {
return;
}
using var treePop = new OnDispose(ImGui.TreePop);
var availWidth = ImGui.GetContentRegionAvail().X;
var buttonWidth = availWidth / 2 - ImGui.GetStyle().ItemSpacing.X / 2;
if (ImGui.Button("Open", new Vector2(buttonWidth, 0))) {
Process.Start(new ProcessStartInfo(shot.Path) {
UseShellExecute = true,
});
}
ImGui.SameLine();
if (ImGui.Button("View", new Vector2(buttonWidth, 0))) {
this.Plugin.Ui.Drawables.Add(new Viewer(this.Plugin, shot.Path));
}
if (ImGui.CollapsingHeader("Players visible in shot")) {
if (shot.Metadata.VisibleCharacters.Length == 0) {
ImGui.TextUnformatted("None");
}
var viewers = this.Plugin.Ui.Drawables
.Where(drawable => drawable is Viewer)
.Cast<Viewer>()
.Where(viewer => viewer.ImagePath == shot.Path)
.ToList();
var anyHovered = false;
foreach (var chara in shot.Metadata.VisibleCharacters) {
ImGui.TextUnformatted($"{chara.Name} ({chara.HomeWorld})");
if (ImGui.IsItemHovered()) {
foreach (var viewer in viewers) {
anyHovered = true;
viewer.DotPosition = chara.ImagePosition;
}
}
}
if (!anyHovered) {
foreach (var viewer in viewers) {
viewer.DotPosition = null;
}
}
}
if (ImGui.CollapsingHeader("Mods visible in shot")) {
if (shot.Metadata.ModsInUse.Length == 0) {
ImGui.TextUnformatted("None");
}
foreach (var mod in shot.Metadata.ModsInUse) {
ImGui.TextUnformatted(mod.Name);
}
}
}
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>("hash"),
Path = reader.GetFieldValue<string>("path"),
Metadata = new ScreenshotMetadata {
ActiveCharacter = JsonConvert.DeserializeObject<Character>(
reader.GetFieldValue<string>("active_character")
),
Location = reader.GetNullableFieldValue<string>("location"),
LocationSub = reader.GetNullableFieldValue<string>("location_sub"),
Area = reader.GetNullableFieldValue<string>("area"),
AreaSub = reader.GetNullableFieldValue<string>("area_sub"),
TerritoryType = (uint) reader.GetFieldValue<int>("territory_type"),
World = reader.GetNullableFieldValue<string>("world"),
WorldId = (uint) reader.GetFieldValue<int>("world_id"),
CapturedAtLocal = reader.GetFieldValue<DateTime>("captured_at_local"),
CapturedAtUtc = reader.GetFieldValue<DateTime>("captured_at_utc"),
EorzeaTime = reader.GetFieldValue<string>("eorzea_time"),
Weather = reader.GetNullableFieldValue<string>("weather"),
Ward = (uint?) reader.GetNullableFieldValue<int>("ward"),
Plot = (uint?) reader.GetNullableFieldValue<int>("plot"),
VisibleCharacters = JsonConvert.DeserializeObject<Character[]>(
reader.GetFieldValue<string>("visible_characters")
) ?? [],
ModsInUse = JsonConvert.DeserializeObject<PenumbraMod[]>(
reader.GetFieldValue<string>("mods_in_use")
) ?? [],
},
};
this.Screenshots.Add(meta);
}
}
}