diff --git a/app/lib/features/bangs/data/database/database.drift b/app/lib/features/bangs/data/database/database.drift index 30413633..7c28d25e 100644 --- a/app/lib/features/bangs/data/database/database.drift +++ b/app/lib/features/bangs/data/database/database.drift @@ -90,4 +90,27 @@ bangQuery WITH BangData: bang_icon bi ON b."trigger" = bi."trigger" ORDER BY RANK, - bf.frequency NULLS LAST; \ No newline at end of file + bf.frequency NULLS LAST; + +categoriesJson: + WITH categories AS ( + SELECT + b.category, + json_group_array( + DISTINCT b.sub_category + ORDER BY b.sub_category + ) AS sub_categories + FROM + bang b + WHERE + b.category IS NOT NULL AND + b.sub_category IS NOT NULL + GROUP BY b.category + ORDER BY b.category + ) + SELECT + json_group_object( + c.category, + json(c.sub_categories) + ) AS categories_json + FROM categories c; \ No newline at end of file diff --git a/app/lib/features/bangs/data/database/database.g.dart b/app/lib/features/bangs/data/database/database.g.dart index a3269b0c..8da15a6b 100644 --- a/app/lib/features/bangs/data/database/database.g.dart +++ b/app/lib/features/bangs/data/database/database.g.dart @@ -1094,6 +1094,15 @@ abstract class _$BangDatabase extends GeneratedDatabase { )); } + Selectable categoriesJson() { + return customSelect( + 'WITH categories AS (SELECT b.category, json_group_array(DISTINCT b.sub_category ORDER BY b.sub_category)AS sub_categories FROM bang AS b WHERE b.category IS NOT NULL AND b.sub_category IS NOT NULL GROUP BY b.category ORDER BY b.category) SELECT json_group_object(c.category, json(c.sub_categories)) AS categories_json FROM categories AS c', + variables: [], + readsFrom: { + bang, + }).map((QueryRow row) => row.read('categories_json')); + } + @override Iterable> get allTables => allSchemaEntities.whereType>(); diff --git a/app/lib/features/bangs/domain/providers.g.dart b/app/lib/features/bangs/domain/providers.g.dart index 786c6b87..7367ea85 100644 --- a/app/lib/features/bangs/domain/providers.g.dart +++ b/app/lib/features/bangs/domain/providers.g.dart @@ -170,20 +170,172 @@ final kagiSearchBangDataProvider = StreamProvider.internal( ); typedef KagiSearchBangDataRef = StreamProviderRef; -String _$bangDataListHash() => r'f5544ce7b3cc0f3e0fc3db25a99456c3cd080c1c'; +String _$bangCategoriesHash() => r'dbc63b78208be90c2aa3c3d61b08f98818f4b89d'; -/// See also [bangDataList]. -@ProviderFor(bangDataList) -final bangDataListProvider = AutoDisposeStreamProvider>.internal( - bangDataList, - name: r'bangDataListProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$bangDataListHash, +/// See also [bangCategories]. +@ProviderFor(bangCategories) +final bangCategoriesProvider = + AutoDisposeStreamProvider>>.internal( + bangCategories, + name: r'bangCategoriesProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$bangCategoriesHash, dependencies: null, allTransitiveDependencies: null, ); -typedef BangDataListRef = AutoDisposeStreamProviderRef>; +typedef BangCategoriesRef + = AutoDisposeStreamProviderRef>>; +String _$bangDataListHash() => r'64c3a3c55c481bf97f291f3befd8f958007daac6'; + +/// See also [bangDataList]. +@ProviderFor(bangDataList) +const bangDataListProvider = BangDataListFamily(); + +/// See also [bangDataList]. +class BangDataListFamily extends Family>> { + /// See also [bangDataList]. + const BangDataListFamily(); + + /// See also [bangDataList]. + BangDataListProvider call({ + ({ + ({String category, String? subCategory})? categoryFilter, + String? domain, + Iterable? groups + })? filter, + }) { + return BangDataListProvider( + filter: filter, + ); + } + + @override + BangDataListProvider getProviderOverride( + covariant BangDataListProvider provider, + ) { + return call( + filter: provider.filter, + ); + } + + 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'bangDataListProvider'; +} + +/// See also [bangDataList]. +class BangDataListProvider extends AutoDisposeStreamProvider> { + /// See also [bangDataList]. + BangDataListProvider({ + ({ + ({String category, String? subCategory})? categoryFilter, + String? domain, + Iterable? groups + })? filter, + }) : this._internal( + (ref) => bangDataList( + ref as BangDataListRef, + filter: filter, + ), + from: bangDataListProvider, + name: r'bangDataListProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$bangDataListHash, + dependencies: BangDataListFamily._dependencies, + allTransitiveDependencies: + BangDataListFamily._allTransitiveDependencies, + filter: filter, + ); + + BangDataListProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.filter, + }) : super.internal(); + + final ({ + ({String category, String? subCategory})? categoryFilter, + String? domain, + Iterable? groups + })? filter; + + @override + Override overrideWith( + Stream> Function(BangDataListRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: BangDataListProvider._internal( + (ref) => create(ref as BangDataListRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + filter: filter, + ), + ); + } + + @override + AutoDisposeStreamProviderElement> createElement() { + return _BangDataListProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is BangDataListProvider && other.filter == filter; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, filter.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin BangDataListRef on AutoDisposeStreamProviderRef> { + /// The parameter `filter` of this provider. + ({ + ({String category, String? subCategory})? categoryFilter, + String? domain, + Iterable? groups + })? get filter; +} + +class _BangDataListProviderElement + extends AutoDisposeStreamProviderElement> + with BangDataListRef { + _BangDataListProviderElement(super.provider); + + @override + ({ + ({String category, String? subCategory})? categoryFilter, + String? domain, + Iterable? groups + })? get filter => (origin as BangDataListProvider).filter; +} + String _$frequentBangDataListHash() => r'adf8d0b72adfa8faffadd7f1a294ce3945e22fec'; diff --git a/app/lib/features/bangs/domain/repositories/bang_data.dart b/app/lib/features/bangs/domain/repositories/bang_data.dart index 4ce51906..c7c634b6 100644 --- a/app/lib/features/bangs/domain/repositories/bang_data.dart +++ b/app/lib/features/bangs/domain/repositories/bang_data.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:bang_navigator/domain/services/generic_website.dart'; import 'package:bang_navigator/features/bangs/data/database/database.dart'; import 'package:bang_navigator/features/bangs/data/models/bang.dart'; @@ -27,6 +29,15 @@ class BangDataRepository extends _$BangDataRepository { } } + Stream>> watchCategories() { + return _db.categoriesJson().watchSingle().map((json) { + final decoded = jsonDecode(json) as Map; + return decoded.map( + (key, value) => MapEntry(key, (value as List).cast()), + ); + }); + } + Stream watchBangCount(BangGroup group) { return _db.bangDao.getBangCount(groups: [group]).watchSingle(); } diff --git a/app/lib/features/bangs/domain/repositories/bang_data.g.dart b/app/lib/features/bangs/domain/repositories/bang_data.g.dart index 4f2e52f0..7afb6d8a 100644 --- a/app/lib/features/bangs/domain/repositories/bang_data.g.dart +++ b/app/lib/features/bangs/domain/repositories/bang_data.g.dart @@ -7,7 +7,7 @@ part of 'bang_data.dart'; // ************************************************************************** String _$bangDataRepositoryHash() => - r'6ac3a59546f6d7e22f3c37aacd43a3579978eb50'; + r'a6e4017a54516571af553426b0e8e3597d19f779'; /// See also [BangDataRepository]. @ProviderFor(BangDataRepository) diff --git a/app/lib/features/bangs/presentation/screens/bang.dart b/app/lib/features/bangs/presentation/screens/bang.dart deleted file mode 100644 index e7c259d5..00000000 --- a/app/lib/features/bangs/presentation/screens/bang.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:bang_navigator/core/routing/routes.dart'; -import 'package:bang_navigator/features/bangs/domain/providers.dart'; -import 'package:bang_navigator/features/bangs/presentation/widgets/bang_details.dart'; -import 'package:bang_navigator/features/search_browser/domain/entities/modes.dart'; -import 'package:bang_navigator/features/search_browser/domain/entities/sheet.dart'; -import 'package:bang_navigator/features/search_browser/domain/providers.dart'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; - -class BangScreen extends HookConsumerWidget { - const BangScreen({super.key}); - @override - Widget build(BuildContext context, WidgetRef ref) { - final bangsAsync = ref.watch(bangDataListProvider); - - return Scaffold( - appBar: AppBar( - title: const Text('Bangs'), - actions: [ - IconButton( - onPressed: () async { - await context.push(BangSearchRoute().location); - }, - icon: const Icon(Icons.search), - ), - ], - ), - body: bangsAsync.when( - data: (bangs) { - return ListView.builder( - itemCount: bangs.length, - itemBuilder: (context, index) { - final bang = bangs[index]; - return BangDetails( - bang, - onTap: () { - ref - .read(selectedBangTriggerProvider.notifier) - .setTrigger(bang.trigger); - - if (ref.read(bottomSheetProvider) is! CreateTab) { - ref.read(bottomSheetProvider.notifier).show( - CreateTab( - preferredTool: KagiTool.search, - ), - ); - } - - context.go(KagiRoute().location); - }, - ); - }, - ); - }, - error: (error, stackTrace) => SizedBox.shrink(), - loading: () => SizedBox.shrink(), - ), - ); - } -} diff --git a/app/lib/features/bangs/presentation/screens/categories.dart b/app/lib/features/bangs/presentation/screens/categories.dart new file mode 100644 index 00000000..c8d5398a --- /dev/null +++ b/app/lib/features/bangs/presentation/screens/categories.dart @@ -0,0 +1,90 @@ +import 'package:bang_navigator/core/routing/routes.dart'; +import 'package:bang_navigator/features/bangs/domain/providers.dart'; +import 'package:bang_navigator/presentation/widgets/failure_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class BangCategoriesScreen extends HookConsumerWidget { + const BangCategoriesScreen({super.key}); + @override + Widget build(BuildContext context, WidgetRef ref) { + final categoriesAsync = ref.watch(bangCategoriesProvider); + + return Scaffold( + appBar: AppBar( + title: const Text('Bang Categories'), + actions: [ + IconButton( + onPressed: () async { + await context.push(BangSearchRoute().location); + }, + icon: const Icon(Icons.search), + ), + ], + ), + body: categoriesAsync.when( + data: (categories) { + return SingleChildScrollView( + child: HookBuilder( + builder: (context) { + final expanded = useState({}); + + return ExpansionPanelList( + expansionCallback: (index, expand) { + final key = categories.keys.elementAt(index); + if (!expanded.value.contains(key)) { + expanded.value = {...expanded.value, key}; + } else { + expanded.value = {...expanded.value}..remove(key); + } + }, + children: categories.entries + .map( + (category) => ExpansionPanel( + canTapOnHeader: true, + isExpanded: expanded.value.contains(category.key), + headerBuilder: (context, isExpanded) => ListTile( + title: Text(category.key), + ), + body: Padding( + padding: const EdgeInsets.only(left: 16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: category.value + .map( + (subCategory) => ListTile( + title: Text(subCategory), + onTap: () async { + await context.push( + BangSubCategoryRoute( + category: category.key, + subCategory: subCategory, + ).location, + ); + }, + ), + ) + .toList(), + ), + ), + ), + ) + .toList(), + ); + }, + ), + ); + }, + error: (error, stackTrace) => Center( + child: FailureWidget( + title: 'Failed to load Bang Categories', + exception: error, + ), + ), + loading: () => const Center(child: CircularProgressIndicator()), + ), + ); + } +} diff --git a/app/lib/features/bangs/presentation/screens/list.dart b/app/lib/features/bangs/presentation/screens/list.dart new file mode 100644 index 00000000..854bc001 --- /dev/null +++ b/app/lib/features/bangs/presentation/screens/list.dart @@ -0,0 +1,77 @@ +import 'package:bang_navigator/core/routing/routes.dart'; +import 'package:bang_navigator/features/bangs/domain/providers.dart'; +import 'package:bang_navigator/features/bangs/presentation/widgets/bang_details.dart'; +import 'package:bang_navigator/features/search_browser/domain/entities/modes.dart'; +import 'package:bang_navigator/features/search_browser/domain/entities/sheet.dart'; +import 'package:bang_navigator/features/search_browser/domain/providers.dart'; +import 'package:bang_navigator/presentation/widgets/failure_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class BangListScreen extends HookConsumerWidget { + final String? category; + final String? subCategory; + + const BangListScreen({this.category, this.subCategory, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final bangsAsync = ref.watch( + bangDataListProvider( + filter: ( + categoryFilter: (category != null) + ? (category: category!, subCategory: subCategory) + : null, + domain: null, + groups: null + ), + ), + ); + + return Scaffold( + body: CustomScrollView( + slivers: [ + SliverAppBar.medium( + title: Text('$category: $subCategory'), + ), + bangsAsync.when( + data: (bangs) { + return SliverList.builder( + itemCount: bangs.length, + itemBuilder: (context, index) { + final bang = bangs[index]; + return BangDetails( + bang, + onTap: () { + ref + .read(selectedBangTriggerProvider().notifier) + .setTrigger(bang.trigger); + + if (ref.read(bottomSheetProvider) is! CreateTab) { + ref.read(bottomSheetProvider.notifier).show( + CreateTab( + preferredTool: KagiTool.search, + ), + ); + } + + context.go(KagiRoute().location); + }, + ); + }, + ); + }, + error: (error, stackTrace) => Center( + child: FailureWidget( + title: 'Failed to load Bangs', + exception: error, + ), + ), + loading: () => const Center(child: CircularProgressIndicator()), + ), + ], + ), + ); + } +} diff --git a/app/lib/features/search_browser/domain/providers.dart b/app/lib/features/search_browser/domain/providers.dart index d9bedfce..54353bd2 100644 --- a/app/lib/features/search_browser/domain/providers.dart +++ b/app/lib/features/search_browser/domain/providers.dart @@ -79,14 +79,15 @@ class SelectedBangTrigger extends _$SelectedBangTrigger { } @override - String? build() { + String? build({String? domain}) { return null; } } @Riverpod() -Stream selectedBangData(SelectedBangDataRef ref) { +Stream selectedBangData(SelectedBangDataRef ref, {String? domain}) { final repository = ref.watch(bangDataRepositoryProvider.notifier); - final selectedBangTrigger = ref.watch(selectedBangTriggerProvider); + final selectedBangTrigger = + ref.watch(selectedBangTriggerProvider(domain: domain)); return repository.watchBang(selectedBangTrigger); } diff --git a/app/lib/features/search_browser/domain/providers.g.dart b/app/lib/features/search_browser/domain/providers.g.dart index ee1a07ee..0ccb9939 100644 --- a/app/lib/features/search_browser/domain/providers.g.dart +++ b/app/lib/features/search_browser/domain/providers.g.dart @@ -6,21 +6,156 @@ part of 'providers.dart'; // RiverpodGenerator // ************************************************************************** -String _$selectedBangDataHash() => r'619555a048e9d38602ceffa42dae1ba7d68ced89'; +String _$selectedBangDataHash() => r'40dd3c51694394909fe83659ff3e19d51a06ec55'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} /// See also [selectedBangData]. @ProviderFor(selectedBangData) -final selectedBangDataProvider = AutoDisposeStreamProvider.internal( - selectedBangData, - name: r'selectedBangDataProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$selectedBangDataHash, - dependencies: null, - allTransitiveDependencies: null, -); +const selectedBangDataProvider = SelectedBangDataFamily(); + +/// See also [selectedBangData]. +class SelectedBangDataFamily extends Family> { + /// See also [selectedBangData]. + const SelectedBangDataFamily(); + + /// See also [selectedBangData]. + SelectedBangDataProvider call({ + String? domain, + }) { + return SelectedBangDataProvider( + domain: domain, + ); + } + + @override + SelectedBangDataProvider getProviderOverride( + covariant SelectedBangDataProvider provider, + ) { + return call( + domain: provider.domain, + ); + } + + 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'selectedBangDataProvider'; +} + +/// See also [selectedBangData]. +class SelectedBangDataProvider extends AutoDisposeStreamProvider { + /// See also [selectedBangData]. + SelectedBangDataProvider({ + String? domain, + }) : this._internal( + (ref) => selectedBangData( + ref as SelectedBangDataRef, + domain: domain, + ), + from: selectedBangDataProvider, + name: r'selectedBangDataProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$selectedBangDataHash, + dependencies: SelectedBangDataFamily._dependencies, + allTransitiveDependencies: + SelectedBangDataFamily._allTransitiveDependencies, + domain: domain, + ); + + SelectedBangDataProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.domain, + }) : super.internal(); + + final String? domain; + + @override + Override overrideWith( + Stream Function(SelectedBangDataRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: SelectedBangDataProvider._internal( + (ref) => create(ref as SelectedBangDataRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + domain: domain, + ), + ); + } + + @override + AutoDisposeStreamProviderElement createElement() { + return _SelectedBangDataProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SelectedBangDataProvider && other.domain == domain; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, domain.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin SelectedBangDataRef on AutoDisposeStreamProviderRef { + /// The parameter `domain` of this provider. + String? get domain; +} + +class _SelectedBangDataProviderElement + extends AutoDisposeStreamProviderElement + with SelectedBangDataRef { + _SelectedBangDataProviderElement(super.provider); + + @override + String? get domain => (origin as SelectedBangDataProvider).domain; +} -typedef SelectedBangDataRef = AutoDisposeStreamProviderRef; String _$overlayDialogHash() => r'7a0376fff0ba12c70a257a47391e7c049dabd36d'; /// See also [OverlayDialog]. @@ -69,21 +204,146 @@ final bottomSheetExtendProvider = typedef _$BottomSheetExtend = StreamNotifier; String _$selectedBangTriggerHash() => - r'd110e4f8bd9d362e0cc54ee56a4f247d0870c760'; + r'b0e12bc95e93d50d04f1c658230cea9f15ff0385'; + +abstract class _$SelectedBangTrigger extends BuildlessNotifier { + late final String? domain; + + String? build({ + String? domain, + }); +} /// See also [SelectedBangTrigger]. @ProviderFor(SelectedBangTrigger) -final selectedBangTriggerProvider = - NotifierProvider.internal( - SelectedBangTrigger.new, - name: r'selectedBangTriggerProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$selectedBangTriggerHash, - dependencies: null, - allTransitiveDependencies: null, -); +const selectedBangTriggerProvider = SelectedBangTriggerFamily(); -typedef _$SelectedBangTrigger = Notifier; +/// See also [SelectedBangTrigger]. +class SelectedBangTriggerFamily extends Family { + /// See also [SelectedBangTrigger]. + const SelectedBangTriggerFamily(); + + /// See also [SelectedBangTrigger]. + SelectedBangTriggerProvider call({ + String? domain, + }) { + return SelectedBangTriggerProvider( + domain: domain, + ); + } + + @override + SelectedBangTriggerProvider getProviderOverride( + covariant SelectedBangTriggerProvider provider, + ) { + return call( + domain: provider.domain, + ); + } + + 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'selectedBangTriggerProvider'; +} + +/// See also [SelectedBangTrigger]. +class SelectedBangTriggerProvider + extends NotifierProviderImpl { + /// See also [SelectedBangTrigger]. + SelectedBangTriggerProvider({ + String? domain, + }) : this._internal( + () => SelectedBangTrigger()..domain = domain, + from: selectedBangTriggerProvider, + name: r'selectedBangTriggerProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$selectedBangTriggerHash, + dependencies: SelectedBangTriggerFamily._dependencies, + allTransitiveDependencies: + SelectedBangTriggerFamily._allTransitiveDependencies, + domain: domain, + ); + + SelectedBangTriggerProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.domain, + }) : super.internal(); + + final String? domain; + + @override + String? runNotifierBuild( + covariant SelectedBangTrigger notifier, + ) { + return notifier.build( + domain: domain, + ); + } + + @override + Override overrideWith(SelectedBangTrigger Function() create) { + return ProviderOverride( + origin: this, + override: SelectedBangTriggerProvider._internal( + () => create()..domain = domain, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + domain: domain, + ), + ); + } + + @override + NotifierProviderElement createElement() { + return _SelectedBangTriggerProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SelectedBangTriggerProvider && other.domain == domain; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, domain.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin SelectedBangTriggerRef on NotifierProviderRef { + /// The parameter `domain` of this provider. + String? get domain; +} + +class _SelectedBangTriggerProviderElement + extends NotifierProviderElement + with SelectedBangTriggerRef { + _SelectedBangTriggerProviderElement(super.provider); + + @override + String? get domain => (origin as SelectedBangTriggerProvider).domain; +} // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member