//----------------------------------------------------------------------- // // 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(); } } } }