Skip to content

Commit 60d69d8

Browse files
authored
Merge pull request #5 from devohmycode/0.2.0
feat: v0.2.0 — Firebase sync, window attachment & note security
2 parents 7dcbe7a + ffc9ce8 commit 60d69d8

15 files changed

Lines changed: 2792 additions & 125 deletions

‎ActionPanel.cs‎

Lines changed: 250 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ public static Flyout CreateSettings(string currentTheme, string currentBackdropT
198198
Action<string>? onLanguageSelected = null, Action<bool>? onSlashToggled = null,
199199
Action<Flyout>? onShowAi = null, Action<Flyout>? onShowPrompts = null,
200200
string? currentNoteStyle = null, Action<string>? onNoteStyleSelected = null,
201-
string? currentFont = null, Action<string>? onFontSelected = null)
201+
string? currentFont = null, Action<string>? onFontSelected = null,
202+
Action? onResetPassword = null, Action? onResetNotes = null)
202203
{
203204
var flyout = new Flyout();
204205
flyout.FlyoutPresenterStyle = CreateFlyoutPresenterStyle(260, 320);
@@ -332,6 +333,22 @@ static string FindLabel((string key, string label)[] items, string current)
332333
panel.Children.Add(langBtn);
333334
}
334335

336+
// Reset
337+
if (onResetPassword != null || onResetNotes != null)
338+
{
339+
panel.Children.Add(CreateSeparator());
340+
var resetBtn = CreateNavigateButton(Lang.T("reset"), () =>
341+
ShowResetSubPanel(flyout, onResetPassword, onResetNotes));
342+
resetBtn.Tag = Lang.T("reset") + " Réinitialiser Reset";
343+
// Red text
344+
if (resetBtn.Content is Grid rg)
345+
foreach (var child in rg.Children)
346+
if (child is TextBlock rtb)
347+
rtb.Foreground = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 99, 99));
348+
allButtons.Add(resetBtn);
349+
panel.Children.Add(resetBtn);
350+
}
351+
335352
// Search
336353
panel.Children.Add(CreateSeparator());
337354
var searchBox = new TextBox
@@ -674,6 +691,238 @@ internal static Button CreateButton(ActionItem action, Action handler)
674691
return btn;
675692
}
676693

