Creation of a notification service

This commit is contained in:
Geoffroy BONNEVILLE
2020-04-22 18:12:28 +02:00
parent 61f5e9df0b
commit a9ed588c9a
18 changed files with 201 additions and 194 deletions

View File

@@ -82,7 +82,7 @@
<Compile Include="Common\Interfaces\IFileProxy.cs" />
<Compile Include="Common\Interfaces\IImportFormat.cs" />
<Compile Include="Common\Interfaces\ICredentialsProxy.cs" />
<Compile Include="Common\Interfaces\IProxyInvocationHandler.cs" />
<Compile Include="Common\Interfaces\INotificationService.cs" />
<Compile Include="Common\Interfaces\IRecentProxy.cs" />
<Compile Include="Common\Interfaces\IResourceProxy.cs" />
<Compile Include="Common\Interfaces\ISettingsProxy.cs" />
@@ -135,7 +135,6 @@
<Compile Include="Security\Commands\GenerateKeyFile\GenerateKeyFileCommand.cs" />
<Compile Include="Security\Commands\GeneratePassword\GeneratePasswordCommand.cs" />
<Compile Include="Security\Queries\EstimatePasswordComplexity\EstimatePasswordComplexityQuery.cs" />
<Content Include="Services\DatabaseService.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>

View File

@@ -0,0 +1,7 @@
namespace ModernKeePass.Application.Common.Interfaces
{
public interface INotificationService
{
void Show(string title, string text);
}
}

View File

@@ -1,9 +0,0 @@
using System.Reflection;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface IProxyInvocationHandler
{
object Invoke(object proxy, MethodInfo method, object[] parameters);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -88,6 +88,7 @@
<Compile Include="KeePass\KeePassCredentialsClient.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UWP\StorageFileClient.cs" />
<Compile Include="UWP\ToastNotificationService.cs" />
<Compile Include="UWP\UwpRecentFilesClient.cs" />
<Compile Include="UWP\UwpResourceClient.cs" />
<Compile Include="UWP\UwpSettingsClient.cs" />

View File

@@ -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);
}
}
}

View File

@@ -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<ISettingsProxy>();
_navigation = Services.GetService<INavigationService>();
_dialog = Services.GetService<IDialogService>();
_notification = Services.GetService<INotificationService>();
_hockey = Services.GetService<IHockeyClient>();
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
{

View File

@@ -133,7 +133,7 @@
<value>Opening...</value>
</data>
<data name="CompositeKeyUpdated" xml:space="preserve">
<value>Database composite key updated.</value>
<value>Database credentials updated.</value>
</data>
<data name="EntityDeleteActionButton" xml:space="preserve">
<value>Delete</value>

View File

@@ -133,7 +133,7 @@
<value>Ouverture...</value>
</data>
<data name="CompositeKeyUpdated" xml:space="preserve">
<value>Clé composite de la base de données mise à jour.</value>
<value>Identifiants de la base de données mis à jour.</value>
</data>
<data name="EntityDeleteActionButton" xml:space="preserve">
<value>Supprimer</value>

View File

@@ -14,7 +14,7 @@
<converters:DoubleToSolidColorBrushConverter x:Key="DoubleToSolidColorBrushConverter"/>
<converters:DiscreteIntToSolidColorBrushConverter x:Key="DiscreteIntToSolidColorBrushConverter"/>
<converters:EmptyStringToVisibilityConverter x:Key="EmptyStringToVisibilityConverter"/>
<viewModels:SetCredentialsViewModel x:Key="ViewModel"/>
<viewModels:SetCredentialsVm x:Key="ViewModel"/>
</UserControl.Resources>
<Grid DataContext="{StaticResource ViewModel}">
<Grid.ColumnDefinitions>

View File

@@ -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
{

View File

@@ -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<INotificationService>();
notification.Show(Title, Message);
return null;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<IMediator>(),
App.Services.GetRequiredService<ISettingsProxy>(),
App.Services.GetRequiredService<IMessenger>(),
App.Services.GetRequiredService<INavigationService>()) { }
App.Services.GetRequiredService<IMessenger>(),
App.Services.GetRequiredService<IResourceProxy>(),
App.Services.GetRequiredService<INotificationService>()) { }
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<CredentialsSetMessage>(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"));
}
}
}

View File

@@ -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<IMediator>(),
App.Services.GetRequiredService<IResourceProxy>(),
App.Services.GetRequiredService<IMessenger>(),
App.Services.GetRequiredService<IDialogService>())
App.Services.GetRequiredService<IDialogService>(),
App.Services.GetRequiredService<INotificationService>())
{ }
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<string>(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);
}

View File

@@ -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<IMediator>(),
App.Services.GetRequiredService<ICredentialsProxy>(),
App.Services.GetRequiredService<IMessenger>(),
App.Services.GetRequiredService<IResourceProxy>()) { }
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
});
}
}
}

View File

@@ -14,12 +14,10 @@
<Compile Include="$(MSBuildThisFileDirectory)Actions\SetupFocusAction.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Actions\ToastAction.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\Constants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\MessageDialogHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\NavigationHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\ObservableDictionary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\RelayCommand.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\SuspensionManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\ToastNotificationHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\ListViewWithDisable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\TextBoxWithButton.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Converters\BooleanToVisibilityConverter.cs" />
@@ -58,6 +56,6 @@
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\RecentVm.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\SaveVm.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\UserControls\OpenDatabaseControlVm.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\UserControls\SetCredentialsViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\UserControls\SetCredentialsVm.cs" />
</ItemGroup>
</Project>