diff --git a/ModernKeePass.Application/Application.csproj b/ModernKeePass.Application/Application.csproj index 4d1fc74..421adb2 100644 --- a/ModernKeePass.Application/Application.csproj +++ b/ModernKeePass.Application/Application.csproj @@ -86,7 +86,6 @@ - @@ -101,7 +100,6 @@ - diff --git a/ModernKeePass.Application/Common/Interfaces/IBreadcrumbService.cs b/ModernKeePass.Application/Common/Interfaces/IBreadcrumbService.cs deleted file mode 100644 index cff8b2d..0000000 --- a/ModernKeePass.Application/Common/Interfaces/IBreadcrumbService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using ModernKeePass.Application.Common.Models; - -namespace ModernKeePass.Application.Common.Interfaces -{ - public interface IBreadcrumbService - { - void Push(BreadcrumbItem item); - BreadcrumbItem Pop(int count = 1); - IEnumerable GetItems(); - } -} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Services/BreadcrumbService.cs b/ModernKeePass.Application/Common/Services/BreadcrumbService.cs deleted file mode 100644 index 5965cda..0000000 --- a/ModernKeePass.Application/Common/Services/BreadcrumbService.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using ModernKeePass.Application.Common.Interfaces; -using ModernKeePass.Application.Common.Models; - -namespace ModernKeePass.Application.Common.Services -{ - public class BreadcrumbService: IBreadcrumbService - { - private readonly Stack _breadcrumb; - - public BreadcrumbService() - { - _breadcrumb = new Stack(); - } - - public void Push(BreadcrumbItem item) - { - _breadcrumb.Push(item); - } - - public BreadcrumbItem Pop(int count = 1) - { - if (_breadcrumb.Count == 0) return null; - for (var i = 1; i < count; i++) - { - _breadcrumb.Pop(); - } - - return _breadcrumb.Pop(); - } - - public IEnumerable GetItems() - { - return _breadcrumb; - } - } -} \ No newline at end of file diff --git a/ModernKeePass.Application/DependencyInjection.cs b/ModernKeePass.Application/DependencyInjection.cs index 89d4557..0837d78 100644 --- a/ModernKeePass.Application/DependencyInjection.cs +++ b/ModernKeePass.Application/DependencyInjection.cs @@ -2,8 +2,6 @@ using MediatR; using Microsoft.Extensions.DependencyInjection; using ModernKeePass.Application.Common.Behaviors; -using ModernKeePass.Application.Common.Interfaces; -using ModernKeePass.Application.Common.Services; namespace ModernKeePass.Application { @@ -14,8 +12,7 @@ namespace ModernKeePass.Application var assembly = typeof(DependencyInjection).GetTypeInfo().Assembly; services.AddMediatR(assembly); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(DirtyStatusBehavior<,>)); - - services.AddSingleton(typeof(IBreadcrumbService), typeof(BreadcrumbService)); + return services; } } diff --git a/ModernKeePass/ViewModels/EntryDetailVm.cs b/ModernKeePass/ViewModels/EntryDetailVm.cs index 60f4326..7d273fe 100644 --- a/ModernKeePass/ViewModels/EntryDetailVm.cs +++ b/ModernKeePass/ViewModels/EntryDetailVm.cs @@ -43,13 +43,15 @@ namespace ModernKeePass.ViewModels public bool HasExpired => HasExpirationDate && ExpiryDate < _dateTime.Now; public string Id => _current.Id; - + + public GroupVm Parent { get; private set; } + public bool IsRecycleOnDelete { get { var database = Database; - return database.IsRecycleBinEnabled && _parent.Id != database.RecycleBinId; + return database.IsRecycleBinEnabled && Parent.Id != database.RecycleBinId; } } @@ -224,7 +226,6 @@ namespace ModernKeePass.ViewModels private readonly IFileProxy _file; private readonly ICryptographyClient _cryptography; private readonly IDateTime _dateTime; - private GroupVm _parent; private EntryVm _current; private int _selectedIndex; private int _additionalFieldSelectedIndex = -1; @@ -242,7 +243,7 @@ namespace ModernKeePass.ViewModels _dateTime = dateTime; SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty); - MoveCommand = new RelayCommand(async destination => await Move(destination), destination => _parent != null && !string.IsNullOrEmpty(destination) && destination != _parent.Id); + MoveCommand = new RelayCommand(async destination => await Move(destination), destination => Parent != null && !string.IsNullOrEmpty(destination) && destination != Parent.Id); RestoreCommand = new RelayCommand(async () => await RestoreHistory()); DeleteCommand = new RelayCommand(async () => await AskForDelete()); AddAdditionalField = new RelayCommand(AddField, () => IsCurrentEntry); @@ -263,7 +264,7 @@ namespace ModernKeePass.ViewModels SelectedIndex = 0; _current = await _mediator.Send(new GetEntryQuery { Id = entryId }); SetCurrentEntry(_current); - _parent = await _mediator.Send(new GetGroupQuery { Id = _current.ParentGroupId }); + Parent = await _mediator.Send(new GetGroupQuery { Id = _current.ParentGroupId }); History = new ObservableCollection { _current }; foreach (var entry in _current.History.Skip(1)) { @@ -289,7 +290,7 @@ namespace ModernKeePass.ViewModels private async Task Move(string destination) { await _mediator.Send(new AddEntryCommand { ParentGroupId = destination, EntryId = Id }); - await _mediator.Send(new RemoveEntryCommand { ParentGroupId = _parent.Id, EntryId = Id }); + await _mediator.Send(new RemoveEntryCommand { ParentGroupId = Parent.Id, EntryId = Id }); GoToGroup(destination); } diff --git a/ModernKeePass/ViewModels/GroupDetailVm.cs b/ModernKeePass/ViewModels/GroupDetailVm.cs index 205cb90..c077134 100644 --- a/ModernKeePass/ViewModels/GroupDetailVm.cs +++ b/ModernKeePass/ViewModels/GroupDetailVm.cs @@ -10,7 +10,6 @@ using GalaSoft.MvvmLight.Views; using MediatR; using Messages; using ModernKeePass.Application.Common.Interfaces; -using ModernKeePass.Application.Common.Models; using ModernKeePass.Application.Database.Commands.SaveDatabase; using ModernKeePass.Application.Database.Models; using ModernKeePass.Application.Database.Queries.GetDatabase; @@ -44,6 +43,8 @@ namespace ModernKeePass.ViewModels public bool IsNotRoot => Database.RootGroupId != _group.Id; + public GroupVm Parent { get; private set; } + public IOrderedEnumerable> EntriesZoomedOut => from e in Entries group e by (e.Title.Value ?? string.Empty).ToUpper().FirstOrDefault() into grp orderby grp.Key @@ -82,11 +83,11 @@ namespace ModernKeePass.ViewModels } } - public string ParentGroupName => _parent == null ? Database.Name : _parent.Title; + public string ParentGroupName => Parent == null ? Database.Name : Parent.Title; public bool IsRecycleOnDelete => Database.IsRecycleBinEnabled && !IsInRecycleBin; - public bool IsInRecycleBin => _parent != null && _parent.Id == Database.RecycleBinId; + public bool IsInRecycleBin => Parent != null && Parent.Id == Database.RecycleBinId; public RelayCommand SaveCommand { get; } public RelayCommand SortEntriesCommand { get; } @@ -108,21 +109,18 @@ namespace ModernKeePass.ViewModels private readonly INavigationService _navigation; private readonly IDialogService _dialog; private readonly INotificationService _notification; - private readonly IBreadcrumbService _breadcrumb; private GroupVm _group; - private GroupVm _parent; private bool _isEditMode; private EntryVm _reorderedEntry; private GroupVm _reorderedGroup; - public GroupDetailVm(IMediator mediator, IResourceProxy resource, INavigationService navigation, IDialogService dialog, INotificationService notification, IBreadcrumbService breadcrumb) + public GroupDetailVm(IMediator mediator, IResourceProxy resource, INavigationService navigation, IDialogService dialog, INotificationService notification) { _mediator = mediator; _resource = resource; _navigation = navigation; _dialog = dialog; _notification = notification; - _breadcrumb = breadcrumb; SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty); SortEntriesCommand = new RelayCommand(async () => await SortEntriesAsync(), () => IsEditMode); @@ -132,7 +130,7 @@ namespace ModernKeePass.ViewModels CreateGroupCommand = new RelayCommand(async newGroupName => await AddNewGroup(newGroupName), _ => !IsInRecycleBin && Database.RecycleBinId != Id); DeleteCommand = new RelayCommand(async () => await AskForDelete(),() => IsNotRoot); GoBackCommand = new RelayCommand(() => _navigation.GoBack()); - GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id), () => _parent != null); + GoToParentCommand = new RelayCommand(() => GoToGroup(Parent.Id), () => Parent != null); GoToGroupCommand = new RelayCommand(group => GoToGroup(group.Id), group => group != null); GoToEntryCommand = new RelayCommand(entry => GoToEntry(entry.Id), entry => entry != null); DeleteEntryCommand = new RelayCommand(async entry => await AskForDeleteEntry(entry), entry => entry != null); @@ -140,43 +138,14 @@ namespace ModernKeePass.ViewModels MessengerInstance.Register(this, _ => SaveCommand.RaiseCanExecuteChanged()); } - private async Task AskForDeleteEntry(EntryVm entry) - { - if (IsRecycleOnDelete) - { - await DeleteEntry(entry.Id); - _notification.Show(_resource.GetResourceValue("EntityDeleting"), string.Format(_resource.GetResourceValue("EntryRecycled"), entry.Title)); - } - else - { - await _dialog.ShowMessage( - string.Format(_resource.GetResourceValue("EntryDeletingConfirmation"), entry.Title), - _resource.GetResourceValue("EntityDeleting"), - _resource.GetResourceValue("EntityDeleteActionButton"), - _resource.GetResourceValue("EntityDeleteCancelButton"), - async isOk => - { - if (isOk) await DeleteEntry(entry.Id); - }); - } - } - private async Task DeleteEntry(string entryId) - { - await _mediator.Send(new DeleteEntryCommand - { - EntryId = entryId, - ParentGroupId = Id, - RecycleBinName = _resource.GetResourceValue("RecycleBinTitle") - }); - } - public async Task Initialize(string groupId) { _group = await _mediator.Send(new GetGroupQuery { Id = groupId }); if (!string.IsNullOrEmpty(_group.ParentGroupId)) { - _parent = await _mediator.Send(new GetGroupQuery { Id = _group.ParentGroupId }); + Parent = await _mediator.Send(new GetGroupQuery {Id = _group.ParentGroupId}); } + else Parent = null; Entries = new ObservableCollection(_group.Entries); Entries.CollectionChanged += Entries_CollectionChanged; @@ -186,7 +155,6 @@ namespace ModernKeePass.ViewModels public void GoToEntry(string entryId, bool isNew = false) { - _breadcrumb.Push(new BreadcrumbItem { Name = Title, Path = Id, Icon = _group.Icon }); _navigation.NavigateTo(Constants.Navigation.EntryPage, new NavigationItem { Id = entryId, @@ -195,7 +163,6 @@ namespace ModernKeePass.ViewModels } public void GoToGroup(string groupId, bool isNew = false) { - _breadcrumb.Push(new BreadcrumbItem { Name = Title, Path = Id, Icon = _group.Icon }); _navigation.NavigateTo(Constants.Navigation.GroupPage, new NavigationItem { Id = groupId, @@ -218,7 +185,7 @@ namespace ModernKeePass.ViewModels public async Task Move(string destinationId) { await _mediator.Send(new AddGroupCommand {ParentGroupId = destinationId, GroupId = Id }); - await _mediator.Send(new RemoveGroupCommand {ParentGroupId = _parent.Id, GroupId = Id }); + await _mediator.Send(new RemoveGroupCommand {ParentGroupId = Parent.Id, GroupId = Id }); GoToGroup(destinationId); } @@ -327,9 +294,39 @@ namespace ModernKeePass.ViewModels ParentGroupId = _group.ParentGroupId, RecycleBinName = _resource.GetResourceValue("RecycleBinTitle") }); - - _breadcrumb.Pop(); + _navigation.GoBack(); } + + private async Task AskForDeleteEntry(EntryVm entry) + { + if (IsRecycleOnDelete) + { + await DeleteEntry(entry); + _notification.Show(_resource.GetResourceValue("EntityDeleting"), string.Format(_resource.GetResourceValue("EntryRecycled"), entry.Title)); + } + else + { + await _dialog.ShowMessage( + string.Format(_resource.GetResourceValue("EntryDeletingConfirmation"), entry.Title), + _resource.GetResourceValue("EntityDeleting"), + _resource.GetResourceValue("EntityDeleteActionButton"), + _resource.GetResourceValue("EntityDeleteCancelButton"), + async isOk => + { + if (isOk) await DeleteEntry(entry); + }); + } + } + private async Task DeleteEntry(EntryVm entry) + { + await _mediator.Send(new DeleteEntryCommand + { + EntryId = entry.Id, + ParentGroupId = Id, + RecycleBinName = _resource.GetResourceValue("RecycleBinTitle") + }); + Entries.Remove(entry); + } } } diff --git a/ModernKeePass/Views/EntryDetailPage.xaml b/ModernKeePass/Views/EntryDetailPage.xaml index 7b5e5d0..40552dc 100644 --- a/ModernKeePass/Views/EntryDetailPage.xaml +++ b/ModernKeePass/Views/EntryDetailPage.xaml @@ -232,7 +232,7 @@ - + - + @@ -189,41 +189,12 @@ - - - - - - + - - - @@ -266,9 +234,6 @@ - - - @@ -282,9 +247,6 @@ - - - diff --git a/ModernKeePass/Views/GroupDetailPage.xaml.cs b/ModernKeePass/Views/GroupDetailPage.xaml.cs index 44ba8d3..22aeba9 100644 --- a/ModernKeePass/Views/GroupDetailPage.xaml.cs +++ b/ModernKeePass/Views/GroupDetailPage.xaml.cs @@ -53,18 +53,21 @@ namespace ModernKeePass.Views VisualStateManager.GoToState(this, "Small", true); VisualStateManager.GoToState(TopMenu, "Collapsed", true); VisualStateManager.GoToState(HamburgerMenu, "Hidden", true); + VisualStateManager.GoToState(Breadcrumb, "Small", true); } else if (e.NewSize.Width > 640 && e.NewSize.Width <= 1008) { VisualStateManager.GoToState(this, "Medium", true); VisualStateManager.GoToState(TopMenu, "Overflowed", true); VisualStateManager.GoToState(HamburgerMenu, "Collapsed", true); + VisualStateManager.GoToState(Breadcrumb, "Medium", true); } else { VisualStateManager.GoToState(this, "Large", true); VisualStateManager.GoToState(TopMenu, "Overflowed", true); VisualStateManager.GoToState(HamburgerMenu, "Expanded", true); + VisualStateManager.GoToState(Breadcrumb, "Large", true); } } diff --git a/ModernKeePass/Views/UserControls/BreadcrumbUserControl.xaml b/ModernKeePass/Views/UserControls/BreadcrumbUserControl.xaml index daeb43d..64c9002 100644 --- a/ModernKeePass/Views/UserControls/BreadcrumbUserControl.xaml +++ b/ModernKeePass/Views/UserControls/BreadcrumbUserControl.xaml @@ -9,18 +9,19 @@ xmlns:interactivity="using:Microsoft.Xaml.Interactivity" xmlns:core="using:Microsoft.Xaml.Interactions.Core" mc:Ignorable="d"> - + + - - + + @@ -37,17 +38,18 @@ - + @@ -59,6 +61,7 @@ @@ -71,6 +74,9 @@ + + + @@ -81,6 +87,9 @@ + + + @@ -91,6 +100,9 @@ + + + diff --git a/ModernKeePass/Views/UserControls/BreadcrumbUserControl.xaml.cs b/ModernKeePass/Views/UserControls/BreadcrumbUserControl.xaml.cs index f2b829e..415346f 100644 --- a/ModernKeePass/Views/UserControls/BreadcrumbUserControl.xaml.cs +++ b/ModernKeePass/Views/UserControls/BreadcrumbUserControl.xaml.cs @@ -1,9 +1,30 @@ -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 +using Windows.UI.Xaml; +using ModernKeePass.Application.Group.Models; +using ModernKeePass.ViewModels; + +// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace ModernKeePass.Views.UserControls { public sealed partial class BreadcrumbUserControl { + public GroupVm Group + { + get { return (GroupVm)GetValue(GroupProperty); } + set { SetValue(GroupProperty, value); } + } + public static readonly DependencyProperty GroupProperty = + DependencyProperty.Register( + nameof(Group), + typeof(GroupVm), + typeof(BreadcrumbUserControl), + new PropertyMetadata(null, async (o, args) => + { + var userControl = o as BreadcrumbUserControl; + var vm = userControl?.StackPanel.DataContext as BreadcrumbControlVm; + if (vm != null) await vm.Initialize(args.NewValue as GroupVm).ConfigureAwait(false); + })); + public BreadcrumbUserControl() { InitializeComponent(); diff --git a/WinAppCommon/Strings/en-US/Resources.resw b/WinAppCommon/Strings/en-US/Resources.resw index de58bf3..947b87b 100644 --- a/WinAppCommon/Strings/en-US/Resources.resw +++ b/WinAppCommon/Strings/en-US/Resources.resw @@ -573,4 +573,7 @@ Title copied to clipboard + + Delete + \ No newline at end of file diff --git a/WinAppCommon/Strings/fr-FR/Resources.resw b/WinAppCommon/Strings/fr-FR/Resources.resw index d3b726d..fed4981 100644 --- a/WinAppCommon/Strings/fr-FR/Resources.resw +++ b/WinAppCommon/Strings/fr-FR/Resources.resw @@ -573,4 +573,7 @@ Titre copié dans le presse-papiers + + Supprimer + \ No newline at end of file diff --git a/WinAppCommon/ViewModels/UserControls/BreadcrumbControlVm.cs b/WinAppCommon/ViewModels/UserControls/BreadcrumbControlVm.cs index 02b606d..6062a4b 100644 --- a/WinAppCommon/ViewModels/UserControls/BreadcrumbControlVm.cs +++ b/WinAppCommon/ViewModels/UserControls/BreadcrumbControlVm.cs @@ -1,45 +1,62 @@ -using System.Collections.Generic; -using System.Linq; +using System.Collections.ObjectModel; +using System.Threading.Tasks; using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.Views; -using ModernKeePass.Application.Common.Interfaces; +using MediatR; using ModernKeePass.Application.Common.Models; +using ModernKeePass.Application.Group.Models; +using ModernKeePass.Application.Group.Queries.GetGroup; using ModernKeePass.Common; +using ModernKeePass.Domain.Enums; using ModernKeePass.Models; namespace ModernKeePass.ViewModels { public class BreadcrumbControlVm { - public IEnumerable BreadcrumbItems { get; } - public string ParentGroupName => BreadcrumbItems.Last()?.Name; + public ObservableCollection BreadcrumbItems { get; } + public string ParentGroupName { get; private set; } + public Icon ParentGroupIcon { get; private set; } public RelayCommand GoBackCommand { get; } + public RelayCommand GoUpCommand { get; private set; } public RelayCommand GoToCommand { get; } + private readonly IMediator _mediator; private readonly INavigationService _navigation; - private readonly IBreadcrumbService _breadcrumb; - public BreadcrumbControlVm(INavigationService navigation, IBreadcrumbService breadcrumb) + public BreadcrumbControlVm(IMediator mediator, INavigationService navigation) { + _mediator = mediator; _navigation = navigation; - _breadcrumb = breadcrumb; - - BreadcrumbItems = _breadcrumb.GetItems().Reverse(); - GoBackCommand = new RelayCommand(GoBack); + + BreadcrumbItems = new ObservableCollection(); + GoBackCommand = new RelayCommand(() => _navigation.GoBack()); GoToCommand = new RelayCommand(GoTo); } + public async Task Initialize(GroupVm group) + { + GoUpCommand = new RelayCommand(() => GoTo(BreadcrumbItems.Count - 1), () => group != null); + + if (group == null) return; + ParentGroupName = group.Title; + ParentGroupIcon = group.Icon; + + BreadcrumbItems.Insert(0, new BreadcrumbItem { Path = group.Id, Name = group.Title, Icon = group.Icon }); + var parentGroup = group; + while (!string.IsNullOrEmpty(parentGroup.ParentGroupId)) + { + parentGroup = await _mediator.Send(new GetGroupQuery {Id = parentGroup.ParentGroupId}); + BreadcrumbItems.Insert(0, new BreadcrumbItem {Path = parentGroup.Id, Name = parentGroup.Title, Icon = parentGroup.Icon}); + } + } + private void GoTo(int index) { - var breadcrumb = _breadcrumb.Pop(BreadcrumbItems.Count() - index); + if (BreadcrumbItems.Count == 0) return; + var breadcrumb = BreadcrumbItems[index]; _navigation.NavigateTo(Constants.Navigation.GroupPage, new NavigationItem { Id = breadcrumb.Path }); } - - private void GoBack() - { - _breadcrumb.Pop(); - _navigation.GoBack(); - } } } \ No newline at end of file diff --git a/WinAppCommon/ViewModels/ViewModelLocatorCommon.cs b/WinAppCommon/ViewModels/ViewModelLocatorCommon.cs index 7719b2f..25a6d06 100644 --- a/WinAppCommon/ViewModels/ViewModelLocatorCommon.cs +++ b/WinAppCommon/ViewModels/ViewModelLocatorCommon.cs @@ -57,7 +57,6 @@ namespace ModernKeePass.ViewModels SimpleIoc.Default.Register(() => App.Services.GetRequiredService()); SimpleIoc.Default.Register(() => App.Services.GetRequiredService()); SimpleIoc.Default.Register(() => App.Services.GetRequiredService()); - SimpleIoc.Default.Register(() => App.Services.GetRequiredService()); } SimpleIoc.Default.Register();