diff --git a/packages/fl_query/example/.flutter-plugins-dependencies b/packages/fl_query/example/.flutter-plugins-dependencies index 16deaca..14ff288 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.9/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.22/","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":[]},{"name":"path_provider_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","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":[]},{"name":"path_provider_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","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":[]},{"name":"path_provider_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.5/","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":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2022-12-15 14:54:08.206645","version":"3.3.8"} \ 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.9/","native_build":true,"dependencies":[]},{"name":"path_provider_ios","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_ios-2.0.11/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_android-2.0.22/","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":[]},{"name":"path_provider_macos","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-2.0.6/","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":[]},{"name":"path_provider_linux","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-2.1.7/","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":[]},{"name":"path_provider_windows","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.5/","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":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2022-12-16 21:09:35.483382","version":"3.3.8"} \ No newline at end of file diff --git a/packages/fl_query/example/lib/components/infinite_query_disk_cache.dart b/packages/fl_query/example/lib/components/infinite_query_disk_cache.dart index 3bdb5ec..416152e 100644 --- a/packages/fl_query/example/lib/components/infinite_query_disk_cache.dart +++ b/packages/fl_query/example/lib/components/infinite_query_disk_cache.dart @@ -66,8 +66,9 @@ class _InfiniteQueryDiskCacheExampleState job: infiniteQueryDiskCacheExampleQuery, externalData: null, builder: (context, query) { - final data = - query.pages.expand((page) => page!.toList()).toList(); + final data = query.pages + .expand((page) => page?.toList() ?? []) + .toList(); return Scaffold( floatingActionButton: FloatingActionButton( child: const Icon(Icons.download_rounded), diff --git a/packages/fl_query/lib/fl_query.dart b/packages/fl_query/lib/fl_query.dart index 5751885..8b38056 100644 --- a/packages/fl_query/lib/fl_query.dart +++ b/packages/fl_query/lib/fl_query.dart @@ -14,6 +14,7 @@ export 'src/query_bowl.dart'; export 'src/query_builder.dart'; export 'src/mutation.dart'; export 'src/mutation_builder.dart'; +export 'src/always_online_connectivity.dart'; export 'src/models/infinite_query_job.dart'; export 'src/models/query_job.dart'; export 'src/models/mutation_job.dart'; diff --git a/packages/fl_query/lib/src/always_online_connectivity.dart b/packages/fl_query/lib/src/always_online_connectivity.dart new file mode 100644 index 0000000..1ebf35d --- /dev/null +++ b/packages/fl_query/lib/src/always_online_connectivity.dart @@ -0,0 +1,20 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; + +final _alwaysOnlineConnectivity = AlwaysOnlineConnectivity._(); + +/// make this singleton +class AlwaysOnlineConnectivity implements Connectivity { + AlwaysOnlineConnectivity._(); + + factory AlwaysOnlineConnectivity() { + return _alwaysOnlineConnectivity; + } + + @override + Future checkConnectivity() { + return Future.value(ConnectivityResult.ethernet); + } + + @override + Stream get onConnectivityChanged => Stream.empty(); +} diff --git a/packages/fl_query/lib/src/base_operation.dart b/packages/fl_query/lib/src/base_operation.dart index 1f83b58..b81c071 100644 --- a/packages/fl_query/lib/src/base_operation.dart +++ b/packages/fl_query/lib/src/base_operation.dart @@ -1,3 +1,5 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:fl_query/src/utils.dart'; import 'package:flutter/widgets.dart'; abstract class BaseOperation extends ChangeNotifier { @@ -10,6 +12,8 @@ abstract class BaseOperation extends ChangeNotifier { @protected Duration cacheTime; + Connectivity _connectivity; + // all properties Data? data; Error? error; @@ -31,7 +35,9 @@ abstract class BaseOperation extends ChangeNotifier { required this.retries, required this.retryDelay, this.data, - }) : updatedAt = DateTime.now(); + Connectivity? connectivity, + }) : updatedAt = DateTime.now(), + _connectivity = connectivity ?? Connectivity(); void mount(ValueKey uKey) { _mounts.add(uKey); @@ -52,6 +58,28 @@ abstract class BaseOperation extends ChangeNotifier { Set> get mounts => _mounts; + /// checks if the application is connected to internet in any mean + /// + /// It's true when any one this is connected - + /// - ethernet + /// - mobile + /// - wifi + /// + /// Deprecated: Use [isNetworkOnline] instead + @deprecated + Future isInternetConnected() async { + return isNetworkOnline; + } + + /// checks if the application is connected to internet in any mean + /// + /// It's true when any one this is connected - + /// - ethernet + /// - mobile + /// - wifi + Future get isNetworkOnline => + _connectivity.checkConnectivity().then((v) => isConnectedToInternet(v)); + bool get isInactive => mounts.isEmpty; bool get hasData => data != null; bool get hasError => error != null; diff --git a/packages/fl_query/lib/src/base_query.dart b/packages/fl_query/lib/src/base_query.dart index 2df7e3f..3d4bff5 100644 --- a/packages/fl_query/lib/src/base_query.dart +++ b/packages/fl_query/lib/src/base_query.dart @@ -1,10 +1,8 @@ import 'dart:async'; -import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fl_query/fl_query.dart'; import 'package:fl_query/src/base_operation.dart'; import 'package:fl_query/src/mixins/autocast.dart'; -import 'package:fl_query/src/utils.dart'; import 'package:flutter/widgets.dart'; import 'package:hive/hive.dart'; @@ -45,8 +43,6 @@ abstract class BaseQuery bool? refetchOnApplicationResume; bool? refetchOnWindowFocus; - Connectivity _connectivity; - T? _previousData; BaseQuery({ @@ -57,6 +53,7 @@ abstract class BaseQuery required super.retries, required super.retryDelay, required this.status, + super.connectivity, this.refetchOnMount, this.refetchOnReconnect, this.refetchInterval, @@ -64,14 +61,12 @@ abstract class BaseQuery this.refetchOnWindowFocus, this.enabled = true, T? previousData, - Connectivity? connectivity, T? initialData, onData, onError, }) : _staleTime = staleTime, _initialData = initialData, _externalData = externalData, - _connectivity = connectivity ?? Connectivity(), _previousData = previousData, super(data: previousData ?? initialData) { if (onData != null) onDataListeners.add(onData); @@ -203,7 +198,10 @@ abstract class BaseQuery /// if isLoading/isRefetching is true that means its already fetching/ /// refetching. So [_execute] again can create a race condition - if (isLoading || isRefetching || (hasData && !isPreviousData)) return data; + if (isLoading || + isRefetching || + !(await isNetworkOnline) || + (hasData && !isPreviousData)) return data; status = QueryStatus.loading; notifyListeners(); return execute().then((_) { @@ -227,7 +225,7 @@ abstract class BaseQuery Future refetch() async { /// if isLoading/isRefetching is true that means its already fetching/ /// refetching. So [_execute] again can create a race condition - if (isRefetching || isLoading) return data; + if (isRefetching || isLoading || !(await isNetworkOnline)) return data; if (enabled && !fetched) return await fetch(); status = QueryStatus.refetching; refetchCount++; @@ -349,16 +347,6 @@ abstract class BaseQuery if (updated) notifyListeners(); } - /// checks if the application is connected to internet in any mean - /// - /// It's true when any one this is connected - - /// - ethernet - /// - mobile - /// - wifi - Future isInternetConnected() async { - return isConnectedToInternet(await _connectivity.checkConnectivity()); - } - /// can be used to update the data manually. Can be useful when used /// together with mutations to perform optimistic updates or manual data /// updates diff --git a/packages/fl_query/lib/src/infinite_query.dart b/packages/fl_query/lib/src/infinite_query.dart index 8058808..3fcf398 100644 --- a/packages/fl_query/lib/src/infinite_query.dart +++ b/packages/fl_query/lib/src/infinite_query.dart @@ -129,7 +129,7 @@ class InfiniteQuery (_) async { // only refetch if its connected to the internet or refetch will // always result in error while there's no internet - if (isStale && await isInternetConnected()) await refetchPages(); + if (isStale && await isNetworkOnline) await refetchPages(); }, ); } @@ -241,7 +241,7 @@ class InfiniteQuery /// also checking if the is stale or not /// no need to refetch a valid query for no reason if (refetchOnMount == true && isStale) { - this.isInternetConnected().then((isConnected) async { + isNetworkOnline.then((isConnected) async { if (isConnected) await refetchPages(); }); } diff --git a/packages/fl_query/lib/src/models/mutation_job.dart b/packages/fl_query/lib/src/models/mutation_job.dart index 9d7f9a0..5859f03 100644 --- a/packages/fl_query/lib/src/models/mutation_job.dart +++ b/packages/fl_query/lib/src/models/mutation_job.dart @@ -1,3 +1,4 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fl_query/fl_query.dart'; class MutationJob { @@ -6,10 +7,12 @@ class MutationJob { final int? retries; final Duration? retryDelay; final Duration? cacheTime; + final Connectivity? connectivity; MutationJob({ required String mutationKey, required this.task, + this.connectivity, this.retries, this.retryDelay, this.cacheTime, @@ -28,6 +31,7 @@ class MutationJob { int? retries, Duration? retryDelay, Duration? cacheTime, + Connectivity? connectivity, }) { return (String mutationKey) { if (preMutationKey != null) mutationKey = "$preMutationKey#$mutationKey"; @@ -37,6 +41,7 @@ class MutationJob { retries: retries, retryDelay: retryDelay, cacheTime: cacheTime, + connectivity: connectivity, ); }; } diff --git a/packages/fl_query/lib/src/mutation.dart b/packages/fl_query/lib/src/mutation.dart index 782f71f..51a820b 100644 --- a/packages/fl_query/lib/src/mutation.dart +++ b/packages/fl_query/lib/src/mutation.dart @@ -50,6 +50,7 @@ class Mutation extends BaseOperation required this.task, required super.retries, required super.retryDelay, + super.connectivity, required Duration cacheTime, MutationListener? onData, MutationListener? onError, @@ -73,6 +74,7 @@ class Mutation extends BaseOperation retries: options.retries ?? 3, retryDelay: options.retryDelay ?? const Duration(milliseconds: 200), cacheTime: options.cacheTime ?? const Duration(minutes: 5), + connectivity: options.connectivity, ) { if (onData != null) _onDataListeners.add(onData); if (onError != null) _onErrorListeners.add(onError); @@ -105,6 +107,7 @@ class Mutation extends BaseOperation onError(error, variables, _sideEffectContext); } notifyListeners(); + throw e; } else { // retrying for retry count if failed for the first time while (retryAttempts <= retries) { @@ -128,6 +131,7 @@ class Mutation extends BaseOperation onError(error, variables, _sideEffectContext); } notifyListeners(); + throw e; } retryAttempts++; } @@ -168,10 +172,14 @@ class Mutation extends BaseOperation _variables = variables; if (onData != null) _onDataListeners.add(onData); if (onError != null) _onErrorListeners.add(onError); - _execute(variables).then((_) { - _onDataListeners.remove(onData); - _onErrorListeners.remove(onError); - }); + try { + _execute(variables).then((_) { + _onDataListeners.remove(onData); + _onErrorListeners.remove(onError); + }); + } catch (e) { + return; + } } Future mutateAsync(V variables) async { diff --git a/packages/fl_query/lib/src/query.dart b/packages/fl_query/lib/src/query.dart index bd13062..ac0a691 100644 --- a/packages/fl_query/lib/src/query.dart +++ b/packages/fl_query/lib/src/query.dart @@ -108,7 +108,7 @@ class Query extends BaseQuery { (_) async { // only refetch if its connected to the internet or refetch will // always result in error while there's no internet - if (isStale && await isInternetConnected()) await refetch(); + if (isStale && await isNetworkOnline) await refetch(); }, ); } @@ -123,7 +123,7 @@ class Query extends BaseQuery { /// also checking if the is stale or not /// no need to refetch a valid query for no reason if (refetchOnMount == true && isStale) { - this.isInternetConnected().then((isConnected) async { + isNetworkOnline.then((isConnected) async { if (isConnected) await refetch(); }); } diff --git a/packages/fl_query/lib/src/query_bowl.dart b/packages/fl_query/lib/src/query_bowl.dart index fef421a..f5270d1 100644 --- a/packages/fl_query/lib/src/query_bowl.dart +++ b/packages/fl_query/lib/src/query_bowl.dart @@ -112,12 +112,12 @@ class QueryBowl { .onConnectivityChanged .listen((ConnectivityResult result) async { if (isConnectedToInternet(result)) { - for (final query in this.cache.queries) { + for (final query in this.cache.queries.toList()) { if (query.refetchOnReconnect == false || !query.enabled) continue; await query.refetch(); await Future.delayed(refetchOnReconnectDelay); } - for (final infiniteQuery in this.cache.infiniteQueries) { + for (final infiniteQuery in this.cache.infiniteQueries.toList()) { if (infiniteQuery.refetchOnReconnect == false || !infiniteQuery.enabled) continue; await infiniteQuery.refetchPages(); @@ -130,13 +130,13 @@ class QueryBowl { SystemChannels.lifecycle.setMessageHandler((msg) async { if (msg == 'AppLifecycleState.resumed') { if (_canNotRefetchAfterWeGotTheApp) return null; - for (final query in this.cache.queries) { + for (final query in this.cache.queries.toList()) { if (query.refetchOnApplicationResume == false || !query.enabled) continue; await query.refetch(); await Future.delayed(refetchOnApplicationResumeDelay); } - for (final infiniteQuery in this.cache.infiniteQueries) { + for (final infiniteQuery in this.cache.infiniteQueries.toList()) { if (infiniteQuery.refetchOnApplicationResume == false || !infiniteQuery.enabled) continue; await infiniteQuery.refetchPages(); @@ -185,12 +185,12 @@ class QueryBowl { @protected notifyWindowFocused() async { if (kIsMobile || _canNotRefetchAfterWeGotTheApp) return; - for (final query in this.cache.queries) { + for (final query in this.cache.queries.toList()) { if (query.refetchOnWindowFocus == false || !query.enabled) continue; await query.refetch(); await Future.delayed(refetchOnWindowFocusDelay); } - for (final infiniteQuery in this.cache.infiniteQueries) { + for (final infiniteQuery in this.cache.infiniteQueries.toList()) { if (infiniteQuery.refetchOnWindowFocus == false || !infiniteQuery.enabled) continue; await infiniteQuery.refetchPages();