setting to hide container and isolated tab ui
This commit is contained in:
@@ -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) {
|
||||
|
||||
+12
-19
@@ -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) {
|
||||
|
||||
+17
-6
@@ -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);
|
||||
},
|
||||
|
||||
+13
-9
@@ -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
|
||||
|
||||
+15
-9
@@ -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(
|
||||
|
||||
+1
-1
@@ -577,7 +577,7 @@ class ViewTabGridWidget extends HookConsumerWidget {
|
||||
await SearchRoute(
|
||||
tabType:
|
||||
ref.read(selectedTabTypeProvider) ??
|
||||
settings.defaultCreateTabType,
|
||||
settings.effectiveDefaultCreateTabType,
|
||||
).push(context);
|
||||
|
||||
onClose();
|
||||
|
||||
+1
-1
@@ -606,7 +606,7 @@ class ViewTabListWidget extends HookConsumerWidget {
|
||||
await SearchRoute(
|
||||
tabType:
|
||||
ref.read(selectedTabTypeProvider) ??
|
||||
settings.defaultCreateTabType,
|
||||
settings.effectiveDefaultCreateTabType,
|
||||
).push(context);
|
||||
|
||||
onClose();
|
||||
|
||||
+1
-1
@@ -345,7 +345,7 @@ class ViewTabTreesWidget extends HookConsumerWidget {
|
||||
await SearchRoute(
|
||||
tabType:
|
||||
ref.read(selectedTabTypeProvider) ??
|
||||
settings.defaultCreateTabType,
|
||||
settings.effectiveDefaultCreateTabType,
|
||||
).push(context);
|
||||
|
||||
onClose();
|
||||
|
||||
+72
-53
@@ -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),
|
||||
],
|
||||
),
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class OpenImageInNewTab extends HookConsumerWidget {
|
||||
TabMode.fromTabType(
|
||||
ref
|
||||
.read(generalSettingsWithDefaultsProvider)
|
||||
.defaultCreateTabType,
|
||||
.effectiveDefaultCreateTabType,
|
||||
);
|
||||
|
||||
final tabId = await ref
|
||||
|
||||
+6
-5
@@ -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)
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class OpenInNewTab extends HookConsumerWidget {
|
||||
TabMode.fromTabType(
|
||||
ref
|
||||
.read(generalSettingsWithDefaultsProvider)
|
||||
.defaultCreateTabType,
|
||||
.effectiveDefaultCreateTabType,
|
||||
);
|
||||
|
||||
final tabId = await ref
|
||||
|
||||
+6
-1
@@ -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),
|
||||
|
||||
+29
-25
@@ -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(
|
||||
|
||||
+13
-9
@@ -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(
|
||||
|
||||
+10
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user