feat(ux): explicit cancel affordance on first-run wizard (F8.1+F8.2)

Splits accept from close: OnClose no longer silently sets
FirstRunCompleted, so the X-button leaves the wizard pending and it
reopens on the next plugin load. A new footer 'Later — keep defaults'
button is the explicit path to dismiss the wizard without picking a
profile; defaults stay active and the choice persists.

Strings are bilingual (EN + DE) with a tooltip explaining the
behaviour. Card height now reserves room for the footer separator.
This commit is contained in:
2026-05-12 13:31:53 +02:00
parent 4ecbaf2a4b
commit 8d9151c74a
4 changed files with 38 additions and 9 deletions
+2
View File
@@ -114,6 +114,8 @@ internal class HellionStrings
internal static string Wizard_Profile_FullHistory_GdprWarning => Get(nameof(Wizard_Profile_FullHistory_GdprWarning)); internal static string Wizard_Profile_FullHistory_GdprWarning => Get(nameof(Wizard_Profile_FullHistory_GdprWarning));
internal static string Wizard_Profile_FullHistory_Apply => Get(nameof(Wizard_Profile_FullHistory_Apply)); internal static string Wizard_Profile_FullHistory_Apply => Get(nameof(Wizard_Profile_FullHistory_Apply));
internal static string Wizard_Reopen_Button => Get(nameof(Wizard_Reopen_Button)); internal static string Wizard_Reopen_Button => Get(nameof(Wizard_Reopen_Button));
internal static string Wizard_Cancel_Label => Get(nameof(Wizard_Cancel_Label));
internal static string Wizard_Cancel_Tooltip => Get(nameof(Wizard_Cancel_Tooltip));
internal static string Export_Heading => Get(nameof(Export_Heading)); internal static string Export_Heading => Get(nameof(Export_Heading));
internal static string Export_Help => Get(nameof(Export_Help)); internal static string Export_Help => Get(nameof(Export_Help));
@@ -222,6 +222,12 @@
<data name="Wizard_Reopen_Button" xml:space="preserve"> <data name="Wizard_Reopen_Button" xml:space="preserve">
<value>Wizard erneut zeigen</value> <value>Wizard erneut zeigen</value>
</data> </data>
<data name="Wizard_Cancel_Label" xml:space="preserve">
<value>Später — Defaults behalten</value>
</data>
<data name="Wizard_Cancel_Tooltip" xml:space="preserve">
<value>Schließt den Wizard ohne Profil-Auswahl. Die Plugin-Defaults bleiben aktiv und der Wizard erscheint beim nächsten Plugin-Reload erneut.</value>
</data>
<data name="Export_Heading" xml:space="preserve"> <data name="Export_Heading" xml:space="preserve">
<value>Export (DSGVO Art. 15 — Auskunftsrecht)</value> <value>Export (DSGVO Art. 15 — Auskunftsrecht)</value>
</data> </data>
@@ -222,6 +222,12 @@
<data name="Wizard_Reopen_Button" xml:space="preserve"> <data name="Wizard_Reopen_Button" xml:space="preserve">
<value>Show wizard again</value> <value>Show wizard again</value>
</data> </data>
<data name="Wizard_Cancel_Label" xml:space="preserve">
<value>Later — keep defaults</value>
</data>
<data name="Wizard_Cancel_Tooltip" xml:space="preserve">
<value>Close the wizard without selecting a profile. The plugin defaults stay active and the wizard returns on next plugin load.</value>
</data>
<data name="Export_Heading" xml:space="preserve"> <data name="Export_Heading" xml:space="preserve">
<value>Export (GDPR Art. 15 — Right of access)</value> <value>Export (GDPR Art. 15 — Right of access)</value>
</data> </data>
+24 -9
View File
@@ -30,14 +30,10 @@ public sealed class FirstRunWizard : Window
public override void OnClose() public override void OnClose()
{ {
// Closing the wizard without picking anything = the user accepts // OnClose fires on explicit X-click and on plugin dispose. We never
// whatever defaults are already in place. Mark as complete so we // implicitly accept the defaults here — the explicit "Later" button
// don't pester them again on the next launch. // does that. If the user hasn't picked a profile yet, the wizard
if (!Plugin.Config.FirstRunCompleted) // reopens on the next plugin load.
{
Plugin.Config.FirstRunCompleted = true;
Plugin.SaveConfig();
}
} }
public override void Draw() public override void Draw()
@@ -49,7 +45,12 @@ public sealed class FirstRunWizard : Window
var avail = ImGui.GetContentRegionAvail(); var avail = ImGui.GetContentRegionAvail();
var cardWidth = (avail.X - ImGui.GetStyle().ItemSpacing.X * 2) / 3f; var cardWidth = (avail.X - ImGui.GetStyle().ItemSpacing.X * 2) / 3f;
var cardHeight = avail.Y - ImGui.GetTextLineHeightWithSpacing(); // Reserve room for the footer separator + cancel button below the cards.
var footerReserve =
ImGui.GetStyle().ItemSpacing.Y * 3
+ ImGui.GetTextLineHeight()
+ ImGui.GetFrameHeightWithSpacing();
var cardHeight = avail.Y - footerReserve;
DrawCard( DrawCard(
"privacy-first", "privacy-first",
@@ -87,6 +88,20 @@ public sealed class FirstRunWizard : Window
HellionStrings.Wizard_Profile_FullHistory_Apply, HellionStrings.Wizard_Profile_FullHistory_Apply,
ApplyFullHistory ApplyFullHistory
); );
ImGui.Spacing();
ImGui.Separator();
ImGui.Spacing();
if (ImGui.Button(HellionStrings.Wizard_Cancel_Label))
{
Plugin.Config.FirstRunCompleted = true;
Plugin.SaveConfig();
IsOpen = false;
}
if (ImGui.IsItemHovered())
ImGuiUtil.Tooltip(HellionStrings.Wizard_Cancel_Tooltip);
} }
private void DrawCard( private void DrawCard(