65 Commits
V1.6 ... V1.10

Author SHA1 Message Date
BONNEVILLE Geoffroy
13901d17ab Added FR store metadata 2017-12-12 14:59:56 +01:00
BONNEVILLE Geoffroy
19bc9005e9 Removed add-ons ordering to avoid Culture bugs - for now 2017-12-12 13:25:42 +01:00
BONNEVILLE Geoffroy
7c86a325d9 Solution metadata files correction 2017-12-12 11:56:25 +01:00
BONNEVILLE Geoffroy
d203b521c1 Small design changes
Create new database button now properly translated
Store metadata and screenshots updated
2017-12-12 11:54:15 +01:00
BONNEVILLE Geoffroy
0afa59fb66 Minor XAML changes 2017-12-11 19:13:28 +01:00
BONNEVILLE Geoffroy
470a08f4bc Entry page now wraps expiration date controls depending on page size
Group page now toggle filter box visibility depending on size, with a button and flyout on small size
Search text renamed to filter
2017-12-11 19:00:14 +01:00
BONNEVILLE Geoffroy
50c5940a0a Donations are sorted ascending 2017-12-11 11:08:33 +01:00
BONNEVILLE Geoffroy
35f64eec1b Implemented Donate page with wirking (?) in app purchases
Moved Pages to Views
2017-12-08 19:38:33 +01:00
BONNEVILLE Geoffroy
e25f9f4aae Create a LicenseService to handle in-app purchases 2017-12-07 18:49:03 +01:00
BONNEVILLE Geoffroy
a86dbf9dac New database settings version flyout now wraps text instead of showing scrollbar 2017-12-06 18:42:02 +01:00
BONNEVILLE Geoffroy
026bfcba78 New group text is now visible again in Group and Settings pages 2017-12-06 18:29:19 +01:00
BONNEVILLE Geoffroy
3b66824c58 Code cleanup 2017-12-04 18:08:42 +01:00
BONNEVILLE Geoffroy
898a9a0935 Search box now directly filters entries, no need for another drop down
TextBoxWithButton now scales button with text size and text can now be properly aligned
Corrected some French translations
2017-12-04 18:07:03 +01:00
BONNEVILLE Geoffroy
7aa342cf9c French translation added 2017-12-04 12:20:05 +01:00
BONNEVILLE Geoffroy
f173283a66 New clear all button in recent pages
First-time open of app correctly shows Welcome page
New Home button in group and entry pages
2017-12-04 10:46:01 +01:00
bg45
4f69b5cdcc Minor code refactor 2017-12-02 08:42:10 -05:00
BONNEVILLE Geoffroy
744858df81 Created a Settings Service
Created a Recent Service
Created a Resources Service
Code refactor
Updated tests
2017-12-01 17:59:38 +01:00
BONNEVILLE Geoffroy
f172e31250 Settings are now disabled instead of not present when database is closed 2017-12-01 09:31:59 +01:00
BONNEVILLE Geoffroy
7530cf8006 Groups sorting now works with new Lib
New database settings improved
2017-11-30 18:56:56 +01:00
BONNEVILLE Geoffroy
33223934e3 Sorting now works for entries (not yet for groups) 2017-11-30 11:05:47 +01:00
BONNEVILLE Geoffroy
f2731c49dd Drag drop finally works
WIP item background
New Donate page stub
Renamed some classes as services
2017-11-29 19:13:38 +01:00
bg45
227bc30dde New database setting page
(Database) Settings available from Main menu
2017-11-28 16:57:16 -05:00
BONNEVILLE Geoffroy
7b39fe79c8 WIP strings in ressource file (XAML is done, code-behind is not)
Invalid URI now shows a message
Create entry is now a link above entries
Entries gridview allows reordering (WIP enable it conditionnally)
Code cleanup in adding/removing PwEntries from VM
2017-11-28 18:53:10 +01:00
BONNEVILLE Geoffroy
fcbda1e33d Adds some VM tests
New tooltip in Textbox with button control
New welcome page in Settings (shown when noting is selected)
Settings are now grouped
2017-11-27 15:26:36 +01:00
BONNEVILLE Geoffroy
42ac04b02c Layout change in CompositeKey user control
Button text is now settable
Opening database is placed in async task dispatcher to return control to the UI
2017-11-24 18:21:06 +01:00
BONNEVILLE Geoffroy
7cd05cb1d8 Better global exception handling
Save error now shows a Save as button
Recent list now not changed at every access (only on actual file open)
Some code refactoring
2017-11-24 12:17:41 +01:00
BONNEVILLE Geoffroy
1b2d25e171 Error messages are now caught at the app level (see if it's a good solution in the long term)
Redesign of the create key file button
2017-11-23 19:02:49 +01:00
BONNEVILLE Geoffroy
675a718107 Update test project certificate 2017-11-23 15:32:44 +01:00
BONNEVILLE Geoffroy
a8f5897364 Changed VMs references to database singleton
Added some unit tests (WIP)
2017-11-23 15:26:57 +01:00
BONNEVILLE Geoffroy
5120c8177b Adding tests for App
WIP make VMs app agnostic
2017-11-22 18:54:03 +01:00
BONNEVILLE Geoffroy
f2d97b4e7e Bump to 1.10
Bug when pressing enter with invalid composite key
2017-11-21 18:45:42 +01:00
BONNEVILLE Geoffroy
197e061bc5 Update release notes 2017-11-20 18:09:20 +01:00
BONNEVILLE Geoffroy
d1a6b418d5 Added store metadata information 2017-11-20 18:08:19 +01:00
BONNEVILLE Geoffroy
e9c79b192b Finally satisfiable assets
Attempt to handle null reference exception in Key File (not sure to have found source)
2017-11-20 17:21:22 +01:00
BONNEVILLE Geoffroy
52c56757ca Correctly reference logo assets 2017-11-17 17:48:24 +01:00
BONNEVILLE Geoffroy
559af0ddd8 Clean up 2017-11-17 17:43:56 +01:00
BONNEVILLE Geoffroy
cd1b3ce1ed Changed app assets (not fully satisfied though) 2017-11-17 17:43:01 +01:00
BONNEVILLE Geoffroy
5273a25385 Adds the ability to create key files (no entropy generator for now) 2017-11-17 10:20:54 +01:00
BONNEVILLE Geoffroy
3089609c19 Code cleanup 2017-11-16 18:55:20 +01:00
BONNEVILLE Geoffroy
e1f62342d9 Update app and tests to use new ModernKeePassLib 2017-11-15 18:17:41 +01:00
BONNEVILLE Geoffroy
9313ac1abf Repaired key file creation in lib 2017-11-15 17:56:31 +01:00
7a632c8f80 Updated README.md 2017-11-15 09:35:57 +00:00
7f9a0e5b1e Updated README.md 2017-11-14 17:30:37 +00:00
BONNEVILLE Geoffroy
b0a3f796cb Merge branch 'master' of https://geogeob.visualstudio.com/_git/ModernKeePass 2017-11-14 18:00:47 +01:00
BONNEVILLE Geoffroy
97521f174a Test project uses same certificate as main App 2017-11-14 18:00:44 +01:00
432d5e49d5 Updated ImportCertificate.ps1 2017-11-14 16:26:44 +00:00
b2c8f2e0f4 Updated ImportCertificate.ps1 2017-11-14 16:22:37 +00:00
23011568b7 Updated ImportCertificate.ps1 2017-11-14 16:15:31 +00:00
078f9535cf Updated ImportCertificate.ps1 2017-11-14 16:10:28 +00:00
BONNEVILLE Geoffroy
ea481187d5 Add build scripts 2017-11-14 17:03:24 +01:00
BONNEVILLE Geoffroy
810caaf8e2 Test project uses Nuget for lib 2017-11-13 18:31:47 +01:00
BONNEVILLE Geoffroy
d290d9b4e3 Exclude certificate from project 2017-11-13 17:19:08 +01:00
BONNEVILLE Geoffroy
abb12accc7 Correct two bugs related to key file opening
Bettter error messages with composite key
Show an error message if save has failed and don't close the database
2017-11-13 11:28:14 +01:00
2779e5b7c7 Updated README.md 2017-11-09 16:54:43 +00:00
3970d485f6 Updated README.md 2017-11-09 16:53:47 +00:00
BONNEVILLE Geoffroy
7b888cc4a2 Merge branch 'master' of https://geogeob.visualstudio.com/_git/ModernKeePass 2017-11-09 13:46:15 +01:00
BONNEVILLE Geoffroy
117513d6bf Correct credits in About 2017-11-09 13:46:10 +01:00
97511ab290 Updated README.md 2017-11-09 12:43:41 +00:00
3131eca8a1 Updated README.md 2017-11-09 12:39:55 +00:00
91a5507217 Added file README.md 2017-11-09 11:16:13 +00:00
7d904b7120 Updated README.md 2017-11-09 11:08:46 +00:00
BONNEVILLE Geoffroy
be72fc4f7e Minor change for Designer 2017-11-08 18:52:48 +01:00
BONNEVILLE Geoffroy
ecba11a9a9 Version 1.7 - only difference with 1.6 is Argon2Kdf fully working 2017-11-08 18:01:50 +01:00
BONNEVILLE Geoffroy
65f2e529f4 Argon2KDF write mode works! (thanks to an option in XMLWriterSettings) 2017-11-08 17:52:00 +01:00
BONNEVILLE Geoffroy
29e7b22953 Ignored useless files 2017-11-08 17:17:11 +01:00
213 changed files with 4670 additions and 1200 deletions

2
.gitignore vendored
View File

@@ -37,3 +37,5 @@ Translation/TrlUtil.vshost.exe.manifest
packages/ packages/
project.lock.json project.lock.json
AppPackages/ AppPackages/
BundleArtifacts/
*.DotSettings

View File

@@ -9,6 +9,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePassLib", "ModernK
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePassLib.Test", "ModernKeePassLib.Test\ModernKeePassLib.Test.csproj", "{0A4279CF-2A67-4868-9906-052E50C25F3B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePassLib.Test", "ModernKeePassLib.Test\ModernKeePassLib.Test.csproj", "{0A4279CF-2A67-4868-9906-052E50C25F3B}"
EndProject EndProject
Project("{F5034706-568F-408A-B7B3-4D38C6DB8A32}") = "Scripts", "Scripts\Scripts.pssproj", "{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePassApp.Test", "ModernKeePassApp.Test\ModernKeePassApp.Test.csproj", "{7E80F5E7-724A-4668-9333-B10F5D75C6D0}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -85,6 +89,46 @@ Global
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.ActiveCfg = Release|x86 {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.ActiveCfg = Release|x86
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Build.0 = Release|x86 {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Build.0 = Release|x86
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Deploy.0 = Release|x86 {0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Deploy.0 = Release|x86
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|ARM.ActiveCfg = Debug|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|ARM.Build.0 = Debug|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|x64.ActiveCfg = Debug|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|x64.Build.0 = Debug|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|x86.ActiveCfg = Debug|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|x86.Build.0 = Debug|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.Build.0 = Release|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|ARM.ActiveCfg = Release|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|ARM.Build.0 = Release|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x64.ActiveCfg = Release|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x64.Build.0 = Release|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x86.ActiveCfg = Release|Any CPU
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x86.Build.0 = Release|Any CPU
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|ARM.ActiveCfg = Debug|ARM
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|ARM.Build.0 = Debug|ARM
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|ARM.Deploy.0 = Debug|ARM
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|x64.ActiveCfg = Debug|x64
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|x64.Build.0 = Debug|x64
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|x64.Deploy.0 = Debug|x64
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|x86.ActiveCfg = Debug|x86
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|x86.Build.0 = Debug|x86
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|x86.Deploy.0 = Debug|x86
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|Any CPU.Build.0 = Release|Any CPU
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|Any CPU.Deploy.0 = Release|Any CPU
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|ARM.ActiveCfg = Release|ARM
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|ARM.Build.0 = Release|ARM
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|ARM.Deploy.0 = Release|ARM
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x64.ActiveCfg = Release|x64
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x64.Build.0 = Release|x64
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x64.Deploy.0 = Release|x64
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x86.ActiveCfg = Release|x86
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x86.Build.0 = Release|x86
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -10,8 +10,8 @@
<ResourceDictionary Source="Styles/HamburgerButtonStyle.xaml" /> <ResourceDictionary Source="Styles/HamburgerButtonStyle.xaml" />
<ResourceDictionary Source="Styles/ListViewLeftIndicatorStyle.xaml" /> <ResourceDictionary Source="Styles/ListViewLeftIndicatorStyle.xaml" />
<ResourceDictionary Source="Styles/NoBorderButtonStyle.xaml" /> <ResourceDictionary Source="Styles/NoBorderButtonStyle.xaml" />
<ResourceDictionary Source="Styles/TextBlockStyles.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>
</Application> </Application>

View File

@@ -1,14 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Reflection;
using Windows.ApplicationModel; using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation; using Windows.ApplicationModel.Activation;
using Windows.Data.Json;
using Windows.Storage; using Windows.Storage;
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 ModernKeePass.Common; using ModernKeePass.Common;
using ModernKeePass.Interfaces; using ModernKeePass.Exceptions;
using ModernKeePass.Services;
using ModernKeePass.Views;
// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227 // The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227
@@ -19,7 +20,7 @@ namespace ModernKeePass
/// </summary> /// </summary>
sealed partial class App sealed partial class App
{ {
public DatabaseHelper Database { get; set; } = new DatabaseHelper(); public DatabaseService Database { get; private set; }
/// <summary> /// <summary>
/// Initializes the singleton application object. This is the first line of authored code /// Initializes the singleton application object. This is the first line of authored code
@@ -29,9 +30,26 @@ namespace ModernKeePass
{ {
InitializeComponent(); InitializeComponent();
Suspending += OnSuspending; Suspending += OnSuspending;
UnhandledException += OnUnhandledException;
} }
#region Event Handlers #region Event Handlers
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
// Save the argument exception because it's cleared on first access
var exception = unhandledExceptionEventArgs.Exception;
var realException =
exception is TargetInvocationException &&
exception.InnerException != null
? exception.InnerException
: exception;
if (!(realException is SaveException)) return;
unhandledExceptionEventArgs.Handled = true;
MessageDialogHelper.SaveErrorDialog(realException as SaveException, Database);
}
/// <summary> /// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points /// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file. /// will be used such as when the application is launched to open a specific file.
@@ -86,7 +104,7 @@ namespace ModernKeePass
// When the navigation stack isn't restored navigate to the first page, // When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation // configuring the new page by passing required information as a navigation
// parameter // parameter
rootFrame.Navigate(typeof(Pages.MainPage), lauchActivatedEventArgs.Arguments); rootFrame.Navigate(typeof(MainPage), lauchActivatedEventArgs.Arguments);
} }
/*else /*else
{ {
@@ -104,6 +122,7 @@ namespace ModernKeePass
}*/ }*/
// Ensure the current window is active // Ensure the current window is active
Window.Current.Activate(); Window.Current.Activate();
Database = new DatabaseService();
} }
/// <summary> /// <summary>
@@ -126,6 +145,7 @@ namespace ModernKeePass
private void OnSuspending(object sender, SuspendingEventArgs e) private void OnSuspending(object sender, SuspendingEventArgs e)
{ {
var deferral = e.SuspendingOperation.GetDeferral(); var deferral = e.SuspendingOperation.GetDeferral();
UnhandledException -= OnUnhandledException;
Database.Save(); Database.Save();
deferral.Complete(); deferral.Complete();
} }
@@ -139,10 +159,11 @@ namespace ModernKeePass
base.OnFileActivated(args); base.OnFileActivated(args);
var rootFrame = new Frame(); var rootFrame = new Frame();
Database.DatabaseFile = args.Files[0] as StorageFile; Database.DatabaseFile = args.Files[0] as StorageFile;
rootFrame.Navigate(typeof(Pages.MainPage), args); rootFrame.Navigate(typeof(MainPage), args);
Window.Current.Content = rootFrame; Window.Current.Content = rootFrame;
Window.Current.Activate(); Window.Current.Activate();
} }
#endregion #endregion
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 907 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1020 B

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 907 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1020 B

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,4 +0,0 @@
MainPackage=C:\Users\GBE\Source\Repos\ModernKeePass\ModernKeePass\bin\Release\ModernKeePassApp_1.6.0.27_AnyCPU.appx
SymbolPackage=C:\Users\GBE\Source\Repos\ModernKeePass\ModernKeePass\AppPackages\ModernKeePassApp_1.6.0.27_Test\ModernKeePassApp_1.6.0.27_AnyCPU.appxsym
ResourcePack=C:\Users\GBE\Source\Repos\ModernKeePass\ModernKeePass\bin\Release\ModernKeePassApp_1.6.0.27_scale-140.appx
ResourcePack=C:\Users\GBE\Source\Repos\ModernKeePass\ModernKeePass\bin\Release\ModernKeePassApp_1.6.0.27_scale-180.appx

View File

