From a9ed588c9a06a780b3841073f7dd540e4d559ddb Mon Sep 17 00:00:00 2001 From: Geoffroy BONNEVILLE Date: Wed, 22 Apr 2020 18:12:28 +0200 Subject: [PATCH] Creation of a notification service --- ModernKeePass.Application/Application.csproj | 3 +- .../Common/Interfaces/INotificationService.cs | 7 + .../Interfaces/IProxyInvocationHandler.cs | 9 -- .../Services/DatabaseService.cs | 103 ------------- .../DependencyInjection.cs | 1 + .../Infrastructure.csproj | 1 + .../UWP/ToastNotificationService.cs | 23 +++ ModernKeePass/App.xaml.cs | 8 +- ModernKeePass/Strings/en-US/CodeBehind.resw | 2 +- ModernKeePass/Strings/fr-FR/CodeBehind.resw | 2 +- .../SetCredentialsUserControl.xaml | 2 +- .../SetCredentialsUserControl.xaml.cs | 2 +- WinAppCommon/Actions/ToastAction.cs | 6 +- .../Common/ToastNotificationHelper.cs | 53 ------- .../ViewModels/Items/SettingsSecurityVm.cs | 20 +-- .../UserControls/OpenDatabaseControlVm.cs | 12 +- .../UserControls/SetCredentialsVm.cs | 137 ++++++++++++++++++ WinAppCommon/WinAppCommon.projitems | 4 +- 18 files changed, 201 insertions(+), 194 deletions(-) create mode 100644 ModernKeePass.Application/Common/Interfaces/INotificationService.cs delete mode 100644 ModernKeePass.Application/Common/Interfaces/IProxyInvocationHandler.cs delete mode 100644 ModernKeePass.Application/Services/DatabaseService.cs create mode 100644 ModernKeePass.Infrastructure/UWP/ToastNotificationService.cs delete mode 100644 WinAppCommon/Common/ToastNotificationHelper.cs create mode 100644 WinAppCommon/ViewModels/UserControls/SetCredentialsVm.cs diff --git a/ModernKeePass.Application/Application.csproj b/ModernKeePass.Application/Application.csproj index f50d458..e48f95d 100644 --- a/ModernKeePass.Application/Application.csproj +++ b/ModernKeePass.Application/Application.csproj @@ -82,7 +82,7 @@ - + @@ -135,7 +135,6 @@ - diff --git a/ModernKeePass.Application/Common/Interfaces/INotificationService.cs b/ModernKeePass.Application/Common/Interfaces/INotificationService.cs new file mode 100644 index 0000000..3c0fccc --- /dev/null +++ b/ModernKeePass.Application/Common/Interfaces/INotificationService.cs @@ -0,0 +1,7 @@ +namespace ModernKeePass.Application.Common.Interfaces +{ + public interface INotificationService + { + void Show(string title, string text); + } +} \ No newline at end of file diff --git a/ModernKeePass.Application/Common/Interfaces/IProxyInvocationHandler.cs b/ModernKeePass.Application/Common/Interfaces/IProxyInvocationHandler.cs deleted file mode 100644 index 5a04d1f..0000000 --- a/ModernKeePass.Application/Common/Interfaces/IProxyInvocationHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Reflection; - -namespace ModernKeePass.Application.Common.Interfaces -{ - public interface IProxyInvocationHandler - { - object Invoke(object proxy, MethodInfo method, object[] parameters); - } -} \ No newline at end of file diff --git a/ModernKeePass.Application/Services/DatabaseService.cs b/ModernKeePass.Application/Services/DatabaseService.cs deleted file mode 100644 index cbfe4ce..0000000 --- a/ModernKeePass.Application/Services/DatabaseService.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Threading.Tasks; -using ModernKeePass.Application.Common.Interfaces; -using ModernKeePass.Domain.Dtos; -using ModernKeePass.Domain.Entities; -using ModernKeePass.Domain.Interfaces; - -namespace ModernKeePass.Application.Services -{ - public class DatabaseService: IDatabaseService - { - private readonly IDatabaseProxy _databaseProxy; - - public string Name { get; private set; } - public bool IsOpen { get; private set; } - public Domain.Entities.GroupEntity RootGroupEntity { get; private set; } - public Domain.Entities.GroupEntity RecycleBin - { - get => _databaseProxy.RecycleBin; - set => _databaseProxy.RecycleBin = value; - } - public Entity Cipher - { - get => _databaseProxy.Cipher; - set => _databaseProxy.Cipher = value; - } - public Entity KeyDerivation - { - get => _databaseProxy.KeyDerivation; - set => _databaseProxy.KeyDerivation = value; - } - public string Compression - { - get => _databaseProxy.Compression; - set => _databaseProxy.Compression = value; - } - public bool IsRecycleBinEnabled => RecycleBin != null; - - public DatabaseService(IDatabaseProxy databaseProxy) - { - _databaseProxy = databaseProxy; - } - - public async Task Open(FileInfo fileInfo, Credentials credentials) - { - RootGroupEntity = await _databaseProxy.Open(fileInfo, credentials); - Name = RootGroupEntity?.Name; - IsOpen = true; - } - - public async Task Create(FileInfo fileInfo, Credentials credentials) - { - RootGroupEntity = await _databaseProxy.Create(fileInfo, credentials); - Name = RootGroupEntity?.Name; - IsOpen = true; - } - - public async Task Save() - { - await _databaseProxy.SaveDatabase(); - } - - public async Task SaveAs(FileInfo fileInfo) - { - await _databaseProxy.SaveDatabase(fileInfo); - } - - public Task CreateRecycleBin(Domain.Entities.GroupEntity recycleBinGroupEntity) - { - throw new NotImplementedException(); - } - - public async Task UpdateCredentials(Credentials credentials) - { - await _databaseProxy.UpdateCredentials(credentials); - await Save(); - } - - public void Close() - { - _databaseProxy.CloseDatabase(); - IsOpen = false; - } - - public async Task AddEntity(GroupEntity parentEntity, Entity entity) - { - await _databaseProxy.AddEntity(parentEntity, entity); - //await Save(); - } - - public async Task UpdateEntity(Entity entity) - { - await _databaseProxy.UpdateEntity(entity); - } - - public async Task DeleteEntity(Entity entity) - { - if (IsRecycleBinEnabled) await AddEntity(RecycleBin, entity); - await _databaseProxy.DeleteEntity(entity); - //await Save(); - } - } -} \ No newline at end of file diff --git a/ModernKeePass.Infrastructure/DependencyInjection.cs b/ModernKeePass.Infrastructure/DependencyInjection.cs index 1c9f466..49f0d0d 100644 --- a/ModernKeePass.Infrastructure/DependencyInjection.cs +++ b/ModernKeePass.Infrastructure/DependencyInjection.cs @@ -29,6 +29,7 @@ namespace ModernKeePass.Infrastructure services.AddTransient(typeof(ISettingsProxy), typeof(UwpSettingsClient)); services.AddTransient(typeof(IRecentProxy), typeof(UwpRecentFilesClient)); services.AddTransient(typeof(IResourceProxy), typeof(UwpResourceClient)); + services.AddTransient(typeof(INotificationService), typeof(ToastNotificationService)); return services; } } diff --git a/ModernKeePass.Infrastructure/Infrastructure.csproj b/ModernKeePass.Infrastructure/Infrastructure.csproj index aa33c0d..bcf0d3d 100644 --- a/ModernKeePass.Infrastructure/Infrastructure.csproj +++ b/ModernKeePass.Infrastructure/Infrastructure.csproj @@ -88,6 +88,7 @@ + diff --git a/ModernKeePass.Infrastructure/UWP/ToastNotificationService.cs b/ModernKeePass.Infrastructure/UWP/ToastNotificationService.cs new file mode 100644 index 0000000..f5742b7 --- /dev/null +++ b/ModernKeePass.Infrastructure/UWP/ToastNotificationService.cs @@ -0,0 +1,23 @@ +using System; +using Windows.UI.Notifications; +using ModernKeePass.Application.Common.Interfaces; + +namespace ModernKeePass.Infrastructure.UWP +{ + public class ToastNotificationService: INotificationService + { + public void Show(string title, string text) + { + var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02); + var toastElements = notificationXml.GetElementsByTagName("text"); + toastElements[0].AppendChild(notificationXml.CreateTextNode(title)); + toastElements[1].AppendChild(notificationXml.CreateTextNode(text)); + + var toast = new ToastNotification(notificationXml) + { + ExpirationTime = DateTime.Now.AddSeconds(5) + }; + ToastNotificationManager.CreateToastNotifier().Show(toast); + } + } +} \ No newline at end of file diff --git a/ModernKeePass/App.xaml.cs b/ModernKeePass/App.xaml.cs index 64afcb9..e855750 100644 --- a/ModernKeePass/App.xaml.cs +++ b/ModernKeePass/App.xaml.cs @@ -41,6 +41,7 @@ namespace ModernKeePass private readonly INavigationService _navigation; private readonly IHockeyClient _hockey; private readonly IDialogService _dialog; + private readonly INotificationService _notification; public static IServiceProvider Services { get; private set; } @@ -64,6 +65,7 @@ namespace ModernKeePass _settings = Services.GetService(); _navigation = Services.GetService(); _dialog = Services.GetService(); + _notification = Services.GetService(); _hockey = Services.GetService(); InitializeComponent(); @@ -181,14 +183,14 @@ namespace ModernKeePass { await _mediator.Send(new ReOpenDatabaseQuery()); #if DEBUG - ToastNotificationHelper.ShowGenericToast("App resumed", "Database reopened (changes were saved)"); + _notification.Show("App resumed", "Database reopened (changes were saved)"); #endif } catch (Exception) { currentFrame?.Navigate(typeof(MainPage)); #if DEBUG - ToastNotificationHelper.ShowGenericToast("App resumed", "Nothing to do, no previous database opened"); + _notification.Show("App resumed", "Nothing to do, no previous database opened"); #endif } } @@ -229,7 +231,7 @@ namespace ModernKeePass } catch (Exception exception) { - ToastNotificationHelper.ShowErrorToast(exception); + _notification.Show(exception.Source, exception.Message); } finally { diff --git a/ModernKeePass/Strings/en-US/CodeBehind.resw b/ModernKeePass/Strings/en-US/CodeBehind.resw index 9365040..a6e2ccb 100644 --- a/ModernKeePass/Strings/en-US/CodeBehind.resw +++ b/ModernKeePass/Strings/en-US/CodeBehind.resw @@ -133,7 +133,7 @@ Opening... - Database composite key updated. + Database credentials updated. Delete diff --git a/ModernKeePass/Strings/fr-FR/CodeBehind.resw b/ModernKeePass/Strings/fr-FR/CodeBehind.resw index 5ef0eeb..c3e8b29 100644 --- a/ModernKeePass/Strings/fr-FR/CodeBehind.resw +++ b/ModernKeePass/Strings/fr-FR/CodeBehind.resw @@ -133,7 +133,7 @@ Ouverture... - Clé composite de la base de données mise à jour. + Identifiants de la base de données mis à jour. Supprimer diff --git a/ModernKeePass/Views/UserControls/SetCredentialsUserControl.xaml b/ModernKeePass/Views/UserControls/SetCredentialsUserControl.xaml index 5c2875c..79b88a5 100644 --- a/ModernKeePass/Views/UserControls/SetCredentialsUserControl.xaml +++ b/ModernKeePass/Views/UserControls/SetCredentialsUserControl.xaml @@ -14,7 +14,7 @@ - + diff --git a/ModernKeePass/Views/UserControls/SetCredentialsUserControl.xaml.cs b/ModernKeePass/Views/UserControls/SetCredentialsUserControl.xaml.cs index 3e60976..d5562d0 100644 --- a/ModernKeePass/Views/UserControls/SetCredentialsUserControl.xaml.cs +++ b/ModernKeePass/Views/UserControls/SetCredentialsUserControl.xaml.cs @@ -11,7 +11,7 @@ namespace ModernKeePass.Views.UserControls { public sealed partial class SetCredentialsUserControl { - private SetCredentialsViewModel Model => (SetCredentialsViewModel)Resources["ViewModel"]; + private SetCredentialsVm Model => (SetCredentialsVm)Resources["ViewModel"]; public string ButtonLabel { diff --git a/WinAppCommon/Actions/ToastAction.cs b/WinAppCommon/Actions/ToastAction.cs index e6da006..7c61493 100644 --- a/WinAppCommon/Actions/ToastAction.cs +++ b/WinAppCommon/Actions/ToastAction.cs @@ -1,6 +1,7 @@ using Windows.UI.Xaml; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Xaml.Interactivity; -using ModernKeePass.Common; +using ModernKeePass.Application.Common.Interfaces; namespace ModernKeePass.Actions { @@ -26,7 +27,8 @@ namespace ModernKeePass.Actions public object Execute(object sender, object parameter) { - ToastNotificationHelper.ShowGenericToast(Title, Message); + var notification = App.Services.GetRequiredService(); + notification.Show(Title, Message); return null; } } diff --git a/WinAppCommon/Common/ToastNotificationHelper.cs b/WinAppCommon/Common/ToastNotificationHelper.cs deleted file mode 100644 index 8d18c5a..0000000 --- a/WinAppCommon/Common/ToastNotificationHelper.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using Windows.Data.Json; -using Windows.Data.Xml.Dom; -using Windows.UI.Notifications; -using ModernKeePass.Interfaces; - -namespace ModernKeePass.Common -{ - public static class ToastNotificationHelper - { - public static void ShowMovedToast(IVmEntity entity, string action, string text) - { - var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02); - var toastElements = notificationXml.GetElementsByTagName("text"); - toastElements[0].AppendChild(notificationXml.CreateTextNode($"{action} {entity.Title}")); - toastElements[1].AppendChild(notificationXml.CreateTextNode(text)); - var toastNode = notificationXml.SelectSingleNode("/toast"); - - // This is useful only for Windows 10 UWP - var launch = new JsonObject - { - {"entityType", JsonValue.CreateStringValue(entity.GetType().Name)}, - {"entityId", JsonValue.CreateStringValue(entity.Id)} - }; - ((XmlElement)toastNode)?.SetAttribute("launch", launch.Stringify()); - - var toast = new ToastNotification(notificationXml) - { - ExpirationTime = DateTime.Now.AddSeconds(5) - }; - ToastNotificationManager.CreateToastNotifier().Show(toast); - } - - public static void ShowGenericToast(string title, string text) - { - var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02); - var toastElements = notificationXml.GetElementsByTagName("text"); - toastElements[0].AppendChild(notificationXml.CreateTextNode(title)); - toastElements[1].AppendChild(notificationXml.CreateTextNode(text)); - - var toast = new ToastNotification(notificationXml) - { - ExpirationTime = DateTime.Now.AddSeconds(5) - }; - ToastNotificationManager.CreateToastNotifier().Show(toast); - } - - public static void ShowErrorToast(Exception exception) - { - ShowGenericToast(exception.Source, exception.Message); - } - } -} diff --git a/WinAppCommon/ViewModels/Items/SettingsSecurityVm.cs b/WinAppCommon/ViewModels/Items/SettingsSecurityVm.cs index c8e6c04..b93cd13 100644 --- a/WinAppCommon/ViewModels/Items/SettingsSecurityVm.cs +++ b/WinAppCommon/ViewModels/Items/SettingsSecurityVm.cs @@ -6,26 +6,27 @@ using Messages; using Microsoft.Extensions.DependencyInjection; using ModernKeePass.Application.Common.Interfaces; using ModernKeePass.Application.Database.Commands.UpdateCredentials; +using ModernKeePass.Application.Database.Queries.GetDatabase; namespace ModernKeePass.ViewModels.ListItems { public class SettingsSecurityVm { private readonly IMediator _mediator; - private readonly ISettingsProxy _settings; - private readonly INavigationService _navigation; + private readonly IResourceProxy _resource; + private readonly INotificationService _notification; public SettingsSecurityVm(): this( App.Services.GetRequiredService(), - App.Services.GetRequiredService(), - App.Services.GetRequiredService(), - App.Services.GetRequiredService()) { } + App.Services.GetRequiredService(), + App.Services.GetRequiredService(), + App.Services.GetRequiredService()) { } - public SettingsSecurityVm(IMediator mediator, ISettingsProxy settings, IMessenger messenger, INavigationService navigation) + public SettingsSecurityVm(IMediator mediator, IMessenger messenger, IResourceProxy resource, INotificationService notification) { _mediator = mediator; - _settings = settings; - _navigation = navigation; + _resource = resource; + _notification = notification; messenger.Register(this, async message => await UpdateDatabaseCredentials(message)); } @@ -37,7 +38,8 @@ namespace ModernKeePass.ViewModels.ListItems KeyFilePath = message.KeyFilePath, Password = message.Password }); - //TODO: Add Toast + var database = await _mediator.Send(new GetDatabaseQuery()); + _notification.Show(database.Name, _resource.GetResourceValue("CompositeKeyUpdated")); } } } \ No newline at end of file diff --git a/WinAppCommon/ViewModels/UserControls/OpenDatabaseControlVm.cs b/WinAppCommon/ViewModels/UserControls/OpenDatabaseControlVm.cs index 000bddd..9fd6f9d 100644 --- a/WinAppCommon/ViewModels/UserControls/OpenDatabaseControlVm.cs +++ b/WinAppCommon/ViewModels/UserControls/OpenDatabaseControlVm.cs @@ -13,7 +13,6 @@ using ModernKeePass.Application.Database.Commands.CloseDatabase; using ModernKeePass.Application.Database.Commands.SaveDatabase; using ModernKeePass.Application.Database.Queries.GetDatabase; using ModernKeePass.Application.Database.Queries.OpenDatabase; -using ModernKeePass.Common; namespace ModernKeePass.ViewModels { @@ -103,6 +102,7 @@ namespace ModernKeePass.ViewModels private readonly IResourceProxy _resource; private readonly IMessenger _messenger; private readonly IDialogService _dialog; + private readonly INotificationService _notification; private bool _hasPassword; private bool _hasKeyFile; private bool _isOpening; @@ -117,15 +117,17 @@ namespace ModernKeePass.ViewModels App.Services.GetRequiredService(), App.Services.GetRequiredService(), App.Services.GetRequiredService(), - App.Services.GetRequiredService()) + App.Services.GetRequiredService(), + App.Services.GetRequiredService()) { } - public OpenDatabaseControlVm(IMediator mediator, IResourceProxy resource, IMessenger messenger, IDialogService dialog) + public OpenDatabaseControlVm(IMediator mediator, IResourceProxy resource, IMessenger messenger, IDialogService dialog, INotificationService notification) { _mediator = mediator; _resource = resource; _messenger = messenger; _dialog = dialog; + _notification = notification; OpenDatabaseCommand = new RelayCommand(async databaseFilePath => await TryOpenDatabase(databaseFilePath), _ => IsValid); _keyFileText = _resource.GetResourceValue("CompositeKeyDefaultKeyFile"); _openButtonLabel = _resource.GetResourceValue("CompositeKeyOpenButtonLabel"); @@ -147,9 +149,7 @@ namespace ModernKeePass.ViewModels if (isOk) { await _mediator.Send(new SaveDatabaseCommand()); - ToastNotificationHelper.ShowGenericToast( - database.Name, - _resource.GetResourceValue("ToastSavedMessage")); + _notification.Show(database.Name, _resource.GetResourceValue("ToastSavedMessage")); await _mediator.Send(new CloseDatabaseCommand()); await OpenDatabase(databaseFilePath); } diff --git a/WinAppCommon/ViewModels/UserControls/SetCredentialsVm.cs b/WinAppCommon/ViewModels/UserControls/SetCredentialsVm.cs new file mode 100644 index 0000000..2cd942f --- /dev/null +++ b/WinAppCommon/ViewModels/UserControls/SetCredentialsVm.cs @@ -0,0 +1,137 @@ +using System.Threading.Tasks; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Command; +using GalaSoft.MvvmLight.Messaging; +using MediatR; +using Messages; +using Microsoft.Extensions.DependencyInjection; +using ModernKeePass.Application.Common.Interfaces; +using ModernKeePass.Application.Security.Commands.GenerateKeyFile; + +namespace ModernKeePass.ViewModels +{ + public class SetCredentialsVm : ObservableObject + { + private readonly IMediator _mediator; + private readonly ICredentialsProxy _credentials; + private readonly IMessenger _messenger; + + public bool HasPassword + { + get { return _hasPassword; } + set + { + Set(() => HasPassword, ref _hasPassword, value); + RaisePropertyChanged(nameof(IsValid)); + GenerateCredentialsCommand.RaiseCanExecuteChanged(); + } + } + + public bool HasKeyFile + { + get { return _hasKeyFile; } + set + { + Set(() => HasKeyFile, ref _hasKeyFile, value); + RaisePropertyChanged(nameof(IsValid)); + GenerateCredentialsCommand.RaiseCanExecuteChanged(); + } + } + + public string Status + { + get { return _status; } + set { Set(() => Status, ref _status, value); } + } + + public string Password + { + get { return _password; } + set + { + _password = value; + RaisePropertyChanged(nameof(IsValid)); + RaisePropertyChanged(nameof(PasswordComplexityIndicator)); + GenerateCredentialsCommand.RaiseCanExecuteChanged(); + } + } + public string ConfirmPassword + { + get { return _confirmPassword; } + set + { + _confirmPassword = value; + RaisePropertyChanged(nameof(IsValid)); + GenerateCredentialsCommand.RaiseCanExecuteChanged(); + } + } + + public string KeyFilePath + { + get { return _keyFilePath; } + set + { + _keyFilePath = value; + RaisePropertyChanged(nameof(IsValid)); + GenerateCredentialsCommand.RaiseCanExecuteChanged(); + } + } + + public string KeyFileText + { + get { return _keyFileText; } + set { Set(() => KeyFileText, ref _keyFileText, value); } + } + + public string OpenButtonLabel + { + get { return _openButtonLabel; } + set { Set(() => OpenButtonLabel, ref _openButtonLabel, value); } + } + + public double PasswordComplexityIndicator => _credentials.EstimatePasswordComplexity(Password); + + public bool IsValid => HasPassword && Password == ConfirmPassword || HasKeyFile && !string.IsNullOrEmpty(KeyFilePath); + + public RelayCommand GenerateCredentialsCommand{ get; } + + private bool _hasPassword; + private bool _hasKeyFile; + private string _password = string.Empty; + private string _confirmPassword; + private string _status; + private string _keyFilePath; + private string _keyFileText; + private string _openButtonLabel; + + public SetCredentialsVm(): this( + App.Services.GetRequiredService(), + App.Services.GetRequiredService(), + App.Services.GetRequiredService(), + App.Services.GetRequiredService()) { } + + public SetCredentialsVm(IMediator mediator, ICredentialsProxy credentials, IMessenger messenger, IResourceProxy resource) + { + _mediator = mediator; + _credentials = credentials; + _messenger = messenger; + GenerateCredentialsCommand = new RelayCommand(GenerateCredentials, () => IsValid); + + _keyFileText = resource.GetResourceValue("CompositeKeyDefaultKeyFile"); + } + + public async Task GenerateKeyFile() + { + await _mediator.Send(new GenerateKeyFileCommand {KeyFilePath = KeyFilePath}); + } + + private void GenerateCredentials() + { + _messenger.Send(new CredentialsSetMessage + { + Password = HasPassword ? Password : null, + KeyFilePath = HasKeyFile ? KeyFilePath : null + }); + } + } +} \ No newline at end of file diff --git a/WinAppCommon/WinAppCommon.projitems b/WinAppCommon/WinAppCommon.projitems index aa661d6..63cc9c7 100644 --- a/WinAppCommon/WinAppCommon.projitems +++ b/WinAppCommon/WinAppCommon.projitems @@ -14,12 +14,10 @@ - - @@ -58,6 +56,6 @@ - + \ No newline at end of file