diff --git a/HellionChat/PluginHostFactory.cs b/HellionChat/PluginHostFactory.cs index ad99d10..ece7946 100644 --- a/HellionChat/PluginHostFactory.cs +++ b/HellionChat/PluginHostFactory.cs @@ -180,6 +180,9 @@ internal static class PluginHostFactory services.AddSingleton(sp => new Ui.Components.Settings.Tabs.ChannelsTab( sp.GetRequiredService() )); + services.AddSingleton(sp => new Ui.Components.Settings.Tabs.DataPrivacyTab( + sp.GetRequiredService() + )); services.AddSingleton(sp => new Ui.Components.StatusBar( sp.GetRequiredService(), sp.GetRequiredService() diff --git a/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs b/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs new file mode 100644 index 0000000..043aa31 --- /dev/null +++ b/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs @@ -0,0 +1,117 @@ +using Dalamud.Bindings.ImGui; +using HellionChat.Code; + +namespace HellionChat.Ui.Components.Settings.Tabs; + +internal sealed class DataPrivacyTab +{ + private readonly Plugin _plugin; + + public DataPrivacyTab(Plugin plugin) + { + _plugin = plugin; + } + + public void Draw() + { + if (ImGui.CollapsingHeader("Logging", ImGuiTreeNodeFlags.DefaultOpen)) + { + DrawToggle( + "Print changelog on update", + () => Plugin.Config.PrintChangelog, + v => Plugin.Config.PrintChangelog = v + ); + DrawToggle( + "Enable retention sweep", + () => Plugin.Config.RetentionEnabled, + v => Plugin.Config.RetentionEnabled = v + ); + DrawSliderInt( + "Default retention (days)", + () => Plugin.Config.RetentionDefaultDays, + v => Plugin.Config.RetentionDefaultDays = v, + 1, + 365 + ); + + // RetentionLastRunAt defaults to MinValue on a fresh install, which + // would render as "0001-01-01 00:00" and look like a bug; the "Never" + // sentinel handles that. Disabling the sweep does NOT reset the + // timestamp — the historical last-run value is kept as informational + // carry-over until the next sweep updates it. + var lastRun = + Plugin.Config.RetentionLastRunAt == DateTimeOffset.MinValue + ? "Never" + : Plugin.Config.RetentionLastRunAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm"); + ImGui.TextDisabled($"Last run: {lastRun}"); + } + + if (ImGui.CollapsingHeader("Privacy filter", ImGuiTreeNodeFlags.DefaultOpen)) + { + DrawToggle( + "Enable privacy filter", + () => Plugin.Config.PrivacyFilterEnabled, + v => Plugin.Config.PrivacyFilterEnabled = v + ); + DrawPrivacyPersistChannelsGrid(); + DrawToggle( + "Persist unknown channels", + () => Plugin.Config.PrivacyPersistUnknownChannels, + v => Plugin.Config.PrivacyPersistUnknownChannels = v + ); + } + + if (ImGui.CollapsingHeader("Telemetry")) + { + // Read-only placeholder; no telemetry is wired in v1.7.0. Do not + // promote this to a toggle without an explicit Sub-Spec change. + ImGui.TextUnformatted("No telemetry is collected."); + } + } + + private void DrawPrivacyPersistChannelsGrid() + { + // HashSet: iterate Enum.GetValues() for stable + // display order (HashSet itself has none); toggle membership via + // Contains/Add/Remove. + ImGui.TextUnformatted("Persist channels:"); + foreach (var ct in Enum.GetValues()) + { + var label = ct.ToString(); + var present = Plugin.Config.PrivacyPersistChannels.Contains(ct); + if (ImGui.Checkbox($"{label}##privacy-persist-{label}", ref present)) + { + if (present) + { + Plugin.Config.PrivacyPersistChannels.Add(ct); + } + else + { + Plugin.Config.PrivacyPersistChannels.Remove(ct); + } + _plugin.SaveConfig(); + } + } + } + + private void DrawToggle(string label, Func get, Action set) + { + var current = get(); + if (ImGui.Checkbox(label, ref current)) + { + set(current); + _plugin.SaveConfig(); + } + } + + private void DrawSliderInt(string label, Func get, Action set, int min, int max) + { + var current = get(); + ImGui.SetNextItemWidth(200); + if (ImGui.SliderInt(label, ref current, min, max, "%d")) + { + set(current); + _plugin.SaveConfig(); + } + } +} diff --git a/HellionChat/Ui/Windows/SettingsWindow.cs b/HellionChat/Ui/Windows/SettingsWindow.cs index a2021e9..a52880c 100644 --- a/HellionChat/Ui/Windows/SettingsWindow.cs +++ b/HellionChat/Ui/Windows/SettingsWindow.cs @@ -24,6 +24,7 @@ internal sealed class SettingsWindow : Window private readonly ChatTab _chat; private readonly WindowTab _window; private readonly ChannelsTab _channels; + private readonly DataPrivacyTab _dataPrivacy; public SettingsWindow( Plugin plugin, @@ -37,6 +38,7 @@ internal sealed class SettingsWindow : Window ChatTab chat, WindowTab window, ChannelsTab channels, + DataPrivacyTab dataPrivacy, ILoggerFactory loggerFactory ) : base($"{Language.Settings_Title.Format(Plugin.PluginName)}###chat2-settings") @@ -52,6 +54,7 @@ internal sealed class SettingsWindow : Window _chat = chat; _window = window; _channels = channels; + _dataPrivacy = dataPrivacy; _ = loggerFactory; Size = new Vector2(720, 540); @@ -92,6 +95,9 @@ internal sealed class SettingsWindow : Window case "channels": _channels.Draw(); break; + case "data-privacy": + _dataPrivacy.Draw(); + break; case "appearance": _appearance.Draw(); break;