From a2eba91a3b5fd9e09de829578ad8bfde34e7994b Mon Sep 17 00:00:00 2001 From: Geoffroy BONNEVILLE Date: Tue, 14 Apr 2020 13:44:07 +0200 Subject: [PATCH] Added dirty behavior Removed restore action (-> Move action wip) Added additional check on DB size before auto saving Code cleanup --- ModernKeePass.Application/Application.csproj | 1 + .../Common/Behaviors/SetDirtyBehavior.cs | 35 +++++++ .../Common/Interfaces/IDatabaseProxy.cs | 3 +- .../SaveDatabase/SaveDatabaseCommand.cs | 4 +- .../Database/Models/DatabaseVm.cs | 2 + .../Queries/GetDatabase/GetDatabaseQuery.cs | 2 + .../Queries/OpenDatabase/OpenDatabaseQuery.cs | 1 + .../DependencyInjection.cs | 2 + .../DeleteEntry/DeleteEntryCommand.cs | 3 +- .../DeleteGroup/DeleteGroupCommand.cs | 3 +- ModernKeePass.Domain/Domain.csproj | 1 + .../Exceptions/DatabaseTooBigException.cs | 6 ++ .../KeePass/KeePassDatabaseClient.cs | 6 +- ModernKeePass/App.xaml.cs | 17 ++-- ModernKeePass/Common/Constants.cs | 15 +++ ModernKeePass/Interfaces/IVmEntity.cs | 4 - .../ResourceDictionaries/Styles.xaml | 2 + ModernKeePass/Strings/en-US/Resources.resw | 8 +- ModernKeePass/Strings/fr-FR/Resources.resw | 8 +- ModernKeePass/ViewModels/EntryDetailVm.cs | 51 ++++++----- ModernKeePass/ViewModels/GroupDetailVm.cs | 91 ++++++++----------- .../ViewModels/Items/SettingsSaveVm.cs | 5 +- ModernKeePass/Views/EntryDetailPage.xaml | 14 ++- ModernKeePass/Views/GroupDetailPage.xaml | 15 ++- .../BreadCrumbUserControl.xaml.cs | 2 +- .../ColorPickerUserControl.xaml.cs | 2 +- .../CompositeKeyUserControl.xaml.cs | 8 +- .../HamburgerMenuUserControl.xaml | 11 +-- .../HamburgerMenuUserControl.xaml.cs | 18 ++-- .../SymbolPickerUserControl.xaml.cs | 2 +- .../UserControls/TopMenuUserControl.xaml | 10 +- .../UserControls/TopMenuUserControl.xaml.cs | 64 ++++++------- ModernKeePass/Win81App.csproj | 1 + .../en-us/baselisting/releaseNotes.txt | 9 +- 34 files changed, 236 insertions(+), 190 deletions(-) create mode 100644 ModernKeePass.Application/Common/Behaviors/SetDirtyBehavior.cs create mode 100644 ModernKeePass.Domain/Exceptions/DatabaseTooBigException.cs create mode 100644 ModernKeePass/Common/Constants.cs diff --git a/ModernKeePass.Application/Application.csproj b/ModernKeePass.Application/Application.csproj index 5cee244..5e83155 100644 --- a/ModernKeePass.Application/Application.csproj +++ b/ModernKeePass.Application/Application.csproj @@ -75,6 +75,7 @@ + diff --git a/ModernKeePass.Application/Common/Behaviors/SetDirtyBehavior.cs b/ModernKeePass.Application/Common/Behaviors/SetDirtyBehavior.cs new file mode 100644 index 0000000..d2034ed --- /dev/null +++ b/ModernKeePass.Application/Common/Behaviors/SetDirtyBehavior.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using MediatR; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Database.Commands.CloseDatabase; +using ModernKeePass.Application.Database.Commands.SaveDatabase; + +namespace ModernKeePass.Application.Common.Behaviors +{ + public class SetDirtyBehavior : IPipelineBehavior + { + private readonly List _excludedCommands = new List + {nameof(SaveDatabaseCommand), nameof(CloseDatabaseCommand)}; + + private readonly IDatabaseProxy _database; + + public SetDirtyBehavior(IDatabaseProxy database) + { + _database = database; + } + + public async Task Handle(TRequest request, RequestHandlerDelegate next) + { + var response = await next(); + var queryName = typeof(TRequest).Name; + if (queryName.Contains("Command") && !_excludedCommands.Contains(queryName)) + { + _database.IsDirty = true; + } + + return response; + } + + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs index 1657f15..c7c9458 100644 --- a/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs +++ b/ModernKeePass.Application/Common/Interfaces/IDatabaseProxy.cs @@ -7,7 +7,6 @@ namespace ModernKeePass.Application.Common.Interfaces { public interface IDatabaseProxy { - string ZeroId { get; } bool IsOpen { get; } string Name { get; } string RootGroupId { get; } @@ -17,6 +16,8 @@ namespace ModernKeePass.Application.Common.Interfaces string Compression { get; set; } bool IsRecycleBinEnabled { get; set; } string FileAccessToken { get; set; } + int Size { get; set; } + bool IsDirty { get; set; } Task Open(byte[] file, Credentials credentials); Task ReOpen(byte[] file); diff --git a/ModernKeePass.Application/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs b/ModernKeePass.Application/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs index e3fa59f..36eafb3 100644 --- a/ModernKeePass.Application/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs +++ b/ModernKeePass.Application/Database/Commands/SaveDatabase/SaveDatabaseCommand.cs @@ -48,8 +48,10 @@ namespace ModernKeePass.Application.Database.Commands.SaveDatabase _file.ReleaseFile(_database.FileAccessToken); _database.FileAccessToken = message.FilePath; } + + _database.IsDirty = false; } - catch (Exception exception) + catch (ArgumentException exception) { throw new SaveException(exception); } diff --git a/ModernKeePass.Application/Database/Models/DatabaseVm.cs b/ModernKeePass.Application/Database/Models/DatabaseVm.cs index 8ad5e47..4f21cfd 100644 --- a/ModernKeePass.Application/Database/Models/DatabaseVm.cs +++ b/ModernKeePass.Application/Database/Models/DatabaseVm.cs @@ -10,5 +10,7 @@ public string Compression { get; set; } public string CipherId { get; set; } public string KeyDerivationId { get; set; } + public int Size { get; internal set; } + public bool IsDirty { get; internal set; } } } \ No newline at end of file diff --git a/ModernKeePass.Application/Database/Queries/GetDatabase/GetDatabaseQuery.cs b/ModernKeePass.Application/Database/Queries/GetDatabase/GetDatabaseQuery.cs index 4d207a8..35659f7 100644 --- a/ModernKeePass.Application/Database/Queries/GetDatabase/GetDatabaseQuery.cs +++ b/ModernKeePass.Application/Database/Queries/GetDatabase/GetDatabaseQuery.cs @@ -31,6 +31,8 @@ namespace ModernKeePass.Application.Database.Queries.GetDatabase database.Compression = _databaseProxy.Compression; database.CipherId = _databaseProxy.CipherId; database.KeyDerivationId = _databaseProxy.KeyDerivationId; + database.Size = _databaseProxy.Size; + database.IsDirty = _databaseProxy.IsDirty; } return database; } diff --git a/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs b/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs index ace9e79..baafb10 100644 --- a/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs +++ b/ModernKeePass.Application/Database/Queries/OpenDatabase/OpenDatabaseQuery.cs @@ -33,6 +33,7 @@ namespace ModernKeePass.Application.Database.Queries.OpenDatabase KeyFileContents = !string.IsNullOrEmpty(message.KeyFilePath) ? await _file.OpenBinaryFile(message.KeyFilePath): null, Password = message.Password }); + _database.Size = file.Length; _database.FileAccessToken = message.FilePath; } diff --git a/ModernKeePass.Application/DependencyInjection.cs b/ModernKeePass.Application/DependencyInjection.cs index c29f8ed..8b02a02 100644 --- a/ModernKeePass.Application/DependencyInjection.cs +++ b/ModernKeePass.Application/DependencyInjection.cs @@ -2,6 +2,7 @@ using FluentValidation; using MediatR; using Microsoft.Extensions.DependencyInjection; +using ModernKeePass.Application.Common.Behaviors; namespace ModernKeePass.Application { @@ -11,6 +12,7 @@ namespace ModernKeePass.Application { var assembly = typeof(DependencyInjection).GetTypeInfo().Assembly; services.AddMediatR(assembly); + services.AddTransient(typeof(IPipelineBehavior<,>), typeof(SetDirtyBehavior<,>)); //services.AddValidatorsFromAssembly(assembly); return services; diff --git a/ModernKeePass.Application/Group/Commands/DeleteEntry/DeleteEntryCommand.cs b/ModernKeePass.Application/Group/Commands/DeleteEntry/DeleteEntryCommand.cs index 73f47fd..d9a43bb 100644 --- a/ModernKeePass.Application/Group/Commands/DeleteEntry/DeleteEntryCommand.cs +++ b/ModernKeePass.Application/Group/Commands/DeleteEntry/DeleteEntryCommand.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using MediatR; using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Common; using ModernKeePass.Domain.Exceptions; namespace ModernKeePass.Application.Group.Commands.DeleteEntry @@ -24,7 +25,7 @@ namespace ModernKeePass.Application.Group.Commands.DeleteEntry { if (!_database.IsOpen) throw new DatabaseClosedException(); - if (_database.IsRecycleBinEnabled && (string.IsNullOrEmpty(_database.RecycleBinId) || _database.RecycleBinId.Equals(_database.ZeroId))) + if (_database.IsRecycleBinEnabled && (string.IsNullOrEmpty(_database.RecycleBinId) || _database.RecycleBinId.Equals(Constants.EmptyId))) { _database.CreateGroup(_database.RootGroupId, message.RecycleBinName, true); } diff --git a/ModernKeePass.Application/Group/Commands/DeleteGroup/DeleteGroupCommand.cs b/ModernKeePass.Application/Group/Commands/DeleteGroup/DeleteGroupCommand.cs index 0b09268..d157536 100644 --- a/ModernKeePass.Application/Group/Commands/DeleteGroup/DeleteGroupCommand.cs +++ b/ModernKeePass.Application/Group/Commands/DeleteGroup/DeleteGroupCommand.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using MediatR; using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Domain.Common; using ModernKeePass.Domain.Exceptions; namespace ModernKeePass.Application.Group.Commands.DeleteGroup @@ -24,7 +25,7 @@ namespace ModernKeePass.Application.Group.Commands.DeleteGroup { if (!_database.IsOpen) throw new DatabaseClosedException(); - if (_database.IsRecycleBinEnabled && (string.IsNullOrEmpty(_database.RecycleBinId) || _database.RecycleBinId.Equals(_database.ZeroId))) + if (_database.IsRecycleBinEnabled && (string.IsNullOrEmpty(_database.RecycleBinId) || _database.RecycleBinId.Equals(Constants.EmptyId))) { _database.CreateGroup(_database.RootGroupId, message.RecycleBinName, true); } diff --git a/ModernKeePass.Domain/Domain.csproj b/ModernKeePass.Domain/Domain.csproj index e75a3d8..2b52280 100644 --- a/ModernKeePass.Domain/Domain.csproj +++ b/ModernKeePass.Domain/Domain.csproj @@ -90,6 +90,7 @@ + diff --git a/ModernKeePass.Domain/Exceptions/DatabaseTooBigException.cs b/ModernKeePass.Domain/Exceptions/DatabaseTooBigException.cs new file mode 100644 index 0000000..6dfb764 --- /dev/null +++ b/ModernKeePass.Domain/Exceptions/DatabaseTooBigException.cs @@ -0,0 +1,6 @@ +using System; + +namespace ModernKeePass.Domain.Exceptions +{ + public class DatabaseTooBigException: Exception { } +} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs index f889343..c8932dc 100644 --- a/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs +++ b/ModernKeePass.Infrastructure/KeePass/KeePassDatabaseClient.cs @@ -25,9 +25,7 @@ namespace ModernKeePass.Infrastructure.KeePass private Credentials _credentials; // Flag: Has Dispose already been called? private bool _disposed; - - public string ZeroId => PwUuid.Zero.ToHexString(); - + // Main information public bool IsOpen => (_pwDatabase?.IsOpen).GetValueOrDefault(); public string Name => _pwDatabase?.Name; @@ -35,6 +33,8 @@ namespace ModernKeePass.Infrastructure.KeePass // TODO: find a correct place for this public string FileAccessToken { get; set; } + public int Size { get; set; } + public bool IsDirty { get; set; } // Settings public bool IsRecycleBinEnabled diff --git a/ModernKeePass/App.xaml.cs b/ModernKeePass/App.xaml.cs index fa58839..5365dc0 100644 --- a/ModernKeePass/App.xaml.cs +++ b/ModernKeePass/App.xaml.cs @@ -211,16 +211,17 @@ namespace ModernKeePass var deferral = e.SuspendingOperation.GetDeferral(); try { - if (_settings.GetSetting("SaveSuspend", true)) + var database = await _mediator.Send(new GetDatabaseQuery()); + if (database.IsOpen) { - await _mediator.Send(new SaveDatabaseCommand()).ConfigureAwait(false); - } + if (database.Size < Constants.File.OneMegaByte && database.IsDirty && + _settings.GetSetting(Constants.Settings.SaveSuspend, true)) + { + await _mediator.Send(new SaveDatabaseCommand()).ConfigureAwait(false); + } - await _mediator.Send(new CloseDatabaseCommand()).ConfigureAwait(false); - } - catch (DatabaseClosedException) - { - // Do nothing on purpose + await _mediator.Send(new CloseDatabaseCommand()).ConfigureAwait(false); + } } catch (Exception exception) { diff --git a/ModernKeePass/Common/Constants.cs b/ModernKeePass/Common/Constants.cs new file mode 100644 index 0000000..f2850b2 --- /dev/null +++ b/ModernKeePass/Common/Constants.cs @@ -0,0 +1,15 @@ +namespace ModernKeePass.Common +{ + public class Constants + { + public class File + { + public static int OneMegaByte => 1048576; + } + + public class Settings + { + public static string SaveSuspend => nameof(SaveSuspend); + } + } +} \ No newline at end of file diff --git a/ModernKeePass/Interfaces/IVmEntity.cs b/ModernKeePass/Interfaces/IVmEntity.cs index 4b9a174..714ce18 100644 --- a/ModernKeePass/Interfaces/IVmEntity.cs +++ b/ModernKeePass/Interfaces/IVmEntity.cs @@ -19,10 +19,6 @@ namespace ModernKeePass.Interfaces /// ICommand SaveCommand { get; } /// - /// Restore ViewModel - /// - ICommand UndoDeleteCommand { get; } - /// /// Move a entity to the destination group /// /// The destination to move the entity to diff --git a/ModernKeePass/ResourceDictionaries/Styles.xaml b/ModernKeePass/ResourceDictionaries/Styles.xaml index ad8132f..923a753 100644 --- a/ModernKeePass/ResourceDictionaries/Styles.xaml +++ b/ModernKeePass/ResourceDictionaries/Styles.xaml @@ -4,7 +4,9 @@ 60 + 300 60 + 300 diff --git a/ModernKeePass/Strings/en-US/Resources.resw b/ModernKeePass/Strings/en-US/Resources.resw index 0b0bba4..ad79d51 100644 --- a/ModernKeePass/Strings/en-US/Resources.resw +++ b/ModernKeePass/Strings/en-US/Resources.resw @@ -432,11 +432,11 @@ More - - Restore + + Move - - Restore + + Move Save diff --git a/ModernKeePass/Strings/fr-FR/Resources.resw b/ModernKeePass/Strings/fr-FR/Resources.resw index ab51db7..6cd16ab 100644 --- a/ModernKeePass/Strings/fr-FR/Resources.resw +++ b/ModernKeePass/Strings/fr-FR/Resources.resw @@ -432,11 +432,11 @@ Plus - - Restaurer + + Déplacer - - Restaurer + + Déplacer Sauvegarder diff --git a/ModernKeePass/ViewModels/EntryDetailVm.cs b/ModernKeePass/ViewModels/EntryDetailVm.cs index 1ce5ca4..41c1ef8 100644 --- a/ModernKeePass/ViewModels/EntryDetailVm.cs +++ b/ModernKeePass/ViewModels/EntryDetailVm.cs @@ -20,14 +20,13 @@ using ModernKeePass.Application.Security.Commands.GeneratePassword; using ModernKeePass.Application.Security.Queries.EstimatePasswordComplexity; using ModernKeePass.Common; using ModernKeePass.Domain.Enums; -using ModernKeePass.Domain.Interfaces; using ModernKeePass.Interfaces; using ModernKeePass.Application.Group.Models; using ModernKeePass.Domain.AOP; namespace ModernKeePass.ViewModels { - public class EntryDetailVm : NotifyPropertyChangedBase, IVmEntity, ISelectableModel + public class EntryDetailVm : NotifyPropertyChangedBase, IVmEntity { public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password); public bool HasExpired => HasExpirationDate && ExpiryDate < DateTime.Now; @@ -65,7 +64,7 @@ namespace ModernKeePass.ViewModels get { return _entry.Title; } set { - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Title), FieldValue = value}).Wait(); + SetFieldValue(nameof(Title), value).Wait(); _entry.Title = value; } } @@ -81,7 +80,7 @@ namespace ModernKeePass.ViewModels get { return _entry.Password; } set { - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Password), FieldValue = value }).Wait(); + SetFieldValue(nameof(Password), value).Wait(); _entry.Password = value; OnPropertyChanged(); OnPropertyChanged(nameof(PasswordComplexityIndicator)); @@ -93,7 +92,7 @@ namespace ModernKeePass.ViewModels get { return _entry.Url?.ToString(); } set { - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Url), FieldValue = value }).Wait(); + SetFieldValue(nameof(Url), value).Wait(); _entry.Url = new Uri(value); } } @@ -103,7 +102,7 @@ namespace ModernKeePass.ViewModels get { return _entry.Notes; } set { - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Notes), FieldValue = value }).Wait(); + SetFieldValue(nameof(Notes), value).Wait(); _entry.Notes = value; } } @@ -117,7 +116,7 @@ namespace ModernKeePass.ViewModels } set { - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(Icon), FieldValue = value }).Wait(); + SetFieldValue(nameof(Icon), value).Wait(); _entry.Icon = (Icon)value; } } @@ -128,7 +127,8 @@ namespace ModernKeePass.ViewModels set { if (!HasExpirationDate) return; - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = "ExpirationDate", FieldValue = value.Date }).Wait(); + + SetFieldValue("ExpirationDate", value).Wait(); _entry.ExpirationDate = value.Date; } } @@ -139,7 +139,8 @@ namespace ModernKeePass.ViewModels set { if (!HasExpirationDate) return; - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = "ExpirationDate", FieldValue = ExpiryDate.Date.Add(value) }).Wait(); + + SetFieldValue("ExpirationDate", value).Wait(); _entry.ExpirationDate = _entry.ExpirationDate.Date.Add(value); } } @@ -149,7 +150,7 @@ namespace ModernKeePass.ViewModels get { return _entry.HasExpirationDate; } set { - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(HasExpirationDate), FieldValue = value }).Wait(); + SetFieldValue(nameof(HasExpirationDate), value).Wait(); _entry.HasExpirationDate = value; OnPropertyChanged(); } @@ -162,7 +163,7 @@ namespace ModernKeePass.ViewModels { if (value != null) { - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(BackgroundColor), FieldValue = value }).Wait(); + SetFieldValue(nameof(BackgroundColor), value).Wait(); _entry.BackgroundColor = (Color)value; } } @@ -175,12 +176,12 @@ namespace ModernKeePass.ViewModels { if (value != null) { - _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = nameof(ForegroundColor), FieldValue = value }).Wait(); + SetFieldValue(nameof(ForegroundColor), value).Wait(); _entry.ForegroundColor = (Color)value; } } } - public IEnumerable History => _history; + public IEnumerable History { get; } public bool IsEditMode { @@ -200,16 +201,14 @@ namespace ModernKeePass.ViewModels set { SetProperty(ref _isRevealPassword, value); } } - public bool CanRestore => _entry.ParentGroupId == _database.RecycleBinId; - public ICommand SaveCommand { get; } public ICommand GeneratePasswordCommand { get; } - public ICommand UndoDeleteCommand { get; } - + public ICommand MoveCommand { get; } + + private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult(); + private readonly IMediator _mediator; - private readonly DatabaseVm _database; private readonly GroupVm _parent; - private readonly IEnumerable _history; private EntryVm _entry; private bool _isEditMode; private bool _isRevealPassword; @@ -224,17 +223,16 @@ namespace ModernKeePass.ViewModels public EntryDetailVm(string entryId, IMediator mediator, bool isNewEntry = false) { _mediator = mediator; - _database = _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult(); _entry = _mediator.Send(new GetEntryQuery {Id = entryId}).GetAwaiter().GetResult(); _parent = _mediator.Send(new GetGroupQuery {Id = _entry.ParentGroupId}).GetAwaiter().GetResult(); - _history = _entry.History; + History = _entry.History; _isEditMode = isNewEntry; if (isNewEntry) GeneratePassword().GetAwaiter().GetResult(); IsSelected = true; - SaveCommand = new RelayCommand(async () => await _mediator.Send(new SaveDatabaseCommand())); + SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty); GeneratePasswordCommand = new RelayCommand(async () => await GeneratePassword()); - UndoDeleteCommand = new RelayCommand(async () => await Move(_parent), () => _parent != null); + MoveCommand = new RelayCommand(async () => await Move(_parent), () => _parent != null); } public async Task GeneratePassword() @@ -269,6 +267,7 @@ namespace ModernKeePass.ViewModels public async Task SetFieldValue(string fieldName, object value) { await _mediator.Send(new SetFieldValueCommand { EntryId = Id, FieldName = fieldName, FieldValue = value }); + ((RelayCommand)SaveCommand).RaiseCanExecuteChanged(); } internal void SetEntry(EntryVm entry, int index) @@ -276,5 +275,11 @@ namespace ModernKeePass.ViewModels _entry = entry; IsSelected = index == 0; } + + private async Task SaveChanges() + { + await _mediator.Send(new SaveDatabaseCommand()); + ((RelayCommand)SaveCommand).RaiseCanExecuteChanged(); + } } } diff --git a/ModernKeePass/ViewModels/GroupDetailVm.cs b/ModernKeePass/ViewModels/GroupDetailVm.cs index 4875d92..d665928 100644 --- a/ModernKeePass/ViewModels/GroupDetailVm.cs +++ b/ModernKeePass/ViewModels/GroupDetailVm.cs @@ -25,12 +25,11 @@ using ModernKeePass.Application.Group.Queries.GetGroup; using ModernKeePass.Common; using ModernKeePass.Domain.AOP; using ModernKeePass.Domain.Enums; -using ModernKeePass.Domain.Interfaces; using ModernKeePass.Interfaces; namespace ModernKeePass.ViewModels { - public class GroupDetailVm : NotifyPropertyChangedBase, IVmEntity, ISelectableModel + public class GroupDetailVm : NotifyPropertyChangedBase, IVmEntity { public ObservableCollection Entries { get; } @@ -51,25 +50,8 @@ namespace ModernKeePass.ViewModels } } - public bool IsNotRoot => _database.RootGroupId != _group.Id; + public bool IsNotRoot => Database.RootGroupId != _group.Id; - public bool ShowRestore => IsNotRoot && _database.RecycleBinId != _group.Id; - - /// - /// Is the Group the database Recycle Bin? - /// - public bool IsSelected - { - get - { - return _database.IsRecycleBinEnabled && _database.RecycleBinId == _group.Id; - } - set - { - if (value && _group != null) _database.RecycleBinId = _group.Id; - } - } - public IOrderedEnumerable> EntriesZoomedOut => from e in Entries group e by e.Title.ToUpper().FirstOrDefault() into grp orderby grp.Key @@ -111,10 +93,11 @@ namespace ModernKeePass.ViewModels public ICommand SaveCommand { get; } public ICommand SortEntriesCommand { get; } public ICommand SortGroupsCommand { get; } - public ICommand UndoDeleteCommand { get; } + public ICommand MoveCommand { get; } + + private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult(); private readonly IMediator _mediator; - private readonly DatabaseVm _database; private readonly GroupVm _group; private readonly GroupVm _parent; private bool _isEditMode; @@ -129,7 +112,6 @@ namespace ModernKeePass.ViewModels public GroupDetailVm(string groupId, IMediator mediator, bool isEditMode = false) { _mediator = mediator; - _database = _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult(); _group = _mediator.Send(new GetGroupQuery { Id = groupId }).GetAwaiter().GetResult(); if (!string.IsNullOrEmpty(_group.ParentGroupId)) { @@ -138,18 +120,43 @@ namespace ModernKeePass.ViewModels } _isEditMode = isEditMode; - SaveCommand = new RelayCommand(async () => await _mediator.Send(new SaveDatabaseCommand())); - SortEntriesCommand = new RelayCommand(async () => - await SortEntriesAsync(), () => IsEditMode); - SortGroupsCommand = new RelayCommand(async () => - await SortGroupsAsync(), () => IsEditMode); - UndoDeleteCommand = new RelayCommand(async () => await Move(_parent), () => _parent != null); + SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty); + SortEntriesCommand = new RelayCommand(async () => await SortEntriesAsync(), () => IsEditMode); + SortGroupsCommand = new RelayCommand(async () => await SortGroupsAsync(), () => IsEditMode); + MoveCommand = new RelayCommand(async () => await Move(_parent), () => IsNotRoot); Entries = new ObservableCollection(_group.Entries); Entries.CollectionChanged += Entries_CollectionChanged; Groups = new ObservableCollection(_group.SubGroups); } + public async Task AddNewGroup(string name = "") + { + return (await _mediator.Send(new CreateGroupCommand {Name = name, ParentGroup = _group})).Id; + } + + public async Task AddNewEntry() + { + return (await _mediator.Send(new CreateEntryCommand { ParentGroup = _group })).Id; + } + + public async Task MarkForDelete(string recycleBinTitle) + { + await _mediator.Send(new DeleteGroupCommand { GroupId = _group.Id, ParentGroupId = _group.ParentGroupId, RecycleBinName = recycleBinTitle }); + } + + public async Task Move(GroupVm destination) + { + await _mediator.Send(new AddGroupCommand {ParentGroup = destination, Group = _group }); + await _mediator.Send(new RemoveGroupCommand {ParentGroup = _parent, Group = _group }); + } + + private async Task SaveChanges() + { + await _mediator.Send(new SaveDatabaseCommand()); + ((RelayCommand)SaveCommand).RaiseCanExecuteChanged(); + } + private async void Entries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) @@ -170,41 +177,21 @@ namespace ModernKeePass.ViewModels } break; } - } - - public async Task AddNewGroup(string name = "") - { - return (await _mediator.Send(new CreateGroupCommand {Name = name, ParentGroup = _group})).Id; - } - - public async Task AddNewEntry() - { - return (await _mediator.Send(new CreateEntryCommand { ParentGroup = _group })).Id; - } - - public async Task MarkForDelete(string recycleBinTitle) - { - await _mediator.Send(new DeleteGroupCommand { GroupId = _group.Id, ParentGroupId = _group.ParentGroupId, RecycleBinName = recycleBinTitle }); - - ((RelayCommand)UndoDeleteCommand).RaiseCanExecuteChanged(); - } - - public async Task Move(GroupVm destination) - { - await _mediator.Send(new AddGroupCommand {ParentGroup = destination, Group = _group }); - await _mediator.Send(new RemoveGroupCommand {ParentGroup = _parent, Group = _group }); + ((RelayCommand)SaveCommand).RaiseCanExecuteChanged(); } private async Task SortEntriesAsync() { await _mediator.Send(new SortEntriesCommand {Group = _group}); OnPropertyChanged(nameof(Entries)); + ((RelayCommand)SaveCommand).RaiseCanExecuteChanged(); } private async Task SortGroupsAsync() { await _mediator.Send(new SortGroupsCommand {Group = _group}); OnPropertyChanged(nameof(Groups)); + ((RelayCommand)SaveCommand).RaiseCanExecuteChanged(); } } } diff --git a/ModernKeePass/ViewModels/Items/SettingsSaveVm.cs b/ModernKeePass/ViewModels/Items/SettingsSaveVm.cs index 4289d7f..66f8034 100644 --- a/ModernKeePass/ViewModels/Items/SettingsSaveVm.cs +++ b/ModernKeePass/ViewModels/Items/SettingsSaveVm.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Common; namespace ModernKeePass.ViewModels { @@ -17,8 +18,8 @@ namespace ModernKeePass.ViewModels public bool IsSaveSuspend { - get { return _settings.GetSetting("SaveSuspend", true); } - set { _settings.PutSetting("SaveSuspend", value); } + get { return _settings.GetSetting(Constants.Settings.SaveSuspend, true); } + set { _settings.PutSetting(Constants.Settings.SaveSuspend, value); } } } } \ No newline at end of file diff --git a/ModernKeePass/Views/EntryDetailPage.xaml b/ModernKeePass/Views/EntryDetailPage.xaml index f75adde..39cf40b 100644 --- a/ModernKeePass/Views/EntryDetailPage.xaml +++ b/ModernKeePass/Views/EntryDetailPage.xaml @@ -390,7 +390,7 @@ - + @@ -487,7 +487,7 @@ Style="{StaticResource NoBorderButtonStyle}"> - + @@ -523,12 +523,10 @@ + MoveCommand="{Binding MoveCommand}"> @@ -536,9 +534,9 @@ - + - + diff --git a/ModernKeePass/Views/GroupDetailPage.xaml b/ModernKeePass/Views/GroupDetailPage.xaml index 90ab9b6..72e6b2e 100644 --- a/ModernKeePass/Views/GroupDetailPage.xaml +++ b/ModernKeePass/Views/GroupDetailPage.xaml @@ -45,10 +45,10 @@ - + - + @@ -61,7 +61,7 @@ - + @@ -233,13 +233,12 @@ @@ -249,9 +248,9 @@ - + - + diff --git a/ModernKeePass/Views/UserControls/BreadCrumbUserControl.xaml.cs b/ModernKeePass/Views/UserControls/BreadCrumbUserControl.xaml.cs index 9b50c61..62fa708 100644 --- a/ModernKeePass/Views/UserControls/BreadCrumbUserControl.xaml.cs +++ b/ModernKeePass/Views/UserControls/BreadCrumbUserControl.xaml.cs @@ -21,7 +21,7 @@ namespace ModernKeePass.Views.UserControls public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( - "ItemsSource", + nameof(ItemsSource), typeof(IEnumerable), typeof(BreadCrumbUserControl), new PropertyMetadata(new Stack(), (o, args) => { })); diff --git a/ModernKeePass/Views/UserControls/ColorPickerUserControl.xaml.cs b/ModernKeePass/Views/UserControls/ColorPickerUserControl.xaml.cs index 692648e..417202e 100644 --- a/ModernKeePass/Views/UserControls/ColorPickerUserControl.xaml.cs +++ b/ModernKeePass/Views/UserControls/ColorPickerUserControl.xaml.cs @@ -26,7 +26,7 @@ namespace ModernKeePass.Views.UserControls } public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register( - "SelectedColor", + nameof(SelectedColor), typeof(SolidColorBrush), typeof(ColorPickerUserControl), new PropertyMetadata(new SolidColorBrush(), (o, args) => { })); diff --git a/ModernKeePass/Views/UserControls/CompositeKeyUserControl.xaml.cs b/ModernKeePass/Views/UserControls/CompositeKeyUserControl.xaml.cs index a66bb7d..8cd8cc0 100644 --- a/ModernKeePass/Views/UserControls/CompositeKeyUserControl.xaml.cs +++ b/ModernKeePass/Views/UserControls/CompositeKeyUserControl.xaml.cs @@ -34,7 +34,7 @@ namespace ModernKeePass.Views.UserControls } public static readonly DependencyProperty CreateNewProperty = DependencyProperty.Register( - "CreateNew", + nameof(CreateNew), typeof(bool), typeof(CompositeKeyUserControl), new PropertyMetadata(false, (o, args) => { })); @@ -46,7 +46,7 @@ namespace ModernKeePass.Views.UserControls } public static readonly DependencyProperty UpdateKeyProperty = DependencyProperty.Register( - "UpdateKey", + nameof(UpdateKey), typeof(bool), typeof(CompositeKeyUserControl), new PropertyMetadata(false, (o, args) => { })); @@ -58,7 +58,7 @@ namespace ModernKeePass.Views.UserControls } public static readonly DependencyProperty ButtonLabelProperty = DependencyProperty.Register( - "ButtonLabel", + nameof(ButtonLabel), typeof(string), typeof(CompositeKeyUserControl), new PropertyMetadata("OK", (o, args) => { })); @@ -70,7 +70,7 @@ namespace ModernKeePass.Views.UserControls } public static readonly DependencyProperty DatabaseFilePathProperty = DependencyProperty.Register( - "DatabaseFilePath", + nameof(DatabaseFilePath), typeof(string), typeof(CompositeKeyUserControl), new PropertyMetadata(null, (o, args) => { })); diff --git a/ModernKeePass/Views/UserControls/HamburgerMenuUserControl.xaml b/ModernKeePass/Views/UserControls/HamburgerMenuUserControl.xaml index 4912863..a8cd6c0 100644 --- a/ModernKeePass/Views/UserControls/HamburgerMenuUserControl.xaml +++ b/ModernKeePass/Views/UserControls/HamburgerMenuUserControl.xaml @@ -23,7 +23,6 @@ Foreground="{ThemeResource DefaultTextForegroundThemeBrush}" ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}"> - 300 @@ -51,13 +50,13 @@ - + - + @@ -72,7 +71,7 @@ - - - @@ -76,7 +76,7 @@ -