+17
-52
@@ -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,7 +325,6 @@ class BrowserTabBar extends HookConsumerWidget {
|
||||
|
||||
return Visibility(
|
||||
visible: tabBarReaderView || readerabilityStateActive,
|
||||
child: NonFocusable(
|
||||
child: ReaderButton(
|
||||
buttonBuilder: (isLoading, readerActive, icon) =>
|
||||
InkWell(
|
||||
@@ -338,9 +336,7 @@ class BrowserTabBar extends HookConsumerWidget {
|
||||
readerableScreenControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.toggleReaderView(
|
||||
!readerActive,
|
||||
);
|
||||
.toggleReaderView(!readerActive);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
@@ -351,13 +347,11 @@ class BrowserTabBar extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
if (showExtensionShortcut)
|
||||
NonFocusable(
|
||||
child: ExtensionShortcutMenu(
|
||||
ExtensionShortcutMenu(
|
||||
controller: extensionMenuController,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
@@ -370,10 +364,8 @@ class BrowserTabBar extends HookConsumerWidget {
|
||||
icon: const Icon(MdiIcons.puzzle),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (selectedTabId != null)
|
||||
NonFocusable(
|
||||
child: TabMenu(
|
||||
TabMenu(
|
||||
controller: trippleDotMenuController,
|
||||
selectedTabId: selectedTabId,
|
||||
builder: (context, controller, child) {
|
||||
@@ -395,22 +387,17 @@ class BrowserTabBar extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (showMainToolbarTabsCount)
|
||||
NonFocusable(
|
||||
child: TabsCountButton(
|
||||
TabsCountButton(
|
||||
selectedTabId: selectedTabId,
|
||||
displayedSheet: displayedSheet,
|
||||
showLongPressMenu: true,
|
||||
),
|
||||
),
|
||||
if (showMainToolbarNavigationButton)
|
||||
NonFocusable(
|
||||
child: NavigationMenuButton(
|
||||
NavigationMenuButton(
|
||||
selectedTabId: selectedTabId,
|
||||
showNavigationButtons: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -453,15 +440,12 @@ class ContextualToolbar extends HookConsumerWidget {
|
||||
children: [
|
||||
if (tabState?.historyState.canGoBack == true ||
|
||||
tabState?.isLoading == true)
|
||||
NonFocusable(
|
||||
child: NavigateBackButton(
|
||||
NavigateBackButton(
|
||||
selectedTabId: selectedTabId,
|
||||
isLoading: tabState?.isLoading ?? false,
|
||||
),
|
||||
)
|
||||
else
|
||||
NonFocusable(
|
||||
child: IconButton(
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
await BookmarkListRoute(
|
||||
entryGuid: BookmarkRoot.root.id,
|
||||
@@ -469,27 +453,20 @@ class ContextualToolbar extends HookConsumerWidget {
|
||||
},
|
||||
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(
|
||||
ShareMenuButton(selectedTabId: selectedTabId),
|
||||
const AddTabButton(),
|
||||
TabsCountButton(
|
||||
selectedTabId: selectedTabId,
|
||||
displayedSheet: displayedSheet,
|
||||
showLongPressMenu: false,
|
||||
),
|
||||
),
|
||||
NonFocusable(
|
||||
child: NavigationMenuButton(
|
||||
NavigationMenuButton(
|
||||
selectedTabId: selectedTabId,
|
||||
showNavigationButtons: false,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -651,8 +628,7 @@ class ShareMenuButton extends HookConsumerWidget {
|
||||
ShowQrCodeMenuItemButton(selectedTabId: selectedTabId),
|
||||
],
|
||||
builder: (context, controller, child) {
|
||||
return NonFocusable(
|
||||
child: IconButton(
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
if (controller.isOpen) {
|
||||
controller.close();
|
||||
@@ -661,7 +637,6 @@ class ShareMenuButton extends HookConsumerWidget {
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.share),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -730,8 +705,7 @@ class NavigationMenuButton extends HookConsumerWidget {
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
...pageExtensions.map(
|
||||
(extension) => NonFocusable(
|
||||
child: IconButton(
|
||||
(extension) => IconButton(
|
||||
onPressed: () async {
|
||||
//Use parents .ref because after onPressed this consumer gets disposed already
|
||||
await addonService.invokeAddonAction(
|
||||
@@ -745,7 +719,6 @@ class NavigationMenuButton extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -974,8 +947,7 @@ class NavigateForwardButton extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return NonFocusable(
|
||||
child: IconButton(
|
||||
return IconButton(
|
||||
onPressed: canGoForward
|
||||
? () async {
|
||||
final controller = ref.read(
|
||||
@@ -987,7 +959,6 @@ class NavigateForwardButton extends HookConsumerWidget {
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.arrow_forward),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1008,8 +979,7 @@ class NavigateBackButton extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return NonFocusable(
|
||||
child: IconButton(
|
||||
return IconButton(
|
||||
onPressed: (canGoBack || isLoading)
|
||||
? () async {
|
||||
final controller = ref.read(
|
||||
@@ -1035,10 +1005,7 @@ class NavigateBackButton extends HookConsumerWidget {
|
||||
menuControllerToClose?.close();
|
||||
}
|
||||
: null,
|
||||
icon: isLoading
|
||||
? const Icon(Icons.close)
|
||||
: const Icon(Icons.arrow_back),
|
||||
),
|
||||
icon: isLoading ? const Icon(Icons.close) : const Icon(Icons.arrow_back),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1052,7 +1019,6 @@ class AddTabButton extends HookConsumerWidget {
|
||||
|
||||
return TabCreationMenu(
|
||||
controller: tabMenuController,
|
||||
child: NonFocusable(
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
final settings = ref.read(generalSettingsWithDefaultsProvider);
|
||||
@@ -1076,7 +1042,6 @@ class AddTabButton extends HookConsumerWidget {
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-10
@@ -152,7 +152,6 @@ class GridTabPreview extends HookConsumerWidget {
|
||||
child: Text('Close all from ${tabState.url.host}'),
|
||||
),
|
||||
],
|
||||
child: NonFocusable(
|
||||
child: IconButton(
|
||||
visualDensity: const VisualDensity(
|
||||
horizontal: -4.0,
|
||||
@@ -171,7 +170,6 @@ class GridTabPreview extends HookConsumerWidget {
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
),
|
||||
),
|
||||
?trailingChild,
|
||||
],
|
||||
),
|
||||
@@ -352,7 +350,6 @@ class ListTabPreview extends HookConsumerWidget {
|
||||
child: Text('Close all from ${tabState.url.host}'),
|
||||
),
|
||||
],
|
||||
child: NonFocusable(
|
||||
child: IconButton(
|
||||
onPressed: onDelete,
|
||||
onLongPress: onDeleteAll != null
|
||||
@@ -367,7 +364,6 @@ class ListTabPreview extends HookConsumerWidget {
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
),
|
||||
),
|
||||
?trailingChild,
|
||||
],
|
||||
),
|
||||
@@ -631,14 +627,12 @@ class SuggestedSingleGridTabPreview extends StatelessWidget {
|
||||
tabId: tabId,
|
||||
isActive: tabId == activeTabId,
|
||||
onTap: onTap,
|
||||
trailingChild: const NonFocusable(
|
||||
child: IconButton(
|
||||
trailingChild: const IconButton(
|
||||
visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0),
|
||||
icon: Icon(MdiIcons.creation),
|
||||
onPressed: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -665,14 +659,12 @@ class SuggestedSingleListTabPreview extends StatelessWidget {
|
||||
tabId: tabId,
|
||||
isActive: tabId == activeTabId,
|
||||
onTap: onTap,
|
||||
trailingChild: const NonFocusable(
|
||||
child: IconButton(
|
||||
trailingChild: const IconButton(
|
||||
visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0),
|
||||
icon: Icon(MdiIcons.creation),
|
||||
onPressed: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-16
@@ -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,16 +82,13 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
NonFocusable(
|
||||
child: IconButton(
|
||||
IconButton(
|
||||
icon: const Icon(MdiIcons.tabSearch),
|
||||
iconSize: 18,
|
||||
padding: EdgeInsets.zero,
|
||||
tooltip: 'Search inside tabs',
|
||||
onPressed: () {
|
||||
switch (ref.read(
|
||||
tabsViewModeControllerProvider,
|
||||
)) {
|
||||
switch (ref.read(tabsViewModeControllerProvider)) {
|
||||
case TabsViewMode.tree:
|
||||
case TabsViewMode.list:
|
||||
break;
|
||||
@@ -108,7 +104,6 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
searchTextFocus.requestFocus();
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 32,
|
||||
child: VerticalDivider(indent: 4, endIndent: 4),
|
||||
@@ -131,7 +126,6 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
child: NonFocusable(
|
||||
child: IconButton(
|
||||
tooltip: 'Change view mode',
|
||||
onPressed: () {
|
||||
@@ -150,7 +144,6 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (enableAiFeatures &&
|
||||
switch (tabsViewMode) {
|
||||
TabsViewMode.list || TabsViewMode.grid => true,
|
||||
@@ -174,7 +167,6 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
style: const TextStyle(fontSize: 10),
|
||||
)
|
||||
: null,
|
||||
child: NonFocusable(
|
||||
child: IconButton.filledTonal(
|
||||
icon: const Icon(MdiIcons.imageAutoAdjust),
|
||||
isSelected: tabSuggestionsEnabled,
|
||||
@@ -210,7 +202,6 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -513,7 +504,6 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
],
|
||||
child: NonFocusable(
|
||||
child: IconButton(
|
||||
tooltip: 'Tab actions',
|
||||
onPressed: () {
|
||||
@@ -526,7 +516,6 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
icon: const Icon(MdiIcons.dotsVertical),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
else
|
||||
@@ -548,8 +537,7 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
searchTextController.text = data;
|
||||
},
|
||||
),
|
||||
NonFocusable(
|
||||
child: IconButton(
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
searchTextController.clear();
|
||||
searchTextFocus.requestFocus();
|
||||
@@ -557,7 +545,6 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
},
|
||||
icon: const Icon(Icons.clear),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
+1
-4
@@ -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,8 +56,7 @@ class TabsActionButton extends HookConsumerWidget {
|
||||
selectedContainerDataProvider.select((value) => value.value?.color),
|
||||
);
|
||||
|
||||
return NonFocusable(
|
||||
child: InkWell(
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
onDoubleTap: onDoubleTap,
|
||||
onLongPress: onLongPress,
|
||||
@@ -119,7 +117,6 @@ class TabsActionButton extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user