diff --git a/ModernKeePass.Application/Application.csproj b/ModernKeePass.Application/Application.csproj
index ad4f0f3..989b640 100644
--- a/ModernKeePass.Application/Application.csproj
+++ b/ModernKeePass.Application/Application.csproj
@@ -89,6 +89,7 @@
+
diff --git a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs
index 1fc3e48..7f82bb8 100644
--- a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs
+++ b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs
@@ -45,6 +45,7 @@ namespace ModernKeePass.Application.Common.Interfaces
void AddHistory(string entryId);
void RestoreFromHistory(string entryId, int historyIndex);
+ void DeleteHistory(string entryId, int historyIndex);
IEnumerable Search(string groupId, string text);
}
diff --git a/ModernKeePass.Application/Entry/Commands/DeleteHistory/DeleteHistoryCommand.cs b/ModernKeePass.Application/Entry/Commands/DeleteHistory/DeleteHistoryCommand.cs
new file mode 100644
index 0000000..97918ec
--- /dev/null
+++ b/ModernKeePass.Application/Entry/Commands/DeleteHistory/DeleteHistoryCommand.cs
@@ -0,0 +1,29 @@
+using MediatR;
+using ModernKeePass.Application.Common.Interfaces;
+using ModernKeePass.Domain.Exceptions;
+
+namespace ModernKeePass.Application.Entry.Commands.DeleteHistory
+{
+ public class DeleteHistoryCommand : IRequest
+ {
+ public string EntryId { get; set; }
+ public int HistoryIndex { get; set; }
+
+ public class DeleteHistoryCommandHandler : IRequestHandler
+ {
+ private readonly IDatabaseProxy _database;
+
+ public DeleteHistoryCommandHandler(IDatabaseProxy database)
+ {
+ _database = database;
+ }
+
+ public void Handle(DeleteHistoryCommand message)
+ {
+ if (!_database.IsOpen) throw new DatabaseClosedException();
+
+ _database.DeleteHistory(message.EntryId, message.HistoryIndex);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ModernKeePass.Application/Entry/Models/EntryVm.cs b/ModernKeePass.Application/Entry/Models/EntryVm.cs
index 7b31543..c712564 100644
--- a/ModernKeePass.Application/Entry/Models/EntryVm.cs
+++ b/ModernKeePass.Application/Entry/Models/EntryVm.cs
@@ -28,7 +28,6 @@ namespace ModernKeePass.Application.Entry.Models
public bool HasExpirationDate { get; set; }
public DateTimeOffset ExpirationDate { get; set; }
public DateTimeOffset ModificationDate { get; set; }
- public bool IsDirty { get; set; }
public override string ToString()
{
@@ -47,7 +46,7 @@ namespace ModernKeePass.Application.Entry.Models
.ForMember(d => d.Url, opts => opts.MapFrom(s => s.Url))
.ForMember(d => d.Notes, opts => opts.MapFrom(s => s.Notes))
.ForMember(d => d.AdditionalFields, opts => opts.MapFrom(s => s.AdditionalFields))
- .ForMember(d => d.History, opts => opts.MapFrom(s => s.History.OrderByDescending(h => h.LastModificationDate)))
+ .ForMember(d => d.History, opts => opts.MapFrom(s => s.History.Reverse()))
.ForMember(d => d.HasExpirationDate, opts => opts.MapFrom(s => s.HasExpirationDate))
.ForMember(d => d.ExpirationDate, opts => opts.MapFrom(s => s.ExpirationDate))
.ForMember(d => d.ModificationDate, opts => opts.MapFrom(s => s.LastModificationDate))
diff --git a/ModernKeePass.Application/Group/Models/GroupVm.cs b/ModernKeePass.Application/Group/Models/GroupVm.cs
index c7428a8..829ff96 100644
--- a/ModernKeePass.Application/Group/Models/GroupVm.cs
+++ b/ModernKeePass.Application/Group/Models/GroupVm.cs
@@ -9,7 +9,7 @@ using ModernKeePass.Domain.Interfaces;
namespace ModernKeePass.Application.Group.Models
{
- public class GroupVm: IEntityVm, ISelectableModel, IMapFrom
+ public class GroupVm: IEntityVm, IMapFrom
{
public string ParentGroupId { get; set; }
public string ParentGroupName { get; set; }
@@ -18,7 +18,6 @@ namespace ModernKeePass.Application.Group.Models
public Icon Icon { get; set; }
public List SubGroups { get; set; }
public List Entries { get; set; }
- public bool IsSelected { get; set; }
public override string ToString()
{
diff --git a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs
index c28a288..b8882d9 100644
--- a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs
+++ b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs
@@ -266,6 +266,12 @@ namespace ModernKeePass.Infrastructure.KeePass
pwEntry.Touch(true);
}
+ public void DeleteHistory(string entryId, int historyIndex)
+ {
+ var pwEntry = _pwDatabase.RootGroup.FindEntry(BuildIdFromString(entryId), true);
+ pwEntry.History.RemoveAt((uint)historyIndex);
+ }
+
public void UpdateGroup(string groupId)
{
throw new NotImplementedException();
diff --git a/ModernKeePass/Strings/en-US/CodeBehind.resw b/ModernKeePass/Strings/en-US/CodeBehind.resw
index 858ffbc..169b342 100644
--- a/ModernKeePass/Strings/en-US/CodeBehind.resw
+++ b/ModernKeePass/Strings/en-US/CodeBehind.resw
@@ -258,4 +258,10 @@
The CSV file needs to be formatted as such: Name of the account;Login;Password;URL;Comments
+
+ Deleting this history entry will not delete current entry.
+
+
+ Delete history entry ?
+
\ No newline at end of file
diff --git a/ModernKeePass/Strings/fr-FR/CodeBehind.resw b/ModernKeePass/Strings/fr-FR/CodeBehind.resw
index 22a3848..eecc35b 100644
--- a/ModernKeePass/Strings/fr-FR/CodeBehind.resw
+++ b/ModernKeePass/Strings/fr-FR/CodeBehind.resw
@@ -258,4 +258,10 @@
Le fichier CSV doit être formatté de la façon suivante: Nom du compte;Login;Mot de passe;URL;Commentaires
+
+ Supprimer cet historique ne supprimera pas l'entrée en cours.
+
+
+ Supprimer cet historique ?
+
\ No newline at end of file
diff --git a/ModernKeePass/ViewModels/EntryDetailVm.cs b/ModernKeePass/ViewModels/EntryDetailVm.cs
index c5bef11..3bcf093 100644
--- a/ModernKeePass/ViewModels/EntryDetailVm.cs
+++ b/ModernKeePass/ViewModels/EntryDetailVm.cs
@@ -11,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.DeleteHistory;
using ModernKeePass.Application.Entry.Commands.RestoreHistory;
using ModernKeePass.Application.Entry.Commands.SetFieldValue;
using ModernKeePass.Application.Entry.Models;
@@ -44,17 +45,42 @@ namespace ModernKeePass.ViewModels
public bool SpecialPatternSelected { get; set; }
public bool BracketsPatternSelected { get; set; }
public string CustomChars { get; set; } = string.Empty;
- public string Id => _entry.Id;
+ public string Id => SelectedItem.Id;
+
+ public bool IsRecycleOnDelete
+ {
+ get
+ {
+ var database = Database;
+ return database.IsRecycleBinEnabled && _parent.Id != database.RecycleBinId;
+ }
+ }
public IEnumerable BreadCrumb => new List { _parent };
+ public ObservableCollection History { get; }
///
/// Determines if the Entry is current or from history
///
- public bool IsSelected
+ public bool IsCurrentEntry => SelectedIndex == 0;
+
+ public EntryVm SelectedItem
{
- get { return _isSelected; }
- set { SetProperty(ref _isSelected, value); }
+ get { return _selectedItem; }
+ set
+ {
+ SetProperty(ref _selectedItem, value);
+ if (value != null) OnPropertyChanged();
+ }
+ }
+ public int SelectedIndex
+ {
+ get { return _selectedIndex; }
+ set
+ {
+ SetProperty(ref _selectedIndex, value);
+ OnPropertyChanged(nameof(IsCurrentEntry));
+ }
}
public double PasswordLength
@@ -65,26 +91,26 @@ namespace ModernKeePass.ViewModels
public string Title
{
- get { return _entry.Title; }
+ get { return SelectedItem.Title; }
set
{
- _entry.Title = value;
+ SelectedItem.Title = value;
SetFieldValue(nameof(Title), value).Wait();
}
}
public string UserName
{
- get { return _entry.Username; }
- set { _entry.Username = value; }
+ get { return SelectedItem.Username; }
+ set { SelectedItem.Username = value; }
}
public string Password
{
- get { return _entry.Password; }
+ get { return SelectedItem.Password; }
set
{
- _entry.Password = value;
+ SelectedItem.Password = value;
SetFieldValue(nameof(Password), value).Wait();
OnPropertyChanged(nameof(Password));
OnPropertyChanged(nameof(PasswordComplexityIndicator));
@@ -93,64 +119,64 @@ namespace ModernKeePass.ViewModels
public string Url
{
- get { return _entry.Url?.ToString(); }
+ get { return SelectedItem.Url?.ToString(); }
set
{
- _entry.Url = new Uri(value);
+ SelectedItem.Url = new Uri(value);
SetFieldValue(nameof(Url), value).Wait();
}
}
public string Notes
{
- get { return _entry.Notes; }
+ get { return SelectedItem.Notes; }
set
{
- _entry.Notes = value;
+ SelectedItem.Notes = value;
SetFieldValue(nameof(Notes), value).Wait();
}
}
public Symbol Icon
{
- get { return (Symbol)Enum.Parse(typeof(Symbol), _entry.Icon.ToString()); }
+ get { return (Symbol)Enum.Parse(typeof(Symbol), SelectedItem.Icon.ToString()); }
set
{
- _entry.Icon = (Icon)Enum.Parse(typeof(Icon), value.ToString());
- SetFieldValue(nameof(Icon), _entry.Icon).Wait();
+ SelectedItem.Icon = (Icon)Enum.Parse(typeof(Icon), value.ToString());
+ SetFieldValue(nameof(Icon), SelectedItem.Icon).Wait();
}
}
public DateTimeOffset ExpiryDate
{
- get { return _entry.ExpirationDate; }
+ get { return SelectedItem.ExpirationDate; }
set
{
if (!HasExpirationDate) return;
- _entry.ExpirationDate = value.Date;
- SetFieldValue("ExpirationDate", _entry.ExpirationDate).Wait();
+ SelectedItem.ExpirationDate = value.Date;
+ SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate).Wait();
}
}
public TimeSpan ExpiryTime
{
- get { return _entry.ExpirationDate.TimeOfDay; }
+ get { return SelectedItem.ExpirationDate.TimeOfDay; }
set
{
if (!HasExpirationDate) return;
- _entry.ExpirationDate = _entry.ExpirationDate.Date.Add(value);
- SetFieldValue("ExpirationDate", _entry.ExpirationDate).Wait();
+ SelectedItem.ExpirationDate = SelectedItem.ExpirationDate.Date.Add(value);
+ SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate).Wait();
}
}
public bool HasExpirationDate
{
- get { return _entry.HasExpirationDate; }
+ get { return SelectedItem.HasExpirationDate; }
set
{
- _entry.HasExpirationDate = value;
+ SelectedItem.HasExpirationDate = value;
SetFieldValue(nameof(HasExpirationDate), value).Wait();
OnPropertyChanged(nameof(HasExpirationDate));
}
@@ -158,29 +184,28 @@ namespace ModernKeePass.ViewModels
public SolidColorBrush BackgroundColor
{
- get { return _entry?.BackgroundColor.ToSolidColorBrush(); }
+ get { return SelectedItem?.BackgroundColor.ToSolidColorBrush(); }
set
{
- _entry.BackgroundColor = value.ToColor();
- SetFieldValue(nameof(BackgroundColor), _entry.BackgroundColor).Wait();
+ SelectedItem.BackgroundColor = value.ToColor();
+ SetFieldValue(nameof(BackgroundColor), SelectedItem.BackgroundColor).Wait();
}
}
public SolidColorBrush ForegroundColor
{
- get { return _entry?.ForegroundColor.ToSolidColorBrush(); }
+ get { return SelectedItem?.ForegroundColor.ToSolidColorBrush(); }
set
{
- _entry.ForegroundColor = value.ToColor();
- SetFieldValue(nameof(ForegroundColor), _entry.ForegroundColor).Wait();
+ SelectedItem.ForegroundColor = value.ToColor();
+ SetFieldValue(nameof(ForegroundColor), SelectedItem.ForegroundColor).Wait();
}
}
- public ObservableCollection History { get; }
public bool IsEditMode
{
- get { return IsSelected && _isEditMode; }
+ get { return IsCurrentEntry && _isEditMode; }
set { SetProperty(ref _isEditMode, value); }
}
@@ -199,11 +224,12 @@ namespace ModernKeePass.ViewModels
private readonly IMediator _mediator;
private readonly GroupVm _parent;
- private EntryVm _entry;
+ private EntryVm _selectedItem;
+ private int _selectedIndex;
private bool _isEditMode;
private bool _isRevealPassword;
private double _passwordLength = 25;
- private bool _isSelected;
+ private bool _isDirty;
public EntryDetailVm() { }
@@ -212,14 +238,14 @@ 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 = new ObservableCollection {_entry};
- foreach (var entry in _entry.History)
+ SelectedItem = _mediator.Send(new GetEntryQuery { Id = entryId }).GetAwaiter().GetResult();
+ _parent = _mediator.Send(new GetGroupQuery { Id = SelectedItem.ParentGroupId }).GetAwaiter().GetResult();
+ History = new ObservableCollection { SelectedItem };
+ foreach (var entry in SelectedItem.History)
{
History.Add(entry);
}
- IsSelected = true;
+ SelectedIndex = 0;
SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty);
GeneratePasswordCommand = new RelayCommand(async () => await GeneratePassword());
@@ -247,41 +273,41 @@ namespace ModernKeePass.ViewModels
public async Task MarkForDelete(string recycleBinTitle)
{
- await _mediator.Send(new DeleteEntryCommand {EntryId = Id, ParentGroupId = _entry.ParentGroupId, RecycleBinName = recycleBinTitle});
+ await _mediator.Send(new DeleteEntryCommand {EntryId = Id, ParentGroupId = SelectedItem.ParentGroupId, RecycleBinName = recycleBinTitle});
}
public async Task Move(GroupVm destination)
{
- await _mediator.Send(new AddEntryCommand { ParentGroup = destination, Entry = _entry });
- await _mediator.Send(new RemoveEntryCommand { ParentGroup = _parent, Entry = _entry });
+ await _mediator.Send(new AddEntryCommand { ParentGroup = destination, Entry = SelectedItem });
+ await _mediator.Send(new RemoveEntryCommand { ParentGroup = _parent, Entry = SelectedItem });
}
public async Task SetFieldValue(string fieldName, object value)
{
await _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = fieldName, FieldValue = value });
((RelayCommand)SaveCommand).RaiseCanExecuteChanged();
- _entry.IsDirty = true;
+ _isDirty = true;
}
public async Task AddHistory()
{
- if (_entry.IsDirty) await _mediator.Send(new AddHistoryCommand { EntryId = Id });
+ if (_isDirty) await _mediator.Send(new AddHistoryCommand { EntryId = Id });
}
-
- internal void SetEntry(EntryVm entry, int index)
- {
- _entry = entry;
- IsSelected = index == 0;
- 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);
+ await _mediator.Send(new RestoreHistoryCommand { EntryId = Id, HistoryIndex = History.Count - SelectedIndex - 1 });
+ History.Insert(0, SelectedItem);
+ SelectedIndex = 0;
+ ((RelayCommand)SaveCommand).RaiseCanExecuteChanged();
+ }
+
+ public async Task DeleteHistory()
+ {
+ await _mediator.Send(new DeleteHistoryCommand { EntryId = Id, HistoryIndex = History.Count - SelectedIndex - 1 });
+ History.RemoveAt(SelectedIndex);
+ SelectedIndex = 0;
+ ((RelayCommand)SaveCommand).RaiseCanExecuteChanged();
}
private async Task SaveChanges()
@@ -289,7 +315,7 @@ namespace ModernKeePass.ViewModels
await AddHistory();
await _mediator.Send(new SaveDatabaseCommand());
((RelayCommand)SaveCommand).RaiseCanExecuteChanged();
- _entry.IsDirty = false;
+ _isDirty = false;
}
}
}
diff --git a/ModernKeePass/ViewModels/RecentVm.cs b/ModernKeePass/ViewModels/RecentVm.cs
index 246ae42..3084bbc 100644
--- a/ModernKeePass/ViewModels/RecentVm.cs
+++ b/ModernKeePass/ViewModels/RecentVm.cs
@@ -1,6 +1,5 @@
using System.Collections.ObjectModel;
using System.Linq;
-using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.Extensions.DependencyInjection;
using ModernKeePass.Application.Common.Interfaces;
diff --git a/ModernKeePass/Views/EntryDetailPage.xaml b/ModernKeePass/Views/EntryDetailPage.xaml
index e87892a..de553c5 100644
--- a/ModernKeePass/Views/EntryDetailPage.xaml
+++ b/ModernKeePass/Views/EntryDetailPage.xaml
@@ -388,7 +388,11 @@
-
+
@@ -409,7 +413,7 @@
-
+
@@ -418,8 +422,8 @@
-
-
+
+
@@ -430,7 +434,7 @@
-
+
@@ -438,8 +442,8 @@
-
-
+
+
@@ -458,11 +462,11 @@
-
+
-
+
@@ -529,21 +533,16 @@
+ RestoreCommand="{Binding RestoreCommand}"
+ DeleteButtonClick="TopMenu_OnDeleteButtonClick">
-
-
-
-
-
-
diff --git a/ModernKeePass/Views/EntryDetailPage.xaml.cs b/ModernKeePass/Views/EntryDetailPage.xaml.cs
index cab2573..0139688 100644
--- a/ModernKeePass/Views/EntryDetailPage.xaml.cs
+++ b/ModernKeePass/Views/EntryDetailPage.xaml.cs
@@ -1,5 +1,4 @@
using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using ModernKeePass.Common;
using ModernKeePass.Models;
@@ -22,7 +21,7 @@ namespace ModernKeePass.Views
/// gestion de la durée de vie des processus
///
public NavigationHelper NavigationHelper { get; }
-
+
public EntryDetailPage()
{
InitializeComponent();
@@ -65,19 +64,35 @@ namespace ModernKeePass.Views
VisualStateManager.GoToState(TopMenu, e.NewSize.Width < 800 ? "Collapsed" : "Overflowed", true);
}
- private void HamburgerMenuUserControl_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+ private async void TopMenu_OnDeleteButtonClick(object sender, RoutedEventArgs e)
{
- var listView = sender as ListView;
- if (listView == null) return;
- var index = listView.SelectedIndex;
- switch (index)
+ var resource = new ResourceHelper();
+ if (Model.IsCurrentEntry)
{
- case -1:
- return;
- default:
- var entry = listView.SelectedItem as Application.Entry.Models.EntryVm;
- Model.SetEntry(entry, index);
- break;
+ var isRecycleOnDelete = Model.IsRecycleOnDelete;
+
+ var message = isRecycleOnDelete
+ ? resource.GetResourceValue("EntryRecyclingConfirmation")
+ : resource.GetResourceValue("EntryDeletingConfirmation");
+ await MessageDialogHelper.ShowActionDialog(resource.GetResourceValue("EntityDeleteTitle"), message,
+ resource.GetResourceValue("EntityDeleteActionButton"),
+ resource.GetResourceValue("EntityDeleteCancelButton"), async a =>
+ {
+ var text = isRecycleOnDelete ? resource.GetResourceValue("EntryRecycled") : resource.GetResourceValue("EntryDeleted");
+ //ToastNotificationHelper.ShowMovedToast(Entity, _resource.GetResourceValue("EntityDeleting"), text);
+ await Model.MarkForDelete(resource.GetResourceValue("RecycleBinTitle"));
+ NavigationHelper.GoBack();
+ }, null);
+ }
+ else
+ {
+ await MessageDialogHelper.ShowActionDialog(resource.GetResourceValue("HistoryDeleteTitle"), resource.GetResourceValue("HistoryDeleteDescription"),
+ resource.GetResourceValue("EntityDeleteActionButton"),
+ resource.GetResourceValue("EntityDeleteCancelButton"), async a =>
+ {
+ //ToastNotificationHelper.ShowMovedToast(Entity, _resource.GetResourceValue("EntityDeleting"), text);
+ await Model.DeleteHistory();
+ }, null);
}
}
}
diff --git a/ModernKeePass/Views/UserControls/HamburgerMenuUserControl.xaml b/ModernKeePass/Views/UserControls/HamburgerMenuUserControl.xaml
index a8cd6c0..a295250 100644
--- a/ModernKeePass/Views/UserControls/HamburgerMenuUserControl.xaml
+++ b/ModernKeePass/Views/UserControls/HamburgerMenuUserControl.xaml
@@ -15,7 +15,8 @@
{ }));
+ public int SelectedIndex
+ {
+ get { return (int)GetValue(SelectedIndexProperty); }
+ set { SetValue(SelectedIndexProperty, value); }
+ }
+ public static readonly DependencyProperty SelectedIndexProperty =
+ DependencyProperty.Register(
+ nameof(SelectedIndex),
+ typeof(int),
+ typeof(HamburgerMenuUserControl),
+ new PropertyMetadata(-1, (o, args) => { }));
+
public bool IsOpen
{
get { return (bool)GetValue(IsOpenProperty); }
diff --git a/ModernKeePass/appMetadata/en-us/baselisting/releaseNotes.txt b/ModernKeePass/appMetadata/en-us/baselisting/releaseNotes.txt
index 5c60c70..2cbde5e 100644
--- a/ModernKeePass/appMetadata/en-us/baselisting/releaseNotes.txt
+++ b/ModernKeePass/appMetadata/en-us/baselisting/releaseNotes.txt
@@ -1,4 +1,5 @@
Database corruption issues should now be a thing of the past !
Added the ability to move entries and groups
Edits are now in a popup instead of inline
+Allows restoring and deleting from entry history
Updated KeePass lib to version 2.44
\ No newline at end of file