diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart index 0c0fe38a..9c3cf2d9 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart @@ -205,15 +205,21 @@ class _TabSheetHeader extends HookConsumerWidget { return ContainerChips( selectedContainer: selectedContainer, onSelected: (container) async { - final result = await ref - .read(selectedContainerProvider.notifier) - .setContainerId(container.id); + if (container != null) { + final result = await ref + .read(selectedContainerProvider.notifier) + .setContainerId(container.id); - if (context.mounted && - result == SetContainerResult.successHasProxy) { - await ref - .read(startProxyControllerProvider.notifier) - .maybeStartProxy(context); + if (context.mounted && + result == SetContainerResult.successHasProxy) { + await ref + .read(startProxyControllerProvider.notifier) + .maybeStartProxy(context); + } + } else { + ref + .read(selectedContainerProvider.notifier) + .clearContainer(); } }, onDeleted: (container) { diff --git a/app/lib/features/geckoview/features/tabs/presentation/widgets/container_chips.dart b/app/lib/features/geckoview/features/tabs/presentation/widgets/container_chips.dart index 0957336a..2a91a527 100644 --- a/app/lib/features/geckoview/features/tabs/presentation/widgets/container_chips.dart +++ b/app/lib/features/geckoview/features/tabs/presentation/widgets/container_chips.dart @@ -1,11 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:nullability/nullability.dart'; import 'package:weblibre/core/providers/global_drop.dart'; import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/data/models/drag_data.dart'; +import 'package:weblibre/features/geckoview/features/tabs/data/entities/container_filter.dart'; import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart'; @@ -17,7 +19,7 @@ class ContainerChips extends HookConsumerWidget { final ContainerData? selectedContainer; final bool Function(ContainerDataWithCount)? containerFilter; - final void Function(ContainerDataWithCount)? onSelected; + final void Function(ContainerDataWithCount?)? onSelected; final void Function(ContainerDataWithCount)? onDeleted; final ValueListenable? searchTextListenable; @@ -149,6 +151,35 @@ class ContainerChips extends HookConsumerWidget { }, ); }, + prefixListItems: [ + Consumer( + builder: (context, ref, child) { + final tabCount = ref.watch( + containerTabCountProvider( + // ignore: provider_parameters + ContainerFilterById(containerId: null), + ).select((value) => value.valueOrNull ?? 0), + ); + + return FilterChip( + avatar: const Icon(MdiIcons.folderHidden), + labelPadding: (tabCount > 0) + ? null + : const EdgeInsets.only(right: 2.0), + label: (tabCount > 0) + ? Text(tabCount.toString()) + : const SizedBox.shrink(), + selected: selectedContainer == null, + showCheckmark: false, + onSelected: (value) { + if (value) { + onSelected?.call(null); + } + }, + ); + }, + ), + ], availableItems: availableContainers, selectedItem: selectedContainer, onSelected: onSelected, diff --git a/app/lib/presentation/widgets/selectable_chips.dart b/app/lib/presentation/widgets/selectable_chips.dart index 6e5db231..74c59c75 100644 --- a/app/lib/presentation/widgets/selectable_chips.dart +++ b/app/lib/presentation/widgets/selectable_chips.dart @@ -22,6 +22,7 @@ class _BadgeWrapper extends StatelessWidget { class SelectableChips extends StatelessWidget { final List availableItems; + final List prefixListItems; final S? selectedItem; final int maxCount; final bool deleteIcon; @@ -44,6 +45,7 @@ class SelectableChips extends StatelessWidget { this.itemBadgeCount, this.itemWrap, this.itemTooltip, + this.prefixListItems = const [], required this.availableItems, this.selectedItem, this.maxCount = 25, @@ -75,9 +77,16 @@ class SelectableChips extends StatelessWidget { //Improve list performance by not rendering outside screen at all cacheExtent: 0, scrollDirection: Axis.horizontal, - itemCount: items.length, + itemCount: prefixListItems.length + items.length, itemBuilder: (context, index) { - final item = items[index]; + if (index < prefixListItems.length) { + return Padding( + padding: const EdgeInsets.only(right: 8.0, top: 4.0), + child: prefixListItems[index], + ); + } + + final item = items[index - prefixListItems.length]; final child = Padding( padding: const EdgeInsets.only(right: 8.0, top: 4.0), child: _BadgeWrapper(