merge branch 'feature/confirmation-at-closing'

This commit is contained in:
2026-03-13 14:15:45 +03:00
5 changed files with 139 additions and 0 deletions

View File

@@ -8,6 +8,7 @@ namespace KeyKeeper.ViewModels;
public class UnlockedRepositoryViewModel : ViewModelBase
{
private IPassStore passStore;
private bool hasUnsavedChanges;
public IEnumerable<PassStoreEntryPassword> Passwords
{
@@ -19,9 +20,20 @@ public class UnlockedRepositoryViewModel : ViewModelBase
}
}
public bool HasUnsavedChanges
{
get => hasUnsavedChanges;
private set
{
hasUnsavedChanges = value;
OnPropertyChanged(nameof(HasUnsavedChanges));
}
}
public UnlockedRepositoryViewModel(IPassStore store)
{
passStore = store;
HasUnsavedChanges = false;
}
public void AddEntry(PassStoreEntry entry)
@@ -29,6 +41,7 @@ public class UnlockedRepositoryViewModel : ViewModelBase
if (entry is PassStoreEntryPassword)
{
(passStore.GetRootDirectory() as PassStoreEntryGroup)!.ChildEntries.Add(entry);
HasUnsavedChanges = true;
OnPropertyChanged(nameof(Passwords));
}
}
@@ -36,6 +49,7 @@ public class UnlockedRepositoryViewModel : ViewModelBase
public void DeleteEntry(Guid id)
{
(passStore.GetRootDirectory() as PassStoreEntryGroup)!.DeleteEntry(id);
HasUnsavedChanges = true;
OnPropertyChanged(nameof(Passwords));
}
@@ -52,5 +66,6 @@ public class UnlockedRepositoryViewModel : ViewModelBase
public void Save()
{
passStore.Save();
HasUnsavedChanges = false;
}
}

View File

@@ -0,0 +1,29 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="KeyKeeper.Views.CloseConfirmationDialog"
Width="420"
Height="170"
CanResize="False"
WindowStartupLocation="CenterOwner"
Title="Confirm close"
Background="White">
<Grid Margin="16" RowDefinitions="*,Auto">
<TextBlock Text="Save changes before closing the storage?"
TextWrapping="Wrap"
Foreground="Black"
FontSize="16"/>
<StackPanel Grid.Row="1"
Orientation="Horizontal"
HorizontalAlignment="Right"
Spacing="8"
Margin="0,16,0,0">
<Button Content="Save"
Click="Save_Click" />
<Button Content="Do not save"
Click="Discard_Click" />
<Button Content="Cancel"
Click="Cancel_Click" />
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,52 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace KeyKeeper.Views;
public enum CloseConfirmationResult
{
Save,
Discard,
Cancel,
}
public partial class CloseConfirmationDialog : Window
{
private bool closingWithResult;
public CloseConfirmationDialog()
{
InitializeComponent();
}
protected override void OnClosing(WindowClosingEventArgs e)
{
if (!closingWithResult)
{
e.Cancel = true;
closingWithResult = true;
Close(CloseConfirmationResult.Cancel);
return;
}
base.OnClosing(e);
}
private void Save_Click(object? sender, RoutedEventArgs e)
{
closingWithResult = true;
Close(CloseConfirmationResult.Save);
}
private void Discard_Click(object? sender, RoutedEventArgs e)
{
closingWithResult = true;
Close(CloseConfirmationResult.Discard);
}
private void Cancel_Click(object? sender, RoutedEventArgs e)
{
closingWithResult = true;
Close(CloseConfirmationResult.Cancel);
}
}

View File

@@ -4,6 +4,7 @@
xmlns:i="using:Avalonia.Interactivity"
xmlns:kkp="using:KeyKeeper.Views"
x:Class="KeyKeeper.Views.RepositoryWindow"
Closing="RepositoryWindow_Closing"
Title="KeyKeeper - Password store"
CanResize="False"
Width="800"

View File

@@ -12,6 +12,9 @@ namespace KeyKeeper.Views;
public partial class RepositoryWindow : Window
{
private bool allowClose;
private bool closeConfirmationShown;
public RepositoryWindow(RepositoryWindowViewModel model)
{
InitializeComponent();
@@ -27,6 +30,45 @@ public partial class RepositoryWindow : Window
base.OnOpened(e);
}
private async void RepositoryWindow_Closing(object? sender, WindowClosingEventArgs e)
{
if (allowClose || closeConfirmationShown)
{
return;
}
if (DataContext is RepositoryWindowViewModel checkVm &&
checkVm.CurrentPage is UnlockedRepositoryViewModel unlockedVm &&
!unlockedVm.HasUnsavedChanges)
{
allowClose = true;
return;
}
e.Cancel = true;
closeConfirmationShown = true;
var dialog = new CloseConfirmationDialog();
var result = await dialog.ShowDialog<CloseConfirmationResult?>(this);
closeConfirmationShown = false;
if (result == null || result == CloseConfirmationResult.Cancel)
{
return;
}
if (result == CloseConfirmationResult.Save &&
DataContext is RepositoryWindowViewModel vm &&
vm.CurrentPage is UnlockedRepositoryViewModel pageVm)
{
pageVm.Save();
}
allowClose = true;
Close();
}
private async void AddEntryButton_Click(object sender, RoutedEventArgs args)
{
if (DataContext is RepositoryWindowViewModel vm_ && vm_.CurrentPage is UnlockedRepositoryViewModel vm)