diff --git a/packages/fl_query/.flutter-plugins-dependencies b/packages/fl_query/.flutter-plugins-dependencies index a7e775e..016a43e 100644 --- a/packages/fl_query/.flutter-plugins-dependencies +++ b/packages/fl_query/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6+1/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6+1/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.3/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]}],"date_created":"2022-09-14 11:35:43.874010","version":"3.3.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6+1/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6+1/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.3/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]}],"date_created":"2022-09-22 21:58:17.052046","version":"3.3.0"} \ No newline at end of file diff --git a/packages/fl_query/example/.flutter-plugins-dependencies b/packages/fl_query/example/.flutter-plugins-dependencies index f2726d6..fa99993 100644 --- a/packages/fl_query/example/.flutter-plugins-dependencies +++ b/packages/fl_query/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.3/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]}],"date_created":"2022-09-19 10:39:45.071010","version":"3.3.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.3/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]}],"date_created":"2022-09-22 20:53:14.912483","version":"3.3.0"} \ No newline at end of file diff --git a/packages/fl_query/example/lib/components/basic_query.dart b/packages/fl_query/example/lib/components/basic_query.dart index 19d6e20..736a6d3 100644 --- a/packages/fl_query/example/lib/components/basic_query.dart +++ b/packages/fl_query/example/lib/components/basic_query.dart @@ -3,6 +3,8 @@ import 'dart:math'; import 'package:fl_query/fl_query.dart'; import 'package:flutter/material.dart'; +final bowl = QueryBowl(); + final successJob = QueryJob( queryKey: "greetings-example", task: (queryKey, _) => Future.delayed( diff --git a/packages/fl_query/example/lib/main.dart b/packages/fl_query/example/lib/main.dart index db9aa1b..bdddd44 100644 --- a/packages/fl_query/example/lib/main.dart +++ b/packages/fl_query/example/lib/main.dart @@ -1,15 +1,17 @@ import 'package:fl_query_example/components/basic_infinite_query.dart'; import 'package:fl_query_example/components/basic_mutation.dart'; +import 'package:fl_query/fl_query.dart'; import 'package:fl_query_example/components/basic_query.dart'; import 'package:fl_query_example/components/lazy_query.dart'; import 'package:fl_query_example/components/mutation_variable_key.dart'; import 'package:fl_query_example/components/query_external_data.dart'; import 'package:fl_query_example/components/query_previous_data.dart'; import 'package:fl_query_example/components/query_variable_key.dart'; -import 'package:fl_query/fl_query.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; void main() { + debugRepaintRainbowEnabled = true; runApp(const MyApp()); } @@ -19,6 +21,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return QueryBowlScope( + bowl: QueryBowl(), child: MaterialApp( // showPerformanceOverlay: true, title: 'Flutter Demo', diff --git a/packages/fl_query/lib/src/base_operation.dart b/packages/fl_query/lib/src/base_operation.dart index 03978d8..f744dff 100644 --- a/packages/fl_query/lib/src/base_operation.dart +++ b/packages/fl_query/lib/src/base_operation.dart @@ -1,4 +1,3 @@ -import 'package:fl_query/src/query_bowl.dart'; import 'package:flutter/widgets.dart'; abstract class BaseOperation extends ChangeNotifier { @@ -27,7 +26,7 @@ abstract class BaseOperation extends ChangeNotifier { /// storage/cache Set> _mounts = {}; - final QueryBowl queryBowl; + final queryBowl; BaseOperation({ required this.cacheTime, diff --git a/packages/fl_query/lib/src/base_query.dart b/packages/fl_query/lib/src/base_query.dart index 33a92a4..8b0058e 100644 --- a/packages/fl_query/lib/src/base_query.dart +++ b/packages/fl_query/lib/src/base_query.dart @@ -254,22 +254,33 @@ abstract class BaseQuery bool? refetchOnMount, bool? refetchOnReconnect, }) { + bool updated = false; if (this.refetchInterval == null && refetchInterval != null && refetchInterval != Duration.zero) { this.refetchInterval = refetchInterval; _refetchIntervalTimer?.cancel(); _refetchIntervalTimer = createRefetchTimer(); + updated = true; } - if (this.cacheTime == Duration(minutes: 5) && cacheTime != null) + if (this.cacheTime == Duration(minutes: 5) && cacheTime != null) { this.cacheTime = cacheTime; + updated = true; + } if (this._staleTime == const Duration(milliseconds: 500) && - staleTime != null) this._staleTime = staleTime; - if (this.refetchOnMount == null && refetchOnMount != null) + staleTime != null) { + this._staleTime = staleTime; + updated = true; + } + if (this.refetchOnMount == null && refetchOnMount != null) { this.refetchOnMount = refetchOnMount; - if (this.refetchOnReconnect == null && refetchOnReconnect != null) + updated = true; + } + if (this.refetchOnReconnect == null && refetchOnReconnect != null) { this.refetchOnReconnect = refetchOnReconnect; - notifyListeners(); + updated = true; + } + if (updated) notifyListeners(); } /// checks if the application is connected to internet in any mean diff --git a/packages/fl_query/lib/src/infinite_query_builder.dart b/packages/fl_query/lib/src/infinite_query_builder.dart index 973174b..5c24a97 100644 --- a/packages/fl_query/lib/src/infinite_query_builder.dart +++ b/packages/fl_query/lib/src/infinite_query_builder.dart @@ -42,11 +42,23 @@ class _InfiniteQueryBuilderState(uuid.v4()); - WidgetsBinding.instance.addPostFrameCallback((_) => init()); + WidgetsBinding.instance.addPostFrameCallback((_) { + init(); + QueryBowl.of(context).onInfiniteQueriesUpdate( + (infiniteQuery) { + if (infiniteQuery.queryKey != widget.job.queryKey) return; + if (mounted) + setState(() { + this.infiniteQuery = infiniteQuery; + }); + }, + ); + }); } void init([T? previousData]) async { final bowl = QueryBowl.of(context); + infiniteQuery = bowl.addInfiniteQuery( widget.job, externalData: widget.externalData, diff --git a/packages/fl_query/lib/src/mutation_builder.dart b/packages/fl_query/lib/src/mutation_builder.dart index 2afc262..a659f58 100644 --- a/packages/fl_query/lib/src/mutation_builder.dart +++ b/packages/fl_query/lib/src/mutation_builder.dart @@ -37,8 +37,6 @@ class MutationBuilder extends StatefulWidget { class _MutationBuilderState extends State> { - late QueryBowl queryBowl; - late ValueKey uKey; Mutation? mutation; @@ -47,18 +45,32 @@ class _MutationBuilderState void initState() { super.initState(); uKey = ValueKey(uuid.v4()); - WidgetsBinding.instance.addPostFrameCallback(init); + WidgetsBinding.instance.addPostFrameCallback((_) { + init(); + QueryBowl.of(context).onMutationsUpdate( + (mutation) { + if (mutation.mutationKey != widget.job.mutationKey || !mounted) + return; + setState(() { + this.mutation = mutation; + }); + }, + ); + }); } void init([_]) { - queryBowl = QueryBowl.of(context); - mutation = queryBowl.addMutation( - widget.job, - onData: widget.onData, - onError: widget.onError, - onMutate: widget.onMutate, - key: uKey, - ); + final bowl = QueryBowl.of(context); + + setState(() { + mutation = bowl.addMutation( + widget.job, + onData: widget.onData, + onError: widget.onError, + onMutate: widget.onMutate, + key: uKey, + ); + }); } @override @@ -99,10 +111,7 @@ class _MutationBuilderState @override Widget build(BuildContext context) { - queryBowl = QueryBowl.of(context); - final latestMutation = - queryBowl.getMutation(widget.job.mutationKey) ?? mutation; - if (latestMutation == null) return Container(); - return widget.builder(context, latestMutation); + if (mutation == null) return Container(); + return widget.builder(context, mutation!); } } diff --git a/packages/fl_query/lib/src/query_bowl.dart b/packages/fl_query/lib/src/query_bowl.dart index a455740..86a556e 100644 --- a/packages/fl_query/lib/src/query_bowl.dart +++ b/packages/fl_query/lib/src/query_bowl.dart @@ -1,43 +1,35 @@ -import 'dart:async'; - import 'package:connectivity_plus/connectivity_plus.dart'; -import 'package:fl_query/src/infinite_query.dart'; -import 'package:fl_query/src/models/infinite_query_job.dart'; -import 'package:fl_query/src/models/mutation_job.dart'; -import 'package:fl_query/src/models/query_job.dart'; -import 'package:fl_query/src/mutation.dart'; -import 'package:fl_query/src/mutation_builder.dart'; -import 'package:fl_query/src/query.dart'; +import 'package:fl_query/fl_query.dart'; +import 'package:fl_query/src/query_cache.dart'; import 'package:fl_query/src/utils.dart'; +import 'package:flutter/cupertino.dart'; import 'package:collection/collection.dart'; -import 'package:flutter/widgets.dart'; -/// The widget that holds & provides every [Query] & [Mutation] to your +/// The widget that holds every [Query] & [Mutation] to your /// entire Flutter application in anywhere -/// This must be used on the above any other widget +/// [QueryBowl] provides an imperative way to handle all the query & +/// mutation related methods & properties. +/// Its responsible or can be used for (not recommended) creating, +/// updating & deleting queries & mutations +/// +/// This must be used along with [QueryBowlScope] /// /// ```dart /// Widget build(BuildContext context) { /// return QueryBowlScope( +/// bowl: QueryBowl(), /// child: MaterialApp(/*...other stuff...*/), /// ); /// } /// ``` /// -class QueryBowlScope extends StatefulWidget { - final Widget child; - +class QueryBowl { /// global stale time /// /// Makes [Query.data] stale after crossing the duration of provided /// [staleTime] final Duration staleTime; - /// global cache time - /// - /// Removes inactive queries after provided duration of [cacheTime] - final Duration cacheTime; - // refetching options /// refetch query when new query instance mounts @@ -73,10 +65,19 @@ class QueryBowlScope extends StatefulWidget { /// If none is supplied then half of the value of staleTime is used final Duration refetchInterval; - const QueryBowlScope({ - required this.child, + /// The Cache that holds all the queries, mutations and infinite queries + QueryCache cache; + + QueryBowl({ + /// The Cache that holds all the queries, mutations and infinite + /// queries + QueryCache? cache, this.staleTime = Duration.zero, - this.cacheTime = const Duration(minutes: 5), + + /// global cache time + /// + /// Removes inactive queries after provided duration of [cacheTime] + Duration? cacheTime, this.refetchInterval = Duration.zero, this.refetchOnMount = false, this.refetchOnReconnect = true, @@ -84,496 +85,29 @@ class QueryBowlScope extends StatefulWidget { this.refetchOnApplicationResume = true, this.refetchOnWindowFocus = true, this.refetchOnExternalDataChange = false, - Key? key, - }) : super(key: key); - - @override - State createState() => _QueryBowlScopeState(); -} - -class _QueryBowlScopeState extends State { - late Set infiniteQueries; - late Set queries; - late Set mutations; - - StreamSubscription? _connectionStatusSubscription; - - @override - void initState() { - super.initState(); - infiniteQueries = {}; - queries = {}; - mutations = {}; - - _connectionStatusSubscription = Connectivity() + }) : cache = cache ?? QueryCache(cacheTime: cacheTime) { + Connectivity() .onConnectivityChanged .listen((ConnectivityResult result) async { if (isConnectedToInternet(result)) { - for (final query in queries) { + for (final query in this.cache.queries) { if (query.refetchOnReconnect == false || !query.enabled) continue; await query.refetch(); - await Future.delayed(widget.refetchOnReconnectDelay); + await Future.delayed(refetchOnReconnectDelay); } - for (final infiniteQuery in infiniteQueries) { + for (final infiniteQuery in this.cache.infiniteQueries) { if (infiniteQuery.refetchOnReconnect == false || !infiniteQuery.enabled) continue; await infiniteQuery.refetchPages(); - await Future.delayed(widget.refetchOnReconnectDelay); + await Future.delayed(refetchOnReconnectDelay); } } }); } - @override - void dispose() { - _disposeUpdateListeners(); - _connectionStatusSubscription?.cancel(); - super.dispose(); - } - - void _listenToUpdates() { - for (final infiniteQuery in infiniteQueries) { - infiniteQuery.addListener(() => updateInfiniteQueries(infiniteQuery)); - } - for (final query in queries) { - query.addListener(() => updateQueries(query)); - } - for (final mutation in mutations) { - mutation.addListener(() => updateMutations(mutation)); - } - } - - void _disposeUpdateListeners() { - for (final infiniteQuery in infiniteQueries) { - infiniteQuery.removeListener(() => updateInfiniteQueries(infiniteQuery)); - } - for (final query in queries) { - query.removeListener(() => updateQueries(query)); - } - for (final mutation in mutations) { - mutation.removeListener(() => updateMutations(mutation)); - } - } - - void updateQueries(Query query) { - WidgetsBinding.instance.addPostFrameCallback((_) { - // checking & not including inactive queries - // basically garbage collecting queries - setState(() { - queries = Set.from( - query.isInactive - ? queries.where((el) => el.queryKey != query.queryKey) - : queries, - ); - }); - }); - } - - void updateInfiniteQueries(InfiniteQuery infiniteQuery) { - WidgetsBinding.instance.addPostFrameCallback((_) { - // checking & not including inactive queries - // basically garbage collecting queries - setState(() { - infiniteQueries = Set.from( - infiniteQuery.isInactive - ? infiniteQueries - .where((el) => el.queryKey != infiniteQuery.queryKey) - : infiniteQueries, - ); - }); - }); - } - - void updateMutations(Mutation mutation) { - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - // checking & not including inactive mutations - // basically garbage collecting mutations - mutations = Set.from( - mutation.isInactive - ? mutations.where( - (el) => el.mutationKey != mutation.mutationKey, - ) - : mutations, - ); - }); - }); - } - - void addInfiniteQuery( - InfiniteQuery infiniteQuery) { - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - infiniteQueries = Set.from({...infiniteQueries, infiniteQuery}); - }); - }); - } - - void addQuery(Query query) { - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - queries = Set.from({...queries, query}); - }); - }); - } - - void addMutation(Mutation mutation) { - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - mutations = Set.from({...mutations, mutation}); - }); - }); - } - - int removeQueries(List queryKeys) { - int count = 0; - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - mutations = Set.from( - queries.whereNot((query) { - final isAboutToRip = queryKeys.contains(query.queryKey); - if (isAboutToRip) count++; - return isAboutToRip; - }), - ); - }); - }); - return count; - } - - void clear() { - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - queries = Set(); - mutations = Set(); - }); - }); - } - - @override - Widget build(BuildContext context) { - _disposeUpdateListeners(); - _listenToUpdates(); - return QueryBowl( - addInfiniteQuery: addInfiniteQuery, - addQuery: addQuery, - addMutation: addMutation, - removeQueries: removeQueries, - clear: clear, - infiniteQueries: infiniteQueries, - queries: queries, - mutations: mutations, - staleTime: widget.staleTime, - cacheTime: widget.cacheTime, - refetchInterval: widget.refetchInterval, - refetchOnMount: widget.refetchOnMount, - refetchOnReconnect: widget.refetchOnReconnect, - refetchOnExternalDataChange: widget.refetchOnExternalDataChange, - child: widget.child, - ); - } -} - -/// QueryBowl provides an imperative way to handle all the query & -/// mutation related methods & properties. -/// -/// Its responsible or can be used for (not recommended) creating, -/// updating & deleting queries & mutations -class QueryBowl extends InheritedWidget { - final Set _infiniteQueries; - final Set _queries; - final Set _mutations; - final Duration staleTime; - final Duration cacheTime; - - final Duration? refetchInterval; - final bool refetchOnMount; - final bool refetchOnReconnect; - final bool refetchOnExternalDataChange; - - final void Function( - InfiniteQuery infiniteQuery) _addInfiniteQuery; - - final void Function(Query query) - _addQuery; - - final void Function(Mutation mutation) - _addMutation; - - final int Function(List) removeQueries; - - final void Function() clear; - - const QueryBowl({ - required Widget child, - required final void Function( - InfiniteQuery infiniteQuery) - addInfiniteQuery, - required final void Function( - Query query) - addQuery, - required final void Function(Mutation mutation) - addMutation, - required final Set infiniteQueries, - required final Set queries, - required final Set mutations, - required this.staleTime, - required this.cacheTime, - required this.removeQueries, - required this.clear, - required this.refetchOnMount, - required this.refetchOnReconnect, - required this.refetchOnExternalDataChange, - this.refetchInterval, - Key? key, - }) : _addQuery = addQuery, - _queries = queries, - _mutations = mutations, - _addMutation = addMutation, - _addInfiniteQuery = addInfiniteQuery, - _infiniteQueries = infiniteQueries, - super(child: child, key: key); - - Query _createQueryWithDefaults( - QueryJob options, - Outside externalData, [ - T? previousData, - ]) { - final query = Query.fromOptions( - options, - externalData: externalData, - previousData: previousData, - queryBowl: this, - ); - query.updateDefaultOptions( - cacheTime: cacheTime, - staleTime: staleTime, - refetchInterval: refetchInterval, - refetchOnMount: refetchOnMount, - refetchOnReconnect: refetchOnReconnect, - ); - return query; - } - - InfiniteQuery _createInfiniteQueryWithDefaults< - T extends Object, Outside, PageParam extends Object>( - InfiniteQueryJob options, - Outside externalData, - ) { - final infiniteQuery = InfiniteQuery.fromOptions( - options, - externalData: externalData, - queryBowl: this, - ); - infiniteQuery.updateDefaultOptions( - cacheTime: cacheTime, - staleTime: staleTime, - refetchInterval: refetchInterval, - refetchOnMount: refetchOnMount, - refetchOnReconnect: refetchOnReconnect, - ); - return infiniteQuery; - } - - Future prefetchQuery( - QueryJob options, { - required Outside externalData, - }) async { - final prevQuery = - _queries.firstWhereOrNull((q) => q.queryKey == options.queryKey); - if (prevQuery != null && prevQuery is Query) - return prevQuery.data; - - final query = _createQueryWithDefaults(options, externalData); - _addQuery(query); - return await query.fetch(); - } - - /// !⚠️**Warning** only for internal library usage - @protected - Future fetchQuery( - QueryJob options, { - required Outside externalData, - final QueryListener? onData, - final QueryListener? onError, - required ValueKey key, - }) async { - final prevQuery = - _queries.firstWhereOrNull((q) => q.queryKey == options.queryKey); - if (prevQuery is Query) { - // run the query if its still not called or if externalData has - // changed - final hasExternalDataChanged = prevQuery.prevUsedExternalData != null && - externalData != null && - !isShallowEqual( - prevQuery.prevUsedExternalData!, - externalData, - ); - prevQuery.mount(key); - if (onData != null) prevQuery.addDataListener(onData); - if (onError != null) prevQuery.addErrorListener(onError); - if (!prevQuery.hasData || hasExternalDataChanged) { - if (hasExternalDataChanged) prevQuery.setExternalData(externalData); - - return await prevQuery.refetch(); - } - // mounting the widget that is using the query in the prevQuery - return prevQuery.data; - } - - final query = _createQueryWithDefaults(options, externalData); - query.mount(key); - _addQuery(query); - return await query.fetch(); - } - - @protected - InfiniteQuery - addInfiniteQuery( - InfiniteQueryJob infiniteQueryJob, { - required Outside externalData, - required ValueKey key, - final InfiniteQueryListeners? onData, - final InfiniteQueryListeners? onError, - }) { - final prevInfiniteQuery = _infiniteQueries.firstWhereOrNull( - (q) => q.queryKey == infiniteQueryJob.queryKey, - ); - if (prevInfiniteQuery is InfiniteQuery) { - // run the query if its still not called or if externalData has - // changed - if (prevInfiniteQuery.prevUsedExternalData != null && - externalData != null && - !isShallowEqual( - prevInfiniteQuery.prevUsedExternalData!, - externalData, - )) { - prevInfiniteQuery.setExternalData(externalData); - } - prevInfiniteQuery.mount(key); - if (onData != null) prevInfiniteQuery.addDataListener(onData); - if (onError != null) prevInfiniteQuery.addErrorListener(onError); - // mounting the widget that is using the query in the prevQuery - return prevInfiniteQuery; - } - - final infiniteQuery = - _createInfiniteQueryWithDefaults( - infiniteQueryJob, - externalData, - ); - if (onData != null) infiniteQuery.addDataListener(onData); - if (onError != null) infiniteQuery.addErrorListener(onError); - infiniteQuery.mount(key); - _addInfiniteQuery(infiniteQuery); - return infiniteQuery; - } - - /// !⚠️**Warning** only for internal library usage - @protected - Query addQuery( - QueryJob queryJob, { - required Outside externalData, - required ValueKey key, - final QueryListener? onData, - final QueryListener? onError, - final T? previousData, - }) { - final prevQuery = - _queries.firstWhereOrNull((q) => q.queryKey == queryJob.queryKey); - if (prevQuery is Query) { - // run the query if its still not called or if externalData has - // changed - if (prevQuery.prevUsedExternalData != null && - externalData != null && - !isShallowEqual( - prevQuery.prevUsedExternalData!, - externalData, - )) { - prevQuery.setExternalData(externalData); - } - prevQuery.mount(key); - if (onData != null) prevQuery.addDataListener(onData); - if (onError != null) prevQuery.addErrorListener(onError); - // mounting the widget that is using the query in the prevQuery - return prevQuery; - } - final query = _createQueryWithDefaults( - queryJob, - externalData, - previousData, - ); - if (onData != null) query.addDataListener(onData); - if (onError != null) query.addErrorListener(onError); - query.mount(key); - _addQuery(query); - return query; - } - - /// !⚠️**Warning** only for internal library usage - @protected - Mutation addMutation( - MutationJob mutationJob, { - final MutationListener? onData, - final MutationListener? onError, - final MutationListenerReturnable? onMutate, - required ValueKey key, - }) { - final prevMutation = _mutations.firstWhereOrNull( - (prevMutation) => prevMutation.mutationKey == mutationJob.mutationKey); - if (prevMutation != null && prevMutation is Mutation) { - if (onData != null) prevMutation.addDataListener(onData); - if (onError != null) prevMutation.addErrorListener(onError); - if (onMutate != null) prevMutation.addMutateListener(onMutate); - prevMutation.mount(key); - return prevMutation; - } else { - final mutation = Mutation.fromOptions( - mutationJob, - queryBowl: this, - ); - if (onData != null) mutation.addDataListener(onData); - if (onError != null) mutation.addErrorListener(onError); - if (onMutate != null) mutation.addMutateListener(onMutate); - mutation.updateDefaultOptions(cacheTime: cacheTime); - mutation.mount(key); - _addMutation(mutation); - return mutation; - } - } - - InfiniteQuery? - getInfiniteQuery( - String queryKey, - ) { - return _infiniteQueries.firstWhereOrNull((infiniteQuery) { - return infiniteQuery.queryKey == queryKey && - infiniteQuery is InfiniteQuery; - })?.cast>(); - } - - /// Get a query by providing queryKey only - /// - /// Useful for optimistic update or single query refetch - Query? getQuery(String queryKey) { - return _queries.firstWhereOrNull((query) { - return query.queryKey == queryKey && query is Query; - })?.cast>(); - } - - /// Get a mutation by providing mutationKey only - /// - /// Useful for mutation resets - Mutation? getMutation(String mutationKey) { - return _mutations.firstWhereOrNull((mutation) { - return mutation.mutationKey == mutationKey && mutation is Mutation; - })?.cast>(); - } - /// Returns the number of query is currently fetching or refetching int get isFetching { - return _queries.fold( + return cache.queries.fold( 0, (acc, query) { if (query.isLoading || query.isRefetching) acc++; @@ -584,7 +118,7 @@ class QueryBowl extends InheritedWidget { /// Provides the number of mutations that are running at the moment int get isMutating { - return _mutations.fold( + return cache.mutations.fold( 0, (acc, mutation) { if (mutation.isLoading) acc++; @@ -593,6 +127,66 @@ class QueryBowl extends InheritedWidget { ); } + void onQueriesUpdate( + void Function(Query query) listener, + ) { + cache.on((event, changes) { + if (event == CacheEvent.query && changes is Query) { + listener(changes); + } + }); + } + + void onMutationsUpdate( + void Function(Mutation mutation) listener, + ) { + cache.on((event, changes) { + if (event == CacheEvent.mutation && changes is Mutation) { + listener(changes); + } + }); + } + + void onInfiniteQueriesUpdate( + void Function(InfiniteQuery infiniteQuery) listener, + ) { + cache.on((event, changes) { + if (event == CacheEvent.infiniteQuery && + changes is InfiniteQuery) { + listener(changes); + } + }); + } + + InfiniteQuery? + getInfiniteQuery( + String queryKey, + ) { + return cache.infiniteQueries.firstWhereOrNull((infiniteQuery) { + return infiniteQuery.queryKey == queryKey && + infiniteQuery is InfiniteQuery; + })?.cast>(); + } + + /// Get a query by providing queryKey only + /// + /// Useful for optimistic update or single query refetch + Query? getQuery(String queryKey) { + return cache.queries.firstWhereOrNull((query) { + return query.queryKey == queryKey && query is Query; + })?.cast>(); + } + + /// Get a mutation by providing mutationKey only + /// + /// Useful for mutation resets + Mutation? getMutation(String mutationKey) { + return cache.mutations.firstWhereOrNull((mutation) { + return mutation.mutationKey == mutationKey && mutation is Mutation; + })?.cast>(); + } + /// Sets [Query]'s data manually /// /// Mostly used in combination with [onMutate] callback of @@ -621,7 +215,7 @@ class QueryBowl extends InheritedWidget { /// If an empty list of [queryKeys] is passed then all of the queries /// will be reset void resetQueries(List queryKeys) { - for (final query in _queries) { + for (final query in cache.queries) { if (queryKeys.isNotEmpty && !queryKeys.contains(query.queryKey)) continue; query.reset(); } @@ -632,7 +226,7 @@ class QueryBowl extends InheritedWidget { /// If an empty list of [queryKeys] is passed then all of the queries /// will be invalidated void invalidateQueries(List queryKeys) { - for (final query in _queries) { + for (final query in cache.queries) { if (queryKeys.isNotEmpty && queryKeys.contains(query.queryKey)) continue; query.invalidate(); } @@ -643,22 +237,252 @@ class QueryBowl extends InheritedWidget { /// If an empty list of [queryKeys] is passed then all of the queries /// will be refetched Future refetchQueries(List queryKeys) async { - for (final query in _queries) { + for (final query in cache.queries) { if (queryKeys.isNotEmpty && queryKeys.contains(query.queryKey)) continue; await query.refetch(); } } - static QueryBowl of(BuildContext context) => - context.dependOnInheritedWidgetOfExactType()!; + /// Removes all the queries matching the passed List of queryKeys + /// from the [QueryCache] + int removeQueries(List queryKeys) { + int count = 0; + for (final query in cache.queries) { + if (queryKeys.isEmpty || !queryKeys.contains(query.queryKey)) continue; + cache.removeQuery(query); + count++; + } + return count; + } - /// !⚠️**Warning** only for internal library usage - @override - @protected - bool updateShouldNotify(QueryBowl oldWidget) { - return oldWidget.staleTime != staleTime || - oldWidget._queries != _queries || - oldWidget._mutations != _mutations || - oldWidget._infiniteQueries != _infiniteQueries; + Query _createQueryWithDefaults( + QueryJob options, + Outside externalData, [ + T? previousData, + ]) { + final query = Query.fromOptions( + options, + externalData: externalData, + previousData: previousData, + queryBowl: this as dynamic, + ); + query.updateDefaultOptions( + cacheTime: cache.cacheTime, + staleTime: staleTime, + refetchInterval: refetchInterval, + refetchOnMount: refetchOnMount, + refetchOnReconnect: refetchOnReconnect, + ); + return query; + } + + InfiniteQuery _createInfiniteQueryWithDefaults< + T extends Object, Outside, PageParam extends Object>( + InfiniteQueryJob options, + Outside externalData, + ) { + final infiniteQuery = InfiniteQuery.fromOptions( + options, + externalData: externalData, + queryBowl: this as dynamic, + ); + infiniteQuery.updateDefaultOptions( + cacheTime: cache.cacheTime, + staleTime: staleTime, + refetchInterval: refetchInterval, + refetchOnMount: refetchOnMount, + refetchOnReconnect: refetchOnReconnect, + ); + return infiniteQuery; + } + + /// Creates/Updates a [Query] with the provided [QueryJob] and it's + /// [externalData] and listeners and mounts the [QueryBuilder] or + /// [useQuery] for the Query + Query addQuery( + QueryJob queryJob, { + required Outside externalData, + required ValueKey key, + final QueryListener? onData, + final QueryListener? onError, + final T? previousData, + }) { + final prevQuery = getQuery(queryJob.queryKey); + if (prevQuery != null) { + // run the query if its still not called or if externalData has + // changed + if (prevQuery.prevUsedExternalData != null && + externalData != null && + !isShallowEqual( + prevQuery.prevUsedExternalData!, + externalData, + )) { + prevQuery.setExternalData(externalData); + } + prevQuery.mount(key); + if (onData != null) prevQuery.addDataListener(onData); + if (onError != null) prevQuery.addErrorListener(onError); + // mounting the widget that is using the query in the prevQuery + return prevQuery; + } + final query = _createQueryWithDefaults( + queryJob, + externalData, + previousData, + ); + if (onData != null) query.addDataListener(onData); + if (onError != null) query.addErrorListener(onError); + query.mount(key); + cache.addQuery(query); + return query; + } + + /// Creates/Updates a [InfiniteQuery] with the provided + /// [InfiniteQueryJob] and it's [externalData] and listeners and mounts + /// the [InfiniteQueryBuilder] or [useInfiniteQuery] for the it + InfiniteQuery + addInfiniteQuery( + InfiniteQueryJob infiniteQueryJob, { + required Outside externalData, + required ValueKey key, + final InfiniteQueryListeners? onData, + final InfiniteQueryListeners? onError, + }) { + final prevInfiniteQuery = + getInfiniteQuery(infiniteQueryJob.queryKey); + if (prevInfiniteQuery != null) { + // run the query if its still not called or if externalData has + // changed + if (prevInfiniteQuery.prevUsedExternalData != null && + externalData != null && + !isShallowEqual( + prevInfiniteQuery.prevUsedExternalData!, + externalData, + )) { + prevInfiniteQuery.setExternalData(externalData); + } + prevInfiniteQuery.mount(key); + if (onData != null) prevInfiniteQuery.addDataListener(onData); + if (onError != null) prevInfiniteQuery.addErrorListener(onError); + // mounting the widget that is using the query in the prevQuery + return prevInfiniteQuery; + } + + final infiniteQuery = + _createInfiniteQueryWithDefaults( + infiniteQueryJob, + externalData, + ); + if (onData != null) infiniteQuery.addDataListener(onData); + if (onError != null) infiniteQuery.addErrorListener(onError); + infiniteQuery.mount(key); + cache.addInfiniteQuery(infiniteQuery); + return infiniteQuery; + } + + /// Creates/Updates a [Mutation] with the provided + /// [MutationJob] and it's listeners. Mounts + /// the [MutationBuilder] or [useMutation] for the it + Mutation addMutation( + MutationJob mutationJob, { + final MutationListener? onData, + final MutationListener? onError, + final MutationListenerReturnable? onMutate, + required ValueKey key, + }) { + final prevMutation = getMutation(mutationJob.mutationKey); + if (prevMutation != null) { + if (onData != null) prevMutation.addDataListener(onData); + if (onError != null) prevMutation.addErrorListener(onError); + if (onMutate != null) prevMutation.addMutateListener(onMutate); + prevMutation.mount(key); + return prevMutation; + } else { + final mutation = Mutation.fromOptions( + mutationJob, + queryBowl: this as dynamic, + ); + if (onData != null) mutation.addDataListener(onData); + if (onError != null) mutation.addErrorListener(onError); + if (onMutate != null) mutation.addMutateListener(onMutate); + mutation.updateDefaultOptions(cacheTime: cache.cacheTime); + mutation.mount(key); + cache.addMutation(mutation); + return mutation; + } + } + + /// Creates/Updates a [Query] with the provided [QueryJob] and it's + /// [externalData] and listeners and mounts the [QueryBuilder] or + /// [useQuery] for the Query + /// + /// It also fetches/refetches the [Query] strategically/based on changes + Future fetchQuery( + QueryJob options, { + required Outside externalData, + final QueryListener? onData, + final QueryListener? onError, + required ValueKey key, + }) async { + final prevQuery = getQuery(options.queryKey); + if (prevQuery != null) { + // run the query if its still not called or if externalData has + // changed + final hasExternalDataChanged = prevQuery.prevUsedExternalData != null && + externalData != null && + !isShallowEqual( + prevQuery.prevUsedExternalData!, + externalData, + ); + prevQuery.mount(key); + if (onData != null) prevQuery.addDataListener(onData); + if (onError != null) prevQuery.addErrorListener(onError); + if (!prevQuery.hasData || hasExternalDataChanged) { + if (hasExternalDataChanged) prevQuery.setExternalData(externalData); + + return await prevQuery.refetch(); + } + // mounting the widget that is using the query in the prevQuery + return prevQuery.data; + } + + final query = _createQueryWithDefaults( + options, + externalData, + ); + + query.mount(key); + cache.addQuery(query); + return await query.fetch(); + } + + /// Finds the closest instance of [QueryBowl] for the provided + /// [BuildContext] + static QueryBowl of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType()!.bowl; } } + +/// A simple [InheritedWidget] that does the job of injecting [QueryBowl] +/// into context +/// +/// ```dart +/// Widget build(BuildContext context) { +/// return QueryBowlScope( +/// bowl: QueryBowl(), +/// child: MaterialApp(/*...other stuff...*/), +/// ); +/// } +/// ``` +class QueryBowlScope extends InheritedWidget { + final QueryBowl bowl; + + QueryBowlScope({ + required this.bowl, + required Widget child, + Key? key, + }) : super(key: key, child: child); + + @override + bool updateShouldNotify(covariant oldWidget) => false; +} diff --git a/packages/fl_query/lib/src/query_builder.dart b/packages/fl_query/lib/src/query_builder.dart index 6ecbfb2..54584ad 100644 --- a/packages/fl_query/lib/src/query_builder.dart +++ b/packages/fl_query/lib/src/query_builder.dart @@ -1,13 +1,11 @@ -// ignore_for_file: invalid_use_of_protected_member - import 'package:fl_query/src/models/query_job.dart'; import 'package:fl_query/src/query.dart'; import 'package:fl_query/src/query_bowl.dart'; import 'package:fl_query/src/utils.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/cupertino.dart'; class QueryBuilder extends StatefulWidget { - final Function(BuildContext context, Query query) builder; + final Widget Function(BuildContext context, Query query) builder; final QueryJob job; final Outside externalData; @@ -28,21 +26,34 @@ class QueryBuilder extends StatefulWidget { }) : super(key: key); @override - State> createState() => + _QueryBuilderState createState() => _QueryBuilderState(); } class _QueryBuilderState extends State> { - late QueryBowl queryBowl; - late final ValueKey uKey; Query? query; + late final ValueKey uKey; @override void initState() { super.initState(); + uKey = ValueKey(uuid.v4()); - WidgetsBinding.instance.addPostFrameCallback((_) => init()); + + WidgetsBinding.instance.addPostFrameCallback((_) { + init(); + + QueryBowl.of(context).onQueriesUpdate( + (query) { + if (query.queryKey != widget.job.queryKey) return; + if (mounted) + setState(() { + this.query = query; + }); + }, + ); + }); } void init([T? previousData]) async { @@ -55,6 +66,7 @@ class _QueryBuilderState onData: widget.onData, onError: widget.onError, ); + final hasExternalDataChanged = query!.externalData != null && query!.prevUsedExternalData != null && !isShallowEqual( @@ -71,6 +83,7 @@ class _QueryBuilderState @override void didUpdateWidget(covariant oldWidget) { + final bowl = QueryBowl.of(context); final hasOnErrorChanged = oldWidget.onError != widget.onError && oldWidget.onError != null; final hasOnDataChanged = @@ -94,8 +107,8 @@ class _QueryBuilderState widget.externalData != null && !isShallowEqual(oldWidget.externalData!, widget.externalData!)) { if (widget.job.refetchOnExternalDataChange ?? - queryBowl.refetchOnExternalDataChange) { - QueryBowl.of(context).fetchQuery( + bowl.refetchOnExternalDataChange) { + bowl.fetchQuery( widget.job, externalData: widget.externalData, onData: widget.onData, @@ -103,7 +116,7 @@ class _QueryBuilderState key: uKey, ); } else { - QueryBowl.of(context) + bowl .getQuery(widget.job.queryKey) ?.setExternalData(widget.externalData); } @@ -136,10 +149,7 @@ class _QueryBuilderState @override Widget build(BuildContext context) { - queryBowl = QueryBowl.of(context); - final latestQuery = - queryBowl.getQuery(widget.job.queryKey) ?? query; - if (latestQuery == null) return Container(); - return widget.builder(context, latestQuery); + if (query == null) return Container(); + return widget.builder(context, query!); } } diff --git a/packages/fl_query/lib/src/query_cache.dart b/packages/fl_query/lib/src/query_cache.dart new file mode 100644 index 0000000..9454476 --- /dev/null +++ b/packages/fl_query/lib/src/query_cache.dart @@ -0,0 +1,124 @@ +import 'package:collection/collection.dart'; +import 'package:fl_query/fl_query.dart'; +import 'package:fl_query/src/base_operation.dart'; + +typedef ReadonlySet = UnmodifiableSetView; + +enum CacheEvent { + clearCache, + query, + infiniteQuery, + mutation, +} + +typedef CacheUpdateListener = void Function(CacheEvent event, T? changes); + +class QueryCache { + /// Removes inactive queries after provided duration of [cacheTime] + final Duration cacheTime; + + QueryCache({Duration? cacheTime}) + : cacheTime = cacheTime ?? const Duration(minutes: 5) {} + + final Set _queries = {}; + final Set _infiniteQueries = {}; + final Set _mutations = {}; + + final Set> _listeners = {}; + + ReadonlySet get queries => UnmodifiableSetView(_queries); + ReadonlySet get infiniteQueries => + UnmodifiableSetView(_infiniteQueries); + ReadonlySet get mutations => UnmodifiableSetView(_mutations); + + ReadonlySet> get listeners => + UnmodifiableSetView(_listeners); + + _notifyListeners(CacheEvent event, changes) { + _listeners.forEach((listener) => listener(event, changes)); + } + + _listenToQueryChanges(Query query) { + query.addListener(() { + if (query.isInactive) { + _queries.removeWhere((el) => el.queryKey != query.queryKey); + _notifyListeners(CacheEvent.query, null); + } else { + _notifyListeners(CacheEvent.query, query); + } + }); + } + + _listenToInfiniteQueryChanges(InfiniteQuery infiniteQuery) { + infiniteQuery.addListener(() { + if (infiniteQuery.isInactive) { + _infiniteQueries + .removeWhere((el) => el.queryKey != infiniteQuery.queryKey); + _notifyListeners(CacheEvent.infiniteQuery, null); + } else { + _notifyListeners(CacheEvent.infiniteQuery, infiniteQuery); + } + }); + } + + _listenToMutationChanges(Mutation mutation) { + mutation.addListener(() { + if (mutation.isInactive) { + _mutations.removeWhere( + (el) => el.mutationKey != mutation.mutationKey, + ); + _notifyListeners(CacheEvent.mutation, null); + } else { + _notifyListeners(CacheEvent.mutation, mutation); + } + }); + } + + void addQuery(Query query) { + _queries.add(query); + _listenToQueryChanges(query); + _notifyListeners(CacheEvent.query, query); + } + + void addInfiniteQuery(InfiniteQuery infiniteQuery) { + _infiniteQueries.add(infiniteQuery); + _listenToInfiniteQueryChanges(infiniteQuery); + _notifyListeners(CacheEvent.infiniteQuery, infiniteQuery); + } + + void addMutation(Mutation mutation) { + _mutations.add(mutation); + _listenToMutationChanges(mutation); + _notifyListeners(CacheEvent.mutation, mutation); + } + + void removeQuery(Query query) { + _queries.remove(query); + _notifyListeners(CacheEvent.query, null); + } + + void removeInfiniteQuery(InfiniteQuery infiniteQuery) { + _infiniteQueries.remove(infiniteQuery); + _notifyListeners(CacheEvent.infiniteQuery, null); + } + + void removeMutation(Mutation mutation) { + _mutations.remove(mutation); + _notifyListeners(CacheEvent.mutation, null); + } + + void clearCache() { + _infiniteQueries.clear(); + _queries.clear(); + _mutations.clear(); + _notifyListeners(CacheEvent.clearCache, null); + } + + void on(CacheUpdateListener listener) { + _listeners.add(listener); + } + + void off(CacheUpdateListener listener) { + _listeners.remove(listener); + } +} diff --git a/packages/fl_query/test/query_test.mocks.dart b/packages/fl_query/test/query_test.mocks.dart index 8beffea..c42bb79 100644 --- a/packages/fl_query/test/query_test.mocks.dart +++ b/packages/fl_query/test/query_test.mocks.dart @@ -1,18 +1,14 @@ -// Mocks generated by Mockito 5.2.0 from annotations +// Mocks generated by Mockito 5.3.0 from annotations // in fl_query/test/query_test.dart. // Do not manually edit this file. -import 'dart:async' as _i7; +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; -import 'package:connectivity_plus/connectivity_plus.dart' as _i11; -import 'package:fl_query/src/models/mutation_job.dart' as _i9; -import 'package:fl_query/src/models/query_job.dart' as _i8; -import 'package:fl_query/src/mutation.dart' as _i4; -import 'package:fl_query/src/query.dart' as _i3; -import 'package:fl_query/src/query_bowl.dart' as _i6; -import 'package:flutter/foundation.dart' as _i5; -import 'package:flutter/rendering.dart' as _i10; -import 'package:flutter/widgets.dart' as _i2; +import 'package:connectivity_plus/connectivity_plus.dart' as _i6; +import 'package:fl_query/fl_query.dart' as _i3; +import 'package:fl_query/src/query_cache.dart' as _i2; +import 'package:flutter/cupertino.dart' as _i5; import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: type=lint @@ -24,71 +20,92 @@ import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class -class _FakeDuration_0 extends _i1.Fake implements Duration {} - -class _FakeWidget_1 extends _i1.Fake implements _i2.Widget { - @override - String toString({_i2.DiagnosticLevel? minLevel = _i2.DiagnosticLevel.info}) => - super.toString(); +class _FakeDuration_0 extends _i1.SmartFake implements Duration { + _FakeDuration_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } -class _FakeQuery_2 extends _i1.Fake - implements _i3.Query {} - -class _FakeMutation_3 extends _i1.Fake - implements _i4.Mutation {} - -class _FakeInheritedElement_4 extends _i1.Fake implements _i2.InheritedElement { - @override - String toString({_i2.DiagnosticLevel? minLevel = _i2.DiagnosticLevel.info}) => - super.toString(); +class _FakeQueryCache_1 extends _i1.SmartFake implements _i2.QueryCache { + _FakeQueryCache_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } -class _FakeDiagnosticsNode_5 extends _i1.Fake implements _i2.DiagnosticsNode { - @override - String toString( - {_i5.TextTreeConfiguration? parentConfiguration, - _i2.DiagnosticLevel? minLevel = _i2.DiagnosticLevel.info}) => - super.toString(); +class _FakeQuery_2 extends _i1.SmartFake + implements _i3.Query { + _FakeQuery_2(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } -class _FakeObject_6 extends _i1.Fake implements Object {} +class _FakeInfiniteQuery_3 + extends _i1.SmartFake implements _i3.InfiniteQuery { + _FakeInfiniteQuery_3(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeMutation_4 extends _i1.SmartFake + implements _i3.Mutation { + _FakeMutation_4(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakeObject_5 extends _i1.SmartFake implements Object { + _FakeObject_5(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} /// A class which mocks [QueryBowl]. /// /// See the documentation for Mockito's code generation for more information. -class MockQueryBowl extends _i1.Mock implements _i6.QueryBowl { +class MockQueryBowl extends _i1.Mock implements _i3.QueryBowl { MockQueryBowl() { _i1.throwOnMissingStub(this); } @override Duration get staleTime => (super.noSuchMethod(Invocation.getter(#staleTime), - returnValue: _FakeDuration_0()) as Duration); - @override - Duration get cacheTime => (super.noSuchMethod(Invocation.getter(#cacheTime), - returnValue: _FakeDuration_0()) as Duration); + returnValue: _FakeDuration_0(this, Invocation.getter(#staleTime))) + as Duration); @override bool get refetchOnMount => (super .noSuchMethod(Invocation.getter(#refetchOnMount), returnValue: false) as bool); @override + bool get refetchOnWindowFocus => + (super.noSuchMethod(Invocation.getter(#refetchOnWindowFocus), + returnValue: false) as bool); + @override + bool get refetchOnApplicationResume => + (super.noSuchMethod(Invocation.getter(#refetchOnApplicationResume), + returnValue: false) as bool); + @override bool get refetchOnReconnect => (super.noSuchMethod(Invocation.getter(#refetchOnReconnect), returnValue: false) as bool); @override + Duration get refetchOnReconnectDelay => + (super.noSuchMethod(Invocation.getter(#refetchOnReconnectDelay), + returnValue: _FakeDuration_0( + this, Invocation.getter(#refetchOnReconnectDelay))) as Duration); + @override bool get refetchOnExternalDataChange => (super.noSuchMethod(Invocation.getter(#refetchOnExternalDataChange), returnValue: false) as bool); @override - int Function(List) get removeQueries => - (super.noSuchMethod(Invocation.getter(#removeQueries), - returnValue: (List __p0) => 0) as int Function(List)); + Duration get refetchInterval => + (super.noSuchMethod(Invocation.getter(#refetchInterval), + returnValue: + _FakeDuration_0(this, Invocation.getter(#refetchInterval))) + as Duration); @override - void Function() get clear => - (super.noSuchMethod(Invocation.getter(#clear), returnValue: () {}) as void - Function()); + _i2.QueryCache get cache => (super.noSuchMethod(Invocation.getter(#cache), + returnValue: _FakeQueryCache_1(this, Invocation.getter(#cache))) + as _i2.QueryCache); + @override + set cache(_i2.QueryCache? _cache) => + super.noSuchMethod(Invocation.setter(#cache, _cache), + returnValueForMissingStub: null); @override int get isFetching => (super.noSuchMethod(Invocation.getter(#isFetching), returnValue: 0) @@ -98,38 +115,73 @@ class MockQueryBowl extends _i1.Mock implements _i6.QueryBowl { (super.noSuchMethod(Invocation.getter(#isMutating), returnValue: 0) as int); @override - _i2.Widget get child => (super.noSuchMethod(Invocation.getter(#child), - returnValue: _FakeWidget_1()) as _i2.Widget); + void onQueriesUpdate( + void Function(_i3.Query)? listener) => + super.noSuchMethod(Invocation.method(#onQueriesUpdate, [listener]), + returnValueForMissingStub: null); @override - _i7.Future prefetchQuery( - _i8.QueryJob? options, - {Outside? externalData}) => - (super.noSuchMethod( - Invocation.method( - #prefetchQuery, [options], {#externalData: externalData}), - returnValue: Future.value()) as _i7.Future); + void onMutationsUpdate( + void Function(_i3.Mutation)? listener) => + super.noSuchMethod(Invocation.method(#onMutationsUpdate, [listener]), + returnValueForMissingStub: null); @override - _i7.Future fetchQuery( - _i8.QueryJob? options, - {Outside? externalData, - _i3.QueryListener? onData, - _i3.QueryListener? onError, - _i2.ValueKey? key}) => - (super.noSuchMethod( - Invocation.method(#fetchQuery, [ - options - ], { - #externalData: externalData, - #onData: onData, - #onError: onError, - #key: key - }), - returnValue: Future.value()) as _i7.Future); + void onInfiniteQueriesUpdate( + void Function(_i3.InfiniteQuery)? listener) => + super.noSuchMethod( + Invocation.method(#onInfiniteQueriesUpdate, [listener]), + returnValueForMissingStub: null); + @override + _i3.InfiniteQuery? + getInfiniteQuery( + String? queryKey) => + (super.noSuchMethod(Invocation.method(#getInfiniteQuery, [queryKey])) + as _i3.InfiniteQuery?); + @override + _i3.Query? getQuery( + String? queryKey) => + (super.noSuchMethod(Invocation.method(#getQuery, [queryKey])) + as _i3.Query?); + @override + _i3.Mutation? getMutation(String? mutationKey) => + (super.noSuchMethod(Invocation.method(#getMutation, [mutationKey])) + as _i3.Mutation?); + @override + void setQueryData( + String? queryKey, _i3.QueryUpdateFunction? updateCb) => + super.noSuchMethod(Invocation.method(#setQueryData, [queryKey, updateCb]), + returnValueForMissingStub: null); + @override + void + setInfiniteQueryData( + String? queryKey, + _i3.QueryUpdateFunction>? updateCb) => + super.noSuchMethod( + Invocation.method(#setInfiniteQueryData, [queryKey, updateCb]), + returnValueForMissingStub: null); + @override + void resetQueries(List? queryKeys) => + super.noSuchMethod(Invocation.method(#resetQueries, [queryKeys]), + returnValueForMissingStub: null); + @override + void invalidateQueries(List? queryKeys) => + super.noSuchMethod(Invocation.method(#invalidateQueries, [queryKeys]), + returnValueForMissingStub: null); + @override + _i4.Future refetchQueries(List? queryKeys) => + (super.noSuchMethod(Invocation.method(#refetchQueries, [queryKeys]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value()) + as _i4.Future); + @override + int removeQueries(List? queryKeys) => + (super.noSuchMethod(Invocation.method(#removeQueries, [queryKeys]), + returnValue: 0) as int); @override _i3.Query addQuery( - _i8.QueryJob? queryJob, + _i3.QueryJob? queryJob, {Outside? externalData, - _i2.ValueKey? key, + _i5.ValueKey? key, _i3.QueryListener? onData, _i3.QueryListener? onError, T? previousData}) => @@ -143,134 +195,105 @@ class MockQueryBowl extends _i1.Mock implements _i6.QueryBowl { #onError: onError, #previousData: previousData }), - returnValue: _FakeQuery_2()) as _i3.Query); + returnValue: _FakeQuery_2( + this, + Invocation.method(#addQuery, [ + queryJob + ], { + #externalData: externalData, + #key: key, + #onData: onData, + #onError: onError, + #previousData: previousData + }))) as _i3.Query); @override - _i4.Mutation addMutation( - _i9.MutationJob? mutationJob, - {_i4.MutationListener? onData, - _i4.MutationListener? onError, - _i4.MutationListenerReturnable? onMutate, - _i2.ValueKey? key}) => + _i3.InfiniteQuery addInfiniteQuery( + _i3.InfiniteQueryJob? infiniteQueryJob, + {Outside? externalData, + _i5.ValueKey? key, + _i3.InfiniteQueryListeners? onData, + _i3.InfiniteQueryListeners? onError}) => + (super.noSuchMethod(Invocation.method(#addInfiniteQuery, [infiniteQueryJob], {#externalData: externalData, #key: key, #onData: onData, #onError: onError}), + returnValue: _FakeInfiniteQuery_3( + this, + Invocation.method(#addInfiniteQuery, [ + infiniteQueryJob + ], { + #externalData: externalData, + #key: key, + #onData: onData, + #onError: onError + }))) as _i3.InfiniteQuery); + @override + _i3.Mutation addMutation( + _i3.MutationJob? mutationJob, + {_i3.MutationListener? onData, + _i3.MutationListener? onError, + _i3.MutationListenerReturnable? onMutate, + _i5.ValueKey? key}) => + (super + .noSuchMethod(Invocation.method(#addMutation, [mutationJob], {#onData: onData, #onError: onError, #onMutate: onMutate, #key: key}), + returnValue: _FakeMutation_4( + this, + Invocation.method(#addMutation, [ + mutationJob + ], { + #onData: onData, + #onError: onError, + #onMutate: onMutate, + #key: key + }))) as _i3.Mutation); + @override + _i4.Future fetchQuery( + _i3.QueryJob? options, + {Outside? externalData, + _i3.QueryListener? onData, + _i3.QueryListener? onError, + _i5.ValueKey? key}) => (super.noSuchMethod( - Invocation.method(#addMutation, [ - mutationJob + Invocation.method(#fetchQuery, [ + options ], { + #externalData: externalData, #onData: onData, #onError: onError, - #onMutate: onMutate, #key: key }), - returnValue: _FakeMutation_3()) as _i4.Mutation); - @override - _i3.Query? getQuery( - String? queryKey) => - (super.noSuchMethod(Invocation.method(#getQuery, [queryKey])) - as _i3.Query?); - @override - _i4.Mutation? getMutation(String? mutationKey) => - (super.noSuchMethod(Invocation.method(#getMutation, [mutationKey])) - as _i4.Mutation?); - @override - void setQueryData( - String? queryKey, _i3.QueryUpdateFunction? updateCb) => - super.noSuchMethod(Invocation.method(#setQueryData, [queryKey, updateCb]), - returnValueForMissingStub: null); - @override - void resetQueries(List? queryKeys) => - super.noSuchMethod(Invocation.method(#resetQueries, [queryKeys]), - returnValueForMissingStub: null); - @override - void invalidateQueries(List? queryKeys) => - super.noSuchMethod(Invocation.method(#invalidateQueries, [queryKeys]), - returnValueForMissingStub: null); - @override - _i7.Future refetchQueries(List? queryKeys) => - (super.noSuchMethod(Invocation.method(#refetchQueries, [queryKeys]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i7.Future); - @override - bool updateShouldNotify(_i2.InheritedWidget? oldWidget) => - (super.noSuchMethod(Invocation.method(#updateShouldNotify, [oldWidget]), - returnValue: false) as bool); - @override - _i2.InheritedElement createElement() => - (super.noSuchMethod(Invocation.method(#createElement, []), - returnValue: _FakeInheritedElement_4()) as _i2.InheritedElement); - @override - String toStringShort() => (super - .noSuchMethod(Invocation.method(#toStringShort, []), returnValue: '') - as String); - @override - void debugFillProperties(_i10.DiagnosticPropertiesBuilder? properties) => - super.noSuchMethod(Invocation.method(#debugFillProperties, [properties]), - returnValueForMissingStub: null); - @override - String toStringShallow( - {String? joiner = r', ', - _i2.DiagnosticLevel? minLevel = _i2.DiagnosticLevel.debug}) => - (super.noSuchMethod( - Invocation.method( - #toStringShallow, [], {#joiner: joiner, #minLevel: minLevel}), - returnValue: '') as String); - @override - String toStringDeep( - {String? prefixLineOne = r'', - String? prefixOtherLines, - _i2.DiagnosticLevel? minLevel = _i2.DiagnosticLevel.debug}) => - (super.noSuchMethod( - Invocation.method(#toStringDeep, [], { - #prefixLineOne: prefixLineOne, - #prefixOtherLines: prefixOtherLines, - #minLevel: minLevel - }), - returnValue: '') as String); - @override - _i2.DiagnosticsNode toDiagnosticsNode( - {String? name, _i5.DiagnosticsTreeStyle? style}) => - (super.noSuchMethod( - Invocation.method( - #toDiagnosticsNode, [], {#name: name, #style: style}), - returnValue: _FakeDiagnosticsNode_5()) as _i2.DiagnosticsNode); - @override - List<_i2.DiagnosticsNode> debugDescribeChildren() => - (super.noSuchMethod(Invocation.method(#debugDescribeChildren, []), - returnValue: <_i2.DiagnosticsNode>[]) as List<_i2.DiagnosticsNode>); - @override - String toString({_i2.DiagnosticLevel? minLevel = _i2.DiagnosticLevel.info}) => - super.toString(); + returnValue: _i4.Future.value()) as _i4.Future); } /// A class which mocks [Connectivity]. /// /// See the documentation for Mockito's code generation for more information. -class MockConnectivity extends _i1.Mock implements _i11.Connectivity { +class MockConnectivity extends _i1.Mock implements _i6.Connectivity { MockConnectivity() { _i1.throwOnMissingStub(this); } @override - _i7.Stream<_i11.ConnectivityResult> get onConnectivityChanged => + _i4.Stream<_i6.ConnectivityResult> get onConnectivityChanged => (super.noSuchMethod(Invocation.getter(#onConnectivityChanged), - returnValue: Stream<_i11.ConnectivityResult>.empty()) - as _i7.Stream<_i11.ConnectivityResult>); + returnValue: _i4.Stream<_i6.ConnectivityResult>.empty()) + as _i4.Stream<_i6.ConnectivityResult>); @override - _i7.Future<_i11.ConnectivityResult> checkConnectivity() => + _i4.Future<_i6.ConnectivityResult> checkConnectivity() => (super.noSuchMethod(Invocation.method(#checkConnectivity, []), - returnValue: Future<_i11.ConnectivityResult>.value( - _i11.ConnectivityResult.bluetooth)) - as _i7.Future<_i11.ConnectivityResult>); + returnValue: _i4.Future<_i6.ConnectivityResult>.value( + _i6.ConnectivityResult.bluetooth)) + as _i4.Future<_i6.ConnectivityResult>); } /// A class which mocks [QueryJob]. /// /// See the documentation for Mockito's code generation for more information. class MockQueryJobVoidObject extends _i1.Mock - implements _i8.QueryJob { + implements _i3.QueryJob { @override _i3.QueryTaskFunction get task => (super.noSuchMethod(Invocation.getter(#task), returnValue: (String queryKey, void externalData) => - Future.value(_FakeObject_6())) + _i4.Future.value( + _FakeObject_5(this, Invocation.getter(#task)))) as _i3.QueryTaskFunction); @override set task(_i3.QueryTaskFunction? _task) => diff --git a/packages/fl_query_hooks/example/.flutter-plugins-dependencies b/packages/fl_query_hooks/example/.flutter-plugins-dependencies index e40aedb..80cd7ee 100644 --- a/packages/fl_query_hooks/example/.flutter-plugins-dependencies +++ b/packages/fl_query_hooks/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.3/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]}],"date_created":"2022-09-14 11:35:47.051873","version":"3.3.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.3/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":["connectivity_plus_linux","connectivity_plus_macos","connectivity_plus_web","connectivity_plus_windows"]},{"name":"connectivity_plus_linux","dependencies":[]},{"name":"connectivity_plus_macos","dependencies":[]},{"name":"connectivity_plus_web","dependencies":[]},{"name":"connectivity_plus_windows","dependencies":[]}],"date_created":"2022-09-22 21:28:31.234632","version":"3.3.0"} \ No newline at end of file diff --git a/packages/fl_query_hooks/example/android/local.properties b/packages/fl_query_hooks/example/android/local.properties index dfe0f1d..dd4db6b 100644 --- a/packages/fl_query_hooks/example/android/local.properties +++ b/packages/fl_query_hooks/example/android/local.properties @@ -1,2 +1,2 @@ -sdk.dir=/opt/android-sdk +sdk.dir=/home/krtirtho/Android/Sdk flutter.sdk=/opt/flutter \ No newline at end of file diff --git a/packages/fl_query_hooks/example/lib/main.dart b/packages/fl_query_hooks/example/lib/main.dart index 069f3a0..711d30c 100644 --- a/packages/fl_query_hooks/example/lib/main.dart +++ b/packages/fl_query_hooks/example/lib/main.dart @@ -19,6 +19,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return QueryBowlScope( + bowl: QueryBowl(), child: MaterialApp( // showPerformanceOverlay: true, title: 'Fl-Query Hooks Example', diff --git a/packages/fl_query_hooks/example/linux/flutter/ephemeral/generated_config.cmake b/packages/fl_query_hooks/example/linux/flutter/ephemeral/generated_config.cmake index 90b082b..80e8c24 100644 --- a/packages/fl_query_hooks/example/linux/flutter/ephemeral/generated_config.cmake +++ b/packages/fl_query_hooks/example/linux/flutter/ephemeral/generated_config.cmake @@ -2,6 +2,12 @@ file(TO_CMAKE_PATH "/opt/flutter" FLUTTER_ROOT) file(TO_CMAKE_PATH "/home/krtirtho/dev/fl-query/packages/fl_query_hooks/example" PROJECT_DIR) +set(FLUTTER_VERSION "1.0.0+1" PARENT_SCOPE) +set(FLUTTER_VERSION_MAJOR 1 PARENT_SCOPE) +set(FLUTTER_VERSION_MINOR 0 PARENT_SCOPE) +set(FLUTTER_VERSION_PATCH 0 PARENT_SCOPE) +set(FLUTTER_VERSION_BUILD 1 PARENT_SCOPE) + # Environment variables to pass to tool_backend.sh list(APPEND FLUTTER_TOOL_ENVIRONMENT "FLUTTER_ROOT=/opt/flutter" diff --git a/packages/fl_query_hooks/example/linux/flutter/ephemeral/icudtl.dat b/packages/fl_query_hooks/example/linux/flutter/ephemeral/icudtl.dat index d733c28..720a5c7 100644 Binary files a/packages/fl_query_hooks/example/linux/flutter/ephemeral/icudtl.dat and b/packages/fl_query_hooks/example/linux/flutter/ephemeral/icudtl.dat differ diff --git a/packages/fl_query_hooks/example/linux/flutter/ephemeral/libflutter_linux_gtk.so b/packages/fl_query_hooks/example/linux/flutter/ephemeral/libflutter_linux_gtk.so index 5511cd0..6ae4b7d 100644 Binary files a/packages/fl_query_hooks/example/linux/flutter/ephemeral/libflutter_linux_gtk.so and b/packages/fl_query_hooks/example/linux/flutter/ephemeral/libflutter_linux_gtk.so differ diff --git a/packages/fl_query_hooks/lib/src/use_infinite_query.dart b/packages/fl_query_hooks/lib/src/use_infinite_query.dart index 60a392f..267321c 100644 --- a/packages/fl_query_hooks/lib/src/use_infinite_query.dart +++ b/packages/fl_query_hooks/lib/src/use_infinite_query.dart @@ -19,6 +19,8 @@ InfiniteQuery List? keys, }) { final context = useContext(); + final mounted = useIsMounted(); + final update = useForceUpdate(); final QueryBowl queryBowl = QueryBowl.of(context); final ValueKey uKey = useMemoized(() => ValueKey(uuid.v4()), []); final infiniteQuery = useRef( @@ -42,6 +44,7 @@ InfiniteQuery onData: onData, onError: onError, ); + update(); final hasExternalDataChanged = infiniteQuery.value.externalData != null && infiniteQuery.value.prevUsedExternalData != null && !isShallowEqual(infiniteQuery.value.externalData!, @@ -73,7 +76,16 @@ InfiniteQuery ]); useEffect(() { - init(); + WidgetsBinding.instance.addPostFrameCallback((_) { + init(); + QueryBowl.of(context).onInfiniteQueriesUpdate( + (newInfiniteQuery) { + if (newInfiniteQuery.queryKey != job.queryKey || !mounted()) return; + infiniteQuery.value = newInfiniteQuery; + update(); + }, + ); + }); return disposeQuery; }, []); @@ -117,6 +129,5 @@ InfiniteQuery return null; }); - return queryBowl.getInfiniteQuery(job.queryKey) ?? - infiniteQuery.value; + return infiniteQuery.value; } diff --git a/packages/fl_query_hooks/lib/src/use_mutation.dart b/packages/fl_query_hooks/lib/src/use_mutation.dart index c3c80d2..8eb6262 100644 --- a/packages/fl_query_hooks/lib/src/use_mutation.dart +++ b/packages/fl_query_hooks/lib/src/use_mutation.dart @@ -20,6 +20,8 @@ Mutation useMutation({ List? keys, }) { final context = useContext(); + final mounted = useIsMounted(); + final update = useForceUpdate(); final QueryBowl queryBowl = QueryBowl.of(context); final ValueKey uKey = useMemoized(() => ValueKey(uuid.v4()), []); final mutation = @@ -33,6 +35,7 @@ Mutation useMutation({ onMutate: onMutate, key: uKey, ); + update(); }, [mutation.value, job, onData, onError, onMutate, uKey]); final disposeMutation = useCallback(() { @@ -48,7 +51,16 @@ Mutation useMutation({ final oldOnMutate = usePrevious(onMutate); useEffect(() { - init(); + WidgetsBinding.instance.addPostFrameCallback((_) { + init(); + QueryBowl.of(context).onMutationsUpdate( + (newMutation) { + if (newMutation.mutationKey != job.mutationKey || !mounted()) return; + mutation.value = newMutation; + update(); + }, + ); + }); return disposeMutation; }, []); @@ -73,5 +85,5 @@ Mutation useMutation({ return null; }); - return queryBowl.getMutation(job.mutationKey) ?? mutation.value; + return mutation.value; } diff --git a/packages/fl_query_hooks/lib/src/use_query.dart b/packages/fl_query_hooks/lib/src/use_query.dart index 997db7f..94aa236 100644 --- a/packages/fl_query_hooks/lib/src/use_query.dart +++ b/packages/fl_query_hooks/lib/src/use_query.dart @@ -17,6 +17,8 @@ Query useQuery({ QueryListener? onError, List? keys, }) { + final mounted = useIsMounted(); + final update = useForceUpdate(); final context = useContext(); final QueryBowl queryBowl = QueryBowl.of(context); final ValueKey uKey = useMemoized(() => ValueKey(uuid.v4()), []); @@ -42,6 +44,7 @@ Query useQuery({ onData: onData, onError: onError, ); + update(); final hasExternalDataChanged = query.value.externalData != null && query.value.prevUsedExternalData != null && !isShallowEqual( @@ -60,7 +63,16 @@ Query useQuery({ }, [query.value, onData, onError, uKey]); useEffect(() { - init(); + WidgetsBinding.instance.addPostFrameCallback((_) { + init(); + QueryBowl.of(context).onQueriesUpdate( + (newQuery) { + if (newQuery.queryKey != job.queryKey || !mounted()) return; + query.value = newQuery; + update(); + }, + ); + }); return disposeQuery; }, []); @@ -113,5 +125,5 @@ Query useQuery({ return null; }); - return queryBowl.getQuery(job.queryKey) ?? query.value; + return query.value; } diff --git a/packages/fl_query_hooks/lib/src/utils.dart b/packages/fl_query_hooks/lib/src/utils.dart index 941986f..549c9aa 100644 --- a/packages/fl_query_hooks/lib/src/utils.dart +++ b/packages/fl_query_hooks/lib/src/utils.dart @@ -1,3 +1,15 @@ +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:uuid/uuid.dart'; const uuid = Uuid(); + +// a flutter hook that can force update the ui +// +// Usage: +// final forceUpdate = useForceUpdate(); +// forceUpdate(); + +useForceUpdate() { + final state = useState(false); + return () => state.value = !state.value; +}