//-----------------------------------------------------------------------
//
// Copyright (c) lanedirt. All rights reserved.
// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
//
//-----------------------------------------------------------------------
namespace AliasVault.Client.Services;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
///
/// Service to manage and act on keyboard shortcuts across the application.
///
public sealed class KeyboardShortcutService : IAsyncDisposable
{
private readonly DotNetObjectReference _dotNetHelper;
private readonly NavigationManager _navigationManager;
private readonly DbService _dbService;
private readonly AuthService _authService;
private readonly Lazy> _moduleTask;
///
/// Initializes a new instance of the class.
///
/// IJSRuntime instance.
/// NavigationManager instance.
/// DbService instance.
/// AuthService instance.
public KeyboardShortcutService(IJSRuntime jsRuntime, NavigationManager navigationManager, DbService dbService, AuthService authService)
{
_dotNetHelper = DotNetObjectReference.Create(new CallbackWrapper());
_navigationManager = navigationManager;
_dbService = dbService;
_authService = authService;
_moduleTask = new Lazy>(() => jsRuntime.InvokeAsync(
"import", "./js/modules/keyboardShortcuts.js").AsTask());
_ = RegisterStaticShortcuts();
}
///
/// Registers a keyboard shortcut with the given keys and callback.
///
/// The keyboard keys.
/// Callback when shortcut is pressed.
/// Task.
public async Task RegisterShortcutAsync(string keys, Func callback)
{
_dotNetHelper.Value.RegisterCallback(keys, callback);
var module = await _moduleTask.Value;
await module.InvokeVoidAsync("registerShortcut", keys, _dotNetHelper);
}
///
/// Unregisters a keyboard shortcut with the given keys.
///
/// The keyboard keys.
/// Task.
public async Task UnregisterShortcutAsync(string keys)
{
_dotNetHelper.Value.UnregisterCallback(keys);
var module = await _moduleTask.Value;
await module.InvokeVoidAsync("unregisterShortcut", keys);
}
///
/// Disposes the service.
///
/// ValueTask.
public async ValueTask DisposeAsync()
{
var module = await _moduleTask.Value;
await module.InvokeVoidAsync("unregisterAllShortcuts");
await module.DisposeAsync();
_dotNetHelper.Dispose();
}
///
/// Registers static shortcuts that are always available.
///
private async Task RegisterStaticShortcuts()
{
// Global shortcut: Go home
await RegisterShortcutAsync("gh", () =>
{
_navigationManager.NavigateTo("/");
return Task.CompletedTask;
});
// Global shortcut: Go to email page
await RegisterShortcutAsync("ge", () =>
{
_navigationManager.NavigateTo("/emails");
return Task.CompletedTask;
});
// Global shortcut: Lock vault.
await RegisterShortcutAsync("gl", () =>
{
// Remove encryption key.
_authService.RemoveEncryptionKey();
// Initialize empty database which removes unencrypted data.
_dbService.InitializeEmptyDatabase();
// Redirect to unlock page.
_navigationManager.NavigateTo("/unlock");
return Task.CompletedTask;
});
}
///
/// Wrapper class for callback functions that are invoked from JavaScript.
///
private sealed class CallbackWrapper
{
private readonly Dictionary> _callbacks = new Dictionary>();
public void RegisterCallback(string keys, Func callback)
{
_callbacks[keys] = callback;
}
public void UnregisterCallback(string keys)
{
_callbacks.Remove(keys);
}
[JSInvokable]
public async Task Invoke(string keys)
{
if (_callbacks.TryGetValue(keys, out var callback))
{
await callback();
}
}
}
}