feat: implement refetchOnApplicationResume and refetchOnWindowFocus

This commit is contained in:
Kingkor Roy Tirtho
2022-10-08 12:44:59 +06:00
parent f0d3bd36a7
commit cd567efb95
10 changed files with 144 additions and 6 deletions
@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/opt/flutter/.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-10-07 11:18:58.310019","version":"3.3.4"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/opt/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/opt/flutter/.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-10-08 11:24:03.169440","version":"3.3.4"}
+16
View File
@@ -41,6 +41,9 @@ abstract class BaseQuery<T extends Object, Outside, Error>
Timer? _refetchIntervalTimer;
bool? refetchOnApplicationResume;
bool? refetchOnWindowFocus;
Connectivity _connectivity;
T? _previousData;
@@ -56,6 +59,8 @@ abstract class BaseQuery<T extends Object, Outside, Error>
this.refetchOnMount,
this.refetchOnReconnect,
this.refetchInterval,
this.refetchOnApplicationResume,
this.refetchOnWindowFocus,
this.enabled = true,
T? previousData,
Connectivity? connectivity,
@@ -245,6 +250,8 @@ abstract class BaseQuery<T extends Object, Outside, Error>
Duration? cacheTime,
bool? refetchOnMount,
bool? refetchOnReconnect,
bool? refetchOnApplicationResume,
bool? refetchOnWindowFocus,
}) {
bool updated = false;
if (this.refetchInterval == null &&
@@ -272,6 +279,15 @@ abstract class BaseQuery<T extends Object, Outside, Error>
this.refetchOnReconnect = refetchOnReconnect;
updated = true;
}
if (this.refetchOnApplicationResume == null &&
refetchOnApplicationResume != null) {
this.refetchOnApplicationResume = refetchOnApplicationResume;
updated = true;
}
if (this.refetchOnWindowFocus == null && refetchOnWindowFocus != null) {
this.refetchOnWindowFocus = refetchOnWindowFocus;
updated = true;
}
if (updated) notifyListeners();
}
@@ -62,6 +62,7 @@ class InfiniteQuery<T extends Object, Outside, PageParam extends Object>
super.enabled,
super.previousData,
super.connectivity,
super.refetchOnApplicationResume,
InfiniteQueryListeners<T, PageParam>? super.onData,
InfiniteQueryListeners<dynamic, PageParam>? super.onError,
required T? initialPage,
@@ -93,6 +94,9 @@ class InfiniteQuery<T extends Object, Outside, PageParam extends Object>
connectivity: options.connectivity ?? Connectivity(),
queryKey: options.queryKey,
initialData: {options.initialParam: options.initialPage},
refetchOnApplicationResume: options.refetchOnApplicationResume,
onData: onData,
onError: onError,
);
List<PageParam> get pageParams => data?.keys.toList() ?? [];
@@ -19,6 +19,8 @@ class InfiniteQueryJob<T extends Object, Outside, PageParam extends Object> {
final bool? refetchOnMount;
final bool? refetchOnReconnect;
final bool? refetchOnExternalDataChange;
final bool? refetchOnApplicationResume;
final bool? refetchOnWindowFocus;
final Duration? staleTime;
final Duration? cacheTime;
@@ -46,6 +48,8 @@ class InfiniteQueryJob<T extends Object, Outside, PageParam extends Object> {
this.refetchOnMount,
this.refetchOnReconnect,
this.refetchOnExternalDataChange,
this.refetchOnApplicationResume,
this.refetchOnWindowFocus,
this.connectivity,
}) : _queryKey = queryKey;
@@ -72,6 +76,8 @@ class InfiniteQueryJob<T extends Object, Outside, PageParam extends Object> {
bool? refetchOnMount,
bool? refetchOnReconnect,
bool? refetchOnExternalDataChange,
bool? refetchOnApplicationResume,
bool? refetchOnWindowFocus,
Connectivity? connectivity,
}) {
return (String queryKey) {
@@ -91,6 +97,8 @@ class InfiniteQueryJob<T extends Object, Outside, PageParam extends Object> {
refetchOnMount: refetchOnMount,
refetchOnReconnect: refetchOnReconnect,
refetchOnExternalDataChange: refetchOnExternalDataChange,
refetchOnApplicationResume: refetchOnApplicationResume,
refetchOnWindowFocus: refetchOnWindowFocus,
connectivity: connectivity,
initialParam: initialParam,
);
@@ -18,6 +18,8 @@ class QueryJob<T extends Object, Outside> {
final bool? refetchOnMount;
final bool? refetchOnReconnect;
final bool? refetchOnExternalDataChange;
final bool? refetchOnApplicationResume;
final bool? refetchOnWindowFocus;
final bool? keepPreviousData;
final Duration? staleTime;
final Duration? cacheTime;
@@ -43,6 +45,8 @@ class QueryJob<T extends Object, Outside> {
this.refetchOnExternalDataChange,
this.connectivity,
this.keepPreviousData,
this.refetchOnApplicationResume,
this.refetchOnWindowFocus,
}) : _queryKey = queryKey;
String get queryKey => _queryKey;
@@ -65,6 +69,8 @@ class QueryJob<T extends Object, Outside> {
bool? refetchOnMount,
bool? refetchOnReconnect,
bool? refetchOnExternalDataChange,
bool? refetchOnApplicationResume,
bool? refetchOnWindowFocus,
Connectivity? connectivity,
bool? keepPreviousData,
}) {
@@ -85,6 +91,8 @@ class QueryJob<T extends Object, Outside> {
refetchOnExternalDataChange: refetchOnExternalDataChange,
connectivity: connectivity,
keepPreviousData: keepPreviousData,
refetchOnApplicationResume: refetchOnApplicationResume,
refetchOnWindowFocus: refetchOnWindowFocus,
);
query.isDynamic = true;
return query;
+4
View File
@@ -58,6 +58,7 @@ class Query<T extends Object, Outside> extends BaseQuery<T, Outside, dynamic> {
super.previousData,
super.connectivity,
super.initialData,
super.refetchOnApplicationResume,
QueryListener<T>? super.onData,
QueryListener<dynamic>? super.onError,
});
@@ -84,6 +85,9 @@ class Query<T extends Object, Outside> extends BaseQuery<T, Outside, dynamic> {
connectivity: options.connectivity ?? Connectivity(),
previousData: previousData,
queryKey: options.queryKey,
refetchOnApplicationResume: options.refetchOnApplicationResume,
onData: onData,
onError: onError,
);
@override
+89 -4
View File
@@ -4,6 +4,7 @@ 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/services.dart';
/// The widget that holds every [Query] & [Mutation] to your
/// entire Flutter application in anywhere
@@ -35,13 +36,31 @@ class QueryBowl {
/// refetch query when new query instance mounts
final bool refetchOnMount;
/// for desktop & web only (DUMMY & isn't implemented yet)
/// refetch when desktop/web app regains Focus
final bool refetchOnWindowFocus;
/// for mobile only (DUMMY & isn't implemented yet)
/// the delay to call each query when desktop/web application gets focused after
/// being unfocused. Using a delay after each refetch so refetching all the
/// queries at once won't create high CPU spikes & also wouldn't violate
/// rate-limit
///
/// Though its recommended most of the time to use but it can be turned
/// off by passing [Duration.zero]
final Duration refetchOnWindowFocusDelay;
/// refetch when application resumes from the background in mobile devices
final bool refetchOnApplicationResume;
/// refetch when user's device reconnects to the internet after no being
/// the delay to call each query when app resumes from the background in
/// mobile devices. Using a delay after each refetch so refetching all the
/// queries at once won't create high CPU spikes & also wouldn't violate
/// rate-limit
///
/// Though its recommended most of the time to use but it can be turned
/// off by passing [Duration.zero]
final Duration refetchOnApplicationResumeDelay;
/// refetch when user's device reconnects to the internet after not being
/// connected before
final bool refetchOnReconnect;
@@ -82,6 +101,8 @@ class QueryBowl {
this.refetchOnMount = false,
this.refetchOnReconnect = true,
this.refetchOnReconnectDelay = const Duration(milliseconds: 100),
this.refetchOnApplicationResumeDelay = const Duration(milliseconds: 100),
this.refetchOnWindowFocusDelay = const Duration(milliseconds: 100),
this.refetchOnApplicationResume = true,
this.refetchOnWindowFocus = true,
this.refetchOnExternalDataChange = false,
@@ -103,8 +124,33 @@ class QueryBowl {
}
}
});
if (kIsMobile) {
SystemChannels.lifecycle.setMessageHandler((msg) async {
if (msg == 'AppLifecycleState.resumed') {
if (_canNotRefetchAfterWeGotTheApp) return null;
for (final query in this.cache.queries) {
if (query.refetchOnApplicationResume == false || !query.enabled)
continue;
await query.refetch();
await Future.delayed(refetchOnApplicationResumeDelay);
}
for (final infiniteQuery in this.cache.infiniteQueries) {
if (infiniteQuery.refetchOnApplicationResume == false ||
!infiniteQuery.enabled) continue;
await infiniteQuery.refetchPages();
await Future.delayed(refetchOnApplicationResumeDelay);
}
} else if (msg != null) {
updateWeLostTheApp();
}
return null;
});
}
}
DateTime? _weLostTheAppAt;
/// Returns the number of query is currently fetching or refetching
int get isFetching {
return cache.queries.fold<int>(
@@ -127,6 +173,30 @@ class QueryBowl {
);
}
bool get _canNotRefetchAfterWeGotTheApp => (_weLostTheAppAt != null &&
_weLostTheAppAt!.difference(DateTime.now()) <= cache.cacheTime);
@protected
updateWeLostTheApp() {
_weLostTheAppAt = DateTime.now();
}
@protected
notifyWindowFocused() async {
if (kIsMobile || _canNotRefetchAfterWeGotTheApp) return;
for (final query in this.cache.queries) {
if (query.refetchOnWindowFocus == false || !query.enabled) continue;
await query.refetch();
await Future.delayed(refetchOnWindowFocusDelay);
}
for (final infiniteQuery in this.cache.infiniteQueries) {
if (infiniteQuery.refetchOnWindowFocus == false || !infiniteQuery.enabled)
continue;
await infiniteQuery.refetchPages();
await Future.delayed(refetchOnWindowFocusDelay);
}
}
void onQueriesUpdate<T extends Object, Outside>(
void Function(Query<T, Outside> query) listener,
) {
@@ -271,6 +341,8 @@ class QueryBowl {
refetchInterval: refetchInterval,
refetchOnMount: refetchOnMount,
refetchOnReconnect: refetchOnReconnect,
refetchOnApplicationResume: refetchOnApplicationResume,
refetchOnWindowFocus: refetchOnWindowFocus,
);
return query;
}
@@ -290,6 +362,8 @@ class QueryBowl {
refetchInterval: refetchInterval,
refetchOnMount: refetchOnMount,
refetchOnReconnect: refetchOnReconnect,
refetchOnApplicationResume: refetchOnApplicationResume,
refetchOnWindowFocus: refetchOnWindowFocus,
);
return infiniteQuery;
}
@@ -478,7 +552,18 @@ class QueryBowlScope extends InheritedWidget {
required this.bowl,
required Widget child,
Key? key,
}) : super(key: key, child: child);
}) : super(
key: key,
child: MouseRegion(
onEnter: (event) {
bowl.notifyWindowFocused();
},
onExit: (event) {
bowl.updateWeLostTheApp();
},
child: child,
),
);
@override
bool updateShouldNotify(covariant oldWidget) => false;
+13
View File
@@ -1,6 +1,8 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:fl_query/src/query.dart';
import 'package:uuid/uuid.dart';
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart';
Future<void> callQueryListeners<T>(Set<QueryListener<T>> listeners, T data) {
return Future.wait(listeners.map(
@@ -54,3 +56,14 @@ bool isConnectedToInternet(ConnectivityResult result) {
String getVariable(String queryKey) {
return queryKey.split("#").last;
}
final kIsDesktop = kIsLinux || kIsWindows || kIsMacOS;
final kIsMobile = kIsAndroid || kIsIOS;
final kIsMacOS = kIsWeb ? false : Platform.isMacOS;
final kIsLinux = kIsWeb ? false : Platform.isLinux;
final kIsAndroid = kIsWeb ? false : Platform.isAndroid;
final kIsIOS = kIsWeb ? false : Platform.isIOS;
final kIsWindows = kIsWeb ? false : Platform.isWindows;
+1 -1
View File
@@ -14,7 +14,7 @@ environment:
dependencies:
collection: ^1.16.0
connectivity_plus: ^2.3.5
connectivity_plus: ^2.3.9
flutter:
sdk: flutter
queue: ^3.1.0+1