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