diff --git a/ModernKeePass.Application/Group/Commands/SortEntries/SortEntriesCommand.cs b/ModernKeePass.Application/Group/Commands/SortEntries/SortEntriesCommand.cs index 1685afd..d161379 100644 --- a/ModernKeePass.Application/Group/Commands/SortEntries/SortEntriesCommand.cs +++ b/ModernKeePass.Application/Group/Commands/SortEntries/SortEntriesCommand.cs @@ -1,4 +1,5 @@ -using MediatR; +using System.Linq; +using MediatR; using ModernKeePass.Application.Common.Interfaces; using ModernKeePass.Application.Group.Models; using ModernKeePass.Domain.Exceptions; @@ -23,6 +24,7 @@ namespace ModernKeePass.Application.Group.Commands.SortEntries if (!_database.IsOpen) throw new DatabaseClosedException(); _database.SortEntries(message.Group.Id); + message.Group.Entries = message.Group.Entries.OrderBy(e => e.Title).ToList(); } } } diff --git a/ModernKeePass.Application/Group/Commands/SortGroups/SortGroupsCommand.cs b/ModernKeePass.Application/Group/Commands/SortGroups/SortGroupsCommand.cs index 5fd58c5..7235e1e 100644 --- a/ModernKeePass.Application/Group/Commands/SortGroups/SortGroupsCommand.cs +++ b/ModernKeePass.Application/Group/Commands/SortGroups/SortGroupsCommand.cs @@ -1,4 +1,6 @@ -using MediatR; +using System.Collections.Generic; +using System.Linq; +using MediatR; using ModernKeePass.Application.Common.Interfaces; using ModernKeePass.Application.Group.Models; using ModernKeePass.Domain.Exceptions; @@ -23,6 +25,7 @@ namespace ModernKeePass.Application.Group.Commands.SortGroups if (!_database.IsOpen) throw new DatabaseClosedException(); _database.SortSubGroups(message.Group.Id); + message.Group.SubGroups = message.Group.SubGroups.OrderBy(g => g.Title).ToList(); } } } diff --git a/ModernKeePass/ResourceDictionaries/TextBoxWithButtonStyle.xaml b/ModernKeePass/ResourceDictionaries/TextBoxWithButtonStyle.xaml index 5f56d69..c494d7c 100644 --- a/ModernKeePass/ResourceDictionaries/TextBoxWithButtonStyle.xaml +++ b/ModernKeePass/ResourceDictionaries/TextBoxWithButtonStyle.xaml @@ -13,6 +13,9 @@ + + + diff --git a/ModernKeePass/ViewModels/EntryDetailVm.cs b/ModernKeePass/ViewModels/EntryDetailVm.cs index f3464a9..f773fdf 100644 --- a/ModernKeePass/ViewModels/EntryDetailVm.cs +++ b/ModernKeePass/ViewModels/EntryDetailVm.cs @@ -27,7 +27,9 @@ using ModernKeePass.Application.Security.Commands.GeneratePassword; using ModernKeePass.Application.Security.Queries.EstimatePasswordComplexity; using ModernKeePass.Domain.Enums; using ModernKeePass.Application.Group.Models; +using ModernKeePass.Common; using ModernKeePass.Extensions; +using ModernKeePass.Models; namespace ModernKeePass.ViewModels { @@ -45,8 +47,11 @@ namespace ModernKeePass.ViewModels public bool SpecialPatternSelected { get; set; } public bool BracketsPatternSelected { get; set; } public string CustomChars { get; set; } = string.Empty; + public string Id => SelectedItem.Id; + public string ParentGroupName => _parent.Title; + public bool IsRecycleOnDelete { get @@ -221,6 +226,7 @@ namespace ModernKeePass.ViewModels public RelayCommand RestoreCommand { get; } public RelayCommand DeleteCommand { get; } public RelayCommand GoBackCommand { get; } + public RelayCommand GoToParentCommand { get; set; } private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult(); @@ -251,6 +257,7 @@ namespace ModernKeePass.ViewModels RestoreCommand = new RelayCommand(async () => await RestoreHistory()); DeleteCommand = new RelayCommand(async () => await AskForDelete()); GoBackCommand = new RelayCommand(() => _navigation.GoBack()); + GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id)); } public async Task Initialize(string entryId) @@ -323,6 +330,7 @@ namespace ModernKeePass.ViewModels { await _mediator.Send(new AddEntryCommand { ParentGroupId = destination, EntryId = Id }); await _mediator.Send(new RemoveEntryCommand { ParentGroupId = _parent.Id, EntryId = Id }); + GoToGroup(destination); } public async Task SetFieldValue(string fieldName, object value) @@ -363,5 +371,10 @@ namespace ModernKeePass.ViewModels }); _navigation.GoBack(); } + + public void GoToGroup(string groupId) + { + _navigation.NavigateTo(Constants.Navigation.GroupPage, new NavigationItem { Id = groupId }); + } } } diff --git a/ModernKeePass/ViewModels/GroupDetailVm.cs b/ModernKeePass/ViewModels/GroupDetailVm.cs index cfcef80..230b2db 100644 --- a/ModernKeePass/ViewModels/GroupDetailVm.cs +++ b/ModernKeePass/ViewModels/GroupDetailVm.cs @@ -79,12 +79,12 @@ namespace ModernKeePass.ViewModels } } + public string ParentGroupName => _parent?.Title; + public bool IsRecycleOnDelete => Database.IsRecycleBinEnabled && !IsInRecycleBin; public bool IsInRecycleBin => _parent != null && _parent.Id == Database.RecycleBinId; - - public IEnumerable BreadCrumb { get; private set; } - + public RelayCommand SaveCommand { get; } public RelayCommand SortEntriesCommand { get; } public RelayCommand SortGroupsCommand { get; } @@ -93,9 +93,10 @@ namespace ModernKeePass.ViewModels public RelayCommand CreateGroupCommand { get; } public RelayCommand DeleteCommand { get; set; } public RelayCommand GoBackCommand { get; set; } + public RelayCommand GoToParentCommand { get; set; } private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult(); - + private readonly IMediator _mediator; private readonly IResourceProxy _resource; private readonly INavigationService _navigation; @@ -122,6 +123,7 @@ namespace ModernKeePass.ViewModels CreateGroupCommand = new RelayCommand(async () => await AddNewGroup(), () => !IsInRecycleBin && Database.RecycleBinId != Id); DeleteCommand = new RelayCommand(async () => await AskForDelete(),() => IsNotRoot); GoBackCommand = new RelayCommand(() => _navigation.GoBack()); + GoToParentCommand= new RelayCommand(() => GoToGroup(_parent.Id), () => _parent != null); } public async Task Initialize(string groupId) @@ -130,7 +132,6 @@ namespace ModernKeePass.ViewModels if (!string.IsNullOrEmpty(_group.ParentGroupId)) { _parent = await _mediator.Send(new GetGroupQuery { Id = _group.ParentGroupId }); - BreadCrumb = new List { _parent }; } Entries = new ObservableCollection(_group.Entries); @@ -146,11 +147,11 @@ namespace ModernKeePass.ViewModels IsNew = isNew }); } - public void GoToGroup(string entryId, bool isNew = false) + public void GoToGroup(string groupId, bool isNew = false) { _navigation.NavigateTo(Constants.Navigation.GroupPage, new NavigationItem { - Id = entryId, + Id = groupId, IsNew = isNew }); } @@ -171,6 +172,7 @@ namespace ModernKeePass.ViewModels { await _mediator.Send(new AddGroupCommand {ParentGroupId = destinationId, GroupId = Id }); await _mediator.Send(new RemoveGroupCommand {ParentGroupId = _parent.Id, GroupId = Id }); + GoToGroup(destinationId); } public async Task> Search(string queryText) @@ -210,6 +212,8 @@ namespace ModernKeePass.ViewModels private async Task SortEntriesAsync() { await _mediator.Send(new SortEntriesCommand {Group = _group}); + Entries = new ObservableCollection(_group.Entries); + Entries.CollectionChanged += Entries_CollectionChanged; RaisePropertyChanged(nameof(Entries)); SaveCommand.RaiseCanExecuteChanged(); } @@ -217,6 +221,7 @@ namespace ModernKeePass.ViewModels private async Task SortGroupsAsync() { await _mediator.Send(new SortGroupsCommand {Group = _group}); + Groups = new ObservableCollection(_group.SubGroups); RaisePropertyChanged(nameof(Groups)); SaveCommand.RaiseCanExecuteChanged(); } diff --git a/ModernKeePass/Views/EntryDetailPage.xaml b/ModernKeePass/Views/EntryDetailPage.xaml index 6f70e6e..567b914 100644 --- a/ModernKeePass/Views/EntryDetailPage.xaml +++ b/ModernKeePass/Views/EntryDetailPage.xaml @@ -402,14 +402,9 @@ - - + @@ -419,7 +414,7 @@ - + @@ -430,7 +425,7 @@ - + @@ -524,7 +519,12 @@ - + - + - + diff --git a/ModernKeePass/Views/UserControls/BreadCrumbUserControl.xaml b/ModernKeePass/Views/UserControls/BreadCrumbUserControl.xaml index 1872a38..d1a9dcc 100644 --- a/ModernKeePass/Views/UserControls/BreadCrumbUserControl.xaml +++ b/ModernKeePass/Views/UserControls/BreadCrumbUserControl.xaml @@ -16,7 +16,11 @@ - + diff --git a/ModernKeePass/Views/UserControls/TopMenuUserControl.xaml b/ModernKeePass/Views/UserControls/TopMenuUserControl.xaml index 991d762..22c730a 100644 --- a/ModernKeePass/Views/UserControls/TopMenuUserControl.xaml +++ b/ModernKeePass/Views/UserControls/TopMenuUserControl.xaml @@ -56,10 +56,9 @@ - + - - diff --git a/ModernKeePass/Views/UserControls/TopMenuUserControl.xaml.cs b/ModernKeePass/Views/UserControls/TopMenuUserControl.xaml.cs index b64d949..30a2c55 100644 --- a/ModernKeePass/Views/UserControls/TopMenuUserControl.xaml.cs +++ b/ModernKeePass/Views/UserControls/TopMenuUserControl.xaml.cs @@ -134,18 +134,6 @@ namespace ModernKeePass.Views.UserControls typeof(Visibility), typeof(TopMenuUserControl), new PropertyMetadata(Visibility.Collapsed, (o, args) => { })); - - public bool IsDeleteButtonEnabled - { - get { return (bool)GetValue(IsDeleteButtonEnabledProperty); } - set { SetValue(IsDeleteButtonEnabledProperty, value); } - } - public static readonly DependencyProperty IsDeleteButtonEnabledProperty = - DependencyProperty.Register( - nameof(IsDeleteButtonEnabled), - typeof(bool), - typeof(TopMenuUserControl), - new PropertyMetadata(true, (o, args) => { })); public bool IsEditButtonChecked { @@ -160,7 +148,6 @@ namespace ModernKeePass.Views.UserControls new PropertyMetadata(false, (o, args) => { })); public event EventHandler EditButtonClick; - public event EventHandler DeleteButtonClick; public TopMenuUserControl() { @@ -179,27 +166,28 @@ namespace ModernKeePass.Views.UserControls EditButtonClick?.Invoke(sender, e); } - private void DeleteButton_Click(object sender, RoutedEventArgs e) - { - DeleteButtonClick?.Invoke(sender, e); - } - private void OverflowFlyout_OnOpening(object sender, object e) { - DeleteFlyout.IsEnabled = IsDeleteButtonEnabled; - DeleteFlyout.IsEnabled = IsDeleteButtonEnabled; - EditFlyout.IsChecked = IsEditButtonChecked; MoveFlyout.Visibility = MoveButtonVisibility; RestoreFlyout.Visibility = RestoreButtonVisibility; - SortEntriesFlyout.Visibility = SortButtonVisibility; SortGroupsFlyout.Visibility = SortButtonVisibility; + + SaveFlyout.Command = SaveCommand; + DeleteFlyout.Command = DeleteCommand; + RestoreFlyout.Command = RestoreCommand; SortEntriesFlyout.Command = SortEntriesCommand; SortGroupsFlyout.Command = SortGroupsCommand; } + // These are somehow necessary as otherwise, the command is not bound + private void MoveButtonFlyout_OnOpening(object sender, object e) + { + MoveButton.Command = MoveCommand; + } + private void SortFlyout_OnOpening(object sender, object e) { SortEntriesButtonFlyout.Command = SortEntriesCommand; @@ -209,15 +197,21 @@ namespace ModernKeePass.Views.UserControls private void SearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args) { var imageUri = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appdata://Assets/ModernKeePass-SmallLogo.scale-80.png")); - foreach (var group in Model.Groups.Where(g => g.Title.IndexOf(args.QueryText, StringComparison.OrdinalIgnoreCase) >= 0)) + var groups = Model.Groups.Where(g => g.Title.IndexOf(args.QueryText, StringComparison.OrdinalIgnoreCase) >= 0).Take(5); + foreach (var group in groups) { - args.Request.SearchSuggestionCollection.AppendResultSuggestion(group.Title, group.ParentGroupName, group.Id, imageUri, string.Empty); + args.Request.SearchSuggestionCollection.AppendResultSuggestion( + group.Title, + group.ParentGroupName, + group.Id, + imageUri, + string.Empty); } } private void SearchBox_OnResultSuggestionChosen(SearchBox sender, SearchBoxResultSuggestionChosenEventArgs args) { - Model.SelectedDestinationGroup = args.Tag; + MoveButton.CommandParameter = args.Tag; MoveCommand.RaiseCanExecuteChanged(); } } diff --git a/WinAppCommon/ViewModels/UserControls/BreadcrumbVm.cs b/WinAppCommon/ViewModels/UserControls/BreadcrumbVm.cs new file mode 100644 index 0000000..dc53cf2 --- /dev/null +++ b/WinAppCommon/ViewModels/UserControls/BreadcrumbVm.cs @@ -0,0 +1,19 @@ +using GalaSoft.MvvmLight.Command; +using GalaSoft.MvvmLight.Views; +using ModernKeePass.Common; +using ModernKeePass.Models; + +namespace ModernKeePass.ViewModels +{ + public class BreadcrumbVm + { + public RelayCommand NavigateCommand { get; } + + public BreadcrumbVm(INavigationService navigation) + { + NavigateCommand = new RelayCommand(groupId => + navigation.NavigateTo(Constants.Navigation.GroupPage, new NavigationItem {Id = groupId}), + groupId => !string.IsNullOrEmpty(groupId)); + } + } +} \ No newline at end of file diff --git a/WinAppCommon/ViewModels/UserControls/TopMenuVm.cs b/WinAppCommon/ViewModels/UserControls/TopMenuVm.cs index fb0a93e..2e1704f 100644 --- a/WinAppCommon/ViewModels/UserControls/TopMenuVm.cs +++ b/WinAppCommon/ViewModels/UserControls/TopMenuVm.cs @@ -9,7 +9,6 @@ namespace ModernKeePass.ViewModels public class TopMenuVm { public IEnumerable Groups { get; set; } - public string SelectedDestinationGroup { get; set; } public TopMenuVm(IMediator mediator) {