From dd19618002e738d8ec8ca6c63d164325e06c1875 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Sun, 1 Feb 2026 09:23:33 +0100 Subject: [PATCH] reorganize navigation into drawer; change button placement --- .../domain/providers/tab_state.g.dart | 2 +- .../browser/presentation/screens/browser.dart | 2 + .../browser_modules/app_bar_title.dart | 1 + .../browser_modules/bottom_app_bar.dart | 287 ++------------- .../browser_modules/navigation_drawer.dart | 329 ++++++++++++++++++ 5 files changed, 367 insertions(+), 254 deletions(-) create mode 100644 app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/navigation_drawer.dart diff --git a/app/lib/features/geckoview/domain/providers/tab_state.g.dart b/app/lib/features/geckoview/domain/providers/tab_state.g.dart index d957e5bb..195280c5 100644 --- a/app/lib/features/geckoview/domain/providers/tab_state.g.dart +++ b/app/lib/features/geckoview/domain/providers/tab_state.g.dart @@ -41,7 +41,7 @@ final class TabStatesProvider } } -String _$tabStatesHash() => r'985d2eb87c59c3a113b8bbcf9d96267c42a2f543'; +String _$tabStatesHash() => r'2d18c0c2105ce53bd13e6a6dff1d33c1b531919d'; abstract class _$TabStates extends $Notifier> { Map build(); diff --git a/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart b/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart index 7238ae1b..4a49eb34 100644 --- a/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart +++ b/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart @@ -46,6 +46,7 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_fab.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/browser_modules/draggable_fab.dart'; +import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/browser_modules/navigation_drawer.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/sheets/view_tab.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_view/tab_grid_view.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_view/tab_list_view.dart'; @@ -428,6 +429,7 @@ class BrowserScreen extends HookConsumerWidget { child: Scaffold( // Minimal scaffold - only for Material overlay support (SnackBars) resizeToAvoidBottomInset: false, + drawer: const BrowserNavigationDrawer(), body: Stack( children: [ // Layer 0: Browser content diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/app_bar_title.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/app_bar_title.dart index 4e66eea0..734ebf06 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/app_bar_title.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/app_bar_title.dart @@ -179,6 +179,7 @@ class AppBarTitle extends HookConsumerWidget { ), ), ), + const SizedBox(width: 8.0), ], ); } 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 702f96b6..2e912bb2 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 @@ -18,27 +18,22 @@ * along with this program. If not, see . */ -import 'package:drift/drift.dart' show Value; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:weblibre/core/design/app_colors.dart'; import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/features/geckoview/domain/controllers/bottom_sheet.dart'; import 'package:weblibre/features/geckoview/domain/entities/states/readerable.dart'; -import 'package:weblibre/features/geckoview/domain/providers.dart'; import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart'; import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart'; -import 'package:weblibre/features/geckoview/domain/providers/web_extensions_state.dart'; import 'package:weblibre/features/geckoview/domain/repositories/tab.dart'; import 'package:weblibre/features/geckoview/features/browser/domain/entities/sheet.dart'; import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/controllers/tab_bar_dismissable.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/browser_modules/app_bar_title.dart'; -import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/extension_shortcut_menu.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/menu_item_buttons.dart'; import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/navigation_buttons.dart'; @@ -51,17 +46,12 @@ import 'package:weblibre/features/geckoview/features/readerview/presentation/con import 'package:weblibre/features/geckoview/features/readerview/presentation/widgets/reader_button.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'; import 'package:weblibre/features/geckoview/features/tabs/utils/container_colors.dart'; -import 'package:weblibre/features/tor/domain/services/tor_proxy.dart'; import 'package:weblibre/features/user/data/models/general_settings.dart'; -import 'package:weblibre/features/user/domain/presentation/dialogs/quit_browser_dialog.dart'; -import 'package:weblibre/features/user/domain/providers.dart'; 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/selectable_chips.dart'; import 'package:weblibre/presentation/widgets/url_icon.dart'; -import 'package:weblibre/utils/exit_app.dart'; class BrowserTopAppBar extends HookConsumerWidget { final bool showMainToolbar; @@ -286,11 +276,15 @@ class BrowserTabBar extends HookConsumerWidget { primary: false, automaticallyImplyLeading: false, titleSpacing: 0.0, + leadingWidth: 40.0, toolbarHeight: kToolbarHeight, backgroundColor: (containerColor != null && displayedSheet is! ViewTabsSheet) ? ContainerColors.forAppBar(containerColor) : null, + leading: showMainToolbarNavigationButton + ? NavigationMenuButton(selectedTabId: selectedTabId) + : null, title: (selectedTabId != null && displayedSheet is! ViewTabsSheet) ? const AppBarTitle() @@ -349,6 +343,12 @@ class BrowserTabBar extends HookConsumerWidget { child: const Icon(MdiIcons.puzzle), ), ), + if (showMainToolbarTabsCount) + TabsCountButton( + selectedTabId: selectedTabId, + displayedSheet: displayedSheet, + showLongPressMenu: true, + ), if (selectedTabId != null) TabMenu( controller: trippleDotMenuController, @@ -366,14 +366,6 @@ class BrowserTabBar extends HookConsumerWidget { ); }, ), - if (showMainToolbarTabsCount) - TabsCountButton( - selectedTabId: selectedTabId, - displayedSheet: displayedSheet, - showLongPressMenu: true, - ), - if (showMainToolbarNavigationButton) - NavigationMenuButton(selectedTabId: selectedTabId), ], ), ), @@ -414,6 +406,7 @@ class ContextualToolbar extends HookConsumerWidget { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ + NavigationMenuButton(selectedTabId: selectedTabId), if (tabState?.historyState.canGoBack == true || tabState?.isLoading == true) NavigateBackButton( @@ -439,7 +432,23 @@ class ContextualToolbar extends HookConsumerWidget { displayedSheet: displayedSheet, showLongPressMenu: false, ), - NavigationMenuButton(selectedTabId: selectedTabId), + if (selectedTabId != null) + TabMenu( + controller: useMenuController(), + selectedTabId: selectedTabId!, + builder: (context, controller, child) { + return ToolbarButton( + onTap: () { + if (controller.isOpen) { + controller.close(); + } else { + controller.open(); + } + }, + child: const Icon(MdiIcons.dotsVertical), + ); + }, + ), ], ); } @@ -616,246 +625,18 @@ class ShareMenuButton extends HookConsumerWidget { } } -class NavigationMenuButton extends HookConsumerWidget { +class NavigationMenuButton extends StatelessWidget { final String? selectedTabId; const NavigationMenuButton({super.key, required this.selectedTabId}); @override - Widget build(BuildContext context, WidgetRef ref) { - final addonService = ref.watch(addonServiceProvider); - - final hamburgerMenuController = useMenuController(); - - return MenuAnchor( - controller: hamburgerMenuController, - builder: (context, controller, child) { - return Padding( - padding: const EdgeInsets.only(right: 4.0), - child: InkWell( - onTap: () { - if (controller.isOpen) { - controller.close(); - } else { - controller.open(); - } - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 8.0), - child: Icon(Icons.menu), - ), - ), - ); + Widget build(BuildContext context) { + return ToolbarButton( + onTap: () { + Scaffold.of(context).openDrawer(); }, - menuChildren: [ - MenuItemButton( - onPressed: () async { - await const SelectProfileRoute().push(context); - }, - leadingIcon: const Icon(Icons.person), - child: Consumer( - builder: (context, ref, child) { - final profile = ref.watch(selectedProfileProvider); - return Text(profile.value?.name ?? 'User'); - }, - ), - ), - MenuItemButton( - onPressed: () async { - final result = await showQuitBrowserDialog(context); - - if (result == true && context.mounted) { - await exitApp(ProviderScope.containerOf(context)); - } - }, - leadingIcon: const Icon(MdiIcons.power), - child: const Text('Quit Browser'), - ), - const Divider(), - Consumer( - builder: (context, childRef, child) { - final pageExtensions = childRef.watch( - webExtensionsStateProvider( - WebExtensionActionType.page, - ).select((value) => value.values.toList()), - ); - - return Wrap( - alignment: WrapAlignment.center, - children: [ - ...pageExtensions.map( - (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), - ), - ), - ), - ], - ); - }, - ), - MenuItemButton( - onPressed: () async { - await AboutRoute().push(context); - }, - leadingIcon: const Icon(Icons.info), - child: const Text('About'), - ), - // MenuItemButton( - // onPressed: () async { - // final isPrivate = - // ref - // .read(generalSettingsWithDefaultsProvider) - // .defaultCreateTabType == - // TabType.private; - - // await ref - // .read(tabRepositoryProvider.notifier) - // .addTab( - // url: ref.read(docsUriProvider), - // private: isPrivate, - // container: const Value(null), - // ); - // }, - // leadingIcon: const Icon(Icons.help), - // child: const Text('Help and feedback'), - // ), - const Divider(), - MenuItemButton( - onPressed: () async { - await SettingsRoute().push(context); - }, - leadingIcon: const Icon(Icons.settings), - child: const Text('Settings'), - ), - Consumer( - builder: (context, childRef, child) { - final browserExtensions = childRef.watch( - webExtensionsStateProvider( - WebExtensionActionType.browser, - ).select((value) => value.values.toList()), - ); - - return SubmenuButton( - menuChildren: [ - ...browserExtensions.map( - (extension) => MenuItemButton( - onPressed: () async { - //Use parents .ref because after onPressed this consumer gets disposed already - await addonService.invokeAddonAction( - extension.extensionId, - WebExtensionActionType.browser, - ); - }, - leadingIcon: Padding( - padding: const EdgeInsets.only(top: 4.0), - child: ExtensionBadgeIcon(extension), - ), - child: Text(extension.title ?? ''), - ), - ), - MenuItemButton( - onPressed: () async { - await addonService.startAddonManagerActivity(); - }, - leadingIcon: const Icon(MdiIcons.puzzleEdit), - child: const Text('Manage Extension'), - ), - MenuItemButton( - onPressed: () async { - final isPrivate = - ref - .read(generalSettingsWithDefaultsProvider) - .defaultCreateTabType == - TabType.private; - - await ref - .read(tabRepositoryProvider.notifier) - .addTab( - url: Uri.parse('https://addons.mozilla.org'), - private: isPrivate, - container: const Value(null), - selectTab: true, - ); - }, - leadingIcon: const Icon(MdiIcons.puzzlePlus), - child: const Text('Get Extensions'), - ), - ], - leadingIcon: const Icon(MdiIcons.puzzle), - child: const Text('Extensions'), - ); - }, - ), - MenuItemButton( - onPressed: () async { - await const TorProxyRoute().push(context); - }, - leadingIcon: const Icon(TorIcons.onionAlt), - child: Consumer( - child: const Text('Torâ„¢ Proxy'), - builder: (context, ref, child) { - final torConnected = ref.watch( - torProxyServiceProvider.select( - (value) => value.value?.isRunning == true, - ), - ); - - return Badge( - isLabelVisible: torConnected, - backgroundColor: AppColors.of(context).torActiveGreen, - child: child, - ); - }, - ), - ), - const Divider(), - MenuItemButton( - onPressed: () async { - await const HistoryRoute().push(context); - }, - leadingIcon: const Icon(Icons.history), - child: const Text('History'), - ), - MenuItemButton( - onPressed: () async { - await BookmarkListRoute( - entryGuid: BookmarkRoot.root.id, - ).push(context); - }, - leadingIcon: const Icon(MdiIcons.bookmarkMultiple), - child: const Text('Bookmarks'), - ), - MenuItemButton( - onPressed: () async { - await const BangMenuRoute().push(context); - }, - leadingIcon: const Icon(MdiIcons.exclamationThick), - child: const Text('Bangs'), - ), - MenuItemButton( - onPressed: () async { - await const ContainerListRoute().push(context); - }, - leadingIcon: const Icon(MdiIcons.folder), - child: const Text('Containers'), - ), - MenuItemButton( - onPressed: () async { - await context.push(FeedListRoute().location); - }, - leadingIcon: const Icon(Icons.rss_feed), - child: const Text('Feeds'), - ), - ], + child: const Icon(Icons.menu), ); } } diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/navigation_drawer.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/navigation_drawer.dart new file mode 100644 index 00000000..d0e59756 --- /dev/null +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/navigation_drawer.dart @@ -0,0 +1,329 @@ +/* + * 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:drift/drift.dart' show Value; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; +import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:weblibre/core/design/app_colors.dart'; +import 'package:weblibre/core/routing/routes.dart'; +import 'package:weblibre/features/geckoview/domain/providers.dart'; +import 'package:weblibre/features/geckoview/domain/providers/web_extensions_state.dart'; +import 'package:weblibre/features/geckoview/domain/repositories/tab.dart'; +import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart'; +import 'package:weblibre/features/tor/domain/services/tor_proxy.dart'; +import 'package:weblibre/features/user/domain/presentation/dialogs/quit_browser_dialog.dart'; +import 'package:weblibre/features/user/domain/providers.dart'; +import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; +import 'package:weblibre/presentation/icons/tor_icons.dart'; +import 'package:weblibre/utils/exit_app.dart'; + +/// Navigation drawer for the browser screen. +/// Contains all navigation destinations and settings. +class BrowserNavigationDrawer extends HookConsumerWidget { + const BrowserNavigationDrawer({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final colorScheme = Theme.of(context).colorScheme; + + return NavigationDrawer( + backgroundColor: colorScheme.surface, + children: [ + // Profile Header + _ProfileHeader(), + + const Divider(), + + // Section 1: Tools & Configuration + _ExtensionsSection(), + + ListTile( + leading: const Icon(Icons.settings), + title: const Text('Settings'), + onTap: () async { + Navigator.of(context).pop(); + await SettingsRoute().push(context); + }, + ), + + Consumer( + builder: (context, ref, child) { + final torConnected = ref.watch( + torProxyServiceProvider.select( + (value) => value.value?.isRunning == true, + ), + ); + + return ListTile( + leading: Badge( + isLabelVisible: torConnected, + backgroundColor: AppColors.of(context).torActiveGreen, + child: const Icon(TorIcons.onionAlt), + ), + title: const Text('Torâ„¢ Proxy'), + onTap: () async { + Navigator.of(context).pop(); + await const TorProxyRoute().push(context); + }, + ); + }, + ), + + const Divider(), + + // Section 2: Data & Content + ListTile( + leading: const Icon(Icons.history), + title: const Text('History'), + onTap: () async { + Navigator.of(context).pop(); + await const HistoryRoute().push(context); + }, + ), + + ListTile( + leading: const Icon(MdiIcons.bookmarkMultiple), + title: const Text('Bookmarks'), + onTap: () async { + Navigator.of(context).pop(); + await BookmarkListRoute( + entryGuid: BookmarkRoot.root.id, + ).push(context); + }, + ), + + ListTile( + leading: const Icon(MdiIcons.exclamationThick), + title: const Text('Bangs'), + onTap: () async { + Navigator.of(context).pop(); + await const BangMenuRoute().push(context); + }, + ), + + ListTile( + leading: const Icon(MdiIcons.folder), + title: const Text('Containers'), + onTap: () async { + Navigator.of(context).pop(); + await const ContainerListRoute().push(context); + }, + ), + + ListTile( + leading: const Icon(Icons.rss_feed), + title: const Text('Feeds'), + onTap: () async { + Navigator.of(context).pop(); + await context.push(FeedListRoute().location); + }, + ), + + const Divider(), + + // Section 3: App + ListTile( + leading: const Icon(Icons.info), + title: const Text('About'), + onTap: () async { + Navigator.of(context).pop(); + await AboutRoute().push(context); + }, + ), + + // Quit Browser - styled as destructive action + ListTile( + leading: Icon(MdiIcons.power, color: colorScheme.error), + title: Text( + 'Quit Browser', + style: TextStyle(color: colorScheme.error), + ), + onTap: () async { + final result = await showQuitBrowserDialog(context); + + if (result == true && context.mounted) { + await exitApp(ProviderScope.containerOf(context)); + } + }, + ), + ], + ); + } +} + +/// Profile header widget showing current profile information. +class _ProfileHeader extends ConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = Theme.of(context); + final profile = ref.watch(selectedProfileProvider); + + return InkWell( + onTap: () async { + Navigator.of(context).pop(); // Close drawer + await const SelectProfileRoute().push(context); + }, + child: Container( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 28, + backgroundColor: theme.colorScheme.primaryContainer, + child: Icon( + Icons.person, + size: 28, + color: theme.colorScheme.onPrimaryContainer, + ), + ), + const SizedBox(height: 12), + Text( + profile.value?.name ?? 'User', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 4), + Text( + 'Tap to switch profile', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + ); + } +} + +/// Extensions section with expandable list of installed extensions. +class _ExtensionsSection extends HookConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final addonService = ref.watch(addonServiceProvider); + final pageExtensions = ref.watch( + webExtensionsStateProvider( + WebExtensionActionType.page, + ).select((value) => value.values.toList()), + ); + final browserExtensions = ref.watch( + webExtensionsStateProvider( + WebExtensionActionType.browser, + ).select((value) => value.values.toList()), + ); + + final isExpanded = useState(false); + + return Column( + children: [ + ListTile( + leading: const Icon(MdiIcons.puzzle), + title: const Text('Extensions'), + trailing: Icon( + isExpanded.value ? Icons.expand_less : Icons.expand_more, + ), + onTap: () => isExpanded.value = !isExpanded.value, + ), + if (isExpanded.value) + Padding( + padding: const EdgeInsets.only(left: 16), + child: Column( + children: [ + // Page extensions + if (pageExtensions.isNotEmpty) ...[ + ...pageExtensions.map( + (extension) => ListTile( + leading: ExtensionBadgeIcon(extension), + title: Text(extension.title ?? 'Extension'), + dense: true, + onTap: () async { + Navigator.of(context).pop(); // Close drawer + await addonService.invokeAddonAction( + extension.extensionId, + WebExtensionActionType.page, + ); + }, + ), + ), + const Divider(indent: 16, endIndent: 16), + ], + // Browser extensions + if (browserExtensions.isNotEmpty) ...[ + ...browserExtensions.map( + (extension) => ListTile( + leading: ExtensionBadgeIcon(extension), + title: Text(extension.title ?? 'Extension'), + dense: true, + onTap: () async { + Navigator.of(context).pop(); // Close drawer + await addonService.invokeAddonAction( + extension.extensionId, + WebExtensionActionType.browser, + ); + }, + ), + ), + const Divider(indent: 16, endIndent: 16), + ], + // Management options + ListTile( + leading: const Icon(MdiIcons.puzzleEdit), + title: const Text('Manage Extensions'), + dense: true, + onTap: () async { + Navigator.of(context).pop(); // Close drawer + await addonService.startAddonManagerActivity(); + }, + ), + ListTile( + leading: const Icon(MdiIcons.puzzlePlus), + title: const Text('Get Extensions'), + dense: true, + onTap: () async { + Navigator.of(context).pop(); // Close drawer + final isPrivate = + ref + .read(generalSettingsWithDefaultsProvider) + .defaultCreateTabType == + TabType.private; + + await ref + .read(tabRepositoryProvider.notifier) + .addTab( + url: Uri.parse('https://addons.mozilla.org'), + private: isPrivate, + container: const Value(null), + selectTab: true, + ); + }, + ), + ], + ), + ), + ], + ); + } +}