Files
QSafe/windows/QSafe.Desktop/PasswordGeneratorDialog.cs
T

79 lines
5.2 KiB
C#

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<string> 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<RadioButton>();
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);
}
}