694+
// ── Reset sub-panel ──
695+
696+
private static void ShowResetSubPanel(Flyout flyout, Action? onResetPassword, Action? onResetNotes)
697+
{
698+
var panel = CreateSubPanelWithHeader(Lang.T("reset"), () =>
699+
{
700+
// Back: re-show would require recreating settings; just hide
701+
flyout.Hide();
702+
});
703+
704+
if (onResetPassword != null)
705+
{
706+
var pwBtn = CreateNavigateButton(Lang.T("reset_password"), () =>
707+
ShowResetConfirmPanel(flyout, Lang.T("reset_password"), Lang.T("reset_password_warn"), () =>
708+
{
709+
flyout.Hide();
710+
onResetPassword();
711+
}, onResetPassword, onResetNotes, requirePassword: true));
712+
panel.Children.Add(pwBtn);
713+
}
714+
715+
if (onResetNotes != null)
716+
{
717+
var notesBtn = CreateNavigateButton(Lang.T("reset_notes"), () =>
718+
ShowResetConfirmPanel(flyout, Lang.T("reset_notes"), Lang.T("reset_notes_warn"), () =>
719+
{
720+
flyout.Hide();
721+
onResetNotes();
722+
}, onResetPassword, onResetNotes));
723+
panel.Children.Add(notesBtn);
724+
}
725+
726+
flyout.Content = panel;
727+
}
728+
729+
private static void ShowResetConfirmPanel(Flyout flyout, string title, string warning, Action onConfirm,
730+
Action? onResetPassword = null, Action? onResetNotes = null, bool requirePassword = false)
731+
{
732+
var panel = CreateSubPanelWithHeader(title, () =>
733+
ShowResetSubPanel(flyout, onResetPassword, onResetNotes));
734+
735+
var warningText = new TextBlock
736+
{
737+
Text = warning,
738+
FontSize = 12,
739+
MaxWidth = 250,
740+
TextWrapping = TextWrapping.Wrap,
741+
Foreground = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 99, 99)),
742+
Margin = new Thickness(8, 6, 8, 6),
743+
Opacity = 0.9,
744+
};
745+
panel.Children.Add(warningText);
746+
747+
PasswordBox? passwordBox = null;
748+
TextBlock? errorText = null;
749+
750+
if (requirePassword)
751+
{
752+
passwordBox = new PasswordBox
753+
{
754+
PlaceholderText = Lang.T("master_password"),
755+
FontSize = 12,
756+
Margin = new Thickness(6, 4, 6, 0),
757+
};
758+
panel.Children.Add(passwordBox);
759+
760+
errorText = new TextBlock
761+
{
762+
FontSize = 11,
763+
Foreground = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 99, 99)),
764+
Margin = new Thickness(8, 0, 8, 0),
765+
Visibility = Visibility.Collapsed,
766+
};
767+
panel.Children.Add(errorText);
768+
}
769+
770+
panel.Children.Add(CreateSeparator());
771+
772+
var confirmBtn = new Button
773+
{
774+
HorizontalAlignment = HorizontalAlignment.Stretch,
775+
HorizontalContentAlignment = HorizontalAlignment.Stretch,
776+
Background = new SolidColorBrush(Microsoft.UI.Colors.Transparent),
777+
BorderThickness = new Thickness(0),
778+
Padding = new Thickness(8, 5, 8, 5),
779+
CornerRadius = new CornerRadius(4),
780+
MinHeight = 0,
781+
Content = new TextBlock
782+
{
783+
Text = Lang.T("reset_confirm"),
784+
FontSize = 12,
785+
Foreground = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 99, 99)),
786+
}
787+
};
788+
confirmBtn.Click += (_, _) =>
789+
{
790+
if (requirePassword && passwordBox != null && errorText != null)
791+
{
792+
if (string.IsNullOrEmpty(passwordBox.Password))
793+
{
794+
errorText.Text = Lang.T("password_required");
795+
errorText.Visibility = Visibility.Visible;
796+
return;
797+
}
798+
var storedHash = AppSettings.LoadMasterPasswordHash();
799+
if (storedHash != null && AppSettings.HashPassword(passwordBox.Password) != storedHash)
800+
{
801+
errorText.Text = Lang.T("wrong_password");
802+
errorText.Visibility = Visibility.Visible;
803+
return;
804+
}
805+
}
806+
onConfirm();
807+
};
808+
panel.Children.Add(confirmBtn);
809+
810+
flyout.Content = panel;
811+
}
812+
813+
// ── Lock / Password flyouts ──
814+
815+
public static void ShowCreatePasswordFlyout(FrameworkElement target, Action<string> onPasswordCreated)
816+
{
817+
var flyout = new Flyout();
818+
flyout.FlyoutPresenterStyle = CreateFlyoutPresenterStyle();
819+
820+
var panel = new StackPanel { Spacing = 4 };
821+
panel.Children.Add(CreateHeader(Lang.T("create_password")));
822+
panel.Children.Add(CreateSeparator());
823+
824+
var passwordBox = new PasswordBox
825+
{
826+
PlaceholderText = Lang.T("master_password"),
827+
FontSize = 12,
828+
Margin = new Thickness(6, 4, 6, 0),
829+
};
830+
panel.Children.Add(passwordBox);
831+
832+
var confirmBox = new PasswordBox
833+
{
834+
PlaceholderText = Lang.T("confirm_password"),
835+
FontSize = 12,
836+
Margin = new Thickness(6, 0, 6, 0),
837+
};
838+
panel.Children.Add(confirmBox);
839+
840+
var errorText = new TextBlock
841+
{
842+
FontSize = 11,
843+
Foreground = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 99, 99)),
844+
Margin = new Thickness(8, 0, 8, 0),
845+
Visibility = Visibility.Collapsed,
846+
};
847+
panel.Children.Add(errorText);
848+
849+
panel.Children.Add(CreateSeparator());
850+
851+
var confirmBtn = CreateCheckItem("OK", false, () =>
852+
{
853+
if (string.IsNullOrEmpty(passwordBox.Password))
854+
{
855+
errorText.Text = Lang.T("password_required");
856+
errorText.Visibility = Visibility.Visible;
857+
return;
858+
}
859+
if (passwordBox.Password != confirmBox.Password)
860+
{
861+
errorText.Text = Lang.T("passwords_dont_match");
862+
errorText.Visibility = Visibility.Visible;
863+
return;
864+
}
865+
flyout.Hide();
866+
onPasswordCreated(passwordBox.Password);
867+
});
868+
panel.Children.Add(confirmBtn);
869+
870+
flyout.Content = panel;
871+
flyout.ShowAt(target);
872+
}
873+
874+
public static void ShowEnterPasswordFlyout(FrameworkElement target, string storedHash, Action onSuccess)
875+
{
876+
var flyout = new Flyout();
877+
flyout.FlyoutPresenterStyle = CreateFlyoutPresenterStyle();
878+
879+
var panel = new StackPanel { Spacing = 4 };
880+
panel.Children.Add(CreateHeader(Lang.T("enter_password")));
881+
panel.Children.Add(CreateSeparator());
882+
883+
var passwordBox = new PasswordBox
884+
{
885+
PlaceholderText = Lang.T("master_password"),
886+
FontSize = 12,
887+
Margin = new Thickness(6, 4, 6, 0),
888+
};
889+
panel.Children.Add(passwordBox);
890+
891+
var errorText = new TextBlock
892+
{
893+
FontSize = 11,
894+
Foreground = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 99, 99)),
895+
Margin = new Thickness(8, 0, 8, 0),
896+
Visibility = Visibility.Collapsed,
897+
};
898+
panel.Children.Add(errorText);
899+
900+
panel.Children.Add(CreateSeparator());
901+
902+
var confirmBtn = CreateCheckItem("OK", false, () =>
903+
{
904+
if (string.IsNullOrEmpty(passwordBox.Password))
905+
{
906+
errorText.Text = Lang.T("password_required");
907+
errorText.Visibility = Visibility.Visible;
908+
return;
909+
}
910+
var inputHash = AppSettings.HashPassword(passwordBox.Password);
911+
if (inputHash != storedHash)
912+
{
913+
errorText.Text = Lang.T("wrong_password");
914+
errorText.Visibility = Visibility.Visible;
915+
return;
916+
}
917+
flyout.Hide();
918+
onSuccess();
919+
});
920+
panel.Children.Add(confirmBtn);
921+
922+
flyout.Content = panel;
923+
flyout.ShowAt(target);
924+
}
925+
677926
public static void ShowVoiceModelsPanel(Flyout flyout, string? currentModelId,
678927
XamlRoot xamlRoot,
679928
Action<SttModelInfo> onSelectModel, Action<SttModelInfo> onDeleteModel, Action onBack, Action onRebuild,

0 commit comments

Comments
 (0)