mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 23:50:18 -04:00
Save error is now handled via Messenger instead of unhandled exception handler (which didn't work)
Save as actually works now WIP Styles Code cleanup
This commit is contained in:
@@ -27,7 +27,6 @@ namespace ModernKeePass.Application.Common.Interfaces
|
|||||||
Task ReOpen(byte[] file);
|
Task ReOpen(byte[] file);
|
||||||
Task Create(Credentials credentials, string name, DatabaseVersion version = DatabaseVersion.V4);
|
Task Create(Credentials credentials, string name, DatabaseVersion version = DatabaseVersion.V4);
|
||||||
Task<byte[]> SaveDatabase();
|
Task<byte[]> SaveDatabase();
|
||||||
Task<byte[]> SaveDatabase(byte[] newFileContents);
|
|
||||||
void UpdateCredentials(Credentials credentials);
|
void UpdateCredentials(Credentials credentials);
|
||||||
void CloseDatabase();
|
void CloseDatabase();
|
||||||
|
|
||||||
|
@@ -1,12 +1,15 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ModernKeePass.Domain.Dtos;
|
||||||
|
|
||||||
namespace ModernKeePass.Application.Common.Interfaces
|
namespace ModernKeePass.Application.Common.Interfaces
|
||||||
{
|
{
|
||||||
public interface IFileProxy
|
public interface IFileProxy
|
||||||
{
|
{
|
||||||
Task<byte[]> OpenBinaryFile(string path);
|
Task<FileInfo> OpenFile(string name, string extension, bool addToRecent);
|
||||||
Task<IList<string>> OpenTextFile(string path);
|
Task<FileInfo> CreateFile(string name, string extension, string description, bool addToRecent);
|
||||||
|
Task<byte[]> ReadBinaryFile(string path);
|
||||||
|
Task<IList<string>> ReadTextFile(string path);
|
||||||
Task WriteBinaryContentsToFile(string path, byte[] contents);
|
Task WriteBinaryContentsToFile(string path, byte[] contents);
|
||||||
void ReleaseFile(string path);
|
void ReleaseFile(string path);
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,7 @@ namespace ModernKeePass.Application.Database.Commands.CreateDatabase
|
|||||||
|
|
||||||
await _database.Create(new Credentials
|
await _database.Create(new Credentials
|
||||||
{
|
{
|
||||||
KeyFileContents = !string.IsNullOrEmpty(message.KeyFilePath) ? await _file.OpenBinaryFile(message.KeyFilePath) : null,
|
KeyFileContents = !string.IsNullOrEmpty(message.KeyFilePath) ? await _file.ReadBinaryFile(message.KeyFilePath) : null,
|
||||||
Password = message.Password
|
Password = message.Password
|
||||||
}, message.Name, version);
|
}, message.Name, version);
|
||||||
_database.FileAccessToken = message.FilePath;
|
_database.FileAccessToken = message.FilePath;
|
||||||
|
@@ -27,27 +27,20 @@ namespace ModernKeePass.Application.Database.Commands.SaveDatabase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] contents;
|
if (!string.IsNullOrEmpty(message.FilePath))
|
||||||
if (string.IsNullOrEmpty(message.FilePath))
|
|
||||||
{
|
{
|
||||||
contents = await _database.SaveDatabase();
|
_database.FileAccessToken = message.FilePath;
|
||||||
|
}
|
||||||
|
|
||||||
// Test DB integrity before writing changes to file
|
var contents = await _database.SaveDatabase();
|
||||||
|
|
||||||
|
// Test DB integrity
|
||||||
_database.CloseDatabase();
|
_database.CloseDatabase();
|
||||||
await _database.ReOpen(contents);
|
await _database.ReOpen(contents);
|
||||||
|
|
||||||
|
// Transactional write to file
|
||||||
await _file.WriteBinaryContentsToFile(_database.FileAccessToken, contents);
|
await _file.WriteBinaryContentsToFile(_database.FileAccessToken, contents);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var newFileContents = await _file.OpenBinaryFile(message.FilePath);
|
|
||||||
contents = await _database.SaveDatabase(newFileContents);
|
|
||||||
await _file.WriteBinaryContentsToFile(message.FilePath, contents);
|
|
||||||
|
|
||||||
_file.ReleaseFile(_database.FileAccessToken);
|
|
||||||
_database.FileAccessToken = message.FilePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
throw new SaveException(exception);
|
throw new SaveException(exception);
|
||||||
|
@@ -27,7 +27,7 @@ namespace ModernKeePass.Application.Database.Commands.UpdateCredentials
|
|||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
_database.UpdateCredentials(new Credentials
|
_database.UpdateCredentials(new Credentials
|
||||||
{
|
{
|
||||||
KeyFileContents = !string.IsNullOrEmpty(message.KeyFilePath) ? await _file.OpenBinaryFile(message.KeyFilePath) : null,
|
KeyFileContents = !string.IsNullOrEmpty(message.KeyFilePath) ? await _file.ReadBinaryFile(message.KeyFilePath) : null,
|
||||||
Password = message.Password
|
Password = message.Password
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -27,11 +27,11 @@ namespace ModernKeePass.Application.Database.Queries.OpenDatabase
|
|||||||
{
|
{
|
||||||
if (_database.IsDirty) throw new DatabaseOpenException();
|
if (_database.IsDirty) throw new DatabaseOpenException();
|
||||||
|
|
||||||
var file = await _file.OpenBinaryFile(message.FilePath);
|
var file = await _file.ReadBinaryFile(message.FilePath);
|
||||||
var hasKeyFile = !string.IsNullOrEmpty(message.KeyFilePath);
|
var hasKeyFile = !string.IsNullOrEmpty(message.KeyFilePath);
|
||||||
await _database.Open(file, new Credentials
|
await _database.Open(file, new Credentials
|
||||||
{
|
{
|
||||||
KeyFileContents = hasKeyFile ? await _file.OpenBinaryFile(message.KeyFilePath): null,
|
KeyFileContents = hasKeyFile ? await _file.ReadBinaryFile(message.KeyFilePath): null,
|
||||||
Password = message.Password
|
Password = message.Password
|
||||||
});
|
});
|
||||||
if (hasKeyFile) _file.ReleaseFile(message.KeyFilePath);
|
if (hasKeyFile) _file.ReleaseFile(message.KeyFilePath);
|
||||||
|
@@ -23,7 +23,7 @@ namespace ModernKeePass.Application.Database.Queries.ReOpenDatabase
|
|||||||
if (_database.IsOpen) throw new DatabaseOpenException();
|
if (_database.IsOpen) throw new DatabaseOpenException();
|
||||||
if (string.IsNullOrEmpty(_database.FileAccessToken)) throw new DatabaseClosedException();
|
if (string.IsNullOrEmpty(_database.FileAccessToken)) throw new DatabaseClosedException();
|
||||||
|
|
||||||
var file = await _file.OpenBinaryFile(_database.FileAccessToken);
|
var file = await _file.ReadBinaryFile(_database.FileAccessToken);
|
||||||
await _database.ReOpen(file);
|
await _database.ReOpen(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,5 +3,11 @@
|
|||||||
public static class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
public static string EmptyId => "00000000000000000000000000000000";
|
public static string EmptyId => "00000000000000000000000000000000";
|
||||||
|
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
public static string Any => "*";
|
||||||
|
public static string Kdbx => ".kdbx";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -152,15 +152,6 @@ namespace ModernKeePass.Infrastructure.KeePass
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<byte[]> SaveDatabase(byte[] newFileContents)
|
|
||||||
{
|
|
||||||
return await Task.Run(() =>
|
|
||||||
{
|
|
||||||
_pwDatabase.SaveAs(IOConnectionInfo.FromByteArray(newFileContents), true, new NullStatusLogger());
|
|
||||||
return _pwDatabase.IOConnectionInfo.Bytes;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CloseDatabase()
|
public void CloseDatabase()
|
||||||
{
|
{
|
||||||
_pwDatabase?.Close();
|
_pwDatabase?.Close();
|
||||||
|
@@ -5,20 +5,69 @@ using System.Runtime.InteropServices.WindowsRuntime;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Windows.Storage.AccessCache;
|
using Windows.Storage.AccessCache;
|
||||||
|
using Windows.Storage.Pickers;
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Domain.Dtos;
|
||||||
|
|
||||||
namespace ModernKeePass.Infrastructure.UWP
|
namespace ModernKeePass.Infrastructure.UWP
|
||||||
{
|
{
|
||||||
public class StorageFileClient: IFileProxy
|
public class StorageFileClient: IFileProxy
|
||||||
{
|
{
|
||||||
public async Task<byte[]> OpenBinaryFile(string path)
|
public async Task<FileInfo> OpenFile(string name, string extension, bool addToRecent)
|
||||||
|
{
|
||||||
|
var picker = new FileOpenPicker
|
||||||
|
{
|
||||||
|
ViewMode = PickerViewMode.List,
|
||||||
|
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
|
||||||
|
};
|
||||||
|
picker.FileTypeFilter.Add(extension);
|
||||||
|
|
||||||
|
// Application now has read/write access to the picked file
|
||||||
|
var file = await picker.PickSingleFileAsync().AsTask();
|
||||||
|
if (file == null) return null;
|
||||||
|
|
||||||
|
var token = addToRecent
|
||||||
|
? StorageApplicationPermissions.MostRecentlyUsedList.Add(file, file.Path)
|
||||||
|
: StorageApplicationPermissions.FutureAccessList.Add(file, file.Name);
|
||||||
|
return new FileInfo
|
||||||
|
{
|
||||||
|
Id = token,
|
||||||
|
Name = file.Name,
|
||||||
|
Path = file.Path
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<FileInfo> CreateFile(string name, string extension, string description, bool addToRecent)
|
||||||
|
{
|
||||||
|
var savePicker = new FileSavePicker
|
||||||
|
{
|
||||||
|
SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
|
||||||
|
SuggestedFileName = name
|
||||||
|
};
|
||||||
|
savePicker.FileTypeChoices.Add(description, new List<string> { extension });
|
||||||
|
|
||||||
|
var file = await savePicker.PickSaveFileAsync().AsTask();
|
||||||
|
if (file == null) return null;
|
||||||
|
|
||||||
|
var token = addToRecent
|
||||||
|
? StorageApplicationPermissions.MostRecentlyUsedList.Add(file, file.Path)
|
||||||
|
: StorageApplicationPermissions.FutureAccessList.Add(file, file.Name);
|
||||||
|
return new FileInfo
|
||||||
|
{
|
||||||
|
Id = token,
|
||||||
|
Name = file.Name,
|
||||||
|
Path = file.Path
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<byte[]> ReadBinaryFile(string path)
|
||||||
{
|
{
|
||||||
var file = await GetFile(path);
|
var file = await GetFile(path);
|
||||||
var result = await FileIO.ReadBufferAsync(file).AsTask();
|
var result = await FileIO.ReadBufferAsync(file).AsTask();
|
||||||
return result.ToArray();
|
return result.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IList<string>> OpenTextFile(string path)
|
public async Task<IList<string>> ReadTextFile(string path)
|
||||||
{
|
{
|
||||||
var file = await GetFile(path);
|
var file = await GetFile(path);
|
||||||
var result = await FileIO.ReadLinesAsync(file).AsTask();
|
var result = await FileIO.ReadLinesAsync(file).AsTask();
|
||||||
|
@@ -1,17 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Windows.ApplicationModel;
|
using Windows.ApplicationModel;
|
||||||
using Windows.ApplicationModel.Activation;
|
using Windows.ApplicationModel.Activation;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Windows.Storage.AccessCache;
|
using Windows.Storage.AccessCache;
|
||||||
using Windows.Storage.Pickers;
|
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Navigation;
|
using Windows.UI.Xaml.Navigation;
|
||||||
|
using GalaSoft.MvvmLight.Messaging;
|
||||||
using GalaSoft.MvvmLight.Views;
|
using GalaSoft.MvvmLight.Views;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Messages;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.HockeyApp;
|
using Microsoft.HockeyApp;
|
||||||
using ModernKeePass.Application;
|
using ModernKeePass.Application;
|
||||||
@@ -41,6 +40,7 @@ namespace ModernKeePass
|
|||||||
private readonly IHockeyClient _hockey;
|
private readonly IHockeyClient _hockey;
|
||||||
private readonly IDialogService _dialog;
|
private readonly IDialogService _dialog;
|
||||||
private readonly INotificationService _notification;
|
private readonly INotificationService _notification;
|
||||||
|
private readonly IFileProxy _file;
|
||||||
|
|
||||||
public static IServiceProvider Services { get; private set; }
|
public static IServiceProvider Services { get; private set; }
|
||||||
|
|
||||||
@@ -66,57 +66,33 @@ namespace ModernKeePass
|
|||||||
_dialog = Services.GetService<IDialogService>();
|
_dialog = Services.GetService<IDialogService>();
|
||||||
_notification = Services.GetService<INotificationService>();
|
_notification = Services.GetService<INotificationService>();
|
||||||
_hockey = Services.GetService<IHockeyClient>();
|
_hockey = Services.GetService<IHockeyClient>();
|
||||||
|
_file = Services.GetService<IFileProxy>();
|
||||||
|
var messenger = Services.GetService<IMessenger>();
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Suspending += OnSuspending;
|
Suspending += OnSuspending;
|
||||||
Resuming += OnResuming;
|
Resuming += OnResuming;
|
||||||
UnhandledException += OnUnhandledException;
|
UnhandledException += OnUnhandledException;
|
||||||
|
|
||||||
|
messenger.Register<SaveErrorMessage>(this, async message => await HandelSaveError(message.Message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandelSaveError(string message)
|
||||||
|
{
|
||||||
|
_notification.Show(_resource.GetResourceValue("MessageDialogSaveErrorTitle"), message);
|
||||||
|
var database = await _mediator.Send(new GetDatabaseQuery());
|
||||||
|
var file = await _file.CreateFile($"{database.Name} - copy",
|
||||||
|
Domain.Common.Constants.Extensions.Kdbx,
|
||||||
|
_resource.GetResourceValue("MessageDialogSaveErrorFileTypeDesc"), true);
|
||||||
|
if (file != null) await _mediator.Send(new SaveDatabaseCommand { FilePath = file.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Event Handlers
|
#region Event Handlers
|
||||||
|
|
||||||
private async void OnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
|
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
// Save the argument exception because it's cleared on first access
|
_hockey.TrackException(e.Exception);
|
||||||
var exception = unhandledExceptionEventArgs.Exception;
|
_hockey.Flush();
|
||||||
var realException =
|
|
||||||
exception is TargetInvocationException &&
|
|
||||||
exception.InnerException != null
|
|
||||||
? exception.InnerException
|
|
||||||
: exception;
|
|
||||||
|
|
||||||
_hockey.TrackException(realException);
|
|
||||||
if (realException is SaveException)
|
|
||||||
{
|
|
||||||
// TODO: this is not working
|
|
||||||
unhandledExceptionEventArgs.Handled = true;
|
|
||||||
await _dialog.ShowMessage(realException.Message,
|
|
||||||
_resource.GetResourceValue("MessageDialogSaveErrorTitle"),
|
|
||||||
_resource.GetResourceValue("MessageDialogSaveErrorButtonSaveAs"),
|
|
||||||
_resource.GetResourceValue("MessageDialogSaveErrorButtonDiscard"),
|
|
||||||
async isOk =>
|
|
||||||
{
|
|
||||||
if (isOk)
|
|
||||||
{
|
|
||||||
var database = await _mediator.Send(new GetDatabaseQuery());
|
|
||||||
var savePicker = new FileSavePicker
|
|
||||||
{
|
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
|
|
||||||
SuggestedFileName = $"{database.Name} - copy"
|
|
||||||
};
|
|
||||||
savePicker.FileTypeChoices.Add(
|
|
||||||
_resource.GetResourceValue("MessageDialogSaveErrorFileTypeDesc"),
|
|
||||||
new List<string> {".kdbx"});
|
|
||||||
|
|
||||||
var file = await savePicker.PickSaveFileAsync();
|
|
||||||
if (file != null)
|
|
||||||
{
|
|
||||||
var token = StorageApplicationPermissions.FutureAccessList.Add(file, file.Name);
|
|
||||||
await _mediator.Send(new SaveDatabaseCommand {FilePath = token});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using GalaSoft.MvvmLight.Messaging;
|
||||||
using GalaSoft.MvvmLight.Views;
|
using GalaSoft.MvvmLight.Views;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.HockeyApp;
|
using Microsoft.HockeyApp;
|
||||||
@@ -24,6 +25,7 @@ namespace ModernKeePass
|
|||||||
nav.Configure(Constants.Navigation.GroupPage, typeof(GroupDetailPage));
|
nav.Configure(Constants.Navigation.GroupPage, typeof(GroupDetailPage));
|
||||||
return nav;
|
return nav;
|
||||||
});
|
});
|
||||||
|
services.AddSingleton(provider => Messenger.Default);
|
||||||
services.AddTransient(typeof(IDialogService), typeof(DialogService));
|
services.AddTransient(typeof(IDialogService), typeof(DialogService));
|
||||||
|
|
||||||
services.AddSingleton(provider =>
|
services.AddSingleton(provider =>
|
||||||
|
@@ -83,4 +83,7 @@
|
|||||||
<SolidColorBrush x:Key="SliderTrackDecreaseBackgroundThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="SliderTrackDecreaseBackgroundThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
<SolidColorBrush x:Key="SliderTrackDecreasePressedBackgroundThemeBrush" Color="{ThemeResource MainColorDark}" />
|
<SolidColorBrush x:Key="SliderTrackDecreasePressedBackgroundThemeBrush" Color="{ThemeResource MainColorDark}" />
|
||||||
<SolidColorBrush x:Key="SliderTrackDecreasePointerOverBackgroundThemeBrush" Color="{ThemeResource MainColorLight}" />
|
<SolidColorBrush x:Key="SliderTrackDecreasePointerOverBackgroundThemeBrush" Color="{ThemeResource MainColorLight}" />
|
||||||
|
|
||||||
|
<Thickness x:Key="FlyoutBorderThemeThickness">0</Thickness>
|
||||||
|
<Thickness x:Key="MenuFlyoutPresenterThemePadding">0</Thickness>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
@@ -9,6 +9,7 @@ using GalaSoft.MvvmLight;
|
|||||||
using GalaSoft.MvvmLight.Command;
|
using GalaSoft.MvvmLight.Command;
|
||||||
using GalaSoft.MvvmLight.Views;
|
using GalaSoft.MvvmLight.Views;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Messages;
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||||
using ModernKeePass.Application.Database.Models;
|
using ModernKeePass.Application.Database.Models;
|
||||||
@@ -28,12 +29,13 @@ using ModernKeePass.Application.Security.Queries.EstimatePasswordComplexity;
|
|||||||
using ModernKeePass.Domain.Enums;
|
using ModernKeePass.Domain.Enums;
|
||||||
using ModernKeePass.Application.Group.Models;
|
using ModernKeePass.Application.Group.Models;
|
||||||
using ModernKeePass.Common;
|
using ModernKeePass.Common;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
using ModernKeePass.Extensions;
|
using ModernKeePass.Extensions;
|
||||||
using ModernKeePass.Models;
|
using ModernKeePass.Models;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
public class EntryDetailVm : ObservableObject
|
public class EntryDetailVm : ViewModelBase
|
||||||
{
|
{
|
||||||
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
|
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
|
||||||
public bool HasExpired => HasExpirationDate && ExpiryDate < DateTime.Now;
|
public bool HasExpired => HasExpirationDate && ExpiryDate < DateTime.Now;
|
||||||
@@ -362,7 +364,14 @@ namespace ModernKeePass.ViewModels
|
|||||||
private async Task SaveChanges()
|
private async Task SaveChanges()
|
||||||
{
|
{
|
||||||
await AddHistory();
|
await AddHistory();
|
||||||
|
try
|
||||||
|
{
|
||||||
await _mediator.Send(new SaveDatabaseCommand());
|
await _mediator.Send(new SaveDatabaseCommand());
|
||||||
|
}
|
||||||
|
catch (SaveException e)
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new SaveErrorMessage { Message = e.Message });
|
||||||
|
}
|
||||||
SaveCommand.RaiseCanExecuteChanged();
|
SaveCommand.RaiseCanExecuteChanged();
|
||||||
_isDirty = false;
|
_isDirty = false;
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ using GalaSoft.MvvmLight;
|
|||||||
using GalaSoft.MvvmLight.Command;
|
using GalaSoft.MvvmLight.Command;
|
||||||
using GalaSoft.MvvmLight.Views;
|
using GalaSoft.MvvmLight.Views;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Messages;
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||||
using ModernKeePass.Application.Database.Models;
|
using ModernKeePass.Application.Database.Models;
|
||||||
@@ -29,11 +30,12 @@ using ModernKeePass.Application.Group.Queries.GetGroup;
|
|||||||
using ModernKeePass.Application.Group.Queries.SearchEntries;
|
using ModernKeePass.Application.Group.Queries.SearchEntries;
|
||||||
using ModernKeePass.Common;
|
using ModernKeePass.Common;
|
||||||
using ModernKeePass.Domain.Enums;
|
using ModernKeePass.Domain.Enums;
|
||||||
|
using ModernKeePass.Domain.Exceptions;
|
||||||
using ModernKeePass.Models;
|
using ModernKeePass.Models;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
public class GroupDetailVm : ObservableObject
|
public class GroupDetailVm : ViewModelBase
|
||||||
{
|
{
|
||||||
public ObservableCollection<EntryVm> Entries { get; private set; }
|
public ObservableCollection<EntryVm> Entries { get; private set; }
|
||||||
|
|
||||||
@@ -181,8 +183,15 @@ namespace ModernKeePass.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveChanges()
|
private async Task SaveChanges()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await _mediator.Send(new SaveDatabaseCommand());
|
await _mediator.Send(new SaveDatabaseCommand());
|
||||||
|
}
|
||||||
|
catch (SaveException e)
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new SaveErrorMessage { Message = e.Message });
|
||||||
|
}
|
||||||
SaveCommand.RaiseCanExecuteChanged();
|
SaveCommand.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -183,6 +183,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
}
|
}
|
||||||
catch (SaveException exception)
|
catch (SaveException exception)
|
||||||
{
|
{
|
||||||
|
// TODO: Implement save as
|
||||||
_notification.Show(exception.Source, exception.Message);
|
_notification.Show(exception.Source, exception.Message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
|
|
||||||
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<HyperlinkButton x:Uid="NewCreateButton" Click="CreateDatabaseButton_OnClick" />
|
<HyperlinkButton x:Uid="NewCreateButton" Command="{Binding CreateDatabaseFileCommand}" />
|
||||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" x:Uid="NewCreateDesc" />
|
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" x:Uid="NewCreateDesc" />
|
||||||
<Border HorizontalAlignment="Left" BorderThickness="1" BorderBrush="AliceBlue" Width="550" Visibility="{Binding IsFileSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<Border HorizontalAlignment="Left" BorderThickness="1" BorderBrush="AliceBlue" Width="550" Visibility="{Binding IsFileSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<StackPanel Margin="25,0,25,0">
|
<StackPanel Margin="25,0,25,0">
|
||||||
|
@@ -1,11 +1,4 @@
|
|||||||
using System;
|
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
||||||
using System.Collections.Generic;
|
|
||||||
using Windows.Storage.AccessCache;
|
|
||||||
using Windows.Storage.Pickers;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using ModernKeePass.ViewModels;
|
|
||||||
|
|
||||||
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
|
||||||
|
|
||||||
namespace ModernKeePass.Views
|
namespace ModernKeePass.Views
|
||||||
{
|
{
|
||||||
@@ -14,28 +7,9 @@ namespace ModernKeePass.Views
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class NewDatabasePage
|
public sealed partial class NewDatabasePage
|
||||||
{
|
{
|
||||||
private NewVm Model => (NewVm)DataContext;
|
|
||||||
|
|
||||||
public NewDatabasePage()
|
public NewDatabasePage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void CreateDatabaseButton_OnClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var savePicker = new FileSavePicker
|
|
||||||
{
|
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
|
|
||||||
SuggestedFileName = "New Database"
|
|
||||||
};
|
|
||||||
savePicker.FileTypeChoices.Add("KeePass 2.x database", new List<string> {".kdbx"});
|
|
||||||
|
|
||||||
var file = await savePicker.PickSaveFileAsync().AsTask();
|
|
||||||
if (file == null) return;
|
|
||||||
|
|
||||||
Model.Token = StorageApplicationPermissions.FutureAccessList.Add(file, file.Name);
|
|
||||||
Model.Name = file.Name;
|
|
||||||
Model.Path = file.Path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
|
|
||||||
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<HyperlinkButton x:Uid="OpenBrowseButton" Click="ButtonBase_OnClick" />
|
<HyperlinkButton x:Uid="OpenBrowseButton" Command="{Binding OpenDatabaseFileCommand}" />
|
||||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" x:Uid="OpenBrowseDesc" />
|
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" x:Uid="OpenBrowseDesc" />
|
||||||
<!--<HyperlinkButton x:Uid="OpenUrlButton" IsEnabled="False" Foreground="{StaticResource MainColor}" Style="{StaticResource MainColorHyperlinkButton}" />
|
<!--<HyperlinkButton x:Uid="OpenUrlButton" IsEnabled="False" Foreground="{StaticResource MainColor}" Style="{StaticResource MainColorHyperlinkButton}" />
|
||||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" x:Uid="OpenUrlDesc" />-->
|
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" x:Uid="OpenUrlDesc" />-->
|
||||||
|
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using Windows.UI.Xaml.Navigation;
|
||||||
using Windows.Storage.AccessCache;
|
|
||||||
using Windows.Storage.Pickers;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Navigation;
|
|
||||||
using ModernKeePass.Domain.Dtos;
|
using ModernKeePass.Domain.Dtos;
|
||||||
using ModernKeePass.ViewModels;
|
using ModernKeePass.ViewModels;
|
||||||
|
|
||||||
@@ -26,31 +22,7 @@ namespace ModernKeePass.Views
|
|||||||
{
|
{
|
||||||
base.OnNavigatedTo(e);
|
base.OnNavigatedTo(e);
|
||||||
var file = e.Parameter as FileInfo;
|
var file = e.Parameter as FileInfo;
|
||||||
if (file != null)
|
Model.SetFileInformation(file);
|
||||||
{
|
|
||||||
Model.Path = file.Path;
|
|
||||||
Model.Name = file.Name;
|
|
||||||
Model.Token = file.Id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var picker = new FileOpenPicker
|
|
||||||
{
|
|
||||||
ViewMode = PickerViewMode.List,
|
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
|
|
||||||
};
|
|
||||||
picker.FileTypeFilter.Add(".kdbx");
|
|
||||||
|
|
||||||
// Application now has read/write access to the picked file
|
|
||||||
var file = await picker.PickSingleFileAsync().AsTask();
|
|
||||||
if (file == null) return;
|
|
||||||
|
|
||||||
// TODO: use service
|
|
||||||
Model.Token = StorageApplicationPermissions.MostRecentlyUsedList.Add(file, file.Path);
|
|
||||||
Model.Path = file.Path;
|
|
||||||
Model.Name = file.Name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
// Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238
|
// Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238
|
||||||
|
|
||||||
using ModernKeePass.ViewModels;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Views
|
namespace ModernKeePass.Views
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<HyperlinkButton x:Uid="SaveButton" Command="{Binding SaveCommand}" />
|
<HyperlinkButton x:Uid="SaveButton" Command="{Binding SaveCommand}" />
|
||||||
<TextBlock x:Uid="SaveDesc" Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" />
|
<TextBlock x:Uid="SaveDesc" Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" />
|
||||||
<HyperlinkButton x:Uid="SaveAsButton" Click="SaveAsButton_OnClick" />
|
<HyperlinkButton x:Uid="SaveAsButton" Command="{Binding SaveAsCommand}" />
|
||||||
<TextBlock x:Uid="SaveAsDesc" Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" />
|
<TextBlock x:Uid="SaveAsDesc" Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" />
|
||||||
<HyperlinkButton x:Uid="CloseButton" Command="{Binding CloseCommand}" />
|
<HyperlinkButton x:Uid="CloseButton" Command="{Binding CloseCommand}" />
|
||||||
<TextBlock x:Uid="CloseDesc" Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" />
|
<TextBlock x:Uid="CloseDesc" Style="{StaticResource BodyTextBlockStyle}" Margin="15,0,0,30" />
|
||||||
|
@@ -1,10 +1,4 @@
|
|||||||
using System;
|
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
||||||
using System.Collections.Generic;
|
|
||||||
using Windows.Storage.Pickers;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using ModernKeePass.ViewModels;
|
|
||||||
|
|
||||||
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
|
||||||
|
|
||||||
namespace ModernKeePass.Views
|
namespace ModernKeePass.Views
|
||||||
{
|
{
|
||||||
@@ -13,24 +7,9 @@ namespace ModernKeePass.Views
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class SaveDatabasePage
|
public sealed partial class SaveDatabasePage
|
||||||
{
|
{
|
||||||
public SaveVm Model => (SaveVm)DataContext;
|
|
||||||
public SaveDatabasePage()
|
public SaveDatabasePage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SaveAsButton_OnClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var savePicker = new FileSavePicker
|
|
||||||
{
|
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
|
|
||||||
SuggestedFileName = "New Database"
|
|
||||||
};
|
|
||||||
savePicker.FileTypeChoices.Add("KeePass 2.x database", new List<string> { ".kdbx" });
|
|
||||||
|
|
||||||
var file = await savePicker.PickSaveFileAsync().AsTask();
|
|
||||||
if (file == null) return;
|
|
||||||
await Model.Save(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
<HyperlinkButton Grid.Row="1" Grid.Column="1" Margin="-15,0,0,0"
|
<HyperlinkButton Grid.Row="1" Grid.Column="1" Margin="-15,0,0,0"
|
||||||
x:Name="HyperlinkButton"
|
x:Name="HyperlinkButton"
|
||||||
Content="{Binding KeyFileText}"
|
Content="{Binding KeyFileText}"
|
||||||
Click="KeyFileButton_Click" />
|
Command="{Binding OpenKeyFileCommand}" />
|
||||||
|
|
||||||
<Button Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2"
|
<Button Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2"
|
||||||
x:Uid="OpenDatabaseControlButton"
|
x:Uid="OpenDatabaseControlButton"
|
||||||
|
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
using Windows.System;
|
||||||
using Windows.Storage.AccessCache;
|
|
||||||
using Windows.Storage.Pickers;
|
|
||||||
using Windows.System;
|
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Input;
|
using Windows.UI.Xaml.Input;
|
||||||
using ModernKeePass.ViewModels;
|
using ModernKeePass.ViewModels;
|
||||||
@@ -38,24 +35,5 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
// Stop the event from triggering twice
|
// Stop the event from triggering twice
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void KeyFileButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var picker = new FileOpenPicker
|
|
||||||
{
|
|
||||||
ViewMode = PickerViewMode.List,
|
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
|
|
||||||
};
|
|
||||||
picker.FileTypeFilter.Add("*");
|
|
||||||
|
|
||||||
// Application now has read/write access to the picked file
|
|
||||||
var file = await picker.PickSingleFileAsync();
|
|
||||||
if (file == null) return;
|
|
||||||
|
|
||||||
var token = StorageApplicationPermissions.FutureAccessList.Add(file, file.Name);
|
|
||||||
Model.KeyFilePath = token;
|
|
||||||
Model.KeyFileText = file.Name;
|
|
||||||
Model.HasKeyFile = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
<converters:DoubleToSolidColorBrushConverter x:Key="DoubleToSolidColorBrushConverter"/>
|
<converters:DoubleToSolidColorBrushConverter x:Key="DoubleToSolidColorBrushConverter"/>
|
||||||
<converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter"/>
|
<converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter"/>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid x:Name="Grid" DataContext="{Binding Source={StaticResource Locator}, Path=SetCredentials}">
|
<Grid DataContext="{Binding Source={StaticResource Locator}, Path=SetCredentials}">
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<SolidColorBrush x:Key="ErrorBrush" Color="Red" />
|
<SolidColorBrush x:Key="ErrorBrush" Color="Red" />
|
||||||
<SolidColorBrush x:Key="ValidBrush" Color="Green" />
|
<SolidColorBrush x:Key="ValidBrush" Color="Green" />
|
||||||
@@ -57,11 +57,9 @@
|
|||||||
<HyperlinkButton Grid.Row="3" Grid.Column="1" Margin="-15,0,0,0"
|
<HyperlinkButton Grid.Row="3" Grid.Column="1" Margin="-15,0,0,0"
|
||||||
x:Name="HyperlinkButton"
|
x:Name="HyperlinkButton"
|
||||||
Content="{Binding KeyFileText}"
|
Content="{Binding KeyFileText}"
|
||||||
IsEnabled="{Binding HasKeyFile}"
|
Command="{Binding OpenKeyFileCommand}" />
|
||||||
Click="KeyFileButton_Click" />
|
|
||||||
<HyperlinkButton Grid.Row="3" Grid.Column="1" HorizontalAlignment="Right"
|
<HyperlinkButton Grid.Row="3" Grid.Column="1" HorizontalAlignment="Right"
|
||||||
IsEnabled="{Binding HasKeyFile}"
|
Command="{Binding CreateKeyFileCommand}">
|
||||||
Click="CreateKeyFileButton_Click">
|
|
||||||
<SymbolIcon Symbol="Add">
|
<SymbolIcon Symbol="Add">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<ToolTip x:Uid="CompositeKeyNewKeyFileTooltip" />
|
<ToolTip x:Uid="CompositeKeyNewKeyFileTooltip" />
|
||||||
|
@@ -1,9 +1,4 @@
|
|||||||
using System;
|
using Windows.UI.Xaml;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Windows.Storage.AccessCache;
|
|
||||||
using Windows.Storage.Pickers;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using ModernKeePass.ViewModels;
|
|
||||||
|
|
||||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||||
|
|
||||||
@@ -11,8 +6,6 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
{
|
{
|
||||||
public sealed partial class SetCredentialsUserControl
|
public sealed partial class SetCredentialsUserControl
|
||||||
{
|
{
|
||||||
private SetCredentialsVm Model => (SetCredentialsVm)Grid.DataContext;
|
|
||||||
|
|
||||||
public string ButtonLabel
|
public string ButtonLabel
|
||||||
{
|
{
|
||||||
get { return (string)GetValue(ButtonLabelProperty); }
|
get { return (string)GetValue(ButtonLabelProperty); }
|
||||||
@@ -29,40 +22,5 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void KeyFileButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var picker =
|
|
||||||
new FileOpenPicker
|
|
||||||
{
|
|
||||||
ViewMode = PickerViewMode.List,
|
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
|
|
||||||
};
|
|
||||||
picker.FileTypeFilter.Add("*");
|
|
||||||
|
|
||||||
// Application now has read/write access to the picked file
|
|
||||||
var file = await picker.PickSingleFileAsync();
|
|
||||||
if (file == null) return;
|
|
||||||
|
|
||||||
Model.KeyFilePath = StorageApplicationPermissions.FutureAccessList.Add(file, file.Name);
|
|
||||||
Model.KeyFileText = file.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void CreateKeyFileButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var savePicker = new FileSavePicker
|
|
||||||
{
|
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
|
|
||||||
SuggestedFileName = "Key"
|
|
||||||
};
|
|
||||||
savePicker.FileTypeChoices.Add("Key file", new List<string> { ".key" });
|
|
||||||
|
|
||||||
var file = await savePicker.PickSaveFileAsync();
|
|
||||||
if (file == null) return;
|
|
||||||
|
|
||||||
Model.KeyFilePath = StorageApplicationPermissions.FutureAccessList.Add(file, file.Name);
|
|
||||||
Model.KeyFileText = file.Name;
|
|
||||||
await Model.GenerateKeyFile();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GalaSoft.MvvmLight.Command;
|
||||||
using GalaSoft.MvvmLight.Views;
|
using GalaSoft.MvvmLight.Views;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Messages;
|
using Messages;
|
||||||
@@ -15,16 +16,31 @@ namespace ModernKeePass.ViewModels
|
|||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly ISettingsProxy _settings;
|
private readonly ISettingsProxy _settings;
|
||||||
private readonly INavigationService _navigation;
|
private readonly INavigationService _navigation;
|
||||||
|
private readonly IFileProxy _file;
|
||||||
|
|
||||||
public NewVm(IMediator mediator, IRecentProxy recent, ISettingsProxy settings, INavigationService navigation)
|
public RelayCommand CreateDatabaseFileCommand { get; }
|
||||||
|
|
||||||
|
public NewVm(IMediator mediator, ISettingsProxy settings, INavigationService navigation, IFileProxy file): base(file)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_navigation = navigation;
|
_navigation = navigation;
|
||||||
|
_file = file;
|
||||||
|
|
||||||
|
CreateDatabaseFileCommand = new RelayCommand(async () => await CreateDatabaseFile());
|
||||||
|
|
||||||
MessengerInstance.Register<CredentialsSetMessage>(this, async m => await TryCreateDatabase(m));
|
MessengerInstance.Register<CredentialsSetMessage>(this, async m => await TryCreateDatabase(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CreateDatabaseFile()
|
||||||
|
{
|
||||||
|
// TODO: get these from resource
|
||||||
|
var file = await _file.CreateFile("New Database", Domain.Common.Constants.Extensions.Kdbx, "KeePass 2.x database", true);
|
||||||
|
Token = file.Id;
|
||||||
|
Path = file.Path;
|
||||||
|
Name = file.Name;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task TryCreateDatabase(CredentialsSetMessage message)
|
private async Task TryCreateDatabase(CredentialsSetMessage message)
|
||||||
{
|
{
|
||||||
var database = await _mediator.Send(new GetDatabaseQuery());
|
var database = await _mediator.Send(new GetDatabaseQuery());
|
||||||
@@ -45,7 +61,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
Password = message.Password,
|
Password = message.Password,
|
||||||
Name = "ModernKeePass",
|
Name = "ModernKeePass",
|
||||||
Version = _settings.GetSetting(Constants.Settings.DefaultFileFormat, "4"),
|
Version = _settings.GetSetting(Constants.Settings.DefaultFileFormat, "4"),
|
||||||
CreateSampleData = _settings.GetSetting<bool>(Constants.Settings.Sample, true)
|
CreateSampleData = _settings.GetSetting(Constants.Settings.Sample, true)
|
||||||
});
|
});
|
||||||
|
|
||||||
var database = await _mediator.Send(new GetDatabaseQuery());
|
var database = await _mediator.Send(new GetDatabaseQuery());
|
||||||
|
@@ -1,9 +1,15 @@
|
|||||||
using GalaSoft.MvvmLight;
|
using System.Threading.Tasks;
|
||||||
|
using GalaSoft.MvvmLight;
|
||||||
|
using GalaSoft.MvvmLight.Command;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Domain.Common;
|
||||||
|
using ModernKeePass.Domain.Dtos;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
public class OpenVm: ViewModelBase
|
public class OpenVm: ViewModelBase
|
||||||
{
|
{
|
||||||
|
private readonly IFileProxy _file;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _path;
|
private string _path;
|
||||||
private string _token;
|
private string _token;
|
||||||
@@ -30,5 +36,27 @@ namespace ModernKeePass.ViewModels
|
|||||||
get { return _path; }
|
get { return _path; }
|
||||||
set { Set(() => Path, ref _path, value); }
|
set { Set(() => Path, ref _path, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RelayCommand OpenDatabaseFileCommand { get; }
|
||||||
|
|
||||||
|
public OpenVm(IFileProxy file)
|
||||||
|
{
|
||||||
|
_file = file;
|
||||||
|
OpenDatabaseFileCommand = new RelayCommand(async () => await OpenDatabaseFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetFileInformation(FileInfo file)
|
||||||
|
{
|
||||||
|
if (file == null) return;
|
||||||
|
Token = file.Id;
|
||||||
|
Path = file.Path;
|
||||||
|
Name = file.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OpenDatabaseFile()
|
||||||
|
{
|
||||||
|
var file = await _file.OpenFile(string.Empty, Constants.Extensions.Kdbx, true);
|
||||||
|
SetFileInformation(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,46 +1,61 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Windows.Storage;
|
using GalaSoft.MvvmLight;
|
||||||
using Windows.Storage.AccessCache;
|
using GalaSoft.MvvmLight.Command;
|
||||||
using GalaSoft.MvvmLight.Views;
|
using GalaSoft.MvvmLight.Views;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Messages;
|
||||||
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Application.Database.Commands.CloseDatabase;
|
using ModernKeePass.Application.Database.Commands.CloseDatabase;
|
||||||
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
using ModernKeePass.Application.Database.Commands.SaveDatabase;
|
||||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
using ModernKeePass.Common;
|
using ModernKeePass.Common;
|
||||||
using RelayCommand = GalaSoft.MvvmLight.Command.RelayCommand;
|
using ModernKeePass.Domain.Exceptions;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
public class SaveVm
|
public class SaveVm: ViewModelBase
|
||||||
{
|
{
|
||||||
public bool IsSaveEnabled => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult().IsDirty;
|
public bool IsSaveEnabled => _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult().IsDirty;
|
||||||
|
|
||||||
|
public RelayCommand SaveAsCommand { get; }
|
||||||
public RelayCommand SaveCommand { get; }
|
public RelayCommand SaveCommand { get; }
|
||||||
public RelayCommand CloseCommand { get; }
|
public RelayCommand CloseCommand { get; }
|
||||||
|
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly INavigationService _navigation;
|
private readonly INavigationService _navigation;
|
||||||
|
private readonly IFileProxy _file;
|
||||||
|
|
||||||
public SaveVm(IMediator mediator, INavigationService navigation)
|
public SaveVm(IMediator mediator, INavigationService navigation, IFileProxy file)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_navigation = navigation;
|
_navigation = navigation;
|
||||||
|
_file = file;
|
||||||
|
|
||||||
|
SaveAsCommand = new RelayCommand(async () => await SaveAs());
|
||||||
SaveCommand = new RelayCommand(async () => await Save(), () => IsSaveEnabled);
|
SaveCommand = new RelayCommand(async () => await Save(), () => IsSaveEnabled);
|
||||||
CloseCommand = new RelayCommand(async () => await Close());
|
CloseCommand = new RelayCommand(async () => await Close());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Save(bool close = true)
|
private async Task SaveAs()
|
||||||
{
|
{
|
||||||
await _mediator.Send(new SaveDatabaseCommand());
|
// TODO: get these from resource
|
||||||
if (close) await _mediator.Send(new CloseDatabaseCommand());
|
var file = await _file.CreateFile("New Database", Domain.Common.Constants.Extensions.Kdbx, "KeePass 2.x database", true);
|
||||||
|
|
||||||
|
await _mediator.Send(new SaveDatabaseCommand { FilePath = file.Id });
|
||||||
_navigation.NavigateTo(Constants.Navigation.MainPage);
|
_navigation.NavigateTo(Constants.Navigation.MainPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Save(StorageFile file)
|
public async Task Save()
|
||||||
{
|
{
|
||||||
var token = StorageApplicationPermissions.FutureAccessList.Add(file, file.Name);
|
try
|
||||||
await _mediator.Send(new SaveDatabaseCommand { FilePath = token });
|
{
|
||||||
_navigation.NavigateTo(Constants.Navigation.MainPage);
|
await _mediator.Send(new SaveDatabaseCommand());
|
||||||
|
await Close();
|
||||||
|
}
|
||||||
|
catch (SaveException e)
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new SaveErrorMessage { Message = e.Message });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Close()
|
public async Task Close()
|
||||||
|
@@ -9,6 +9,7 @@ using Messages;
|
|||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
using ModernKeePass.Application.Database.Queries.OpenDatabase;
|
using ModernKeePass.Application.Database.Queries.OpenDatabase;
|
||||||
|
using ModernKeePass.Domain.Common;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
@@ -85,11 +86,13 @@ namespace ModernKeePass.ViewModels
|
|||||||
|
|
||||||
public bool IsValid => !IsOpening && (HasPassword || HasKeyFile && !string.IsNullOrEmpty(KeyFilePath));
|
public bool IsValid => !IsOpening && (HasPassword || HasKeyFile && !string.IsNullOrEmpty(KeyFilePath));
|
||||||
|
|
||||||
|
public RelayCommand OpenKeyFileCommand { get; }
|
||||||
public RelayCommand<string> OpenDatabaseCommand { get; }
|
public RelayCommand<string> OpenDatabaseCommand { get; }
|
||||||
|
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly IResourceProxy _resource;
|
private readonly IResourceProxy _resource;
|
||||||
private readonly INotificationService _notification;
|
private readonly INotificationService _notification;
|
||||||
|
private readonly IFileProxy _file;
|
||||||
private bool _hasPassword;
|
private bool _hasPassword;
|
||||||
private bool _hasKeyFile;
|
private bool _hasKeyFile;
|
||||||
private bool _isOpening;
|
private bool _isOpening;
|
||||||
@@ -99,15 +102,26 @@ namespace ModernKeePass.ViewModels
|
|||||||
private string _keyFileText;
|
private string _keyFileText;
|
||||||
private bool _isError;
|
private bool _isError;
|
||||||
|
|
||||||
public OpenDatabaseControlVm(IMediator mediator, IResourceProxy resource, INotificationService notification)
|
public OpenDatabaseControlVm(IMediator mediator, IResourceProxy resource, INotificationService notification, IFileProxy file)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_resource = resource;
|
_resource = resource;
|
||||||
_notification = notification;
|
_notification = notification;
|
||||||
|
_file = file;
|
||||||
|
OpenKeyFileCommand = new RelayCommand(async () => await OpenKeyFile());
|
||||||
OpenDatabaseCommand = new RelayCommand<string>(async databaseFilePath => await TryOpenDatabase(databaseFilePath), _ => IsValid);
|
OpenDatabaseCommand = new RelayCommand<string>(async databaseFilePath => await TryOpenDatabase(databaseFilePath), _ => IsValid);
|
||||||
_keyFileText = _resource.GetResourceValue("CompositeKeyDefaultKeyFile");
|
_keyFileText = _resource.GetResourceValue("CompositeKeyDefaultKeyFile");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task OpenKeyFile()
|
||||||
|
{
|
||||||
|
var file = await _file.OpenFile(string.Empty, Constants.Extensions.Any, false);
|
||||||
|
if (file == null) return;
|
||||||
|
KeyFilePath = file.Id;
|
||||||
|
KeyFileText = file.Name;
|
||||||
|
HasKeyFile = true;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task TryOpenDatabase(string databaseFilePath)
|
public async Task TryOpenDatabase(string databaseFilePath)
|
||||||
{
|
{
|
||||||
MessengerInstance.Send(new DatabaseOpeningMessage {Token = databaseFilePath});
|
MessengerInstance.Send(new DatabaseOpeningMessage {Token = databaseFilePath});
|
||||||
|
@@ -5,6 +5,8 @@ using MediatR;
|
|||||||
using Messages;
|
using Messages;
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Application.Security.Commands.GenerateKeyFile;
|
using ModernKeePass.Application.Security.Commands.GenerateKeyFile;
|
||||||
|
using ModernKeePass.Domain.Common;
|
||||||
|
using ModernKeePass.Domain.Dtos;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
@@ -12,6 +14,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly ICredentialsProxy _credentials;
|
private readonly ICredentialsProxy _credentials;
|
||||||
|
private readonly IFileProxy _file;
|
||||||
|
|
||||||
public bool HasPassword
|
public bool HasPassword
|
||||||
{
|
{
|
||||||
@@ -33,6 +36,8 @@ namespace ModernKeePass.ViewModels
|
|||||||
Set(() => HasKeyFile, ref _hasKeyFile, value);
|
Set(() => HasKeyFile, ref _hasKeyFile, value);
|
||||||
RaisePropertyChanged(nameof(IsKeyFileValid));
|
RaisePropertyChanged(nameof(IsKeyFileValid));
|
||||||
RaisePropertyChanged(nameof(IsValid));
|
RaisePropertyChanged(nameof(IsValid));
|
||||||
|
OpenKeyFileCommand.RaiseCanExecuteChanged();
|
||||||
|
CreateKeyFileCommand.RaiseCanExecuteChanged();
|
||||||
GenerateCredentialsCommand.RaiseCanExecuteChanged();
|
GenerateCredentialsCommand.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,6 +90,8 @@ namespace ModernKeePass.ViewModels
|
|||||||
public bool IsKeyFileValid => HasKeyFile && !string.IsNullOrEmpty(KeyFilePath) || !HasKeyFile;
|
public bool IsKeyFileValid => HasKeyFile && !string.IsNullOrEmpty(KeyFilePath) || !HasKeyFile;
|
||||||
public bool IsValid => HasPassword && Password == ConfirmPassword || HasKeyFile && !string.IsNullOrEmpty(KeyFilePath) && (HasPassword || HasKeyFile);
|
public bool IsValid => HasPassword && Password == ConfirmPassword || HasKeyFile && !string.IsNullOrEmpty(KeyFilePath) && (HasPassword || HasKeyFile);
|
||||||
|
|
||||||
|
public RelayCommand OpenKeyFileCommand { get; }
|
||||||
|
public RelayCommand CreateKeyFileCommand { get; }
|
||||||
public RelayCommand GenerateCredentialsCommand{ get; }
|
public RelayCommand GenerateCredentialsCommand{ get; }
|
||||||
|
|
||||||
private bool _hasPassword;
|
private bool _hasPassword;
|
||||||
@@ -94,18 +101,39 @@ namespace ModernKeePass.ViewModels
|
|||||||
private string _keyFilePath;
|
private string _keyFilePath;
|
||||||
private string _keyFileText;
|
private string _keyFileText;
|
||||||
|
|
||||||
public SetCredentialsVm(IMediator mediator, ICredentialsProxy credentials, IResourceProxy resource)
|
public SetCredentialsVm(IMediator mediator, ICredentialsProxy credentials, IResourceProxy resource, IFileProxy file)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_credentials = credentials;
|
_credentials = credentials;
|
||||||
|
_file = file;
|
||||||
|
|
||||||
|
OpenKeyFileCommand = new RelayCommand(async () => await OpenKeyFile(), () => HasKeyFile);
|
||||||
|
CreateKeyFileCommand = new RelayCommand(async () => await CreateKeyFile(), () => HasKeyFile);
|
||||||
GenerateCredentialsCommand = new RelayCommand(GenerateCredentials, () => IsValid);
|
GenerateCredentialsCommand = new RelayCommand(GenerateCredentials, () => IsValid);
|
||||||
|
|
||||||
_keyFileText = resource.GetResourceValue("CompositeKeyDefaultKeyFile");
|
_keyFileText = resource.GetResourceValue("CompositeKeyDefaultKeyFile");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GenerateKeyFile()
|
private async Task OpenKeyFile()
|
||||||
{
|
{
|
||||||
await _mediator.Send(new GenerateKeyFileCommand {KeyFilePath = KeyFilePath});
|
var file = await _file.OpenFile(string.Empty, Constants.Extensions.Any, false);
|
||||||
|
SetKeyFileInfo(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CreateKeyFile()
|
||||||
|
{
|
||||||
|
var file = await _file.CreateFile("Key", Constants.Extensions.Any, "Key file", false);
|
||||||
|
SetKeyFileInfo(file);
|
||||||
|
|
||||||
|
await _mediator.Send(new GenerateKeyFileCommand { KeyFilePath = KeyFilePath });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetKeyFileInfo(FileInfo file)
|
||||||
|
{
|
||||||
|
if (file == null) return;
|
||||||
|
KeyFilePath = file.Id;
|
||||||
|
KeyFileText = file.Name;
|
||||||
|
HasKeyFile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateCredentials()
|
private void GenerateCredentials()
|
||||||
|
@@ -50,6 +50,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<IRecentProxy>());
|
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<IRecentProxy>());
|
||||||
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<IResourceProxy>());
|
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<IResourceProxy>());
|
||||||
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<ISettingsProxy>());
|
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<ISettingsProxy>());
|
||||||
|
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<IFileProxy>());
|
||||||
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<ICredentialsProxy>());
|
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<ICredentialsProxy>());
|
||||||
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<IDialogService>());
|
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<IDialogService>());
|
||||||
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<INavigationService>());
|
SimpleIoc.Default.Register(() => App.Services.GetRequiredService<INavigationService>());
|
||||||
|
Reference in New Issue
Block a user