From d3c6771b6a0dc25e21a9d247abea1b64be8069ff Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Sun, 20 Jul 2025 12:18:14 +0200 Subject: [PATCH] show tab count filtered by selected container --- .../widgets/tabs_action_button.dart | 57 ++++++-- .../features/tabs/domain/providers.dart | 7 + .../features/tabs/domain/providers.g.dart | 123 ++++++++++++++++++ .../domain/providers/selected_container.dart | 12 ++ .../providers/selected_container.g.dart | 19 +++ 5 files changed, 207 insertions(+), 11 deletions(-) diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart index 36eec540..44e4dbd9 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:weblibre/features/geckoview/domain/providers/tab_list.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:weblibre/core/logger.dart'; +import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selected_container.dart'; class TabsActionButton extends HookConsumerWidget { final bool isActive; @@ -20,9 +23,8 @@ class TabsActionButton extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final theme = Theme.of(context); - final tabCount = ref.watch( - tabListProvider.select((tabs) => tabs.value.length), - ); + final tabCount = ref.watch(selectedContainerTabCountProvider); + final lastTabCount = useRef(null); return InkWell( onTap: onTap, @@ -42,13 +44,46 @@ class TabsActionButton extends HookConsumerWidget { ), constraints: const BoxConstraints(minWidth: 25.0), child: Center( - child: Text( - tabCount.toString(), - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.0, - color: isActive ? theme.colorScheme.primary : null, - ), + child: tabCount.when( + skipLoadingOnReload: true, + data: (count) { + lastTabCount.value = count; + + return Text( + count.toString(), + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.0, + color: isActive ? theme.colorScheme.primary : null, + ), + ); + }, + loading: () => (lastTabCount.value != null) + ? Text( + lastTabCount.value.toString(), + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.0, + color: isActive ? theme.colorScheme.primary : null, + ), + ) + : const Skeletonizer(child: Text('00')), + error: (error, stackTrace) { + logger.e( + 'Could not determine tab count', + error: error, + stackTrace: stackTrace, + ); + + return Text( + '-1', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.0, + color: isActive ? theme.colorScheme.primary : null, + ), + ); + }, ), ), ), diff --git a/app/lib/features/geckoview/features/tabs/domain/providers.dart b/app/lib/features/geckoview/features/tabs/domain/providers.dart index d331a5be..c5c93240 100644 --- a/app/lib/features/geckoview/features/tabs/domain/providers.dart +++ b/app/lib/features/geckoview/features/tabs/domain/providers.dart @@ -49,6 +49,13 @@ Stream> containerTabIds(Ref ref, ContainerFilter containerFilter) { } } +@Riverpod() +Future containerTabCount(Ref ref, ContainerFilter containerFilter) { + return ref.watch( + containerTabIdsProvider(containerFilter).selectAsync((tabs) => tabs.length), + ); +} + @Riverpod() Stream> tabTrees(Ref ref) { final db = ref.watch(tabDatabaseProvider); diff --git a/app/lib/features/geckoview/features/tabs/domain/providers.g.dart b/app/lib/features/geckoview/features/tabs/domain/providers.g.dart index 9e41f6b6..a66c24e8 100644 --- a/app/lib/features/geckoview/features/tabs/domain/providers.g.dart +++ b/app/lib/features/geckoview/features/tabs/domain/providers.g.dart @@ -303,6 +303,129 @@ class _ContainerTabIdsProviderElement (origin as ContainerTabIdsProvider).containerFilter; } +String _$containerTabCountHash() => r'586e83429b527b546d43232a58453635ab860d69'; + +/// See also [containerTabCount]. +@ProviderFor(containerTabCount) +const containerTabCountProvider = ContainerTabCountFamily(); + +/// See also [containerTabCount]. +class ContainerTabCountFamily extends Family> { + /// See also [containerTabCount]. + const ContainerTabCountFamily(); + + /// See also [containerTabCount]. + ContainerTabCountProvider call(ContainerFilter containerFilter) { + return ContainerTabCountProvider(containerFilter); + } + + @override + ContainerTabCountProvider getProviderOverride( + covariant ContainerTabCountProvider provider, + ) { + return call(provider.containerFilter); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'containerTabCountProvider'; +} + +/// See also [containerTabCount]. +class ContainerTabCountProvider extends AutoDisposeFutureProvider { + /// See also [containerTabCount]. + ContainerTabCountProvider(ContainerFilter containerFilter) + : this._internal( + (ref) => + containerTabCount(ref as ContainerTabCountRef, containerFilter), + from: containerTabCountProvider, + name: r'containerTabCountProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$containerTabCountHash, + dependencies: ContainerTabCountFamily._dependencies, + allTransitiveDependencies: + ContainerTabCountFamily._allTransitiveDependencies, + containerFilter: containerFilter, + ); + + ContainerTabCountProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.containerFilter, + }) : super.internal(); + + final ContainerFilter containerFilter; + + @override + Override overrideWith( + FutureOr Function(ContainerTabCountRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: ContainerTabCountProvider._internal( + (ref) => create(ref as ContainerTabCountRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + containerFilter: containerFilter, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _ContainerTabCountProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is ContainerTabCountProvider && + other.containerFilter == containerFilter; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, containerFilter.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin ContainerTabCountRef on AutoDisposeFutureProviderRef { + /// The parameter `containerFilter` of this provider. + ContainerFilter get containerFilter; +} + +class _ContainerTabCountProviderElement + extends AutoDisposeFutureProviderElement + with ContainerTabCountRef { + _ContainerTabCountProviderElement(super.provider); + + @override + ContainerFilter get containerFilter => + (origin as ContainerTabCountProvider).containerFilter; +} + String _$tabTreesHash() => r'b7b7f7136827207dd01a7894a915be3d17b1ae63'; /// See also [tabTrees]. diff --git a/app/lib/features/geckoview/features/tabs/domain/providers/selected_container.dart b/app/lib/features/geckoview/features/tabs/domain/providers/selected_container.dart index 977b5d1f..e6541a0e 100644 --- a/app/lib/features/geckoview/features/tabs/domain/providers/selected_container.dart +++ b/app/lib/features/geckoview/features/tabs/domain/providers/selected_container.dart @@ -3,6 +3,7 @@ import 'package:riverpod/riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/geckoview/domain/providers/selected_tab.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/data/providers.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'; @@ -138,3 +139,14 @@ Stream selectedContainerData(Ref ref) { return Stream.value(null); } + +@Riverpod() +AsyncValue selectedContainerTabCount(Ref ref) { + final selectedContainer = ref.watch(selectedContainerProvider); + final tabCount = ref.watch( + // ignore: provider_parameters + containerTabCountProvider(ContainerFilter.from(selectedContainer)), + ); + + return tabCount; +} diff --git a/app/lib/features/geckoview/features/tabs/domain/providers/selected_container.g.dart b/app/lib/features/geckoview/features/tabs/domain/providers/selected_container.g.dart index b4ec2240..fe1ba768 100644 --- a/app/lib/features/geckoview/features/tabs/domain/providers/selected_container.g.dart +++ b/app/lib/features/geckoview/features/tabs/domain/providers/selected_container.g.dart @@ -25,6 +25,25 @@ final selectedContainerDataProvider = @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element typedef SelectedContainerDataRef = AutoDisposeStreamProviderRef; +String _$selectedContainerTabCountHash() => + r'60218b4a9058738dfd43628d5e3c55f93080732f'; + +/// See also [selectedContainerTabCount]. +@ProviderFor(selectedContainerTabCount) +final selectedContainerTabCountProvider = + AutoDisposeProvider>.internal( + selectedContainerTabCount, + name: r'selectedContainerTabCountProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$selectedContainerTabCountHash, + dependencies: null, + allTransitiveDependencies: null, + ); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef SelectedContainerTabCountRef = AutoDisposeProviderRef>; String _$selectedContainerHash() => r'34457f0adc45d437a9ab817387be4b1664cd2e7a'; /// See also [SelectedContainer].