mirror of
https://github.com/KeyKeeperApp/KeyKeeper.git
synced 2026-04-17 18:16:28 +03:00
merge branch 'Design&Fix'
This commit is contained in:
93
src/KeyKeeper/Views/CreateVaultDialog.axaml
Normal file
93
src/KeyKeeper/Views/CreateVaultDialog.axaml
Normal file
@@ -0,0 +1,93 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="KeyKeeper.Views.CreateVaultFileWindow"
|
||||
Title="Create New Vault"
|
||||
Background="#fff"
|
||||
Icon="/Assets/icon.ico"
|
||||
Width="600" Height="450"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
x:Name="ThisWindow">
|
||||
|
||||
<Grid ColumnDefinitions="1.5*, 2*">
|
||||
<!-- Левая синяя панель -->
|
||||
<Border Background="#2328C4" Grid.Column="0">
|
||||
<StackPanel VerticalAlignment="Center" Margin="20">
|
||||
<TextBlock Text="Choose where to save your password database and set a master password"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="#E0E0FF"
|
||||
FontSize="20"
|
||||
TextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Правая белая панель с формой -->
|
||||
<ScrollViewer Grid.Column="1" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Margin="30" VerticalAlignment="Center" Spacing="20">
|
||||
<TextBlock Text="Create new vault"
|
||||
FontSize="22"
|
||||
FontWeight="Bold"
|
||||
Foreground="#2328C4"/>
|
||||
|
||||
<!-- Выбор файла -->
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Text="File location" FontWeight="SemiBold" Foreground="Black" />
|
||||
<Grid ColumnDefinitions="*, Auto" ColumnSpacing="10">
|
||||
<TextBox x:Name="FilePathTextBox"
|
||||
Grid.Column="0"
|
||||
Watermark="Select file path..."
|
||||
Padding="10,8"/>
|
||||
<Button x:Name="BrowseButton"
|
||||
Grid.Column="1"
|
||||
Content="Browse..."
|
||||
Classes="secondaryButton"
|
||||
Padding="15,8"
|
||||
Click="BrowseButton_Click"/>
|
||||
</Grid>
|
||||
<TextBlock x:Name="PathWarning"
|
||||
FontSize="12"
|
||||
Foreground="Orange"
|
||||
Text=" "/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Ввод мастер-пароля -->
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Text="Master password" FontWeight="SemiBold" Foreground="Black" />
|
||||
<TextBox x:Name="PasswordBox"
|
||||
PasswordChar="*"
|
||||
Watermark="Enter password"
|
||||
Padding="10,8"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Text="Confirm password" FontWeight="SemiBold" Foreground="Black" />
|
||||
<TextBox x:Name="ConfirmPasswordBox"
|
||||
PasswordChar="*"
|
||||
Watermark="Confirm password"
|
||||
Padding="10,8"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Сообщение об ошибке пароля -->
|
||||
<TextBlock x:Name="PasswordErrorText"
|
||||
FontSize="12"
|
||||
Foreground="Red"
|
||||
Text=""
|
||||
IsVisible="False"/>
|
||||
|
||||
<!-- Кнопки действий -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10" Margin="0,20,0,0">
|
||||
<Button Content="Cancel"
|
||||
Classes="secondaryButton"
|
||||
Width="80"
|
||||
Click="CancelButton_Click"/>
|
||||
<Button x:Name="CreateButton"
|
||||
Content="Create"
|
||||
Classes="accentButton"
|
||||
Width="80"
|
||||
IsEnabled="False"
|
||||
Click="CreateButton_Click"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Window>
|
||||
124
src/KeyKeeper/Views/CreateVaultDialog.axaml.cs
Normal file
124
src/KeyKeeper/Views/CreateVaultDialog.axaml.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace KeyKeeper.Views
|
||||
{
|
||||
public partial class CreateVaultFileWindow : Window
|
||||
{
|
||||
public string FilePath { get; private set; } = string.Empty;
|
||||
public string Password { get; private set; } = string.Empty;
|
||||
public bool Success { get; private set; }
|
||||
|
||||
public CreateVaultFileWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
FilePathTextBox.TextChanged += OnTextChanged;
|
||||
PasswordBox.TextChanged += OnPasswordTextChanged;
|
||||
ConfirmPasswordBox.TextChanged += OnPasswordTextChanged;
|
||||
}
|
||||
|
||||
private async void OnTextChanged(object? sender, TextChangedEventArgs e)
|
||||
{
|
||||
UpdateCreateButtonState();
|
||||
PathWarning.Text = "";
|
||||
|
||||
string path = FilePathTextBox.Text ?? "";
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var storageFile = await StorageProvider.TryGetFileFromPathAsync(path);
|
||||
if (storageFile != null)
|
||||
{
|
||||
PathWarning.Text = "File already exists. It will be overwritten.";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPasswordTextChanged(object? sender, TextChangedEventArgs e)
|
||||
{
|
||||
UpdateCreateButtonState();
|
||||
PasswordErrorText.IsVisible = false;
|
||||
}
|
||||
|
||||
private void UpdateCreateButtonState()
|
||||
{
|
||||
bool pathValid = !string.IsNullOrWhiteSpace(FilePathTextBox.Text);
|
||||
bool passwordsEntered = !string.IsNullOrWhiteSpace(PasswordBox.Text) &&
|
||||
!string.IsNullOrWhiteSpace(ConfirmPasswordBox.Text);
|
||||
CreateButton.IsEnabled = pathValid && passwordsEntered;
|
||||
}
|
||||
|
||||
private async void BrowseButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
Title = "Create new password store",
|
||||
SuggestedFileName = "passwords.kkp",
|
||||
DefaultExtension = "kkp",
|
||||
FileTypeChoices = new[]
|
||||
{
|
||||
new FilePickerFileType("KeyKeeper files")
|
||||
{
|
||||
Patterns = new[] { "*.kkp" }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (file?.TryGetLocalPath() is string path)
|
||||
{
|
||||
FilePathTextBox.Text = path;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
string path = FilePathTextBox.Text ?? "";
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return;
|
||||
|
||||
string password = PasswordBox.Text ?? "";
|
||||
string confirm = ConfirmPasswordBox.Text ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(password) || string.IsNullOrEmpty(confirm))
|
||||
{
|
||||
ShowPasswordError("Password cannot be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (password != confirm)
|
||||
{
|
||||
ShowPasswordError("Passwords don't match");
|
||||
return;
|
||||
}
|
||||
|
||||
FilePath = path;
|
||||
Password = password;
|
||||
Success = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void ShowPasswordError(string message)
|
||||
{
|
||||
PasswordErrorText.Text = message;
|
||||
PasswordErrorText.IsVisible = true;
|
||||
}
|
||||
|
||||
private void CancelButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Success = false;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,41 +22,26 @@ namespace KeyKeeper.Views
|
||||
|
||||
private async void CreateNewVault_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
Title = "Create new password store",
|
||||
SuggestedFileName = "passwords.kkp",
|
||||
DefaultExtension = "kkp",
|
||||
FileTypeChoices = new[]
|
||||
{
|
||||
new FilePickerFileType("KeyKeeper files")
|
||||
{
|
||||
Patterns = new[] { "*.kkp" }
|
||||
}
|
||||
}
|
||||
});
|
||||
var createVaultDialog = new CreateVaultFileWindow();
|
||||
await createVaultDialog.ShowDialog(this);
|
||||
|
||||
if (file != null)
|
||||
if (createVaultDialog.Success &&
|
||||
!string.IsNullOrEmpty(createVaultDialog.FilePath) &&
|
||||
!string.IsNullOrEmpty(createVaultDialog.Password))
|
||||
{
|
||||
if (file.TryGetLocalPath() is string path)
|
||||
{
|
||||
var passwordDialog = new PasswordDialog();
|
||||
await passwordDialog.ShowDialog(this);
|
||||
if (passwordDialog.Created && !string.IsNullOrEmpty(passwordDialog.Password))
|
||||
var path = createVaultDialog.FilePath;
|
||||
var password = createVaultDialog.Password;
|
||||
var compositeKey = new CompositeKey(password, null);
|
||||
var passStoreAccessor = new PassStoreFileAccessor(
|
||||
filename: path,
|
||||
create: true,
|
||||
createOptions: new StoreCreationOptions()
|
||||
{
|
||||
var compositeKey = new CompositeKey(passwordDialog.Password, null);
|
||||
var passStoreAccessor = new PassStoreFileAccessor(
|
||||
filename: path,
|
||||
create: true,
|
||||
createOptions: new StoreCreationOptions()
|
||||
{
|
||||
Key = compositeKey,
|
||||
LockTimeoutSeconds = 800
|
||||
});
|
||||
IPassStore passStore = passStoreAccessor;
|
||||
OpenRepositoryWindow(passStore);
|
||||
}
|
||||
}
|
||||
Key = compositeKey,
|
||||
LockTimeoutSeconds = 800
|
||||
});
|
||||
IPassStore passStore = passStoreAccessor;
|
||||
OpenRepositoryWindow(passStore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="KeyKeeper.Views.PasswordDialog"
|
||||
Title="Создание хранилища"
|
||||
Width="350"
|
||||
Height="230">
|
||||
|
||||
<StackPanel Margin="20" VerticalAlignment="Center">
|
||||
|
||||
<TextBlock Text="Set Master Password"
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Margin="0,0,0,15"/>
|
||||
|
||||
<!-- Поле для пароля (звездочки) -->
|
||||
<StackPanel Margin="0,0,0,10">
|
||||
<TextBlock Text="Password:" Margin="0,0,0,5"/>
|
||||
<TextBox x:Name="PasswordBox"
|
||||
PasswordChar="*"
|
||||
Width="250"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Поле для подтверждения (звездочки) -->
|
||||
<StackPanel Margin="0,0,0,15">
|
||||
<TextBlock Text="Confirm Password:" Margin="0,0,0,5"/>
|
||||
<TextBox x:Name="ConfirmPasswordBox"
|
||||
PasswordChar="*"
|
||||
Width="250"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Сообщение об ошибке -->
|
||||
<TextBlock x:Name="ErrorText"
|
||||
Text="Passwords do not match"
|
||||
Foreground="Red"
|
||||
FontSize="12"
|
||||
Margin="0,0,0,10"
|
||||
IsVisible="False"/>
|
||||
|
||||
<!-- Кнопки -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10">
|
||||
<Button Content="Cancel"
|
||||
Width="80"
|
||||
Height="30"
|
||||
Click="CancelButton_Click"/>
|
||||
|
||||
<Button Content="Create"
|
||||
Width="80"
|
||||
Height="30"
|
||||
Click="CreateButton_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</Window>
|
||||
@@ -1,65 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace KeyKeeper.Views
|
||||
{
|
||||
public partial class PasswordDialog : Window
|
||||
{
|
||||
public string Password { get; private set; } = "";
|
||||
public bool Created { get; private set; } = false;
|
||||
|
||||
public PasswordDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void CreateButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var passwordBox = this.FindControl<TextBox>("PasswordBox");
|
||||
var confirmBox = this.FindControl<TextBox>("ConfirmPasswordBox");
|
||||
var errorText = this.FindControl<TextBlock>("ErrorText");
|
||||
|
||||
string password = passwordBox?.Text ?? "";
|
||||
string confirmPassword = confirmBox?.Text ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(password) || string.IsNullOrEmpty(confirmPassword))
|
||||
{
|
||||
ShowError("Password cannot be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (password != confirmPassword)
|
||||
{
|
||||
ShowError("Passwords don't match");
|
||||
return;
|
||||
}
|
||||
|
||||
Password = password;
|
||||
Created = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void ShowError(string message)
|
||||
{
|
||||
var errorText = this.FindControl<TextBlock>("ErrorText");
|
||||
if (errorText != null)
|
||||
{
|
||||
errorText.Text = message;
|
||||
errorText.IsVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Created = false;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
Margin="0,0,0,20"/>
|
||||
|
||||
<!-- Рамочка -->
|
||||
<Border BorderBrush="Gray"
|
||||
<!-- <Border BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5"
|
||||
Padding="20"
|
||||
@@ -42,7 +42,7 @@
|
||||
HorizontalAlignment="Left"/>
|
||||
</StackPanel>
|
||||
|
||||
</Border>
|
||||
</Border> -->
|
||||
<!-- Save Passwords -->
|
||||
<Button Content="Save Passwords"
|
||||
Classes="accentSidebarButton"
|
||||
|
||||
Reference in New Issue
Block a user