mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 15:40: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.Navigation;
|
||||
using ModernKeePass.Common;
|
||||
using ModernKeePass.Exceptions;
|
||||
using ModernKeePass.Interfaces;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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;
|
||||
MessageDialogHelper.ShowErrorDialog(
|
||||
var realException =
|
||||
exception is TargetInvocationException &&
|
||||
exception.InnerException != null
|
||||
? exception.InnerException
|
||||
: exception);
|
||||
: exception;
|
||||
|
||||
if (!(realException is SaveException)) return;
|
||||
unhandledExceptionEventArgs.Handled = true;
|
||||
MessageDialogHelper.SaveErrorDialog(realException as SaveException, Database);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.AccessCache;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using ModernKeePass.Exceptions;
|
||||
using ModernKeePass.Interfaces;
|
||||
using ModernKeePass.ViewModels;
|
||||
using ModernKeePassLib;
|
||||
@@ -102,7 +104,7 @@ namespace ModernKeePass.Common
|
||||
{
|
||||
Status = (int)DatabaseStatus.CompositeKeyError;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception)
|
||||
{
|
||||
Status = (int)DatabaseStatus.Error;
|
||||
throw;
|
||||
@@ -115,9 +117,21 @@ namespace ModernKeePass.Common
|
||||
/// <param name="file">The new database file</param>
|
||||
public void Save(StorageFile file)
|
||||
{
|
||||
var oldFile = DatabaseFile;
|
||||
DatabaseFile = file;
|
||||
_pwDatabase.SaveAs(IOConnectionInfo.FromFile(DatabaseFile), true, new NullStatusLogger());
|
||||
Status = (int)DatabaseStatus.Opened;
|
||||
try
|
||||
{
|
||||
_pwDatabase.SaveAs(IOConnectionInfo.FromFile(DatabaseFile), true, new NullStatusLogger());
|
||||
}
|
||||
catch
|
||||
{
|
||||
DatabaseFile = oldFile;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Status = (int)DatabaseStatus.Opened;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -126,7 +140,14 @@ namespace ModernKeePass.Common
|
||||
public void Save()
|
||||
{
|
||||
if (_pwDatabase == null || !_pwDatabase.IsOpen) return;
|
||||
_pwDatabase.Save(new NullStatusLogger());
|
||||
try
|
||||
{
|
||||
_pwDatabase.Save(new NullStatusLogger());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SaveException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -145,7 +166,7 @@ namespace ModernKeePass.Common
|
||||
|
||||
public void CreateRecycleBin()
|
||||
{
|
||||
RecycleBin = ((GroupVm)RootGroup).AddNewGroup("Recycle bin");
|
||||
RecycleBin = RootGroup.AddNewGroup("Recycle bin");
|
||||
RecycleBin.IsSelected = true;
|
||||
RecycleBin.IconSymbol = Symbol.Delete;
|
||||
}
|
||||
|
@@ -1,18 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.UI.Popups;
|
||||
using ModernKeePass.Exceptions;
|
||||
using ModernKeePass.Interfaces;
|
||||
|
||||
namespace ModernKeePass.Common
|
||||
{
|
||||
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
|
||||
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
|
||||
messageDialog.Commands.Add(new UICommand(actionText, action));
|
||||
messageDialog.Commands.Add(new UICommand("Cancel"));
|
||||
messageDialog.Commands.Add(new UICommand(actionButtonText, action));
|
||||
messageDialog.Commands.Add(new UICommand(cancelButtonText));
|
||||
|
||||
// Set the command that will be invoked by default
|
||||
messageDialog.DefaultCommandIndex = 1;
|
||||
@@ -24,6 +28,22 @@ namespace ModernKeePass.Common
|
||||
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;
|
||||
|
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="Converters\DiscreteIntToSolidColorBrushConverter.cs" />
|
||||
<Compile Include="Converters\NullToBooleanConverter.cs" />
|
||||
<Compile Include="Exceptions\SaveException.cs" />
|
||||
<Compile Include="Interfaces\IDatabase.cs" />
|
||||
<Compile Include="Interfaces\IHasSelectableObject.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 delete this entry?";
|
||||
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);
|
||||
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 delete the whole group and all its entries?";
|
||||
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);
|
||||
Model.MarkForDelete();
|
||||
|
@@ -34,9 +34,13 @@
|
||||
</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">
|
||||
<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>
|
||||
<core:EventTriggerBehavior EventName="ValidationChecking">
|
||||
<core:CallMethodAction TargetObject="{Binding}" MethodName="OpenDatabaseFile" />
|
||||
</core:EventTriggerBehavior>
|
||||
<core:EventTriggerBehavior EventName="ValidationChecked">
|
||||
<core:CallMethodAction TargetObject="{Binding}" MethodName="UpdateAccessTime" />
|
||||
<core:NavigateToPageAction TargetPage="ModernKeePass.Pages.GroupDetailPage" />
|
||||
</core:EventTriggerBehavior>
|
||||
</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
|
||||
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using ModernKeePass.ViewModels;
|
||||
|
||||
namespace ModernKeePass.Pages
|
||||
{
|
||||
/// <summary>
|
||||
@@ -11,17 +7,9 @@ namespace ModernKeePass.Pages
|
||||
/// </summary>
|
||||
public sealed partial class RecentDatabasesPage
|
||||
{
|
||||
|
||||
public RecentVm Model => (RecentVm)DataContext;
|
||||
public RecentDatabasesPage()
|
||||
{
|
||||
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 Windows.Storage.AccessCache;
|
||||
using Windows.UI.Xaml;
|
||||
using ModernKeePass.Interfaces;
|
||||
|
||||
namespace ModernKeePass.ViewModels
|
||||
@@ -27,5 +29,21 @@ namespace ModernKeePass.ViewModels
|
||||
get { return _isSelected; }
|
||||
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()
|
||||
{
|
||||
// TODO: opening the files actually changes the MRU order
|
||||
var mru = StorageApplicationPermissions.MostRecentlyUsedList;
|
||||
foreach (var entry in mru.Entries)
|
||||
{
|
||||
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));
|
||||
}
|
||||
catch (Exception)
|
||||
|
Reference in New Issue
Block a user