@@ -1,157 +0,0 @@
using System;
using Windows.Storage;
using Windows.UI.Xaml.Controls;
using ModernKeePass.ViewModels;
using ModernKeePassLib;
using ModernKeePassLib.Cryptography.KeyDerivation;
using ModernKeePassLib.Interfaces;
using ModernKeePassLib.Keys;
using ModernKeePassLib.Serialization;
namespace ModernKeePass.Common
{
public class DatabaseHelper
{
public enum DatabaseStatus
{
Closed = 0,
Opening = 1,
Opened = 2
}
private readonly PwDatabase _pwDatabase = new PwDatabase();
private StorageFile _databaseFile;
private GroupVm _recycleBin;
public GroupVm RootGroup { get; set; }
public GroupVm RecycleBin
{
get { return _recycleBin; }
set
{
_recycleBin = value;
_pwDatabase.RecycleBinUuid = _recycleBin.IdUuid;
}
}
public DatabaseStatus Status { get; private set; } = DatabaseStatus.Closed;
public string Name => DatabaseFile?.Name;
public bool RecycleBinEnabled
{
get { return _pwDatabase.RecycleBinEnabled; }
set { _pwDatabase.RecycleBinEnabled = value; }
}
public StorageFile DatabaseFile
{
get { return _databaseFile; }
set
{
_databaseFile = value;
Status = DatabaseStatus.Opening;
}
}
public PwUuid DataCipher
{
get { return _pwDatabase.DataCipherUuid; }
set { _pwDatabase.DataCipherUuid = value; }
}
public PwCompressionAlgorithm CompressionAlgorithm
{
get { return _pwDatabase.Compression; }
set { _pwDatabase.Compression = value; }
}
public KdfParameters KeyDerivation
{
get { return _pwDatabase.KdfParameters; }
set { _pwDatabase.KdfParameters = value; }
}
/// <summary>
/// Open a KeePass database
/// </summary>
/// <param name="key">The database composite key</param>
/// <param name="createNew">True to create a new database before opening it</param>
/// <returns>An error message, if any</returns>
public string Open(CompositeKey key, bool createNew = false)
{
try
{
if (key == null) return "No composite key";
var ioConnection = IOConnectionInfo.FromFile(DatabaseFile);
if (createNew) _pwDatabase.New(ioConnection, key);
else _pwDatabase.Open(ioConnection, key, new NullStatusLogger());
if (_pwDatabase.IsOpen)
{
Status = DatabaseStatus.Opened;
RootGroup = new GroupVm(_pwDatabase.RootGroup, null, RecycleBinEnabled ? _pwDatabase.RecycleBinUuid : null);
}
}
catch (ArgumentNullException)
{
return "Password cannot be empty";
}
catch (InvalidCompositeKeyException)
{
return "Wrong password";
}
catch (Exception ex)
{
return ex.Message;
}
return string.Empty;
}
/// <summary>
/// Save the current database to another file and open it
/// </summary>
/// <param name="file">The new database file</param>
internal void Save(StorageFile file)
{
DatabaseFile = file;
_pwDatabase.SaveAs(IOConnectionInfo.FromFile(DatabaseFile), true, new NullStatusLogger());
Status = DatabaseStatus.Opened;
}
/// <summary>
/// Commit the changes to the currently opened database to file
/// </summary>
public void Save()
{
// TODO: Save is disabled for now for Argon2Kdf because it corrupts DB (read works)
if (_pwDatabase == null || !_pwDatabase.IsOpen || KdfPool.Get(KeyDerivation.KdfUuid) is Argon2Kdf) return;
_pwDatabase.Save(new NullStatusLogger());
}
/// <summary>
/// Close the currently opened database
/// </summary>
public void Close()
{
_pwDatabase?.Close();
Status = DatabaseStatus.Closed;
}
public void AddDeletedItem(PwUuid id)
{
_pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow));
}
public void CreateRecycleBin()
{
RecycleBin = RootGroup.AddNewGroup("Recycle bin");
RecycleBin.IsSelected = true;
RecycleBin.IconSymbol = Symbol.Delete;
}
public void UpdateCompositeKey(CompositeKey key)
{
_pwDatabase.MasterKey = key;
}
}
}

View File

@@ -1,18 +1,68 @@
using System; using System;
using System.Collections.Generic;
using Windows.Storage.Pickers;
using Windows.UI.Popups; using Windows.UI.Popups;
using Windows.UI.Xaml.Media.Animation;
using ModernKeePass.Exceptions;
using ModernKeePass.Interfaces;
namespace ModernKeePass.Common namespace ModernKeePass.Common
{ {
public static class MessageDialogHelper public static class MessageDialogHelper
{ {
public static async void ShowDeleteConfirmationDialog(string actionText, string contentText, UICommandInvokedHandler action) public static async void ShowActionDialog(string title, string contentText, string actionButtonText, string cancelButtonText, UICommandInvokedHandler action)
{ {
// Create the message dialog and set its content // Create the message dialog and set its content
var messageDialog = new MessageDialog(contentText); var messageDialog = CreateBasicDialog(title, contentText, cancelButtonText);
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers // Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
messageDialog.Commands.Add(new UICommand(actionText, action)); messageDialog.Commands.Add(new UICommand(actionButtonText, action));
messageDialog.Commands.Add(new UICommand("Cancel"));
// Show the message dialog
await messageDialog.ShowAsync();
}
public static void SaveErrorDialog(SaveException exception, IDatabase database)
{
ShowActionDialog("Save error", exception.InnerException.Message, "Save as", "Discard", async command =>
{
var savePicker = new FileSavePicker
{
SuggestedStartLocation = PickerLocationId.DocumentsLibrary,
SuggestedFileName = $"{database.DatabaseFile.DisplayName} - copy"
};
savePicker.FileTypeChoices.Add("KeePass 2.x database", new List<string> { ".kdbx" });
var file = await savePicker.PickSaveFileAsync();
if (file != null) database.Save(file);
});
}
public static async void ShowErrorDialog(Exception exception)
{
if (exception == null) return;
// Create the message dialog and set its content
var messageDialog = CreateBasicDialog("Error occured", exception.Message, "OK");
// Show the message dialog
await messageDialog.ShowAsync();
}
public static async void ShowNotificationDialog(string title, string message)
{
var dialog = CreateBasicDialog(title, message, "OK");
// Show the message dialog
await dialog.ShowAsync();
}
private static MessageDialog CreateBasicDialog(string title, string message, string dismissActionText)
{
// 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));
// Set the command that will be invoked by default // Set the command that will be invoked by default
messageDialog.DefaultCommandIndex = 1; messageDialog.DefaultCommandIndex = 1;
@@ -20,8 +70,7 @@ namespace ModernKeePass.Common
// Set the command to be invoked when escape is pressed // Set the command to be invoked when escape is pressed
messageDialog.CancelCommandIndex = 1; messageDialog.CancelCommandIndex = 1;
// Show the message dialog return messageDialog;
await messageDialog.ShowAsync();
} }
} }
} }

View File

@@ -32,5 +32,18 @@ namespace ModernKeePass.Common
ToastNotificationManager.CreateToastNotifier().Show(toast); ToastNotificationManager.CreateToastNotifier().Show(toast);
} }
public static void ShowGenericToast(string title, string text)
{
var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
var toastElements = notificationXml.GetElementsByTagName("text");
toastElements[0].AppendChild(notificationXml.CreateTextNode(title));
toastElements[1].AppendChild(notificationXml.CreateTextNode(text));
var toast = new ToastNotification(notificationXml)
{
ExpirationTime = DateTime.Now.AddSeconds(5)
};
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
} }
} }

View File

