diff --git a/ModernKeePass/App.xaml.cs b/ModernKeePass/App.xaml.cs index d905fbc..050ed75 100644 --- a/ModernKeePass/App.xaml.cs +++ b/ModernKeePass/App.xaml.cs @@ -1,6 +1,7 @@ using System; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; +using Windows.Storage; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; @@ -16,15 +17,15 @@ namespace ModernKeePass /// sealed partial class App : Application { - public DatabaseHelper Database { get; set; } + public DatabaseHelper Database { get; set; } = new DatabaseHelper(); /// /// Initializes the singleton application object. This is the first line of authored code /// executed, and as such is the logical equivalent of main() or WinMain(). /// public App() { - this.InitializeComponent(); - this.Suspending += OnSuspending; + InitializeComponent(); + Suspending += OnSuspending; } /// @@ -38,11 +39,11 @@ namespace ModernKeePass #if DEBUG if (System.Diagnostics.Debugger.IsAttached) { - this.DebugSettings.EnableFrameRateCounter = true; + DebugSettings.EnableFrameRateCounter = true; } #endif - Frame rootFrame = Window.Current.Content as Frame; + var rootFrame = Window.Current.Content as Frame; // Do not repeat app initialization when the Window already has content, // just ensure that the window is active @@ -95,8 +96,18 @@ namespace ModernKeePass private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); - //TODO: Save application state and stop any background activity + Database.Save(); deferral.Complete(); } + + protected override void OnFileActivated(FileActivatedEventArgs args) + { + base.OnFileActivated(args); + Database.DatabaseFile = args.Files[0] as StorageFile; + var rootFrame = new Frame(); + rootFrame.Navigate(typeof(MainPage), args); + Window.Current.Content = rootFrame; + Window.Current.Activate(); + } } } diff --git a/ModernKeePass/Common/DatabaseHelper.cs b/ModernKeePass/Common/DatabaseHelper.cs index 8e05e15..01c8fc7 100644 --- a/ModernKeePass/Common/DatabaseHelper.cs +++ b/ModernKeePass/Common/DatabaseHelper.cs @@ -1,6 +1,5 @@ using System; using Windows.Storage; -using System.Threading.Tasks; using ModernKeePass.ViewModels; using ModernKeePassLib; using ModernKeePassLib.Interfaces; @@ -11,18 +10,27 @@ namespace ModernKeePass.Common { public class DatabaseHelper { + public enum DatabaseStatus + { + Closed = 0, + Opening = 1, + Opened = 2 + } private readonly PwDatabase _pwDatabase = new PwDatabase(); - private readonly StorageFile _databaseFile; + private StorageFile _databaseFile; public GroupVm RootGroup { get; set; } - - public bool IsOpen => _pwDatabase.IsOpen; - - public string Name => _databaseFile.Name; - - public DatabaseHelper(StorageFile databaseFile) + public DatabaseStatus Status { get; private set; } = DatabaseStatus.Closed; + public string Name => DatabaseFile.Name; + + public StorageFile DatabaseFile { - _databaseFile = databaseFile; + get { return _databaseFile; } + set + { + _databaseFile = value; + Status = DatabaseStatus.Opening; + } } public string Open(string password) { @@ -30,9 +38,13 @@ namespace ModernKeePass.Common try { key.AddUserKey(new KcpPassword(password)); - _pwDatabase.Open(IOConnectionInfo.FromFile(_databaseFile), key, new NullStatusLogger()); + _pwDatabase.Open(IOConnectionInfo.FromFile(DatabaseFile), key, new NullStatusLogger()); - if (IsOpen) RootGroup = new GroupVm(_pwDatabase.RootGroup, null); + if (_pwDatabase.IsOpen) + { + Status = DatabaseStatus.Opened; + RootGroup = new GroupVm(_pwDatabase.RootGroup, null); + } } catch (ArgumentNullException) { @@ -51,12 +63,14 @@ namespace ModernKeePass.Common public void Save() { - _pwDatabase.Save(new NullStatusLogger()); + if (_pwDatabase != null && _pwDatabase.IsOpen) + _pwDatabase.Save(new NullStatusLogger()); } public void Close() { - _pwDatabase.Close(); + _pwDatabase?.Close(); + Status = DatabaseStatus.Closed; } } } diff --git a/ModernKeePass/Controls/OpenDatabaseUserControl.xaml.cs b/ModernKeePass/Controls/OpenDatabaseUserControl.xaml.cs index ca1831b..14b705a 100644 --- a/ModernKeePass/Controls/OpenDatabaseUserControl.xaml.cs +++ b/ModernKeePass/Controls/OpenDatabaseUserControl.xaml.cs @@ -1,10 +1,11 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; using Windows.System; using Windows.UI.Core; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; +using ModernKeePass.Common; +using ModernKeePass.Events; // Pour en savoir plus sur le modèle d'élément Contrôle utilisateur, consultez la page http://go.microsoft.com/fwlink/?LinkId=234236 @@ -18,13 +19,14 @@ namespace ModernKeePass.Controls } public event PasswordCheckedEventHandler ValidationChecked; - public delegate void PasswordCheckedEventHandler(object sender, EventArgs e); + public delegate void PasswordCheckedEventHandler(object sender, PasswordEventArgs e); private void OpenButton_OnClick(object sender, RoutedEventArgs e) { var app = (App)Application.Current; StatusTextBlock.Text = app.Database.Open(PasswordBox.Password); - ValidationChecked?.Invoke(this, new EventArgs()); + if (app.Database.Status == DatabaseHelper.DatabaseStatus.Opened) + ValidationChecked?.Invoke(this, new PasswordEventArgs(app.Database.RootGroup)); } private void PasswordBox_KeyDown(object sender, KeyRoutedEventArgs e) diff --git a/ModernKeePass/Events/PasswordEventArgs.cs b/ModernKeePass/Events/PasswordEventArgs.cs new file mode 100644 index 0000000..099a5f9 --- /dev/null +++ b/ModernKeePass/Events/PasswordEventArgs.cs @@ -0,0 +1,15 @@ +using System; +using ModernKeePass.ViewModels; + +namespace ModernKeePass.Events +{ + public class PasswordEventArgs: EventArgs + { + public GroupVm RootGroup { get; set; } + + public PasswordEventArgs(GroupVm groupVm) + { + RootGroup = groupVm; + } + } +} \ No newline at end of file diff --git a/ModernKeePass/ModernKeePass.csproj b/ModernKeePass/ModernKeePass.csproj index 58fe225..b8de761 100644 --- a/ModernKeePass/ModernKeePass.csproj +++ b/ModernKeePass/ModernKeePass.csproj @@ -125,6 +125,7 @@ + MainPage.xaml @@ -148,11 +149,12 @@ SaveDatabasePage.xaml - + + diff --git a/ModernKeePass/Package.appxmanifest b/ModernKeePass/Package.appxmanifest index 78d89d7..779e8cf 100644 --- a/ModernKeePass/Package.appxmanifest +++ b/ModernKeePass/Package.appxmanifest @@ -28,6 +28,15 @@ + + + KeePass 2.x database + + + .kdbx + + + diff --git a/ModernKeePass/Pages/OpenDatabasePage.xaml b/ModernKeePass/Pages/OpenDatabasePage.xaml index 09d0a30..65e32ef 100644 --- a/ModernKeePass/Pages/OpenDatabasePage.xaml +++ b/ModernKeePass/Pages/OpenDatabasePage.xaml @@ -5,16 +5,20 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewModels="using:ModernKeePass.ViewModels" xmlns:local="using:ModernKeePass.Controls" + xmlns:converters="using:ModernKeePass.Converters" x:Class="ModernKeePass.Pages.OpenDatabasePage" mc:Ignorable="d"> + + + - + - + - + \ No newline at end of file diff --git a/ModernKeePass/Pages/OpenDatabasePage.xaml.cs b/ModernKeePass/Pages/OpenDatabasePage.xaml.cs index 4391b80..a89a789 100644 --- a/ModernKeePass/Pages/OpenDatabasePage.xaml.cs +++ b/ModernKeePass/Pages/OpenDatabasePage.xaml.cs @@ -1,14 +1,10 @@ using System; using Windows.Storage.Pickers; -using Windows.System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Navigation; -using ModernKeePass.Common; +using ModernKeePass.Events; using ModernKeePass.ViewModels; -using Windows.Storage.AccessCache; -using Windows.Storage; // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 @@ -41,34 +37,15 @@ namespace ModernKeePass.Pages SuggestedStartLocation = PickerLocationId.DocumentsLibrary }; picker.FileTypeFilter.Add(".kdbx"); - - var file = await picker.PickSingleFileAsync(); + + var viewModel = DataContext as OpenVm; // Application now has read/write access to the picked file - if (file == null) return; - // Initialize KDBX database - ((App)Application.Current).Database = new DatabaseHelper(file); - AddToRecentFiles(file); - ShowPassword(file); + viewModel.OpenFile(await picker.PickSingleFileAsync()); } - private void AddToRecentFiles(StorageFile file) + private void PasswordUserControl_PasswordChecked(object sender, PasswordEventArgs e) { - var mru = StorageApplicationPermissions.MostRecentlyUsedList; - mru.Add(file, file.DisplayName); - } - - private void ShowPassword(StorageFile file) - { - var databaseVm = DataContext as DatabaseVm; - if (databaseVm == null) return; - databaseVm.SelectedVisibility = Visibility.Visible; - databaseVm.Name = file.Name; - } - - private void PasswordUserControl_PasswordChecked(object sender, EventArgs e) - { - var app = (App)Application.Current; - if (app.Database.IsOpen) _mainFrame.Navigate(typeof(GroupDetailPage), app.Database.RootGroup); + _mainFrame.Navigate(typeof(GroupDetailPage), e.RootGroup); } } } diff --git a/ModernKeePass/Pages/RecentDatabasesPage.xaml b/ModernKeePass/Pages/RecentDatabasesPage.xaml index 62c4b76..be6bdf7 100644 --- a/ModernKeePass/Pages/RecentDatabasesPage.xaml +++ b/ModernKeePass/Pages/RecentDatabasesPage.xaml @@ -18,7 +18,6 @@ diff --git a/ModernKeePass/Pages/RecentDatabasesPage.xaml.cs b/ModernKeePass/Pages/RecentDatabasesPage.xaml.cs index 03433a0..2df6cb7 100644 --- a/ModernKeePass/Pages/RecentDatabasesPage.xaml.cs +++ b/ModernKeePass/Pages/RecentDatabasesPage.xaml.cs @@ -6,6 +6,7 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; using ModernKeePass.Common; +using ModernKeePass.Events; using ModernKeePass.ViewModels; // Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238 @@ -29,23 +30,10 @@ namespace ModernKeePass.Pages base.OnNavigatedTo(e); _mainFrame = e.Parameter as Frame; } - - private async void RecentListView_SelectionChanged(object sender, SelectionChangedEventArgs e) + + private void PasswordUserControl_PasswordChecked(object sender, PasswordEventArgs e) { - var recentVm = DataContext as RecentVm; - if (recentVm.SelectedItem == null) return; - var mru = StorageApplicationPermissions.MostRecentlyUsedList; - var file = await mru.GetFileAsync(recentVm.SelectedItem.Token); - - // TODO: this closes the current opened database - var app = (App)Application.Current; - app.Database = new DatabaseHelper(file); - } - - private void PasswordUserControl_PasswordChecked(object sender, EventArgs e) - { - var app = (App)Application.Current; - if (app.Database.IsOpen) _mainFrame.Navigate(typeof(GroupDetailPage), app.Database.RootGroup); + _mainFrame.Navigate(typeof(GroupDetailPage), e.RootGroup); } } } diff --git a/ModernKeePass/Pages/SaveDatabasePage.xaml b/ModernKeePass/Pages/SaveDatabasePage.xaml index 7a8b14b..557f3fc 100644 --- a/ModernKeePass/Pages/SaveDatabasePage.xaml +++ b/ModernKeePass/Pages/SaveDatabasePage.xaml @@ -8,11 +8,11 @@ mc:Ignorable="d"> - + - + diff --git a/ModernKeePass/Pages/SaveDatabasePage.xaml.cs b/ModernKeePass/Pages/SaveDatabasePage.xaml.cs index c10052f..688e98c 100644 --- a/ModernKeePass/Pages/SaveDatabasePage.xaml.cs +++ b/ModernKeePass/Pages/SaveDatabasePage.xaml.cs @@ -22,25 +22,13 @@ namespace ModernKeePass.Pages { base.OnNavigatedTo(e); _mainFrame = e.Parameter as Frame; - var app = (App)Application.Current; - if (app.Database == null) return; - var databaseVm = DataContext as DatabaseVm; - if (databaseVm == null) return; - UpdateDatabaseStatus(app, databaseVm); } private void SaveButton_OnClick(object sender, RoutedEventArgs e) { - var app = (App) Application.Current; - app.Database.Save(); - app.Database.Close(); - UpdateDatabaseStatus(app, DataContext as DatabaseVm); + var viewModel = DataContext as SaveVm; + viewModel.Save(); _mainFrame.Navigate(typeof(MainPage)); } - - private void UpdateDatabaseStatus(App app, DatabaseVm databaseVm) - { - databaseVm.IsOpen = app.Database.IsOpen; - } } } diff --git a/ModernKeePass/ViewModels/DatabaseVm.cs b/ModernKeePass/ViewModels/DatabaseVm.cs deleted file mode 100644 index 06e70a6..0000000 --- a/ModernKeePass/ViewModels/DatabaseVm.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Windows.UI.Xaml; -using ModernKeePass.Common; - -namespace ModernKeePass.ViewModels -{ - public class DatabaseVm : NotifyPropertyChangedBase - { - private string _name; - private Visibility _selectedVisibility = Visibility.Collapsed; - private bool _isOpen; - - public Visibility SelectedVisibility - { - get { return _selectedVisibility; } - set { SetProperty(ref _selectedVisibility, value); } - } - - public bool IsOpen - { - get { return _isOpen; } - set { SetProperty(ref _isOpen, value); } - } - - public string Name { - get { return string.IsNullOrEmpty(_name) ? string.Empty : $"Database {_name} selected"; } - set { SetProperty(ref _name, value); } - } - } -} diff --git a/ModernKeePass/ViewModels/MainVm.cs b/ModernKeePass/ViewModels/MainVm.cs index 646547a..5311e70 100644 --- a/ModernKeePass/ViewModels/MainVm.cs +++ b/ModernKeePass/ViewModels/MainVm.cs @@ -48,15 +48,25 @@ namespace ModernKeePass.ViewModels var mainMenuItems = new ObservableCollection { - new MainMenuItemVm {Title = "Open", PageType = typeof(OpenDatabasePage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Page2}, + new MainMenuItemVm + { + Title = "Open", PageType = typeof(OpenDatabasePage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Page2, + IsSelected = app.Database.Status == DatabaseHelper.DatabaseStatus.Opening + }, new MainMenuItemVm {Title = "New" /*, PageType = typeof(NewDatabasePage)*/, Destination = destinationFrame, SymbolIcon = Symbol.Add}, - new MainMenuItemVm {Title = "Save" , PageType = typeof(SaveDatabasePage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Save}, - new MainMenuItemVm {Title = "Recent" , PageType = typeof(RecentDatabasesPage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Copy, - IsSelected = (app.Database == null || !app.Database.IsOpen) && mru.Entries.Count > 0} + new MainMenuItemVm + { + Title = "Save" , PageType = typeof(SaveDatabasePage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Save, + IsSelected = app.Database != null && app.Database.Status == DatabaseHelper.DatabaseStatus.Opened + }, + new MainMenuItemVm { + Title = "Recent" , PageType = typeof(RecentDatabasesPage), Destination = destinationFrame, Parameter = referenceFrame, SymbolIcon = Symbol.Copy, + IsSelected = (app.Database == null || app.Database.Status == DatabaseHelper.DatabaseStatus.Closed) && mru.Entries.Count > 0 + } }; // Auto-select the Recent Items menu item if the conditions are met SelectedItem = mainMenuItems.FirstOrDefault(m => m.IsSelected); - if (app.Database != null && app.Database.IsOpen) + if (app.Database != null && app.Database.Status == DatabaseHelper.DatabaseStatus.Opened) mainMenuItems.Add(new MainMenuItemVm { Title = app.Database.Name, @@ -66,7 +76,7 @@ namespace ModernKeePass.ViewModels Group = 1, SymbolIcon = Symbol.ProtectedDocument }); - + MainMenuItems = from item in mainMenuItems group item by item.Group into grp orderby grp.Key select grp; } } diff --git a/ModernKeePass/ViewModels/OpenVm.cs b/ModernKeePass/ViewModels/OpenVm.cs new file mode 100644 index 0000000..6ff33dd --- /dev/null +++ b/ModernKeePass/ViewModels/OpenVm.cs @@ -0,0 +1,50 @@ +using System.ComponentModel; +using Windows.Storage; +using Windows.Storage.AccessCache; +using Windows.UI.Xaml; +using ModernKeePass.Common; + +namespace ModernKeePass.ViewModels +{ + public class OpenVm: INotifyPropertyChanged + { + public bool ShowPasswordBox + { + get { return ((App) Application.Current).Database.Status == DatabaseHelper.DatabaseStatus.Opening; } + } + + public string Name + { + get { return ((App) Application.Current).Database.Name; } + } + + public event PropertyChangedEventHandler PropertyChanged; + + public OpenVm() + { + var database = ((App) Application.Current).Database; + if (database == null || database.Status != DatabaseHelper.DatabaseStatus.Opening) return; + OpenFile(database.DatabaseFile); + } + + private void NotifyPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public void OpenFile(StorageFile file) + { + var database = ((App)Application.Current).Database; + database.DatabaseFile = file; + NotifyPropertyChanged("Name"); + NotifyPropertyChanged("ShowPasswordBox"); + AddToRecentList(file); + } + + private void AddToRecentList(StorageFile file) + { + var mru = StorageApplicationPermissions.MostRecentlyUsedList; + mru.Add(file, file.DisplayName); + } + } +} diff --git a/ModernKeePass/ViewModels/RecentVm.cs b/ModernKeePass/ViewModels/RecentVm.cs index 93b7752..064a263 100644 --- a/ModernKeePass/ViewModels/RecentVm.cs +++ b/ModernKeePass/ViewModels/RecentVm.cs @@ -1,6 +1,8 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using System.Linq; using Windows.Storage.AccessCache; +using Windows.UI.Xaml; using ModernKeePass.Common; namespace ModernKeePass.ViewModels @@ -43,6 +45,11 @@ namespace ModernKeePass.ViewModels { _selectedItem.IsSelected = true; } + + var mru = StorageApplicationPermissions.MostRecentlyUsedList; + var file = mru.GetFileAsync(SelectedItem.Token).GetAwaiter().GetResult(); + var app = (App)Application.Current; + app.Database.DatabaseFile = file; } } } diff --git a/ModernKeePass/ViewModels/SaveVm.cs b/ModernKeePass/ViewModels/SaveVm.cs new file mode 100644 index 0000000..2d27db0 --- /dev/null +++ b/ModernKeePass/ViewModels/SaveVm.cs @@ -0,0 +1,33 @@ +using System.ComponentModel; +using Windows.UI.Xaml; +using ModernKeePass.Common; + +namespace ModernKeePass.ViewModels +{ + public class SaveVm: INotifyPropertyChanged + { + public bool IsSaveEnabled + { + get + { + var app = (App)Application.Current; + return app.Database.Status == DatabaseHelper.DatabaseStatus.Opened; + } + } + + public event PropertyChangedEventHandler PropertyChanged; + private void NotifyPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public void Save(bool close = true) + { + var app = (App)Application.Current; + app.Database.Save(); + if (!close) return; + app.Database.Close(); + NotifyPropertyChanged("IsSaveEnabled"); + } + } +} \ No newline at end of file