mirror of
https://github.com/KeyKeeperApp/KeyKeeper.git
synced 2026-05-19 06:46:32 +03:00
add "Add Group" button
This commit is contained in:
@@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace KeyKeeper.PasswordStore;
|
namespace KeyKeeper.PasswordStore;
|
||||||
|
|
||||||
public static class EntryIconType
|
public static class BuiltinEntryIconType
|
||||||
{
|
{
|
||||||
public static readonly Guid KEY = Guid.Parse("65ab3d55-1652-4f66-aac9-c3617f14e308");
|
public static readonly Guid KEY = Guid.Parse("65ab3d55-1652-4f66-aac9-c3617f14e308");
|
||||||
public static readonly Guid DEFAULT = KEY;
|
public static readonly Guid DEFAULT = KEY;
|
||||||
|
|||||||
@@ -323,7 +323,6 @@ public class EntryEditViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
// Validation should have caught this, but handle gracefully
|
|
||||||
totp = null;
|
totp = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,7 +331,7 @@ public class EntryEditViewModel : ViewModelBase
|
|||||||
id,
|
id,
|
||||||
created,
|
created,
|
||||||
DateTime.UtcNow,
|
DateTime.UtcNow,
|
||||||
EntryIconType.DEFAULT,
|
BuiltinEntryIconType.DEFAULT,
|
||||||
EntryName.Trim(),
|
EntryName.Trim(),
|
||||||
new LoginField() { Type = LOGIN_FIELD_USERNAME_ID, Value = Username.Trim() },
|
new LoginField() { Type = LOGIN_FIELD_USERNAME_ID, Value = Username.Trim() },
|
||||||
new LoginField() { Type = LOGIN_FIELD_PASSWORD_ID, Value = Password },
|
new LoginField() { Type = LOGIN_FIELD_PASSWORD_ID, Value = Password },
|
||||||
|
|||||||
@@ -95,6 +95,15 @@ public class UnlockedRepositoryViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddGroup(PassStoreEntryGroup group)
|
||||||
|
{
|
||||||
|
if (rootDirectory == null)
|
||||||
|
return;
|
||||||
|
rootDirectory.AddEntry(group);
|
||||||
|
HasUnsavedChanges = true;
|
||||||
|
OnPropertyChanged(nameof(PasswordGroups));
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteEntry(Guid id)
|
public void DeleteEntry(Guid id)
|
||||||
{
|
{
|
||||||
currentDirectory.DeleteEntry(id);
|
currentDirectory.DeleteEntry(id);
|
||||||
|
|||||||
60
src/KeyKeeper/Views/CreateGroupDialog.axaml
Normal file
60
src/KeyKeeper/Views/CreateGroupDialog.axaml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
x:Class="KeyKeeper.Views.CreateGroupDialog"
|
||||||
|
Title="Create New Group"
|
||||||
|
Background="White"
|
||||||
|
Icon="/Assets/icon.ico"
|
||||||
|
Width="420" Height="320"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
|
CanResize="False">
|
||||||
|
|
||||||
|
<StackPanel Margin="20" Spacing="16">
|
||||||
|
<TextBlock Text="Create new group"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="#2328C4"/>
|
||||||
|
|
||||||
|
<StackPanel Spacing="6">
|
||||||
|
<TextBlock Text="Group name" FontWeight="SemiBold" Foreground="Black" />
|
||||||
|
<TextBox x:Name="NameTextBox"
|
||||||
|
Watermark="Enter group name"
|
||||||
|
Padding="10,8"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Spacing="6">
|
||||||
|
<TextBlock Text="Icon" FontWeight="SemiBold" Foreground="Black" />
|
||||||
|
<ListBox x:Name="IconListBox"
|
||||||
|
Height="80"
|
||||||
|
SelectionMode="Single"
|
||||||
|
Background="#F5F5F5">
|
||||||
|
<ListBox.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ListBox.ItemsPanel>
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:CompileBindings="False">
|
||||||
|
<Svg Path="{Binding IconPath}" Width="48" Height="48" Margin="6"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock x:Name="ErrorText"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="Red"
|
||||||
|
Text=""
|
||||||
|
IsVisible="False"/>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10">
|
||||||
|
<Button Content="Cancel"
|
||||||
|
Width="80"
|
||||||
|
Click="CancelButton_Click"/>
|
||||||
|
<Button x:Name="CreateButton"
|
||||||
|
Content="Create"
|
||||||
|
Width="80"
|
||||||
|
IsEnabled="False"
|
||||||
|
Click="CreateButton_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Window>
|
||||||
74
src/KeyKeeper/Views/CreateGroupDialog.axaml.cs
Normal file
74
src/KeyKeeper/Views/CreateGroupDialog.axaml.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using KeyKeeper.PasswordStore;
|
||||||
|
|
||||||
|
namespace KeyKeeper.Views;
|
||||||
|
|
||||||
|
public partial class CreateGroupDialog : Window
|
||||||
|
{
|
||||||
|
public string GroupName { get; private set; } = string.Empty;
|
||||||
|
public Guid IconType { get; private set; } = BuiltinEntryIconType.DEFAULT;
|
||||||
|
public bool Success { get; private set; }
|
||||||
|
|
||||||
|
private record IconChoice(Guid Id)
|
||||||
|
{
|
||||||
|
public string IconPath => $"avares://KeyKeeper/Assets/builtin-entry-icon-{Id}.svg";
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateGroupDialog()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
var icons = new List<IconChoice>
|
||||||
|
{
|
||||||
|
new(BuiltinEntryIconType.KEY),
|
||||||
|
};
|
||||||
|
IconListBox.ItemsSource = icons;
|
||||||
|
IconListBox.SelectedIndex = 0;
|
||||||
|
|
||||||
|
NameTextBox.TextChanged += (_, _) => UpdateCreateButtonState();
|
||||||
|
KeyDown += OnKeyDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCreateButtonState()
|
||||||
|
{
|
||||||
|
CreateButton.IsEnabled = !string.IsNullOrWhiteSpace(NameTextBox.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnKeyDown(object? sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Escape)
|
||||||
|
Close();
|
||||||
|
else if (e.Key == Key.Enter && CreateButton.IsEnabled)
|
||||||
|
Submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateButton_Click(object? sender, RoutedEventArgs e) => Submit();
|
||||||
|
|
||||||
|
private void CancelButton_Click(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Success = false;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Submit()
|
||||||
|
{
|
||||||
|
var name = NameTextBox.Text?.Trim() ?? string.Empty;
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
ErrorText.Text = "Name cannot be empty";
|
||||||
|
ErrorText.IsVisible = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupName = name;
|
||||||
|
if (IconListBox.SelectedItem is IconChoice choice)
|
||||||
|
IconType = choice.Id;
|
||||||
|
|
||||||
|
Success = true;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -96,6 +96,14 @@
|
|||||||
Height="30"
|
Height="30"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Margin="0,20,0,0"/>
|
Margin="0,20,0,0"/>
|
||||||
|
|
||||||
|
<!-- New Group -->
|
||||||
|
<Button Content="New Group"
|
||||||
|
Classes="accentSidebarButton"
|
||||||
|
Click="AddGroupButton_Click"
|
||||||
|
Height="30"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Margin="0,20,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,34 @@ public partial class RepositoryWindow : Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void AddGroupButton_Click(object sender, RoutedEventArgs args)
|
||||||
|
{
|
||||||
|
if (DataContext is RepositoryWindowViewModel vm_ && vm_.CurrentPage is UnlockedRepositoryViewModel vm)
|
||||||
|
{
|
||||||
|
CreateGroupDialog dialog = new();
|
||||||
|
|
||||||
|
vm_.StopLockTimer();
|
||||||
|
|
||||||
|
await dialog.ShowDialog(this);
|
||||||
|
|
||||||
|
vm_.StartLockTimer();
|
||||||
|
|
||||||
|
if (dialog.Success)
|
||||||
|
{
|
||||||
|
var group = new PassStoreEntryGroup(
|
||||||
|
Guid.NewGuid(),
|
||||||
|
DateTime.UtcNow,
|
||||||
|
DateTime.UtcNow,
|
||||||
|
dialog.IconType,
|
||||||
|
dialog.GroupName,
|
||||||
|
FileFormatConstants.GROUP_TYPE_SIMPLE
|
||||||
|
);
|
||||||
|
vm.AddGroup(group);
|
||||||
|
this.FindControlRecursive<ToastNotificationHost>("NotificationHost")?.Show("Group created");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SaveButton_Click(object sender, RoutedEventArgs args)
|
private void SaveButton_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
if (DataContext is RepositoryWindowViewModel vm && vm.CurrentPage is UnlockedRepositoryViewModel pageVm)
|
if (DataContext is RepositoryWindowViewModel vm && vm.CurrentPage is UnlockedRepositoryViewModel pageVm)
|
||||||
|
|||||||
Reference in New Issue
Block a user