diff --git a/packages/example/macos/Flutter/GeneratedPluginRegistrant.swift b/packages/example/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..be95aee 100644 --- a/packages/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/packages/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,8 @@ import FlutterMacOS import Foundation +import connectivity_plus_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) } diff --git a/packages/example/pubspec.lock b/packages/example/pubspec.lock index dc5beaa..8ca63f7 100644 --- a/packages/example/pubspec.lock +++ b/packages/example/pubspec.lock @@ -1,6 +1,13 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" async: dependency: transitive description: @@ -43,6 +50,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.16.0" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.5" + connectivity_plus_linux: + dependency: transitive + description: + name: connectivity_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + connectivity_plus_macos: + dependency: transitive + description: + name: connectivity_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.4" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + connectivity_plus_web: + dependency: transitive + description: + name: connectivity_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.2" + connectivity_plus_windows: + dependency: transitive + description: + name: connectivity_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.2" crypto: dependency: transitive description: @@ -57,6 +106,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" + dbus: + dependency: transitive + description: + name: dbus + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.5" fake_async: dependency: transitive description: @@ -64,6 +120,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" fl_query: dependency: "direct main" description: @@ -95,6 +158,11 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" http: dependency: "direct main" description: @@ -109,6 +177,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.1" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" lints: dependency: transitive description: @@ -137,6 +212,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + nm: + dependency: transitive + description: + name: nm + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.0" path: dependency: transitive description: @@ -144,6 +226,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" sky_engine: dependency: transitive description: flutter @@ -212,6 +308,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0" sdks: dart: ">=2.17.1 <3.0.0" flutter: ">=3.0.0" diff --git a/packages/example/windows/flutter/generated_plugin_registrant.cc b/packages/example/windows/flutter/generated_plugin_registrant.cc index 8b6d468..8083d74 100644 --- a/packages/example/windows/flutter/generated_plugin_registrant.cc +++ b/packages/example/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); } diff --git a/packages/example/windows/flutter/generated_plugins.cmake b/packages/example/windows/flutter/generated_plugins.cmake index b93c4c3..8cf5d42 100644 --- a/packages/example/windows/flutter/generated_plugins.cmake +++ b/packages/example/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + connectivity_plus_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/packages/fl_query/.flutter-plugins b/packages/fl_query/.flutter-plugins new file mode 100644 index 0000000..a59874f --- /dev/null +++ b/packages/fl_query/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +connectivity_plus=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.5/ +connectivity_plus_linux=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_linux-1.3.1/ +connectivity_plus_macos=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_macos-1.2.4/ +connectivity_plus_web=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_web-1.2.2/ +connectivity_plus_windows=/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus_windows-1.2.2/ diff --git a/packages/fl_query/.flutter-plugins-dependencies b/packages/fl_query/.flutter-plugins-dependencies new file mode 100644 index 0000000..1520781 --- /dev/null +++ b/packages/fl_query/.flutter-plugins-dependencies @@ -0,0 +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.5/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/krtirtho/.pub-cache/hosted/pub.dartlang.org/connectivity_plus-2.3.5/","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.2/","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-06-22 21:14:04.467520","version":"3.0.1"} \ No newline at end of file diff --git a/packages/fl_query/lib/src/models/query_job.dart b/packages/fl_query/lib/src/models/query_job.dart index c4e2007..f3462b6 100644 --- a/packages/fl_query/lib/src/models/query_job.dart +++ b/packages/fl_query/lib/src/models/query_job.dart @@ -31,6 +31,7 @@ class QueryJob { // got from global options bool? refetchOnMount; + bool? refetchOnReconnect; Duration? staleTime; Duration? cacheTime; @@ -47,6 +48,7 @@ class QueryJob { this.enabled, this.refetchInterval, this.refetchOnMount, + this.refetchOnReconnect, }) : _queryKey = queryKey; String get queryKey => _queryKey; @@ -67,6 +69,7 @@ class QueryJob { bool? enabled, Duration? refetchInterval, bool? refetchOnMount, + bool? refetchOnReconnect, }) { return (String queryKey) { if (preQueryKey != null) queryKey = "$preQueryKey#$queryKey"; @@ -81,6 +84,7 @@ class QueryJob { enabled: enabled, refetchInterval: refetchInterval, refetchOnMount: refetchOnMount, + refetchOnReconnect: refetchOnReconnect, ); }; } diff --git a/packages/fl_query/lib/src/query.dart b/packages/fl_query/lib/src/query.dart index fc37ce5..56970ed 100644 --- a/packages/fl_query/lib/src/query.dart +++ b/packages/fl_query/lib/src/query.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fl_query/src/base_operation.dart'; import 'package:fl_query/src/models/query_job.dart'; import 'package:fl_query/src/query_bowl.dart'; @@ -44,6 +45,7 @@ class Query extends BaseOperation { QueryTaskFunction task; bool? refetchOnMount; + bool? refetchOnReconnect; final T? _initialData; @@ -83,6 +85,7 @@ class Query extends BaseOperation { required super.retryDelay, required this.queryBowl, this.refetchOnMount, + this.refetchOnReconnect, this.refetchInterval, this.enabled = true, T? initialData, @@ -117,6 +120,7 @@ class Query extends BaseOperation { _externalData = externalData, refetchInterval = options.refetchInterval, refetchOnMount = options.refetchOnMount, + refetchOnReconnect = options.refetchOnReconnect, super( status: QueryStatus.idle, cacheTime: options.cacheTime ?? const Duration(minutes: 5), @@ -137,7 +141,11 @@ class Query extends BaseOperation { return Timer.periodic( refetchInterval!, (_) async { - if (isStale) await refetch(); + // only refetch if its connected to the internet or refetch will + // always result in error while there's no internet + if (isStale && + isConnectedToInternet(await Connectivity().checkConnectivity())) + await refetch(); }, ); } @@ -278,6 +286,7 @@ class Query extends BaseOperation { Duration? staleTime, Duration? cacheTime, bool? refetchOnMount, + bool? refetchOnReconnect, }) { if (this.refetchInterval == null && refetchInterval != null && @@ -292,12 +301,14 @@ class Query extends BaseOperation { staleTime != null) this._staleTime = staleTime; if (this.refetchOnMount == null && refetchOnMount != null) this.refetchOnMount = refetchOnMount; + if (this.refetchOnReconnect == null && refetchOnReconnect != null) + this.refetchOnReconnect = refetchOnReconnect; notifyListeners(); } Map, Query> _dependencyQueries = {}; - /// only usable inside any task method + /// only usable inside [QueryJob.task] method Query dependOnQuery( QueryJob job, { required Outside externalData, diff --git a/packages/fl_query/lib/src/query_bowl.dart b/packages/fl_query/lib/src/query_bowl.dart index 3f1c08e..ac74046 100644 --- a/packages/fl_query/lib/src/query_bowl.dart +++ b/packages/fl_query/lib/src/query_bowl.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fl_query/src/models/query_job.dart'; import 'package:fl_query/src/mutation.dart'; import 'package:fl_query/src/query.dart'; @@ -14,16 +15,28 @@ class QueryBowlScope extends StatefulWidget { // refetching options - // refetch query when new query instance mounts + /// refetch query when new query instance mounts final bool refetchOnMount; - // for desktop & web only + + /// for desktop & web only final bool refetchOnWindowFocus; - // for mobile only + + /// for mobile only final bool refetchOnApplicationResume; - // refetch when user's device reconnects to the internet after no being - // connected before + + /// refetch when user's device reconnects to the internet after no being + /// connected before final bool refetchOnReconnect; + /// the delay to call each query when user device reconnects to the + /// internet. 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 setting passing [Duration.zero] + final Duration refetchOnReconnectDelay; + /// used for periodically checking if any query got stale. /// If none is supplied then half of the value of staleTime is used final Duration refetchInterval; @@ -34,6 +47,7 @@ class QueryBowlScope extends StatefulWidget { this.refetchInterval = Duration.zero, this.refetchOnMount = false, this.refetchOnReconnect = true, + this.refetchOnReconnectDelay = const Duration(milliseconds: 100), this.refetchOnApplicationResume = true, this.refetchOnWindowFocus = true, Key? key, @@ -47,16 +61,31 @@ class _QueryBowlScopeState extends State { late Set queries; late Set mutations; + StreamSubscription? _connectionStatusSubscription; + @override void initState() { super.initState(); queries = {}; mutations = {}; + + _connectionStatusSubscription = Connectivity() + .onConnectivityChanged + .listen((ConnectivityResult result) async { + if (isConnectedToInternet(result)) { + for (final query in queries) { + if (query.refetchOnReconnect == false) continue; + await query.refetch(); + await Future.delayed(widget.refetchOnReconnectDelay); + } + } + }); } @override void dispose() { _disposeUpdateListeners(); + _connectionStatusSubscription?.cancel(); super.dispose(); } @@ -166,6 +195,7 @@ class _QueryBowlScopeState extends State { cacheTime: widget.cacheTime, refetchInterval: widget.refetchInterval, refetchOnMount: widget.refetchOnMount, + refetchOnReconnect: widget.refetchOnReconnect, child: widget.child, ); } @@ -181,6 +211,7 @@ class QueryBowl extends InheritedWidget { final Duration? refetchInterval; final bool refetchOnMount; + final bool refetchOnReconnect; final void Function(Query query) _addQuery; @@ -206,6 +237,7 @@ class QueryBowl extends InheritedWidget { required this.removeQueries, required this.clear, required this.refetchOnMount, + required this.refetchOnReconnect, this.refetchInterval, Key? key, }) : _addQuery = addQuery, @@ -251,6 +283,7 @@ class QueryBowl extends InheritedWidget { options.staleTime ??= staleTime; options.cacheTime ??= cacheTime; options.refetchOnMount ??= refetchOnMount; + options.refetchOnReconnect ??= refetchOnReconnect; final query = Query.fromOptions( options, externalData: externalData, @@ -296,6 +329,7 @@ class QueryBowl extends InheritedWidget { staleTime: staleTime, refetchInterval: refetchInterval, refetchOnMount: refetchOnMount, + refetchOnReconnect: refetchOnReconnect, ); query.mount(key); _addQuery(query); diff --git a/packages/fl_query/lib/src/utils.dart b/packages/fl_query/lib/src/utils.dart index 3589c76..36f93cf 100644 --- a/packages/fl_query/lib/src/utils.dart +++ b/packages/fl_query/lib/src/utils.dart @@ -1,3 +1,4 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fl_query/src/query.dart'; import 'package:uuid/uuid.dart'; @@ -41,3 +42,11 @@ bool isShallowEqual(Object obj1, Object obj2) { return obj1 == obj2; } } + +bool isConnectedToInternet(ConnectivityResult result) { + return [ + ConnectivityResult.ethernet, + ConnectivityResult.mobile, + ConnectivityResult.wifi, + ].contains(result); +} diff --git a/packages/fl_query/pubspec.yaml b/packages/fl_query/pubspec.yaml index ad44c47..dfced3b 100644 --- a/packages/fl_query/pubspec.yaml +++ b/packages/fl_query/pubspec.yaml @@ -10,6 +10,7 @@ environment: dependencies: async: ^2.8.2 collection: ^1.16.0 + connectivity_plus: ^2.3.5 flutter: sdk: flutter uuid: ^3.0.6