79 lines
5.2 KiB
C#
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);
|
|
}
|
|
}
|