mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-04 08:00:16 -04:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1488c3244f | ||
![]() |
2e22a2bd92 | ||
![]() |
8fb468358e | ||
![]() |
5ce0262318 | ||
![]() |
2f30389f6c | ||
![]() |
b3c7683c12 | ||
![]() |
1e7662def7 | ||
![]() |
97b10baedc | ||
![]() |
654bd6b4e5 |
@@ -25,9 +25,8 @@ namespace ModernKeePass.Application.Common.Interfaces
|
|||||||
|
|
||||||
Task Open(byte[] file, Credentials credentials);
|
Task Open(byte[] file, Credentials credentials);
|
||||||
Task ReOpen(byte[] file);
|
Task ReOpen(byte[] file);
|
||||||
Task Create(Credentials credentials, string name, DatabaseVersion version = DatabaseVersion.V3);
|
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);
|
||||||
}
|
}
|
||||||
|
@@ -18,10 +18,6 @@ namespace ModernKeePass.Application.Database.Commands.CloseDatabase
|
|||||||
{
|
{
|
||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
_database.CloseDatabase();
|
_database.CloseDatabase();
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
_database.FileAccessToken = null;
|
|
||||||
_database.Size = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,10 +43,10 @@ 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;
|
||||||
|
|
||||||
if (message.CreateSampleData)
|
if (message.CreateSampleData)
|
||||||
|
@@ -27,26 +27,19 @@ namespace ModernKeePass.Application.Database.Commands.SaveDatabase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] contents;
|
if (!string.IsNullOrEmpty(message.FilePath))
|
||||||
if (string.IsNullOrEmpty(message.FilePath))
|
|
||||||
{
|
{
|
||||||
contents = await _database.SaveDatabase();
|
|
||||||
|
|
||||||
// Test DB integrity before writing changes to file
|
|
||||||
_database.CloseDatabase();
|
|
||||||
await _database.ReOpen(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;
|
_database.FileAccessToken = message.FilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var contents = await _database.SaveDatabase();
|
||||||
|
|
||||||
|
// Test DB integrity
|
||||||
|
_database.CloseDatabase();
|
||||||
|
await _database.ReOpen(contents);
|
||||||
|
|
||||||
|
// Transactional write to file
|
||||||
|
await _file.WriteBinaryContentsToFile(_database.FileAccessToken, contents);
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception 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);
|
||||||
|
@@ -20,9 +20,10 @@ namespace ModernKeePass.Application.Database.Queries.ReOpenDatabase
|
|||||||
|
|
||||||
public async Task Handle(ReOpenDatabaseQuery message)
|
public async Task Handle(ReOpenDatabaseQuery message)
|
||||||
{
|
{
|
||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (_database.IsOpen) throw new DatabaseOpenException();
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using FluentValidation;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using ModernKeePass.Application.Common.Behaviors;
|
using ModernKeePass.Application.Common.Behaviors;
|
||||||
@@ -13,7 +12,6 @@ namespace ModernKeePass.Application
|
|||||||
var assembly = typeof(DependencyInjection).GetTypeInfo().Assembly;
|
var assembly = typeof(DependencyInjection).GetTypeInfo().Assembly;
|
||||||
services.AddMediatR(assembly);
|
services.AddMediatR(assembly);
|
||||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(DirtyStatusBehavior<,>));
|
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(DirtyStatusBehavior<,>));
|
||||||
//services.AddValidatorsFromAssembly(assembly);
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,6 @@ namespace ModernKeePass.Application.Group.Commands.AddEntry
|
|||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
await _database.AddEntry(message.ParentGroupId, message.EntryId);
|
await _database.AddEntry(message.ParentGroupId, message.EntryId);
|
||||||
//message.ParentGroup.Entries.Add(message.Entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,6 @@ namespace ModernKeePass.Application.Group.Commands.AddGroup
|
|||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
await _database.AddGroup(message.ParentGroupId, message.GroupId);
|
await _database.AddGroup(message.ParentGroupId, message.GroupId);
|
||||||
//message.ParentGroup.SubGroups.Add(message.Group);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,6 @@ namespace ModernKeePass.Application.Group.Commands.RemoveEntry
|
|||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
await _database.RemoveEntry(message.ParentGroupId, message.EntryId);
|
await _database.RemoveEntry(message.ParentGroupId, message.EntryId);
|
||||||
//message.ParentGroup.Entries.Remove(message.Entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,6 @@ namespace ModernKeePass.Application.Group.Commands.RemoveGroup
|
|||||||
if (!_database.IsOpen) throw new DatabaseClosedException();
|
if (!_database.IsOpen) throw new DatabaseClosedException();
|
||||||
|
|
||||||
await _database.RemoveGroup(message.ParentGroupId, message.GroupId);
|
await _database.RemoveGroup(message.ParentGroupId, message.GroupId);
|
||||||
//message.ParentGroup.SubGroups.Remove(message.Group);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Application.Group.Models;
|
using ModernKeePass.Application.Group.Models;
|
||||||
|
@@ -3,5 +3,12 @@
|
|||||||
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";
|
||||||
|
public static string Key => ".key";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -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;
|
||||||
@@ -39,8 +38,9 @@ namespace ModernKeePass
|
|||||||
private readonly ISettingsProxy _settings;
|
private readonly ISettingsProxy _settings;
|
||||||
private readonly INavigationService _navigation;
|
private readonly INavigationService _navigation;
|
||||||
private readonly IHockeyClient _hockey;
|
private readonly IHockeyClient _hockey;
|
||||||
private readonly IDialogService _dialog;
|
|
||||||
private readonly INotificationService _notification;
|
private readonly INotificationService _notification;
|
||||||
|
private readonly IFileProxy _file;
|
||||||
|
private readonly IMessenger _messenger;
|
||||||
|
|
||||||
public static IServiceProvider Services { get; private set; }
|
public static IServiceProvider Services { get; private set; }
|
||||||
|
|
||||||
@@ -63,60 +63,39 @@ namespace ModernKeePass
|
|||||||
_resource = Services.GetService<IResourceProxy>();
|
_resource = Services.GetService<IResourceProxy>();
|
||||||
_settings = Services.GetService<ISettingsProxy>();
|
_settings = Services.GetService<ISettingsProxy>();
|
||||||
_navigation = Services.GetService<INavigationService>();
|
_navigation = Services.GetService<INavigationService>();
|
||||||
_dialog = Services.GetService<IDialogService>();
|
|
||||||
_notification = Services.GetService<INotificationService>();
|
_notification = Services.GetService<INotificationService>();
|
||||||
_hockey = Services.GetService<IHockeyClient>();
|
_hockey = Services.GetService<IHockeyClient>();
|
||||||
|
_file = Services.GetService<IFileProxy>();
|
||||||
|
_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 HandleSaveError(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task HandleSaveError(SaveErrorMessage message)
|
||||||
|
{
|
||||||
|
_notification.Show(_resource.GetResourceValue("MessageDialogSaveErrorTitle"), message?.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 });
|
||||||
|
_messenger.Send(new DatabaseSavedMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#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>
|
||||||
@@ -153,9 +132,6 @@ namespace ModernKeePass
|
|||||||
{
|
{
|
||||||
// Load state from previously terminated application
|
// Load state from previously terminated application
|
||||||
await SuspensionManager.RestoreAsync();
|
await SuspensionManager.RestoreAsync();
|
||||||
#if DEBUG
|
|
||||||
await _dialog.ShowMessage("Windows or an error made the app terminate", "App terminated");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place the frame in the current Window
|
// Place the frame in the current Window
|
||||||
@@ -179,13 +155,27 @@ namespace ModernKeePass
|
|||||||
_notification.Show("App resumed", "Database reopened (changes were saved)");
|
_notification.Show("App resumed", "Database reopened (changes were saved)");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (DatabaseOpenException)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
_notification.Show("App resumed", "Previous database still open because it couldn't be closed (probable save error)");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch (DatabaseClosedException)
|
||||||
{
|
{
|
||||||
_navigation.NavigateTo(Constants.Navigation.MainPage);
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
_notification.Show("App resumed", "Nothing to do, no previous database opened");
|
_notification.Show("App resumed", "Nothing to do, no previous database opened");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_hockey.TrackException(ex);
|
||||||
|
_hockey.Flush();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_navigation.NavigateTo(Constants.Navigation.MainPage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -222,9 +212,14 @@ namespace ModernKeePass
|
|||||||
await _mediator.Send(new CloseDatabaseCommand()).ConfigureAwait(false);
|
await _mediator.Send(new CloseDatabaseCommand()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (SaveException ex)
|
||||||
{
|
{
|
||||||
_notification.Show(exception.Source, exception.Message);
|
_notification.Show(_resource.GetResourceValue("MessageDialogSaveErrorTitle"), ex.Message);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_hockey.TrackException(ex);
|
||||||
|
_hockey.Flush();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@@ -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 =>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest">
|
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest">
|
||||||
<Identity Name="wismna.ModernKeePass" Publisher="CN=0719A91A-C322-4EE0-A257-E60733EECF06" Version="1.16.0.12" />
|
<Identity Name="wismna.ModernKeePass" Publisher="CN=0719A91A-C322-4EE0-A257-E60733EECF06" Version="1.17.0.12" />
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>ModernKeePass</DisplayName>
|
<DisplayName>ModernKeePass</DisplayName>
|
||||||
<PublisherDisplayName>wismna</PublisherDisplayName>
|
<PublisherDisplayName>wismna</PublisherDisplayName>
|
||||||
|
@@ -13,14 +13,14 @@
|
|||||||
<VisualState x:Name="PointerOver">
|
<VisualState x:Name="PointerOver">
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
|
||||||
Storyboard.TargetProperty="Opacity">
|
Storyboard.TargetProperty="Background">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="0.8" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ToggleButtonPointerOverBackgroundThemeBrush}" />
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
<Grid x:Name="Grid" Background="{StaticResource MainColor}" Margin="0" Width="{StaticResource MenuSize}" Height="{StaticResource MenuSize}">
|
<Grid x:Name="Grid" Background="{StaticResource AppBarBackgroundThemeBrush}" Margin="0" Width="{StaticResource MenuWidth}" Height="{StaticResource MenuHeight}">
|
||||||
<Canvas x:Name="HamburgerMenu" HorizontalAlignment="Center" Height="17" UseLayoutRounding="False" VerticalAlignment="Center" Width="28">
|
<Canvas x:Name="HamburgerMenu" HorizontalAlignment="Center" Height="17" UseLayoutRounding="False" VerticalAlignment="Center" Width="28">
|
||||||
<Canvas x:Name="Layer1" Height="17" Canvas.Left="0" Width="28" Margin="0" RenderTransformOrigin="0.5,0.5">
|
<Canvas x:Name="Layer1" Height="17" Canvas.Left="0" Width="28" Margin="0" RenderTransformOrigin="0.5,0.5">
|
||||||
<Canvas.RenderTransform>
|
<Canvas.RenderTransform>
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
<Setter Property="Margin" Value="0" />
|
<Setter Property="Margin" Value="0" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="HeaderTextBoxStyle" TargetType="TextBox">
|
<Style x:Key="HeaderTextBoxStyle" TargetType="TextBox">
|
||||||
<Setter Property="FontSize" Value="40"/>
|
<Setter Property="FontSize" Value="30"/>
|
||||||
<Setter Property="FontWeight" Value="Light"/>
|
<Setter Property="FontWeight" Value="Light"/>
|
||||||
<Setter Property="BorderBrush" Value="Transparent" />
|
<Setter Property="BorderBrush" Value="Transparent" />
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<!-- Default style for Windows.UI.Xaml.Controls.Button -->
|
<!-- Default style for Windows.UI.Xaml.Controls.Button -->
|
||||||
<Style TargetType="Button" x:Key="NoBorderButtonStyle">
|
<Style TargetType="Button" x:Key="NoBorderButtonStyle">
|
||||||
<Setter Property="Background" Value="{ThemeResource ToggleButtonBackgroundThemeBrush}" />
|
<Setter Property="Background" Value="{ThemeResource ToggleButtonBackgroundThemeBrush}" />
|
||||||
<Setter Property="Foreground" Value="{ThemeResource TextColorDark}"/>
|
<Setter Property="Foreground" Value="{ThemeResource ButtonPointerOverForegroundThemeBrush}"/>
|
||||||
<Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderThemeBrush}" />
|
<Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderThemeBrush}" />
|
||||||
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
|
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
|
||||||
<Setter Property="Padding" Value="12,4,12,4" />
|
<Setter Property="Padding" Value="12,4,12,4" />
|
||||||
|
@@ -3,39 +3,31 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
<!-- Common theme values -->
|
<!-- Common theme values -->
|
||||||
<x:Double x:Key="MenuSize">60</x:Double>
|
<x:Double x:Key="MenuWidth">60</x:Double>
|
||||||
|
<x:Double x:Key="MenuHeight">40</x:Double>
|
||||||
<x:Double x:Key="ExpandedMenuSize">300</x:Double>
|
<x:Double x:Key="ExpandedMenuSize">300</x:Double>
|
||||||
<GridLength x:Key="MenuGridLength">60</GridLength>
|
<GridLength x:Key="MenuHeightGridLength">40</GridLength>
|
||||||
|
<GridLength x:Key="MenuWidthGridLength">60</GridLength>
|
||||||
<GridLength x:Key="ExpandedMenuGridLength">300</GridLength>
|
<GridLength x:Key="ExpandedMenuGridLength">300</GridLength>
|
||||||
<!-- Only available for Windows 10 -->
|
|
||||||
<!--<SolidColorBrush x:Key="MainColor" Color="{ThemeResource SystemAccentColor}" />
|
|
||||||
<SolidColorBrush x:Key="TextColor" Color="{ThemeResource SystemColorHighlightTextColor}" />
|
|
||||||
|
|
||||||
<SolidColorBrush x:Key="CheckBoxForegroundChecked" Color="{ThemeResource MainColor}"/>
|
|
||||||
<SolidColorBrush x:Key="CheckBoxCheckGlyphForegroundChecked" Color="{ThemeResource TextColorLight}"/>
|
|
||||||
<SolidColorBrush x:Key="CheckBoxCheckBackgroundStrokeChecked" Color="{ThemeResource MainColor}"/>
|
|
||||||
<SolidColorBrush x:Key="CheckBoxCheckBackgroundFillChecked" Color="{ThemeResource MainColor}"/>-->
|
|
||||||
|
|
||||||
<Color x:Key="MainColor">SlateBlue</Color>
|
<Color x:Key="MainColor">SlateBlue</Color>
|
||||||
<Color x:Key="MainColorLight">MediumPurple</Color>
|
<Color x:Key="MainColorLight">MediumPurple</Color>
|
||||||
<Color x:Key="MainColorDark">Indigo</Color>
|
<Color x:Key="MainColorDark">Indigo</Color>
|
||||||
<Color x:Key="TextColorLight">WhiteSmoke</Color>
|
<Color x:Key="TextColorLight">WhiteSmoke</Color>
|
||||||
<Color x:Key="TextColorDark">DarkSlateGray</Color>
|
|
||||||
<Color x:Key="BorderColor">DarkGray</Color>
|
<Color x:Key="BorderColor">DarkGray</Color>
|
||||||
|
<Color x:Key="FlyoutColor">#FFF0F0F0</Color>
|
||||||
|
|
||||||
<SolidColorBrush x:Key="MainColorBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="MainColorBrush" Color="{ThemeResource MainColor}" />
|
||||||
<SolidColorBrush x:Key="MainColorLightBrush" Color="{ThemeResource MainColorLight}" />
|
<SolidColorBrush x:Key="MainColorLightBrush" Color="{ThemeResource MainColorLight}" />
|
||||||
<SolidColorBrush x:Key="MainColorDarkBrush" Color="{ThemeResource MainColorDark}" />
|
<SolidColorBrush x:Key="MainColorDarkBrush" Color="{ThemeResource MainColorDark}" />
|
||||||
<SolidColorBrush x:Key="TextColorLightBrush" Color="{ThemeResource TextColorLight}" />
|
<SolidColorBrush x:Key="TextColorLightBrush" Color="{ThemeResource TextColorLight}" />
|
||||||
<SolidColorBrush x:Key="TextColorDarkBrush" Color="{ThemeResource TextColorDark}" />
|
|
||||||
|
|
||||||
<Style TargetType="TextBlock" x:Key="TextBlockSettingsHeaderStyle" >
|
<Style TargetType="TextBlock" x:Key="TextBlockSettingsHeaderStyle" >
|
||||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||||
<Setter Property="FontSize" Value="14.667" />
|
<Setter Property="FontSize" Value="16" />
|
||||||
<Setter Property="FontWeight" Value="SemiLight" />
|
<Setter Property="FontWeight" Value="SemiLight" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<SolidColorBrush x:Key="TextBoxForegroundThemeBrush" Color="{ThemeResource TextColorDark}" />
|
|
||||||
<SolidColorBrush x:Key="TextBoxBorderThemeBrush" Color="{ThemeResource BorderColor}" />
|
<SolidColorBrush x:Key="TextBoxBorderThemeBrush" Color="{ThemeResource BorderColor}" />
|
||||||
<SolidColorBrush x:Key="TextSelectionHighlightColorThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="TextSelectionHighlightColorThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
|
|
||||||
@@ -50,9 +42,9 @@
|
|||||||
<SolidColorBrush x:Key="HyperlinkForegroundThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="HyperlinkForegroundThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
<SolidColorBrush x:Key="HyperlinkPointerOverForegroundThemeBrush" Color="{ThemeResource MainColorLight}" />
|
<SolidColorBrush x:Key="HyperlinkPointerOverForegroundThemeBrush" Color="{ThemeResource MainColorLight}" />
|
||||||
|
|
||||||
<SolidColorBrush x:Key="SearchBoxForegroundThemeBrush" Color="{ThemeResource TextColorDark}" />
|
|
||||||
<!--<SolidColorBrush x:Key="SearchBoxPointerOverBorderThemeBrush" Color="{ThemeResource MainColorLight}" />-->
|
<!--<SolidColorBrush x:Key="SearchBoxPointerOverBorderThemeBrush" Color="{ThemeResource MainColorLight}" />-->
|
||||||
<SolidColorBrush x:Key="SearchBoxPointerOverTextThemeBrush" Color="{ThemeResource MainColorLight}" />
|
<SolidColorBrush x:Key="SearchBoxPointerOverTextThemeBrush" Color="{ThemeResource MainColorLight}" />
|
||||||
|
<SolidColorBrush x:Key="SearchBoxBorderThemeBrush" Color="{ThemeResource BorderColor}" />
|
||||||
<SolidColorBrush x:Key="SearchBoxFocusedBorderThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="SearchBoxFocusedBorderThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
<SolidColorBrush x:Key="SearchBoxButtonBackgroundThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="SearchBoxButtonBackgroundThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
<SolidColorBrush x:Key="SearchBoxHitHighlightForegroundThemeBrush" Color="{ThemeResource MainColor}" />
|
<SolidColorBrush x:Key="SearchBoxHitHighlightForegroundThemeBrush" Color="{ThemeResource MainColor}" />
|
||||||
@@ -83,4 +75,10 @@
|
|||||||
<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="MenuFlyoutPresenterThemePadding">0</Thickness>
|
||||||
|
<Thickness x:Key="FlyoutContentThemePadding">5</Thickness>
|
||||||
|
<Thickness x:Key="FlyoutBorderThemeThickness">0</Thickness>
|
||||||
|
<SolidColorBrush x:Key="FlyoutBorderThemeBrush" Color="{ThemeResource FlyoutColor}" />
|
||||||
|
<SolidColorBrush x:Key="FlyoutBackgroundThemeBrush" Color="{ThemeResource FlyoutColor}" />
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
@@ -291,7 +291,7 @@
|
|||||||
TextWrapping="NoWrap"
|
TextWrapping="NoWrap"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, Path=Text}" />
|
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, Path=Text, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
<Button x:Name="ActionButton"
|
<Button x:Name="ActionButton"
|
||||||
AutomationProperties.AccessibilityView="Raw"
|
AutomationProperties.AccessibilityView="Raw"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
@@ -301,7 +301,8 @@
|
|||||||
Style="{StaticResource ActionButtonStyle}"
|
Style="{StaticResource ActionButtonStyle}"
|
||||||
Content="{TemplateBinding ButtonSymbol}"
|
Content="{TemplateBinding ButtonSymbol}"
|
||||||
IsEnabled="{TemplateBinding IsButtonEnabled}"
|
IsEnabled="{TemplateBinding IsButtonEnabled}"
|
||||||
Command="{TemplateBinding ButtonCommand}">
|
Command="{TemplateBinding ButtonCommand}"
|
||||||
|
CommandParameter="{TemplateBinding ButtonCommandParameter}">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<ToolTip Content="{TemplateBinding ButtonTooltip}" />
|
<ToolTip Content="{TemplateBinding ButtonTooltip}" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
|
@@ -267,4 +267,13 @@
|
|||||||
<data name="FileNotFoundTitle" xml:space="preserve">
|
<data name="FileNotFoundTitle" xml:space="preserve">
|
||||||
<value>File not found</value>
|
<value>File not found</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="MessageDialogSaveNameSuggestion" xml:space="preserve">
|
||||||
|
<value>KeePass</value>
|
||||||
|
</data>
|
||||||
|
<data name="CompositeKeyFileTypeDesc" xml:space="preserve">
|
||||||
|
<value>Key file</value>
|
||||||
|
</data>
|
||||||
|
<data name="CompositeKeyFileNameSuggestion" xml:space="preserve">
|
||||||
|
<value>Key</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -513,4 +513,7 @@
|
|||||||
<data name="SettingsSaveDatabaseSuspendDesc.Text" xml:space="preserve">
|
<data name="SettingsSaveDatabaseSuspendDesc.Text" xml:space="preserve">
|
||||||
<value>This settings is generally recommended. If you enable it, database will automatically be saved on application suspension and closing, provided your database is less than 1MB big. Saving bigger databases may take too long and Windows may then forcibly kill the app before saving is finished, resulting in your changes not being saved.</value>
|
<value>This settings is generally recommended. If you enable it, database will automatically be saved on application suspension and closing, provided your database is less than 1MB big. Saving bigger databases may take too long and Windows may then forcibly kill the app before saving is finished, resulting in your changes not being saved.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NewGroupTextBox.ButtonTooltip" xml:space="preserve">
|
||||||
|
<value>New group name</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -267,4 +267,13 @@
|
|||||||
<data name="FileNotFoundTitle" xml:space="preserve">
|
<data name="FileNotFoundTitle" xml:space="preserve">
|
||||||
<value>Fichier manquant</value>
|
<value>Fichier manquant</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="MessageDialogSaveNameSuggestion" xml:space="preserve">
|
||||||
|
<value>KeePass</value>
|
||||||
|
</data>
|
||||||
|
<data name="CompositeKeyFileTypeDesc" xml:space="preserve">
|
||||||
|
<value>Fichier de clé</value>
|
||||||
|
</data>
|
||||||
|
<data name="CompositeKeyFileNameSuggestion" xml:space="preserve">
|
||||||
|
<value>Clé</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -492,9 +492,6 @@
|
|||||||
<data name="NewImportFormat.Text" xml:space="preserve">
|
<data name="NewImportFormat.Text" xml:space="preserve">
|
||||||
<value>Format</value>
|
<value>Format</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NewImportFormatHelp.Text" xml:space="preserve">
|
|
||||||
<value>Le fichier CSV doit être formatté de la façon suivante: Nom du compte;Login;Mot de passe:URL;Commentaires</value>
|
|
||||||
</data>
|
|
||||||
<data name="CloseButton.Content" xml:space="preserve">
|
<data name="CloseButton.Content" xml:space="preserve">
|
||||||
<value>Fermer sans sauvegarder</value>
|
<value>Fermer sans sauvegarder</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -516,4 +513,7 @@
|
|||||||
<data name="CompositeKeyConfirmPassword.PlaceholderText" xml:space="preserve">
|
<data name="CompositeKeyConfirmPassword.PlaceholderText" xml:space="preserve">
|
||||||
<value>Confirmer le mot de passe</value>
|
<value>Confirmer le mot de passe</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NewGroupTextBox.ButtonTooltip" xml:space="preserve">
|
||||||
|
<value>Nom du groupe</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -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;
|
||||||
@@ -264,6 +266,8 @@ namespace ModernKeePass.ViewModels
|
|||||||
DeleteCommand = new RelayCommand(async () => await AskForDelete());
|
DeleteCommand = new RelayCommand(async () => await AskForDelete());
|
||||||
GoBackCommand = new RelayCommand(() => _navigation.GoBack());
|
GoBackCommand = new RelayCommand(() => _navigation.GoBack());
|
||||||
GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id));
|
GoToParentCommand = new RelayCommand(() => GoToGroup(_parent.Id));
|
||||||
|
|
||||||
|
MessengerInstance.Register<DatabaseSavedMessage>(this, _ => SaveCommand.RaiseCanExecuteChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Initialize(string entryId)
|
public async Task Initialize(string entryId)
|
||||||
@@ -362,7 +366,14 @@ namespace ModernKeePass.ViewModels
|
|||||||
private async Task SaveChanges()
|
private async Task SaveChanges()
|
||||||
{
|
{
|
||||||
await AddHistory();
|
await AddHistory();
|
||||||
await _mediator.Send(new SaveDatabaseCommand());
|
try
|
||||||
|
{
|
||||||
|
await _mediator.Send(new SaveDatabaseCommand());
|
||||||
|
}
|
||||||
|
catch (SaveException e)
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new SaveErrorMessage { Message = e.Message });
|
||||||
|
}
|
||||||
SaveCommand.RaiseCanExecuteChanged();
|
SaveCommand.RaiseCanExecuteChanged();
|
||||||
_isDirty = false;
|
_isDirty = false;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -9,6 +8,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;
|
||||||
@@ -26,14 +26,14 @@ using ModernKeePass.Application.Group.Commands.SortGroups;
|
|||||||
using ModernKeePass.Application.Group.Commands.UpdateGroup;
|
using ModernKeePass.Application.Group.Commands.UpdateGroup;
|
||||||
using ModernKeePass.Application.Group.Models;
|
using ModernKeePass.Application.Group.Models;
|
||||||
using ModernKeePass.Application.Group.Queries.GetGroup;
|
using ModernKeePass.Application.Group.Queries.GetGroup;
|
||||||
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; }
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
public RelayCommand SortGroupsCommand { get; }
|
public RelayCommand SortGroupsCommand { get; }
|
||||||
public RelayCommand<string> MoveCommand { get; }
|
public RelayCommand<string> MoveCommand { get; }
|
||||||
public RelayCommand CreateEntryCommand { get; }
|
public RelayCommand CreateEntryCommand { get; }
|
||||||
public RelayCommand CreateGroupCommand { get; }
|
public RelayCommand<string> CreateGroupCommand { get; }
|
||||||
public RelayCommand DeleteCommand { get; set; }
|
public RelayCommand DeleteCommand { get; set; }
|
||||||
public RelayCommand GoBackCommand { get; set; }
|
public RelayCommand GoBackCommand { get; set; }
|
||||||
public RelayCommand GoToParentCommand { get; set; }
|
public RelayCommand GoToParentCommand { get; set; }
|
||||||
@@ -120,10 +120,12 @@ namespace ModernKeePass.ViewModels
|
|||||||
SortGroupsCommand = new RelayCommand(async () => await SortGroupsAsync(), () => IsEditMode);
|
SortGroupsCommand = new RelayCommand(async () => await SortGroupsAsync(), () => IsEditMode);
|
||||||
MoveCommand = new RelayCommand<string>(async destination => await Move(destination), destination => IsNotRoot && !string.IsNullOrEmpty(destination) && destination != Id);
|
MoveCommand = new RelayCommand<string>(async destination => await Move(destination), destination => IsNotRoot && !string.IsNullOrEmpty(destination) && destination != Id);
|
||||||
CreateEntryCommand = new RelayCommand(async () => await AddNewEntry(), () => !IsInRecycleBin && Database.RecycleBinId != Id);
|
CreateEntryCommand = new RelayCommand(async () => await AddNewEntry(), () => !IsInRecycleBin && Database.RecycleBinId != Id);
|
||||||
CreateGroupCommand = new RelayCommand(async () => await AddNewGroup(), () => !IsInRecycleBin && Database.RecycleBinId != Id);
|
CreateGroupCommand = new RelayCommand<string>(async newGroupName => await AddNewGroup(newGroupName), _ => !IsInRecycleBin && Database.RecycleBinId != Id);
|
||||||
DeleteCommand = new RelayCommand(async () => await AskForDelete(),() => IsNotRoot);
|
DeleteCommand = new RelayCommand(async () => await AskForDelete(),() => IsNotRoot);
|
||||||
GoBackCommand = new RelayCommand(() => _navigation.GoBack());
|
GoBackCommand = new RelayCommand(() => _navigation.GoBack());
|
||||||
GoToParentCommand= new RelayCommand(() => GoToGroup(_parent.Id), () => _parent != null);
|
GoToParentCommand= new RelayCommand(() => GoToGroup(_parent.Id), () => _parent != null);
|
||||||
|
|
||||||
|
MessengerInstance.Register<DatabaseSavedMessage>(this, _ => SaveCommand.RaiseCanExecuteChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Initialize(string groupId)
|
public async Task Initialize(string groupId)
|
||||||
@@ -159,7 +161,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
public async Task AddNewGroup(string name = "")
|
public async Task AddNewGroup(string name = "")
|
||||||
{
|
{
|
||||||
var group = await _mediator.Send(new CreateGroupCommand {Name = name, ParentGroup = _group});
|
var group = await _mediator.Send(new CreateGroupCommand {Name = name, ParentGroup = _group});
|
||||||
GoToGroup(group.Id, true);
|
Groups.Add(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddNewEntry()
|
public async Task AddNewEntry()
|
||||||
@@ -174,15 +176,17 @@ namespace ModernKeePass.ViewModels
|
|||||||
await _mediator.Send(new RemoveGroupCommand {ParentGroupId = _parent.Id, GroupId = Id });
|
await _mediator.Send(new RemoveGroupCommand {ParentGroupId = _parent.Id, GroupId = Id });
|
||||||
GoToGroup(destinationId);
|
GoToGroup(destinationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<EntryVm>> Search(string queryText)
|
|
||||||
{
|
|
||||||
return await _mediator.Send(new SearchEntriesQuery {GroupId = Id, SearchText = queryText});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveChanges()
|
private async Task SaveChanges()
|
||||||
{
|
{
|
||||||
await _mediator.Send(new SaveDatabaseCommand());
|
try
|
||||||
|
{
|
||||||
|
await _mediator.Send(new SaveDatabaseCommand());
|
||||||
|
}
|
||||||
|
catch (SaveException e)
|
||||||
|
{
|
||||||
|
MessengerInstance.Send(new SaveErrorMessage { Message = e.Message });
|
||||||
|
}
|
||||||
SaveCommand.RaiseCanExecuteChanged();
|
SaveCommand.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -184,6 +184,7 @@ namespace ModernKeePass.ViewModels
|
|||||||
catch (SaveException exception)
|
catch (SaveException exception)
|
||||||
{
|
{
|
||||||
_notification.Show(exception.Source, exception.Message);
|
_notification.Show(exception.Source, exception.Message);
|
||||||
|
MessengerInstance.Send(new SaveErrorMessage { Message = exception.Message });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,6 @@ using System.Linq;
|
|||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using GalaSoft.MvvmLight;
|
using GalaSoft.MvvmLight;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
using ModernKeePass.Domain.Interfaces;
|
using ModernKeePass.Domain.Interfaces;
|
||||||
|
@@ -365,19 +365,20 @@
|
|||||||
</TransitionCollection>
|
</TransitionCollection>
|
||||||
</Grid.ChildrenTransitions>
|
</Grid.ChildrenTransitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="{StaticResource MenuGridLength}"/>
|
<RowDefinition Height="{StaticResource MenuHeightGridLength}"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="{StaticResource MenuGridLength}" x:Name="LeftListViewColumn" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<userControls:HamburgerMenuUserControl x:Uid="HistoryLeftListView"
|
<userControls:HamburgerMenuUserControl
|
||||||
ItemsSource="{Binding History}"
|
x:Name="HamburgerMenu"
|
||||||
ResizeTarget="{Binding ElementName=LeftListViewColumn}"
|
x:Uid="HistoryLeftListView"
|
||||||
SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"
|
ItemsSource="{Binding History}"
|
||||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
|
SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"
|
||||||
|
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
|
||||||
<Grid Grid.Column="1">
|
<Grid Grid.Column="1">
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
<StackPanel Margin="20,0,0,20">
|
<StackPanel Margin="20,0,0,20">
|
||||||
@@ -456,36 +457,38 @@
|
|||||||
<!-- Bouton Précédent et titre de la page -->
|
<!-- Bouton Précédent et titre de la page -->
|
||||||
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
|
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="{StaticResource MenuGridLength}"/>
|
<ColumnDefinition Width="{StaticResource MenuWidthGridLength}"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Button Grid.Column="0"
|
<Button Grid.Column="0"
|
||||||
Command="{Binding GoBackCommand}"
|
Command="{Binding GoBackCommand}"
|
||||||
Height="{StaticResource MenuSize}"
|
Height="{StaticResource MenuHeight}"
|
||||||
Width="{StaticResource MenuSize}"
|
Width="{StaticResource MenuWidth}"
|
||||||
AutomationProperties.Name="Back"
|
AutomationProperties.Name="Back"
|
||||||
AutomationProperties.AutomationId="BackButton"
|
AutomationProperties.AutomationId="BackButton"
|
||||||
AutomationProperties.ItemType="Navigation Button"
|
AutomationProperties.ItemType="Navigation Button"
|
||||||
Style="{StaticResource NoBorderButtonStyle}">
|
Style="{StaticResource NoBorderButtonStyle}">
|
||||||
<SymbolIcon Symbol="Back" />
|
<SymbolIcon Symbol="Back" />
|
||||||
</Button>
|
</Button>
|
||||||
<Grid Grid.Column="1">
|
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||||
<Grid.ColumnDefinitions>
|
<Button
|
||||||
<ColumnDefinition Width="60" />
|
Height="{StaticResource MenuHeight}"
|
||||||
<ColumnDefinition Width="*" />
|
Width="{StaticResource MenuWidth}"
|
||||||
</Grid.ColumnDefinitions>
|
Command="{Binding GoToParentCommand}"
|
||||||
<Grid.RowDefinitions>
|
Style="{StaticResource NoBorderButtonStyle}">
|
||||||
<RowDefinition Height="40" />
|
<SymbolIcon Symbol="Up" />
|
||||||
<RowDefinition Height="20" />
|
<ToolTipService.ToolTip>
|
||||||
</Grid.RowDefinitions>
|
<ToolTip Content="{Binding ParentGroupName}" />
|
||||||
<Viewbox MaxHeight="200" Width="200" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
</ToolTipService.ToolTip>
|
||||||
|
</Button>
|
||||||
|
<Viewbox MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<userControls:SymbolPickerUserControl Width="100" Height="70" SelectedSymbol="{Binding Icon, Mode=TwoWay}" />
|
<userControls:SymbolPickerUserControl Width="100" Height="70" SelectedSymbol="{Binding Icon, Mode=TwoWay}" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox MaxHeight="200" Width="200" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
<Viewbox MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
||||||
<SymbolIcon Symbol="{Binding Icon}" Width="100" Height="70" />
|
<SymbolIcon Symbol="{Binding Icon}" Width="100" Height="70" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBox Grid.Column="1" Grid.Row="0"
|
<TextBox
|
||||||
x:Uid="EntryTitle"
|
x:Uid="EntryTitle"
|
||||||
x:Name="TitleTextBox"
|
x:Name="TitleTextBox"
|
||||||
Text="{Binding Title, Mode=TwoWay}"
|
Text="{Binding Title, Mode=TwoWay}"
|
||||||
@@ -494,6 +497,7 @@
|
|||||||
FontSize="20"
|
FontSize="20"
|
||||||
FontWeight="Light"
|
FontWeight="Light"
|
||||||
TextWrapping="NoWrap"
|
TextWrapping="NoWrap"
|
||||||
|
MinWidth="360"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
|
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
|
||||||
@@ -505,11 +509,7 @@
|
|||||||
</core:DataTriggerBehavior>
|
</core:DataTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
<HyperlinkButton Grid.Column="1" Grid.Row="1"
|
</StackPanel>
|
||||||
FontWeight="Light" FontSize="12" Padding="0" Margin="5,-5,0,0"
|
|
||||||
Content="{Binding ParentGroupName}"
|
|
||||||
Command="{Binding GoToParentCommand}"/>
|
|
||||||
</Grid>
|
|
||||||
<userControls:TopMenuUserControl
|
<userControls:TopMenuUserControl
|
||||||
x:Name="TopMenu" Grid.Column="2"
|
x:Name="TopMenu" Grid.Column="2"
|
||||||
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
||||||
|
@@ -42,8 +42,24 @@ namespace ModernKeePass.Views
|
|||||||
|
|
||||||
private void EntryDetailPage_OnSizeChanged(object sender, SizeChangedEventArgs e)
|
private void EntryDetailPage_OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
{
|
{
|
||||||
VisualStateManager.GoToState(this, e.NewSize.Width < 700 ? "Small" : "Large", true);
|
if (e.NewSize.Width <= 640)
|
||||||
VisualStateManager.GoToState(TopMenu, e.NewSize.Width < 800 ? "Collapsed" : "Overflowed", true);
|
{
|
||||||
|
VisualStateManager.GoToState(this, "Small", true);
|
||||||
|
VisualStateManager.GoToState(TopMenu, "Collapsed", true);
|
||||||
|
VisualStateManager.GoToState(HamburgerMenu, "Hidden", true);
|
||||||
|
}
|
||||||
|
else if (e.NewSize.Width > 640 && e.NewSize.Width <= 1008)
|
||||||
|
{
|
||||||
|
VisualStateManager.GoToState(this, "Medium", true);
|
||||||
|
VisualStateManager.GoToState(TopMenu, "Overflowed", true);
|
||||||
|
VisualStateManager.GoToState(HamburgerMenu, "Collapsed", true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VisualStateManager.GoToState(this, "Large", true);
|
||||||
|
VisualStateManager.GoToState(TopMenu, "Overflowed", true);
|
||||||
|
VisualStateManager.GoToState(HamburgerMenu, "Collapsed", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,21 +36,20 @@
|
|||||||
</TransitionCollection>
|
</TransitionCollection>
|
||||||
</Grid.ChildrenTransitions>
|
</Grid.ChildrenTransitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="{StaticResource MenuGridLength}"/>
|
<RowDefinition Height="{StaticResource MenuHeightGridLength}"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="{StaticResource ExpandedMenuGridLength}" x:Name="LeftListViewColumn" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<userControls:HamburgerMenuUserControl
|
<userControls:HamburgerMenuUserControl
|
||||||
|
x:Name="HamburgerMenu"
|
||||||
x:Uid="GroupsLeftListView"
|
x:Uid="GroupsLeftListView"
|
||||||
ItemsSource="{Binding Groups}"
|
ItemsSource="{Binding Groups}"
|
||||||
SelectionChanged="groups_SelectionChanged"
|
SelectionChanged="groups_SelectionChanged"
|
||||||
ActionButtonCommand="{Binding CreateGroupCommand}"
|
ActionButtonCommand="{Binding CreateGroupCommand}"
|
||||||
ResizeTarget="{Binding ElementName=LeftListViewColumn}"
|
|
||||||
IsOpen="True"
|
|
||||||
IsButtonVisible="Visible" />
|
IsButtonVisible="Visible" />
|
||||||
<Grid Grid.Column="1">
|
<Grid Grid.Column="1">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -116,7 +115,7 @@
|
|||||||
<TextBlock Text="{Binding Username}" Style="{StaticResource BodyTextBlockStyle}" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}" MaxHeight="60" />
|
<TextBlock Text="{Binding Username}" Style="{StaticResource BodyTextBlockStyle}" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}" MaxHeight="60" />
|
||||||
<TextBlock Text="{Binding Url}" Style="{StaticResource BodyTextBlockStyle}" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}" MaxHeight="60" />
|
<TextBlock Text="{Binding Url}" Style="{StaticResource BodyTextBlockStyle}" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}" MaxHeight="60" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button Grid.Column="2" Style="{StaticResource NoBorderButtonStyle}" Background="{StaticResource AppBarBackgroundThemeBrush}" VerticalAlignment="Bottom" Foreground="{StaticResource TextColorDarkBrush}">
|
<Button Grid.Column="2" Style="{StaticResource NoBorderButtonStyle}" Background="{StaticResource AppBarBackgroundThemeBrush}" VerticalAlignment="Bottom">
|
||||||
<SymbolIcon Symbol="More" />
|
<SymbolIcon Symbol="More" />
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<MenuFlyout>
|
<MenuFlyout>
|
||||||
@@ -183,37 +182,38 @@
|
|||||||
<!-- Back button and page title -->
|
<!-- Back button and page title -->
|
||||||
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
|
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="{StaticResource MenuGridLength}"/>
|
<ColumnDefinition Width="{StaticResource MenuWidthGridLength}"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Button Grid.Column="0"
|
<Button Grid.Column="0"
|
||||||
Command="{Binding GoBackCommand}"
|
Command="{Binding GoBackCommand}"
|
||||||
Height="{StaticResource MenuSize}"
|
Height="{StaticResource MenuHeight}"
|
||||||
Width="{StaticResource MenuSize}"
|
Width="{StaticResource MenuWidth}"
|
||||||
AutomationProperties.Name="Back"
|
AutomationProperties.Name="Back"
|
||||||
AutomationProperties.AutomationId="BackButton"
|
AutomationProperties.AutomationId="BackButton"
|
||||||
AutomationProperties.ItemType="Navigation Button"
|
AutomationProperties.ItemType="Navigation Button"
|
||||||
Style="{StaticResource NoBorderButtonStyle}">
|
Style="{StaticResource NoBorderButtonStyle}">
|
||||||
<SymbolIcon Symbol="Back" />
|
<SymbolIcon Symbol="Back" />
|
||||||
</Button>
|
</Button>
|
||||||
<Grid Grid.Column="1" >
|
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||||
<Grid.ColumnDefinitions>
|
<Button
|
||||||
<ColumnDefinition Width="60" />
|
Height="{StaticResource MenuHeight}"
|
||||||
<ColumnDefinition Width="*" />
|
Width="{StaticResource MenuWidth}"
|
||||||
</Grid.ColumnDefinitions>
|
Command="{Binding GoToParentCommand}"
|
||||||
<Grid.RowDefinitions>
|
Style="{StaticResource NoBorderButtonStyle}">
|
||||||
<RowDefinition Height="40" />
|
<SymbolIcon Symbol="Up" />
|
||||||
<RowDefinition Height="20" />
|
<ToolTipService.ToolTip>
|
||||||
</Grid.RowDefinitions>
|
<ToolTip Content="{Binding ParentGroupName}" />
|
||||||
<Viewbox MaxHeight="200" Width="200" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
</ToolTipService.ToolTip>
|
||||||
|
</Button>
|
||||||
|
<Viewbox MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<userControls:SymbolPickerUserControl Width="100" Height="70" SelectedSymbol="{Binding Icon, Mode=TwoWay}" />
|
<userControls:SymbolPickerUserControl Width="100" Height="70" SelectedSymbol="{Binding Icon, Mode=TwoWay}" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<Viewbox MaxHeight="200" Width="200" Grid.Column="0" Grid.Row="0" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
<Viewbox MaxHeight="200" Visibility="{Binding IsEditMode, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
|
||||||
<SymbolIcon Symbol="{Binding Icon}" Width="100" Height="70" />
|
<SymbolIcon Symbol="{Binding Icon}" Width="100" Height="70" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBox Grid.Column="1" Grid.Row="0"
|
<TextBox
|
||||||
x:Uid="GroupTitle"
|
x:Uid="GroupTitle"
|
||||||
x:Name="TitleTextBox"
|
x:Name="TitleTextBox"
|
||||||
Text="{Binding Title, Mode=TwoWay}"
|
Text="{Binding Title, Mode=TwoWay}"
|
||||||
@@ -222,6 +222,7 @@
|
|||||||
FontSize="20"
|
FontSize="20"
|
||||||
FontWeight="Light"
|
FontWeight="Light"
|
||||||
TextWrapping="NoWrap"
|
TextWrapping="NoWrap"
|
||||||
|
MinWidth="360"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
|
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
|
||||||
@@ -233,11 +234,7 @@
|
|||||||
</core:DataTriggerBehavior>
|
</core:DataTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
<HyperlinkButton Grid.Column="1" Grid.Row="1"
|
</StackPanel>
|
||||||
FontWeight="Light" FontSize="12" Padding="0" Margin="5,-5,0,0"
|
|
||||||
Content="{Binding ParentGroupName}"
|
|
||||||
Command="{Binding GoToParentCommand}" />
|
|
||||||
</Grid>
|
|
||||||
<userControls:TopMenuUserControl x:Name="TopMenu" Grid.Column="2"
|
<userControls:TopMenuUserControl x:Name="TopMenu" Grid.Column="2"
|
||||||
SortButtonVisibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}"
|
SortButtonVisibility="{Binding IsEditMode, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||||
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
IsEditButtonChecked="{Binding IsEditMode, Mode=TwoWay}"
|
||||||
@@ -252,31 +249,7 @@
|
|||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
</userControls:TopMenuUserControl>
|
</userControls:TopMenuUserControl>
|
||||||
<Button Grid.Column="3" x:Name="SearchButton" Style="{StaticResource NoBorderButtonStyle}" Background="{ThemeResource ToggleButtonBackgroundThemeBrush}" Height="{StaticResource MenuSize}" Padding="25,0,25,0">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<SymbolIcon Symbol="Find" />
|
|
||||||
<TextBlock x:Uid="SearchButtonLabel" x:Name="SearchButtonLabel" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="10,0,0,0" />
|
|
||||||
</StackPanel>
|
|
||||||
<ToolTipService.ToolTip>
|
|
||||||
<ToolTip x:Uid="SearchButtonTooltip" />
|
|
||||||
</ToolTipService.ToolTip>
|
|
||||||
<interactivity:Interaction.Behaviors>
|
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchBox}" PropertyName="Visibility" Value="Visible" />
|
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchButton}" PropertyName="Visibility" Value="Collapsed" />
|
|
||||||
<!-- TODO: make this work -->
|
|
||||||
<actions:SetupFocusAction TargetObject="{Binding ElementName=SearchBox}" />
|
|
||||||
</core:EventTriggerBehavior>
|
|
||||||
</interactivity:Interaction.Behaviors>
|
|
||||||
</Button>
|
|
||||||
<SearchBox Grid.Column="3" x:Uid="EntriesSearch" x:Name="SearchBox" Padding="12" Width="350" Visibility="Collapsed" Margin="0,5,0,5" FontSize="15" SuggestionsRequested="SearchBox_OnSuggestionsRequested" SearchHistoryEnabled="False" ResultSuggestionChosen="SearchBox_OnResultSuggestionChosen">
|
|
||||||
<interactivity:Interaction.Behaviors>
|
|
||||||
<core:EventTriggerBehavior EventName="LostFocus">
|
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchBox}" PropertyName="Visibility" Value="Collapsed" />
|
|
||||||
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchButton}" PropertyName="Visibility" Value="Visible" />
|
|
||||||
</core:EventTriggerBehavior>
|
|
||||||
</interactivity:Interaction.Behaviors>
|
|
||||||
</SearchBox>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
<VisualStateGroup x:Name="DragDropGroup">
|
<VisualStateGroup x:Name="DragDropGroup">
|
||||||
@@ -295,14 +268,21 @@
|
|||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
<VisualStateGroup x:Name="TopMenuGroup">
|
<VisualStateGroup x:Name="PageLayout">
|
||||||
<VisualState x:Name="Small">
|
<VisualState x:Name="Small">
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="AddEntryTextBlock" Storyboard.TargetProperty="Visibility">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="AddEntryTextBlock" Storyboard.TargetProperty="Visibility">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SearchButtonLabel" Storyboard.TargetProperty="Visibility">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HamburgerMenu" Storyboard.TargetProperty="IsOpen">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
<DiscreteObjectKeyFrame KeyTime="0" Value="False"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="Medium">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HamburgerMenu" Storyboard.TargetProperty="IsOpen">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="False"/>
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
@@ -311,8 +291,8 @@
|
|||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="AddEntryTextBlock" Storyboard.TargetProperty="Visibility">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="AddEntryTextBlock" Storyboard.TargetProperty="Visibility">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SearchButtonLabel" Storyboard.TargetProperty="Visibility">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HamburgerMenu" Storyboard.TargetProperty="IsOpen">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
<DiscreteObjectKeyFrame KeyTime="0" Value="True"/>
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
|
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using System.Linq;
|
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
|
||||||
using Windows.Storage.Streams;
|
|
||||||
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;
|
||||||
@@ -83,26 +80,27 @@ namespace ModernKeePass.Views
|
|||||||
e.Cancel = !Model.IsEditMode;
|
e.Cancel = !Model.IsEditMode;
|
||||||
e.Data.RequestedOperation = DataPackageOperation.Move;
|
e.Data.RequestedOperation = DataPackageOperation.Move;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
|
|
||||||
{
|
|
||||||
var imageUri = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appdata://Assets/ModernKeePass-SmallLogo.scale-80.png"));
|
|
||||||
var results = (await Model.Search(args.QueryText)).Take(5);
|
|
||||||
foreach (var result in results)
|
|
||||||
{
|
|
||||||
args.Request.SearchSuggestionCollection.AppendResultSuggestion(result.Title, result.ParentGroupName, result.Id, imageUri, string.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SearchBox_OnResultSuggestionChosen(SearchBox sender, SearchBoxResultSuggestionChosenEventArgs args)
|
|
||||||
{
|
|
||||||
Model.GoToEntry(args.Tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GroupDetailPage_OnSizeChanged(object sender, SizeChangedEventArgs e)
|
private void GroupDetailPage_OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
{
|
{
|
||||||
VisualStateManager.GoToState(this, e.NewSize.Width < 800 ? "Small" : "Large", true);
|
if (e.NewSize.Width <= 640)
|
||||||
VisualStateManager.GoToState(TopMenu, e.NewSize.Width < 800 ? "Collapsed" : "Overflowed", true);
|
{
|
||||||
|
VisualStateManager.GoToState(this, "Small", true);
|
||||||
|
VisualStateManager.GoToState(TopMenu, "Collapsed", true);
|
||||||
|
VisualStateManager.GoToState(HamburgerMenu, "Hidden", true);
|
||||||
|
}
|
||||||
|
else if (e.NewSize.Width > 640 && e.NewSize.Width <= 1008)
|
||||||
|
{
|
||||||
|
VisualStateManager.GoToState(this, "Medium", true);
|
||||||
|
VisualStateManager.GoToState(TopMenu, "Overflowed", true);
|
||||||
|
VisualStateManager.GoToState(HamburgerMenu, "Collapsed", true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VisualStateManager.GoToState(this, "Large", true);
|
||||||
|
VisualStateManager.GoToState(TopMenu, "Overflowed", true);
|
||||||
|
VisualStateManager.GoToState(HamburgerMenu, "Expanded", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
</TransitionCollection>
|
</TransitionCollection>
|
||||||
</Grid.ChildrenTransitions>
|
</Grid.ChildrenTransitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="{StaticResource MenuGridLength}"/>
|
<RowDefinition Height="{StaticResource MenuHeightGridLength}"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<Button x:Name="BackButton"
|
<Button x:Name="BackButton"
|
||||||
Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}"
|
Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}"
|
||||||
Visibility="Collapsed"
|
Visibility="Collapsed"
|
||||||
Height="{StaticResource MenuSize}"
|
Height="{StaticResource MenuWidth}"
|
||||||
AutomationProperties.Name="Back"
|
AutomationProperties.Name="Back"
|
||||||
AutomationProperties.AutomationId="BackButton"
|
AutomationProperties.AutomationId="BackButton"
|
||||||
AutomationProperties.ItemType="Navigation Button"
|
AutomationProperties.ItemType="Navigation Button"
|
||||||
|
@@ -6,15 +6,14 @@
|
|||||||
xmlns:viewModels="using:ModernKeePass.ViewModels"
|
xmlns:viewModels="using:ModernKeePass.ViewModels"
|
||||||
x:Class="ModernKeePass.Views.AboutPage"
|
x:Class="ModernKeePass.Views.AboutPage"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Page.DataContext>
|
<Page.DataContext>
|
||||||
<viewModels:AboutVm/>
|
<viewModels:AboutVm/>
|
||||||
</Page.DataContext>
|
</Page.DataContext>
|
||||||
|
|
||||||
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="10,0,0,0">
|
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="10,0,0,0">
|
||||||
<Run Text="{Binding Name}"/>
|
<Run Text="{Binding Name}" />
|
||||||
<Run Text="version"/>
|
<Run Text="version" />
|
||||||
<Run Text="{Binding Version}" />
|
<Run Text="{Binding Version}" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="30,0,0,0">
|
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="30,0,0,0">
|
||||||
@@ -23,7 +22,7 @@
|
|||||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="30,0,0,0">
|
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="30,0,0,0">
|
||||||
<Run x:Uid="AboutHomepage" />
|
<Run x:Uid="AboutHomepage" />
|
||||||
<Hyperlink NavigateUri="https://wismna.github.io/ModernKeePass/">
|
<Hyperlink NavigateUri="https://wismna.github.io/ModernKeePass/">
|
||||||
<Run Text="https://wismna.github.io/ModernKeePass/"/>
|
<Run Text="https://wismna.github.io/ModernKeePass/" />
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="10,0,0,0">
|
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="10,0,0,0">
|
||||||
|
@@ -20,10 +20,10 @@
|
|||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Text="Import" Style="{StaticResource SubheaderTextBlockStyle}" />
|
<TextBlock Text="Import" Style="{StaticResource SubheaderTextBlockStyle}" />
|
||||||
<HyperlinkButton Grid.Column="0" Grid.Row="1" Content="Select file..." Style="{StaticResource MainColorHyperlinkButton}" Click="ImportFileButton_OnClick" />
|
<HyperlinkButton Grid.Column="0" Grid.Row="1" Content="Select file..." />
|
||||||
<StackPanel Grid.Column="1" Grid.Row="1" >
|
<StackPanel Grid.Column="1" Grid.Row="1" >
|
||||||
<TextBlock Text="Format" Style="{StaticResource BodyTextBlockStyle}" Margin="0,0,0,10" />
|
<TextBlock Text="Format" Style="{StaticResource BodyTextBlockStyle}" Margin="0,0,0,10" />
|
||||||
<ComboBox Style="{StaticResource MainColorComboBox}">
|
<ComboBox>
|
||||||
<ComboBoxItem>CSV</ComboBoxItem>
|
<ComboBoxItem>CSV</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -32,6 +32,6 @@
|
|||||||
<RadioButton GroupName="ImportDestination" Content="New database" />
|
<RadioButton GroupName="ImportDestination" Content="New database" />
|
||||||
<RadioButton GroupName="ImportDestination" Content="Currently opened database" />
|
<RadioButton GroupName="ImportDestination" Content="Currently opened database" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button Grid.Column="3" Grid.Row="1" Content="Import" Style="{StaticResource MainColorButton}" />
|
<Button Grid.Column="3" Grid.Row="1" Content="Import" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</Page>
|
||||||
|
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
||||||
using Windows.Storage.Pickers;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
|
|
||||||
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
|
|
||||||
|
|
||||||
namespace ModernKeePass.Views
|
namespace ModernKeePass.Views
|
||||||
{
|
{
|
||||||
@@ -15,21 +11,5 @@ namespace ModernKeePass.Views
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ImportFileButton_OnClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var picker =
|
|
||||||
new FileOpenPicker
|
|
||||||
{
|
|
||||||
ViewMode = PickerViewMode.List,
|
|
||||||
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
|
|
||||||
};
|
|
||||||
picker.FileTypeFilter.Add(".csv");
|
|
||||||
|
|
||||||
// Application now has read/write access to the picked file
|
|
||||||
var file = await picker.PickSingleFileAsync().AsTask();
|
|
||||||
if (file == null) 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
<Grid x:Name="Grid" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
|
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="40" />
|
<RowDefinition Height="40" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
|
@@ -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>
|
||||||
@@ -9,8 +7,6 @@ namespace ModernKeePass.Views
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class RecentDatabasesPage
|
public sealed partial class RecentDatabasesPage
|
||||||
{
|
{
|
||||||
private RecentVm Model => (RecentVm)DataContext;
|
|
||||||
|
|
||||||
public RecentDatabasesPage()
|
public RecentDatabasesPage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,18 +13,12 @@
|
|||||||
</StackPanel.Resources>
|
</StackPanel.Resources>
|
||||||
<TextBlock x:Uid="SettingsNewDatabaseDesc" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,0,0,10"/>
|
<TextBlock x:Uid="SettingsNewDatabaseDesc" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,0,0,10"/>
|
||||||
<ToggleSwitch x:Uid="SettingsNewDatabaseSample" IsOn="{Binding IsCreateSample, Mode=TwoWay}" />
|
<ToggleSwitch x:Uid="SettingsNewDatabaseSample" IsOn="{Binding IsCreateSample, Mode=TwoWay}" />
|
||||||
<TextBlock x:Uid="SettingsNewDatabaseKdf" Style="{StaticResource TextBlockSettingsHeaderStyle}" Margin="5,20,0,10" />
|
<StackPanel Orientation="Horizontal" Margin="5,20,0,10">
|
||||||
<Grid>
|
<TextBlock x:Uid="SettingsNewDatabaseKdf" Style="{StaticResource TextBlockSettingsHeaderStyle}" />
|
||||||
<Grid.ColumnDefinitions>
|
<Button Style="{StaticResource TextBlockButtonStyle}" Foreground="{StaticResource ButtonPointerOverForegroundThemeBrush}" Margin="0,-2,0,0">
|
||||||
<ColumnDefinition Width="Auto" />
|
<SymbolIcon Symbol="Help" RenderTransformOrigin="0.5,0.5">
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<ComboBox Grid.Column="1" ItemsSource="{Binding Source={StaticResource KeyDerivations}}" SelectedItem="{Binding DatabaseFormatVersion, Mode=TwoWay}" DisplayMemberPath="DisplayText" />
|
|
||||||
<Button Grid.Column="2" Style="{StaticResource TextBlockButtonStyle}">
|
|
||||||
<SymbolIcon Symbol="Help" RenderTransformOrigin="0.5,0.5" >
|
|
||||||
<SymbolIcon.RenderTransform>
|
<SymbolIcon.RenderTransform>
|
||||||
<CompositeTransform ScaleX="0.7" ScaleY="0.7"/>
|
<CompositeTransform ScaleX="0.6" ScaleY="0.6"/>
|
||||||
</SymbolIcon.RenderTransform>
|
</SymbolIcon.RenderTransform>
|
||||||
</SymbolIcon>
|
</SymbolIcon>
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
@@ -33,6 +27,7 @@
|
|||||||
</Flyout>
|
</Flyout>
|
||||||
</Button.Flyout>
|
</Button.Flyout>
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</StackPanel>
|
||||||
|
<ComboBox ItemsSource="{Binding Source={StaticResource KeyDerivations}}" SelectedItem="{Binding DatabaseFormatVersion, Mode=TwoWay}" DisplayMemberPath="DisplayText" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Page>
|
</Page>
|
||||||
|
@@ -8,136 +8,213 @@
|
|||||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||||
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
|
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
|
||||||
xmlns:converters="using:ModernKeePass.Converters"
|
xmlns:converters="using:ModernKeePass.Converters"
|
||||||
|
xmlns:actions="using:ModernKeePass.Actions"
|
||||||
|
xmlns:controls="using:ModernKeePass.Controls"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:IconToSymbolConverter x:Key="IconToSymbolConverter"/>
|
<converters:IconToSymbolConverter x:Key="IconToSymbolConverter"/>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<ListView
|
<Grid HorizontalAlignment="Left">
|
||||||
ItemsSource="{Binding ItemsSource, ElementName=UserControl}"
|
<VisualStateManager.VisualStateGroups>
|
||||||
SelectionChanged="Selector_OnSelectionChanged"
|
<VisualStateGroup x:Name="VisibilityStates">
|
||||||
SelectedItem="{Binding SelectedItem, ElementName=UserControl, Mode=TwoWay}"
|
<VisualState x:Name="Hidden">
|
||||||
SelectedIndex="{Binding SelectedIndex, ElementName=UserControl, Mode=TwoWay}"
|
<Storyboard>
|
||||||
IsSwipeEnabled="false"
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ListView" Storyboard.TargetProperty="Visibility">
|
||||||
IsSynchronizedWithCurrentItem="False"
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
||||||
RequestedTheme="Dark"
|
</ObjectAnimationUsingKeyFrames>
|
||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderTextBlock" Storyboard.TargetProperty="Visibility">
|
||||||
Foreground="{ThemeResource TextColorLightBrush}"
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
||||||
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<ListView.Resources>
|
</Storyboard>
|
||||||
<DataTemplate x:Name="IsSpecial">
|
</VisualState>
|
||||||
<StackPanel Orientation="Horizontal">
|
<VisualState x:Name="Collapsed">
|
||||||
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IconToSymbolConverter}, ConverterParameter=48}" Margin="7,15,0,15">
|
<Storyboard>
|
||||||
<ToolTipService.ToolTip>
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ListView" Storyboard.TargetProperty="Visibility">
|
||||||
<ToolTip Content="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||||
</ToolTipService.ToolTip>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</SymbolIcon>
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ListView" Storyboard.TargetProperty="Width">
|
||||||
<TextBlock Text="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" x:Name="GroupTextBlock" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="30,0,20,0" FontStyle="Italic" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource MenuWidth}"/>
|
||||||
</StackPanel>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</DataTemplate>
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderTextBlock" Storyboard.TargetProperty="Visibility">
|
||||||
<DataTemplate x:Name="IsNormal">
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
||||||
<StackPanel Orientation="Horizontal">
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IconToSymbolConverter}, ConverterParameter=48}" Margin="7,15,0,15">
|
</Storyboard>
|
||||||
<ToolTipService.ToolTip>
|
</VisualState>
|
||||||
<ToolTip Content="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" />
|
<VisualState x:Name="Expanded">
|
||||||
</ToolTipService.ToolTip>
|
<Storyboard>
|
||||||
</SymbolIcon>
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ListView" Storyboard.TargetProperty="Visibility">
|
||||||
<TextBlock Text="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" x:Name="GroupTextBlock" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="30,0,20,0" />
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||||
</StackPanel>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</DataTemplate>
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ListView" Storyboard.TargetProperty="Width">
|
||||||
</ListView.Resources>
|
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ExpandedMenuSize}"/>
|
||||||
<ListView.ItemTemplateSelector>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<templateSelectors:SelectableDataTemplateSelector FalseItem="{StaticResource IsNormal}" TrueItem="{StaticResource IsSpecial}" />
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderTextBlock" Storyboard.TargetProperty="Visibility">
|
||||||
</ListView.ItemTemplateSelector>
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||||
<ListView.HeaderTemplate>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
<DataTemplate>
|
</Storyboard>
|
||||||
<StackPanel Orientation="Horizontal">
|
</VisualState>
|
||||||
<ToggleButton Style="{StaticResource HamburgerToggleButton}" IsChecked="{Binding IsOpen, ElementName=UserControl}">
|
</VisualStateGroup>
|
||||||
<ToolTipService.ToolTip>
|
</VisualStateManager.VisualStateGroups>
|
||||||
<ToolTip Content="{Binding HeaderLabel, ElementName=UserControl}" />
|
<Grid.RowDefinitions>
|
||||||
</ToolTipService.ToolTip>
|
<RowDefinition Height="{StaticResource MenuHeightGridLength}" />
|
||||||
<interactivity:Interaction.Behaviors>
|
<RowDefinition Height="*" />
|
||||||
<core:EventTriggerBehavior EventName="Checked">
|
</Grid.RowDefinitions>
|
||||||
<core:ChangePropertyAction PropertyName="Width" Value="{StaticResource ExpandedMenuSize}" TargetObject="{Binding ResizeTarget, ElementName=UserControl}"/>
|
<StackPanel Orientation="Horizontal">
|
||||||
</core:EventTriggerBehavior>
|
<ToggleButton Style="{StaticResource HamburgerToggleButton}" IsChecked="{Binding IsOpen, ElementName=UserControl}" Unchecked="ToggleButton_OnUnchecked">
|
||||||
<core:EventTriggerBehavior EventName="Unchecked">
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:ChangePropertyAction PropertyName="Width" Value="{StaticResource MenuSize}" TargetObject="{Binding ResizeTarget, ElementName=UserControl}"/>
|
<core:EventTriggerBehavior EventName="Checked">
|
||||||
</core:EventTriggerBehavior>
|
<core:GoToStateAction StateName="Expanded" />
|
||||||
</interactivity:Interaction.Behaviors>
|
</core:EventTriggerBehavior>
|
||||||
</ToggleButton>
|
</interactivity:Interaction.Behaviors>
|
||||||
<TextBlock Text="{Binding HeaderLabel, ElementName=UserControl}" FontWeight="Bold" FontSize="18" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="30,0,20,0" HorizontalAlignment="Center" />
|
</ToggleButton>
|
||||||
</StackPanel>
|
<TextBlock
|
||||||
</DataTemplate>
|
x:Name="HeaderTextBlock"
|
||||||
</ListView.HeaderTemplate>
|
Text="{Binding HeaderLabel, ElementName=UserControl}"
|
||||||
<ListView.FooterTemplate>
|
FontWeight="Bold"
|
||||||
<DataTemplate>
|
FontSize="18"
|
||||||
<StackPanel Orientation="Vertical">
|
TextWrapping="NoWrap"
|
||||||
<Border BorderBrush="White" BorderThickness="0,0,0,1" />
|
VerticalAlignment="Center"
|
||||||
<Button Padding="0" Margin="0"
|
Margin="30,0,20,0"
|
||||||
Height="{StaticResource MenuSize}"
|
HorizontalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
<ListView
|
||||||
|
x:Name="ListView"
|
||||||
|
Grid.Row="1"
|
||||||
|
ItemsSource="{Binding ItemsSource, ElementName=UserControl}"
|
||||||
|
SelectionChanged="Selector_OnSelectionChanged"
|
||||||
|
SelectedItem="{Binding SelectedItem, ElementName=UserControl, Mode=TwoWay}"
|
||||||
|
SelectedIndex="{Binding SelectedIndex, ElementName=UserControl, Mode=TwoWay}"
|
||||||
|
IsSwipeEnabled="false"
|
||||||
|
IsSynchronizedWithCurrentItem="False"
|
||||||
|
Background="{ThemeResource AppBarBackgroundThemeBrush}"
|
||||||
|
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
|
||||||
|
<ListView.Resources>
|
||||||
|
<DataTemplate x:Name="IsSpecial">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IconToSymbolConverter}, ConverterParameter=48}" Margin="7,15,0,15">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip Content="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</SymbolIcon>
|
||||||
|
<TextBlock Text="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" x:Name="GroupTextBlock" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="30,0,20,0" FontStyle="Italic" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
<DataTemplate x:Name="IsNormal">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<SymbolIcon Symbol="{Binding Icon, Converter={StaticResource IconToSymbolConverter}, ConverterParameter=48}" Margin="7,15,0,15">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip Content="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</SymbolIcon>
|
||||||
|
<TextBlock Text="{Binding Path={Binding DisplayMemberPath, ElementName=UserControl}}" x:Name="GroupTextBlock" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="30,0,20,0" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.Resources>
|
||||||
|
<ListView.ItemTemplateSelector>
|
||||||
|
<templateSelectors:SelectableDataTemplateSelector FalseItem="{StaticResource IsNormal}" TrueItem="{StaticResource IsSpecial}" />
|
||||||
|
</ListView.ItemTemplateSelector>
|
||||||
|
<ListView.HeaderTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Vertical" Visibility="{Binding IsButtonVisible, ElementName=UserControl}">
|
||||||
|
<Button x:Name="NewGroupButton"
|
||||||
|
Padding="0" Margin="0"
|
||||||
|
Height="{StaticResource MenuWidth}"
|
||||||
Visibility="{Binding IsButtonVisible, ElementName=UserControl}"
|
Visibility="{Binding IsButtonVisible, ElementName=UserControl}"
|
||||||
Style="{StaticResource NoBorderButtonStyle}"
|
Style="{StaticResource NoBorderButtonStyle}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
Foreground="{ThemeResource TextColorLightBrush}"
|
|
||||||
BorderThickness="0"
|
|
||||||
Width="{StaticResource ExpandedMenuSize}"
|
|
||||||
HorizontalContentAlignment="Left"
|
|
||||||
Command="{Binding ActionButtonCommand, ElementName=UserControl}">
|
|
||||||
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
|
||||||
<SymbolIcon Symbol="Add">
|
|
||||||
<ToolTipService.ToolTip>
|
|
||||||
<ToolTip Content="{Binding ButtonLabel, ElementName=UserControl}" />
|
|
||||||
</ToolTipService.ToolTip>
|
|
||||||
</SymbolIcon>
|
|
||||||
<TextBlock Text="{Binding ButtonLabel, ElementName=UserControl}" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
|
||||||
</StackPanel>
|
|
||||||
</Button>
|
|
||||||
<Button Padding="0" Margin="0"
|
|
||||||
Height="{StaticResource MenuSize}"
|
|
||||||
Style="{StaticResource NoBorderButtonStyle}"
|
|
||||||
Foreground="{ThemeResource TextColorLightBrush}"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
Width="{StaticResource ExpandedMenuSize}"
|
Width="{StaticResource ExpandedMenuSize}"
|
||||||
HorizontalContentAlignment="Left">
|
HorizontalContentAlignment="Left">
|
||||||
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
||||||
<SymbolIcon Symbol="Home">
|
<SymbolIcon Symbol="Add">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<ToolTip x:Uid="HamburgerMenuHomeTooltip" />
|
<ToolTip Content="{Binding ButtonLabel, ElementName=UserControl}" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
</SymbolIcon>
|
</SymbolIcon>
|
||||||
<TextBlock x:Uid="HamburgerMenuHomeLabel" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
<TextBlock Text="{Binding ButtonLabel, ElementName=UserControl}" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
<core:NavigateToPageAction TargetPage="ModernKeePass.Views.MainPage" />
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupTextBox}" PropertyName="Visibility" Value="Visible" />
|
||||||
</core:EventTriggerBehavior>
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupButton}" PropertyName="Visibility" Value="Collapsed" />
|
||||||
</interactivity:Interaction.Behaviors>
|
<actions:SetupFocusAction TargetObject="{Binding ElementName=NewGroupTextBox}" />
|
||||||
</Button>
|
</core:EventTriggerBehavior>
|
||||||
<Button
|
</interactivity:Interaction.Behaviors>
|
||||||
Padding="0" Margin="0"
|
</Button>
|
||||||
Height="{StaticResource MenuSize}"
|
<controls:TextBoxWithButton
|
||||||
Style="{StaticResource NoBorderButtonStyle}"
|
x:Uid="NewGroupTextBox"
|
||||||
Foreground="{ThemeResource TextColorLightBrush}"
|
x:Name="NewGroupTextBox"
|
||||||
Background="Transparent"
|
Margin="0,5,0,5"
|
||||||
BorderThickness="0"
|
Visibility="Collapsed"
|
||||||
Width="{StaticResource ExpandedMenuSize}"
|
Width="280"
|
||||||
HorizontalContentAlignment="Left">
|
HorizontalAlignment="Center"
|
||||||
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
ButtonCommand="{Binding ActionButtonCommand, ElementName=UserControl}"
|
||||||
<SymbolIcon Symbol="Setting">
|
ButtonCommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}"
|
||||||
<ToolTipService.ToolTip>
|
Style="{StaticResource TextBoxWithButtonStyle}"
|
||||||
<ToolTip x:Uid="HamburgerMenuSettingsTooltip" />
|
KeyDown="NewGroupTextBox_OnKeyDown"
|
||||||
</ToolTipService.ToolTip>
|
ButtonSymbol="">
|
||||||
</SymbolIcon>
|
<interactivity:Interaction.Behaviors>
|
||||||
<TextBlock x:Uid="HamburgerMenuSettingsLabel" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
<core:EventTriggerBehavior EventName="LostFocus">
|
||||||
</StackPanel>
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupButton}" PropertyName="Visibility" Value="Visible" />
|
||||||
<interactivity:Interaction.Behaviors>
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupTextBox}" PropertyName="Visibility" Value="Collapsed" />
|
||||||
<core:EventTriggerBehavior EventName="Click">
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=NewGroupTextBox}" PropertyName="Text" Value="" />
|
||||||
<core:NavigateToPageAction TargetPage="ModernKeePass.Views.SettingsPage" />
|
</core:EventTriggerBehavior>
|
||||||
</core:EventTriggerBehavior>
|
</interactivity:Interaction.Behaviors>
|
||||||
</interactivity:Interaction.Behaviors>
|
</controls:TextBoxWithButton>
|
||||||
</Button>
|
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.FooterTemplate>
|
</ListView.HeaderTemplate>
|
||||||
</ListView>
|
<ListView.FooterTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<Border BorderBrush="DarkGray" BorderThickness="0,0,0,1" />
|
||||||
|
<Button Padding="0" Margin="0"
|
||||||
|
Height="{StaticResource MenuWidth}"
|
||||||
|
Style="{StaticResource NoBorderButtonStyle}"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
Width="{StaticResource ExpandedMenuSize}"
|
||||||
|
HorizontalContentAlignment="Left">
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
||||||
|
<SymbolIcon Symbol="Home">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip x:Uid="HamburgerMenuHomeTooltip" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</SymbolIcon>
|
||||||
|
<TextBlock x:Uid="HamburgerMenuHomeLabel" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
||||||
|
</StackPanel>
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
|
<core:NavigateToPageAction TargetPage="ModernKeePass.Views.MainPage" />
|
||||||
|
</core:EventTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
Padding="0" Margin="0"
|
||||||
|
Height="{StaticResource MenuWidth}"
|
||||||
|
Style="{StaticResource NoBorderButtonStyle}"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
Width="{StaticResource ExpandedMenuSize}"
|
||||||
|
HorizontalContentAlignment="Left">
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="17,0,5,0">
|
||||||
|
<SymbolIcon Symbol="Setting">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip x:Uid="HamburgerMenuSettingsTooltip" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</SymbolIcon>
|
||||||
|
<TextBlock x:Uid="HamburgerMenuSettingsLabel" FontWeight="SemiBold" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="30,0,20,0" />
|
||||||
|
</StackPanel>
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
|
<core:NavigateToPageAction TargetPage="ModernKeePass.Views.SettingsPage" />
|
||||||
|
</core:EventTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.FooterTemplate>
|
||||||
|
</ListView>
|
||||||
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using Windows.System;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Input;
|
||||||
using ModernKeePass.Application.Common.Interfaces;
|
using ModernKeePass.Application.Common.Interfaces;
|
||||||
|
using ModernKeePass.Controls;
|
||||||
|
|
||||||
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
|
||||||
|
|
||||||
@@ -11,11 +14,6 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
{
|
{
|
||||||
public sealed partial class HamburgerMenuUserControl
|
public sealed partial class HamburgerMenuUserControl
|
||||||
{
|
{
|
||||||
public HamburgerMenuUserControl()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string HeaderLabel
|
public string HeaderLabel
|
||||||
{
|
{
|
||||||
get { return (string)GetValue(HeaderLabelProperty); }
|
get { return (string)GetValue(HeaderLabelProperty); }
|
||||||
@@ -51,19 +49,7 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
typeof(string),
|
typeof(string),
|
||||||
typeof(HamburgerMenuUserControl),
|
typeof(HamburgerMenuUserControl),
|
||||||
new PropertyMetadata("Title", (o, args) => { }));
|
new PropertyMetadata("Title", (o, args) => { }));
|
||||||
|
|
||||||
public object ResizeTarget
|
|
||||||
{
|
|
||||||
get { return GetValue(ResizeTargetProperty); }
|
|
||||||
set { SetValue(ResizeTargetProperty, value); }
|
|
||||||
}
|
|
||||||
public static readonly DependencyProperty ResizeTargetProperty =
|
|
||||||
DependencyProperty.Register(
|
|
||||||
nameof(ResizeTarget),
|
|
||||||
typeof(object),
|
|
||||||
typeof(HamburgerMenuUserControl),
|
|
||||||
new PropertyMetadata(null, (o, args) => { }));
|
|
||||||
|
|
||||||
public Visibility IsButtonVisible
|
public Visibility IsButtonVisible
|
||||||
{
|
{
|
||||||
get { return (Visibility)GetValue(IsButtonVisibleProperty); }
|
get { return (Visibility)GetValue(IsButtonVisibleProperty); }
|
||||||
@@ -112,7 +98,7 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
typeof(int),
|
typeof(int),
|
||||||
typeof(HamburgerMenuUserControl),
|
typeof(HamburgerMenuUserControl),
|
||||||
new PropertyMetadata(-1, (o, args) => { }));
|
new PropertyMetadata(-1, (o, args) => { }));
|
||||||
|
|
||||||
public bool IsOpen
|
public bool IsOpen
|
||||||
{
|
{
|
||||||
get { return (bool)GetValue(IsOpenProperty); }
|
get { return (bool)GetValue(IsOpenProperty); }
|
||||||
@@ -136,12 +122,33 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
typeof(ICommand),
|
typeof(ICommand),
|
||||||
typeof(HamburgerMenuUserControl),
|
typeof(HamburgerMenuUserControl),
|
||||||
new PropertyMetadata(null, (o, args) => { }));
|
new PropertyMetadata(null, (o, args) => { }));
|
||||||
|
|
||||||
|
|
||||||
public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
|
public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
|
||||||
|
|
||||||
|
public HamburgerMenuUserControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
SelectionChanged?.Invoke(sender, e);
|
SelectionChanged?.Invoke(sender, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ToggleButton_OnUnchecked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var parent = Parent as FrameworkElement;
|
||||||
|
if (parent == null) return;
|
||||||
|
VisualStateManager.GoToState(this, parent.ActualWidth <= 640 ? "Hidden" : "Collapsed", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NewGroupTextBox_OnKeyDown(object sender, KeyRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key != VirtualKey.Enter) return;
|
||||||
|
var textBox = sender as TextBoxWithButton;
|
||||||
|
ActionButtonCommand.Execute(textBox?.Text);
|
||||||
|
// Stop the event from triggering twice
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -39,9 +39,8 @@
|
|||||||
<CheckBox Grid.Row="1" Grid.Column="0" IsChecked="{Binding HasKeyFile, Mode=TwoWay}" />
|
<CheckBox Grid.Row="1" Grid.Column="0" IsChecked="{Binding HasKeyFile, Mode=TwoWay}" />
|
||||||
<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}"
|
||||||
IsEnabled="{Binding HasKeyFile}"
|
Command="{Binding OpenKeyFileCommand}" />
|
||||||
Click="KeyFileButton_Click" />
|
|
||||||
|
|
||||||
<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"
|
||||||
@@ -79,6 +78,7 @@
|
|||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<!-- TODO: Correct the Runtime template binding error (even though it is actually working as intended) -->
|
||||||
<core:DataTriggerBehavior Binding="{Binding IsError}" Value="True">
|
<core:DataTriggerBehavior Binding="{Binding IsError}" Value="True">
|
||||||
<core:GoToStateAction StateName="Error"/>
|
<core:GoToStateAction StateName="Error"/>
|
||||||
</core:DataTriggerBehavior>
|
</core:DataTriggerBehavior>
|
||||||
|
@@ -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,23 +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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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" />
|
||||||
@@ -35,17 +35,13 @@
|
|||||||
x:Uid="CompositeKeyPassword"
|
x:Uid="CompositeKeyPassword"
|
||||||
x:Name="PasswordBox"
|
x:Name="PasswordBox"
|
||||||
Password="{Binding Password, Mode=TwoWay}"
|
Password="{Binding Password, Mode=TwoWay}"
|
||||||
IsPasswordRevealButtonEnabled="True" >
|
IsEnabled="{Binding HasPassword}"
|
||||||
<interactivity:Interaction.Behaviors>
|
IsPasswordRevealButtonEnabled="True" />
|
||||||
<core:EventTriggerBehavior EventName="GotFocus">
|
|
||||||
<core:ChangePropertyAction TargetObject="{Binding}" PropertyName="HasPassword" Value="True" />
|
|
||||||
</core:EventTriggerBehavior>
|
|
||||||
</interactivity:Interaction.Behaviors>
|
|
||||||
</PasswordBox>
|
|
||||||
<PasswordBox Grid.Row="1" Grid.Column="1" Height="30"
|
<PasswordBox Grid.Row="1" Grid.Column="1" Height="30"
|
||||||
x:Uid="CompositeKeyConfirmPassword"
|
x:Uid="CompositeKeyConfirmPassword"
|
||||||
x:Name="ConfirmPasswordBox"
|
x:Name="ConfirmPasswordBox"
|
||||||
Password="{Binding ConfirmPassword, Mode=TwoWay}"
|
Password="{Binding ConfirmPassword, Mode=TwoWay}"
|
||||||
|
IsEnabled="{Binding HasPassword}"
|
||||||
IsPasswordRevealButtonEnabled="True" />
|
IsPasswordRevealButtonEnabled="True" />
|
||||||
<ProgressBar Grid.Row="1" Grid.Column="1"
|
<ProgressBar Grid.Row="1" Grid.Column="1"
|
||||||
Maximum="128" VerticalAlignment="Bottom"
|
Maximum="128" VerticalAlignment="Bottom"
|
||||||
@@ -61,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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,15 +4,18 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
|
||||||
|
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
|
||||||
|
xmlns:actions="using:ModernKeePass.Actions"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<Style BasedOn="{StaticResource NoBorderButtonStyle}" TargetType="Button" x:Key="MenuButtonStyle" >
|
<Style BasedOn="{StaticResource NoBorderButtonStyle}" TargetType="Button" x:Key="MenuButtonStyle" >
|
||||||
<Setter Property="Padding" Value="25,0,25,0" />
|
<Setter Property="Padding" Value="25,0,25,0" />
|
||||||
<Setter Property="Height" Value="{StaticResource MenuSize}" />
|
<Setter Property="Height" Value="{StaticResource MenuHeight}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style BasedOn="{StaticResource NoBorderToggleButtonStyle}" TargetType="ToggleButton" x:Key="MenuToggleButtonStyle" >
|
<Style BasedOn="{StaticResource NoBorderToggleButtonStyle}" TargetType="ToggleButton" x:Key="MenuToggleButtonStyle" >
|
||||||
<Setter Property="Padding" Value="25,0,25,0" />
|
<Setter Property="Padding" Value="25,0,25,0" />
|
||||||
<Setter Property="Height" Value="{StaticResource MenuSize}" />
|
<Setter Property="Height" Value="{StaticResource MenuHeight}" />
|
||||||
</Style>
|
</Style>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<StackPanel x:Name="StackPanel" Orientation="Horizontal" DataContext="{Binding Source={StaticResource Locator}, Path=TopMenu}">
|
<StackPanel x:Name="StackPanel" Orientation="Horizontal" DataContext="{Binding Source={StaticResource Locator}, Path=TopMenu}">
|
||||||
@@ -26,6 +29,9 @@
|
|||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="MoreButton" Storyboard.TargetProperty="Visibility">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="MoreButton" Storyboard.TargetProperty="Visibility">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SearchButtonLabel" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
<VisualState x:Name="Collapsed">
|
<VisualState x:Name="Collapsed">
|
||||||
@@ -36,6 +42,9 @@
|
|||||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="MoreButton" Storyboard.TargetProperty="Visibility">
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="MoreButton" Storyboard.TargetProperty="Visibility">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SearchButtonLabel" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
@@ -56,13 +65,12 @@
|
|||||||
</SymbolIcon>
|
</SymbolIcon>
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout Opening="MoveButtonFlyout_OnOpening">
|
<Flyout Opening="MoveButtonFlyout_OnOpening">
|
||||||
<StackPanel>
|
<StackPanel Background="Transparent">
|
||||||
<SearchBox x:Uid="GroupsSearch"
|
<SearchBox x:Uid="GroupsSearch"
|
||||||
Padding="12" Width="350"
|
Width="250"
|
||||||
Margin="0,5,0,5"
|
Margin="0,5,0,5"
|
||||||
FontSize="15"
|
SuggestionsRequested="GroupSearchBox_OnSuggestionsRequested"
|
||||||
SuggestionsRequested="SearchBox_OnSuggestionsRequested"
|
ResultSuggestionChosen="GroupSearchBox_OnResultSuggestionChosen"
|
||||||
ResultSuggestionChosen="SearchBox_OnResultSuggestionChosen"
|
|
||||||
SearchHistoryEnabled="False">
|
SearchHistoryEnabled="False">
|
||||||
</SearchBox>
|
</SearchBox>
|
||||||
<Button x:Name="MoveButton" x:Uid="MoveButton" />
|
<Button x:Name="MoveButton" x:Uid="MoveButton" />
|
||||||
@@ -104,6 +112,38 @@
|
|||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
</SymbolIcon>
|
</SymbolIcon>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button x:Name="SearchButton" Style="{StaticResource NoBorderButtonStyle}" Height="{StaticResource MenuHeight}" Padding="25,0,25,0">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<SymbolIcon Symbol="Find" />
|
||||||
|
<TextBlock x:Uid="SearchButtonLabel" x:Name="SearchButtonLabel" TextWrapping="NoWrap" FontSize="16" VerticalAlignment="Center" Margin="10,0,0,0" />
|
||||||
|
</StackPanel>
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip x:Uid="SearchButtonTooltip" />
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<core:EventTriggerBehavior EventName="Click">
|
||||||
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchBox}" PropertyName="Visibility" Value="Visible" />
|
||||||
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchButton}" PropertyName="Visibility" Value="Collapsed" />
|
||||||
|
<actions:SetupFocusAction TargetObject="{Binding ElementName=SearchBox}" />
|
||||||
|
</core:EventTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
</Button>
|
||||||
|
<SearchBox
|
||||||
|
x:Uid="EntriesSearch"
|
||||||
|
x:Name="SearchBox"
|
||||||
|
Margin="0,5,0,5"
|
||||||
|
Width="350"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
SuggestionsRequested="EntrySearchBox_OnSuggestionsRequested"
|
||||||
|
SearchHistoryEnabled="False"
|
||||||
|
ResultSuggestionChosen="EntrySearchBox_OnResultSuggestionChosen">
|
||||||
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<core:EventTriggerBehavior EventName="LostFocus">
|
||||||
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchBox}" PropertyName="Visibility" Value="Collapsed" />
|
||||||
|
<core:ChangePropertyAction TargetObject="{Binding ElementName=SearchButton}" PropertyName="Visibility" Value="Visible" />
|
||||||
|
</core:EventTriggerBehavior>
|
||||||
|
</interactivity:Interaction.Behaviors>
|
||||||
|
</SearchBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button x:Name="MoreButton" Style="{StaticResource MenuButtonStyle}">
|
<Button x:Name="MoreButton" Style="{StaticResource MenuButtonStyle}">
|
||||||
<SymbolIcon Symbol="More" />
|
<SymbolIcon Symbol="More" />
|
||||||
|
@@ -194,7 +194,7 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
SortGroupsButtonFlyout.Command = SortGroupsCommand;
|
SortGroupsButtonFlyout.Command = SortGroupsCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
|
private void GroupSearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
|
||||||
{
|
{
|
||||||
var imageUri = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appdata://Assets/ModernKeePass-SmallLogo.scale-80.png"));
|
var imageUri = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appdata://Assets/ModernKeePass-SmallLogo.scale-80.png"));
|
||||||
var groups = Model.Groups.Where(g => g.Title.IndexOf(args.QueryText, StringComparison.OrdinalIgnoreCase) >= 0).Take(5);
|
var groups = Model.Groups.Where(g => g.Title.IndexOf(args.QueryText, StringComparison.OrdinalIgnoreCase) >= 0).Take(5);
|
||||||
@@ -209,10 +209,26 @@ namespace ModernKeePass.Views.UserControls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SearchBox_OnResultSuggestionChosen(SearchBox sender, SearchBoxResultSuggestionChosenEventArgs args)
|
private void GroupSearchBox_OnResultSuggestionChosen(SearchBox sender, SearchBoxResultSuggestionChosenEventArgs args)
|
||||||
{
|
{
|
||||||
MoveButton.CommandParameter = args.Tag;
|
MoveButton.CommandParameter = args.Tag;
|
||||||
MoveCommand.RaiseCanExecuteChanged();
|
MoveCommand.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async void EntrySearchBox_OnSuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
|
||||||
|
{
|
||||||
|
var imageUri = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appdata://Assets/ModernKeePass-SmallLogo.scale-80.png"));
|
||||||
|
var results = (await Model.Search(args.QueryText)).Take(5);
|
||||||
|
foreach (var result in results)
|
||||||
|
{
|
||||||
|
args.Request.SearchSuggestionCollection.AppendResultSuggestion(result.Title, result.ParentGroupName, result.Id, imageUri, string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EntrySearchBox_OnResultSuggestionChosen(SearchBox sender, SearchBoxResultSuggestionChosenEventArgs args)
|
||||||
|
{
|
||||||
|
Model.GoToEntry(args.Tag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
Database corruption issues should now be a thing of the past:
|
Redesign of the UI (top menu and hamburger menu)
|
||||||
Database integrity is checked after each save
|
Resuming the app re-opens previously opened database
|
||||||
Data is written to the filesystem using a transactional model (meaning: if an error occurs, the original file is left untouched)
|
Notify user and show the Save As dialog when an error is encountered during saving
|
||||||
Auto-save on suspend/exit is now only active when database has changes and its size is under 1MB
|
Save As actually works now
|
||||||
Added the ability to move entries and groups
|
Creating a new group is now done inline
|
||||||
Allows restoring and deleting from entry history
|
|
||||||
Updated KeePass lib to version 2.44
|
|
@@ -1,7 +1,5 @@
|
|||||||
Les problemes de corruption de bases de donn<6E>es sont maintenant totalement corrigees :
|
Redesign de l'interface utilisateur (menu superieur et menu hamburger)
|
||||||
L'integrite de la base de donnees est verfiee apres chaque sauvegarde
|
Le re-chargement de l'app re-ouvre la base de donnees ouverte precedemment
|
||||||
Les donnees sont ecrites dans le systeme de fichiers en utilisant un modele transactionnel (autrement dit, s'il y a une erreur, le fichier original n'est pas modifie)
|
L'utlisateur est prevenu et un popup de sauvegarde est affiche quand il y a une erreur de sauvegarde
|
||||||
L'auto-sauvegarde lors de la suspension/sortie ne se fait que lorsqu'il y a eu des changements et que la taille de la base de donnees est inferieure a 1MB
|
La fonctionnalite Sauvegarder Sous fonctionne correctement
|
||||||
Possibilite de deplacer des groupes et des entree
|
La creation d'un nouveau groupe se fait directement dans le menu
|
||||||
Possibilite de supprimer et restaurer des versions de l'historique d'entrees
|
|
||||||
Libraire mise a jour en version 2.44
|
|
@@ -1,4 +1,5 @@
|
|||||||
[<img src="https://geogeob.visualstudio.com/_apis/public/build/definitions/04291454-0e79-47a4-9502-5bd374804ccf/2/badge"/>](https://geogeob.visualstudio.com/_apis/public/build/index?definitionId=2)
|
[<img src="https://geogeob.visualstudio.com/_apis/public/build/definitions/04291454-0e79-47a4-9502-5bd374804ccf/2/badge"/>](https://geogeob.visualstudio.com/_apis/public/build/index?definitionId=2)
|
||||||
|
[](https://sonarcloud.io/dashboard?id=ModernKeePass)
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
**ModernKeePass** is port of the classic Windows application KeePass 2.x for the Windows Store.
|
**ModernKeePass** is port of the classic Windows application KeePass 2.x for the Windows Store.
|
||||||
@@ -17,7 +18,7 @@ You can get it [here](https://www.microsoft.com/en-us/store/p/modernkeepass/9mwq
|
|||||||
- Use Recycle Bin
|
- Use Recycle Bin
|
||||||
- Search entries
|
- Search entries
|
||||||
- Sort and reorder entries
|
- Sort and reorder entries
|
||||||
- View entries history
|
- View, delete and restore from entry history
|
||||||
- Use Semantic Zoom to see your entries in a grouped mode
|
- Use Semantic Zoom to see your entries in a grouped mode
|
||||||
- List recently opened databases
|
- List recently opened databases
|
||||||
- Open database from Windows Explorer
|
- Open database from Windows Explorer
|
||||||
@@ -29,7 +30,7 @@ You can get it [here](https://www.microsoft.com/en-us/store/p/modernkeepass/9mwq
|
|||||||
|
|
||||||
# Build and Test
|
# Build and Test
|
||||||
1. Clone the repository
|
1. Clone the repository
|
||||||
2. Build the main app (the library reference dll is actually a NuGet dependency, built from the [**ModernKeePassLib** project](../ModernKeePassLib/README.md))
|
2. Build the main app (the library reference dll is actually a NuGet dependency, built from the [**ModernKeePassLib** project](https://github.com/wismna/ModernKeePassLib))
|
||||||
3. Edit the `.appxmanifest` file to select another certificate (you can create one using Visual Studio or *certutil.exe*)
|
3. Edit the `.appxmanifest` file to select another certificate (you can create one using Visual Studio or *certutil.exe*)
|
||||||
|
|
||||||
# Contribute
|
# Contribute
|
||||||
@@ -43,4 +44,4 @@ Otherwise, there are still many things left to implement:
|
|||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
*Dominik Reichl* for the [KeePass application](https://keepass.info/), library and file format
|
*Dominik Reichl* for the [KeePass application](https://keepass.info/), library and file format
|
||||||
*David Lechner* for his [PCL adapatation](https://github.com/dlech/KeePass2PCL) of the KeePass Library and the correlated tests which served as an inspiration basis for my own adaptation
|
*David Lechner* for his [PCL adapatation](https://github.com/dlech/KeePass2PCL) of the KeePass Library and the related tests which served as an inspiration basis for my own adaptation
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
namespace ModernKeePass.Common
|
namespace ModernKeePass.Common
|
||||||
{
|
{
|
||||||
public class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
public class Navigation
|
public static class Navigation
|
||||||
{
|
{
|
||||||
public static string MainPage => nameof(MainPage);
|
public static string MainPage => nameof(MainPage);
|
||||||
public static string EntryPage => nameof(EntryPage);
|
public static string EntryPage => nameof(EntryPage);
|
||||||
public static string GroupPage => nameof(GroupPage);
|
public static string GroupPage => nameof(GroupPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class File
|
public static class File
|
||||||
{
|
{
|
||||||
public static int OneMegaByte => 1048576;
|
public static int OneMegaByte => 1048576;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Settings
|
public static class Settings
|
||||||
{
|
{
|
||||||
public static string SaveSuspend => nameof(SaveSuspend);
|
public static string SaveSuspend => nameof(SaveSuspend);
|
||||||
public static string Sample => nameof(Sample);
|
public static string Sample => nameof(Sample);
|
||||||
|
@@ -1,56 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Windows.UI.Popups;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Common
|
|
||||||
{
|
|
||||||
public static class MessageDialogHelper
|
|
||||||
{
|
|
||||||
public static async Task ShowActionDialog(string title, string contentText, string actionButtonText, string cancelButtonText, UICommandInvokedHandler actionCommand, UICommandInvokedHandler cancelCommand)
|
|
||||||
{
|
|
||||||
// Create the message dialog and set its content
|
|
||||||
var messageDialog = CreateBasicDialog(title, contentText, cancelButtonText, cancelCommand);
|
|
||||||
|
|
||||||
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
|
|
||||||
messageDialog.Commands.Add(new UICommand(actionButtonText, actionCommand));
|
|
||||||
|
|
||||||
// Show the message dialog
|
|
||||||
await messageDialog.ShowAsync().AsTask().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ShowErrorDialog(Exception exception)
|
|
||||||
{
|
|
||||||
if (exception == null) return;
|
|
||||||
// Create the message dialog and set its content
|
|
||||||
var messageDialog = CreateBasicDialog(exception.Message, exception.StackTrace, "OK");
|
|
||||||
|
|
||||||
// Show the message dialog
|
|
||||||
await messageDialog.ShowAsync().AsTask().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ShowNotificationDialog(string title, string message)
|
|
||||||
{
|
|
||||||
var dialog = CreateBasicDialog(title, message, "OK");
|
|
||||||
|
|
||||||
// Show the message dialog
|
|
||||||
await dialog.ShowAsync().AsTask().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MessageDialog CreateBasicDialog(string title, string message, string dismissActionText, UICommandInvokedHandler cancelCommand = null)
|
|
||||||
{
|
|
||||||
// Create the message dialog and set its content
|
|
||||||
var messageDialog = new MessageDialog(message, title);
|
|
||||||
|
|
||||||
// Add commands and set their callbacks
|
|
||||||
messageDialog.Commands.Add(new UICommand(dismissActionText, cancelCommand));
|
|
||||||
|
|
||||||
// Set the command that will be invoked by default
|
|
||||||
messageDialog.DefaultCommandIndex = 1;
|
|
||||||
|
|
||||||
// Set the command to be invoked when escape is pressed
|
|
||||||
messageDialog.CancelCommandIndex = 1;
|
|
||||||
|
|
||||||
return messageDialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -57,6 +57,18 @@ namespace ModernKeePass.Controls
|
|||||||
typeof(TextBoxWithButton),
|
typeof(TextBoxWithButton),
|
||||||
new PropertyMetadata(null, (o, args) => { }));
|
new PropertyMetadata(null, (o, args) => { }));
|
||||||
|
|
||||||
|
public string ButtonCommandParameter
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(ButtonCommandParameterProperty); }
|
||||||
|
set { SetValue(ButtonCommandParameterProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty ButtonCommandParameterProperty =
|
||||||
|
DependencyProperty.Register(
|
||||||
|
nameof(ButtonCommandParameter),
|
||||||
|
typeof(string),
|
||||||
|
typeof(TextBoxWithButton),
|
||||||
|
new PropertyMetadata(null, (o, args) => { }));
|
||||||
|
|
||||||
public bool IsButtonEnabled
|
public bool IsButtonEnabled
|
||||||
{
|
{
|
||||||
get { return (bool)GetValue(IsButtonEnabledProperty); }
|
get { return (bool)GetValue(IsButtonEnabledProperty); }
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
using ModernKeePass.Application.Database.Models;
|
namespace Messages
|
||||||
|
|
||||||
namespace Messages
|
|
||||||
{
|
{
|
||||||
public class DatabaseAlreadyOpenedMessage
|
public class DatabaseAlreadyOpenedMessage
|
||||||
{
|
{
|
||||||
|
7
WinAppCommon/Messages/DatabaseSavedMessage.cs
Normal file
7
WinAppCommon/Messages/DatabaseSavedMessage.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Messages
|
||||||
|
{
|
||||||
|
public class DatabaseSavedMessage
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -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,36 @@ 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;
|
||||||
|
private readonly IResourceProxy _resource;
|
||||||
|
|
||||||
|
public RelayCommand CreateDatabaseFileCommand { get; }
|
||||||
|
|
||||||
public NewVm(IMediator mediator, IRecentProxy recent, ISettingsProxy settings, INavigationService navigation)
|
public NewVm(IMediator mediator, ISettingsProxy settings, INavigationService navigation, IFileProxy file, IResourceProxy resource): base(file)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_navigation = navigation;
|
_navigation = navigation;
|
||||||
|
_file = file;
|
||||||
|
_resource = resource;
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
var file = await _file.CreateFile(_resource.GetResourceValue("MessageDialogSaveNameSuggestion"),
|
||||||
|
Domain.Common.Constants.Extensions.Kdbx,
|
||||||
|
_resource.GetResourceValue("MessageDialogSaveErrorFileTypeDesc"),
|
||||||
|
true);
|
||||||
|
if (file == null) return;
|
||||||
|
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 +66,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,48 +1,69 @@
|
|||||||
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)
|
private readonly IResourceProxy _resource;
|
||||||
|
|
||||||
|
public SaveVm(IMediator mediator, INavigationService navigation, IFileProxy file, IResourceProxy resource)
|
||||||
{
|
{
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_navigation = navigation;
|
_navigation = navigation;
|
||||||
|
_file = file;
|
||||||
|
_resource = resource;
|
||||||
|
|
||||||
|
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)
|
MessengerInstance.Register<DatabaseSavedMessage>(this, _ => SaveCommand.RaiseCanExecuteChanged());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveAs()
|
||||||
{
|
{
|
||||||
await _mediator.Send(new SaveDatabaseCommand());
|
var file = await _file.CreateFile(_resource.GetResourceValue("MessageDialogSaveNameSuggestion"),
|
||||||
if (close) await _mediator.Send(new CloseDatabaseCommand());
|
Domain.Common.Constants.Extensions.Kdbx,
|
||||||
|
_resource.GetResourceValue("MessageDialogSaveErrorFileTypeDesc"),
|
||||||
|
true);
|
||||||
|
if (file == null) return;
|
||||||
|
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()
|
||||||
{
|
{
|
||||||
await _mediator.Send(new CloseDatabaseCommand());
|
await _mediator.Send(new CloseDatabaseCommand());
|
||||||
|
@@ -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,7 +14,9 @@ namespace ModernKeePass.ViewModels
|
|||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly ICredentialsProxy _credentials;
|
private readonly ICredentialsProxy _credentials;
|
||||||
|
private readonly IResourceProxy _resource;
|
||||||
|
private readonly IFileProxy _file;
|
||||||
|
|
||||||
public bool HasPassword
|
public bool HasPassword
|
||||||
{
|
{
|
||||||
get { return _hasPassword; }
|
get { return _hasPassword; }
|
||||||
@@ -33,6 +37,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 +91,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,20 +102,45 @@ 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;
|
||||||
|
_resource = resource;
|
||||||
|
_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);
|
||||||
|
if (file == null) return;
|
||||||
|
SetKeyFileInfo(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CreateKeyFile()
|
||||||
|
{
|
||||||
|
var file = await _file.CreateFile(_resource.GetResourceValue("CompositeKeyFileNameSuggestion"),
|
||||||
|
Constants.Extensions.Key, _resource.GetResourceValue("CompositeKeyFileTypeDesc"),
|
||||||
|
false);
|
||||||
|
if (file == null) return;
|
||||||
|
SetKeyFileInfo(file);
|
||||||
|
|
||||||
|
await _mediator.Send(new GenerateKeyFileCommand { KeyFilePath = KeyFilePath });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetKeyFileInfo(FileInfo file)
|
||||||
|
{
|
||||||
|
KeyFilePath = file.Id;
|
||||||
|
KeyFileText = file.Name;
|
||||||
|
HasKeyFile = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void GenerateCredentials()
|
private void GenerateCredentials()
|
||||||
{
|
{
|
||||||
MessengerInstance.Send(new CredentialsSetMessage
|
MessengerInstance.Send(new CredentialsSetMessage
|
||||||
|
@@ -1,19 +1,46 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GalaSoft.MvvmLight.Views;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using ModernKeePass.Application.Database.Models;
|
||||||
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
using ModernKeePass.Application.Database.Queries.GetDatabase;
|
||||||
|
using ModernKeePass.Application.Entry.Models;
|
||||||
using ModernKeePass.Application.Group.Models;
|
using ModernKeePass.Application.Group.Models;
|
||||||
using ModernKeePass.Application.Group.Queries.GetAllGroups;
|
using ModernKeePass.Application.Group.Queries.GetAllGroups;
|
||||||
|
using ModernKeePass.Application.Group.Queries.SearchEntries;
|
||||||
|
using ModernKeePass.Common;
|
||||||
|
using ModernKeePass.Models;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
{
|
{
|
||||||
public class TopMenuVm
|
public class TopMenuVm
|
||||||
{
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
private readonly INavigationService _navigation;
|
||||||
|
private readonly DatabaseVm _database;
|
||||||
public IEnumerable<GroupVm> Groups { get; set; }
|
public IEnumerable<GroupVm> Groups { get; set; }
|
||||||
|
|
||||||
public TopMenuVm(IMediator mediator)
|
public TopMenuVm(IMediator mediator, INavigationService navigation)
|
||||||
{
|
{
|
||||||
var database = mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
|
_mediator = mediator;
|
||||||
Groups = mediator.Send(new GetAllGroupsQuery { GroupId = database.RootGroupId }).GetAwaiter().GetResult();
|
_navigation = navigation;
|
||||||
|
|
||||||
|
_database = _mediator.Send(new GetDatabaseQuery()).GetAwaiter().GetResult();
|
||||||
|
Groups = _mediator.Send(new GetAllGroupsQuery { GroupId = _database.RootGroupId }).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GoToEntry(string entryId, bool isNew = false)
|
||||||
|
{
|
||||||
|
_navigation.NavigateTo(Constants.Navigation.EntryPage, new NavigationItem
|
||||||
|
{
|
||||||
|
Id = entryId,
|
||||||
|
IsNew = isNew
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<EntryVm>> Search(string queryText)
|
||||||
|
{
|
||||||
|
return await _mediator.Send(new SearchEntriesQuery { GroupId = _database.RootGroupId, SearchText = queryText });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -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>());
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
<Compile Include="$(MSBuildThisFileDirectory)Messages\DatabaseClosedMessage.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\DatabaseClosedMessage.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Messages\DatabaseOpenedMessage.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\DatabaseOpenedMessage.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Messages\DatabaseOpeningMessage.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\DatabaseOpeningMessage.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\DatabaseSavedMessage.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Messages\FileNotFoundMessage.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\FileNotFoundMessage.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Messages\NavigateToPageMessage.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\NavigateToPageMessage.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Messages\SaveErrorMessage.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\SaveErrorMessage.cs" />
|
||||||
|
Reference in New Issue
Block a user