mirror of
https://github.com/lantean-code/qbtmud.git
synced 2025-11-03 05:23:17 +00:00
Ensure keyboard events can be scoped to dialogs only.
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
@inherits SubmittableDialog
|
||||
|
||||
<MudDialog>
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudGrid>
|
||||
<MudItem xs="12">
|
||||
<MudTextField @ref="UrlsTextField" Label="Urls" Lines="10" @bind-Value="Urls" Variant="Variant.Outlined" AutoFocus="true" />
|
||||
<MudFocusTrap>
|
||||
<MudTextField @ref="UrlsTextField" Label="Urls" Lines="10" @bind-Value="Urls" Variant="Variant.Outlined" AutoFocus="true" />
|
||||
</MudFocusTrap>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<AddTorrentOptions @ref="TorrentOptions" ShowCookieOption="false" />
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
using Lantean.QBTMudBlade.Models;
|
||||
using Lantean.QBTMudBlade.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
namespace Lantean.QBTMudBlade.Components.Dialogs
|
||||
{
|
||||
public partial class AddTorrentLinkDialog
|
||||
public partial class AddTorrentLinkDialog : IAsyncDisposable
|
||||
{
|
||||
private bool _disposedValue;
|
||||
private readonly KeyboardEvent _ctrlEnterKey = new KeyboardEvent("Enter")
|
||||
{
|
||||
CtrlKey = true,
|
||||
};
|
||||
|
||||
[Inject]
|
||||
protected IKeyboardService KeyboardService { get; set; } = default!;
|
||||
|
||||
[CascadingParameter]
|
||||
public MudDialogInstance MudDialog { get; set; } = default!;
|
||||
|
||||
@@ -15,6 +25,19 @@ namespace Lantean.QBTMudBlade.Components.Dialogs
|
||||
|
||||
protected AddTorrentOptions TorrentOptions { get; set; } = default!;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await KeyboardService.RegisterKeypressEvent(_ctrlEnterKey, k =>
|
||||
{
|
||||
Submit();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
await KeyboardService.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
protected void Cancel()
|
||||
{
|
||||
MudDialog.Cancel();
|
||||
@@ -31,19 +54,25 @@ namespace Lantean.QBTMudBlade.Components.Dialogs
|
||||
MudDialog.Close(DialogResult.Ok(options));
|
||||
}
|
||||
|
||||
protected override Task Submit(KeyboardEvent keyboardEvent)
|
||||
protected virtual async ValueTask DisposeAsync(bool disposing)
|
||||
{
|
||||
Submit();
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
await KeyboardService.UnregisterKeypressEvent(_ctrlEnterKey);
|
||||
await KeyboardService.UnFocus();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (firstRender && UrlsTextField is not null)
|
||||
{
|
||||
await UrlsTextField.FocusAsync();
|
||||
}
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
await DisposeAsync(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ namespace Lantean.QBTMudBlade.Components.Dialogs
|
||||
if (firstRender)
|
||||
{
|
||||
await KeyboardService.RegisterKeypressEvent("Enter", k => Submit(k));
|
||||
await KeyboardService.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +29,7 @@ namespace Lantean.QBTMudBlade.Components.Dialogs
|
||||
if (disposing)
|
||||
{
|
||||
await KeyboardService.UnregisterKeypressEvent("Enter");
|
||||
await KeyboardService.UnFocus();
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
|
||||
@@ -161,9 +161,12 @@ namespace Lantean.QBTMudBlade.Components
|
||||
|
||||
protected async Task Remove()
|
||||
{
|
||||
await DialogService.InvokeDeleteTorrentDialog(ApiClient, Hashes.ToArray());
|
||||
var deleted = await DialogService.InvokeDeleteTorrentDialog(ApiClient, Hashes.ToArray());
|
||||
|
||||
NavigationManager.NavigateTo("/");
|
||||
if (deleted)
|
||||
{
|
||||
NavigationManager.NavigateTo("/");
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task SetLocation()
|
||||
|
||||
@@ -95,11 +95,11 @@ namespace Lantean.QBTMudBlade.Helpers
|
||||
options.DownloadFirstAndLastPiecesFirst);
|
||||
}
|
||||
|
||||
public static async Task InvokeDeleteTorrentDialog(this IDialogService dialogService, IApiClient apiClient, params string[] hashes)
|
||||
public static async Task<bool> InvokeDeleteTorrentDialog(this IDialogService dialogService, IApiClient apiClient, params string[] hashes)
|
||||
{
|
||||
if (hashes.Length == 0)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
var parameters = new DialogParameters
|
||||
@@ -111,10 +111,12 @@ namespace Lantean.QBTMudBlade.Helpers
|
||||
var dialogResult = await reference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
await apiClient.DeleteTorrents(hashes, (bool)dialogResult.Data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task InvokeRenameFilesDialog(this IDialogService dialogService, IApiClient apiClient, string hash)
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Lantean.QBTMudBlade
|
||||
builder.Services.AddSingleton<IDataManager, DataManager>();
|
||||
builder.Services.AddBlazoredLocalStorage();
|
||||
builder.Services.AddSingleton<IClipboardService, ClipboardService>();
|
||||
builder.Services.AddSingleton<IKeyboardService, KeyboardService>();
|
||||
builder.Services.AddTransient<IKeyboardService, KeyboardService>();
|
||||
|
||||
#if DEBUG
|
||||
builder.Logging.SetMinimumLevel(LogLevel.Information);
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace Lantean.QBTMudBlade.Services
|
||||
{
|
||||
public interface IKeyboardService
|
||||
{
|
||||
Task Focus();
|
||||
Task UnFocus();
|
||||
Task RegisterKeypressEvent(KeyboardEvent criteria, Func<KeyboardEvent, Task> onKeyPress);
|
||||
|
||||
Task UnregisterKeypressEvent(KeyboardEvent criteria);
|
||||
|
||||
@@ -4,12 +4,12 @@ using System.Collections.Concurrent;
|
||||
|
||||
namespace Lantean.QBTMudBlade.Services
|
||||
{
|
||||
public class KeyboardService : IKeyboardService
|
||||
public class KeyboardService : IKeyboardService, IAsyncDisposable
|
||||
{
|
||||
private readonly IJSRuntime _jSRuntime;
|
||||
|
||||
private DotNetObjectReference<KeyboardService>? _dotNetObjectReference;
|
||||
|
||||
private bool _disposedValue;
|
||||
private readonly ConcurrentDictionary<string, Func<KeyboardEvent, Task>> _keyboardHandlers = new();
|
||||
|
||||
public KeyboardService(IJSRuntime jSRuntime)
|
||||
@@ -46,5 +46,41 @@ namespace Lantean.QBTMudBlade.Services
|
||||
await _jSRuntime.InvokeVoidAsync("qbt.unregisterKeypressEvent", criteria, GetObjectReference());
|
||||
_keyboardHandlers.Remove(criteria, out var _);
|
||||
}
|
||||
|
||||
public async Task Focus()
|
||||
{
|
||||
await _jSRuntime.InvokeVoidAsync("qbt.keyPressFocusInstance", GetObjectReference());
|
||||
}
|
||||
|
||||
public async Task UnFocus()
|
||||
{
|
||||
await _jSRuntime.InvokeVoidAsync("qbt.keyPressUnFocusInstance", GetObjectReference());
|
||||
}
|
||||
|
||||
protected async virtual ValueTask DisposeAsync(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
await UnFocus();
|
||||
foreach (var key in _keyboardHandlers.Keys)
|
||||
{
|
||||
await _jSRuntime.InvokeVoidAsync("qbt.unregisterKeypressEvent", key, GetObjectReference());
|
||||
}
|
||||
|
||||
_keyboardHandlers.Clear();
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
await DisposeAsync(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,21 +103,20 @@ window.qbt.clearSelection = () => {
|
||||
}
|
||||
|
||||
let supportedEvents = new Map();
|
||||
let focusInstance = null;
|
||||
|
||||
document.addEventListener('keyup', event => {
|
||||
const key = getKey(event);
|
||||
|
||||
console.log(key);
|
||||
console.log(event);
|
||||
|
||||
const references = supportedEvents.get(key);
|
||||
if (!references) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(references);
|
||||
|
||||
references.forEach(dotNetObjectReference => {
|
||||
if (focusInstance && dotNetObjectReference !== focusInstance) {
|
||||
return;
|
||||
}
|
||||
dotNetObjectReference.invokeMethodAsync('HandleKeyPressEvent', {
|
||||
key: event.key,
|
||||
code: event.code,
|
||||
@@ -143,8 +142,6 @@ window.qbt.registerKeypressEvent = (keyboardEventArgs, dotNetObjectReference) =>
|
||||
references.set(dotNetObjectReference._id, dotNetObjectReference);
|
||||
supportedEvents.set(key, references);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
window.qbt.unregisterKeypressEvent = (keyboardEventArgs, dotNetObjectReference) => {
|
||||
@@ -158,6 +155,14 @@ window.qbt.unregisterKeypressEvent = (keyboardEventArgs, dotNetObjectReference)
|
||||
references.delete(dotNetObjectReference._id);
|
||||
}
|
||||
|
||||
window.qbt.keyPressFocusInstance = dotNetObjectReference => {
|
||||
focusInstance = dotNetObjectReference;
|
||||
}
|
||||
|
||||
window.qbt.keyPressUnFocusInstance = dotNetObjectReference => {
|
||||
focusInstance = null;
|
||||
}
|
||||
|
||||
function getKey(keyboardEvent) {
|
||||
return keyboardEvent.key + (keyboardEvent.ctrlKey ? '1' : '0') + (keyboardEvent.shiftKey ? '1' : '0') + (keyboardEvent.altKey ? '1' : '0') + (keyboardEvent.metaKey ? '1' : '0') + (keyboardEvent.repeat ? '1' : '0');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user