using System.Windows; using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Media; using QSafe.Core; namespace QSafe.Desktop; public sealed class PasswordGeneratorDialog : AppDialog { private readonly TextBox output; private readonly Slider length; private readonly TextBlock lengthLabel, hint; private readonly CheckBox symbols, digits; private readonly int[] sizes = [24, 12, 8]; private PasswordMode mode; private bool updating; public PasswordGeneratorDialog(Window owner, Action use, bool forField = true) : base(owner, "Генератор паролей", "Выберите тип и длину, затем используйте подходящий вариант.", 620) { Ui.Label(Body, "Сгенерированный пароль"); output = new TextBox { IsReadOnly = true, IsUndoEnabled = false, FontFamily = new FontFamily("Cascadia Mono, Consolas"), FontSize = 22, TextWrapping = TextWrapping.Wrap, MinHeight = 96, Margin = new Thickness(0, 0, 0, 8) }; AutomationProperties.SetName(output, "Сгенерированный пароль"); Body.Children.Add(output); Ui.Label(Body, "Тип пароля"); var choices = new WrapPanel(); Body.Children.Add(choices); var titles = new[] { "Сложный", "Только цифры", "Запоминающийся" }; var radios = new List(); for (int i = 0; i < titles.Length; i++) { var selectedMode = (PasswordMode)i; var radio = new RadioButton { Content = titles[i], GroupName = "PasswordMode", Foreground = Ui.Brush("#F0F2F6"), FontSize = 14, Padding = new Thickness(3, 8, 0, 8), Margin = new Thickness(0, 0, 18, 0), VerticalContentAlignment = VerticalAlignment.Center }; AutomationProperties.SetName(radio, titles[i]); radios.Add(radio); choices.Children.Add(radio); radio.Checked += (_, _) => { mode = selectedMode; Configure(); }; } lengthLabel = Ui.Text("", 14); lengthLabel.Margin = new Thickness(0, 18, 0, 12); Body.Children.Add(lengthLabel); length = new Slider { IsSnapToTickEnabled = true, TickFrequency = 1, SmallChange = 1, LargeChange = 4, MinHeight = 30 }; AutomationProperties.SetName(length, "Длина пароля"); Body.Children.Add(length); symbols = new CheckBox { Content = "Специальные символы (!@#…)", IsChecked = true, Margin = new Thickness(0, 18, 0, 12) }; Body.Children.Add(symbols); digits = new CheckBox { Content = "Добавлять цифры (0–9)", IsChecked = true, Margin = new Thickness(0, 0, 0, 12) }; Body.Children.Add(digits); hint = Ui.Text("", 12, "#969EAD"); Body.Children.Add(hint); length.ValueChanged += (_, _) => { if (!updating) { sizes[(int)mode] = (int)length.Value; Generate(); } }; symbols.Checked += (_, _) => Generate(); symbols.Unchecked += (_, _) => Generate(); digits.Checked += (_, _) => Generate(); digits.Unchecked += (_, _) => Generate(); var regenerate = Ui.Button("Другой вариант", Generate); regenerate.Margin = new Thickness(0, 16, 0, 0); Body.Children.Add(regenerate); AddCancel(); Actions.Children.Add(Ui.Button(forField ? "Использовать пароль" : "Скопировать пароль", () => { use(output.Text); Accept(); }, "Primary")); Closed += (_, _) => output.Clear(); radios[0].IsChecked = true; } private void Configure() { updating = true; // Reset both bounds first so switching between words and characters never coerces a saved value. length.Minimum = 0; length.Maximum = 128; length.Minimum = mode == PasswordMode.Complex ? 16 : mode == PasswordMode.Digits ? 4 : 2; length.Maximum = mode == PasswordMode.Memorable ? 12 : 64; length.Value = sizes[(int)mode]; symbols.Visibility = mode != PasswordMode.Digits ? Visibility.Visible : Visibility.Collapsed; digits.Visibility = mode == PasswordMode.Memorable ? Visibility.Visible : Visibility.Collapsed; hint.Text = mode switch { PasswordMode.Complex => "Заглавные и строчные латинские буквы, цифры. Похожие символы исключены.", PasswordMode.Digits => "Цифры 0–9, в том числе в начале. Короткий код легче подобрать.", _ => "От 2 случайных английских слов. Цифры и знаки размещаются случайно перед словами, между ними или в конце. Слова остаются целыми." }; updating = false; Generate(); } private void Generate() { int size = sizes[(int)mode]; output.Text = PasswordGenerator.Generate(mode, size, symbols.IsChecked == true, digits.IsChecked == true); lengthLabel.Text = mode == PasswordMode.Memorable ? $"Слов: {size} · символов: {output.Text.Length}" : $"Длина: {size} {(mode == PasswordMode.Digits ? "цифр" : "символов")}"; AutomationProperties.SetHelpText(length, lengthLabel.Text); } }