diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/bottom_app_bar.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/bottom_app_bar.dart index 21c24668..b57e0542 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/bottom_app_bar.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/bottom_app_bar.dart @@ -57,7 +57,6 @@ import 'package:weblibre/features/user/domain/repositories/general_settings.dart import 'package:weblibre/presentation/hooks/cached_future.dart'; import 'package:weblibre/presentation/hooks/menu_controller.dart'; import 'package:weblibre/presentation/icons/tor_icons.dart'; -import 'package:weblibre/presentation/widgets/non_focusable.dart'; import 'package:weblibre/presentation/widgets/selectable_chips.dart'; import 'package:weblibre/presentation/widgets/url_icon.dart'; @@ -326,90 +325,78 @@ class BrowserTabBar extends HookConsumerWidget { return Visibility( visible: tabBarReaderView || readerabilityStateActive, - child: NonFocusable( - child: ReaderButton( - buttonBuilder: (isLoading, readerActive, icon) => - InkWell( - onTap: isLoading - ? null - : () async { - await ref - .read( - readerableScreenControllerProvider - .notifier, - ) - .toggleReaderView( - !readerActive, - ); - }, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 15.0, - horizontal: 8.0, - ), - child: icon, + child: ReaderButton( + buttonBuilder: (isLoading, readerActive, icon) => + InkWell( + onTap: isLoading + ? null + : () async { + await ref + .read( + readerableScreenControllerProvider + .notifier, + ) + .toggleReaderView(!readerActive); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 15.0, + horizontal: 8.0, ), + child: icon, ), - ), + ), ), ); }, ), if (showExtensionShortcut) - NonFocusable( - child: ExtensionShortcutMenu( - controller: extensionMenuController, - child: IconButton( - onPressed: () { - if (extensionMenuController.isOpen) { - extensionMenuController.close(); - } else { - extensionMenuController.open(); - } - }, - icon: const Icon(MdiIcons.puzzle), - ), + ExtensionShortcutMenu( + controller: extensionMenuController, + child: IconButton( + onPressed: () { + if (extensionMenuController.isOpen) { + extensionMenuController.close(); + } else { + extensionMenuController.open(); + } + }, + icon: const Icon(MdiIcons.puzzle), ), ), if (selectedTabId != null) - NonFocusable( - child: TabMenu( - controller: trippleDotMenuController, - selectedTabId: selectedTabId, - builder: (context, controller, child) { - return InkWell( - onTap: () { - if (controller.isOpen) { - controller.close(); - } else { - controller.open(); - } - }, - child: const Padding( - padding: EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 15.0, - ), - child: Icon(MdiIcons.dotsVertical), + TabMenu( + controller: trippleDotMenuController, + selectedTabId: selectedTabId, + builder: (context, controller, child) { + return InkWell( + onTap: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 15.0, ), - ); - }, - ), + child: Icon(MdiIcons.dotsVertical), + ), + ); + }, ), if (showMainToolbarTabsCount) - NonFocusable( - child: TabsCountButton( - selectedTabId: selectedTabId, - displayedSheet: displayedSheet, - showLongPressMenu: true, - ), + TabsCountButton( + selectedTabId: selectedTabId, + displayedSheet: displayedSheet, + showLongPressMenu: true, ), if (showMainToolbarNavigationButton) - NonFocusable( - child: NavigationMenuButton( - selectedTabId: selectedTabId, - showNavigationButtons: true, - ), + NavigationMenuButton( + selectedTabId: selectedTabId, + showNavigationButtons: true, ), ], ), @@ -453,42 +440,32 @@ class ContextualToolbar extends HookConsumerWidget { children: [ if (tabState?.historyState.canGoBack == true || tabState?.isLoading == true) - NonFocusable( - child: NavigateBackButton( - selectedTabId: selectedTabId, - isLoading: tabState?.isLoading ?? false, - ), + NavigateBackButton( + selectedTabId: selectedTabId, + isLoading: tabState?.isLoading ?? false, ) else - NonFocusable( - child: IconButton( - onPressed: () async { - await BookmarkListRoute( - entryGuid: BookmarkRoot.root.id, - ).push(context); - }, - icon: const Icon(MdiIcons.bookmarkMultiple), - ), + IconButton( + onPressed: () async { + await BookmarkListRoute( + entryGuid: BookmarkRoot.root.id, + ).push(context); + }, + icon: const Icon(MdiIcons.bookmarkMultiple), ), if (tabState?.historyState.canGoForward == true) - NonFocusable( - child: NavigateForwardButton(selectedTabId: selectedTabId), - ) + NavigateForwardButton(selectedTabId: selectedTabId) else - NonFocusable(child: ShareMenuButton(selectedTabId: selectedTabId)), - const NonFocusable(child: AddTabButton()), - NonFocusable( - child: TabsCountButton( - selectedTabId: selectedTabId, - displayedSheet: displayedSheet, - showLongPressMenu: false, - ), + ShareMenuButton(selectedTabId: selectedTabId), + const AddTabButton(), + TabsCountButton( + selectedTabId: selectedTabId, + displayedSheet: displayedSheet, + showLongPressMenu: false, ), - NonFocusable( - child: NavigationMenuButton( - selectedTabId: selectedTabId, - showNavigationButtons: false, - ), + NavigationMenuButton( + selectedTabId: selectedTabId, + showNavigationButtons: false, ), ], ); @@ -651,17 +628,15 @@ class ShareMenuButton extends HookConsumerWidget { ShowQrCodeMenuItemButton(selectedTabId: selectedTabId), ], builder: (context, controller, child) { - return NonFocusable( - child: IconButton( - onPressed: () { - if (controller.isOpen) { - controller.close(); - } else { - controller.open(); - } - }, - icon: const Icon(Icons.share), - ), + return IconButton( + onPressed: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + icon: const Icon(Icons.share), ); }, ); @@ -730,19 +705,17 @@ class NavigationMenuButton extends HookConsumerWidget { alignment: WrapAlignment.center, children: [ ...pageExtensions.map( - (extension) => NonFocusable( - child: IconButton( - onPressed: () async { - //Use parents .ref because after onPressed this consumer gets disposed already - await addonService.invokeAddonAction( - extension.extensionId, - WebExtensionActionType.page, - ); - }, - icon: Padding( - padding: const EdgeInsets.only(top: 4.0), - child: ExtensionBadgeIcon(extension), - ), + (extension) => IconButton( + onPressed: () async { + //Use parents .ref because after onPressed this consumer gets disposed already + await addonService.invokeAddonAction( + extension.extensionId, + WebExtensionActionType.page, + ); + }, + icon: Padding( + padding: const EdgeInsets.only(top: 4.0), + child: ExtensionBadgeIcon(extension), ), ), ), @@ -974,20 +947,18 @@ class NavigateForwardButton extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - return NonFocusable( - child: IconButton( - onPressed: canGoForward - ? () async { - final controller = ref.read( - tabSessionProvider(tabId: selectedTabId).notifier, - ); + return IconButton( + onPressed: canGoForward + ? () async { + final controller = ref.read( + tabSessionProvider(tabId: selectedTabId).notifier, + ); - await controller.goForward(); - menuControllerToClose?.close(); - } - : null, - icon: const Icon(Icons.arrow_forward), - ), + await controller.goForward(); + menuControllerToClose?.close(); + } + : null, + icon: const Icon(Icons.arrow_forward), ); } } @@ -1008,37 +979,33 @@ class NavigateBackButton extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - return NonFocusable( - child: IconButton( - onPressed: (canGoBack || isLoading) - ? () async { - final controller = ref.read( - tabSessionProvider(tabId: selectedTabId).notifier, - ); + return IconButton( + onPressed: (canGoBack || isLoading) + ? () async { + final controller = ref.read( + tabSessionProvider(tabId: selectedTabId).notifier, + ); - final isReaderActive = ref.read( - selectedTabStateProvider.select( - (state) => state?.readerableState.active ?? false, - ), - ); + final isReaderActive = ref.read( + selectedTabStateProvider.select( + (state) => state?.readerableState.active ?? false, + ), + ); - if (isLoading) { - await controller.stopLoading(); - } else if (isReaderActive) { - await ref - .read(readerableScreenControllerProvider.notifier) - .toggleReaderView(false); - } else { - await controller.goBack(); - } - - menuControllerToClose?.close(); + if (isLoading) { + await controller.stopLoading(); + } else if (isReaderActive) { + await ref + .read(readerableScreenControllerProvider.notifier) + .toggleReaderView(false); + } else { + await controller.goBack(); } - : null, - icon: isLoading - ? const Icon(Icons.close) - : const Icon(Icons.arrow_back), - ), + + menuControllerToClose?.close(); + } + : null, + icon: isLoading ? const Icon(Icons.close) : const Icon(Icons.arrow_back), ); } } @@ -1052,30 +1019,28 @@ class AddTabButton extends HookConsumerWidget { return TabCreationMenu( controller: tabMenuController, - child: NonFocusable( - child: IconButton( - onPressed: () async { - final settings = ref.read(generalSettingsWithDefaultsProvider); + child: IconButton( + onPressed: () async { + final settings = ref.read(generalSettingsWithDefaultsProvider); - await SearchRoute( - tabType: - ref.read(selectedTabTypeProvider) ?? - settings.defaultCreateTabType, - ).push(context); + await SearchRoute( + tabType: + ref.read(selectedTabTypeProvider) ?? + settings.defaultCreateTabType, + ).push(context); - if (context.mounted) { - const BrowserRoute().go(context); - } - }, - icon: const Icon(MdiIcons.tabPlus), - onLongPress: () { - if (tabMenuController.isOpen) { - tabMenuController.close(); - } else { - tabMenuController.open(); - } - }, - ), + if (context.mounted) { + const BrowserRoute().go(context); + } + }, + icon: const Icon(MdiIcons.tabPlus), + onLongPress: () { + if (tabMenuController.isOpen) { + tabMenuController.close(); + } else { + tabMenuController.open(); + } + }, ), ); } diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_preview.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_preview.dart index 7442450f..25649a70 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_preview.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_preview.dart @@ -152,24 +152,22 @@ class GridTabPreview extends HookConsumerWidget { child: Text('Close all from ${tabState.url.host}'), ), ], - child: NonFocusable( - child: IconButton( - visualDensity: const VisualDensity( - horizontal: -4.0, - vertical: -4.0, - ), - onPressed: onDelete, - onLongPress: onDeleteAll != null - ? () { - if (extendedDeleteMenuController.isOpen) { - extendedDeleteMenuController.close(); - } else { - extendedDeleteMenuController.open(); - } - } - : null, - icon: const Icon(Icons.close), + child: IconButton( + visualDensity: const VisualDensity( + horizontal: -4.0, + vertical: -4.0, ), + onPressed: onDelete, + onLongPress: onDeleteAll != null + ? () { + if (extendedDeleteMenuController.isOpen) { + extendedDeleteMenuController.close(); + } else { + extendedDeleteMenuController.open(); + } + } + : null, + icon: const Icon(Icons.close), ), ), ?trailingChild, @@ -352,20 +350,18 @@ class ListTabPreview extends HookConsumerWidget { child: Text('Close all from ${tabState.url.host}'), ), ], - child: NonFocusable( - child: IconButton( - onPressed: onDelete, - onLongPress: onDeleteAll != null - ? () { - if (extendedDeleteMenuController.isOpen) { - extendedDeleteMenuController.close(); - } else { - extendedDeleteMenuController.open(); - } + child: IconButton( + onPressed: onDelete, + onLongPress: onDeleteAll != null + ? () { + if (extendedDeleteMenuController.isOpen) { + extendedDeleteMenuController.close(); + } else { + extendedDeleteMenuController.open(); } - : null, - icon: const Icon(Icons.close), - ), + } + : null, + icon: const Icon(Icons.close), ), ), ?trailingChild, @@ -631,12 +627,10 @@ class SuggestedSingleGridTabPreview extends StatelessWidget { tabId: tabId, isActive: tabId == activeTabId, onTap: onTap, - trailingChild: const NonFocusable( - child: IconButton( - visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0), - icon: Icon(MdiIcons.creation), - onPressed: null, - ), + trailingChild: const IconButton( + visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0), + icon: Icon(MdiIcons.creation), + onPressed: null, ), ), ); @@ -665,12 +659,10 @@ class SuggestedSingleListTabPreview extends StatelessWidget { tabId: tabId, isActive: tabId == activeTabId, onTap: onTap, - trailingChild: const NonFocusable( - child: IconButton( - visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0), - icon: Icon(MdiIcons.creation), - onPressed: null, - ), + trailingChild: const IconButton( + visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0), + icon: Icon(MdiIcons.creation), + onPressed: null, ), ), ); diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_view_header.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_view_header.dart index 822bd4d9..f22f86ed 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_view_header.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_view/tab_view_header.dart @@ -26,7 +26,6 @@ import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/c import 'package:weblibre/features/tor/presentation/controllers/start_tor_proxy.dart'; import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; import 'package:weblibre/presentation/hooks/menu_controller.dart'; -import 'package:weblibre/presentation/widgets/non_focusable.dart'; import 'package:weblibre/presentation/widgets/speech_to_text_button.dart'; import 'package:weblibre/utils/ui_helper.dart' as ui_helper; @@ -83,31 +82,27 @@ class TabViewHeader extends HookConsumerWidget { Row( mainAxisSize: MainAxisSize.min, children: [ - NonFocusable( - child: IconButton( - icon: const Icon(MdiIcons.tabSearch), - iconSize: 18, - padding: EdgeInsets.zero, - tooltip: 'Search inside tabs', - onPressed: () { - switch (ref.read( - tabsViewModeControllerProvider, - )) { - case TabsViewMode.tree: - case TabsViewMode.list: - break; - case TabsViewMode.grid: - ref - .read( - tabsViewModeControllerProvider.notifier, - ) - .set(TabsViewMode.list); - } + IconButton( + icon: const Icon(MdiIcons.tabSearch), + iconSize: 18, + padding: EdgeInsets.zero, + tooltip: 'Search inside tabs', + onPressed: () { + switch (ref.read(tabsViewModeControllerProvider)) { + case TabsViewMode.tree: + case TabsViewMode.list: + break; + case TabsViewMode.grid: + ref + .read( + tabsViewModeControllerProvider.notifier, + ) + .set(TabsViewMode.list); + } - searchMode.value = true; - searchTextFocus.requestFocus(); - }, - ), + searchMode.value = true; + searchTextFocus.requestFocus(); + }, ), const SizedBox( height: 32, @@ -131,23 +126,21 @@ class TabViewHeader extends HookConsumerWidget { ), ) .toList(), - child: NonFocusable( - child: IconButton( - tooltip: 'Change view mode', - onPressed: () { - if (viewModeMenuController.isOpen) { - viewModeMenuController.close(); - } else { - viewModeMenuController.open(); - } - }, - icon: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(tabsViewMode.icon, size: 18), - const Icon(Icons.arrow_drop_down, size: 18), - ], - ), + child: IconButton( + tooltip: 'Change view mode', + onPressed: () { + if (viewModeMenuController.isOpen) { + viewModeMenuController.close(); + } else { + viewModeMenuController.open(); + } + }, + icon: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(tabsViewMode.icon, size: 18), + const Icon(Icons.arrow_drop_down, size: 18), + ], ), ), ), @@ -174,42 +167,40 @@ class TabViewHeader extends HookConsumerWidget { style: const TextStyle(fontSize: 10), ) : null, - child: NonFocusable( - child: IconButton.filledTonal( - icon: const Icon(MdiIcons.imageAutoAdjust), - isSelected: tabSuggestionsEnabled, - iconSize: 18, - padding: EdgeInsets.zero, - tooltip: downloadProgress != null - ? 'Downloading AI models (${downloadProgress.progress.toInt()}%)' - : tabSuggestionsEnabled - ? 'Disable AI tab suggestions' - : 'Enable AI tab suggestions', - onPressed: () async { - if (!tabSuggestionsEnabled) { - final result = - await showEnableAiTabSuggestionsDialog( - context, - ); + child: IconButton.filledTonal( + icon: const Icon(MdiIcons.imageAutoAdjust), + isSelected: tabSuggestionsEnabled, + iconSize: 18, + padding: EdgeInsets.zero, + tooltip: downloadProgress != null + ? 'Downloading AI models (${downloadProgress.progress.toInt()}%)' + : tabSuggestionsEnabled + ? 'Disable AI tab suggestions' + : 'Enable AI tab suggestions', + onPressed: () async { + if (!tabSuggestionsEnabled) { + final result = + await showEnableAiTabSuggestionsDialog( + context, + ); - if (result == true) { - ref - .read( - tabSuggestionsControllerProvider - .notifier, - ) - .enable(); - } - } else { + if (result == true) { ref .read( tabSuggestionsControllerProvider .notifier, ) - .disable(); + .enable(); } - }, - ), + } else { + ref + .read( + tabSuggestionsControllerProvider + .notifier, + ) + .disable(); + } + }, ), ); }, @@ -513,18 +504,16 @@ class TabViewHeader extends HookConsumerWidget { }, ), ], - child: NonFocusable( - child: IconButton( - tooltip: 'Tab actions', - onPressed: () { - if (tabsActionMenuController.isOpen) { - tabsActionMenuController.close(); - } else { - tabsActionMenuController.open(); - } - }, - icon: const Icon(MdiIcons.dotsVertical), - ), + child: IconButton( + tooltip: 'Tab actions', + onPressed: () { + if (tabsActionMenuController.isOpen) { + tabsActionMenuController.close(); + } else { + tabsActionMenuController.open(); + } + }, + icon: const Icon(MdiIcons.dotsVertical), ), ), ], @@ -548,15 +537,13 @@ class TabViewHeader extends HookConsumerWidget { searchTextController.text = data; }, ), - NonFocusable( - child: IconButton( - onPressed: () { - searchTextController.clear(); - searchTextFocus.requestFocus(); - searchMode.value = false; - }, - icon: const Icon(Icons.clear), - ), + IconButton( + onPressed: () { + searchTextController.clear(); + searchTextFocus.requestFocus(); + searchMode.value = false; + }, + icon: const Icon(Icons.clear), ), ], ), diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart index f3df1a23..67fb8ab3 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart @@ -26,7 +26,6 @@ import 'package:weblibre/features/geckoview/features/tabs/data/entities/containe import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selected_container.dart'; import 'package:weblibre/features/geckoview/features/tabs/utils/container_colors.dart'; -import 'package:weblibre/presentation/widgets/non_focusable.dart'; class TabsActionButton extends HookConsumerWidget { final bool isActive; @@ -57,65 +56,63 @@ class TabsActionButton extends HookConsumerWidget { selectedContainerDataProvider.select((value) => value.value?.color), ); - return NonFocusable( - child: InkWell( - onTap: onTap, - onDoubleTap: onDoubleTap, - onLongPress: onLongPress, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 15.0), - child: Container( - decoration: BoxDecoration( - border: Border.all( - width: 2.0, - color: isActive - ? theme.colorScheme.primary - : DefaultTextStyle.of(context).style.color!, - ), - borderRadius: BorderRadius.circular(5.0), - color: containerColor.mapNotNull(ContainerColors.forAppBar), + return InkWell( + onTap: onTap, + onDoubleTap: onDoubleTap, + onLongPress: onLongPress, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 15.0), + child: Container( + decoration: BoxDecoration( + border: Border.all( + width: 2.0, + color: isActive + ? theme.colorScheme.primary + : DefaultTextStyle.of(context).style.color!, ), - constraints: const BoxConstraints(minWidth: 25.0), - child: Center( - child: tabCount.when( - skipLoadingOnReload: true, - data: (count) { - return Text( - count.toString(), - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.0, - color: isActive ? theme.colorScheme.primary : null, - ), - ); - }, - loading: () => (tabCount.hasValue) - ? Text( - tabCount.value.toString(), - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.0, - color: isActive ? theme.colorScheme.primary : null, - ), - ) - : const Skeletonizer(child: Text('00')), - error: (error, stackTrace) { - logger.e( - 'Could not determine tab count', - error: error, - stackTrace: stackTrace, - ); + borderRadius: BorderRadius.circular(5.0), + color: containerColor.mapNotNull(ContainerColors.forAppBar), + ), + constraints: const BoxConstraints(minWidth: 25.0), + child: Center( + child: tabCount.when( + skipLoadingOnReload: true, + data: (count) { + return Text( + count.toString(), + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.0, + color: isActive ? theme.colorScheme.primary : null, + ), + ); + }, + loading: () => (tabCount.hasValue) + ? Text( + tabCount.value.toString(), + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.0, + color: isActive ? theme.colorScheme.primary : null, + ), + ) + : const Skeletonizer(child: Text('00')), + error: (error, stackTrace) { + logger.e( + 'Could not determine tab count', + error: error, + stackTrace: stackTrace, + ); - return Text( - '-1', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.0, - color: isActive ? theme.colorScheme.primary : null, - ), - ); - }, - ), + return Text( + '-1', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.0, + color: isActive ? theme.colorScheme.primary : null, + ), + ); + }, ), ), ), diff --git a/app/lib/presentation/widgets/non_focusable.dart b/app/lib/presentation/widgets/non_focusable.dart deleted file mode 100644 index 8967e591..00000000 --- a/app/lib/presentation/widgets/non_focusable.dart +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2024-2025 Fabian Freund. - * - * This file is part of WebLibre - * (see https://weblibre.eu). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -import 'package:flutter/material.dart'; - -/// A wrapper that prevents a widget from receiving keyboard focus. -/// -/// This fixes the issue where arrow keys on a bluetooth keyboard navigate -/// to toolbar buttons instead of moving the text cursor in input fields. -/// -/// Example: -/// ```dart -/// NonFocusable( -/// child: IconButton( -/// onPressed: () {}, -/// icon: Icon(Icons.menu), -/// ), -/// ) -/// ``` -class NonFocusable extends StatelessWidget { - final Widget child; - - const NonFocusable({required this.child, super.key}); - - @override - Widget build(BuildContext context) { - return Focus(canRequestFocus: false, skipTraversal: true, child: child); - } -}