@@ -6,18 +6,6 @@ namespace ModernKeePass.Controls
{ {
public class TextBoxWithButton : TextBox public class TextBoxWithButton : TextBox
{ {
/*public Symbol ButtonSymbol
{
get { return (Symbol)GetValue(ButtonSymbolProperty); }
set { SetValue(ButtonSymbolProperty, value); }
}
public static readonly DependencyProperty ButtonSymbolProperty =
DependencyProperty.Register(
"ButtonSymbol",
typeof(Symbol),
typeof(TextBoxWithButton),
new PropertyMetadata(Symbol.Delete, (o, args) => { }));*/
public string ButtonSymbol public string ButtonSymbol
{ {
get { return (string)GetValue(ButtonSymbolProperty); } get { return (string)GetValue(ButtonSymbolProperty); }
@@ -31,6 +19,31 @@ namespace ModernKeePass.Controls
new PropertyMetadata("&#xE107;", (o, args) => { })); new PropertyMetadata("&#xE107;", (o, args) => { }));
public event EventHandler<RoutedEventArgs> ButtonClick; public event EventHandler<RoutedEventArgs> ButtonClick;
public string ButtonTooltip
{
get { return (string)GetValue(ButtonTooltipProperty); }
set { SetValue(ButtonTooltipProperty, value); }
}
public static readonly DependencyProperty ButtonTooltipProperty =
DependencyProperty.Register(
"ButtonTooltip",
typeof(string),
typeof(TextBoxWithButton),
new PropertyMetadata(string.Empty, (o, args) => { }));
public bool IsButtonEnabled
{
get { return (bool)GetValue(IsButtonEnabledProperty); }
set { SetValue(IsButtonEnabledProperty, value); }
}
public static readonly DependencyProperty IsButtonEnabledProperty =
DependencyProperty.Register(
"IsButtonEnabled",
typeof(bool),
typeof(TextBoxWithButton),
new PropertyMetadata(true, (o, args) => { }));
protected override void OnApplyTemplate() protected override void OnApplyTemplate()
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();

View File

@@ -0,0 +1,20 @@
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace ModernKeePass.Converters
{
class EmptyStringToVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var text = value is string ? value.ToString() : string.Empty;
return string.IsNullOrEmpty(text) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8" ?>
<CurrentApp>
<ListingInformation>
<App>
<AppId>0719A91A-C322-4EE0-A257-E60733EECF06</AppId>
<LinkUri>https://www.microsoft.com/store/apps/9mwq48zk8nhv</LinkUri>
<CurrentMarket>en-us</CurrentMarket>
<AgeRating>3</AgeRating>
<MarketData xml:lang="en-us">
<Name>App with several in-app products</Name>
<Description>Sample app for demonstrating an expiring in-app product and a consumable in-app product</Description>
<Price>5.99</Price>
<CurrencySymbol>$</CurrencySymbol>
</MarketData>
</App>
<Product ProductId="donate1" LicenseDuration="0" ProductType="Consumable">
<MarketData xml:lang="en-us">
<Name>Small Donation</Name>
<Price>0.99</Price>
<CurrencySymbol>$</CurrencySymbol>
</MarketData>
</Product>
<Product ProductId="donate5" LicenseDuration="0" ProductType="Consumable">
<MarketData xml:lang="en-us">
<Name>Medium Donation</Name>
<Price>4.99</Price>
<CurrencySymbol>$</CurrencySymbol>
</MarketData>
</Product>
<Product ProductId="donate10" LicenseDuration="0" ProductType="Consumable">
<MarketData xml:lang="en-us">
<Name>Large Donation</Name>
<Price>9.99</Price>
<CurrencySymbol>$</CurrencySymbol>
</MarketData>
</Product>
<Product ProductId="donate20" LicenseDuration="0" ProductType="Consumable">
<MarketData xml:lang="en-us">
<Name>Generous Donation</Name>
<Price>19.99</Price>
<CurrencySymbol>$</CurrencySymbol>
</MarketData>
</Product>
</ListingInformation>
<LicenseInformation>
<App>
<IsActive>true</IsActive>
<IsTrial>false</IsTrial>
</App>
</LicenseInformation>
<ConsumableInformation>
<Product ProductId="donate1" TransactionId="00000001-0000-0000-0000-000000000000" Status="Active"/>
<Product ProductId="donate5" TransactionId="00000001-0000-0000-0000-000000000000" Status="Active"/>
<Product ProductId="donate10" TransactionId="00000001-0000-0000-0000-000000000000" Status="Active"/>
<Product ProductId="donate20" TransactionId="00000001-0000-0000-0000-000000000000" Status="Active"/>
</ConsumableInformation>
</CurrentApp>

View File

@@ -0,0 +1,14 @@
using System;
namespace ModernKeePass.Exceptions
{
public class SaveException : Exception
{
public new Exception InnerException { get; }
public SaveException(Exception exception)
{
InnerException = exception;
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Threading.Tasks;
using Windows.UI.Core;
namespace ModernKeePass.Extensions
{
public static class DispatcherTaskExtensions
{
public static async Task<T> RunTaskAsync<T>(this CoreDispatcher dispatcher,
Func<Task<T>> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal)
{
var taskCompletionSource = new TaskCompletionSource<T>();
await dispatcher.RunAsync(priority, async () =>
{
try
{
taskCompletionSource.SetResult(await func());
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
});
return await taskCompletionSource.Task;
}
// There is no TaskCompletionSource<void> so we use a bool that we throw away.
public static async Task RunTaskAsync(this CoreDispatcher dispatcher,
Func<Task> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) =>
await RunTaskAsync(dispatcher, async () => { await func(); return false; }, priority);
}
}

View File

@@ -0,0 +1,29 @@
using Windows.Storage;
using ModernKeePass.ViewModels;
using ModernKeePassLib;
using ModernKeePassLib.Cryptography.KeyDerivation;
using ModernKeePassLib.Keys;
namespace ModernKeePass.Interfaces
{
public interface IDatabase
{
string Name { get; }
bool RecycleBinEnabled { get; set; }
int Status { get; set; }
GroupVm RootGroup { get; set; }
GroupVm RecycleBin { get; set; }
StorageFile DatabaseFile { get; set; }
PwUuid DataCipher { get; set; }
PwCompressionAlgorithm CompressionAlgorithm { get; set; }
KdfParameters KeyDerivation { get; set; }
void Open(CompositeKey key, bool createNew);
void UpdateCompositeKey(CompositeKey key);
void Save();
void Save(StorageFile file);
void CreateRecycleBin();
void AddDeletedItem(PwUuid id);
void Close();
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.ApplicationModel.Store;
namespace ModernKeePass.Interfaces
{
public interface ILicenseService
{
IReadOnlyDictionary<string, ProductListing> Products { get; }
Task<int> Purchase(string addOn);
}
}

View File

@@ -12,6 +12,7 @@ namespace ModernKeePass.Interfaces
string Name { get; set; } string Name { get; set; }
string Path { get; } string Path { get; }
bool IsEditMode { get; } bool IsEditMode { get; }
bool IsRecycleOnDelete { get; }
/// <summary> /// <summary>
/// Move a entity to the destination group /// Move a entity to the destination group

View File

@@ -0,0 +1,15 @@
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Windows.Storage;
namespace ModernKeePass.Interfaces
{
public interface IRecent
{
int EntryCount { get; }
Task<IStorageItem> GetFileAsync(string token);
ObservableCollection<IRecentItem> GetAllFiles(bool removeIfNonExistant = true);
void Add(IStorageItem file, string metadata);
void ClearAll();
}
}

View File

@@ -0,0 +1,11 @@
using Windows.Storage;
namespace ModernKeePass.Interfaces
{
public interface IRecentItem
{
StorageFile DatabaseFile { get; }
string Token { get; }
string Name { get; }
}
}

View File

@@ -0,0 +1,7 @@
namespace ModernKeePass.Interfaces
{
public interface IResource
{
string GetResourceValue(string key);
}
}

View File

@@ -0,0 +1,8 @@
namespace ModernKeePass.Interfaces
{
public interface ISettings
{
T GetSetting<T>(string property);
void PutSetting<T>(string property, T value);
}
}

View File

@@ -1,3 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp70</s:String>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=viewmodels_005Citems/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -113,28 +113,51 @@
<Compile Include="App.xaml.cs"> <Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon> <DependentUpon>App.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Common\DatabaseHelper.cs" /> <Compile Include="Interfaces\ILicenseService.cs" />
<Compile Include="Interfaces\IRecent.cs" />
<Compile Include="Interfaces\IRecentItem.cs" />
<Compile Include="Interfaces\IResource.cs" />
<Compile Include="ViewModels\DonateVm.cs" />
<Compile Include="Views\MainPageFrames\DonatePage.xaml.cs">
<DependentUpon>DonatePage.xaml</DependentUpon>
</Compile>
<Compile Include="Services\DatabaseService.cs" />
<Compile Include="Interfaces\ISettings.cs" />
<Compile Include="Common\MessageDialogHelper.cs" /> <Compile Include="Common\MessageDialogHelper.cs" />
<Compile Include="Common\NavigationHelper.cs" /> <Compile Include="Common\NavigationHelper.cs" />
<Compile Include="Common\NotifyPropertyChangedBase.cs" /> <Compile Include="Common\NotifyPropertyChangedBase.cs" />
<Compile Include="Common\ObservableDictionary.cs" /> <Compile Include="Common\ObservableDictionary.cs" />
<Compile Include="Common\RelayCommand.cs" /> <Compile Include="Common\RelayCommand.cs" />
<Compile Include="Common\SuspensionManager.cs" /> <Compile Include="Common\SuspensionManager.cs" />
<Compile Include="Services\LicenseService.cs" />
<Compile Include="Services\RecentService.cs" />
<Compile Include="Services\ResourcesService.cs" />
<Compile Include="Services\SettingsService.cs" />
<Compile Include="Common\ToastNotificationHelper.cs" /> <Compile Include="Common\ToastNotificationHelper.cs" />
<Compile Include="Converters\DiscreteIntToSolidColorBrushConverter.cs" /> <Compile Include="Converters\DiscreteIntToSolidColorBrushConverter.cs" />
<Compile Include="Converters\EmptyStringToVisibilityConverter.cs" />
<Compile Include="Converters\NullToBooleanConverter.cs" /> <Compile Include="Converters\NullToBooleanConverter.cs" />
<Compile Include="Exceptions\SaveException.cs" />
<Compile Include="Extensions\DispatcherTaskExtensions.cs" />
<Compile Include="Interfaces\IDatabase.cs" />
<Compile Include="Interfaces\IHasSelectableObject.cs" /> <Compile Include="Interfaces\IHasSelectableObject.cs" />
<Compile Include="Interfaces\ISelectableModel.cs" /> <Compile Include="Interfaces\ISelectableModel.cs" />
<Compile Include="Pages\BasePages\LayoutAwarePageBase.cs" /> <Compile Include="Views\BasePages\LayoutAwarePageBase.cs" />
<Compile Include="Pages\SettingsPageFrames\SettingsDatabasePage.xaml.cs"> <Compile Include="Views\SettingsPageFrames\SettingsDatabasePage.xaml.cs">
<DependentUpon>SettingsDatabasePage.xaml</DependentUpon> <DependentUpon>SettingsDatabasePage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\SettingsPageFrames\SettingsSecurityPage.xaml.cs"> <Compile Include="Views\SettingsPageFrames\SettingsNewDatabasePage.xaml.cs">
<DependentUpon>SettingsNewDatabasePage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\SettingsPageFrames\SettingsSecurityPage.xaml.cs">
<DependentUpon>SettingsSecurityPage.xaml</DependentUpon> <DependentUpon>SettingsSecurityPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\SettingsPageFrames\SettingsWelcomePage.xaml.cs">
<DependentUpon>SettingsWelcomePage.xaml</DependentUpon>
</Compile>
<Compile Include="TemplateSelectors\FirstItemDataTemplateSelector.cs" /> <Compile Include="TemplateSelectors\FirstItemDataTemplateSelector.cs" />
<Compile Include="Controls\ListViewWithDisable.cs" /> <Compile Include="Controls\ListViewWithDisable.cs" />
<Compile Include="Controls\CompositeKeyUserControl.xaml.cs"> <Compile Include="Views\UserControls\CompositeKeyUserControl.xaml.cs">
<DependentUpon>CompositeKeyUserControl.xaml</DependentUpon> <DependentUpon>CompositeKeyUserControl.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Controls\TextBoxWithButton.cs" /> <Compile Include="Controls\TextBoxWithButton.cs" />
@@ -149,20 +172,20 @@
<Compile Include="Events\PasswordEventArgs.cs" /> <Compile Include="Events\PasswordEventArgs.cs" />
<Compile Include="Interfaces\IIsEnabled.cs" /> <Compile Include="Interfaces\IIsEnabled.cs" />
<Compile Include="Interfaces\IPwEntity.cs" /> <Compile Include="Interfaces\IPwEntity.cs" />
<Compile Include="Pages\MainPage.xaml.cs"> <Compile Include="Views\MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon> <DependentUpon>MainPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Mappings\PwIconToSegoeMapping.cs" /> <Compile Include="Mappings\PwIconToSegoeMapping.cs" />
<Compile Include="Pages\MainPageFrames\AboutPage.xaml.cs"> <Compile Include="Views\MainPageFrames\AboutPage.xaml.cs">
<DependentUpon>AboutPage.xaml</DependentUpon> <DependentUpon>AboutPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\MainPageFrames\NewDatabasePage.xaml.cs"> <Compile Include="Views\MainPageFrames\NewDatabasePage.xaml.cs">
<DependentUpon>NewDatabasePage.xaml</DependentUpon> <DependentUpon>NewDatabasePage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\SettingsPage.xaml.cs"> <Compile Include="Views\SettingsPage.xaml.cs">
<DependentUpon>SettingsPage.xaml</DependentUpon> <DependentUpon>SettingsPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\MainPageFrames\WelcomePage.xaml.cs"> <Compile Include="Views\MainPageFrames\WelcomePage.xaml.cs">
<DependentUpon>WelcomePage.xaml</DependentUpon> <DependentUpon>WelcomePage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="ViewModels\AboutVm.cs" /> <Compile Include="ViewModels\AboutVm.cs" />
@@ -170,24 +193,25 @@
<Compile Include="ViewModels\Items\ListMenuItemVm.cs" /> <Compile Include="ViewModels\Items\ListMenuItemVm.cs" />
<Compile Include="ViewModels\Items\MainMenuItemVm.cs" /> <Compile Include="ViewModels\Items\MainMenuItemVm.cs" />
<Compile Include="ViewModels\Items\RecentItemVm.cs" /> <Compile Include="ViewModels\Items\RecentItemVm.cs" />
<Compile Include="Pages\EntryDetailPage.xaml.cs"> <Compile Include="Views\EntryDetailPage.xaml.cs">
<DependentUpon>EntryDetailPage.xaml</DependentUpon> <DependentUpon>EntryDetailPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\GroupDetailPage.xaml.cs"> <Compile Include="Views\GroupDetailPage.xaml.cs">
<DependentUpon>GroupDetailPage.xaml</DependentUpon> <DependentUpon>GroupDetailPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\MainPageFrames\OpenDatabasePage.xaml.cs"> <Compile Include="Views\MainPageFrames\OpenDatabasePage.xaml.cs">
<DependentUpon>OpenDatabasePage.xaml</DependentUpon> <DependentUpon>OpenDatabasePage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\MainPageFrames\RecentDatabasesPage.xaml.cs"> <Compile Include="Views\MainPageFrames\RecentDatabasesPage.xaml.cs">
<DependentUpon>RecentDatabasesPage.xaml</DependentUpon> <DependentUpon>RecentDatabasesPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\MainPageFrames\SaveDatabasePage.xaml.cs"> <Compile Include="Views\MainPageFrames\SaveDatabasePage.xaml.cs">
<DependentUpon>SaveDatabasePage.xaml</DependentUpon> <DependentUpon>SaveDatabasePage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewModels\EntryVm.cs" /> <Compile Include="ViewModels\EntryVm.cs" />
<Compile Include="ViewModels\GroupVm.cs" /> <Compile Include="ViewModels\GroupVm.cs" />
<Compile Include="ViewModels\Items\SettingsNewVm.cs" />
<Compile Include="ViewModels\SettingsVm.cs" /> <Compile Include="ViewModels\SettingsVm.cs" />
<Compile Include="ViewModels\MainVm.cs" /> <Compile Include="ViewModels\MainVm.cs" />
<Compile Include="ViewModels\NewVm.cs" /> <Compile Include="ViewModels\NewVm.cs" />
@@ -200,11 +224,13 @@
<AppxManifest Include="Package.appxmanifest"> <AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</AppxManifest> </AppxManifest>
<None Include="ModernKeePass_StoreKey.pfx" />
<None Include="ModernKeePass_TemporaryKey.pfx" />
<None Include="packages.config"> <None Include="packages.config">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</None> </None>
<PRIResource Include="Strings\fr-FR\Resources.resw" />
<PRIResource Include="Strings\fr-FR\CodeBehind.resw" />
<PRIResource Include="Strings\en-US\CodeBehind.resw" />
<PRIResource Include="Strings\en-US\Resources.resw" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Package.StoreAssociation.xml" /> <None Include="Package.StoreAssociation.xml" />
@@ -214,55 +240,67 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Page Include="Controls\CompositeKeyUserControl.xaml"> <Page Include="Views\UserControls\CompositeKeyUserControl.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\MainPage.xaml"> <Page Include="Views\MainPage.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
<Page Include="Pages\MainPageFrames\AboutPage.xaml"> <Page Include="Views\MainPageFrames\AboutPage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\EntryDetailPage.xaml"> <Page Include="Views\EntryDetailPage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\GroupDetailPage.xaml"> <Page Include="Views\GroupDetailPage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\MainPageFrames\NewDatabasePage.xaml"> <Page Include="Views\MainPageFrames\DonatePage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\MainPageFrames\OpenDatabasePage.xaml"> <Page Include="Views\MainPageFrames\NewDatabasePage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\MainPageFrames\RecentDatabasesPage.xaml"> <Page Include="Views\MainPageFrames\OpenDatabasePage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\MainPageFrames\SaveDatabasePage.xaml"> <Page Include="Views\MainPageFrames\RecentDatabasesPage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\SettingsPage.xaml"> <Page Include="Views\MainPageFrames\SaveDatabasePage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\MainPageFrames\WelcomePage.xaml"> <Page Include="Views\SettingsPage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\SettingsPageFrames\SettingsDatabasePage.xaml"> <Page Include="Views\MainPageFrames\WelcomePage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Pages\SettingsPageFrames\SettingsSecurityPage.xaml"> <Page Include="Views\SettingsPageFrames\SettingsDatabasePage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsPageFrames\SettingsNewDatabasePage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsPageFrames\SettingsSecurityPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SettingsPageFrames\SettingsWelcomePage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
@@ -281,6 +319,11 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page> </Page>
<Page Include="Styles\TextBlockStyles.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Page>
<Page Include="Styles\TextBoxWithButtonStyle.xaml"> <Page Include="Styles\TextBoxWithButtonStyle.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@@ -297,7 +340,7 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="ModernKeePassLib, Version=2.37.0.2000, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="ModernKeePassLib, Version=2.37.0.2000, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ModernKeePassLib.2.37.5000\lib\netstandard1.2\ModernKeePassLib.dll</HintPath> <HintPath>..\packages\ModernKeePassLib.2.37.8000\lib\netstandard1.2\ModernKeePassLib.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
@@ -319,31 +362,63 @@
</SDKReference> </SDKReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="appMetadata\en-us\baselisting\description.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\description.Entry.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\description.Filter.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\description.Group.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\description.New.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\description.Open.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\description.Recent.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\description.Semantic.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\description.Settings.txt" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\Entry.png" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\Filter.png" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\Group.png" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\New.png" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\Open.png" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\Recent.png" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\Semantic.png" />
<Content Include="appMetadata\en-us\baselisting\images\Screenshot\Settings.png" />
<Content Include="appMetadata\en-us\baselisting\keywords.txt" />
<Content Include="appMetadata\en-us\baselisting\privacyPolicy.txt" />
<Content Include="appMetadata\en-us\baselisting\releaseNotes.txt" />
<Content Include="appMetadata\en-us\baselisting\websiteUrl.txt" />
<Content Include="appMetadata\fr-fr\baselisting\description.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\description.Entry.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\description.Filter.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\description.Group.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\description.New.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\description.Open.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\description.Recent.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\description.Semantic.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\description.Settings.txt" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\Entry.png" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\Filter.png" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\Group.png" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\New.png" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\Open.png" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\Recent.png" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\Semantic.png" />
<Content Include="appMetadata\fr-fr\baselisting\images\Screenshot\Settings.png" />
<Content Include="appMetadata\fr-fr\baselisting\keywords.txt" />
<Content Include="appMetadata\fr-fr\baselisting\privacyPolicy.txt" />
<Content Include="appMetadata\fr-fr\baselisting\releaseNotes.txt" />
<Content Include="appMetadata\fr-fr\baselisting\websiteUrl.txt" />
<Content Include="Assets\Logo.scale-100.png" /> <Content Include="Assets\Logo.scale-100.png" />
<Content Include="Assets\Logo.scale-140.png" /> <Content Include="Assets\Logo.scale-140.png" />
<Content Include="Assets\Logo.scale-180.png" /> <Content Include="Assets\Logo.scale-180.png" />
<Content Include="Assets\Logo.scale-80.png" /> <Content Include="Assets\Logo.scale-80.png" />
<Content Include="Assets\ModernKeePass-Logo.scale-100.png" />
<Content Include="Assets\ModernKeePass-Logo.scale-140.png" />
<Content Include="Assets\ModernKeePass-Logo.scale-180.png" />
<Content Include="Assets\ModernKeePass-Logo.scale-80.png" />
<Content Include="Assets\ModernKeePass-SmallLogo.scale-100.png" /> <Content Include="Assets\ModernKeePass-SmallLogo.scale-100.png" />
<Content Include="Assets\ModernKeePass-SmallLogo.scale-140.png" /> <Content Include="Assets\ModernKeePass-SmallLogo.scale-140.png" />
<Content Include="Assets\ModernKeePass-SmallLogo.scale-180.png" /> <Content Include="Assets\ModernKeePass-SmallLogo.scale-180.png" />
<Content Include="Assets\ModernKeePass-SmallLogo.scale-80.png" /> <Content Include="Assets\ModernKeePass-SmallLogo.scale-80.png" />
<Content Include="Assets\ModernKeePass-SmallLogo.targetsize-16.png" />
<Content Include="Assets\ModernKeePass-SmallLogo.targetsize-256.png" />
<Content Include="Assets\ModernKeePass-SmallLogo.targetsize-32.png" />
<Content Include="Assets\ModernKeePass-SmallLogo.targetsize-48.png" />
<Content Include="Assets\ModernKeePass-SplashScreen.scale-100.png" /> <Content Include="Assets\ModernKeePass-SplashScreen.scale-100.png" />
<Content Include="Assets\ModernKeePass-SplashScreen.scale-140.png" /> <Content Include="Assets\ModernKeePass-SplashScreen.scale-140.png" />
<Content Include="Assets\ModernKeePass-SplashScreen.scale-180.png" /> <Content Include="Assets\ModernKeePass-SplashScreen.scale-180.png" />
<Content Include="Assets\ModernKeePass-StoreLogo.scale-100.png" />
<Content Include="Assets\ModernKeePass-StoreLogo.scale-140.png" />
<Content Include="Assets\ModernKeePass-StoreLogo.scale-180.png" />
<Content Include="Assets\SmallLogo.scale-100.png" />
<Content Include="Assets\SmallLogo.scale-140.png" />
<Content Include="Assets\SmallLogo.scale-180.png" />
<Content Include="Assets\SmallLogo.scale-80.png" />
<Content Include="Assets\SplashScreen.scale-100.png" />
<Content Include="Assets\SplashScreen.scale-140.png" />
<Content Include="Assets\SplashScreen.scale-180.png" />
<Content Include="Assets\Square310x310Logo.scale-100.png" /> <Content Include="Assets\Square310x310Logo.scale-100.png" />
<Content Include="Assets\Square310x310Logo.scale-140.png" /> <Content Include="Assets\Square310x310Logo.scale-140.png" />
<Content Include="Assets\Square310x310Logo.scale-180.png" /> <Content Include="Assets\Square310x310Logo.scale-180.png" />
@@ -359,6 +434,9 @@
<Content Include="Assets\Wide310x150Logo.scale-140.png" /> <Content Include="Assets\Wide310x150Logo.scale-140.png" />
<Content Include="Assets\Wide310x150Logo.scale-180.png" /> <Content Include="Assets\Wide310x150Logo.scale-180.png" />
<Content Include="Assets\Wide310x150Logo.scale-80.png" /> <Content Include="Assets\Wide310x150Logo.scale-80.png" />
<Content Include="Data\WindowsStoreProxy.xml">
<SubType>Designer</SubType>
</Content>
</ItemGroup> </ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '12.0' "> <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '12.0' ">
<VisualStudioVersion>12.0</VisualStudioVersion> <VisualStudioVersion>12.0</VisualStudioVersion>

View File

@@ -1,3 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp70</s:String>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=viewmodels_005Citems/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,10 +1,10 @@
<?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.6.0.27" /> <Identity Name="wismna.ModernKeePass" Publisher="CN=0719A91A-C322-4EE0-A257-E60733EECF06" Version="1.10.0.31" />
<Properties> <Properties>
<DisplayName>ModernKeePass</DisplayName> <DisplayName>ModernKeePass</DisplayName>
<PublisherDisplayName>wismna</PublisherDisplayName> <PublisherDisplayName>wismna</PublisherDisplayName>
<Logo>Assets\ModernKeePass-StoreLogo.png</Logo> <Logo>Assets\StoreLogo.png</Logo>
</Properties> </Properties>
<Prerequisites> <Prerequisites>
<OSMinVersion>6.3.0</OSMinVersion> <OSMinVersion>6.3.0</OSMinVersion>
@@ -15,10 +15,10 @@
</Resources> </Resources>
<Applications> <Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="ModernKeePass.App"> <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="ModernKeePass.App">
<m2:VisualElements DisplayName="ModernKeePass" Square150x150Logo="Assets\ModernKeePass-Logo.png" Square30x30Logo="Assets\ModernKeePass-SmallLogo.png" Description="A port of the KeePass application for the Windows store. You can create, open and edit KeePass 2.x password databases in a modern fashion." ForegroundText="light" BackgroundColor="#464646" ToastCapable="true"> <m2:VisualElements DisplayName="ModernKeePass" Square150x150Logo="Assets\Logo.png" Square30x30Logo="Assets\ModernKeePass-SmallLogo.png" Description="A port of the KeePass application for the Windows store. You can create, open and edit KeePass 2.x password databases in a modern fashion." ForegroundText="light" BackgroundColor="#7755c4" ToastCapable="true">
<m2:DefaultTile Square310x310Logo="Assets\Square310x310Logo.png" Wide310x150Logo="Assets\Wide310x150Logo.png" Square70x70Logo="Assets\Square70x70Logo.png"> <m2:DefaultTile Square310x310Logo="Assets\Square310x310Logo.png" Wide310x150Logo="Assets\Wide310x150Logo.png" Square70x70Logo="Assets\Square70x70Logo.png">
</m2:DefaultTile> </m2:DefaultTile>
<m2:SplashScreen Image="Assets\ModernKeePass-SplashScreen.png" /> <m2:SplashScreen Image="Assets\ModernKeePass-SplashScreen.png" BackgroundColor="#7755c4" />
</m2:VisualElements> </m2:VisualElements>
<Extensions> <Extensions>
<Extension Category="windows.fileOpenPicker"> <Extension Category="windows.fileOpenPicker">

View File

@@ -1,304 +0,0 @@
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="using:ModernKeePass.ViewModels"
xmlns:converters="using:ModernKeePass.Converters"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:actions="using:ModernKeePass.Actions"
xmlns:templateSelectors="using:ModernKeePass.TemplateSelectors"
x:Name="PageRoot"
x:Class="ModernKeePass.Pages.GroupDetailPage"
mc:Ignorable="d" >
<Page.Resources>
<SolidColorBrush x:Key="Transparent" Color="Transparent"/>
<SolidColorBrush x:Key="SystemColor" Color="{StaticResource SystemColorButtonFaceColor}" />
<converters:ColorToBrushConverter x:Key="ColorToBrushConverter"/>
<converters:BooleanToFontStyleConverter x:Key="BooleanToFontStyleConverter"/>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<converters:NullToBooleanConverter x:Key="NullToBooleanConverter"/>
</Page.Resources>
<Page.DataContext>
<viewModels:GroupVm />
</Page.DataContext>
<Page.BottomAppBar>
<CommandBar x:Name="CommandBar" VerticalAlignment="Center">
<CommandBar.SecondaryCommands>
<AppBarButton Icon="Save" Label="Save">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:CallMethodAction TargetObject="{Binding}" MethodName="Save"/>
<core:ChangePropertyAction TargetObject="{Binding ElementName=CommandBar}" PropertyName="IsOpen" Value="False" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</AppBarButton>
<AppBarButton Icon="Setting" Label="Settings">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:NavigateToPageAction TargetPage="ModernKeePass.Pages.SettingsPage" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</AppBarButton>
</CommandBar.SecondaryCommands>
<AppBarToggleButton Icon="Edit" Label="Edit" IsChecked="{Binding IsEditMode, Mode=TwoWay}">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:ChangePropertyAction TargetObject="{Binding ElementName=CommandBar}" PropertyName="IsOpen" Value="False" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</AppBarToggleButton>
<AppBarButton Icon="Undo" Label="Restore" Visibility="{Binding ShowRestore, Converter={StaticResource BooleanToVisibilityConverter}}" IsEnabled="{Binding PreviousGroup, Converter={StaticResource NullToBooleanConverter}}" Click="RestoreButton_Click">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:CallMethodAction MethodName="UndoDelete" TargetObject="{Binding}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</AppBarButton>
<AppBarButton Icon="Delete" Label="Delete" IsEnabled="{Binding IsNotRoot}" Click="DeleteButton_Click" />
</CommandBar>
</Page.BottomAppBar>
<Grid>
<Grid.Resources>
<CollectionViewSource
x:Name="GroupsViewSource"
Source="{Binding Groups}" />
<CollectionViewSource
x:Name="EntriesViewSource"
Source="{Binding Entries}" />
<CollectionViewSource
x:Name="EntriesZoomedOutViewSource"
Source="{Binding EntriesZoomedOut}" IsSourceGrouped="True"/>
</Grid.Resources>
<Grid.Background>
<StaticResource ResourceKey="ApplicationPageBackgroundThemeBrush"/>
</Grid.Background>
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListView
Grid.Column="0"
x:Name="LeftListView"
Margin="0,0,0,-10"
SelectionChanged="groups_SelectionChanged"
IsSwipeEnabled="false"
IsSynchronizedWithCurrentItem="False"
DataContext="{Binding DataContext, ElementName=PageRoot}"
RequestedTheme="Dark"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Foreground="{ThemeResource DefaultTextForegroundThemeBrush}">
<ListView.Resources>
<DataTemplate x:Name="Collapsed">
<SymbolIcon Symbol="{Binding IconSymbol}" Margin="8,0,0,0">
<ToolTipService.ToolTip>
<ToolTip Content="{Binding Name}" />
</ToolTipService.ToolTip>
</SymbolIcon>
</DataTemplate>
<DataTemplate x:Name="Expanded">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="{Binding IconSymbol}" Margin="8,0,0,0" />
<TextBlock Text="{Binding Name}" FontWeight="{Binding FontWeight}" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="30,0,20,0" FontStyle="{Binding IsSelected, Converter={StaticResource BooleanToFontStyleConverter}}" />
</StackPanel>
</DataTemplate>
</ListView.Resources>
<ListView.ItemsSource>
<Binding Source="{StaticResource GroupsViewSource}"/>
</ListView.ItemsSource>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<!--<Setter Property="HorizontalContentAlignment" Value="Center" />-->
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.HeaderTemplate>
<DataTemplate>
<ToggleButton Style="{StaticResource HamburgerToggleButton}">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Loaded">
<core:ChangePropertyAction PropertyName="ItemTemplate" Value="{StaticResource Collapsed}" TargetObject="{Binding ElementName=LeftListView}"/>
</core:EventTriggerBehavior>
<core:EventTriggerBehavior EventName="Checked">
<core:ChangePropertyAction PropertyName="ItemTemplate" Value="{StaticResource Expanded}" TargetObject="{Binding ElementName=LeftListView}"/>
</core:EventTriggerBehavior>
<core:EventTriggerBehavior EventName="Unchecked">
<core:ChangePropertyAction PropertyName="ItemTemplate" Value="{StaticResource Collapsed}" TargetObject="{Binding ElementName=LeftListView}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</ToggleButton>
</DataTemplate>
</ListView.HeaderTemplate>
</ListView>
<!-- Horizontal scrolling grid -->
<SemanticZoom Grid.Column="1" ViewChangeStarted="SemanticZoom_ViewChangeStarted" Margin="0,30,0,0">
<SemanticZoom.ZoomedInView>
<GridView
x:Name="GridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Entries"
TabIndex="1"
SelectionChanged="entries_SelectionChanged"
IsSynchronizedWithCurrentItem="False">
<interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="False">
<actions:SetupFocusAction TargetObject="{Binding ElementName=GridView}" />
</core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
<GridView.Resources>
<DataTemplate x:Name="GroupFirstItem">
<Border
BorderThickness="2"
BorderBrush="{StaticResource SystemColor}"
Background="{StaticResource HubSectionHeaderPressedForegroundThemeBrush}">
<Grid Height="110" Width="480">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<SymbolIcon Grid.Column="0" Symbol="{Binding IconSymbol}" Width="100" Height="100" RenderTransformOrigin="0.5,0.5" Foreground="{ThemeResource TextBoxBackgroundThemeBrush}" >
<SymbolIcon.RenderTransform>
<CompositeTransform ScaleX="2" TranslateX="0" TranslateY="0" ScaleY="2"/>
</SymbolIcon.RenderTransform>
</SymbolIcon>
<TextBlock Grid.Column="1" Text="{Binding Name}" FontWeight="Bold" Style="{ThemeResource TitleTextBlockStyle}" Foreground="{ThemeResource TextBoxBackgroundThemeBrush}" TextWrapping="NoWrap" VerticalAlignment="Center" Margin="13,0,0,5"/>
</Grid>
</Border>
</DataTemplate>
<DataTemplate x:Name="GroupOtherItem">
<Grid Height="110" Width="480" x:Name="EntryGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border
Grid.Column="0"
BorderThickness="2"
BorderBrush="{StaticResource SystemColor}"
Background="{Binding BackgroundColor, ConverterParameter={StaticResource Transparent}, Converter={StaticResource ColorToBrushConverter}}">
<SymbolIcon Symbol="{Binding IconSymbol}" Width="100" Height="100" RenderTransformOrigin="0.5,0.5" >
<SymbolIcon.RenderTransform>
<CompositeTransform ScaleX="2" TranslateX="0" TranslateY="0" ScaleY="2"/>
</SymbolIcon.RenderTransform>
</SymbolIcon>
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="10,10,0,0" >
<TextBlock x:Name="NameTextBlock" Text="{Binding Name}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap" Foreground="{Binding ForegroundColor, ConverterParameter={StaticResource TextBoxForegroundThemeBrush}, Converter={StaticResource ColorToBrushConverter}}"/>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
<TextBlock Text="{Binding UserName}" Style="{StaticResource BodyTextBlockStyle}" MaxHeight="60" />
<TextBlock Text="{Binding Url}" Style="{StaticResource BodyTextBlockStyle}" MaxHeight="60" />
</StackPanel>
</Grid>
</DataTemplate>
</GridView.Resources>
<GridView.ItemsSource>
<Binding Source="{StaticResource EntriesViewSource}"/>
</GridView.ItemsSource>
<GridView.DataContext>
<viewModels:EntryVm/>
</GridView.DataContext>
<GridView.ItemTemplateSelector>
<templateSelectors:FirstItemDataTemplateSelector
FirstItem="{StaticResource GroupFirstItem}"
OtherItem="{StaticResource GroupOtherItem}" />
</GridView.ItemTemplateSelector>
<GridView.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<Setter Property="Margin" Value="52,0,0,2"/>
</Style>
</GridView.ItemContainerStyle>
</GridView>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<ListView
x:Name="SemanticListView"
ItemsSource="{Binding Source={StaticResource EntriesZoomedOutViewSource}}"
IsSwipeEnabled="false"
SelectionChanged="groups_SelectionChanged"
IsSynchronizedWithCurrentItem="False">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupStyle>
<GroupStyle HidesIfEmpty="True">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Background="LightGray" Margin="0,0,10,0" HorizontalAlignment="Left">
<TextBlock Text="{Binding Key}" Width="40" Foreground="Black" Margin="30" Style="{StaticResource HeaderTextBlockStyle}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
</Grid>
<!-- Back button and page title -->
<Grid Grid.Row="0" Background="{ThemeResource AppBarBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="400"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
x:Name="BackButton"
Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}"
Height="50"
Width="50"
VerticalAlignment="Center"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button"
Style="{StaticResource NoBorderButtonStyle}">
<SymbolIcon Symbol="Back" />
</Button>
<StackPanel Grid.Column="1" >
<TextBox
x:Name="TitleTextBox"
Text="{Binding Name, Mode=TwoWay}"
Foreground="{ThemeResource DefaultTextForegroundThemeBrush}"
Background="Transparent"
IsHitTestVisible="{Binding IsEditMode}"
BorderThickness="0"
FontSize="20"
FontWeight="SemiBold"
TextWrapping="NoWrap"
VerticalAlignment="Center"
PlaceholderText="New group name...">
<interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{Binding IsEditMode}" Value="True">
<actions:SetupFocusAction TargetObject="{Binding ElementName=TitleTextBox}" />
</core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBox>
<TextBlock FontSize="12" Text="{Binding Path}" />
</StackPanel>
<SearchBox Grid.Column="2" PlaceholderText="Search..." Width="350" Background="{ThemeResource TextBoxDisabledBackgroundThemeBrush}" BorderThickness="0" FontSize="18" SuggestionsRequested="SearchBox_OnSuggestionsRequested" SearchHistoryEnabled="False" ResultSuggestionChosen="SearchBox_OnResultSuggestionChosen" />
</Grid>
</Grid>
</Page>

View File

@@ -1,48 +0,0 @@
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="using:ModernKeePass.ViewModels"
xmlns:local="using:ModernKeePass.Controls"
xmlns:converters="using:ModernKeePass.Converters"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
x:Class="ModernKeePass.Pages.RecentDatabasesPage"
mc:Ignorable="d">
<Page.Resources>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<CollectionViewSource x:Name="RecentItemsSource" Source="{Binding RecentItems}" />
</Page.Resources>
<Page.DataContext>
<viewModels:RecentVm/>
</Page.DataContext>
<ListView Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
ItemsSource="{Binding Source={StaticResource RecentItemsSource}}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
ItemContainerStyle="{StaticResource ListViewLeftIndicatorItemExpanded}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="10,0,10,0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Name}" Padding="5,0,0,0" />
<TextBlock Grid.Row="1" Text="{Binding Path}" Padding="5,0,0,0" FontSize="10" />
<local:CompositeKeyUserControl Grid.Row="2" x:Name="DatabaseUserControl" HorizontalAlignment="Stretch" MinWidth="400" Margin="0,10,0,0" Visibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}" ValidationChecking="OpenDatabaseUserControl_OnValidationChecking">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="ValidationChecked">
<core:NavigateToPageAction TargetPage="ModernKeePass.Pages.GroupDetailPage" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</local:CompositeKeyUserControl>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Page>

View File

@@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace ModernKeePass.Pages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class WelcomePage : Page
{
public WelcomePage()
{
this.InitializeComponent();
}
}
}

View File

@@ -1,14 +0,0 @@
<Page
x:Class="ModernKeePass.Pages.SettingsSecurityPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ModernKeePass.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Change database security options" />
<local:CompositeKeyUserControl UpdateKey="True" />
</StackPanel>
</Page>

View File

@@ -24,6 +24,6 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.6.0.0")] [assembly: AssemblyVersion("1.10.0.0")]
[assembly: AssemblyFileVersion("1.6.0.0")] [assembly: AssemblyFileVersion("1.10.0.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View File

@@ -0,0 +1,235 @@
using System;
using Windows.Storage;
using Windows.UI.Xaml.Controls;
using ModernKeePass.Exceptions;
using ModernKeePass.Interfaces;
using ModernKeePass.ViewModels;
using ModernKeePassLib;
using ModernKeePassLib.Collections;
using ModernKeePassLib.Cryptography.KeyDerivation;
using ModernKeePassLib.Interfaces;
using ModernKeePassLib.Keys;
using ModernKeePassLib.Security;
using ModernKeePassLib.Serialization;
namespace ModernKeePass.Services
{
public class DatabaseService: IDatabase
{
public enum DatabaseStatus
{
Error = -3,
NoCompositeKey = -2,
CompositeKeyError = -1,
Closed = 0,
Opening = 1,
Opened = 2
}
private readonly PwDatabase _pwDatabase = new PwDatabase();
private readonly ISettings _settings;
private readonly IResource _resource;
private StorageFile _databaseFile;
private GroupVm _recycleBin;
public GroupVm RootGroup { get; set; }
public GroupVm RecycleBin
{
get { return _recycleBin; }
set
{
_recycleBin = value;
_pwDatabase.RecycleBinUuid = _recycleBin.IdUuid;
}
}
public int Status { get; set; } = (int)DatabaseStatus.Closed;
public string Name => DatabaseFile?.Name;
public bool RecycleBinEnabled
{
get { return _pwDatabase.RecycleBinEnabled; }
set { _pwDatabase.RecycleBinEnabled = value; }
}
public StorageFile DatabaseFile
{
get { return _databaseFile; }
set
{
_databaseFile = value;
Status = (int)DatabaseStatus.Opening;
}
}
public PwUuid DataCipher
{
get { return _pwDatabase.DataCipherUuid; }
set { _pwDatabase.DataCipherUuid = value; }
}
public PwCompressionAlgorithm CompressionAlgorithm
{
get { return _pwDatabase.Compression; }
set { _pwDatabase.Compression = value; }
}
public KdfParameters KeyDerivation
{
get { return _pwDatabase.KdfParameters; }
set { _pwDatabase.KdfParameters = value; }
}
public DatabaseService() : this(new SettingsService())
{ }
public DatabaseService(ISettings settings)
{
_settings = settings;
}
/// <summary>
/// Open a KeePass database
/// </summary>
/// <param name="key">The database composite key</param>
/// <param name="createNew">True to create a new database before opening it</param>
/// <returns>An error message, if any</returns>
public void Open(CompositeKey key, bool createNew = false)
{
try
{
if (key == null)
{
Status = (int)DatabaseStatus.NoCompositeKey;
return;
}
var ioConnection = IOConnectionInfo.FromFile(DatabaseFile);
if (createNew)
{
_pwDatabase.New(ioConnection, key);
//Get settings default values
if (_settings.GetSetting<bool>("Sample")) CreateSampleData();
var fileFormat = _settings.GetSetting<string>("DefaultFileFormat");
switch (fileFormat)
{
case "4":
KeyDerivation = KdfPool.Get("Argon2").GetDefaultParameters();
break;
}
}
else _pwDatabase.Open(ioConnection, key, new NullStatusLogger());
if (!_pwDatabase.IsOpen) return;
Status = (int)DatabaseStatus.Opened;
RootGroup = new GroupVm(_pwDatabase.RootGroup, null, RecycleBinEnabled ? _pwDatabase.RecycleBinUuid : null);
}
catch (InvalidCompositeKeyException)
{
Status = (int)DatabaseStatus.CompositeKeyError;
}
catch (Exception)
{
Status = (int)DatabaseStatus.Error;
throw;
}
}
/// <summary>
/// Save the current database to another file and open it
/// </summary>
/// <param name="file">The new database file</param>
public void Save(StorageFile file)
{
var oldFile = DatabaseFile;
DatabaseFile = file;
try
{
_pwDatabase.SaveAs(IOConnectionInfo.FromFile(DatabaseFile), true, new NullStatusLogger());
}
catch
{
DatabaseFile = oldFile;
throw;
}
finally
{
Status = (int)DatabaseStatus.Opened;
}
}
/// <summary>
/// Commit the changes to the currently opened database to file
/// </summary>
public void Save()
{
if (_pwDatabase == null || !_pwDatabase.IsOpen) return;
try
{
_pwDatabase.Save(new NullStatusLogger());
}
catch (Exception e)
{
throw new SaveException(e);
}
}
/// <summary>
/// Close the currently opened database
/// </summary>
public void Close()
{
_pwDatabase?.Close();
Status = (int)DatabaseStatus.Closed;
}
public void AddDeletedItem(PwUuid id)
{
_pwDatabase.DeletedObjects.Add(new PwDeletedObject(id, DateTime.UtcNow));
}
public void CreateRecycleBin()
{
RecycleBin = RootGroup.AddNewGroup("Recycle bin");
RecycleBin.IsSelected = true;
RecycleBin.IconSymbol = Symbol.Delete;
}
public void UpdateCompositeKey(CompositeKey key)
{
_pwDatabase.MasterKey = key;
}
private void CreateSampleData()
{
_pwDatabase.RootGroup.AddGroup(new PwGroup(true, true, "Banking", PwIcon.Count), true);
_pwDatabase.RootGroup.AddGroup(new PwGroup(true, true, "Email", PwIcon.EMail), true);
_pwDatabase.RootGroup.AddGroup(new PwGroup(true, true, "Internet", PwIcon.World), true);
var pe = new PwEntry(true, true);
pe.Strings.Set(PwDefs.TitleField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectTitle,
"Sample Entry"));
pe.Strings.Set(PwDefs.UserNameField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectUserName,
"Username"));
pe.Strings.Set(PwDefs.UrlField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectUrl,
PwDefs.HomepageUrl));
pe.Strings.Set(PwDefs.PasswordField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectPassword,
"Password"));
pe.Strings.Set(PwDefs.NotesField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectNotes,
"You may safely delete this sample"));
_pwDatabase.RootGroup.AddEntry(pe, true);
pe = new PwEntry(true, true);
pe.Strings.Set(PwDefs.TitleField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectTitle,
"Sample Entry #2"));
pe.Strings.Set(PwDefs.UserNameField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectUserName,
"Michael321"));
pe.Strings.Set(PwDefs.UrlField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectUrl,
PwDefs.HelpUrl + "kb/testform.html"));
pe.Strings.Set(PwDefs.PasswordField, new ProtectedString(_pwDatabase.MemoryProtection.ProtectPassword,
"12345"));
pe.AutoType.Add(new AutoTypeAssociation("*Test Form - KeePass*", string.Empty));
_pwDatabase.RootGroup.AddEntry(pe, true);
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Store;
using ModernKeePass.Interfaces;
namespace ModernKeePass.Services
{
public class LicenseService : ILicenseService
{
public enum PurchaseResult
{
Succeeded,
NothingToFulfill,
PurchasePending,
PurchaseReverted,
ServerError,
NotPurchased,
AlreadyPurchased
}
public IReadOnlyDictionary<string, ProductListing> Products { get; }
//private LicenseInformation _licenseInformation;
private readonly HashSet<Guid> _consumedTransactionIds = new HashSet<Guid>();
public LicenseService()
{
// Initialize the license info for use in the app that is uploaded to the Store.
// Uncomment the following line in the release version of your app.
//_licenseInformation = CurrentApp.LicenseInformation;
// Initialize the license info for testing.
// Comment the following line in the release version of your app.
//_licenseInformation = CurrentAppSimulator.LicenseInformation;
#if DEBUG
try
{
var proxyFile = Package.Current.InstalledLocation.GetFileAsync("data\\WindowsStoreProxy.xml").GetAwaiter().GetResult();
CurrentAppSimulator.ReloadSimulatorAsync(proxyFile).GetAwaiter().GetResult();
}
catch { }
var listing = CurrentAppSimulator.LoadListingInformationAsync().GetAwaiter().GetResult();
#else
var listing = CurrentApp.LoadListingInformationAsync().GetAwaiter().GetResult();
#endif
Products = listing.ProductListings;
}
public async Task<int> Purchase(string addOn)
{
#if DEBUG
var purchaseResults = await CurrentAppSimulator.RequestProductPurchaseAsync(addOn);
#else
var purchaseResults = await CurrentApp.RequestProductPurchaseAsync(addOn);
#endif
switch (purchaseResults.Status)
{
case ProductPurchaseStatus.Succeeded:
GrantFeatureLocally(purchaseResults.TransactionId);
return (int) await ReportFulfillmentAsync(purchaseResults.TransactionId, addOn);
case ProductPurchaseStatus.NotFulfilled:
// The purchase failed because we haven't confirmed fulfillment of a previous purchase.
// Fulfill it now.
if (!IsLocallyFulfilled(purchaseResults.TransactionId))
{
GrantFeatureLocally(purchaseResults.TransactionId);
}
return (int) await ReportFulfillmentAsync(purchaseResults.TransactionId, addOn);
case ProductPurchaseStatus.NotPurchased:
return (int) PurchaseResult.NotPurchased;
case ProductPurchaseStatus.AlreadyPurchased:
return (int) PurchaseResult.AlreadyPurchased;
default:
throw new ArgumentOutOfRangeException();
}
}
private async Task<PurchaseResult> ReportFulfillmentAsync(Guid transactionId, string productName)
{
#if DEBUG
var result = await CurrentAppSimulator.ReportConsumableFulfillmentAsync(productName, transactionId);
#else
var result = await CurrentApp.ReportConsumableFulfillmentAsync(productName, transactionId);
#endif
return (PurchaseResult) result;
}
private void GrantFeatureLocally(Guid transactionId)
{
_consumedTransactionIds.Add(transactionId);
}
private bool IsLocallyFulfilled(Guid transactionId)
{
return _consumedTransactionIds.Contains(transactionId);
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using ModernKeePass.Interfaces;
using Windows.Storage;
using Windows.Storage.AccessCache;
using ModernKeePass.ViewModels;
namespace ModernKeePass.Services
{
public class RecentService : IRecent
{
private readonly StorageItemMostRecentlyUsedList _mru = StorageApplicationPermissions.MostRecentlyUsedList;
public int EntryCount => _mru.Entries.Count;
public ObservableCollection<IRecentItem> GetAllFiles(bool removeIfNonExistant = true)
{
var result = new ObservableCollection<IRecentItem>();
foreach (var entry in _mru.Entries)
{
try
{
var file = _mru.GetFileAsync(entry.Token, AccessCacheOptions.SuppressAccessTimeUpdate).GetAwaiter().GetResult();
result.Add(new RecentItemVm(entry.Token, entry.Metadata, file));
}
catch (Exception)
{
if (removeIfNonExistant) _mru.Remove(entry.Token);
}
}
return result;
}
public void Add(IStorageItem file, string metadata)
{
_mru.Add(file, metadata);
}
public void ClearAll()
{
_mru.Clear();
}
public async Task<IStorageItem> GetFileAsync(string token)
{
return await _mru.GetFileAsync(token);
}
}
}

View File

@@ -0,0 +1,17 @@
using Windows.ApplicationModel.Resources;
using ModernKeePass.Interfaces;
namespace ModernKeePass.Services
{
public class ResourcesService: IResource
{
private const string ResourceFileName = "CodeBehind";
private readonly ResourceLoader _resourceLoader = ResourceLoader.GetForCurrentView();
public string GetResourceValue(string key)
{
var resource = _resourceLoader.GetString($"/{ResourceFileName}/{key}");
return resource;
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using Windows.Foundation.Collections;
using Windows.Storage;
using ModernKeePass.Interfaces;
namespace ModernKeePass.Services
{
public class SettingsService : ISettings
{
private readonly IPropertySet _values = ApplicationData.Current.LocalSettings.Values;
public T GetSetting<T>(string property)
{
try
{
return (T)Convert.ChangeType(_values[property], typeof(T));
}
catch (InvalidCastException)
{
return default(T);
}
}
public void PutSetting<T>(string property, T value)
{
if (_values.ContainsKey(property))
_values[property] = value;
else _values.Add(property, value);
}
}
}

View File

@@ -0,0 +1,273 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="CompositeKeyDefaultKeyFile" xml:space="preserve">
<value>Select key file from disk...</value>
</data>
<data name="CompositeKeyErrorOpen" xml:space="preserve">
<value>Error</value>
</data>
<data name="CompositeKeyErrorUserKeyFile" xml:space="preserve">
<value>key file</value>
</data>
<data name="CompositeKeyErrorUserOr" xml:space="preserve">
<value> or </value>
</data>
<data name="CompositeKeyErrorUserPassword" xml:space="preserve">
<value>password</value>
</data>
<data name="CompositeKeyErrorUserStart" xml:space="preserve">
<value>Error: wrong </value>
</data>
<data name="CompositeKeyOpening" xml:space="preserve">
<value>Opening...</value>
</data>
<data name="CompositeKeyUpdated" xml:space="preserve">
<value>Database composite key updated.</value>
</data>
<data name="DonateAlreadyPurchasedMessage" xml:space="preserve">
<value>Your product has already been purchased.</value>
</data>
<data name="DonateAlreadyPurchasedTitle" xml:space="preserve">
<value>Purchase</value>
</data>
<data name="DonateNothingToFulfillMessage" xml:space="preserve">
<value>No purchased product to fulfill</value>
</data>
<data name="DonateNothingToFulfillTitle" xml:space="preserve">
<value>Fulfillment</value>
</data>
<data name="DonateNotPurchasedMessage" xml:space="preserve">
<value>The purchase failed because we haven't confirmed fulfillment of a previous purchase.</value>
</data>
<data name="DonateNotPurchasedTitle" xml:space="preserve">
<value>Purchase</value>
</data>
<data name="DonatePurchasePendingMessage" xml:space="preserve">
<value>The purchase is pending so we cannot fulfill the product.</value>
</data>
<data name="DonatePurchasePendingTitle" xml:space="preserve">
<value>Purchase</value>
</data>
<data name="DonatePurchaseRevertedMessage" xml:space="preserve">
<value>Your purchase has been reverted.</value>
</data>
<data name="DonatePurchaseRevertedTitle" xml:space="preserve">
<value>Purchase</value>
</data>
<data name="DonateServerErrorMessage" xml:space="preserve">
<value>Impossible to contact the Windows Store, there was an error when fulfilling.</value>
</data>
<data name="DonateServerErrorTitle" xml:space="preserve">
<value>Error</value>
</data>
<data name="DonateSucceededMessage" xml:space="preserve">
<value>Your donation was successful.</value>
</data>
<data name="DonateSucceededTitle" xml:space="preserve">
<value>Thank you!</value>
</data>
<data name="EntityDeleteActionButton" xml:space="preserve">
<value>Delete</value>
</data>
<data name="EntityDeleteCancelButton" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="EntityDeleteTitle" xml:space="preserve">
<value>Warning</value>
</data>
<data name="EntityDeleting" xml:space="preserve">
<value>Deleting</value>
</data>
<data name="EntityRestoredTitle" xml:space="preserve">
<value>Restored</value>
</data>
<data name="EntryDeleted" xml:space="preserve">
<value>Entry permanently removed</value>
</data>
<data name="EntryDeletingConfirmation" xml:space="preserve">
<value>Are you sure you want to delete this entry?</value>
</data>
<data name="EntryNew" xml:space="preserve">
<value>&lt; New entry &gt;</value>
</data>
<data name="EntryRecycled" xml:space="preserve">
<value>Entry moved to the Recycle bin</value>
</data>
<data name="EntryRecyclingConfirmation" xml:space="preserve">
<value>Are you sure you want to send this entry to the recycle bin?</value>
</data>
<data name="EntryRestored" xml:space="preserve">
<value>Entry returned to its original group</value>
</data>
<data name="GroupDeleted" xml:space="preserve">
<value>Group permanently removed</value>
</data>
<data name="GroupDeletingConfirmation" xml:space="preserve">
<value>Are you sure you want to delete the whole group and all its entries?</value>
</data>
<data name="GroupNew" xml:space="preserve">
<value>&lt; New group &gt;</value>
</data>
<data name="GroupRecycled" xml:space="preserve">
<value>Group moved to the Recycle bin</value>
</data>
<data name="GroupRecyclingConfirmation" xml:space="preserve">
<value>Are you sure you want to send the whole group and all its entries to the recycle bin?</value>
</data>
<data name="GroupRestored" xml:space="preserve">
<value>Group returned to its original group</value>
</data>
<data name="MainMenuItemAbout" xml:space="preserve">
<value>About</value>
</data>
<data name="MainMenuItemDonate" xml:space="preserve">
<value>Donate</value>
</data>
<data name="MainMenuItemNew" xml:space="preserve">
<value>New</value>
</data>
<data name="MainMenuItemOpen" xml:space="preserve">
<value>Open</value>
</data>
<data name="MainMenuItemRecent" xml:space="preserve">
<value>Recent</value>
</data>
<data name="MainMenuItemSave" xml:space="preserve">
<value>Save</value>
</data>
<data name="MainMenuItemSettings" xml:space="preserve">
<value>Settings</value>
</data>
<data name="SettingsMenuGroupApplication" xml:space="preserve">
<value>Application</value>
</data>
<data name="SettingsMenuGroupDatabase" xml:space="preserve">
<value>Database</value>
</data>
<data name="SettingsMenuItemGeneral" xml:space="preserve">
<value>General</value>
</data>
<data name="SettingsMenuItemNew" xml:space="preserve">
<value>New</value>
</data>
<data name="SettingsMenuItemSecurity" xml:space="preserve">
<value>Security</value>
</data>
</root>

View File

@@ -0,0 +1,354 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AboutCredits1.Text" xml:space="preserve">
<value>Dominik Reichl for the KeePass application and file format</value>
</data>
<data name="AboutCredits2.Text" xml:space="preserve">
<value>David Lechner for his PCL adapatation of the KeePass Library and his correlated tests</value>
</data>
<data name="AboutCreditsLabel.Text" xml:space="preserve">
<value>Credits</value>
</data>
<data name="AboutDesc.Text" xml:space="preserve">
<value>A modern password manager for the Windows Store</value>
</data>
<data name="AboutHomepage.Text" xml:space="preserve">
<value>Homepage:</value>
</data>
<data name="AppBarDelete.Label" xml:space="preserve">
<value>Delete</value>
</data>
<data name="AppBarEdit.Label" xml:space="preserve">
<value>Edit</value>
</data>
<data name="AppBarHome.Label" xml:space="preserve">
<value>Home</value>
</data>
<data name="AppBarRestore.Label" xml:space="preserve">
<value>Restore</value>
</data>
<data name="AppBarSave.Label" xml:space="preserve">
<value>Save</value>
</data>
<data name="AppBarSettings.Label" xml:space="preserve">
<value>Settings</value>
</data>
<data name="AppBarSort.Label" xml:space="preserve">
<value>Sort</value>
</data>
<data name="AppBarSortEntries.Text" xml:space="preserve">
<value>Entries</value>
</data>
<data name="AppBarSortGroups.Text" xml:space="preserve">
<value>Groups</value>
</data>
<data name="CompositeKeyNewButton.ButtonLabel" xml:space="preserve">
<value>Create</value>
</data>
<data name="CompositeKeyNewKeyFileTooltip.Content" xml:space="preserve">
<value>Create new key file</value>
</data>
<data name="CompositeKeyOpenButton.ButtonLabel" xml:space="preserve">
<value>Open</value>
</data>
<data name="CompositeKeyPassword.PlaceholderText" xml:space="preserve">
<value>Password</value>
</data>
<data name="DonateButton.Content" xml:space="preserve">
<value>Donate</value>
</data>
<data name="DonateDesc.Text" xml:space="preserve">
<value>Like this app? Why not make a small donation to support my work and help this app stay ad-free :) ?</value>
</data>
<data name="EntryExpirationDate.Content" xml:space="preserve">
<value>Expiration date</value>
</data>
<data name="EntryExpirationTooltip.Content" xml:space="preserve">
<value>Password has expired</value>
</data>
<data name="EntryLogin.Text" xml:space="preserve">
<value>User name or login</value>
</data>
<data name="EntryNotes.Text" xml:space="preserve">
<value>Notes</value>
</data>
<data name="EntryPassword.Text" xml:space="preserve">
<value>Password</value>
</data>
<data name="EntryShowPassword.Content" xml:space="preserve">
<value>Show password</value>
</data>
<data name="GroupCreateEntry.Text" xml:space="preserve">
<value>Create new entry</value>
</data>
<data name="GroupFilter.PlaceholderText" xml:space="preserve">
<value>Filter...</value>
</data>
<data name="GroupNewItemTextBox.Text" xml:space="preserve">
<value>&lt; New group &gt;</value>
</data>
<data name="GroupNewItemTooltip.Content" xml:space="preserve">
<value>&lt; New group &gt;</value>
</data>
<data name="GroupSearch.PlaceholderText" xml:space="preserve">
<value>Search...</value>
</data>
<data name="GroupTitle.PlaceholderText" xml:space="preserve">
<value>New group name...</value>
</data>
<data name="NewCreateButton.Content" xml:space="preserve">
<value>Create new...</value>
</data>
<data name="NewCreateDesc.Text" xml:space="preserve">
<value>Create a new password database to the location of your chosing.</value>
</data>
<data name="OpenBrowseButton.Content" xml:space="preserve">
<value>Browse files...</value>
</data>
<data name="OpenBrowseDesc.Text" xml:space="preserve">
<value>Open an existing password database from your PC.</value>
</data>
<data name="OpenUrlButton.Content" xml:space="preserve">
<value>From Url...</value>
</data>
<data name="OpenUrlDesc.Text" xml:space="preserve">
<value>Open an existing password database from an Internet location (not yet implemented).</value>
</data>
<data name="PasswordGeneratorAlso.Text" xml:space="preserve">
<value>Also add these characters:</value>
</data>
<data name="PasswordGeneratorBrackets.Content" xml:space="preserve">
<value>Brackets ([], {}, (), ...)</value>
</data>
<data name="PasswordGeneratorButton.Content" xml:space="preserve">
<value>Generate</value>
</data>
<data name="PasswordGeneratorDigits.Content" xml:space="preserve">
<value>Digits (0, 1, 2, ...)</value>
</data>
<data name="PasswordGeneratorLength.Text" xml:space="preserve">
<value>Password Length:</value>
</data>
<data name="PasswordGeneratorLower.Content" xml:space="preserve">
<value>Lower case (a, b, c, ...)</value>
</data>
<data name="PasswordGeneratorMinus.Content" xml:space="preserve">
<value>Minus (-)</value>
</data>
<data name="PasswordGeneratorSpace.Content" xml:space="preserve">
<value>Space ( )</value>
</data>
<data name="PasswordGeneratorSpecial.Content" xml:space="preserve">
<value>Special (!, $, %, ...)</value>
</data>
<data name="PasswordGeneratorTooltip.Content" xml:space="preserve">
<value>Generate password</value>
</data>
<data name="PasswordGeneratorUnderscore.Content" xml:space="preserve">
<value>Underscore (_)</value>
</data>
<data name="PasswordGeneratorUpper.Content" xml:space="preserve">
<value>Upper case (A, B, C, ...)</value>
</data>
<data name="RecentClear.Text" xml:space="preserve">
<value>Clear all</value>
</data>
<data name="SaveAsButton.Content" xml:space="preserve">
<value>Save as...</value>
</data>
<data name="SaveAsDesc.Text" xml:space="preserve">
<value>This will save the currently opened database as a new file and leave it open.</value>
</data>
<data name="SaveButton.Content" xml:space="preserve">
<value>Save and close</value>
</data>
<data name="SaveDesc.Text" xml:space="preserve">
<value>This will save and close the currently opened database.</value>
</data>
<data name="SettingsDatabaseCompression.Text" xml:space="preserve">
<value>Compression Algorithm</value>
</data>
<data name="SettingsDatabaseEncryption.Text" xml:space="preserve">
<value>Encryption Algorithm</value>
</data>
<data name="SettingsDatabaseKdf.Text" xml:space="preserve">
<value>Key Derivation Algorithm</value>
</data>
<data name="SettingsDatabaseRecycleBin.Header" xml:space="preserve">
<value>Recycle bin</value>
</data>
<data name="SettingsDatabaseRecycleBin.OffContent" xml:space="preserve">
<value>Disabled</value>
</data>
<data name="SettingsDatabaseRecycleBin.OnContent" xml:space="preserve">
<value>Enabled</value>
</data>
<data name="SettingsNewDatabaseDesc.Text" xml:space="preserve">
<value>Here, you can change some default options when creating a database.</value>
</data>
<data name="SettingsNewDatabaseKdf.Text" xml:space="preserve">
<value>KDBX database file version</value>
</data>
<data name="SettingsNewDatabaseKdfMoreInfo.Text" xml:space="preserve">
<value>Higher is better, but there may be compatibility issues with older applications</value>
</data>
<data name="SettingsNewDatabaseSample.Header" xml:space="preserve">
<value>Create sample data</value>
</data>
<data name="SettingsNewDatabaseSample.OffContent" xml:space="preserve">
<value>No</value>
</data>
<data name="SettingsNewDatabaseSample.OnContent" xml:space="preserve">
<value>Yes</value>
</data>
<data name="SettingsSecurityDesc1.Text" xml:space="preserve">
<value>Here, you may change your database password, key file, or both. Just click on on</value>
</data>
<data name="SettingsSecurityDesc2.Text" xml:space="preserve">
<value>Update master key</value>
</data>
<data name="SettingsSecurityDesc3.Text" xml:space="preserve">
<value>when you're done. Please make sure to remember the password you choose here!</value>
</data>
<data name="SettingsSecurityTitle.Text" xml:space="preserve">
<value>Change database security options</value>
</data>
<data name="SettingsSecurityUpdateButton.ButtonLabel" xml:space="preserve">
<value>Update master key</value>
</data>
<data name="SettingsTitle.Text" xml:space="preserve">
<value>Settings</value>
</data>
<data name="SettingsWelcomeDesc.Text" xml:space="preserve">
<value>Here, you may change the application or the database settings.</value>
</data>
<data name="SettingsWelcomeHowto.Text" xml:space="preserve">
<value>Select a setting pane on the left to access the options.</value>
</data>
<data name="SettingsWelcomeTitle.Text" xml:space="preserve">
<value>Settings</value>
</data>
<data name="WelcomeNew.Text" xml:space="preserve">
<value>Want to create a new password database? Do it here.</value>
</data>
<data name="WelcomeOpen.Text" xml:space="preserve">
<value>Have an existing password database? Open it here.</value>
</data>
</root>

View File

@@ -0,0 +1,274 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="CompositeKeyDefaultKeyFile" xml:space="preserve">
<value>Choisissez un fichier...</value>
</data>
<data name="CompositeKeyErrorOpen" xml:space="preserve">
<value>Erreur</value>
</data>
<data name="CompositeKeyErrorUserKeyFile" xml:space="preserve">
<value>fichier de clé</value>
</data>
<data name="CompositeKeyErrorUserOr" xml:space="preserve">
<value> ou </value>
</data>
<data name="CompositeKeyErrorUserPassword" xml:space="preserve">
<value>mot de passe</value>
</data>
<data name="CompositeKeyErrorUserStart" xml:space="preserve">
<value>Erreur: mauvais </value>
</data>
<data name="CompositeKeyOpening" xml:space="preserve">
<value>Ouverture...</value>
</data>
<data name="CompositeKeyUpdated" xml:space="preserve">
<value>Clé composite de la base de données mise à jour.</value>
</data>
<data name="DonateAlreadyPurchasedMessage" xml:space="preserve">
<value>Vous avez déjà acheté ce produit.</value>
</data>
<data name="DonateAlreadyPurchasedTitle" xml:space="preserve">
<value>Achat</value>
</data>
<data name="DonateNothingToFulfillMessage" xml:space="preserve">
<value>Il n'y a aucun produit acheté à valider.</value>
</data>
<data name="DonateNothingToFulfillTitle" xml:space="preserve">
<value>Validation</value>
</data>
<data name="DonateNotPurchasedMessage" xml:space="preserve">
<value>L'achat a échoué parce que nous n'avons pas pu valider un achat précédent.</value>
</data>
<data name="DonateNotPurchasedTitle" xml:space="preserve">
<value>Achat</value>
</data>
<data name="DonatePurchasePendingMessage" xml:space="preserve">
<value>Un achat est en cours donc nous ne pouvons le valider.</value>
</data>
<data name="DonatePurchasePendingTitle" xml:space="preserve">
<value>Achat</value>
</data>
<data name="DonatePurchaseRevertedMessage" xml:space="preserve">
<value>Votre achat a été annulé.</value>
</data>
<data name="DonatePurchaseRevertedTitle" xml:space="preserve">
<value>Achat</value>
</data>
<data name="DonateServerErrorMessage" xml:space="preserve">
<value>Impossible de contacter le Windows Store, l'achat n'a pas été réalisé.</value>
</data>
<data name="DonateServerErrorTitle" xml:space="preserve">
<value>Erreur</value>
</data>
<data name="DonateSucceededMessage" xml:space="preserve">
<value>Votre don a été enregistré.</value>
</data>
<data name="DonateSucceededTitle" xml:space="preserve">
<value>Merci!</value>
</data>
<data name="EntityDeleteActionButton" xml:space="preserve">
<value>Supprimer</value>
</data>
<data name="EntityDeleteCancelButton" xml:space="preserve">
<value>Annuler</value>
</data>
<data name="EntityDeleteTitle" xml:space="preserve">
<value>Attention</value>
</data>
<data name="EntityDeleting" xml:space="preserve">
<value>Suprression</value>
</data>
<data name="EntityRestoredTitle" xml:space="preserve">
<value>Restauré</value>
</data>
<data name="EntryDeleted" xml:space="preserve">
<value>Entrée supprimée définitivement</value>
</data>
<data name="EntryDeletingConfirmation" xml:space="preserve">
<value>Êtes-vous sûr de vouloir supprimer cette entrée ?</value>
</data>
<data name="EntryNew" xml:space="preserve">
<value>&lt; Nouvelle entrée &gt;</value>
<comment>Unused</comment>
</data>
<data name="EntryRecycled" xml:space="preserve">
<value>Entrée placée dans la Corbeille</value>
</data>
<data name="EntryRecyclingConfirmation" xml:space="preserve">
<value>Êtes-vous sûr de vouloir placer cette entrée dans la Corbeille ?</value>
</data>
<data name="EntryRestored" xml:space="preserve">
<value>Entrée replacée dans son groupe d'origine</value>
</data>
<data name="GroupDeleted" xml:space="preserve">
<value>Groupe supprimé défnitivement</value>
</data>
<data name="GroupDeletingConfirmation" xml:space="preserve">
<value>Êtes-vous sûr de vouloir supprimer ce group et toutes ses entrées ?</value>
</data>
<data name="GroupNew" xml:space="preserve">
<value>&lt; Nouveau groupe &gt;</value>
</data>
<data name="GroupRecycled" xml:space="preserve">
<value>Groupe placé dans la Corbeille</value>
</data>
<data name="GroupRecyclingConfirmation" xml:space="preserve">
<value>Êtes-vous sûr de vouloir envoyer ce groupe et toutes ses entrées vers la Corbeille ?</value>
</data>
<data name="GroupRestored" xml:space="preserve">
<value>Groupe replacé à sa place originelle</value>
</data>
<data name="MainMenuItemAbout" xml:space="preserve">
<value>A propos</value>
</data>
<data name="MainMenuItemDonate" xml:space="preserve">
<value>Donation</value>
</data>
<data name="MainMenuItemNew" xml:space="preserve">
<value>Nouveau</value>
</data>
<data name="MainMenuItemOpen" xml:space="preserve">
<value>Ouvrir</value>
</data>
<data name="MainMenuItemRecent" xml:space="preserve">
<value>Récents</value>
</data>
<data name="MainMenuItemSave" xml:space="preserve">
<value>Sauvegarder</value>
</data>
<data name="MainMenuItemSettings" xml:space="preserve">
<value>Paramètres</value>
</data>
<data name="SettingsMenuGroupApplication" xml:space="preserve">
<value>Application</value>
</data>
<data name="SettingsMenuGroupDatabase" xml:space="preserve">
<value>Base de données</value>
</data>
<data name="SettingsMenuItemGeneral" xml:space="preserve">
<value>Général</value>
</data>
<data name="SettingsMenuItemNew" xml:space="preserve">
<value>Nouveau</value>
</data>
<data name="SettingsMenuItemSecurity" xml:space="preserve">
<value>Sécurité</value>
</data>
</root>

View File

@@ -0,0 +1,354 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AboutCredits1.Text" xml:space="preserve">
<value>Dominik Reichl pour l'application KeePass et le format de fichier</value>
</data>
<data name="AboutCredits2.Text" xml:space="preserve">
<value>David Lechner pour son adaptation PCL de la blibliothèque KeePass et ses tests associés</value>
</data>
<data name="AboutCreditsLabel.Text" xml:space="preserve">
<value>Crédits</value>
</data>
<data name="AboutDesc.Text" xml:space="preserve">
<value>Un gestionnaire de mot de passes moderne pour le Windows Store</value>
</data>
<data name="AboutHomepage.Text" xml:space="preserve">
<value>Page d'accueil :</value>
</data>
<data name="AppBarDelete.Label" xml:space="preserve">
<value>Supprimer</value>
</data>
<data name="AppBarEdit.Label" xml:space="preserve">
<value>Editer</value>
</data>
<data name="AppBarHome.Label" xml:space="preserve">
<value>Accueil</value>
</data>
<data name="AppBarRestore.Label" xml:space="preserve">
<value>Restorer</value>
</data>
<data name="AppBarSave.Label" xml:space="preserve">
<value>Sauvegarder</value>
</data>
<data name="AppBarSettings.Label" xml:space="preserve">
<value>Paramètres</value>
</data>
<data name="AppBarSort.Label" xml:space="preserve">
<value>Trier</value>
</data>
<data name="AppBarSortEntries.Text" xml:space="preserve">
<value>Entrées</value>
</data>
<data name="AppBarSortGroups.Text" xml:space="preserve">
<value>Groupes</value>
</data>
<data name="CompositeKeyNewButton.ButtonLabel" xml:space="preserve">
<value>Créer</value>
</data>
<data name="CompositeKeyNewKeyFileTooltip.Content" xml:space="preserve">
<value>Créer un nouveau fichier de clé</value>
</data>
<data name="CompositeKeyOpenButton.ButtonLabel" xml:space="preserve">
<value>Ouvrir</value>
</data>
<data name="CompositeKeyPassword.PlaceholderText" xml:space="preserve">
<value>Mot de passe</value>
</data>
<data name="DonateButton.Content" xml:space="preserve">
<value>Donner</value>
</data>
<data name="DonateDesc.Text" xml:space="preserve">
<value>Vous aimez cette app? Pourquoi ne pas faire un petit don afin de m'encourager et d'éviter le recours aux publicités :) ?</value>
</data>
<data name="EntryExpirationDate.Content" xml:space="preserve">
<value>Date d'expiration</value>
</data>
<data name="EntryExpirationTooltip.Content" xml:space="preserve">
<value>Le mot de passe a expiré</value>
</data>
<data name="EntryLogin.Text" xml:space="preserve">
<value>Nom d'utilisateur ou login</value>
</data>
<data name="EntryNotes.Text" xml:space="preserve">
<value>Notes</value>
</data>
<data name="EntryPassword.Text" xml:space="preserve">
<value>Mot de passe</value>
</data>
<data name="EntryShowPassword.Content" xml:space="preserve">
<value>Afficher le mot de passe</value>
</data>
<data name="GroupCreateEntry.Text" xml:space="preserve">
<value>Créer une nouvelle entrée</value>
</data>
<data name="GroupFilter.PlaceholderText" xml:space="preserve">
<value>Filtrer...</value>
</data>
<data name="GroupNewItemTextBox.Text" xml:space="preserve">
<value>&lt; Nouveau groupe &gt;</value>
</data>
<data name="GroupNewItemTooltip.Content" xml:space="preserve">
<value>&lt; Nouveau groupe &gt;</value>
</data>
<data name="GroupSearch.PlaceholderText" xml:space="preserve">
<value>Rechercher...</value>
</data>
<data name="GroupTitle.PlaceholderText" xml:space="preserve">
<value>Nom du nouveau groupe...</value>
</data>
<data name="NewCreateButton.Content" xml:space="preserve">
<value>Créer une nouvelle...</value>
</data>
<data name="NewCreateDesc.Text" xml:space="preserve">
<value>Créer une nouvelle base de données de mots de passe à l'endroit de votre choix.</value>
</data>
<data name="OpenBrowseButton.Content" xml:space="preserve">
<value>Parcourir les fichiers...</value>
</data>
<data name="OpenBrowseDesc.Text" xml:space="preserve">
<value>Ouvrir une base de données de mots de passe existante sur votre PC.</value>
</data>
<data name="OpenUrlButton.Content" xml:space="preserve">
<value>Depuis une URL...</value>
</data>
<data name="OpenUrlDesc.Text" xml:space="preserve">
<value>Ouvrir une base de données de mots de passe depuis Internet (pas encore implementé).</value>
</data>
<data name="PasswordGeneratorAlso.Text" xml:space="preserve">
<value>Ajouter aussi ces caractères :</value>
</data>
<data name="PasswordGeneratorBrackets.Content" xml:space="preserve">
<value>Parenthèses ([], {}, (), ...)</value>
</data>
<data name="PasswordGeneratorButton.Content" xml:space="preserve">
<value>Générer</value>
</data>
<data name="PasswordGeneratorDigits.Content" xml:space="preserve">
<value>Chiffres (0, 1, 2, ...)</value>
</data>
<data name="PasswordGeneratorLength.Text" xml:space="preserve">
<value>Longueur de mot de passe :</value>
</data>
<data name="PasswordGeneratorLower.Content" xml:space="preserve">
<value>Minuscules (a, b, c, ...)</value>
</data>
<data name="PasswordGeneratorMinus.Content" xml:space="preserve">
<value>Moins (-)</value>
</data>
<data name="PasswordGeneratorSpace.Content" xml:space="preserve">
<value>Espace ( )</value>
</data>
<data name="PasswordGeneratorSpecial.Content" xml:space="preserve">
<value>Spéciaux (!, $, %, ...)</value>
</data>
<data name="PasswordGeneratorTooltip.Content" xml:space="preserve">
<value>Générer le mot de passe</value>
</data>
<data name="PasswordGeneratorUnderscore.Content" xml:space="preserve">
<value>Underscore (_)</value>
</data>
<data name="PasswordGeneratorUpper.Content" xml:space="preserve">
<value>Majuscules (A, B, C, ...)</value>
</data>
<data name="RecentClear.Text" xml:space="preserve">
<value>Supprimer tout</value>
</data>
<data name="SaveAsButton.Content" xml:space="preserve">
<value>Sauvegarder sous...</value>
</data>
<data name="SaveAsDesc.Text" xml:space="preserve">
<value>Cela va sauvegarder la base de données dans un nouveau fichier et l'ouvrir.</value>
</data>
<data name="SaveButton.Content" xml:space="preserve">
<value>Sauvegarder et fermer</value>
</data>
<data name="SaveDesc.Text" xml:space="preserve">
<value>Cela va sauvegarder et fermer la base de données.</value>
</data>
<data name="SettingsDatabaseCompression.Text" xml:space="preserve">
<value>Algorithme de compression</value>
</data>
<data name="SettingsDatabaseEncryption.Text" xml:space="preserve">
<value>Algorithme de chiffrement</value>
</data>
<data name="SettingsDatabaseKdf.Text" xml:space="preserve">
<value>Algorithme de dérivation de clé</value>
</data>
<data name="SettingsDatabaseRecycleBin.Header" xml:space="preserve">
<value>Corbeille</value>
</data>
<data name="SettingsDatabaseRecycleBin.OffContent" xml:space="preserve">
<value>Désactivé</value>
</data>
<data name="SettingsDatabaseRecycleBin.OnContent" xml:space="preserve">
<value>Activé</value>
</data>
<data name="SettingsNewDatabaseDesc.Text" xml:space="preserve">
<value>Ici, vous pouvez changer certains options lors de la création d'une nouvelle base de données</value>
</data>
<data name="SettingsNewDatabaseKdf.Text" xml:space="preserve">
<value>Version de fichier KDBX</value>
</data>
<data name="SettingsNewDatabaseKdfMoreInfo.Text" xml:space="preserve">
<value>Le plus élévé est le mieux, mais vous pourriez rencontrer des problèmes de compatibilité avec des application plus anciennes</value>
</data>
<data name="SettingsNewDatabaseSample.Header" xml:space="preserve">
<value>Créer des données d'exemple</value>
</data>
<data name="SettingsNewDatabaseSample.OffContent" xml:space="preserve">
<value>Non</value>
</data>
<data name="SettingsNewDatabaseSample.OnContent" xml:space="preserve">
<value>Oui</value>
</data>
<data name="SettingsSecurityDesc1.Text" xml:space="preserve">
<value>Ici, vous pouvez changer le mot de passe maître, le fichier de clé, ou les deux. Cliquez simplement sur</value>
</data>
<data name="SettingsSecurityDesc2.Text" xml:space="preserve">
<value>Mettre à jour la clé maître</value>
</data>
<data name="SettingsSecurityDesc3.Text" xml:space="preserve">
<value>quand vous avez fini. Retenez bien le mot de passe que vous utilisez !</value>
</data>
<data name="SettingsSecurityTitle.Text" xml:space="preserve">
<value>Changer les options de sécurité de la base de données</value>
</data>
<data name="SettingsSecurityUpdateButton.ButtonLabel" xml:space="preserve">
<value>Mettre à jour la clé maître</value>
</data>
<data name="SettingsTitle.Text" xml:space="preserve">
<value>Paramètres</value>
</data>
<data name="SettingsWelcomeDesc.Text" xml:space="preserve">
<value>Ici, vous pouvez changer les options de l'application ou de la base de données.</value>
</data>
<data name="SettingsWelcomeHowto.Text" xml:space="preserve">
<value>Choisissez un élément dans le menu de gauche.</value>
</data>
<data name="SettingsWelcomeTitle.Text" xml:space="preserve">
<value>Paramètres</value>
</data>
<data name="WelcomeNew.Text" xml:space="preserve">
<value>Pour créer une nouvelle base de données de mots de passe, c'est ici.</value>
</data>
<data name="WelcomeOpen.Text" xml:space="preserve">
<value>Pour ouvrir une base de données existante, c'est ici.</value>
</data>
</root>

View File

@@ -0,0 +1,9 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="TextBlock" x:Name="TextBlockSettingsHeaderStyle" >
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="14.667" />
<Setter Property="FontWeight" Value="SemiLight" />
</Style>
</ResourceDictionary>

View File

@@ -62,7 +62,7 @@
</ObjectAnimationUsingKeyFrames> </ObjectAnimationUsingKeyFrames>
</Storyboard> </Storyboard>
</VisualState> </VisualState>
<VisualState x:Name="Disabled"> <!--<VisualState x:Name="Disabled">
<Storyboard> <Storyboard>
<DoubleAnimation Storyboard.TargetName="BackgroundElement" <DoubleAnimation Storyboard.TargetName="BackgroundElement"
Storyboard.TargetProperty="Opacity" Storyboard.TargetProperty="Opacity"
@@ -73,7 +73,7 @@
To="0" To="0"
Duration="0" /> Duration="0" />
</Storyboard> </Storyboard>
</VisualState> </VisualState>-->
</VisualStateGroup> </VisualStateGroup>
</VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups>
<Border x:Name="BorderElement" <Border x:Name="BorderElement"
@@ -89,6 +89,7 @@
HorizontalAlignment="Center" HorizontalAlignment="Center"
FontStyle="Normal" FontStyle="Normal"
Text="{TemplateBinding Content}" Text="{TemplateBinding Content}"
FontSize="{TemplateBinding FontSize}"
FontFamily="{ThemeResource SymbolThemeFontFamily}" FontFamily="{ThemeResource SymbolThemeFontFamily}"
AutomationProperties.AccessibilityView="Raw"/> AutomationProperties.AccessibilityView="Raw"/>
</Border> </Border>
@@ -142,9 +143,28 @@
Storyboard.TargetProperty="Opacity" Storyboard.TargetProperty="Opacity"
Duration="0" Duration="0"
To="{ThemeResource TextControlPointerOverBorderThemeOpacity}" /> To="{ThemeResource TextControlPointerOverBorderThemeOpacity}" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ActionButton"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ActionButton"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard> </Storyboard>
</VisualState> </VisualState>
<VisualState x:Name="Focused" />
</VisualStateGroup> </VisualStateGroup>
<VisualStateGroup x:Name="ButtonStates"> <VisualStateGroup x:Name="ButtonStates">
<VisualState x:Name="ButtonVisible"> <VisualState x:Name="ButtonVisible">
@@ -199,6 +219,7 @@
IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding BorderThickness}" Margin="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}" Padding="{TemplateBinding Padding}"
IsTabStop="False" IsTabStop="False"
@@ -209,6 +230,7 @@
Foreground="{ThemeResource TextBoxPlaceholderTextThemeBrush}" Foreground="{ThemeResource TextBoxPlaceholderTextThemeBrush}"
Margin="{TemplateBinding BorderThickness}" Margin="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}" Padding="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
IsTabStop="False" IsTabStop="False"
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
Content="{TemplateBinding PlaceholderText}" Content="{TemplateBinding PlaceholderText}"
@@ -222,7 +244,12 @@
Visibility="Collapsed" Visibility="Collapsed"
FontSize="{TemplateBinding FontSize}" FontSize="{TemplateBinding FontSize}"
Content="{TemplateBinding ButtonSymbol}" Content="{TemplateBinding ButtonSymbol}"
VerticalAlignment="Stretch"/> IsEnabled="{TemplateBinding IsButtonEnabled}"
VerticalAlignment="Stretch">
<ToolTipService.ToolTip>
<ToolTip Content="{TemplateBinding ButtonTooltip}" />
</ToolTipService.ToolTip>
</Button>
</Grid> </Grid>
</ControlTemplate> </ControlTemplate>
</Setter.Value> </Setter.Value>

View File

@@ -4,17 +4,24 @@ namespace ModernKeePass.ViewModels
{ {
public class AboutVm public class AboutVm
{ {
public string Name { get; } = Package.Current.DisplayName; private readonly Package _package;
public string Name => _package.DisplayName;
public string Version public string Version
{ {
get get
{ {
var package = Package.Current; var version = _package.Id.Version;
var version = package.Id.Version;
return $"{version.Major}.{version.Minor}"; return $"{version.Major}.{version.Minor}";
} }
} }
public AboutVm() : this(Package.Current) { }
public AboutVm(Package package)
{
_package = package;
}
} }
} }

View File

@@ -1,6 +1,11 @@
using Windows.Storage; using System;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using ModernKeePass.Common; using ModernKeePass.Common;
using ModernKeePass.Interfaces;
using ModernKeePass.Services;
using ModernKeePassLib.Cryptography; using ModernKeePassLib.Cryptography;
using ModernKeePassLib.Keys; using ModernKeePassLib.Keys;
using ModernKeePassLib.Serialization; using ModernKeePassLib.Serialization;
@@ -17,13 +22,7 @@ namespace ModernKeePass.ViewModels
Success = 5 Success = 5
} }
private readonly App _app = Application.Current as App; public IDatabase Database { get; set; }
private bool _hasPassword;
private bool _hasKeyFile;
private string _password = string.Empty;
private string _status;
private StatusTypes _statusType;
private StorageFile _keyFile;
public bool HasPassword public bool HasPassword
{ {
@@ -45,7 +44,7 @@ namespace ModernKeePass.ViewModels
} }
} }
public bool IsValid => HasPassword || HasKeyFile; public bool IsValid => !_isOpening && (HasPassword || HasKeyFile && KeyFile != null);
public string Status public string Status
{ {
@@ -67,6 +66,7 @@ namespace ModernKeePass.ViewModels
_password = value; _password = value;
OnPropertyChanged("PasswordComplexityIndicator"); OnPropertyChanged("PasswordComplexityIndicator");
StatusType = (int)StatusTypes.Normal; StatusType = (int)StatusTypes.Normal;
Status = string.Empty;
} }
} }
@@ -76,24 +76,86 @@ namespace ModernKeePass.ViewModels
set set
{ {
_keyFile = value; _keyFile = value;
UpdateStatus($"Key file: {value.Name}", StatusTypes.Normal); KeyFileText = value?.Name;
OnPropertyChanged("IsValid");
} }
} }
public string KeyFileText
{
get { return _keyFileText; }
set { SetProperty(ref _keyFileText, value); }
}
public GroupVm RootGroup { get; set; } public GroupVm RootGroup { get; set; }
public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password?.ToCharArray()); public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password?.ToCharArray());
public DatabaseHelper.DatabaseStatus OpenDatabase(bool createNew) private bool _hasPassword;
private bool _hasKeyFile;
private bool _isOpening;
private string _password = string.Empty;
private string _status;
private StatusTypes _statusType;
private StorageFile _keyFile;
private string _keyFileText;
private readonly IResource _resource;
public CompositeKeyVm() : this((Application.Current as App)?.Database, new ResourcesService()) { }
public CompositeKeyVm(IDatabase database, IResource resource)
{ {
UpdateStatus(_app.Database.Open(CreateCompositeKey(), createNew), StatusTypes.Error); _resource = resource;
RootGroup = _app.Database.RootGroup; _keyFileText = _resource.GetResourceValue("CompositeKeyDefaultKeyFile");
return _app.Database.Status; Database = database;
}
public async Task<bool> OpenDatabase(bool createNew)
{
var error = string.Empty;
try
{
_isOpening = true;
Database.Open(CreateCompositeKey(), createNew);
}
catch (Exception e)
{
error = $"{_resource.GetResourceValue("CompositeKeyErrorOpen")}: {e.Message}";
}
finally
{
_isOpening = false;
}
switch ((DatabaseService.DatabaseStatus)Database.Status)
{
case DatabaseService.DatabaseStatus.Opened:
await Task.Run(() => RootGroup = Database.RootGroup);
return true;
case DatabaseService.DatabaseStatus.CompositeKeyError:
var errorMessage = new StringBuilder(_resource.GetResourceValue("CompositeKeyErrorUserStart"));
if (HasPassword) errorMessage.Append(_resource.GetResourceValue("CompositeKeyErrorUserPassword"));
if (HasPassword && HasKeyFile) errorMessage.Append(_resource.GetResourceValue("CompositeKeyErrorUserOr"));
if (HasKeyFile) errorMessage.Append(_resource.GetResourceValue("CompositeKeyErrorUserKeyFile"));
UpdateStatus(errorMessage.ToString(), StatusTypes.Error);
break;
case DatabaseService.DatabaseStatus.Error:
UpdateStatus(error, StatusTypes.Error);
break;
}
return false;
} }
public void UpdateKey() public void UpdateKey()
{ {
_app.Database.UpdateCompositeKey(CreateCompositeKey()); Database.UpdateCompositeKey(CreateCompositeKey());
UpdateStatus("Database composite key updated.", StatusTypes.Success); UpdateStatus(_resource.GetResourceValue("CompositeKeyUpdated"), StatusTypes.Success);
}
public void CreateKeyFile(StorageFile file)
{
// TODO: implement entropy generator
KcpKeyFile.Create(file, null);
KeyFile = file;
} }
private void UpdateStatus(string text, StatusTypes type) private void UpdateStatus(string text, StatusTypes type)
@@ -106,7 +168,7 @@ namespace ModernKeePass.ViewModels
{ {
var compositeKey = new CompositeKey(); var compositeKey = new CompositeKey();
if (HasPassword) compositeKey.AddUserKey(new KcpPassword(Password)); if (HasPassword) compositeKey.AddUserKey(new KcpPassword(Password));
if (HasKeyFile) compositeKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromFile(KeyFile))); if (HasKeyFile && KeyFile != null) compositeKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromFile(KeyFile)));
return compositeKey; return compositeKey;
} }
} }

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel.Store;
using ModernKeePass.Common;
using ModernKeePass.Interfaces;
using ModernKeePass.Services;
namespace ModernKeePass.ViewModels
{
public class DonateVm: NotifyPropertyChangedBase
{
public ObservableCollection<ProductListing> Donations { get; }
public ProductListing SelectedItem
{
get { return _selectedItem; }
set { SetProperty(ref _selectedItem, value); }
}
private readonly ILicenseService _license;
private ProductListing _selectedItem;
public DonateVm() : this (new LicenseService()) { }
public DonateVm(ILicenseService license)
{
// TODO: find a nice way to order products
_license = license;
Donations = new ObservableCollection<ProductListing>(
_license.Products.Values
/*.OrderBy(p => decimal.Parse(p.FormattedPrice.Replace('\u00A0', ' '), NumberStyles.Currency,
CultureInfo.CurrentCulture.NumberFormat))*/
);
}
public async Task<int> Purchase()
{
return await _license.Purchase(SelectedItem.ProductId);
}
}
}

