feat: safe cancellation of running operation on reset

This commit is contained in:
Kingkor Roy Tirtho
2023-02-23 13:14:42 +06:00
parent 68e60c1914
commit 5dde200c84
9 changed files with 67 additions and 37 deletions
@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_macos-1.2.6/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.8/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/kingkor/.pub-cache/hosted/pub.dev/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_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-02-21 09:32:52.281806","version":"3.7.3"} {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_macos-1.2.6/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.8/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/kingkor/.pub-cache/hosted/pub.dev/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_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-02-23 13:13:41.719080","version":"3.7.3"}
-16
View File
@@ -359,14 +359,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.4" version: "4.2.4"
queue:
dependency: transitive
description:
name: queue
sha256: "9a41ecadc15db79010108c06eae229a45c56b18db699760f34e8c9ac9b831ff9"
url: "https://pub.dev"
source: hosted
version: "3.1.0+2"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@@ -436,14 +428,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.3.1"
uuid:
dependency: transitive
description:
name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
url: "https://pub.dev"
source: hosted
version: "3.0.7"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -1,9 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'package:async/async.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:fl_query/fl_query.dart'; import 'package:fl_query/fl_query.dart';
import 'package:fl_query/src/core/retryer.dart'; import 'package:fl_query/src/core/mixins/retryer.dart';
import 'package:fl_query/src/core/validation.dart'; import 'package:fl_query/src/core/mixins/validation.dart';
import 'package:hive_flutter/adapters.dart'; import 'package:hive_flutter/adapters.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
import 'package:state_notifier/state_notifier.dart'; import 'package:state_notifier/state_notifier.dart';
@@ -108,6 +109,8 @@ class InfiniteQuery<DataType, ErrorType, PageType>
final RefreshConfig refreshConfig; final RefreshConfig refreshConfig;
final JsonConfig<DataType>? jsonConfig; final JsonConfig<DataType>? jsonConfig;
final PageType _initialParam;
InfiniteQuery( InfiniteQuery(
this.key, this.key,
InfiniteQueryFn<DataType, PageType> queryFn, { InfiniteQueryFn<DataType, PageType> queryFn, {
@@ -116,7 +119,8 @@ class InfiniteQuery<DataType, ErrorType, PageType>
this.retryConfig = DefaultConstants.retryConfig, this.retryConfig = DefaultConstants.retryConfig,
this.refreshConfig = DefaultConstants.refreshConfig, this.refreshConfig = DefaultConstants.refreshConfig,
this.jsonConfig, this.jsonConfig,
}) : _dataController = StreamController.broadcast(), }) : _initialParam = initialParam,
_dataController = StreamController.broadcast(),
_errorController = StreamController.broadcast(), _errorController = StreamController.broadcast(),
_box = Hive.lazyBox(QueryClient.infiniteQueryCachePrefix), _box = Hive.lazyBox(QueryClient.infiniteQueryCachePrefix),
super(InfiniteQueryState<DataType, ErrorType, PageType>( super(InfiniteQueryState<DataType, ErrorType, PageType>(
@@ -175,6 +179,8 @@ class InfiniteQuery<DataType, ErrorType, PageType>
final StreamController<PageEvent<DataType, PageType>> _dataController; final StreamController<PageEvent<DataType, PageType>> _dataController;
final StreamController<PageEvent<ErrorType, PageType>> _errorController; final StreamController<PageEvent<ErrorType, PageType>> _errorController;
CancelableOperation<void>? _operation;
List<DataType> get pages => List<DataType> get pages =>
state.pages.map((e) => e.data).whereType<DataType>().toList(); state.pages.map((e) => e.data).whereType<DataType>().toList();
List<ErrorType> get errors => List<ErrorType> get errors =>
@@ -197,10 +203,10 @@ class InfiniteQuery<DataType, ErrorType, PageType>
bool get hasNextPage => state.hasNextPage; bool get hasNextPage => state.hasNextPage;
Future<void> _operation(PageType page) { Future<void> _operate(PageType page) {
return _mutex.protect(() async { return _mutex.protect(() async {
state = state.copyWith(); state = state.copyWith();
return await retryOperation( _operation = cancellableRetryOperation(
() => state.queryFn(page), () => state.queryFn(page),
config: retryConfig, config: retryConfig,
onSuccessful: (data) async { onSuccessful: (data) async {
@@ -262,14 +268,14 @@ class InfiniteQuery<DataType, ErrorType, PageType>
final lastPage = state.lastPage; final lastPage = state.lastPage;
if (_mutex.isLocked || hasPageData || hasPageError) if (_mutex.isLocked || hasPageData || hasPageError)
return state.pages.last.data; return state.pages.last.data;
return await _operation(lastPage).then((_) => state.pages.last.data); return await _operate(lastPage).then((_) => state.pages.last.data);
} }
Future<DataType?> refresh([PageType? page]) async { Future<DataType?> refresh([PageType? page]) async {
page ??= lastPage; page ??= lastPage;
if (_mutex.isLocked) if (_mutex.isLocked)
return state.pages.firstWhereOrNull((e) => e.page == page)?.data; return state.pages.firstWhereOrNull((e) => e.page == page)?.data;
return await _operation(page!).then((_) { return await _operate(page!).then((_) {
return state.pages.firstWhereOrNull((e) => e.page == page)?.data; return state.pages.firstWhereOrNull((e) => e.page == page)?.data;
}); });
} }
@@ -277,7 +283,7 @@ class InfiniteQuery<DataType, ErrorType, PageType>
Future<List<DataType>?> refreshAll() async { Future<List<DataType>?> refreshAll() async {
if (_mutex.isLocked) return pages; if (_mutex.isLocked) return pages;
return await Future.wait( return await Future.wait(
state.pages.map((e) => _operation(e.page)), state.pages.map((e) => _operate(e.page)),
).then((_) => pages); ).then((_) => pages);
} }
@@ -286,7 +292,7 @@ class InfiniteQuery<DataType, ErrorType, PageType>
if (_mutex.isLocked || nextPage == null) { if (_mutex.isLocked || nextPage == null) {
return state.pages.lastOrNull?.data; return state.pages.lastOrNull?.data;
} }
return await _operation(nextPage).then((_) { return await _operate(nextPage).then((_) {
return state.pages.firstWhereOrNull((e) => e.page == nextPage)?.data; return state.pages.firstWhereOrNull((e) => e.page == nextPage)?.data;
}); });
} }
@@ -331,6 +337,18 @@ class InfiniteQuery<DataType, ErrorType, PageType>
); );
} }
Future<void> reset() async {
await _operation?.cancel();
state = state.copyWith(pages: {
InfiniteQueryPage<DataType, ErrorType, PageType>(
page: _initialParam,
updatedAt: DateTime.now(),
staleDuration: refreshConfig.staleDuration,
)
});
_box.delete(key);
}
@override @override
RemoveListener addListener( RemoveListener addListener(
Listener<InfiniteQueryState<DataType, ErrorType, PageType>> listener, { Listener<InfiniteQueryState<DataType, ErrorType, PageType>> listener, {
@@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:async/async.dart';
import 'package:fl_query/src/collections/retry_config.dart'; import 'package:fl_query/src/collections/retry_config.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -38,4 +39,20 @@ mixin Retryer<T, E> {
} }
} }
} }
CancelableOperation<void> cancellableRetryOperation(
FutureOr<T?> Function() operation, {
required RetryConfig config,
required void Function(T?) onSuccessful,
required void Function(E?) onFailed,
}) {
return CancelableOperation.fromFuture(
retryOperation(
operation,
config: config,
onSuccessful: onSuccessful,
onFailed: onFailed,
),
);
}
} }
+6 -3
View File
@@ -1,8 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'package:async/async.dart';
import 'package:fl_query/src/collections/default_configs.dart'; import 'package:fl_query/src/collections/default_configs.dart';
import 'package:fl_query/src/collections/retry_config.dart'; import 'package:fl_query/src/collections/retry_config.dart';
import 'package:fl_query/src/core/retryer.dart'; import 'package:fl_query/src/core/mixins/retryer.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
import 'package:state_notifier/state_notifier.dart'; import 'package:state_notifier/state_notifier.dart';
@@ -74,11 +75,12 @@ class Mutation<DataType, ErrorType, VariablesType>
final StreamController<VariablesType> _mutationController; final StreamController<VariablesType> _mutationController;
final StreamController<DataType> _dataController; final StreamController<DataType> _dataController;
final StreamController<ErrorType> _errorController; final StreamController<ErrorType> _errorController;
CancelableOperation<void>? _operation;
Future<void> _operate(VariablesType variables) { Future<void> _operate(VariablesType variables) {
return _mutex.protect(() async { return _mutex.protect(() async {
state = state.copyWith(); state = state.copyWith();
return await retryOperation( _operation = await cancellableRetryOperation(
() { () {
_mutationController.add(variables); _mutationController.add(variables);
return state.mutationFn(variables); return state.mutationFn(variables);
@@ -115,7 +117,8 @@ class Mutation<DataType, ErrorType, VariablesType>
state = state.copyWith(mutationFn: mutationFn, updatedAt: state.updatedAt); state = state.copyWith(mutationFn: mutationFn, updatedAt: state.updatedAt);
} }
void reset() { Future<void> reset() async {
await _operation?.cancel();
state = MutationState<DataType, ErrorType, VariablesType>( state = MutationState<DataType, ErrorType, VariablesType>(
mutationFn: state.mutationFn, mutationFn: state.mutationFn,
); );
+14 -5
View File
@@ -5,11 +5,12 @@ import 'package:fl_query/src/collections/json_config.dart';
import 'package:fl_query/src/collections/refresh_config.dart'; import 'package:fl_query/src/collections/refresh_config.dart';
import 'package:fl_query/src/collections/retry_config.dart'; import 'package:fl_query/src/collections/retry_config.dart';
import 'package:fl_query/src/core/client.dart'; import 'package:fl_query/src/core/client.dart';
import 'package:fl_query/src/core/retryer.dart'; import 'package:fl_query/src/core/mixins/retryer.dart';
import 'package:fl_query/src/core/validation.dart'; import 'package:fl_query/src/core/mixins/validation.dart';
import 'package:hive_flutter/adapters.dart'; import 'package:hive_flutter/adapters.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
import 'package:state_notifier/state_notifier.dart'; import 'package:state_notifier/state_notifier.dart';
import 'package:async/async.dart';
typedef QueryFn<DataType> = FutureOr<DataType?> Function(); typedef QueryFn<DataType> = FutureOr<DataType?> Function();
@@ -73,7 +74,7 @@ class Query<DataType, ErrorType>
)) { )) {
if (jsonConfig != null) { if (jsonConfig != null) {
_mutex.protect(() async { _mutex.protect(() async {
final json = await _box.get(key.toString()); final json = await _box.get(key);
if (json != null) { if (json != null) {
_initial = jsonConfig!.fromJson( _initial = jsonConfig!.fromJson(
Map.castFrom<dynamic, dynamic, String, dynamic>(json), Map.castFrom<dynamic, dynamic, String, dynamic>(json),
@@ -116,10 +117,12 @@ class Query<DataType, ErrorType>
Stream<DataType> get dataStream => _dataController.stream; Stream<DataType> get dataStream => _dataController.stream;
Stream<ErrorType> get errorStream => _errorController.stream; Stream<ErrorType> get errorStream => _errorController.stream;
CancelableOperation<void>? _operation;
Future<void> _operate() { Future<void> _operate() {
return _mutex.protect(() async { return _mutex.protect(() async {
state = state.copyWith(); state = state.copyWith();
return await retryOperation( _operation = cancellableRetryOperation(
state.queryFn, state.queryFn,
config: retryConfig, config: retryConfig,
onSuccessful: (DataType? data) { onSuccessful: (DataType? data) {
@@ -131,7 +134,7 @@ class Query<DataType, ErrorType>
_dataController.add(data); _dataController.add(data);
if (jsonConfig != null) { if (jsonConfig != null) {
_box.put( _box.put(
key.toString(), key,
jsonConfig!.toJson(data), jsonConfig!.toJson(data),
); );
} }
@@ -168,6 +171,12 @@ class Query<DataType, ErrorType>
state = state.copyWith(data: data, updatedAt: DateTime.now()); state = state.copyWith(data: data, updatedAt: DateTime.now());
} }
Future<void> reset() async {
await _operation?.cancel();
state = state.copyWith(data: _initial, updatedAt: DateTime.now());
_box.delete(key);
}
@override @override
RemoveListener addListener(Listener<QueryState<DataType, ErrorType>> listener, RemoveListener addListener(Listener<QueryState<DataType, ErrorType>> listener,
{bool fireImmediately = true}) { {bool fireImmediately = true}) {
+1 -2
View File
@@ -20,8 +20,7 @@ dependencies:
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
state_notifier: ^0.7.2+1 state_notifier: ^0.7.2+1
mutex: ^3.0.1 mutex: ^3.0.1
queue: ^3.1.0+1 async: ^2.10.0
uuid: ^3.0.6
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_macos-1.2.6/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.8/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/kingkor/.pub-cache/hosted/pub.dev/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_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-02-21 09:32:49.296117","version":"3.7.3"} {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"android":[{"name":"connectivity_plus","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus-2.3.9/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_android-2.0.22/","native_build":true,"dependencies":[]}],"macos":[{"name":"connectivity_plus_macos","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_macos-1.2.6/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_foundation-2.1.1/","native_build":true,"dependencies":[]}],"linux":[{"name":"connectivity_plus_linux","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_linux-1.3.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.8/","native_build":false,"dependencies":[]}],"windows":[{"name":"connectivity_plus_windows","path":"/home/kingkor/.pub-cache/hosted/pub.dev/connectivity_plus_windows-1.2.2/","native_build":true,"dependencies":[]},{"name":"path_provider_windows","path":"/home/kingkor/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.3/","native_build":false,"dependencies":[]}],"web":[{"name":"connectivity_plus_web","path":"/home/kingkor/.pub-cache/hosted/pub.dev/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_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-02-23 13:13:38.929384","version":"3.7.3"}