mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 15:40:18 -04:00
WIP History
Restore from history works
This commit is contained in:
@@ -89,6 +89,7 @@
|
||||
<Compile Include="Common\Mappings\IMapFrom.cs" />
|
||||
<Compile Include="Common\Mappings\MappingProfile.cs" />
|
||||
<Compile Include="Entry\Commands\AddHistory\AddHistoryCommand.cs" />
|
||||
<Compile Include="Entry\Commands\RestoreHistory\RestoreHistoryCommand.cs" />
|
||||
<Compile Include="Entry\Queries\GetEntry\GetEntryQuery.cs" />
|
||||
<Compile Include="Group\Commands\DeleteEntry\DeleteEntryCommand.cs" />
|
||||
<Compile Include="Group\Commands\DeleteGroup\DeleteGroupCommand.cs" />
|
||||
|
@@ -22,7 +22,6 @@ namespace ModernKeePass.Application.Common.Interfaces
|
||||
|
||||
Task Open(byte[] file, Credentials credentials);
|
||||
Task ReOpen(byte[] file);
|
||||
void AddHistory(string entryId);
|
||||
Task Create(Credentials credentials, string name, DatabaseVersion version = DatabaseVersion.V2);
|
||||
Task<byte[]> SaveDatabase();
|
||||
Task<byte[]> SaveDatabase(byte[] newFileContents);
|
||||
@@ -44,6 +43,9 @@ namespace ModernKeePass.Application.Common.Interfaces
|
||||
void SortEntries(string groupId);
|
||||
void SortSubGroups(string groupId);
|
||||
|
||||
void AddHistory(string entryId);
|
||||
void RestoreFromHistory(string entryId, int historyIndex);
|
||||
|
||||
IEnumerable<EntryEntity> Search(string groupId, string text);
|
||||
}
|
||||
}
|
@@ -51,7 +51,7 @@ namespace ModernKeePass.Application.Database.Commands.SaveDatabase
|
||||
|
||||
_database.IsDirty = false;
|
||||
}
|
||||
catch (ArgumentException exception)
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new SaveException(exception);
|
||||
}
|
||||
|
@@ -0,0 +1,29 @@
|
||||
using MediatR;
|
||||
using ModernKeePass.Application.Common.Interfaces;
|
||||
using ModernKeePass.Domain.Exceptions;
|
||||
|
||||
namespace ModernKeePass.Application.Entry.Commands.RestoreHistory
|
||||
{
|
||||
public class RestoreHistoryCommand : IRequest
|
||||
{
|
||||
public string EntryId { get; set; }
|
||||
public int HistoryIndex { get; set; }
|
||||
|
||||
public class RestoreHistoryCommandHandler : IRequestHandler<RestoreHistoryCommand>
|
||||
{
|
||||
private readonly IDatabaseProxy _database;
|
||||
|
||||
public RestoreHistoryCommandHandler(IDatabaseProxy database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public void Handle(RestoreHistoryCommand message)
|
||||
{
|
||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||
|
||||
_database.RestoreFromHistory(message.EntryId, message.HistoryIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -259,6 +259,13 @@ namespace ModernKeePass.Infrastructure.KeePass
|
||||
pwEntry.CreateBackup(null);
|
||||
}
|
||||
|
||||
public void RestoreFromHistory(string entryId, int historyIndex)
|
||||
{
|
||||
var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
|
||||
pwEntry.RestoreFromBackup((uint)historyIndex, _pwDatabase);
|
||||
pwEntry.Touch(true);
|
||||
}
|
||||
|
||||
public void UpdateGroup(string groupId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
@@ -10,6 +11,7 @@ using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||
using ModernKeePass.Application.Database.Models;
|
||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||
using ModernKeePass.Application.Entry.Commands.AddHistory;
|
||||
using ModernKeePass.Application.Entry.Commands.RestoreHistory;
|
||||
using ModernKeePass.Application.Entry.Commands.SetFieldValue;
|
||||
using ModernKeePass.Application.Entry.Models;
|
||||
using ModernKeePass.Application.Entry.Queries.GetEntry;
|
||||
@@ -173,7 +175,8 @@ namespace ModernKeePass.ViewModels
|
||||
SetFieldValue(nameof(ForegroundColor), _entry.ForegroundColor).Wait();
|
||||
}
|
||||
}
|
||||
public IEnumerable<EntryVm> History { get; }
|
||||
|
||||
public ObservableCollection<EntryVm> History { get; }
|
||||
|
||||
public bool IsEditMode
|
||||
{
|
||||
@@ -190,6 +193,7 @@ namespace ModernKeePass.ViewModels
|
||||
public ICommand SaveCommand { get; }
|
||||
public ICommand GeneratePasswordCommand { get; }
|
||||
public ICommand MoveCommand { get; }
|
||||
public ICommand RestoreCommand { get; }
|
||||
|
||||
private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
|
||||
|
||||
@@ -208,16 +212,21 @@ namespace ModernKeePass.ViewModels
|
||||
public EntryDetailVm(string entryId, IMediator mediator)
|
||||
{
|
||||
_mediator = mediator;
|
||||
_entry = _mediator.Send(new GetEntryQuery {Id = entryId}).GetAwaiter().GetResult();
|
||||
_parent = _mediator.Send(new GetGroupQuery {Id = _entry.ParentGroupId}).GetAwaiter().GetResult();
|
||||
History = _entry.History;
|
||||
_entry = _mediator.Send(new GetEntryQuery { Id = entryId }).GetAwaiter().GetResult();
|
||||
_parent = _mediator.Send(new GetGroupQuery { Id = _entry.ParentGroupId }).GetAwaiter().GetResult();
|
||||
History = new ObservableCollection<EntryVm> {_entry};
|
||||
foreach (var entry in _entry.History)
|
||||
{
|
||||
History.Add(entry);
|
||||
}
|
||||
IsSelected = true;
|
||||
|
||||
SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty);
|
||||
GeneratePasswordCommand = new RelayCommand(async () => await GeneratePassword());
|
||||
MoveCommand = new RelayCommand(async () => await Move(_parent), () => _parent != null);
|
||||
RestoreCommand = new RelayCommand(async () => await RestoreHistory());
|
||||
}
|
||||
|
||||
|
||||
public async Task GeneratePassword()
|
||||
{
|
||||
Password = await _mediator.Send(new GeneratePasswordCommand
|
||||
@@ -256,7 +265,7 @@ namespace ModernKeePass.ViewModels
|
||||
|
||||
public async Task AddHistory()
|
||||
{
|
||||
if (_entry.IsDirty) await _mediator.Send(new AddHistoryCommand {EntryId = Id});
|
||||
if (_entry.IsDirty) await _mediator.Send(new AddHistoryCommand { EntryId = Id });
|
||||
}
|
||||
|
||||
internal void SetEntry(EntryVm entry, int index)
|
||||
@@ -266,6 +275,15 @@ namespace ModernKeePass.ViewModels
|
||||
OnPropertyChanged();
|
||||
}
|
||||
|
||||
private async Task RestoreHistory()
|
||||
{
|
||||
var index = History.IndexOf(_entry);
|
||||
var entryToRestore = History[index];
|
||||
SetEntry(entryToRestore, 0);
|
||||
await _mediator.Send(new RestoreHistoryCommand { EntryId = Id, HistoryIndex = index });
|
||||
History.Insert(0, entryToRestore);
|
||||
}
|
||||
|
||||
private async Task SaveChanges()
|
||||
{
|
||||
await AddHistory();
|
||||
@@ -273,6 +291,5 @@ namespace ModernKeePass.ViewModels
|
||||
((RelayCommand)SaveCommand).RaiseCanExecuteChanged();
|
||||
_entry.IsDirty = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@
|
||||
<converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
|
||||
<converters:ProgressBarLegalValuesConverter x:Key="ProgressBarLegalValuesConverter" />
|
||||
<converters:DoubleToSolidColorBrushConverter x:Key="DoubleToForegroundBrushComplexityConverter" />
|
||||
<converters:IconToSymbolConverter x:Key="IconToSymbolConverter"/>
|
||||
<Style TargetType="PasswordBox" x:Name="PasswordBoxWithButtonStyle">
|
||||
<Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}" />
|
||||
<Setter Property="MinHeight" Value="{ThemeResource TextControlThemeMinHeight}" />
|
||||
@@ -410,7 +409,7 @@
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<TextBlock x:Uid="EntryLogin" />
|
||||
<local:TextBoxWithButton x:Uid="LoginTextBox" Text="{Binding UserName, Mode=TwoWay}" LostFocus="Username_OnLostFocus" Style="{StaticResource EntryTextBoxWithButtonStyle}" ButtonSymbol="" IsEnabled="{Binding IsSelected}">
|
||||
<local:TextBoxWithButton x:Uid="LoginTextBox" Text="{Binding UserName, Mode=TwoWay}" Style="{StaticResource EntryTextBoxWithButtonStyle}" ButtonSymbol="" IsEnabled="{Binding IsSelected}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<core:EventTriggerBehavior EventName="ButtonClick">
|
||||
<actions:ClipboardAction Text="{Binding UserName}" />
|
||||
@@ -530,12 +529,18 @@
|
||||
<userControls:TopMenuUserControl
|
||||
x:Name="TopMenu" Grid.Column="2"
|
||||
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
||||
MoveButtonVisibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
RestoreButtonVisibility="{Binding IsSelected, Converter={StaticResource InverseBooleanToVisibilityConverter}}"
|
||||
SaveCommand="{Binding SaveCommand}"
|
||||
MoveCommand="{Binding MoveCommand}">
|
||||
MoveCommand="{Binding MoveCommand}"
|
||||
RestoreCommand="{Binding RestoreCommand}">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<core:EventTriggerBehavior EventName="EditButtonClick">
|
||||
<actions:SetupFocusAction TargetObject="{Binding ElementName=TitleTextBox}" />
|
||||
</core:EventTriggerBehavior>
|
||||
<core:EventTriggerBehavior EventName="RestoreButtonClick">
|
||||
<core:ChangePropertyAction TargetObject="" />
|
||||
</core:EventTriggerBehavior>
|
||||
<core:EventTriggerBehavior EventName="DeleteButtonClick">
|
||||
<actions:DeleteEntityAction Entity="{Binding}" Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}" />
|
||||
</core:EventTriggerBehavior>
|
||||
|
@@ -47,7 +47,7 @@ namespace ModernKeePass.Views
|
||||
if (args != null)
|
||||
{
|
||||
DataContext = new EntryDetailVm(args.Id) { IsEditMode = args.IsNew };
|
||||
await Model.GeneratePassword();
|
||||
if (args.IsNew) await Model.GeneratePassword();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,10 +80,5 @@ namespace ModernKeePass.Views
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async void Username_OnLostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await Model.SetFieldValue(nameof(Model.UserName), ((TextBox) sender).Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -42,17 +42,24 @@
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<StackPanel x:Name="OverflowButtons" Orientation="Horizontal">
|
||||
<Button Command="{Binding MoveCommand, ElementName=UserControl}" IsEnabled="{Binding IsMoveButtonEnabled, ElementName=UserControl}" Click="MoveButton_Click" Style="{StaticResource MenuButtonStyle}">
|
||||
<Button Command="{Binding SaveCommand, ElementName=UserControl}" Style="{StaticResource MenuButtonStyle}">
|
||||
<SymbolIcon Symbol="Save">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="TopMenuSaveButton" />
|
||||
</ToolTipService.ToolTip>
|
||||
</SymbolIcon>
|
||||
</Button>
|
||||
<Button Command="{Binding MoveCommand, ElementName=UserControl}" IsEnabled="{Binding IsMoveButtonEnabled, ElementName=UserControl}" Visibility="{Binding MoveButtonVisibility, ElementName=UserControl}" Click="MoveButton_Click" Style="{StaticResource MenuButtonStyle}">
|
||||
<SymbolIcon Symbol="MoveToFolder">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="TopMenuMoveButton" />
|
||||
</ToolTipService.ToolTip>
|
||||
</SymbolIcon>
|
||||
</Button>
|
||||
<Button Command="{Binding SaveCommand, ElementName=UserControl}" Style="{StaticResource MenuButtonStyle}">
|
||||
<SymbolIcon Symbol="Save">
|
||||
<Button Command="{Binding RestoreCommand, ElementName=UserControl}" Visibility="{Binding RestoreButtonVisibility, ElementName=UserControl}" Click="RestoreButton_Click" Style="{StaticResource MenuButtonStyle}">
|
||||
<SymbolIcon Symbol="Undo">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Uid="TopMenuSaveButton" />
|
||||
<ToolTip x:Uid="TopMenuRestoreButton" />
|
||||
</ToolTipService.ToolTip>
|
||||
</SymbolIcon>
|
||||
</Button>
|
||||
@@ -88,10 +95,11 @@
|
||||
<SymbolIcon Symbol="More" />
|
||||
<Button.Flyout>
|
||||
<MenuFlyout Opening="OverflowFlyout_OnOpening">
|
||||
<MenuFlyoutItem x:Uid="TopMenuMoveFlyout" x:Name="MoveFlyout" Command="{Binding MoveCommand, ElementName=UserControl}" Click="MoveButton_Click" IsEnabled="{Binding IsMoveButtonEnabled, ElementName=UserControl}" />
|
||||
<MenuFlyoutItem x:Uid="TopMenuSaveFlyout" Command="{Binding SaveCommand, ElementName=UserControl}" />
|
||||
<MenuFlyoutItem x:Uid="TopMenuMoveFlyout" x:Name="MoveFlyout" Command="{Binding MoveCommand, ElementName=UserControl}" IsEnabled="{Binding IsMoveButtonEnabled, ElementName=UserControl}" Visibility="{Binding MoveButtonVisibility, ElementName=UserControl}" Click="MoveButton_Click" />
|
||||
<MenuFlyoutItem x:Uid="TopMenuRestoreFlyout" x:Name="RestoreFlyout" Command="{Binding RestoreCommand, ElementName=UserControl}" Visibility="{Binding RestoreButtonVisibility, ElementName=UserControl}" Click="RestoreButton_Click" />
|
||||
<ToggleMenuFlyoutItem x:Uid="TopMenuEditFlyout" x:Name="EditFlyout" Command="{Binding EditCommand, ElementName=UserControl}" IsChecked="{Binding IsEditButtonChecked, ElementName=UserControl, Mode=TwoWay}" Click="EditButton_Click" />
|
||||
<MenuFlyoutItem x:Uid="TopMenuDeleteFlyout" x:Name="DeleteFlyout" Command="{Binding DeleteCommand, ElementName=UserControl}" Click="DeleteButton_Click" IsEnabled="{Binding IsDeleteButtonEnabled, ElementName=UserControl}" />
|
||||
<MenuFlyoutItem x:Uid="TopMenuDeleteFlyout" x:Name="DeleteFlyout" Command="{Binding DeleteCommand, ElementName=UserControl}" IsEnabled="{Binding IsDeleteButtonEnabled, ElementName=UserControl}" Click="DeleteButton_Click" />
|
||||
<MenuFlyoutItem x:Uid="TopMenuSortEntriesFlyout" x:Name="SortEntriesFlyout" Command="{Binding SortEntriesCommand, ElementName=UserControl}" Visibility="{Binding SortButtonVisibility, ElementName=UserControl}" />
|
||||
<MenuFlyoutItem x:Uid="TopMenuSortGroupsFlyout" x:Name="SortGroupsFlyout" Command="{Binding SortGroupsCommand, ElementName=UserControl}" Visibility="{Binding SortButtonVisibility, ElementName=UserControl}" />
|
||||
</MenuFlyout>
|
||||
|
@@ -56,6 +56,18 @@ namespace ModernKeePass.Views.UserControls
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(null, (o, args) => { }));
|
||||
|
||||
public ICommand RestoreCommand
|
||||
{
|
||||
get { return (ICommand)GetValue(RestoreCommandProperty); }
|
||||
set { SetValue(RestoreCommandProperty, value); }
|
||||
}
|
||||
public static readonly DependencyProperty RestoreCommandProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(RestoreCommand),
|
||||
typeof(ICommand),
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(null, (o, args) => { }));
|
||||
|
||||
public ICommand SortEntriesCommand
|
||||
{
|
||||
get { return (ICommand)GetValue(SortEntriesCommandProperty); }
|
||||
@@ -79,18 +91,6 @@ namespace ModernKeePass.Views.UserControls
|
||||
typeof(ICommand),
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(null, (o, args) => { }));
|
||||
|
||||
public bool IsMoveButtonEnabled
|
||||
{
|
||||
get { return (bool)GetValue(IsMoveButtonEnabledProperty); }
|
||||
set { SetValue(IsMoveButtonEnabledProperty, value); }
|
||||
}
|
||||
public static readonly DependencyProperty IsMoveButtonEnabledProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(IsMoveButtonEnabled),
|
||||
typeof(bool),
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(true, (o, args) => { }));
|
||||
|
||||
public Visibility SortButtonVisibility
|
||||
{
|
||||
@@ -104,6 +104,30 @@ namespace ModernKeePass.Views.UserControls
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(Visibility.Collapsed, (o, args) => { }));
|
||||
|
||||
public Visibility MoveButtonVisibility
|
||||
{
|
||||
get { return (Visibility)GetValue(MoveButtonVisibilityProperty); }
|
||||
set { SetValue(MoveButtonVisibilityProperty, value); }
|
||||
}
|
||||
public static readonly DependencyProperty MoveButtonVisibilityProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(MoveButtonVisibility),
|
||||
typeof(Visibility),
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(Visibility.Collapsed, (o, args) => { }));
|
||||
|
||||
public Visibility RestoreButtonVisibility
|
||||
{
|
||||
get { return (Visibility)GetValue(RestoreButtonVisibilityProperty); }
|
||||
set { SetValue(RestoreButtonVisibilityProperty, value); }
|
||||
}
|
||||
public static readonly DependencyProperty RestoreButtonVisibilityProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(RestoreButtonVisibility),
|
||||
typeof(Visibility),
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(Visibility.Collapsed, (o, args) => { }));
|
||||
|
||||
public bool IsDeleteButtonEnabled
|
||||
{
|
||||
get { return (bool)GetValue(IsDeleteButtonEnabledProperty); }
|
||||
@@ -116,6 +140,18 @@ namespace ModernKeePass.Views.UserControls
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(true, (o, args) => { }));
|
||||
|
||||
public bool IsMoveButtonEnabled
|
||||
{
|
||||
get { return (bool)GetValue(IsMoveButtonEnabledProperty); }
|
||||
set { SetValue(IsMoveButtonEnabledProperty, value); }
|
||||
}
|
||||
public static readonly DependencyProperty IsMoveButtonEnabledProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(IsMoveButtonEnabled),
|
||||
typeof(bool),
|
||||
typeof(TopMenuUserControl),
|
||||
new PropertyMetadata(true, (o, args) => { }));
|
||||
|
||||
public bool IsEditButtonChecked
|
||||
{
|
||||
get { return (bool)GetValue(IsEditButtonCheckedProperty); }
|
||||
@@ -131,6 +167,7 @@ namespace ModernKeePass.Views.UserControls
|
||||
public event EventHandler<RoutedEventArgs> EditButtonClick;
|
||||
public event EventHandler<RoutedEventArgs> DeleteButtonClick;
|
||||
public event EventHandler<RoutedEventArgs> MoveButtonClick;
|
||||
public event EventHandler<RoutedEventArgs> RestoreButtonClick;
|
||||
|
||||
public TopMenuUserControl()
|
||||
{
|
||||
@@ -158,6 +195,10 @@ namespace ModernKeePass.Views.UserControls
|
||||
{
|
||||
MoveButtonClick?.Invoke(sender, e);
|
||||
}
|
||||
private void RestoreButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RestoreButtonClick?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void OverflowFlyout_OnOpening(object sender, object e)
|
||||
{
|
||||
@@ -166,7 +207,8 @@ namespace ModernKeePass.Views.UserControls
|
||||
|
||||
EditFlyout.IsChecked = IsEditButtonChecked;
|
||||
|
||||
MoveFlyout.IsEnabled = IsMoveButtonEnabled;
|
||||
MoveFlyout.Visibility = MoveButtonVisibility;
|
||||
RestoreFlyout.Visibility = RestoreButtonVisibility;
|
||||
|
||||
SortEntriesFlyout.Visibility = SortButtonVisibility;
|
||||
SortGroupsFlyout.Visibility = SortButtonVisibility;
|
||||
@@ -179,5 +221,6 @@ namespace ModernKeePass.Views.UserControls
|
||||
SortEntriesButtonFlyout.Command = SortEntriesCommand;
|
||||
SortGroupsButtonFlyout.Command = SortGroupsCommand;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user