fix: query, infinite_query fetching/refetching when offline
This commit is contained in:
@@ -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<ConnectivityResult> checkConnectivity() {
|
||||
return Future.value(ConnectivityResult.ethernet);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<ConnectivityResult> get onConnectivityChanged => Stream.empty();
|
||||
}
|
||||
@@ -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<Data, Error> extends ChangeNotifier {
|
||||
@@ -10,6 +12,8 @@ abstract class BaseOperation<Data, Error> extends ChangeNotifier {
|
||||
@protected
|
||||
Duration cacheTime;
|
||||
|
||||
Connectivity _connectivity;
|
||||
|
||||
// all properties
|
||||
Data? data;
|
||||
Error? error;
|
||||
@@ -31,7 +35,9 @@ abstract class BaseOperation<Data, Error> extends ChangeNotifier {
|
||||
required this.retries,
|
||||
required this.retryDelay,
|
||||
this.data,
|
||||
}) : updatedAt = DateTime.now();
|
||||
Connectivity? connectivity,
|
||||
}) : updatedAt = DateTime.now(),
|
||||
_connectivity = connectivity ?? Connectivity();
|
||||
|
||||
void mount(ValueKey<String> uKey) {
|
||||
_mounts.add(uKey);
|
||||
@@ -52,6 +58,28 @@ abstract class BaseOperation<Data, Error> extends ChangeNotifier {
|
||||
|
||||
Set<ValueKey<String>> 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<bool> 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<bool> get isNetworkOnline =>
|
||||
_connectivity.checkConnectivity().then((v) => isConnectedToInternet(v));
|
||||
|
||||
bool get isInactive => mounts.isEmpty;
|
||||
bool get hasData => data != null;
|
||||
bool get hasError => error != null;
|
||||
|
||||
@@ -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<T extends Object, Outside, Error>
|
||||
bool? refetchOnApplicationResume;
|
||||
bool? refetchOnWindowFocus;
|
||||
|
||||
Connectivity _connectivity;
|
||||
|
||||
T? _previousData;
|
||||
|
||||
BaseQuery({
|
||||
@@ -57,6 +53,7 @@ abstract class BaseQuery<T extends Object, Outside, Error>
|
||||
required super.retries,
|
||||
required super.retryDelay,
|
||||
required this.status,
|
||||
super.connectivity,
|
||||
this.refetchOnMount,
|
||||
this.refetchOnReconnect,
|
||||
this.refetchInterval,
|
||||
@@ -64,14 +61,12 @@ abstract class BaseQuery<T extends Object, Outside, Error>
|
||||
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<T extends Object, Outside, Error>
|
||||
|
||||
/// 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<T extends Object, Outside, Error>
|
||||
Future<T?> 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<T extends Object, Outside, Error>
|
||||
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<bool> 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
|
||||
|
||||
@@ -129,7 +129,7 @@ class InfiniteQuery<T extends Object, Outside, PageParam extends Object>
|
||||
(_) 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<T extends Object, Outside, PageParam extends Object>
|
||||
/// 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();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:fl_query/fl_query.dart';
|
||||
|
||||
class MutationJob<T extends Object, V> {
|
||||
@@ -6,10 +7,12 @@ class MutationJob<T extends Object, V> {
|
||||
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<T extends Object, V> {
|
||||
int? retries,
|
||||
Duration? retryDelay,
|
||||
Duration? cacheTime,
|
||||
Connectivity? connectivity,
|
||||
}) {
|
||||
return (String mutationKey) {
|
||||
if (preMutationKey != null) mutationKey = "$preMutationKey#$mutationKey";
|
||||
@@ -37,6 +41,7 @@ class MutationJob<T extends Object, V> {
|
||||
retries: retries,
|
||||
retryDelay: retryDelay,
|
||||
cacheTime: cacheTime,
|
||||
connectivity: connectivity,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ class Mutation<T extends Object, V> extends BaseOperation<T, dynamic>
|
||||
required this.task,
|
||||
required super.retries,
|
||||
required super.retryDelay,
|
||||
super.connectivity,
|
||||
required Duration cacheTime,
|
||||
MutationListener<T, V>? onData,
|
||||
MutationListener<dynamic, V>? onError,
|
||||
@@ -73,6 +74,7 @@ class Mutation<T extends Object, V> extends BaseOperation<T, dynamic>
|
||||
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<T extends Object, V> extends BaseOperation<T, dynamic>
|
||||
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<T extends Object, V> extends BaseOperation<T, dynamic>
|
||||
onError(error, variables, _sideEffectContext);
|
||||
}
|
||||
notifyListeners();
|
||||
throw e;
|
||||
}
|
||||
retryAttempts++;
|
||||
}
|
||||
@@ -168,10 +172,14 @@ class Mutation<T extends Object, V> extends BaseOperation<T, dynamic>
|
||||
_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<T?> mutateAsync(V variables) async {
|
||||
|
||||
@@ -108,7 +108,7 @@ class Query<T extends Object, Outside> extends BaseQuery<T, Outside, dynamic> {
|
||||
(_) 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<T extends Object, Outside> extends BaseQuery<T, Outside, dynamic> {
|
||||
/// 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();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user