View File

@@ -5,6 +5,7 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using ModernKeePass.Interfaces; using ModernKeePass.Interfaces;
using ModernKeePass.Mappings; using ModernKeePass.Mappings;
using ModernKeePass.Services;
using ModernKeePassLib; using ModernKeePassLib;
using ModernKeePassLib.Cryptography.PasswordGenerator; using ModernKeePassLib.Cryptography.PasswordGenerator;
using ModernKeePassLib.Security; using ModernKeePassLib.Security;
@@ -15,17 +16,13 @@ namespace ModernKeePass.ViewModels
public class EntryVm : INotifyPropertyChanged, IPwEntity public class EntryVm : INotifyPropertyChanged, IPwEntity
{ {
public GroupVm ParentGroup { get; private set; } public GroupVm ParentGroup { get; private set; }
public GroupVm PreviousGroup { get; private set; } public GroupVm PreviousGroup { get; private set; }
public System.Drawing.Color? BackgroundColor => _pwEntry?.BackgroundColor; public System.Drawing.Color? BackgroundColor => _pwEntry?.BackgroundColor;
public System.Drawing.Color? ForegroundColor => _pwEntry?.ForegroundColor; public System.Drawing.Color? ForegroundColor => _pwEntry?.ForegroundColor;
public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password); public bool IsRevealPasswordEnabled => !string.IsNullOrEmpty(Password);
public bool HasExpired => HasExpirationDate && _pwEntry.ExpiryTime < DateTime.Now; public bool HasExpired => HasExpirationDate && _pwEntry.ExpiryTime < DateTime.Now;
public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password.ToCharArray()); public double PasswordComplexityIndicator => QualityEstimation.EstimatePasswordBits(Password.ToCharArray());
public bool IsFirstItem => _pwEntry == null; public bool IsFirstItem => _pwEntry == null;
public bool UpperCasePatternSelected { get; set; } = true; public bool UpperCasePatternSelected { get; set; } = true;
public bool LowerCasePatternSelected { get; set; } = true; public bool LowerCasePatternSelected { get; set; } = true;
public bool DigitsPatternSelected { get; set; } = true; public bool DigitsPatternSelected { get; set; } = true;
@@ -36,6 +33,7 @@ namespace ModernKeePass.ViewModels
public bool BracketsPatternSelected { get; set; } public bool BracketsPatternSelected { get; set; }
public string CustomChars { get; set; } = string.Empty; public string CustomChars { get; set; } = string.Empty;
public PwUuid IdUuid => _pwEntry?.Uuid; public PwUuid IdUuid => _pwEntry?.Uuid;
public string Id => _pwEntry?.Uuid.ToHexString();
public double PasswordLength public double PasswordLength
{ {
@@ -46,17 +44,18 @@ namespace ModernKeePass.ViewModels
NotifyPropertyChanged("PasswordLength"); NotifyPropertyChanged("PasswordLength");
} }
} }
public string Name public string Name
{ {
get get
{ {
var title = GetEntryValue(PwDefs.TitleField); /*var title = GetEntryValue(PwDefs.TitleField);
return title == null ? "< New entry >" : title; return title == null ? _resource.GetResourceValue("EntryNew") : title;*/
return GetEntryValue(PwDefs.TitleField);
} }
set { SetEntryValue(PwDefs.TitleField, value); } set { SetEntryValue(PwDefs.TitleField, value); }
} }
public string Id => _pwEntry?.Uuid.ToHexString();
public string UserName public string UserName
{ {
@@ -118,6 +117,8 @@ namespace ModernKeePass.ViewModels
} }
} }
public bool IsRecycleOnDelete => _database.RecycleBinEnabled && !ParentGroup.IsSelected;
public bool IsRevealPassword public bool IsRevealPassword
{ {
get { return _isRevealPassword; } get { return _isRevealPassword; }
@@ -150,7 +151,7 @@ namespace ModernKeePass.ViewModels
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
private readonly PwEntry _pwEntry; private readonly PwEntry _pwEntry;
private readonly App _app = Application.Current as App; private readonly IDatabase _database;
private bool _isEditMode; private bool _isEditMode;
private bool _isRevealPassword; private bool _isRevealPassword;
private double _passwordLength = 25; private double _passwordLength = 25;
@@ -161,15 +162,19 @@ namespace ModernKeePass.ViewModels
} }
public EntryVm() { } public EntryVm() { }
public EntryVm(PwEntry entry, GroupVm parent)
internal EntryVm(PwEntry entry, GroupVm parent) : this(entry, parent, (Application.Current as App)?.Database) { }
public EntryVm(PwEntry entry, GroupVm parent, IDatabase database)
{ {
_database = database;
_pwEntry = entry; _pwEntry = entry;
ParentGroup = parent; ParentGroup = parent;
} }
public void GeneratePassword() public void GeneratePassword()
{ {
var pwProfile = new PwProfile() var pwProfile = new PwProfile
{ {
GeneratorType = PasswordGeneratorType.CharSet, GeneratorType = PasswordGeneratorType.CharSet,
Length = (uint)PasswordLength, Length = (uint)PasswordLength,
@@ -208,9 +213,9 @@ namespace ModernKeePass.ViewModels
public void MarkForDelete() public void MarkForDelete()
{ {
if (_app.Database.RecycleBinEnabled && _app.Database.RecycleBin?.IdUuid == null) if (_database.RecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
_app.Database.CreateRecycleBin(); _database.CreateRecycleBin();
Move(_app.Database.RecycleBinEnabled && !ParentGroup.IsSelected ? _app.Database.RecycleBin : null); Move(_database.RecycleBinEnabled && !ParentGroup.IsSelected ? _database.RecycleBin : null);
} }
public void UndoDelete() public void UndoDelete()
@@ -222,27 +227,29 @@ namespace ModernKeePass.ViewModels
{ {
PreviousGroup = ParentGroup; PreviousGroup = ParentGroup;
PreviousGroup.Entries.Remove(this); PreviousGroup.Entries.Remove(this);
PreviousGroup.RemovePwEntry(_pwEntry);
if (destination == null) if (destination == null)
{ {
_app.Database.AddDeletedItem(IdUuid); _database.AddDeletedItem(IdUuid);
return; return;
} }
ParentGroup = destination; ParentGroup = destination;
ParentGroup.Entries.Add(this); ParentGroup.Entries.Add(this);
ParentGroup.AddPwEntry(_pwEntry);
} }
public void CommitDelete() public void CommitDelete()
{ {
_pwEntry.ParentGroup.Entries.Remove(_pwEntry); _pwEntry.ParentGroup.Entries.Remove(_pwEntry);
if (_app.Database.RecycleBinEnabled && !PreviousGroup.IsSelected) _app.Database.RecycleBin.AddPwEntry(_pwEntry); if (!_database.RecycleBinEnabled || PreviousGroup.IsSelected) _database.AddDeletedItem(IdUuid);
else _app.Database.AddDeletedItem(IdUuid);
} }
public void Save() public void Save()
{ {
_app.Database.Save(); _database.Save();
}
public PwEntry GetPwEntry()
{
return _pwEntry;
} }
} }
} }

View File

@@ -1,7 +1,8 @@
using System.Collections.ObjectModel; using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Windows.UI.Text;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using ModernKeePass.Common; using ModernKeePass.Common;
@@ -15,33 +16,32 @@ namespace ModernKeePass.ViewModels
{ {
public GroupVm ParentGroup { get; private set; } public GroupVm ParentGroup { get; private set; }
public GroupVm PreviousGroup { get; private set; } public GroupVm PreviousGroup { get; private set; }
public ObservableCollection<EntryVm> Entries { get; set; } = new ObservableCollection<EntryVm>();
public ObservableCollection<EntryVm> Entries
{
get { return _entries; }
set { SetProperty(ref _entries, value); }
}
public ObservableCollection<GroupVm> Groups { get; set; } = new ObservableCollection<GroupVm>(); public ObservableCollection<GroupVm> Groups { get; set; } = new ObservableCollection<GroupVm>();
public int EntryCount => Entries.Count() - 1;
public FontWeight FontWeight => _pwGroup == null ? FontWeights.Bold : FontWeights.Normal;
public int GroupCount => Groups.Count - 1;
public PwUuid IdUuid => _pwGroup?.Uuid; public PwUuid IdUuid => _pwGroup?.Uuid;
public string Id => IdUuid?.ToHexString(); public string Id => IdUuid?.ToHexString();
public bool IsNotRoot => ParentGroup != null; public bool IsNotRoot => ParentGroup != null;
public bool ShowRestore => IsNotRoot && ParentGroup.IsSelected; public bool ShowRestore => IsNotRoot && ParentGroup.IsSelected;
public bool IsRecycleOnDelete => _database.RecycleBinEnabled && !IsSelected && !ParentGroup.IsSelected;
/// <summary> /// <summary>
/// Is the Group the database Recycle Bin? /// Is the Group the database Recycle Bin?
/// </summary> /// </summary>
public bool IsSelected public bool IsSelected
{ {
get { return _app.Database.RecycleBinEnabled && _app.Database.RecycleBin?.Id == Id; } get { return _database != null && _database.RecycleBinEnabled && _database.RecycleBin?.Id == Id; }
set set
{ {
if (value && _pwGroup != null) _app.Database.RecycleBin = this; if (value && _pwGroup != null) _database.RecycleBin = this;
/*else if (value && _pwGroup == null)
{
var recycleBin = _app.Database.RootGroup.AddNewGroup("Recycle bin");
recycleBin.IsSelected = true;
recycleBin.IconSymbol = Symbol.Delete;
}*/
} }
} }
@@ -53,7 +53,7 @@ namespace ModernKeePass.ViewModels
public string Name public string Name
{ {
get { return _pwGroup == null ? "< New group >" : _pwGroup.Name; } get { return _pwGroup == null ? string.Empty : _pwGroup.Name; }
set { _pwGroup.Name = value; } set { _pwGroup.Name = value; }
} }
@@ -74,6 +74,25 @@ namespace ModernKeePass.ViewModels
set { SetProperty(ref _isEditMode, value); } set { SetProperty(ref _isEditMode, value); }
} }
public bool IsMenuClosed
{
get { return _isMenuClosed; }
set { SetProperty(ref _isMenuClosed, value); }
}
public string Filter
{
get { return _filter; }
set
{
SetProperty(ref _filter, value);
OnPropertyChanged("EntriesFiltered");
}
}
public ObservableCollection<EntryVm> EntriesFiltered =>
new ObservableCollection<EntryVm>(Entries.Where(e => e.Name.IndexOf(Filter, StringComparison.OrdinalIgnoreCase) >= 0));
public string Path public string Path
{ {
get get
@@ -86,21 +105,46 @@ namespace ModernKeePass.ViewModels
} }
private readonly PwGroup _pwGroup; private readonly PwGroup _pwGroup;
private readonly App _app = Application.Current as App; private readonly IDatabase _database;
private bool _isEditMode; private bool _isEditMode;
private PwEntry _reorderedEntry;
private ObservableCollection<EntryVm> _entries = new ObservableCollection<EntryVm>();
private string _filter = string.Empty;
private bool _isMenuClosed = true;
public GroupVm() {} public GroupVm() {}
public GroupVm(PwGroup pwGroup, GroupVm parent, PwUuid recycleBinId = null) internal GroupVm(PwGroup pwGroup, GroupVm parent, PwUuid recycleBinId = null) : this(pwGroup, parent,
(Application.Current as App)?.Database, recycleBinId)
{ }
public GroupVm(PwGroup pwGroup, GroupVm parent, IDatabase database, PwUuid recycleBinId = null)
{ {
_pwGroup = pwGroup; _pwGroup = pwGroup;
_database = database;
ParentGroup = parent; ParentGroup = parent;
if (recycleBinId != null && _pwGroup.Uuid.Equals(recycleBinId)) _app.Database.RecycleBin = this; if (recycleBinId != null && _pwGroup.Uuid.Equals(recycleBinId)) _database.RecycleBin = this;
Entries = new ObservableCollection<EntryVm>(pwGroup.Entries.Select(e => new EntryVm(e, this)).OrderBy(e => e.Name)); Entries = new ObservableCollection<EntryVm>(pwGroup.Entries.Select(e => new EntryVm(e, this)));
Entries.Insert(0, new EntryVm ()); Entries.CollectionChanged += Entries_CollectionChanged;
Groups = new ObservableCollection<GroupVm>(pwGroup.Groups.Select(g => new GroupVm(g, this, recycleBinId)).OrderBy(g => g.Name)); Groups = new ObservableCollection<GroupVm>(pwGroup.Groups.Select(g => new GroupVm(g, this, recycleBinId)));
Groups.Insert(0, new GroupVm ()); Groups.Insert(0, new GroupVm());
}
private void Entries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Remove:
var oldIndex = (uint) e.OldStartingIndex;
_reorderedEntry = _pwGroup.Entries.GetAt(oldIndex);
_pwGroup.Entries.RemoveAt(oldIndex);
break;
case NotifyCollectionChangedAction.Add:
if (_reorderedEntry == null) _pwGroup.AddEntry(((EntryVm) e.NewItems[0]).GetPwEntry(), true);
else _pwGroup.Entries.Insert((uint)e.NewStartingIndex, _reorderedEntry);
break;
}
} }
public GroupVm AddNewGroup(string name = "") public GroupVm AddNewGroup(string name = "")
@@ -115,30 +159,19 @@ namespace ModernKeePass.ViewModels
public EntryVm AddNewEntry() public EntryVm AddNewEntry()
{ {
var pwEntry = new PwEntry(true, true); var pwEntry = new PwEntry(true, true);
_pwGroup.AddEntry(pwEntry, true);
var newEntry = new EntryVm(pwEntry, this) {IsEditMode = true}; var newEntry = new EntryVm(pwEntry, this) {IsEditMode = true};
newEntry.GeneratePassword();
Entries.Add(newEntry); Entries.Add(newEntry);
return newEntry; return newEntry;
} }
public void AddPwEntry(PwEntry entry)
{
_pwGroup.AddEntry(entry, true);
}
public void RemovePwEntry(PwEntry entry)
{
_pwGroup.Entries.Remove(entry);
}
public void MarkForDelete() public void MarkForDelete()
{ {
if (_app.Database.RecycleBinEnabled && _app.Database.RecycleBin?.IdUuid == null) if (_database.RecycleBinEnabled && _database.RecycleBin?.IdUuid == null)
_app.Database.CreateRecycleBin(); _database.CreateRecycleBin();
Move(_app.Database.RecycleBinEnabled && !IsSelected ? _app.Database.RecycleBin : null); Move(_database.RecycleBinEnabled && !IsSelected ? _database.RecycleBin : null);
} }
public void UndoDelete() public void UndoDelete()
{ {
Move(PreviousGroup); Move(PreviousGroup);
@@ -151,7 +184,7 @@ namespace ModernKeePass.ViewModels
PreviousGroup._pwGroup.Groups.Remove(_pwGroup); PreviousGroup._pwGroup.Groups.Remove(_pwGroup);
if (destination == null) if (destination == null)
{ {
_app.Database.AddDeletedItem(IdUuid); _database.AddDeletedItem(IdUuid);
return; return;
} }
ParentGroup = destination; ParentGroup = destination;
@@ -162,13 +195,41 @@ namespace ModernKeePass.ViewModels
public void CommitDelete() public void CommitDelete()
{ {
_pwGroup.ParentGroup.Groups.Remove(_pwGroup); _pwGroup.ParentGroup.Groups.Remove(_pwGroup);
if (_app.Database.RecycleBinEnabled && !PreviousGroup.IsSelected) _app.Database.RecycleBin._pwGroup.AddGroup(_pwGroup, true); if (_database.RecycleBinEnabled && !PreviousGroup.IsSelected) _database.RecycleBin._pwGroup.AddGroup(_pwGroup, true);
else _app.Database.AddDeletedItem(IdUuid); else _database.AddDeletedItem(IdUuid);
} }
public void Save() public void Save()
{ {
_app.Database.Save(); _database.Save();
}
public void SortEntries()
{
var comparer = new PwEntryComparer(PwDefs.TitleField, true, false);
try
{
_pwGroup.Entries.Sort(comparer);
Entries = new ObservableCollection<EntryVm>(Entries.OrderBy(e => e.Name));
}
catch (Exception e)
{
MessageDialogHelper.ShowErrorDialog(e);
}
}
public void SortGroups()
{
try
{
_pwGroup.SortSubGroups(false);
Groups = new ObservableCollection<GroupVm>(Groups.OrderBy(g => g.Name).ThenBy(g => g._pwGroup == null));
OnPropertyChanged("Groups");
}
catch (Exception e)
{
MessageDialogHelper.ShowErrorDialog(e);
}
} }
public override string ToString() public override string ToString()

View File

@@ -11,7 +11,7 @@ namespace ModernKeePass.ViewModels
public string Title { get; set; } public string Title { get; set; }
public int Group { get; set; } = 0; public string Group { get; set; } = "_";
public Type PageType { get; set; } public Type PageType { get; set; }
public Symbol SymbolIcon { get; set; } public Symbol SymbolIcon { get; set; }
public bool IsEnabled { get; set; } = true; public bool IsEnabled { get; set; } = true;

View File

@@ -1,22 +1,15 @@
using Windows.Storage; using Windows.Storage;
using ModernKeePass.Common; using ModernKeePass.Common;
using Windows.Storage.AccessCache; using Windows.UI.Xaml;
using ModernKeePass.Interfaces; using ModernKeePass.Interfaces;
using ModernKeePass.Services;
namespace ModernKeePass.ViewModels namespace ModernKeePass.ViewModels
{ {
public class RecentItemVm: NotifyPropertyChangedBase, ISelectableModel public class RecentItemVm: NotifyPropertyChangedBase, ISelectableModel, IRecentItem
{ {
private bool _isSelected; private bool _isSelected;
public RecentItemVm() {}
public RecentItemVm(AccessListEntry entry, StorageFile file)
{
Token = entry.Token;
Name = entry.Metadata;
DatabaseFile = file;
}
public StorageFile DatabaseFile { get; } public StorageFile DatabaseFile { get; }
public string Token { get; } public string Token { get; }
public string Name { get; } public string Name { get; }
@@ -27,5 +20,33 @@ namespace ModernKeePass.ViewModels
get { return _isSelected; } get { return _isSelected; }
set { SetProperty(ref _isSelected, value); } set { SetProperty(ref _isSelected, value); }
} }
public RecentItemVm() {}
public RecentItemVm(string token, string metadata, IStorageItem file)
{
Token = token;
Name = metadata;
DatabaseFile = file as StorageFile;
}
public void OpenDatabaseFile()
{
OpenDatabaseFile((Application.Current as App)?.Database);
}
public void OpenDatabaseFile(IDatabase database)
{
database.DatabaseFile = DatabaseFile;
}
public void UpdateAccessTime()
{
UpdateAccessTime(new RecentService());
}
public async void UpdateAccessTime(IRecent recent)
{
await recent.GetFileAsync(Token);
}
} }
} }

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Windows.Storage;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using ModernKeePass.Common; using ModernKeePass.Common;
using ModernKeePass.Interfaces; using ModernKeePass.Interfaces;
@@ -12,19 +11,19 @@ using ModernKeePassLib.Cryptography.KeyDerivation;
namespace ModernKeePass.ViewModels namespace ModernKeePass.ViewModels
{ {
// TODO: implement Kdf settings
public class SettingsDatabaseVm: NotifyPropertyChangedBase, IHasSelectableObject public class SettingsDatabaseVm: NotifyPropertyChangedBase, IHasSelectableObject
{ {
private readonly App _app = Application.Current as App; private readonly IDatabase _database;
private readonly ApplicationDataContainer _localSettings = ApplicationData.Current.LocalSettings;
private GroupVm _selectedItem; private GroupVm _selectedItem;
public bool HasRecycleBin public bool HasRecycleBin
{ {
get { return _app.Database.RecycleBinEnabled; } get { return _database.RecycleBinEnabled; }
set set
{ {
_app.Database.RecycleBinEnabled = value; _database.RecycleBinEnabled = value;
OnPropertyChanged(); OnPropertyChanged("HasRecycleBin");
} }
} }
@@ -47,26 +46,26 @@ namespace ModernKeePass.ViewModels
{ {
for (var inx = 0; inx < CipherPool.GlobalPool.EngineCount; ++inx) for (var inx = 0; inx < CipherPool.GlobalPool.EngineCount; ++inx)
{ {
if (CipherPool.GlobalPool[inx].CipherUuid.Equals(_app.Database.DataCipher)) return inx; if (CipherPool.GlobalPool[inx].CipherUuid.Equals(_database.DataCipher)) return inx;
} }
return -1; return -1;
} }
set { _app.Database.DataCipher = CipherPool.GlobalPool[value].CipherUuid; } set { _database.DataCipher = CipherPool.GlobalPool[value].CipherUuid; }
} }
public IEnumerable<string> Compressions => Enum.GetNames(typeof(PwCompressionAlgorithm)).Take((int)PwCompressionAlgorithm.Count); public IEnumerable<string> Compressions => Enum.GetNames(typeof(PwCompressionAlgorithm)).Take((int)PwCompressionAlgorithm.Count);
public string CompressionName public string CompressionName
{ {
get { return Enum.GetName(typeof(PwCompressionAlgorithm), _app.Database.CompressionAlgorithm); } get { return Enum.GetName(typeof(PwCompressionAlgorithm), _database.CompressionAlgorithm); }
set { _app.Database.CompressionAlgorithm = (PwCompressionAlgorithm)Enum.Parse(typeof(PwCompressionAlgorithm), value); } set { _database.CompressionAlgorithm = (PwCompressionAlgorithm)Enum.Parse(typeof(PwCompressionAlgorithm), value); }
} }
public IEnumerable<string> KeyDerivations => KdfPool.Engines.Select(e => e.Name); public IEnumerable<string> KeyDerivations => KdfPool.Engines.Select(e => e.Name);
public string KeyDerivationName public string KeyDerivationName
{ {
get { return KdfPool.Get(_app.Database.KeyDerivation.KdfUuid).Name; } get { return KdfPool.Get(_database.KeyDerivation.KdfUuid).Name; }
set { _app.Database.KeyDerivation = KdfPool.Engines.FirstOrDefault(e => e.Name == value)?.GetDefaultParameters(); } set { _database.KeyDerivation = KdfPool.Engines.FirstOrDefault(e => e.Name == value)?.GetDefaultParameters(); }
} }
public ISelectableModel SelectedItem public ISelectableModel SelectedItem
@@ -89,22 +88,12 @@ namespace ModernKeePass.ViewModels
} }
} }
public SettingsDatabaseVm() public SettingsDatabaseVm() : this((Application.Current as App)?.Database) { }
{
Groups = _app.Database.RootGroup.Groups;
}
// TODO: Move to another setting class (or a static class) public SettingsDatabaseVm(IDatabase database)
private T GetSetting<T>(string property)
{ {
try _database = database;
{ Groups = _database?.RootGroup.Groups;
return (T) Convert.ChangeType(_localSettings.Values[property], typeof(T));
}
catch (InvalidCastException)
{
return default(T);
}
} }
} }
} }

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using ModernKeePass.Interfaces;
using ModernKeePass.Services;
namespace ModernKeePass.ViewModels
{
public class SettingsNewVm
{
private ISettings _settings;
public SettingsNewVm() : this(new SettingsService())
{ }
public SettingsNewVm(ISettings settings)
{
_settings = settings;
}
public bool IsCreateSample
{
get { return _settings.GetSetting<bool>("Sample"); }
set { _settings.PutSetting("Sample", value); }
}
public IEnumerable<string> FileFormats => new []{"2", "4"};
public string FileFormatVersion
{
get { return _settings.GetSetting<string>("DefaultFileFormat"); }
set { _settings.PutSetting("DefaultFileFormat", value); }
}
}
}

