mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 23:50:18 -04:00
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
This commit is contained in:
@@ -9,6 +9,7 @@ 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.Exceptions;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
|
|
||||||
// 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
|
||||||
@@ -37,14 +38,17 @@ namespace ModernKeePass
|
|||||||
|
|
||||||
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
|
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
|
||||||
{
|
{
|
||||||
// TODO: catch only save errors for now, rethrow (do not handle) otherwise
|
// Save the argument exception because it's cleared on first access
|
||||||
var exception = unhandledExceptionEventArgs.Exception;
|
var exception = unhandledExceptionEventArgs.Exception;
|
||||||
MessageDialogHelper.ShowErrorDialog(
|
var realException =
|
||||||
exception is TargetInvocationException &&
|
exception is TargetInvocationException &&
|
||||||
exception.InnerException != null
|
exception.InnerException != null
|
||||||
? exception.InnerException
|
? exception.InnerException
|
||||||
: exception);
|
: exception;
|
||||||
|
|
||||||
|
if (!(realException is SaveException)) return;
|
||||||
unhandledExceptionEventArgs.Handled = true;
|
unhandledExceptionEventArgs.Handled = true;
|
||||||
|
MessageDialogHelper.SaveErrorDialog(realException as SaveException, Database);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
using Windows.Storage.AccessCache;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using ModernKeePass.Exceptions;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
using ModernKeePass.ViewModels;
|
using ModernKeePass.ViewModels;
|
||||||
using ModernKeePassLib;
|
using ModernKeePassLib;
|
||||||
@@ -102,7 +104,7 @@ namespace ModernKeePass.Common
|
|||||||
{
|
{
|
||||||
Status = (int)DatabaseStatus.CompositeKeyError;
|
Status = (int)DatabaseStatus.CompositeKeyError;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Status = (int)DatabaseStatus.Error;
|
Status = (int)DatabaseStatus.Error;
|
||||||
throw;
|
throw;
|
||||||
@@ -115,10 +117,22 @@ namespace ModernKeePass.Common
|
|||||||
/// <param name="file">The new database file</param>
|
/// <param name="file">The new database file</param>
|
||||||
public void Save(StorageFile file)
|
public void Save(StorageFile file)
|
||||||
{
|
{
|
||||||
|
var oldFile = DatabaseFile;
|
||||||
DatabaseFile = file;
|
DatabaseFile = file;
|
||||||
|
try
|
||||||
|
{
|
||||||
_pwDatabase.SaveAs(IOConnectionInfo.FromFile(DatabaseFile), true, new NullStatusLogger());
|
_pwDatabase.SaveAs(IOConnectionInfo.FromFile(DatabaseFile), true, new NullStatusLogger());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
DatabaseFile = oldFile;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
Status = (int)DatabaseStatus.Opened;
|
Status = (int)DatabaseStatus.Opened;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Commit the changes to the currently opened database to file
|
/// Commit the changes to the currently opened database to file
|
||||||
@@ -126,8 +140,15 @@ namespace ModernKeePass.Common
|
|||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
if (_pwDatabase == null || !_pwDatabase.IsOpen) return;
|
if (_pwDatabase == null || !_pwDatabase.IsOpen) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
_pwDatabase.Save(new NullStatusLogger());
|
_pwDatabase.Save(new NullStatusLogger());
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new SaveException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Close the currently opened database
|
/// Close the currently opened database
|
||||||
@@ -145,7 +166,7 @@ namespace ModernKeePass.Common
|
|||||||
|
|
||||||
public void CreateRecycleBin()
|
public void CreateRecycleBin()
|
||||||
{
|
{
|
||||||
RecycleBin = ((GroupVm)RootGroup).AddNewGroup("Recycle bin");
|
RecycleBin = RootGroup.AddNewGroup("Recycle bin");
|
||||||
RecycleBin.IsSelected = true;
|
RecycleBin.IsSelected = true;
|
||||||
RecycleBin.IconSymbol = Symbol.Delete;
|
RecycleBin.IconSymbol = Symbol.Delete;
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Windows.Storage.Pickers;
|
||||||
using Windows.UI.Popups;
|
using Windows.UI.Popups;
|
||||||
|
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 = new MessageDialog(contentText, title);
|
||||||
|
|
||||||
// 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"));
|
messageDialog.Commands.Add(new UICommand(cancelButtonText));
|
||||||
|
|
||||||
// Set the command that will be invoked by default
|
// Set the command that will be invoked by default
|
||||||
messageDialog.DefaultCommandIndex = 1;
|
messageDialog.DefaultCommandIndex = 1;
|
||||||
@@ -24,6 +28,22 @@ namespace ModernKeePass.Common
|
|||||||
await messageDialog.ShowAsync();
|
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)
|
public static async void ShowErrorDialog(Exception exception)
|
||||||
{
|
{
|
||||||
if (exception == null) return;
|
if (exception == null) return;
|
||||||
|
14
ModernKeePass/Exceptions/SaveException.cs
Normal file
14
ModernKeePass/Exceptions/SaveException.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -123,6 +123,7 @@
|
|||||||
<Compile Include="Common\ToastNotificationHelper.cs" />
|
<Compile Include="Common\ToastNotificationHelper.cs" />
|
||||||
<Compile Include="Converters\DiscreteIntToSolidColorBrushConverter.cs" />
|
<Compile Include="Converters\DiscreteIntToSolidColorBrushConverter.cs" />
|
||||||
<Compile Include="Converters\NullToBooleanConverter.cs" />
|
<Compile Include="Converters\NullToBooleanConverter.cs" />
|
||||||
|
<Compile Include="Exceptions\SaveException.cs" />
|
||||||
<Compile Include="Interfaces\IDatabase.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" />
|
||||||
|
@@ -76,7 +76,7 @@ namespace ModernKeePass.Pages
|
|||||||
? "Are you sure you want to send this entry to the recycle bin?"
|
? "Are you sure you want to send this entry to the recycle bin?"
|
||||||
: "Are you sure you want to delete this entry?";
|
: "Are you sure you want to delete this entry?";
|
||||||
var text = isRecycleBinEnabled ? "Item moved to the Recycle bin" : "Item permanently removed";
|
var text = isRecycleBinEnabled ? "Item moved to the Recycle bin" : "Item permanently removed";
|
||||||
MessageDialogHelper.ShowDeleteConfirmationDialog("Delete", message, a =>
|
MessageDialogHelper.ShowActionDialog("Warning", message, "Delete", "Cancel", a =>
|
||||||
{
|
{
|
||||||
ToastNotificationHelper.ShowMovedToast(Model, "Deleting", text);
|
ToastNotificationHelper.ShowMovedToast(Model, "Deleting", text);
|
||||||
Model.MarkForDelete();
|
Model.MarkForDelete();
|
||||||
|
@@ -116,7 +116,7 @@ namespace ModernKeePass.Pages
|
|||||||
? "Are you sure you want to send the whole group and all its entries to the recycle bin?"
|
? "Are you sure you want to send the whole group and all its entries to the recycle bin?"
|
||||||
: "Are you sure you want to delete the whole group and all its entries?";
|
: "Are you sure you want to delete the whole group and all its entries?";
|
||||||
var text = isRecycleBinEnabled ? "Item moved to the Recycle bin" : "Item permanently removed";
|
var text = isRecycleBinEnabled ? "Item moved to the Recycle bin" : "Item permanently removed";
|
||||||
MessageDialogHelper.ShowDeleteConfirmationDialog("Delete", message, a =>
|
MessageDialogHelper.ShowActionDialog("Warning", message, "Delete", "Cancel", a =>
|
||||||
{
|
{
|
||||||
ToastNotificationHelper.ShowMovedToast(Model, "Deleting", text);
|
ToastNotificationHelper.ShowMovedToast(Model, "Deleting", text);
|
||||||
Model.MarkForDelete();
|
Model.MarkForDelete();
|
||||||
|
@@ -34,9 +34,13 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Row="0" Text="{Binding Name}" Padding="5,0,0,0" />
|
<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" />
|
<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">
|
<local:CompositeKeyUserControl Grid.Row="2" x:Name="DatabaseUserControl" HorizontalAlignment="Stretch" MinWidth="400" Margin="0,10,0,0" Visibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<interactivity:Interaction.Behaviors>
|
<interactivity:Interaction.Behaviors>
|
||||||
|
<core:EventTriggerBehavior EventName="ValidationChecking">
|
||||||
|
<core:CallMethodAction TargetObject="{Binding}" MethodName="OpenDatabaseFile" />
|
||||||
|
</core:EventTriggerBehavior>
|
||||||
<core:EventTriggerBehavior EventName="ValidationChecked">
|
<core:EventTriggerBehavior EventName="ValidationChecked">
|
||||||
|
<core:CallMethodAction TargetObject="{Binding}" MethodName="UpdateAccessTime" />
|
||||||
<core:NavigateToPageAction TargetPage="ModernKeePass.Pages.GroupDetailPage" />
|
<core:NavigateToPageAction TargetPage="ModernKeePass.Pages.GroupDetailPage" />
|
||||||
</core:EventTriggerBehavior>
|
</core:EventTriggerBehavior>
|
||||||
</interactivity:Interaction.Behaviors>
|
</interactivity:Interaction.Behaviors>
|
||||||
|
@@ -1,9 +1,5 @@
|
|||||||
// Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238
|
// Pour en savoir plus sur le modèle d'élément Page vierge, consultez la page http://go.microsoft.com/fwlink/?LinkId=234238
|
||||||
|
|
||||||
using System;
|
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using ModernKeePass.ViewModels;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Pages
|
namespace ModernKeePass.Pages
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -11,17 +7,9 @@ namespace ModernKeePass.Pages
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class RecentDatabasesPage
|
public sealed partial class RecentDatabasesPage
|
||||||
{
|
{
|
||||||
|
|
||||||
public RecentVm Model => (RecentVm)DataContext;
|
|
||||||
public RecentDatabasesPage()
|
public RecentDatabasesPage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenDatabaseUserControl_OnValidationChecking(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var app = (App)Application.Current;
|
|
||||||
app.Database.DatabaseFile = ((RecentItemVm)Model.SelectedItem).DatabaseFile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
using Windows.Storage;
|
using System;
|
||||||
|
using Windows.Storage;
|
||||||
using ModernKeePass.Common;
|
using ModernKeePass.Common;
|
||||||
using Windows.Storage.AccessCache;
|
using Windows.Storage.AccessCache;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
using ModernKeePass.Interfaces;
|
using ModernKeePass.Interfaces;
|
||||||
|
|
||||||
namespace ModernKeePass.ViewModels
|
namespace ModernKeePass.ViewModels
|
||||||
@@ -27,5 +29,21 @@ namespace ModernKeePass.ViewModels
|
|||||||
get { return _isSelected; }
|
get { return _isSelected; }
|
||||||
set { SetProperty(ref _isSelected, value); }
|
set { SetProperty(ref _isSelected, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OpenDatabaseFile()
|
||||||
|
{
|
||||||
|
OpenDatabaseFile((Application.Current as App)?.Database);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenDatabaseFile(IDatabase database)
|
||||||
|
{
|
||||||
|
database.DatabaseFile = DatabaseFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void UpdateAccessTime()
|
||||||
|
{
|
||||||
|
var mru = StorageApplicationPermissions.MostRecentlyUsedList;
|
||||||
|
await mru.GetFileAsync(Token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,13 +37,12 @@ namespace ModernKeePass.ViewModels
|
|||||||
|
|
||||||
public RecentVm()
|
public RecentVm()
|
||||||
{
|
{
|
||||||
// TODO: opening the files actually changes the MRU order
|
|
||||||
var mru = StorageApplicationPermissions.MostRecentlyUsedList;
|
var mru = StorageApplicationPermissions.MostRecentlyUsedList;
|
||||||
foreach (var entry in mru.Entries)
|
foreach (var entry in mru.Entries)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var file = mru.GetFileAsync(entry.Token).GetAwaiter().GetResult();
|
var file = mru.GetFileAsync(entry.Token, AccessCacheOptions.SuppressAccessTimeUpdate).GetAwaiter().GetResult();
|
||||||
RecentItems.Add(new RecentItemVm(entry, file));
|
RecentItems.Add(new RecentItemVm(entry, file));
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
Reference in New Issue
Block a user