From ac7b867f54e37126e1ff6a5c3288ae9a6d9b5559 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Thu, 4 Dec 2025 07:52:37 +0100 Subject: [PATCH] refactor: util for keyboard activation --- lib/mixins/keyboard_long_press_mixin.dart | 11 ++------ lib/screens/discover_screen.dart | 5 +--- lib/screens/libraries_screen.dart | 28 ++++--------------- .../library_tabs/library_browse_tab.dart | 5 +--- lib/utils/keyboard_utils.dart | 8 ++++++ lib/widgets/folder_tree_item.dart | 11 ++------ lib/widgets/hub_section.dart | 6 ++-- lib/widgets/media_context_menu.dart | 10 ++----- 8 files changed, 25 insertions(+), 59 deletions(-) diff --git a/lib/mixins/keyboard_long_press_mixin.dart b/lib/mixins/keyboard_long_press_mixin.dart index d201eb04..cc89c1fe 100644 --- a/lib/mixins/keyboard_long_press_mixin.dart +++ b/lib/mixins/keyboard_long_press_mixin.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import '../utils/keyboard_utils.dart'; /// A mixin that provides keyboard long-press detection for focusable widgets. /// @@ -42,19 +43,11 @@ mixin KeyboardLongPressMixin on State { /// Override to handle long press action (e.g., show context menu) void onKeyboardLongPress(); - /// Check if the given key is an activation key - bool _isActivationKey(LogicalKeyboardKey key) { - return key == LogicalKeyboardKey.enter || - key == LogicalKeyboardKey.space || - key == LogicalKeyboardKey.select || - key == LogicalKeyboardKey.gameButtonA; - } - /// Call this from your onKeyEvent handler to enable long-press detection. /// Returns [KeyEventResult.handled] if the event was an activation key, /// [KeyEventResult.ignored] otherwise. KeyEventResult handleKeyboardLongPress(KeyEvent event) { - if (!_isActivationKey(event.logicalKey)) { + if (!isKeyboardActivationKey(event.logicalKey)) { return KeyEventResult.ignored; } diff --git a/lib/screens/discover_screen.dart b/lib/screens/discover_screen.dart index 652678c7..93490599 100644 --- a/lib/screens/discover_screen.dart +++ b/lib/screens/discover_screen.dart @@ -133,10 +133,7 @@ class _DiscoverScreenState extends State KeyEventResult _handleHeroKeyEvent(FocusNode node, KeyEvent event) { if (event is KeyDownEvent) { // Enter/Space to play current hero item - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { if (_onDeck.isNotEmpty && _currentHeroIndex < _onDeck.length) { navigateToVideoPlayer(context, metadata: _onDeck[_currentHeroIndex]); return KeyEventResult.handled; diff --git a/lib/screens/libraries_screen.dart b/lib/screens/libraries_screen.dart index 374e918b..2219fc5a 100644 --- a/lib/screens/libraries_screen.dart +++ b/lib/screens/libraries_screen.dart @@ -1028,10 +1028,7 @@ class _LibrariesScreenState extends State focusNode: _libraryDropdownFocusNode, onKeyEvent: (node, event) { if (event is KeyDownEvent) { - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { _libraryDropdownKey.currentState?.showButtonMenu(); return KeyEventResult.handled; } @@ -1133,10 +1130,7 @@ class _LibrariesScreenState extends State onKeyEvent: (node, event) { if (event is KeyDownEvent) { // Activation keys - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { onPressed(); return KeyEventResult.handled; } @@ -1668,24 +1662,17 @@ class _LibraryManagementSheetState extends State<_LibraryManagementSheet> { if (index < maxIndex) onMove(1); return KeyEventResult.handled; } - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { onEndMove(); return KeyEventResult.handled; } - if (event.logicalKey == LogicalKeyboardKey.escape || - event.logicalKey == LogicalKeyboardKey.gameButtonB) { + if (isBackKey(event.logicalKey)) { onCancelMove(); return KeyEventResult.handled; } } else { // Not moving - Enter/Space starts move - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { onStartMove(); return KeyEventResult.handled; } @@ -1749,10 +1736,7 @@ class _LibraryManagementSheetState extends State<_LibraryManagementSheet> { if (event is! KeyDownEvent) return KeyEventResult.ignored; // Handle activation - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { onPressed(); return KeyEventResult.handled; } diff --git a/lib/screens/library_tabs/library_browse_tab.dart b/lib/screens/library_tabs/library_browse_tab.dart index 311a75e9..e66ba6ed 100644 --- a/lib/screens/library_tabs/library_browse_tab.dart +++ b/lib/screens/library_tabs/library_browse_tab.dart @@ -438,10 +438,7 @@ class _LibraryBrowseTabState extends State return Focus( onKeyEvent: (node, event) { if (event is KeyDownEvent) { - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { onPressed(); return KeyEventResult.handled; } diff --git a/lib/utils/keyboard_utils.dart b/lib/utils/keyboard_utils.dart index af761d94..ac5098fb 100644 --- a/lib/utils/keyboard_utils.dart +++ b/lib/utils/keyboard_utils.dart @@ -13,3 +13,11 @@ bool isBackKeyEvent(KeyEvent event) { if (event is! KeyDownEvent) return false; return isBackKey(event.logicalKey); } + +/// Check if the given key should activate/select an item +bool isKeyboardActivationKey(LogicalKeyboardKey key) { + return key == LogicalKeyboardKey.enter || + key == LogicalKeyboardKey.space || + key == LogicalKeyboardKey.select || + key == LogicalKeyboardKey.gameButtonA; +} diff --git a/lib/widgets/folder_tree_item.dart b/lib/widgets/folder_tree_item.dart index cfe8c962..086fb739 100644 --- a/lib/widgets/folder_tree_item.dart +++ b/lib/widgets/folder_tree_item.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../models/plex_metadata.dart'; +import '../utils/keyboard_utils.dart'; /// Individual item in the folder tree /// Can be either a folder (expandable) or a file (tappable) @@ -54,15 +55,9 @@ class _FolderTreeItemState extends State { } } - bool _isActivationKey(LogicalKeyboardKey key) { - return key == LogicalKeyboardKey.enter || - key == LogicalKeyboardKey.space || - key == LogicalKeyboardKey.select || - key == LogicalKeyboardKey.gameButtonA; - } - KeyEventResult _handleKeyEvent(FocusNode node, KeyEvent event) { - if (event is KeyDownEvent && _isActivationKey(event.logicalKey)) { + if (event is KeyDownEvent && + isKeyboardActivationKey(event.logicalKey)) { _isKeyboardActivation = true; return KeyEventResult.ignored; // Let InkWell handle the activation } diff --git a/lib/widgets/hub_section.dart b/lib/widgets/hub_section.dart index 9c2a0136..a9095116 100644 --- a/lib/widgets/hub_section.dart +++ b/lib/widgets/hub_section.dart @@ -7,6 +7,7 @@ import 'horizontal_scroll_with_arrows.dart'; import 'hub_navigation_controller.dart'; import '../i18n/strings.g.dart'; import 'focus/focus_indicator.dart'; +import '../utils/keyboard_utils.dart'; /// Shared hub section widget used in both discover and library screens /// Displays a hub title with icon and a horizontal scrollable list of items @@ -162,10 +163,7 @@ class _HubSectionState extends State { KeyEventResult _handleHeaderKeyEvent(FocusNode node, KeyEvent event) { if (event is KeyDownEvent && widget.hub.more) { - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { _navigateToHubDetail(); return KeyEventResult.handled; } diff --git a/lib/widgets/media_context_menu.dart b/lib/widgets/media_context_menu.dart index ebce1fdd..2220f9d6 100644 --- a/lib/widgets/media_context_menu.dart +++ b/lib/widgets/media_context_menu.dart @@ -1498,10 +1498,7 @@ class _FocusableContextMenuSheetState } // Select with Enter/Space - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { Navigator.pop(context, widget.actions[_focusedIndex].value); return KeyEventResult.handled; } @@ -1628,10 +1625,7 @@ class _FocusablePopupMenuState extends State<_FocusablePopupMenu> { } // Select with Enter/Space - if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.space || - event.logicalKey == LogicalKeyboardKey.select || - event.logicalKey == LogicalKeyboardKey.gameButtonA) { + if (isKeyboardActivationKey(event.logicalKey)) { Navigator.pop(context, widget.actions[_focusedIndex].value); return KeyEventResult.handled; }