View File

@@ -1,23 +1,23 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Windows.ApplicationModel; using Windows.ApplicationModel;
using Windows.Storage.AccessCache;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using ModernKeePass.Common; using ModernKeePass.Common;
using ModernKeePass.Interfaces; using ModernKeePass.Interfaces;
using ModernKeePass.Pages; using ModernKeePass.Services;
using ModernKeePass.Views;
namespace ModernKeePass.ViewModels namespace ModernKeePass.ViewModels
{ {
public class MainVm : NotifyPropertyChangedBase, IHasSelectableObject public class MainVm : NotifyPropertyChangedBase, IHasSelectableObject
{ {
private IOrderedEnumerable<IGrouping<int, MainMenuItemVm>> _mainMenuItems; private IOrderedEnumerable<IGrouping<string, MainMenuItemVm>> _mainMenuItems;
private MainMenuItemVm _selectedItem; private MainMenuItemVm _selectedItem;
public string Name { get; } = Package.Current.DisplayName; public string Name { get; } = Package.Current.DisplayName;
public IOrderedEnumerable<IGrouping<int, MainMenuItemVm>> MainMenuItems public IOrderedEnumerable<IGrouping<string, MainMenuItemVm>> MainMenuItems
{ {
get { return _mainMenuItems; } get { return _mainMenuItems; }
set { SetProperty(ref _mainMenuItems, value); } set { SetProperty(ref _mainMenuItems, value); }
@@ -45,47 +45,89 @@ namespace ModernKeePass.ViewModels
public MainVm() {} public MainVm() {}
public MainVm(Frame referenceFrame, Frame destinationFrame) internal MainVm(Frame referenceFrame, Frame destinationFrame) : this(referenceFrame, destinationFrame,
(Application.Current as App)?.Database, new ResourcesService(), new RecentService())
{ }
public MainVm(Frame referenceFrame, Frame destinationFrame, IDatabase database, IResource resource, IRecent recent)
{ {
var app = (App)Application.Current; var isDatabaseOpen = database != null && database.Status == (int) DatabaseService.DatabaseStatus.Opened;
var mru = StorageApplicationPermissions.MostRecentlyUsedList;
var isDatabaseOpen = app.Database != null && app.Database.Status == DatabaseHelper.DatabaseStatus.Opened;
var mainMenuItems = new ObservableCollection<MainMenuItemVm> var mainMenuItems = new ObservableCollection<MainMenuItemVm>
{ {
new MainMenuItemVm new MainMenuItemVm
{ {
Title = "Open", PageType = typeof(OpenDatabasePage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Page2, Title = resource.GetResourceValue("MainMenuItemOpen"),
IsSelected = app.Database.Status == DatabaseHelper.DatabaseStatus.Opening PageType = typeof(OpenDatabasePage),
Destination = destinationFrame,
Parameter = referenceFrame,
SymbolIcon = Symbol.Page2,
IsSelected = database != null && database.Status == (int) DatabaseService.DatabaseStatus.Opening
}, },
new MainMenuItemVm new MainMenuItemVm
{ {
Title = "New" , PageType = typeof(NewDatabasePage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Add Title = resource.GetResourceValue("MainMenuItemNew"),
PageType = typeof(NewDatabasePage),
Destination = destinationFrame,
Parameter = referenceFrame,
SymbolIcon = Symbol.Add
}, },
new MainMenuItemVm new MainMenuItemVm
{ {
Title = "Save" , PageType = typeof(SaveDatabasePage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Save, Title = resource.GetResourceValue("MainMenuItemSave"),
IsSelected = isDatabaseOpen, IsEnabled = isDatabaseOpen PageType = typeof(SaveDatabasePage),
}, Destination = destinationFrame,
new MainMenuItemVm { Parameter = referenceFrame,
Title = "Recent" , PageType = typeof(RecentDatabasesPage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Copy, SymbolIcon = Symbol.Save,
IsSelected = (app.Database == null || app.Database.Status == DatabaseHelper.DatabaseStatus.Closed) && mru.Entries.Count > 0, IsEnabled = mru.Entries.Count > 0 IsSelected = isDatabaseOpen,
IsEnabled = isDatabaseOpen
}, },
new MainMenuItemVm new MainMenuItemVm
{ {
Title = "About" , PageType = typeof(AboutPage), Destination = destinationFrame, SymbolIcon = Symbol.Help Title = resource.GetResourceValue("MainMenuItemRecent"),
PageType = typeof(RecentDatabasesPage),
Destination = destinationFrame,
Parameter = referenceFrame,
SymbolIcon = Symbol.Copy,
IsSelected =
(database == null || database.Status == (int) DatabaseService.DatabaseStatus.Closed) &&
recent.EntryCount > 0,
IsEnabled = recent.EntryCount > 0
},
new MainMenuItemVm
{
Title = resource.GetResourceValue("MainMenuItemSettings"),
PageType = typeof(SettingsPage),
Destination = referenceFrame,
SymbolIcon = Symbol.Setting
},
new MainMenuItemVm
{
Title = resource.GetResourceValue("MainMenuItemAbout"),
PageType = typeof(AboutPage),
Destination = destinationFrame,
SymbolIcon = Symbol.Help
},
new MainMenuItemVm
{
Title = resource.GetResourceValue("MainMenuItemDonate"),
PageType = typeof(DonatePage),
Destination = destinationFrame,
SymbolIcon = Symbol.Shop
} }
}; };
// Auto-select the Recent Items menu item if the conditions are met // Auto-select the Recent Items menu item if the conditions are met
SelectedItem = mainMenuItems.FirstOrDefault(m => m.IsSelected); SelectedItem = mainMenuItems.FirstOrDefault(m => m.IsSelected);
if (app.Database != null && app.Database.Status == DatabaseHelper.DatabaseStatus.Opened)
// Add currently opened database to the menu
if (database != null && database.Status == (int) DatabaseService.DatabaseStatus.Opened)
mainMenuItems.Add(new MainMenuItemVm mainMenuItems.Add(new MainMenuItemVm
{ {
Title = app.Database.Name, Title = database.Name,
PageType = typeof(GroupDetailPage), PageType = typeof(GroupDetailPage),
Destination = referenceFrame, Destination = referenceFrame,
Parameter = app.Database.RootGroup, Parameter = database.RootGroup,
Group = 1, Group = "Databases",
SymbolIcon = Symbol.ProtectedDocument SymbolIcon = Symbol.ProtectedDocument
}); });

View File

@@ -1,50 +1,44 @@
using System.ComponentModel; using Windows.Storage;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using ModernKeePass.Common; using ModernKeePass.Common;
using ModernKeePass.Interfaces;
using ModernKeePass.Services;
namespace ModernKeePass.ViewModels namespace ModernKeePass.ViewModels
{ {
public class OpenVm: INotifyPropertyChanged public class OpenVm: NotifyPropertyChangedBase
{ {
public bool ShowPasswordBox public bool ShowPasswordBox => _database?.Status == (int) DatabaseService.DatabaseStatus.Opening;
{
get { return ((App)Application.Current).Database.Status == DatabaseHelper.DatabaseStatus.Opening; }
}
public string Name public string Name => _database?.Name;
{
get { return ((App)Application.Current).Database.Name; }
}
public OpenVm() private readonly IDatabase _database;
{
var app = Application.Current as App;
if (app?.Database == null || app.Database.Status != DatabaseHelper.DatabaseStatus.Opening) return;
OpenFile(app.Database.DatabaseFile);
}
public event PropertyChangedEventHandler PropertyChanged; public OpenVm() : this((Application.Current as App)?.Database) { }
protected void NotifyPropertyChanged(string propertyName) public OpenVm(IDatabase database)
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); _database = database;
if (database == null || database.Status != (int) DatabaseService.DatabaseStatus.Opening) return;
OpenFile(database.DatabaseFile);
} }
public void OpenFile(StorageFile file) public void OpenFile(StorageFile file)
{ {
var database = ((App)Application.Current).Database; OpenFile(file, new RecentService());
database.DatabaseFile = file;
NotifyPropertyChanged("Name");
NotifyPropertyChanged("ShowPasswordBox");
AddToRecentList(file);
} }
private void AddToRecentList(StorageFile file) public void OpenFile(StorageFile file, IRecent recent)
{ {
var mru = StorageApplicationPermissions.MostRecentlyUsedList; _database.DatabaseFile = file;
mru.Add(file, file.DisplayName); OnPropertyChanged("Name");
OnPropertyChanged("ShowPasswordBox");
AddToRecentList(file, recent);
}
private void AddToRecentList(StorageFile file, IRecent recent)
{
recent.Add(file, file.DisplayName);
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More