setting to hide container and isolated tab ui

This commit is contained in:
Fabian Freund
2026-02-27 18:23:33 +01:00
parent 60838b446d
commit 3d1293b352
36 changed files with 611 additions and 292 deletions
+44
View File
@@ -116,9 +116,25 @@ class SearchRoute extends GoRouteData with $SearchRoute {
} }
} }
bool _isContainerUiEnabled(BuildContext context) {
final settings = ProviderScope.containerOf(
context,
listen: false,
).read(generalSettingsWithDefaultsProvider);
return settings.showContainerUi;
}
class ContainerDraftRoute extends GoRouteData with $ContainerDraftRoute { class ContainerDraftRoute extends GoRouteData with $ContainerDraftRoute {
const ContainerDraftRoute(); const ContainerDraftRoute();
@override
String? redirect(BuildContext context, GoRouterState state) {
return _isContainerUiEnabled(context)
? null
: const BrowserRoute().location;
}
@override @override
Widget build(BuildContext context, GoRouterState state) { Widget build(BuildContext context, GoRouterState state) {
return const ContainerDraftSuggestionsScreen(); return const ContainerDraftSuggestionsScreen();
@@ -128,6 +144,13 @@ class ContainerDraftRoute extends GoRouteData with $ContainerDraftRoute {
class ContainerListRoute extends GoRouteData with $ContainerListRoute { class ContainerListRoute extends GoRouteData with $ContainerListRoute {
const ContainerListRoute(); const ContainerListRoute();
@override
String? redirect(BuildContext context, GoRouterState state) {
return _isContainerUiEnabled(context)
? null
: const BrowserRoute().location;
}
@override @override
Widget build(BuildContext context, GoRouterState state) { Widget build(BuildContext context, GoRouterState state) {
return const ContainerListScreen(); return const ContainerListScreen();
@@ -138,6 +161,13 @@ class ContainerSelectionRoute extends GoRouteData
with $ContainerSelectionRoute { with $ContainerSelectionRoute {
const ContainerSelectionRoute(); const ContainerSelectionRoute();
@override
String? redirect(BuildContext context, GoRouterState state) {
return _isContainerUiEnabled(context)
? null
: const BrowserRoute().location;
}
@override @override
Widget build(BuildContext context, GoRouterState state) { Widget build(BuildContext context, GoRouterState state) {
return const ContainerSelectionScreen(); return const ContainerSelectionScreen();
@@ -149,6 +179,13 @@ class ContainerEditRoute extends GoRouteData with $ContainerEditRoute {
const ContainerEditRoute({required this.containerData}); const ContainerEditRoute({required this.containerData});
@override
String? redirect(BuildContext context, GoRouterState state) {
return _isContainerUiEnabled(context)
? null
: const BrowserRoute().location;
}
@override @override
Widget build(BuildContext context, GoRouterState state) { Widget build(BuildContext context, GoRouterState state) {
return ContainerEditScreen.edit( return ContainerEditScreen.edit(
@@ -165,6 +202,13 @@ class ContainerCreateRoute extends GoRouteData with $ContainerCreateRoute {
ContainerCreateRoute({required this.containerData, this.tabIds = '[]'}); ContainerCreateRoute({required this.containerData, this.tabIds = '[]'});
@override
String? redirect(BuildContext context, GoRouterState state) {
return _isContainerUiEnabled(context)
? null
: const BrowserRoute().location;
}
@override @override
Widget build(BuildContext context, GoRouterState state) { Widget build(BuildContext context, GoRouterState state) {
final tabIdsList = jsonDecode(tabIds) as List; final tabIdsList = jsonDecode(tabIds) as List;
+2
View File
@@ -23,6 +23,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:nullability/nullability.dart'; import 'package:nullability/nullability.dart';
import 'package:weblibre/core/routing/widgets/bottom_sheet_page.dart'; import 'package:weblibre/core/routing/widgets/bottom_sheet_page.dart';
import 'package:weblibre/core/routing/widgets/dialog_page.dart'; import 'package:weblibre/core/routing/widgets/dialog_page.dart';
@@ -82,6 +83,7 @@ import 'package:weblibre/features/user/domain/presentation/screens/profile_edit.
import 'package:weblibre/features/user/domain/presentation/screens/profile_list.dart'; import 'package:weblibre/features/user/domain/presentation/screens/profile_list.dart';
import 'package:weblibre/features/user/domain/presentation/screens/profile_restore.dart'; import 'package:weblibre/features/user/domain/presentation/screens/profile_restore.dart';
import 'package:weblibre/features/user/domain/presentation/widgets/auth_gate.dart'; import 'package:weblibre/features/user/domain/presentation/widgets/auth_gate.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
import 'package:weblibre/features/web_feed/presentation/add_feed_dialog.dart'; import 'package:weblibre/features/web_feed/presentation/add_feed_dialog.dart';
import 'package:weblibre/features/web_feed/presentation/screens/feed_article.dart'; import 'package:weblibre/features/web_feed/presentation/screens/feed_article.dart';
import 'package:weblibre/features/web_feed/presentation/screens/feed_article_list.dart'; import 'package:weblibre/features/web_feed/presentation/screens/feed_article_list.dart';
@@ -69,7 +69,7 @@ class BangCategoryScreen extends HookConsumerWidget {
SearchRoute( SearchRoute(
tabType: tabType:
ref.read(selectedTabTypeProvider) ?? ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType, settings.effectiveDefaultCreateTabType,
).go(context); ).go(context);
}, },
); );
@@ -92,7 +92,7 @@ class BangDetails extends HookConsumerWidget {
final tabMode = TabMode.fromTabType( final tabMode = TabMode.fromTabType(
ref ref
.read(generalSettingsWithDefaultsProvider) .read(generalSettingsWithDefaultsProvider)
.defaultCreateTabType, .effectiveDefaultCreateTabType,
); );
await ref await ref
@@ -54,7 +54,8 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
final selectedTabType = selectedTabState?.tabMode.toTabType(); final selectedTabType = selectedTabState?.tabMode.toTabType();
final route = SearchRoute( final route = SearchRoute(
tabType: selectedTabType ?? settings.defaultCreateTabType, tabType:
selectedTabType ?? settings.effectiveDefaultCreateTabType,
searchText: text, searchText: text,
); );
@@ -78,7 +79,7 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
TabMode.fromTabType( TabMode.fromTabType(
ref ref
.read(generalSettingsWithDefaultsProvider) .read(generalSettingsWithDefaultsProvider)
.defaultCreateTabType, .effectiveDefaultCreateTabType,
); );
await ref await ref
@@ -55,7 +55,7 @@ final class SelectionActionServiceProvider
} }
String _$selectionActionServiceHash() => String _$selectionActionServiceHash() =>
r'4ba617f9edb4c2ba1cb5d9e4bbc4e5eec6feecba'; r'5faf8c13c414406dfc2eb55fdd372677dbccdf8c';
@ProviderFor(eventService) @ProviderFor(eventService)
final eventServiceProvider = EventServiceProvider._(); final eventServiceProvider = EventServiceProvider._();
@@ -216,9 +216,14 @@ EquatableValue<List<TabStateWirthContainer>> quickTabSwitcherTabStates(
Ref ref, Ref ref,
QuickTabSwitcherMode mode, QuickTabSwitcherMode mode,
) { ) {
final effectiveMode = ref.watch(
generalSettingsWithDefaultsProvider.select(
(settings) => settings.effectiveUiQuickTabSwitcherMode(),
),
);
final selectedTabId = ref.watch(selectedTabProvider); final selectedTabId = ref.watch(selectedTabProvider);
final tabStates = switch (mode) { final tabStates = switch (effectiveMode) {
QuickTabSwitcherMode.lastUsedTabs => ref.watch(fifoTabStatesProvider).value, QuickTabSwitcherMode.lastUsedTabs => ref.watch(fifoTabStatesProvider).value,
QuickTabSwitcherMode.containerTabs => QuickTabSwitcherMode.containerTabs =>
ref.watch(selectedContainerTabStatesWithContainerProvider).value, ref.watch(selectedContainerTabStatesWithContainerProvider).value,
@@ -234,6 +239,11 @@ Future<List<VisitInfo>> quickTabSwitcherHistorySuggestions(
Ref ref, Ref ref,
QuickTabSwitcherMode mode, QuickTabSwitcherMode mode,
) async { ) async {
final effectiveMode = ref.watch(
generalSettingsWithDefaultsProvider.select(
(settings) => settings.effectiveUiQuickTabSwitcherMode(),
),
);
final showHistorySuggestions = ref.watch( final showHistorySuggestions = ref.watch(
generalSettingsWithDefaultsProvider.select( generalSettingsWithDefaultsProvider.select(
(settings) => settings.quickTabSwitcherShowHistorySuggestions, (settings) => settings.quickTabSwitcherShowHistorySuggestions,
@@ -246,7 +256,7 @@ Future<List<VisitInfo>> quickTabSwitcherHistorySuggestions(
final hasTabStates = ref.watch( final hasTabStates = ref.watch(
quickTabSwitcherTabStatesProvider( quickTabSwitcherTabStatesProvider(
mode, effectiveMode,
).select((value) => value.value.isNotEmpty), ).select((value) => value.value.isNotEmpty),
); );
if (hasTabStates) { if (hasTabStates) {
@@ -263,6 +273,11 @@ AsyncValue<bool> quickTabSwitcherHasResults(
Ref ref, Ref ref,
QuickTabSwitcherMode mode, QuickTabSwitcherMode mode,
) { ) {
final effectiveMode = ref.watch(
generalSettingsWithDefaultsProvider.select(
(settings) => settings.effectiveUiQuickTabSwitcherMode(),
),
);
final showQuickTabSwitcherBar = ref.watch( final showQuickTabSwitcherBar = ref.watch(
generalSettingsWithDefaultsProvider.select( generalSettingsWithDefaultsProvider.select(
(settings) => settings.tabBarShowQuickTabSwitcherBar, (settings) => settings.tabBarShowQuickTabSwitcherBar,
@@ -274,7 +289,7 @@ AsyncValue<bool> quickTabSwitcherHasResults(
final hasResults = ref.watch( final hasResults = ref.watch(
quickTabSwitcherTabStatesProvider( quickTabSwitcherTabStatesProvider(
mode, effectiveMode,
).select((value) => value.value.isNotEmpty), ).select((value) => value.value.isNotEmpty),
); );
@@ -283,7 +298,7 @@ AsyncValue<bool> quickTabSwitcherHasResults(
} }
return ref return ref
.watch(quickTabSwitcherHistorySuggestionsProvider(mode)) .watch(quickTabSwitcherHistorySuggestionsProvider(effectiveMode))
.whenData((visits) => visits.isNotEmpty); .whenData((visits) => visits.isNotEmpty);
} }
@@ -559,7 +559,7 @@ final class QuickTabSwitcherTabStatesProvider
} }
String _$quickTabSwitcherTabStatesHash() => String _$quickTabSwitcherTabStatesHash() =>
r'db82bf9e338c94768b0531aeaffb152ff726f81f'; r'df990fb96cca62a272572c925028725f81a0e96b';
final class QuickTabSwitcherTabStatesFamily extends $Family final class QuickTabSwitcherTabStatesFamily extends $Family
with with
@@ -642,7 +642,7 @@ final class QuickTabSwitcherHistorySuggestionsProvider
} }
String _$quickTabSwitcherHistorySuggestionsHash() => String _$quickTabSwitcherHistorySuggestionsHash() =>
r'3446741dfedf6fda9ab61421c1b74370c7f43f5b'; r'2e689ce72aac6b5b5b41e0390b168b3fdf5d4251';
final class QuickTabSwitcherHistorySuggestionsFamily extends $Family final class QuickTabSwitcherHistorySuggestionsFamily extends $Family
with with
@@ -730,7 +730,7 @@ final class QuickTabSwitcherHasResultsProvider
} }
String _$quickTabSwitcherHasResultsHash() => String _$quickTabSwitcherHasResultsHash() =>
r'bcbddfefe7f5eb2c5d8c7c1925fe593a857b477b'; r'5c488c9933372350c9e87ca1b83145176823dc88';
final class QuickTabSwitcherHasResultsFamily extends $Family final class QuickTabSwitcherHasResultsFamily extends $Family
with $FunctionalFamilyOverride<AsyncValue<bool>, QuickTabSwitcherMode> { with $FunctionalFamilyOverride<AsyncValue<bool>, QuickTabSwitcherMode> {
@@ -277,7 +277,7 @@ class BrowserScreen extends HookConsumerWidget {
); );
final quickTabSwitcherMode = ref.watch( final quickTabSwitcherMode = ref.watch(
generalSettingsWithDefaultsProvider.select( generalSettingsWithDefaultsProvider.select(
(value) => value.quickTabSwitcherMode, (value) => value.effectiveUiQuickTabSwitcherMode(),
), ),
); );
final quickTabSwitcherHasResults = ref.watch( final quickTabSwitcherHasResults = ref.watch(
@@ -103,7 +103,7 @@ class TabViewScreen extends HookConsumerWidget {
await SearchRoute( await SearchRoute(
tabType: tabType:
ref.read(selectedTabTypeProvider) ?? ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType, settings.effectiveDefaultCreateTabType,
).push(context); ).push(context);
if (context.mounted) { if (context.mounted) {
@@ -194,6 +194,7 @@ class BrowserTabBar extends HookConsumerWidget {
final trippleDotMenuController = useMenuController(); final trippleDotMenuController = useMenuController();
final selectedTabId = ref.watch(selectedTabProvider); final selectedTabId = ref.watch(selectedTabProvider);
final settings = ref.watch(generalSettingsWithDefaultsProvider);
final containerColor = ref.watch( final containerColor = ref.watch(
watchTabContainerDataProvider( watchTabContainerDataProvider(
@@ -201,23 +202,10 @@ class BrowserTabBar extends HookConsumerWidget {
).select((data) => data.value?.color), ).select((data) => data.value?.color),
); );
final showExtensionShortcut = ref.watch( final showExtensionShortcut = settings.showExtensionShortcut;
generalSettingsWithDefaultsProvider.select( final quickTabSwitcherMode = settings.effectiveUiQuickTabSwitcherMode();
(value) => value.showExtensionShortcut,
),
);
final quickTabSwitcherMode = ref.watch( final tabBarPosition = settings.tabBarPosition;
generalSettingsWithDefaultsProvider.select(
(value) => value.quickTabSwitcherMode,
),
);
final tabBarPosition = ref.watch(
generalSettingsWithDefaultsProvider.select(
(value) => value.tabBarPosition,
),
);
final dragStartPosition = useRef(Offset.zero); final dragStartPosition = useRef(Offset.zero);
@@ -300,7 +288,9 @@ class BrowserTabBar extends HookConsumerWidget {
leadingWidth: 40.0, leadingWidth: 40.0,
toolbarHeight: kToolbarHeight, toolbarHeight: kToolbarHeight,
backgroundColor: backgroundColor:
(containerColor != null && displayedSheet is! ViewTabsSheet) (settings.showContainerUi &&
containerColor != null &&
displayedSheet is! ViewTabsSheet)
? ContainerColors.forAppBar(containerColor) ? ContainerColors.forAppBar(containerColor)
: null, : null,
leading: showMainToolbarNavigationButton leading: showMainToolbarNavigationButton
@@ -485,6 +475,9 @@ class QuickTabSwitcher extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final appColors = AppColors.of(context); final appColors = AppColors.of(context);
final showIsolatedTabUi = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.showIsolatedTabUi),
);
final showTitles = ref.watch( final showTitles = ref.watch(
generalSettingsWithDefaultsProvider.select( generalSettingsWithDefaultsProvider.select(
(s) => s.quickTabSwitcherShowTitles, (s) => s.quickTabSwitcherShowTitles,
@@ -556,7 +549,7 @@ class QuickTabSwitcher extends HookConsumerWidget {
constraints: const BoxConstraints(maxWidth: 64), constraints: const BoxConstraints(maxWidth: 64),
child: Text(item.title), child: Text(item.title),
), ),
if (item.tabMode is IsolatedTabMode) if (showIsolatedTabUi && item.tabMode is IsolatedTabMode)
Padding( Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Icon( child: Icon(
@@ -710,7 +703,7 @@ class AddTabButton extends HookConsumerWidget {
await SearchRoute( await SearchRoute(
tabType: tabType:
ref.read(selectedTabTypeProvider) ?? ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType, settings.effectiveDefaultCreateTabType,
).push(context); ).push(context);
if (context.mounted) { if (context.mounted) {
@@ -240,7 +240,7 @@ class _BrowserViewState extends ConsumerState<BrowserView>
final route = SearchRoute( final route = SearchRoute(
tabType: tabType:
ref.read(selectedTabTypeProvider) ?? ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType, settings.effectiveDefaultCreateTabType,
searchText: sharedContent.text, searchText: sharedContent.text,
launchedFromIntent: true, //launched from intent launchedFromIntent: true, //launched from intent
); );
@@ -334,6 +334,13 @@ class _BrowserViewState extends ConsumerState<BrowserView>
await router.push(route.location); await router.push(route.location);
} else if (type == 'new_isolated_tab') { } else if (type == 'new_isolated_tab') {
final settings = ref.read(
generalSettingsWithDefaultsProvider,
);
if (!settings.showIsolatedTabUi) {
return;
}
lastAction = DateTime.now(); lastAction = DateTime.now();
final router = await ref.read(routerProvider.future); final router = await ref.read(routerProvider.future);
@@ -348,6 +355,9 @@ class _BrowserViewState extends ConsumerState<BrowserView>
} }
}); });
final settings = ref.read(
generalSettingsWithDefaultsProvider,
);
await quickActions.setShortcutItems([ await quickActions.setShortcutItems([
//TODO: add icons //TODO: add icons
const ShortcutItem( const ShortcutItem(
@@ -358,6 +368,7 @@ class _BrowserViewState extends ConsumerState<BrowserView>
type: 'new_private_tab', type: 'new_private_tab',
localizedTitle: 'New Private Tab', localizedTitle: 'New Private Tab',
), ),
if (settings.showIsolatedTabUi)
const ShortcutItem( const ShortcutItem(
type: 'new_isolated_tab', type: 'new_isolated_tab',
localizedTitle: 'New Isolated Tab', localizedTitle: 'New Isolated Tab',
@@ -592,7 +603,7 @@ class _BrowserViewState extends ConsumerState<BrowserView>
await SearchRoute( await SearchRoute(
tabType: tabType:
ref.read(selectedTabTypeProvider) ?? ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType, settings.effectiveDefaultCreateTabType,
searchText: searchText ?? SearchRoute.emptySearchText, searchText: searchText ?? SearchRoute.emptySearchText,
).push(context); ).push(context);
}, },
@@ -52,6 +52,9 @@ class BrowserNavigationDrawer extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
final showContainerUi = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.showContainerUi),
);
return NavigationDrawer( return NavigationDrawer(
backgroundColor: colorScheme.surface, backgroundColor: colorScheme.surface,
@@ -137,6 +140,7 @@ class BrowserNavigationDrawer extends HookConsumerWidget {
}, },
), ),
if (showContainerUi)
ListTile( ListTile(
leading: const Icon(MdiIcons.folder), leading: const Icon(MdiIcons.folder),
title: const Text('Containers'), title: const Text('Containers'),
@@ -322,7 +326,7 @@ class _ExtensionsSection extends HookConsumerWidget {
final tabMode = TabMode.fromTabType( final tabMode = TabMode.fromTabType(
ref ref
.read(generalSettingsWithDefaultsProvider) .read(generalSettingsWithDefaultsProvider)
.defaultCreateTabType, .effectiveDefaultCreateTabType,
); );
await ref await ref
@@ -42,6 +42,11 @@ class TabCreationMenu extends HookConsumerWidget {
(value) => value.createChildTabsOption, (value) => value.createChildTabsOption,
), ),
); );
final showIsolatedTabUi = ref.watch(
generalSettingsWithDefaultsProvider.select(
(value) => value.showIsolatedTabUi,
),
);
return MenuAnchor( return MenuAnchor(
controller: controller, controller: controller,
@@ -63,6 +68,7 @@ class TabCreationMenu extends HookConsumerWidget {
leadingIcon: const Icon(WebLibreIcons.privateTab), leadingIcon: const Icon(WebLibreIcons.privateTab),
child: const Text('Add Private Tab'), child: const Text('Add Private Tab'),
), ),
if (showIsolatedTabUi)
MenuItemButton( MenuItemButton(
onPressed: () async { onPressed: () async {
await const SearchRoute(tabType: TabType.isolated).push(context); await const SearchRoute(tabType: TabType.isolated).push(context);
@@ -48,6 +48,7 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/entities/contai
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart';
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
import 'package:weblibre/presentation/hooks/menu_controller.dart'; import 'package:weblibre/presentation/hooks/menu_controller.dart';
import 'package:weblibre/presentation/icons/weblibre_icons.dart'; import 'package:weblibre/presentation/icons/weblibre_icons.dart';
import 'package:weblibre/presentation/widgets/website_feed_menu_button.dart'; import 'package:weblibre/presentation/widgets/website_feed_menu_button.dart';
@@ -94,6 +95,7 @@ class TabMenu extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final showFeeds = useState(false); final showFeeds = useState(false);
final settings = ref.watch(generalSettingsWithDefaultsProvider);
final controller = this.controller ?? useMenuController(); final controller = this.controller ?? useMenuController();
@@ -313,6 +315,7 @@ class TabMenu extends HookConsumerWidget {
} }
}, },
), ),
if (settings.showIsolatedTabUi)
MenuItemButton( MenuItemButton(
leadingIcon: Icon( leadingIcon: Icon(
MdiIcons.shieldLock, MdiIcons.shieldLock,
@@ -352,7 +355,7 @@ class TabMenu extends HookConsumerWidget {
leadingIcon: const Icon(MdiIcons.tabPlus), leadingIcon: const Icon(MdiIcons.tabPlus),
child: const Text('Clone Tab'), child: const Text('Clone Tab'),
), ),
if (enableContainer) if (enableContainer && settings.showContainerUi)
SubmenuButton( SubmenuButton(
menuChildren: [ menuChildren: [
MenuItemButton( MenuItemButton(
@@ -577,7 +577,7 @@ class ViewTabGridWidget extends HookConsumerWidget {
await SearchRoute( await SearchRoute(
tabType: tabType:
ref.read(selectedTabTypeProvider) ?? ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType, settings.effectiveDefaultCreateTabType,
).push(context); ).push(context);
onClose(); onClose();
@@ -606,7 +606,7 @@ class ViewTabListWidget extends HookConsumerWidget {
await SearchRoute( await SearchRoute(
tabType: tabType:
ref.read(selectedTabTypeProvider) ?? ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType, settings.effectiveDefaultCreateTabType,
).push(context); ).push(context);
onClose(); onClose();
@@ -345,7 +345,7 @@ class ViewTabTreesWidget extends HookConsumerWidget {
await SearchRoute( await SearchRoute(
tabType: tabType:
ref.read(selectedTabTypeProvider) ?? ref.read(selectedTabTypeProvider) ??
settings.defaultCreateTabType, settings.effectiveDefaultCreateTabType,
).push(context); ).push(context);
onClose(); onClose();
@@ -230,6 +230,16 @@ class TabViewHeader extends HookConsumerWidget {
(settings) => settings.enableLocalAiFeatures, (settings) => settings.enableLocalAiFeatures,
), ),
); );
final showContainerUi = ref.watch(
generalSettingsWithDefaultsProvider.select(
(settings) => settings.showContainerUi,
),
);
final showIsolatedTabUi = ref.watch(
generalSettingsWithDefaultsProvider.select(
(settings) => settings.showIsolatedTabUi,
),
);
final selectedContainerId = ref.watch(selectedContainerProvider); final selectedContainerId = ref.watch(selectedContainerProvider);
final isSyncedScope = ref.watch( final isSyncedScope = ref.watch(
@@ -503,6 +513,7 @@ class TabViewHeader extends HookConsumerWidget {
}, },
child: const Text('Close Private Tabs'), child: const Text('Close Private Tabs'),
), ),
if (showIsolatedTabUi)
MenuItemButton( MenuItemButton(
leadingIcon: Icon( leadingIcon: Icon(
MdiIcons.shieldLock, MdiIcons.shieldLock,
@@ -512,7 +523,9 @@ class TabViewHeader extends HookConsumerWidget {
? null ? null
: () async { : () async {
// Count distinct isolation groups that will be destroyed // Count distinct isolation groups that will be destroyed
final allStates = ref.read(tabStatesProvider); final allStates = ref.read(
tabStatesProvider,
);
final isolatedContextIds = allStates.values final isolatedContextIds = allStates.values
.where( .where(
(s) => (s) =>
@@ -527,13 +540,16 @@ class TabViewHeader extends HookConsumerWidget {
final confirmed = await ui_helper final confirmed = await ui_helper
.confirmIsolatedTabClose( .confirmIsolatedTabClose(
context, context,
groupCount: isolatedContextIds.length, groupCount:
isolatedContextIds.length,
); );
if (!confirmed) return; if (!confirmed) return;
} }
final count = await ref final count = await ref
.read(tabDataRepositoryProvider.notifier) .read(
tabDataRepositoryProvider.notifier,
)
.closeContainerTabs( .closeContainerTabs(
selectedContainerId, selectedContainerId,
includeRegular: false, includeRegular: false,
@@ -544,7 +560,9 @@ class TabViewHeader extends HookConsumerWidget {
ui_helper.showTabUndoClose( ui_helper.showTabUndoClose(
context, context,
ref ref
.read(tabRepositoryProvider.notifier) .read(
tabRepositoryProvider.notifier,
)
.undoClose, .undoClose,
count: count.length, count: count.length,
); );
@@ -809,6 +827,7 @@ class TabViewHeader extends HookConsumerWidget {
), ),
), ),
), ),
if (showContainerUi)
Consumer( Consumer(
builder: (context, ref, child) { builder: (context, ref, child) {
return _TabFilters(tabsViewMode: tabsViewMode); return _TabFilters(tabsViewMode: tabsViewMode);
@@ -50,7 +50,7 @@ class OpenImageInNewTab extends HookConsumerWidget {
TabMode.fromTabType( TabMode.fromTabType(
ref ref
.read(generalSettingsWithDefaultsProvider) .read(generalSettingsWithDefaultsProvider)
.defaultCreateTabType, .effectiveDefaultCreateTabType,
); );
final tabId = await ref final tabId = await ref
@@ -61,6 +61,11 @@ class OpenInContainer extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final settings = ref.watch(generalSettingsWithDefaultsProvider);
if (!settings.showContainerUi) {
return const SizedBox.shrink();
}
return ListTile( return ListTile(
leading: const Icon(MdiIcons.selectGroup), leading: const Icon(MdiIcons.selectGroup),
title: const Text('Open in container'), title: const Text('Open in container'),
@@ -92,11 +97,7 @@ class OpenInContainer extends HookConsumerWidget {
final currentTab = ref.read(selectedTabStateProvider); final currentTab = ref.read(selectedTabStateProvider);
final tabMode = final tabMode =
currentTab?.tabMode ?? currentTab?.tabMode ??
TabMode.fromTabType( TabMode.fromTabType(settings.effectiveDefaultCreateTabType);
ref
.read(generalSettingsWithDefaultsProvider)
.defaultCreateTabType,
);
final tabId = await ref final tabId = await ref
.read(tabRepositoryProvider.notifier) .read(tabRepositoryProvider.notifier)
@@ -50,7 +50,7 @@ class OpenInNewTab extends HookConsumerWidget {
TabMode.fromTabType( TabMode.fromTabType(
ref ref
.read(generalSettingsWithDefaultsProvider) .read(generalSettingsWithDefaultsProvider)
.defaultCreateTabType, .effectiveDefaultCreateTabType,
); );
final tabId = await ref final tabId = await ref
@@ -37,6 +37,7 @@ import 'package:weblibre/features/geckoview/features/contextmenu/presentation/ca
import 'package:weblibre/features/geckoview/features/contextmenu/presentation/candidates/share_email.dart'; import 'package:weblibre/features/geckoview/features/contextmenu/presentation/candidates/share_email.dart';
import 'package:weblibre/features/geckoview/features/contextmenu/presentation/candidates/share_image.dart'; import 'package:weblibre/features/geckoview/features/contextmenu/presentation/candidates/share_image.dart';
import 'package:weblibre/features/geckoview/features/contextmenu/presentation/candidates/share_link.dart'; import 'package:weblibre/features/geckoview/features/contextmenu/presentation/candidates/share_link.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
import 'package:weblibre/presentation/hooks/cached_future.dart'; import 'package:weblibre/presentation/hooks/cached_future.dart';
class ContextMenuDialog extends HookConsumerWidget { class ContextMenuDialog extends HookConsumerWidget {
@@ -46,6 +47,10 @@ class ContextMenuDialog extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final showContainerUi = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.showContainerUi),
);
return SimpleDialog( return SimpleDialog(
title: AutoSizeText( title: AutoSizeText(
hitResult.getTitle(), hitResult.getTitle(),
@@ -58,7 +63,7 @@ class ContextMenuDialog extends HookConsumerWidget {
children: [ children: [
if (OpenInNewTab.isSupported(hitResult)) if (OpenInNewTab.isSupported(hitResult))
OpenInNewTab(hitResult: hitResult), OpenInNewTab(hitResult: hitResult),
if (OpenInContainer.isSupported(hitResult)) if (showContainerUi && OpenInContainer.isSupported(hitResult))
OpenInContainer(hitResult: hitResult), OpenInContainer(hitResult: hitResult),
if (CopyLink.isSupported(hitResult)) CopyLink(hitResult: hitResult), if (CopyLink.isSupported(hitResult)) CopyLink(hitResult: hitResult),
if (SaveFile.isSupported(hitResult)) SaveFile(hitResult: hitResult), if (SaveFile.isSupported(hitResult)) SaveFile(hitResult: hitResult),
@@ -240,6 +240,7 @@ class OpenSharedContent extends HookConsumerWidget {
children: [ children: [
Text('Open link', style: Theme.of(context).textTheme.titleLarge), Text('Open link', style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 16), const SizedBox(height: 16),
if (settings.showContainerUi)
ContainerChips( ContainerChips(
displayMenu: false, displayMenu: false,
selectedContainer: selectedContainer.value, selectedContainer: selectedContainer.value,
@@ -380,8 +381,10 @@ class OpenSharedContent extends HookConsumerWidget {
subtitle: 'Add to your browser tabs', subtitle: 'Add to your browser tabs',
icon: MdiIcons.tab, icon: MdiIcons.tab,
trailing: PopupMenuButton<TabMode>( trailing: PopupMenuButton<TabMode>(
icon: Icon(MdiIcons.tabUnselected, size: 24), icon: const Icon(MdiIcons.tabUnselected, size: 24),
tooltip: 'Private / Isolated', tooltip: settings.showIsolatedTabUi
? 'Private / Isolated'
: 'Private',
onSelected: openTab, onSelected: openTab,
itemBuilder: (context) => [ itemBuilder: (context) => [
PopupMenuItem( PopupMenuItem(
@@ -398,6 +401,7 @@ class OpenSharedContent extends HookConsumerWidget {
], ],
), ),
), ),
if (settings.showIsolatedTabUi)
PopupMenuItem( PopupMenuItem(
value: TabMode.newIsolated(), value: TabMode.newIsolated(),
child: Row( child: Row(
@@ -78,10 +78,24 @@ class SearchScreen extends HookConsumerWidget {
(value) => value.createChildTabsOption, (value) => value.createChildTabsOption,
), ),
); );
final settings = ref.watch(generalSettingsWithDefaultsProvider);
final selectedTabType = useState(tabType); final initialTabType =
!settings.showIsolatedTabUi && tabType == TabType.isolated
? TabType.regular
: tabType;
final selectedTabType = useState(initialTabType);
final currentTabTabType = ref.watch(selectedTabTypeProvider); final currentTabTabType = ref.watch(selectedTabTypeProvider);
useEffect(() {
if (!settings.showIsolatedTabUi &&
selectedTabType.value == TabType.isolated) {
selectedTabType.value = TabType.regular;
}
return null;
}, [settings.showIsolatedTabUi]);
final selectedContainer = ref.watch( final selectedContainer = ref.watch(
selectedContainerDataProvider.select((value) => value.value), selectedContainerDataProvider.select((value) => value.value),
); );
@@ -288,45 +302,57 @@ class SearchScreen extends HookConsumerWidget {
? null ? null
: Padding( : Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row( child: Builder(
children: [ builder: (context) {
Expanded( final tabTypeSwitcher = Focus(
flex: 4,
child: Align(
alignment: Alignment.centerLeft,
child: Focus(
canRequestFocus: false, canRequestFocus: false,
child: AnimatedTabTypeSwitcher( child: AnimatedTabTypeSwitcher(
selected: selectedTabType.value, selected: selectedTabType.value,
onChanged: (value) { onChanged: (value) {
selectedTabType.value = value; selectedTabType.value = value;
// Restore focus to search field after segment change // Restore focus to search field after segment change
WidgetsBinding.instance WidgetsBinding.instance.addPostFrameCallback((
.addPostFrameCallback((_) { _,
) {
searchFocusNode.requestFocus(); searchFocusNode.requestFocus();
}); });
}, },
showChildOption: createChildTabsOption, showChildOption: createChildTabsOption,
selectedBackgroundColor: showIsolatedOption: settings.showIsolatedTabUi,
switch (selectedTabType.value) { selectedBackgroundColor: switch (selectedTabType
.value) {
TabType.regular => null, TabType.regular => null,
TabType.private => TabType.private =>
appColors.privateSelectionOverlay, appColors.privateSelectionOverlay,
TabType.isolated => TabType.isolated =>
appColors.isolatedSelectionOverlay, appColors.isolatedSelectionOverlay,
TabType.child => TabType.child => switch (currentTabTabType) {
switch (currentTabTabType) {
TabType.private => TabType.private =>
appColors appColors.privateSelectionOverlay,
.privateSelectionOverlay,
TabType.isolated => TabType.isolated =>
appColors appColors.isolatedSelectionOverlay,
.isolatedSelectionOverlay,
_ => null, _ => null,
}, },
}, },
), ),
);
if (!settings.showContainerUi) {
return Center(
child: Transform.scale(
scale: 1.08,
child: tabTypeSwitcher,
), ),
);
}
return Row(
children: [
Expanded(
flex: 4,
child: Align(
alignment: Alignment.centerLeft,
child: tabTypeSwitcher,
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
@@ -340,6 +366,8 @@ class SearchScreen extends HookConsumerWidget {
), ),
), ),
], ],
);
},
), ),
), ),
bottom: PreferredSize( bottom: PreferredSize(
@@ -28,6 +28,7 @@ class AnimatedTabTypeSwitcher extends StatelessWidget {
final TabType selected; final TabType selected;
final ValueChanged<TabType> onChanged; final ValueChanged<TabType> onChanged;
final bool showChildOption; final bool showChildOption;
final bool showIsolatedOption;
final Color? selectedBackgroundColor; final Color? selectedBackgroundColor;
const AnimatedTabTypeSwitcher({ const AnimatedTabTypeSwitcher({
@@ -35,6 +36,7 @@ class AnimatedTabTypeSwitcher extends StatelessWidget {
required this.selected, required this.selected,
required this.onChanged, required this.onChanged,
this.showChildOption = false, this.showChildOption = false,
this.showIsolatedOption = true,
this.selectedBackgroundColor, this.selectedBackgroundColor,
}); });
@@ -72,6 +74,7 @@ class AnimatedTabTypeSwitcher extends StatelessWidget {
selectedBackgroundColor: selectedBackgroundColor, selectedBackgroundColor: selectedBackgroundColor,
onTap: () => onChanged(TabType.private), onTap: () => onChanged(TabType.private),
), ),
if (showIsolatedOption) ...[
_divider(borderColor), _divider(borderColor),
_Segment( _Segment(
tabType: TabType.isolated, tabType: TabType.isolated,
@@ -81,6 +84,7 @@ class AnimatedTabTypeSwitcher extends StatelessWidget {
selectedBackgroundColor: selectedBackgroundColor, selectedBackgroundColor: selectedBackgroundColor,
onTap: () => onChanged(TabType.isolated), onTap: () => onChanged(TabType.isolated),
), ),
],
if (showChildOption) ...[ if (showChildOption) ...[
_divider(borderColor), _divider(borderColor),
_Segment( _Segment(
@@ -28,6 +28,7 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/entities/contai
import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selected_container.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selected_container.dart';
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_title.dart'; import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_title.dart';
import 'package:weblibre/features/geckoview/features/tabs/utils/container_colors.dart'; import 'package:weblibre/features/geckoview/features/tabs/utils/container_colors.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
/// A compact container selector that displays only the currently selected /// A compact container selector that displays only the currently selected
/// container (or "unassigned" if none selected) without counts. /// container (or "unassigned" if none selected) without counts.
@@ -40,6 +41,15 @@ class CompactContainerSelector extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final containerUiEnabled = ref.watch(
generalSettingsWithDefaultsProvider.select(
(settings) => settings.showContainerUi,
),
);
if (!containerUiEnabled) {
return const SizedBox.shrink();
}
final theme = Theme.of(context); final theme = Theme.of(context);
final isSelected = selectedContainer != null; final isSelected = selectedContainer != null;
@@ -200,6 +200,15 @@ class ContainerChips extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final containerUiEnabled = ref.watch(
generalSettingsWithDefaultsProvider.select(
(settings) => settings.showContainerUi,
),
);
if (!containerUiEnabled) {
return const SizedBox.shrink();
}
final searchText = useListenableSelector( final searchText = useListenableSelector(
searchTextListenable, searchTextListenable,
() => searchTextListenable?.value.text, () => searchTextListenable?.value.text,
@@ -353,9 +353,8 @@ class _QuickTabSwitcherModeSection extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final quickTabSwitcherMode = ref.watch( final settings = ref.watch(generalSettingsWithDefaultsProvider);
generalSettingsWithDefaultsProvider.select((s) => s.quickTabSwitcherMode), final quickTabSwitcherMode = settings.effectiveUiQuickTabSwitcherMode();
);
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8),
@@ -380,14 +379,15 @@ class _QuickTabSwitcherModeSection extends HookConsumerWidget {
); );
} }
}, },
child: const Column( child: Column(
children: [ children: [
RadioListTile.adaptive( const RadioListTile.adaptive(
value: QuickTabSwitcherMode.lastUsedTabs, value: QuickTabSwitcherMode.lastUsedTabs,
title: Text('Recently Used Tabs'), title: Text('Recently Used Tabs'),
subtitle: Text('Recently used tabs across all containers'), subtitle: Text('Recently used tabs across all containers'),
), ),
RadioListTile.adaptive( if (settings.showContainerUi)
const RadioListTile.adaptive(
value: QuickTabSwitcherMode.containerTabs, value: QuickTabSwitcherMode.containerTabs,
title: Text('Container Tabs'), title: Text('Container Tabs'),
subtitle: Text('Ordered tabs of the selected container'), subtitle: Text('Ordered tabs of the selected container'),
@@ -25,6 +25,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:weblibre/core/design/app_colors.dart'; import 'package:weblibre/core/design/app_colors.dart';
import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/core/routing/routes.dart';
import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart'; import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart';
import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selected_container.dart';
import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart'; import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart';
import 'package:weblibre/features/settings/presentation/widgets/sections.dart'; import 'package:weblibre/features/settings/presentation/widgets/sections.dart';
import 'package:weblibre/features/user/data/models/general_settings.dart'; import 'package:weblibre/features/user/data/models/general_settings.dart';
@@ -83,6 +84,8 @@ class _TabOrganizationSection extends StatelessWidget {
return const Column( return const Column(
children: [ children: [
SettingSection(name: 'Tab Organization'), SettingSection(name: 'Tab Organization'),
_ShowContainerUiTile(),
_ShowIsolatedTabUiTile(),
_CreateChildTabsTile(), _CreateChildTabsTile(),
], ],
); );
@@ -110,9 +113,8 @@ class _NewTabDefaultSection extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final appColors = AppColors.of(context); final appColors = AppColors.of(context);
final defaultCreateTabType = ref.watch( final settings = ref.watch(generalSettingsWithDefaultsProvider);
generalSettingsWithDefaultsProvider.select((s) => s.defaultCreateTabType), final defaultCreateTabType = settings.effectiveDefaultCreateTabType;
);
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8),
@@ -140,6 +142,7 @@ class _NewTabDefaultSection extends HookConsumerWidget {
label: Text('Private'), label: Text('Private'),
icon: Icon(WebLibreIcons.privateTab), icon: Icon(WebLibreIcons.privateTab),
), ),
if (settings.showIsolatedTabUi)
ButtonSegment( ButtonSegment(
value: TabType.isolated, value: TabType.isolated,
label: const Text('Isolated'), label: const Text('Isolated'),
@@ -157,7 +160,7 @@ class _NewTabDefaultSection extends HookConsumerWidget {
.read(saveGeneralSettingsControllerProvider.notifier) .read(saveGeneralSettingsControllerProvider.notifier)
.save( .save(
(currentSettings) => currentSettings.copyWith (currentSettings) => currentSettings.copyWith
.defaultCreateTabType(value.first), .storedDefaultCreateTabType(value.first),
); );
}, },
style: switch (defaultCreateTabType) { style: switch (defaultCreateTabType) {
@@ -274,6 +277,75 @@ class _CreateChildTabsTile extends HookConsumerWidget {
} }
} }
class _ShowContainerUiTile extends HookConsumerWidget {
const _ShowContainerUiTile();
@override
Widget build(BuildContext context, WidgetRef ref) {
final showContainerUi = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.showContainerUi),
);
return SwitchListTile.adaptive(
title: const Text('Show Container UI'),
subtitle: const Text('Show container selectors, menus, and management'),
secondary: const Icon(MdiIcons.folder),
value: showContainerUi,
onChanged: (value) async {
await ref.read(saveGeneralSettingsControllerProvider.notifier).save((
currentSettings,
) {
var updated = currentSettings.copyWith.showContainerUi(value);
if (!value &&
updated.quickTabSwitcherMode ==
QuickTabSwitcherMode.containerTabs) {
updated = updated.copyWith.quickTabSwitcherMode(
QuickTabSwitcherMode.lastUsedTabs,
);
}
return updated;
});
if (!value) {
ref.read(selectedContainerProvider.notifier).clearContainer();
}
},
);
}
}
class _ShowIsolatedTabUiTile extends HookConsumerWidget {
const _ShowIsolatedTabUiTile();
@override
Widget build(BuildContext context, WidgetRef ref) {
final showIsolatedTabUi = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.showIsolatedTabUi),
);
return SwitchListTile.adaptive(
title: const Text('Show Isolated Tab UI'),
subtitle: const Text('Show isolated-tab creation options in the UI'),
secondary: const Icon(MdiIcons.shieldLock),
value: showIsolatedTabUi,
onChanged: (value) async {
await ref.read(saveGeneralSettingsControllerProvider.notifier).save((
currentSettings,
) {
var updated = currentSettings.copyWith.showIsolatedTabUi(value);
if (!value &&
updated.storedDefaultCreateTabType == TabType.isolated) {
updated = updated.copyWith.storedDefaultCreateTabType(
TabType.regular,
);
}
return updated;
});
},
);
}
}
class _ShowExtensionShortcutTile extends HookConsumerWidget { class _ShowExtensionShortcutTile extends HookConsumerWidget {
const _ShowExtensionShortcutTile(); const _ShowExtensionShortcutTile();
@@ -29,6 +29,7 @@ import 'package:weblibre/features/settings/presentation/controllers/save_setting
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart'; import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
import 'package:weblibre/features/tor/presentation/screens/country_picker.dart'; import 'package:weblibre/features/tor/presentation/screens/country_picker.dart';
import 'package:weblibre/features/user/data/models/tor_settings.dart'; import 'package:weblibre/features/user/data/models/tor_settings.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
import 'package:weblibre/features/user/domain/repositories/tor_settings.dart'; import 'package:weblibre/features/user/domain/repositories/tor_settings.dart';
import 'package:weblibre/presentation/hooks/on_initialization.dart'; import 'package:weblibre/presentation/hooks/on_initialization.dart';
import 'package:weblibre/utils/ui_helper.dart'; import 'package:weblibre/utils/ui_helper.dart';
@@ -79,6 +80,9 @@ class TorProxyScreen extends HookConsumerWidget {
bootstrapProgress > 0 && bootstrapProgress < 100; bootstrapProgress > 0 && bootstrapProgress < 100;
final torSettings = ref.watch(torSettingsWithDefaultsProvider); final torSettings = ref.watch(torSettingsWithDefaultsProvider);
final showContainerUi = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.showContainerUi),
);
useOnInitialization(() async { useOnInitialization(() async {
await ref.read(torProxyServiceProvider.notifier).requestSync(); await ref.read(torProxyServiceProvider.notifier).requestSync();
@@ -246,22 +250,36 @@ class TorProxyScreen extends HookConsumerWidget {
); );
} }
}, },
child: const Column( child: Column(
children: [ children: [
RadioListTile.adaptive( if (showContainerUi)
const RadioListTile.adaptive(
value: TorRegularTabProxyMode.container, value: TorRegularTabProxyMode.container,
title: Text('Container-Based Routing'), title: Text('Container-Based Routing'),
subtitle: Text( subtitle: Text(
'Route only tabs in Tor containers through the Tor network. Private tabs remain unaffected.', 'Route only tabs in Tor containers through the Tor network. Private tabs remain unaffected.',
), ),
), ),
RadioListTile.adaptive( const RadioListTile.adaptive(
value: TorRegularTabProxyMode.all, value: TorRegularTabProxyMode.all,
title: Text('Global Routing'), title: Text('Global Routing'),
subtitle: Text( subtitle: Text(
'Route all regular tabs through the Tor network. Private tabs remain unaffected.', 'Route all regular tabs through the Tor network. Private tabs remain unaffected.',
), ),
), ),
if (!showContainerUi &&
torSettings.proxyRegularTabsMode ==
TorRegularTabProxyMode.container)
const Padding(
padding: EdgeInsets.only(
left: 56,
right: 24,
top: 4,
),
child: Text(
'Container-based routing is currently active but hidden because Container UI is disabled.',
),
),
], ],
), ),
), ),
@@ -69,7 +69,9 @@ class GeneralSettings with FastEquatable {
final bool createChildTabsOption; final bool createChildTabsOption;
final bool showExtensionShortcut; final bool showExtensionShortcut;
final bool enableLocalAiFeatures; final bool enableLocalAiFeatures;
final TabType defaultCreateTabType; final bool showContainerUi;
final bool showIsolatedTabUi;
final TabType storedDefaultCreateTabType;
final TabIntentOpenSetting tabIntentOpenSetting; final TabIntentOpenSetting tabIntentOpenSetting;
final bool autoHideTabBar; final bool autoHideTabBar;
final TabBarSwipeAction tabBarSwipeAction; final TabBarSwipeAction tabBarSwipeAction;
@@ -113,7 +115,9 @@ class GeneralSettings with FastEquatable {
required this.createChildTabsOption, required this.createChildTabsOption,
required this.showExtensionShortcut, required this.showExtensionShortcut,
required this.enableLocalAiFeatures, required this.enableLocalAiFeatures,
required this.defaultCreateTabType, required this.showContainerUi,
required this.showIsolatedTabUi,
required this.storedDefaultCreateTabType,
required this.tabIntentOpenSetting, required this.tabIntentOpenSetting,
required this.autoHideTabBar, required this.autoHideTabBar,
required this.tabBarSwipeAction, required this.tabBarSwipeAction,
@@ -158,7 +162,9 @@ class GeneralSettings with FastEquatable {
bool? createChildTabsOption, bool? createChildTabsOption,
bool? showExtensionShortcut, bool? showExtensionShortcut,
bool? enableLocalAiFeatures, bool? enableLocalAiFeatures,
TabType? defaultCreateTabType, bool? showContainerUi,
bool? showIsolatedTabUi,
TabType? storedDefaultCreateTabType,
TabIntentOpenSetting? tabIntentOpenSetting, TabIntentOpenSetting? tabIntentOpenSetting,
bool? autoHideTabBar, bool? autoHideTabBar,
TabBarSwipeAction? tabBarSwipeAction, TabBarSwipeAction? tabBarSwipeAction,
@@ -200,7 +206,10 @@ class GeneralSettings with FastEquatable {
createChildTabsOption = createChildTabsOption ?? false, createChildTabsOption = createChildTabsOption ?? false,
showExtensionShortcut = showExtensionShortcut ?? false, showExtensionShortcut = showExtensionShortcut ?? false,
enableLocalAiFeatures = enableLocalAiFeatures ?? true, enableLocalAiFeatures = enableLocalAiFeatures ?? true,
defaultCreateTabType = defaultCreateTabType ?? TabType.regular, showContainerUi = showContainerUi ?? true,
showIsolatedTabUi = showIsolatedTabUi ?? true,
storedDefaultCreateTabType =
storedDefaultCreateTabType ?? TabType.regular,
tabIntentOpenSetting = tabIntentOpenSetting ?? TabIntentOpenSetting.ask, tabIntentOpenSetting = tabIntentOpenSetting ?? TabIntentOpenSetting.ask,
autoHideTabBar = autoHideTabBar ?? true, autoHideTabBar = autoHideTabBar ?? true,
tabBarSwipeAction = tabBarSwipeAction =
@@ -248,6 +257,21 @@ class GeneralSettings with FastEquatable {
Map<String, dynamic> toJson() => _$GeneralSettingsToJson(this); Map<String, dynamic> toJson() => _$GeneralSettingsToJson(this);
TabType get effectiveDefaultCreateTabType {
if (!showIsolatedTabUi && storedDefaultCreateTabType == TabType.isolated) {
return TabType.regular;
}
return storedDefaultCreateTabType;
}
QuickTabSwitcherMode effectiveUiQuickTabSwitcherMode() {
if (!showContainerUi &&
quickTabSwitcherMode == QuickTabSwitcherMode.containerTabs) {
return QuickTabSwitcherMode.lastUsedTabs;
}
return quickTabSwitcherMode;
}
@override @override
List<Object?> get hashParameters => [ List<Object?> get hashParameters => [
themeMode, themeMode,
@@ -259,7 +283,9 @@ class GeneralSettings with FastEquatable {
createChildTabsOption, createChildTabsOption,
showExtensionShortcut, showExtensionShortcut,
enableLocalAiFeatures, enableLocalAiFeatures,
defaultCreateTabType, showContainerUi,
showIsolatedTabUi,
storedDefaultCreateTabType,
tabIntentOpenSetting, tabIntentOpenSetting,
autoHideTabBar, autoHideTabBar,
tabBarSwipeAction, tabBarSwipeAction,
@@ -29,7 +29,13 @@ abstract class _$GeneralSettingsCWProxy {
GeneralSettings enableLocalAiFeatures(bool enableLocalAiFeatures); GeneralSettings enableLocalAiFeatures(bool enableLocalAiFeatures);
GeneralSettings defaultCreateTabType(TabType defaultCreateTabType); GeneralSettings showContainerUi(bool showContainerUi);
GeneralSettings showIsolatedTabUi(bool showIsolatedTabUi);
GeneralSettings storedDefaultCreateTabType(
TabType storedDefaultCreateTabType,
);
GeneralSettings tabIntentOpenSetting( GeneralSettings tabIntentOpenSetting(
TabIntentOpenSetting tabIntentOpenSetting, TabIntentOpenSetting tabIntentOpenSetting,
@@ -124,7 +130,9 @@ abstract class _$GeneralSettingsCWProxy {
bool createChildTabsOption, bool createChildTabsOption,
bool showExtensionShortcut, bool showExtensionShortcut,
bool enableLocalAiFeatures, bool enableLocalAiFeatures,
TabType defaultCreateTabType, bool showContainerUi,
bool showIsolatedTabUi,
TabType storedDefaultCreateTabType,
TabIntentOpenSetting tabIntentOpenSetting, TabIntentOpenSetting tabIntentOpenSetting,
bool autoHideTabBar, bool autoHideTabBar,
TabBarSwipeAction tabBarSwipeAction, TabBarSwipeAction tabBarSwipeAction,
@@ -205,8 +213,17 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
call(enableLocalAiFeatures: enableLocalAiFeatures); call(enableLocalAiFeatures: enableLocalAiFeatures);
@override @override
GeneralSettings defaultCreateTabType(TabType defaultCreateTabType) => GeneralSettings showContainerUi(bool showContainerUi) =>
call(defaultCreateTabType: defaultCreateTabType); call(showContainerUi: showContainerUi);
@override
GeneralSettings showIsolatedTabUi(bool showIsolatedTabUi) =>
call(showIsolatedTabUi: showIsolatedTabUi);
@override
GeneralSettings storedDefaultCreateTabType(
TabType storedDefaultCreateTabType,
) => call(storedDefaultCreateTabType: storedDefaultCreateTabType);
@override @override
GeneralSettings tabIntentOpenSetting( GeneralSettings tabIntentOpenSetting(
@@ -364,7 +381,9 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
Object? createChildTabsOption = const $CopyWithPlaceholder(), Object? createChildTabsOption = const $CopyWithPlaceholder(),
Object? showExtensionShortcut = const $CopyWithPlaceholder(), Object? showExtensionShortcut = const $CopyWithPlaceholder(),
Object? enableLocalAiFeatures = const $CopyWithPlaceholder(), Object? enableLocalAiFeatures = const $CopyWithPlaceholder(),
Object? defaultCreateTabType = const $CopyWithPlaceholder(), Object? showContainerUi = const $CopyWithPlaceholder(),
Object? showIsolatedTabUi = const $CopyWithPlaceholder(),
Object? storedDefaultCreateTabType = const $CopyWithPlaceholder(),
Object? tabIntentOpenSetting = const $CopyWithPlaceholder(), Object? tabIntentOpenSetting = const $CopyWithPlaceholder(),
Object? autoHideTabBar = const $CopyWithPlaceholder(), Object? autoHideTabBar = const $CopyWithPlaceholder(),
Object? tabBarSwipeAction = const $CopyWithPlaceholder(), Object? tabBarSwipeAction = const $CopyWithPlaceholder(),
@@ -450,12 +469,24 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
? _value.enableLocalAiFeatures ? _value.enableLocalAiFeatures
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: enableLocalAiFeatures as bool, : enableLocalAiFeatures as bool,
defaultCreateTabType: showContainerUi:
defaultCreateTabType == const $CopyWithPlaceholder() || showContainerUi == const $CopyWithPlaceholder() ||
defaultCreateTabType == null showContainerUi == null
? _value.defaultCreateTabType ? _value.showContainerUi
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: defaultCreateTabType as TabType, : showContainerUi as bool,
showIsolatedTabUi:
showIsolatedTabUi == const $CopyWithPlaceholder() ||
showIsolatedTabUi == null
? _value.showIsolatedTabUi
// ignore: cast_nullable_to_non_nullable
: showIsolatedTabUi as bool,
storedDefaultCreateTabType:
storedDefaultCreateTabType == const $CopyWithPlaceholder() ||
storedDefaultCreateTabType == null
? _value.storedDefaultCreateTabType
// ignore: cast_nullable_to_non_nullable
: storedDefaultCreateTabType as TabType,
tabIntentOpenSetting: tabIntentOpenSetting:
tabIntentOpenSetting == const $CopyWithPlaceholder() || tabIntentOpenSetting == const $CopyWithPlaceholder() ||
tabIntentOpenSetting == null tabIntentOpenSetting == null
@@ -682,9 +713,11 @@ GeneralSettings _$GeneralSettingsFromJson(
createChildTabsOption: json['createChildTabsOption'] as bool?, createChildTabsOption: json['createChildTabsOption'] as bool?,
showExtensionShortcut: json['showExtensionShortcut'] as bool?, showExtensionShortcut: json['showExtensionShortcut'] as bool?,
enableLocalAiFeatures: json['enableLocalAiFeatures'] as bool?, enableLocalAiFeatures: json['enableLocalAiFeatures'] as bool?,
defaultCreateTabType: $enumDecodeNullable( showContainerUi: json['showContainerUi'] as bool?,
showIsolatedTabUi: json['showIsolatedTabUi'] as bool?,
storedDefaultCreateTabType: $enumDecodeNullable(
_$TabTypeEnumMap, _$TabTypeEnumMap,
json['defaultCreateTabType'], json['storedDefaultCreateTabType'],
), ),
tabIntentOpenSetting: $enumDecodeNullable( tabIntentOpenSetting: $enumDecodeNullable(
_$TabIntentOpenSettingEnumMap, _$TabIntentOpenSettingEnumMap,
@@ -763,7 +796,10 @@ Map<String, dynamic> _$GeneralSettingsToJson(
'createChildTabsOption': instance.createChildTabsOption, 'createChildTabsOption': instance.createChildTabsOption,
'showExtensionShortcut': instance.showExtensionShortcut, 'showExtensionShortcut': instance.showExtensionShortcut,
'enableLocalAiFeatures': instance.enableLocalAiFeatures, 'enableLocalAiFeatures': instance.enableLocalAiFeatures,
'defaultCreateTabType': _$TabTypeEnumMap[instance.defaultCreateTabType]!, 'showContainerUi': instance.showContainerUi,
'showIsolatedTabUi': instance.showIsolatedTabUi,
'storedDefaultCreateTabType':
_$TabTypeEnumMap[instance.storedDefaultCreateTabType]!,
'tabIntentOpenSetting': 'tabIntentOpenSetting':
_$TabIntentOpenSettingEnumMap[instance.tabIntentOpenSetting]!, _$TabIntentOpenSettingEnumMap[instance.tabIntentOpenSetting]!,
'autoHideTabBar': instance.autoHideTabBar, 'autoHideTabBar': instance.autoHideTabBar,
@@ -80,7 +80,15 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
DriftSqlType.bool, DriftSqlType.bool,
db.typeMapping, db.typeMapping,
), ),
'defaultCreateTabType': settings['defaultCreateTabType']?.readAs( 'showContainerUi': settings['showContainerUi']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'showIsolatedTabUi': settings['showIsolatedTabUi']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'storedDefaultCreateTabType': settings['defaultCreateTabType']?.readAs(
DriftSqlType.string, DriftSqlType.string,
db.typeMapping, db.typeMapping,
), ),
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
} }
String _$generalSettingsRepositoryHash() => String _$generalSettingsRepositoryHash() =>
r'5fcb1b28918a6c7bb23f72681fdec8bee77e49a5'; r'51cfcf20b24705f5c6f51d4e204fff5a8e4eee89';
abstract class _$GeneralSettingsRepository abstract class _$GeneralSettingsRepository
extends $StreamNotifier<GeneralSettings> { extends $StreamNotifier<GeneralSettings> {
@@ -199,7 +199,7 @@ class FeedArticleScreen extends HookConsumerWidget {
final tabMode = TabMode.fromTabType( final tabMode = TabMode.fromTabType(
ref ref
.read(generalSettingsWithDefaultsProvider) .read(generalSettingsWithDefaultsProvider)
.defaultCreateTabType, .effectiveDefaultCreateTabType,
); );
await ref await ref
@@ -249,7 +249,7 @@ class FeedArticleScreen extends HookConsumerWidget {
final tabMode = TabMode.fromTabType( final tabMode = TabMode.fromTabType(
ref ref
.read(generalSettingsWithDefaultsProvider) .read(generalSettingsWithDefaultsProvider)
.defaultCreateTabType, .effectiveDefaultCreateTabType,
); );
await ref await ref