mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 15:40:18 -04:00
Toast notifications and undo mechanism now works! (for group and entries)
This commit is contained in:
@@ -9,7 +9,6 @@ using Windows.UI.Xaml.Navigation;
|
||||
using Microsoft.QueryStringDotNET;
|
||||
using ModernKeePass.Common;
|
||||
using ModernKeePass.Interfaces;
|
||||
using ModernKeePass.ViewModels;
|
||||
|
||||
// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227
|
||||
|
||||
@@ -21,7 +20,7 @@ namespace ModernKeePass
|
||||
sealed partial class App : Application
|
||||
{
|
||||
public DatabaseHelper Database { get; set; } = new DatabaseHelper();
|
||||
public Queue<IPwEntity> PendingDeleteQueue = new Queue<IPwEntity>();
|
||||
public Dictionary<string, IPwEntity> PendingDeleteEntities = new Dictionary<string, IPwEntity>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
@@ -33,6 +32,7 @@ namespace ModernKeePass
|
||||
Suspending += OnSuspending;
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
/// <summary>
|
||||
/// 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.
|
||||
@@ -90,25 +90,20 @@ namespace ModernKeePass
|
||||
// parameter
|
||||
rootFrame.Navigate(typeof(MainPage), lauchActivatedEventArgs.Arguments);
|
||||
}
|
||||
}
|
||||
//if (e is ToastNotificationActivatedEventArgs)
|
||||
else
|
||||
{
|
||||
/*var toastActivationArgs = e as ToastNotificationActivatedEventArgs;
|
||||
// App is "launched" via the Toast Activation event
|
||||
UndoEntityDelete(lauchActivatedEventArgs.Arguments);
|
||||
}
|
||||
}
|
||||
// This is only available on Windows 10...
|
||||
/*else if (e is ToastNotificationActivatedEventArgs)
|
||||
{
|
||||
var toastActivationArgs = e as ToastNotificationActivatedEventArgs;
|
||||
|
||||
// Parse the query string (using QueryString.NET)
|
||||
QueryString args = QueryString.Parse(toastActivationArgs.Argument);
|
||||
|
||||
// See what action is being requested
|
||||
switch (args["action"])
|
||||
{
|
||||
UndoEntityDelete(QueryString.Parse(toastActivationArgs.Argument));
|
||||
}*/
|
||||
var entity = PendingDeleteQueue.Dequeue();
|
||||
if (entity is GroupVm)
|
||||
{
|
||||
entity.ParentGroup.Groups.Add(entity as GroupVm);
|
||||
}
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
@@ -138,6 +133,10 @@ namespace ModernKeePass
|
||||
deferral.Complete();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when application is launched from opening a file in Windows Explorer
|
||||
/// </summary>
|
||||
/// <param name="args">Details about the file being opened</param>
|
||||
protected override void OnFileActivated(FileActivatedEventArgs args)
|
||||
{
|
||||
base.OnFileActivated(args);
|
||||
@@ -147,5 +146,14 @@ namespace ModernKeePass
|
||||
Window.Current.Content = rootFrame;
|
||||
Window.Current.Activate();
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void UndoEntityDelete(string arguments)
|
||||
{
|
||||
var args = QueryString.Parse(arguments);
|
||||
var entity = PendingDeleteEntities[args["entityId"]];
|
||||
PendingDeleteEntities.Remove(args["entityId"]);
|
||||
entity.UndoDelete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
97
ModernKeePass/Common/ToastNotificationHelper.cs
Normal file
97
ModernKeePass/Common/ToastNotificationHelper.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using Windows.Data.Xml.Dom;
|
||||
using Windows.UI.Notifications;
|
||||
using Windows.UI.Xaml;
|
||||
using Microsoft.QueryStringDotNET;
|
||||
using ModernKeePass.Interfaces;
|
||||
|
||||
namespace ModernKeePass.Common
|
||||
{
|
||||
public static class ToastNotificationHelper
|
||||
{
|
||||
public static /*async*/ void ShowUndoToast(string entityType, IPwEntity entity)
|
||||
{
|
||||
// This is for Windows 10
|
||||
// Construct the visuals of the toast
|
||||
/*var visual = new ToastVisual
|
||||
{
|
||||
BindingGeneric = new ToastBindingGeneric
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new AdaptiveText
|
||||
{
|
||||
Text = $"{entityType} {entity.Name} deleted."
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Construct the actions for the toast (inputs and buttons)
|
||||
var actions = new ToastActionsCustom
|
||||
{
|
||||
Buttons =
|
||||
{
|
||||
new ToastButton("Undo", new QueryString
|
||||
{
|
||||
{ "action", "undo" },
|
||||
{ "entityType", entityType },
|
||||
{ "entityId", entity.Id }
|
||||
|
||||
}.ToString())
|
||||
}
|
||||
};
|
||||
|
||||
// Now we can construct the final toast content
|
||||
var toastContent = new ToastContent
|
||||
{
|
||||
Visual = visual,
|
||||
Actions = actions,
|
||||
// Arguments when the user taps body of toast
|
||||
Launch = new QueryString()
|
||||
{
|
||||
{ "action", "undo" },
|
||||
{ "entityType", "group" },
|
||||
{ "entityId", entity.Id }
|
||||
|
||||
}.ToString()
|
||||
};
|
||||
|
||||
// And create the toast notification
|
||||
var toastXml = new XmlDocument();
|
||||
toastXml.LoadXml(toastContent.GetContent());
|
||||
|
||||
var toast = new ToastNotification(toastXml) {ExpirationTime = DateTime.Now.AddSeconds(5)};
|
||||
toast.Dismissed += Toast_Dismissed;
|
||||
*/
|
||||
var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
|
||||
var toastElements = notificationXml.GetElementsByTagName("text");
|
||||
toastElements[0].AppendChild(notificationXml.CreateTextNode($"{entityType} deleted"));
|
||||
toastElements[1].AppendChild(notificationXml.CreateTextNode("Click me to undo"));
|
||||
var toastNode = notificationXml.SelectSingleNode("/toast");
|
||||
((XmlElement)toastNode)?.SetAttribute("launch", new QueryString
|
||||
{
|
||||
{ "entityType", entityType },
|
||||
{ "entityId", entity.Id }
|
||||
|
||||
}.ToString());
|
||||
|
||||
var toast = new ToastNotification(notificationXml)
|
||||
{
|
||||
ExpirationTime = DateTime.Now.AddSeconds(5)
|
||||
};
|
||||
toast.Dismissed += Toast_Dismissed;
|
||||
ToastNotificationManager.CreateToastNotifier().Show(toast);
|
||||
}
|
||||
|
||||
private static void Toast_Dismissed(ToastNotification sender, ToastDismissedEventArgs args)
|
||||
{
|
||||
var toastNode = sender.Content.SelectSingleNode("/toast");
|
||||
var launchArguments = QueryString.Parse(((XmlElement)toastNode)?.GetAttribute("launch"));
|
||||
var app = (App)Application.Current;
|
||||
var entity = app.PendingDeleteEntities[launchArguments["entityId"]];
|
||||
app.PendingDeleteEntities.Remove(launchArguments["entityId"]);
|
||||
entity.CommitDelete();
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,5 +12,6 @@ namespace ModernKeePass.Interfaces
|
||||
bool IsEditMode { get; }
|
||||
|
||||
void CommitDelete();
|
||||
void UndoDelete();
|
||||
}
|
||||
}
|
@@ -117,6 +117,7 @@
|
||||
<Compile Include="Common\ObservableDictionary.cs" />
|
||||
<Compile Include="Common\RelayCommand.cs" />
|
||||
<Compile Include="Common\SuspensionManager.cs" />
|
||||
<Compile Include="Common\ToastNotificationHelper.cs" />
|
||||
<Compile Include="Controls\FirstItemDataTemplateSelector.cs" />
|
||||
<Compile Include="Controls\ListViewWithDisable.cs" />
|
||||
<Compile Include="Controls\OpenDatabaseUserControl.xaml.cs">
|
||||
|
@@ -86,8 +86,8 @@ namespace ModernKeePass.Pages
|
||||
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
|
||||
messageDialog.Commands.Add(new UICommand("Delete", delete =>
|
||||
{
|
||||
var entry = DataContext as EntryVm;
|
||||
entry?.RemoveEntry();
|
||||
ToastNotificationHelper.ShowUndoToast("Entry", Model);
|
||||
Model.MarkForDelete();
|
||||
if (Frame.CanGoBack) Frame.GoBack();
|
||||
}));
|
||||
messageDialog.Commands.Add(new UICommand("Cancel"));
|
||||
|
@@ -128,7 +128,7 @@ namespace ModernKeePass.Pages
|
||||
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
|
||||
messageDialog.Commands.Add(new UICommand("Delete", delete =>
|
||||
{
|
||||
ShowToast("Group", Model);
|
||||
ToastNotificationHelper.ShowUndoToast("Group", Model);
|
||||
Model.MarkForDelete();
|
||||
if (Frame.CanGoBack) Frame.GoBack();
|
||||
}));
|
||||
@@ -171,91 +171,5 @@ namespace ModernKeePass.Pages
|
||||
|
||||
#endregion
|
||||
|
||||
private async void ShowToast(string entityType, IPwEntity entity)
|
||||
{
|
||||
// Construct the visuals of the toast
|
||||
/*var visual = new ToastVisual
|
||||
{
|
||||
BindingGeneric = new ToastBindingGeneric
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new AdaptiveText
|
||||
{
|
||||
Text = $"{entityType} {entity.Name} deleted."
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Construct the actions for the toast (inputs and buttons)
|
||||
var actions = new ToastActionsCustom
|
||||
{
|
||||
Buttons =
|
||||
{
|
||||
new ToastButton("Undo", new QueryString
|
||||
{
|
||||
{ "action", "undo" },
|
||||
{ "entityType", entityType },
|
||||
{ "entityId", entity.Id }
|
||||
|
||||
}.ToString())
|
||||
}
|
||||
};
|
||||
|
||||
// Now we can construct the final toast content
|
||||
var toastContent = new ToastContent
|
||||
{
|
||||
Visual = visual,
|
||||
Actions = actions,
|
||||
// Arguments when the user taps body of toast
|
||||
Launch = new QueryString()
|
||||
{
|
||||
{ "action", "undo" },
|
||||
{ "entityType", "group" },
|
||||
{ "entityId", entity.Id }
|
||||
|
||||
}.ToString()
|
||||
};
|
||||
|
||||
// And create the toast notification
|
||||
var toastXml = new XmlDocument();
|
||||
toastXml.LoadXml(toastContent.GetContent());
|
||||
|
||||
var visualXml = toastXml.GetElementsByTagName("visual")[0];
|
||||
((XmlElement)visualXml.ChildNodes[0]).SetAttribute("template", "ToastText02");
|
||||
|
||||
var toast = new ToastNotification(toastXml) {ExpirationTime = DateTime.Now.AddSeconds(5)};
|
||||
toast.Dismissed += Toast_Dismissed;
|
||||
*/
|
||||
var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
|
||||
var toastElements = notificationXml.GetElementsByTagName("text");
|
||||
toastElements[0].AppendChild(notificationXml.CreateTextNode($"{entityType} deleted"));
|
||||
toastElements[1].AppendChild(notificationXml.CreateTextNode("Click me to undo"));
|
||||
var toastNode = notificationXml.SelectSingleNode("/toast");
|
||||
((XmlElement)toastNode).SetAttribute("launch", new QueryString
|
||||
{
|
||||
{ "entityType", entityType },
|
||||
{ "entityId", entity.Id }
|
||||
|
||||
}.ToString());
|
||||
|
||||
var toast = new ToastNotification(notificationXml)
|
||||
{
|
||||
ExpirationTime = DateTime.Now.AddSeconds(5)
|
||||
};
|
||||
ToastNotificationManager.CreateToastNotifier().Show(toast);
|
||||
}
|
||||
|
||||
private void Toast_Dismissed(ToastNotification sender, ToastDismissedEventArgs args)
|
||||
{
|
||||
var app = (App)Application.Current;
|
||||
if (app.PendingDeleteQueue.Count == 0) return;
|
||||
var entity = app.PendingDeleteQueue.Dequeue();
|
||||
if (entity is GroupVm)
|
||||
{
|
||||
entity.CommitDelete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ using ModernKeePassLib;
|
||||
using ModernKeePassLib.Cryptography.PasswordGenerator;
|
||||
using ModernKeePassLib.Security;
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace ModernKeePass.ViewModels
|
||||
{
|
||||
@@ -112,10 +113,6 @@ namespace ModernKeePass.ViewModels
|
||||
ParentGroup = parent;
|
||||
}
|
||||
|
||||
public void RemoveEntry()
|
||||
{
|
||||
ParentGroup.RemoveEntry(this);
|
||||
}
|
||||
|
||||
public void GeneratePassword()
|
||||
{
|
||||
@@ -155,9 +152,21 @@ namespace ModernKeePass.ViewModels
|
||||
Entry?.Strings.Set(key, new ProtectedString(true, newValue));
|
||||
}
|
||||
|
||||
public void MarkForDelete()
|
||||
{
|
||||
var app = (App)Application.Current;
|
||||
app.PendingDeleteEntities.Add(Id, this);
|
||||
ParentGroup.Entries.Remove(this);
|
||||
}
|
||||
public void CommitDelete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
Entry.ParentGroup.Entries.Remove(Entry);
|
||||
}
|
||||
|
||||
public void UndoDelete()
|
||||
{
|
||||
ParentGroup.Entries.Add(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -98,22 +98,10 @@ namespace ModernKeePass.ViewModels
|
||||
return newEntry;
|
||||
}
|
||||
|
||||
public void RemoveGroup()
|
||||
{
|
||||
_pwGroup.ParentGroup.Groups.Remove(_pwGroup);
|
||||
ParentGroup.Groups.Remove(this);
|
||||
}
|
||||
|
||||
public void RemoveEntry(EntryVm entry)
|
||||
{
|
||||
_pwGroup.Entries.Remove(entry.Entry);
|
||||
Entries.Remove(entry);
|
||||
}
|
||||
|
||||
public void MarkForDelete()
|
||||
{
|
||||
var app = (App)Application.Current;
|
||||
app.PendingDeleteQueue.Enqueue(this);
|
||||
app.PendingDeleteEntities.Add(Id, this);
|
||||
ParentGroup.Groups.Remove(this);
|
||||
}
|
||||
|
||||
@@ -121,5 +109,9 @@ namespace ModernKeePass.ViewModels
|
||||
{
|
||||
_pwGroup.ParentGroup.Groups.Remove(_pwGroup);
|
||||
}
|
||||
public void UndoDelete()
|
||||
{
|
||||
ParentGroup.Groups.Add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user