mirror of
https://github.com/KeyKeeperApp/KeyKeeper.git
synced 2026-05-18 22:36:30 +03:00
add "Add Group" button
This commit is contained in:
@@ -2,7 +2,7 @@ using System;
|
||||
|
||||
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 DEFAULT = KEY;
|
||||
|
||||
@@ -323,7 +323,6 @@ public class EntryEditViewModel : ViewModelBase
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Validation should have caught this, but handle gracefully
|
||||
totp = null;
|
||||
}
|
||||
}
|
||||
@@ -332,7 +331,7 @@ public class EntryEditViewModel : ViewModelBase
|
||||
id,
|
||||
created,
|
||||
DateTime.UtcNow,
|
||||
EntryIconType.DEFAULT,
|
||||
BuiltinEntryIconType.DEFAULT,
|
||||
EntryName.Trim(),
|
||||
new LoginField() { Type = LOGIN_FIELD_USERNAME_ID, Value = Username.Trim() },
|
||||
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)
|
||||
{
|
||||
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"
|
||||
HorizontalAlignment="Left"
|
||||
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>
|
||||
</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)
|
||||
{
|
||||
if (DataContext is RepositoryWindowViewModel vm && vm.CurrentPage is UnlockedRepositoryViewModel pageVm)
|
||||
|
||||
Reference in New Issue
Block a user