Files
modernkeepass/ModernKeePass/ViewModels/EntryDetailVm.cs

374 lines
14 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
2020-04-15 19:06:13 +02:00
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
2020-04-14 17:49:29 +02:00
using Windows.UI.Xaml.Media;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Views;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Database.Commands.SaveDatabase;
using ModernKeePass.Application.Database.Models;
using ModernKeePass.Application.Database.Queries.GetDatabase;
using ModernKeePass.Application.Entry.Commands.AddHistory;
2020-04-16 14:08:50 +02:00
using ModernKeePass.Application.Entry.Commands.DeleteHistory;
2020-04-15 19:06:13 +02:00
using ModernKeePass.Application.Entry.Commands.RestoreHistory;
using ModernKeePass.Application.Entry.Commands.SetFieldValue;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Application.Entry.Queries.GetEntry;
using ModernKeePass.Application.Group.Commands.AddEntry;
using ModernKeePass.Application.Group.Commands.DeleteEntry;
using ModernKeePass.Application.Group.Commands.RemoveEntry;
using ModernKeePass.Application.Group.Queries.GetGroup;
using ModernKeePass.Application.Security.Commands.GeneratePassword;
using ModernKeePass.Application.Security.Queries.EstimatePasswordComplexity;
using ModernKeePass.Domain.Enums;
using ModernKeePass.Application.Group.Models;
2020-04-14 17:49:29 +02:00
using ModernKeePass.Extensions;
namespace ModernKeePass.ViewModels
{
public class EntryDetailVm : ObservableObject
{
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
public bool HasExpired => HasExpirationDate && ExpiryDate < DateTime.Now;
public double PasswordComplexityIndicator => _mediator.Send(new EstimatePasswordComplexityQuery {Password = Password}).GetAwaiter().GetResult();
public bool UpperCasePatternSelected { get; set; } = true;
public bool LowerCasePatternSelected { get; set; } = true;
public bool DigitsPatternSelected { get; set; } = true;
public bool MinusPatternSelected { get; set; }
public bool UnderscorePatternSelected { get; set; }
public bool SpacePatternSelected { get; set; }
public bool SpecialPatternSelected { get; set; }
public bool BracketsPatternSelected { get; set; }
public string CustomChars { get; set; } = string.Empty;
2020-04-16 14:08:50 +02:00
public string Id => SelectedItem.Id;
public bool IsRecycleOnDelete
{
get
{
var database = Database;
return database.IsRecycleBinEnabled && _parent.Id != database.RecycleBinId;
}
}
public IEnumerable<GroupVm> BreadCrumb => new List<GroupVm> { _parent };
2020-04-16 14:08:50 +02:00
public ObservableCollection<EntryVm> History { get; }
/// <summary>
/// Determines if the Entry is current or from history
/// </summary>
2020-04-16 14:08:50 +02:00
public bool IsCurrentEntry => SelectedIndex == 0;
public EntryVm SelectedItem
{
2020-04-16 14:08:50 +02:00
get { return _selectedItem; }
set
{
Set(() => SelectedItem, ref _selectedItem, value);
if (value != null) RaisePropertyChanged();
2020-04-16 14:08:50 +02:00
}
}
public int SelectedIndex
{
get { return _selectedIndex; }
set
{
Set(() => SelectedIndex, ref _selectedIndex, value);
RaisePropertyChanged(nameof(IsCurrentEntry));
2020-04-16 14:08:50 +02:00
}
}
public double PasswordLength
{
get { return _passwordLength; }
set { Set(() => PasswordLength, ref _passwordLength, value); }
}
public string Title
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem.Title; }
set
{
2020-04-16 14:08:50 +02:00
SelectedItem.Title = value;
2020-04-14 17:49:29 +02:00
SetFieldValue(nameof(Title), value).Wait();
}
}
public string UserName
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem.Username; }
set { SelectedItem.Username = value; }
}
public string Password
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem.Password; }
set
{
2020-04-16 14:08:50 +02:00
SelectedItem.Password = value;
2020-04-14 17:49:29 +02:00
SetFieldValue(nameof(Password), value).Wait();
RaisePropertyChanged(nameof(Password));
RaisePropertyChanged(nameof(PasswordComplexityIndicator));
}
}
public string Url
{
get { return SelectedItem.Url; }
set
{
SelectedItem.Url = value;
2020-04-14 17:49:29 +02:00
SetFieldValue(nameof(Url), value).Wait();
}
}
public string Notes
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem.Notes; }
set
{
2020-04-16 14:08:50 +02:00
SelectedItem.Notes = value;
2020-04-14 17:49:29 +02:00
SetFieldValue(nameof(Notes), value).Wait();
}
}
public Symbol Icon
{
2020-04-16 14:08:50 +02:00
get { return (Symbol)Enum.Parse(typeof(Symbol), SelectedItem.Icon.ToString()); }
set
{
2020-04-16 14:08:50 +02:00
SelectedItem.Icon = (Icon)Enum.Parse(typeof(Icon), value.ToString());
SetFieldValue(nameof(Icon), SelectedItem.Icon).Wait();
}
}
2017-10-06 14:56:16 +02:00
2017-10-18 13:57:10 +02:00
public DateTimeOffset ExpiryDate
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem.ExpirationDate; }
set
{
if (!HasExpirationDate) return;
2020-04-16 14:08:50 +02:00
SelectedItem.ExpirationDate = value.Date;
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate).Wait();
}
2017-10-18 13:57:10 +02:00
}
2017-10-18 13:57:10 +02:00
public TimeSpan ExpiryTime
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem.ExpirationDate.TimeOfDay; }
set
{
if (!HasExpirationDate) return;
2020-04-16 14:08:50 +02:00
SelectedItem.ExpirationDate = SelectedItem.ExpirationDate.Date.Add(value);
SetFieldValue("ExpirationDate", SelectedItem.ExpirationDate).Wait();
}
2017-10-18 13:57:10 +02:00
}
public bool HasExpirationDate
2017-10-06 14:56:16 +02:00
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem.HasExpirationDate; }
set
{
2020-04-16 14:08:50 +02:00
SelectedItem.HasExpirationDate = value;
2020-04-14 17:49:29 +02:00
SetFieldValue(nameof(HasExpirationDate), value).Wait();
RaisePropertyChanged(nameof(HasExpirationDate));
}
2017-10-06 14:56:16 +02:00
}
2020-04-14 17:49:29 +02:00
public SolidColorBrush BackgroundColor
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem?.BackgroundColor.ToSolidColorBrush(); }
set
{
2020-04-16 14:08:50 +02:00
SelectedItem.BackgroundColor = value.ToColor();
SetFieldValue(nameof(BackgroundColor), SelectedItem.BackgroundColor).Wait();
}
}
2020-04-14 17:49:29 +02:00
public SolidColorBrush ForegroundColor
{
2020-04-16 14:08:50 +02:00
get { return SelectedItem?.ForegroundColor.ToSolidColorBrush(); }
set
{
2020-04-16 14:08:50 +02:00
SelectedItem.ForegroundColor = value.ToColor();
SetFieldValue(nameof(ForegroundColor), SelectedItem.ForegroundColor).Wait();
}
}
2020-04-15 19:06:13 +02:00
public bool IsEditMode
2017-10-18 13:57:10 +02:00
{
2020-04-16 14:08:50 +02:00
get { return IsCurrentEntry && _isEditMode; }
set { Set(() => IsEditMode, ref _isEditMode, value); }
2017-10-18 13:57:10 +02:00
}
public bool IsRevealPassword
{
get { return _isRevealPassword; }
set { Set(() => IsRevealPassword, ref _isRevealPassword, value); }
}
public RelayCommand SaveCommand { get; }
public RelayCommand GeneratePasswordCommand { get; }
public RelayCommand MoveCommand { get; }
public RelayCommand RestoreCommand { get; }
public RelayCommand DeleteCommand { get; }
public RelayCommand GoBackCommand { get; }
private DatabaseVm Database => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
private readonly IMediator _mediator;
private readonly INavigationService _navigation;
private readonly IResourceProxy _resource;
private readonly IDialogService _dialog;
private readonly INotificationService _notification;
private readonly GroupVm _parent;
2020-04-16 14:08:50 +02:00
private EntryVm _selectedItem;
private int _selectedIndex;
2017-10-06 14:56:16 +02:00
private bool _isEditMode;
private bool _isRevealPassword;
private double _passwordLength = 25;
2020-04-16 14:08:50 +02:00
private bool _isDirty;
public EntryDetailVm() { }
internal EntryDetailVm(string entryId) : this(entryId,
App.Services.GetRequiredService<IMediator>(),
App.Services.GetRequiredService<INavigationService>(),
App.Services.GetRequiredService<IResourceProxy>(),
App.Services.GetRequiredService<IDialogService>(),
App.Services.GetRequiredService<INotificationService>()) { }
public EntryDetailVm(string entryId, IMediator mediator, INavigationService navigation, IResourceProxy resource, IDialogService dialog, INotificationService notification)
{
_mediator = mediator;
_navigation = navigation;
_resource = resource;
_dialog = dialog;
_notification = notification;
2020-04-16 14:08:50 +02:00
SelectedItem = _mediator.Send(new GetEntryQuery { Id = entryId }).GetAwaiter().GetResult();
_parent = _mediator.Send(new GetGroupQuery { Id = SelectedItem.ParentGroupId }).GetAwaiter().GetResult();
History = new ObservableCollection<EntryVm> { SelectedItem };
foreach (var entry in SelectedItem.History.Skip(1))
2020-04-15 19:06:13 +02:00
{
History.Add(entry);
}
2020-04-16 14:08:50 +02:00
SelectedIndex = 0;
SaveCommand = new RelayCommand(async () => await SaveChanges(), () => Database.IsDirty);
GeneratePasswordCommand = new RelayCommand(async () => await GeneratePassword());
MoveCommand = new RelayCommand(async () => await Move(_parent), () => _parent != null);
2020-04-15 19:06:13 +02:00
RestoreCommand = new RelayCommand(async () => await RestoreHistory());
DeleteCommand = new RelayCommand(async () => await AskForDelete());
GoBackCommand = new RelayCommand(() => _navigation.GoBack());
}
private async Task AskForDelete()
{
if (IsCurrentEntry)
{
if (IsRecycleOnDelete)
{
await Delete();
_notification.Show(_resource.GetResourceValue("EntryRecyclingConfirmation"), _resource.GetResourceValue("EntryRecycled"));
}
else
{
await _dialog.ShowMessage(_resource.GetResourceValue("EntryDeletingConfirmation"),
_resource.GetResourceValue("EntityDeleteTitle"),
_resource.GetResourceValue("EntityDeleteActionButton"),
_resource.GetResourceValue("EntityDeleteCancelButton"),
async isOk =>
{
if (isOk) await Delete();
});
}
}
else
{
await _dialog.ShowMessage(_resource.GetResourceValue("HistoryDeleteDescription"), _resource.GetResourceValue("HistoryDeleteTitle"),
_resource.GetResourceValue("EntityDeleteActionButton"),
_resource.GetResourceValue("EntityDeleteCancelButton"), async isOk =>
{
if (!isOk) return;
await _mediator.Send(new DeleteHistoryCommand { Entry = History[0], HistoryIndex = History.Count - SelectedIndex - 1 });
History.RemoveAt(SelectedIndex);
SelectedIndex = 0;
SaveCommand.RaiseCanExecuteChanged();
});
}
}
2020-04-15 19:06:13 +02:00
public async Task GeneratePassword()
{
Password = await _mediator.Send(new GeneratePasswordCommand
{
BracketsPatternSelected = BracketsPatternSelected,
CustomChars = CustomChars,
DigitsPatternSelected = DigitsPatternSelected,
LowerCasePatternSelected = LowerCasePatternSelected,
MinusPatternSelected = MinusPatternSelected,
PasswordLength = (int)PasswordLength,
SpacePatternSelected = SpacePatternSelected,
SpecialPatternSelected = SpecialPatternSelected,
UnderscorePatternSelected = UnderscorePatternSelected,
UpperCasePatternSelected = UpperCasePatternSelected
});
RaisePropertyChanged(nameof(IsRevealPasswordEnabled));
}
public async Task Move(GroupVm destination)
{
2020-04-16 14:08:50 +02:00
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 });
SaveCommand.RaiseCanExecuteChanged();
2020-04-16 14:08:50 +02:00
_isDirty = true;
}
public async Task AddHistory()
{
if (_isDirty) await _mediator.Send(new AddHistoryCommand { Entry = History[0] });
}
2020-04-16 14:08:50 +02:00
private async Task RestoreHistory()
{
await _mediator.Send(new RestoreHistoryCommand { Entry = History[0], HistoryIndex = History.Count - SelectedIndex - 1 });
2020-04-16 14:08:50 +02:00
History.Insert(0, SelectedItem);
SelectedIndex = 0;
SaveCommand.RaiseCanExecuteChanged();
}
private async Task SaveChanges()
{
await AddHistory();
await _mediator.Send(new SaveDatabaseCommand());
SaveCommand.RaiseCanExecuteChanged();
2020-04-16 14:08:50 +02:00
_isDirty = false;
}
private async Task Delete()
{
await _mediator.Send(new DeleteEntryCommand
{
EntryId = Id,
ParentGroupId = SelectedItem.ParentGroupId,
RecycleBinName = _resource.GetResourceValue("RecycleBinTitle")
});
_navigation.GoBack();
}
}
}