diff --git a/lib/controls/autocomplete/hashtag_autocomplete_options.dart b/lib/controls/autocomplete/hashtag_autocomplete_options.dart index 0fc09ce..0f8a15f 100644 --- a/lib/controls/autocomplete/hashtag_autocomplete_options.dart +++ b/lib/controls/autocomplete/hashtag_autocomplete_options.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:provider/provider.dart'; -import '../../globals.dart'; +import '../../riverpod_controllers/hashtag_service.dart'; import '../../services/entry_manager_service.dart'; -import '../../services/hashtag_service.dart'; import '../../utils/active_profile_selector.dart'; -class HashtagAutocompleteOptions extends StatelessWidget { +class HashtagAutocompleteOptions extends ConsumerWidget { const HashtagAutocompleteOptions({ super.key, required this.id, @@ -19,7 +19,7 @@ class HashtagAutocompleteOptions extends StatelessWidget { final ValueSetter onHashtagTap; @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final manager = context .read>() .activeEntry @@ -27,7 +27,7 @@ class HashtagAutocompleteOptions extends StatelessWidget { final postTreeHashtags = manager.getPostTreeHashtags(id).getValueOrElse(() => [])..sort(); final hashtagsFromService = - getIt().getMatchingHashTags(query); + ref.watch(hashtagServiceProvider(searchString: query)); final hashtags = [...postTreeHashtags, ...hashtagsFromService]; if (hashtags.isEmpty) return const SizedBox.shrink(); diff --git a/lib/di_initialization.dart b/lib/di_initialization.dart index a97affc..8b60b59 100644 --- a/lib/di_initialization.dart +++ b/lib/di_initialization.dart @@ -15,6 +15,7 @@ import 'friendica_client/friendica_client.dart'; import 'globals.dart'; import 'models/auth/profile.dart'; import 'models/instance_info.dart'; +import 'riverpod_controllers/hashtag_service.dart'; import 'services/auth_service.dart'; import 'services/blocks_manager.dart'; import 'services/connections_manager.dart'; @@ -24,7 +25,6 @@ import 'services/feature_version_checker.dart'; import 'services/fediverse_server_validator.dart'; import 'services/follow_requests_manager.dart'; import 'services/gallery_service.dart'; -import 'services/hashtag_service.dart'; import 'services/interactions_manager.dart'; import 'services/network_status_service.dart'; import 'services/notifications_manager.dart'; @@ -66,7 +66,6 @@ Future dependencyInjectionInitialization() async { final objectBoxCache = await ObjectBoxCache.create(); getIt.registerSingleton(objectBoxCache); getIt.registerSingleton(ObjectBoxHashtagRepo()); - getIt.registerSingleton(HashtagService()); getIt.registerSingleton(NetworkStatusService()); getIt.registerSingleton( FediverseServiceValidator()); @@ -196,7 +195,9 @@ void clearCaches() { _logger.severe('Error clearing GalleryService Repo: $error'), ); - getIt().clear(); + rootRiverpodProviderContainer + ?.read(hashtagServiceProvider().notifier) + .clear(); getIt>().activeEntry.match( onSuccess: (manager) => manager.clear(), diff --git a/lib/globals.dart b/lib/globals.dart index 7642b10..6a4f636 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:get_it/get_it.dart'; import 'package:uuid/uuid.dart'; @@ -32,6 +33,8 @@ const processingSleep = Duration(milliseconds: 1); const apiCallTimeout = Duration(seconds: 60); const oauthTimeout = Duration(seconds: 15); +ProviderContainer? rootRiverpodProviderContainer; + Future showConfirmDialog(BuildContext context, String caption) { return showDialog( context: context, diff --git a/lib/main.dart b/lib/main.dart index 305ea9a..30345c2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,7 +19,6 @@ import 'services/direct_message_service.dart'; import 'services/entry_manager_service.dart'; import 'services/follow_requests_manager.dart'; import 'services/gallery_service.dart'; -import 'services/hashtag_service.dart'; import 'services/interactions_manager.dart'; import 'services/notifications_manager.dart'; import 'services/setting_service.dart'; @@ -30,7 +29,6 @@ import 'utils/active_profile_selector.dart'; import 'utils/app_scrolling_behavior.dart'; import 'utils/old_android_letsencrypte_cert.dart'; -fr.ProviderContainer? rootRiverpodProviderContainer; final preInitializationLogEventQueue = []; void main() async { @@ -147,10 +145,6 @@ class _AppState extends fr.ConsumerState { create: (_) => getIt>(), lazy: true, ), - ChangeNotifierProvider( - create: (_) => getIt(), - lazy: true, - ), ChangeNotifierProvider>( create: (_) => getIt>(), ), diff --git a/lib/riverpod_controllers/hashtag_service.dart b/lib/riverpod_controllers/hashtag_service.dart new file mode 100644 index 0000000..76f02ee --- /dev/null +++ b/lib/riverpod_controllers/hashtag_service.dart @@ -0,0 +1,31 @@ +import 'package:relatica/data/interfaces/hashtag_repo_intf.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import '../data/objectbox/objectbox_hashtag_repo.dart'; +import '../models/hashtag.dart'; + +part 'hashtag_service.g.dart'; + +@Riverpod(keepAlive: true) +IHashtagRepo _hashtagRepo(_HashtagRepoRef ref) { + return ObjectBoxHashtagRepo(); +} + +@riverpod +class HashtagService extends _$HashtagService { + @override + List build({String searchString = ''}) { + final repo = ref.watch(_hashtagRepoProvider); + return repo.getMatchingHashTags(searchString); + } + + Future clear() async { + await ref.read(_hashtagRepoProvider).clear(); + ref.invalidateSelf(); + } + + void add(Hashtag tag) { + ref.read(_hashtagRepoProvider).add(tag); + ref.invalidateSelf(); + } +} diff --git a/lib/riverpod_controllers/hashtag_service.g.dart b/lib/riverpod_controllers/hashtag_service.g.dart new file mode 100644 index 0000000..48ad7a8 --- /dev/null +++ b/lib/riverpod_controllers/hashtag_service.g.dart @@ -0,0 +1,189 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'hashtag_service.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$hashtagRepoHash() => r'8ee41e763536af28769739a977568f5fdcec7b41'; + +/// See also [_hashtagRepo]. +@ProviderFor(_hashtagRepo) +final _hashtagRepoProvider = Provider.internal( + _hashtagRepo, + name: r'_hashtagRepoProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$hashtagRepoHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _HashtagRepoRef = ProviderRef; +String _$hashtagServiceHash() => r'ca0480f1f691248f0dabf233f0e4d190bf3610fc'; + +/// 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)); + } +} + +abstract class _$HashtagService + extends BuildlessAutoDisposeNotifier> { + late final String searchString; + + List build({ + String searchString = '', + }); +} + +/// See also [HashtagService]. +@ProviderFor(HashtagService) +const hashtagServiceProvider = HashtagServiceFamily(); + +/// See also [HashtagService]. +class HashtagServiceFamily extends Family> { + /// See also [HashtagService]. + const HashtagServiceFamily(); + + /// See also [HashtagService]. + HashtagServiceProvider call({ + String searchString = '', + }) { + return HashtagServiceProvider( + searchString: searchString, + ); + } + + @override + HashtagServiceProvider getProviderOverride( + covariant HashtagServiceProvider provider, + ) { + return call( + searchString: provider.searchString, + ); + } + + 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'hashtagServiceProvider'; +} + +/// See also [HashtagService]. +class HashtagServiceProvider + extends AutoDisposeNotifierProviderImpl> { + /// See also [HashtagService]. + HashtagServiceProvider({ + String searchString = '', + }) : this._internal( + () => HashtagService()..searchString = searchString, + from: hashtagServiceProvider, + name: r'hashtagServiceProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$hashtagServiceHash, + dependencies: HashtagServiceFamily._dependencies, + allTransitiveDependencies: + HashtagServiceFamily._allTransitiveDependencies, + searchString: searchString, + ); + + HashtagServiceProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.searchString, + }) : super.internal(); + + final String searchString; + + @override + List runNotifierBuild( + covariant HashtagService notifier, + ) { + return notifier.build( + searchString: searchString, + ); + } + + @override + Override overrideWith(HashtagService Function() create) { + return ProviderOverride( + origin: this, + override: HashtagServiceProvider._internal( + () => create()..searchString = searchString, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + searchString: searchString, + ), + ); + } + + @override + AutoDisposeNotifierProviderElement> + createElement() { + return _HashtagServiceProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is HashtagServiceProvider && + other.searchString == searchString; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, searchString.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin HashtagServiceRef on AutoDisposeNotifierProviderRef> { + /// The parameter `searchString` of this provider. + String get searchString; +} + +class _HashtagServiceProviderElement + extends AutoDisposeNotifierProviderElement> + with HashtagServiceRef { + _HashtagServiceProviderElement(super.provider); + + @override + String get searchString => (origin as HashtagServiceProvider).searchString; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/serializers/mastodon/timeline_entry_mastodon_extensions.dart b/lib/serializers/mastodon/timeline_entry_mastodon_extensions.dart index ce274e7..13a99d8 100644 --- a/lib/serializers/mastodon/timeline_entry_mastodon_extensions.dart +++ b/lib/serializers/mastodon/timeline_entry_mastodon_extensions.dart @@ -7,9 +7,9 @@ import '../../models/link_data.dart'; import '../../models/location_data.dart'; import '../../models/timeline_entry.dart'; import '../../models/visibility.dart'; +import '../../riverpod_controllers/hashtag_service.dart'; import '../../services/auth_service.dart'; import '../../services/connections_manager.dart'; -import '../../services/hashtag_service.dart'; import '../../services/reshared_via_service.dart'; import '../../utils/active_profile_selector.dart'; import '../../utils/dateutils.dart'; @@ -133,11 +133,13 @@ extension TimelineEntryMastodonExtensions on TimelineEntry { final List? tagsJson = json['tags']; final tags = []; if (tagsJson?.isNotEmpty ?? false) { - final tagManager = getIt(); + final tagManager = rootRiverpodProviderContainer + ?.read(hashtagServiceProvider().notifier); + for (final tagJson in tagsJson!) { final tag = HashtagMastodonExtensions.fromJson(tagJson); tags.add(tag.tag); - tagManager.add(tag); + tagManager?.add(tag); } } diff --git a/lib/services/hashtag_service.dart b/lib/services/hashtag_service.dart deleted file mode 100644 index 27baa45..0000000 --- a/lib/services/hashtag_service.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/foundation.dart'; - -import '../data/interfaces/hashtag_repo_intf.dart'; -import '../globals.dart'; -import '../models/hashtag.dart'; - -class HashtagService extends ChangeNotifier { - late final IHashtagRepo repo; - - HashtagService() { - repo = getIt(); - } - - Future clear() async { - await repo.clear(); - notifyListeners(); - } - - void add(Hashtag tag) { - repo.add(tag); - notifyListeners(); - } - - List getMatchingHashTags(String searchString) { - return repo.getMatchingHashTags(searchString); - } -}