From 8c53f1b0fe2a8d3a0e176d134950db7a2b58c3f4 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Jun 2022 13:46:40 +0600 Subject: [PATCH] files moved to src folder added flutter_hooks support with example --- packages/example/lib/another_component.dart | 2 +- packages/example/lib/hooks_example.dart | 27 ++++ packages/example/lib/main.dart | 11 ++ packages/example/pubspec.lock | 9 +- packages/example/pubspec.yaml | 1 + packages/fl_query/lib/fl_query.dart | 14 +- packages/fl_query/lib/fl_query_hooks.dart | 4 + .../lib/{ => src}/base_operation.dart | 0 .../fl_query/lib/src/hooks/use_mutation.dart | 116 +++++++++++++++++ .../fl_query/lib/src/hooks/use_query.dart | 122 ++++++++++++++++++ .../lib/{ => src}/models/mutation_job.dart | 2 +- .../lib/{ => src}/models/query_job.dart | 2 +- packages/fl_query/lib/{ => src}/mutation.dart | 4 +- .../lib/{ => src}/mutation_builder.dart | 8 +- packages/fl_query/lib/{ => src}/query.dart | 4 +- .../fl_query/lib/{ => src}/query_bowl.dart | 8 +- .../fl_query/lib/{ => src}/query_builder.dart | 8 +- packages/fl_query/lib/{ => src}/utils.dart | 2 +- packages/fl_query/pubspec.yaml | 1 + packages/fl_query/test/query_test.dart | 4 +- 20 files changed, 319 insertions(+), 30 deletions(-) create mode 100644 packages/example/lib/hooks_example.dart create mode 100644 packages/fl_query/lib/fl_query_hooks.dart rename packages/fl_query/lib/{ => src}/base_operation.dart (100%) create mode 100644 packages/fl_query/lib/src/hooks/use_mutation.dart create mode 100644 packages/fl_query/lib/src/hooks/use_query.dart rename packages/fl_query/lib/{ => src}/models/mutation_job.dart (96%) rename packages/fl_query/lib/{ => src}/models/query_job.dart (97%) rename packages/fl_query/lib/{ => src}/mutation.dart (97%) rename packages/fl_query/lib/{ => src}/mutation_builder.dart (93%) rename packages/fl_query/lib/{ => src}/query.dart (98%) rename packages/fl_query/lib/{ => src}/query_bowl.dart (98%) rename packages/fl_query/lib/{ => src}/query_builder.dart (94%) rename packages/fl_query/lib/{ => src}/utils.dart (96%) diff --git a/packages/example/lib/another_component.dart b/packages/example/lib/another_component.dart index f774f84..f068388 100644 --- a/packages/example/lib/another_component.dart +++ b/packages/example/lib/another_component.dart @@ -1,4 +1,4 @@ -import 'package:fl_query/query_bowl.dart'; +import 'package:fl_query/fl_query.dart'; import 'package:flutter/material.dart'; class AnotherComponent extends StatelessWidget { diff --git a/packages/example/lib/hooks_example.dart b/packages/example/lib/hooks_example.dart new file mode 100644 index 0000000..2f07d2f --- /dev/null +++ b/packages/example/lib/hooks_example.dart @@ -0,0 +1,27 @@ +import 'package:example/main.dart'; +import 'package:flutter/material.dart'; +import 'package:fl_query/fl_query_hooks.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +class HookExample extends HookWidget { + const HookExample({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final query = useQuery(job: successJob, externalData: null); + + return Scaffold( + appBar: AppBar( + title: const Text("Running the 1st example but with hooks instead"), + ), + body: !query.hasData || query.isLoading || query.isRefetching + ? const CircularProgressIndicator() + : TextButton( + child: Text(query.data!), + onPressed: () async { + await query.refetch(); + }, + ), + ); + } +} diff --git a/packages/example/lib/main.dart b/packages/example/lib/main.dart index f5371fb..c9fa097 100644 --- a/packages/example/lib/main.dart +++ b/packages/example/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:example/another_component.dart'; +import 'package:example/hooks_example.dart'; import 'package:example/lazy_query.dart'; import 'package:example/mutation_example.dart'; import 'package:example/query_with_external_data.dart'; @@ -167,6 +168,16 @@ class _MyHomePageState extends State with WidgetsBindingObserver { ); }, ), + ElevatedButton( + child: const Text("flutter_hooks Example"), + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const HookExample(), + ), + ); + }, + ), const AnotherComponent(), ], ), diff --git a/packages/example/pubspec.lock b/packages/example/pubspec.lock index 26e2b8a..dc5beaa 100644 --- a/packages/example/pubspec.lock +++ b/packages/example/pubspec.lock @@ -76,6 +76,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_hooks: + dependency: "direct main" + description: + name: flutter_hooks + url: "https://pub.dartlang.org" + source: hosted + version: "0.18.5" flutter_lints: dependency: "direct dev" description: @@ -207,4 +214,4 @@ packages: version: "2.1.2" sdks: dart: ">=2.17.1 <3.0.0" - flutter: ">=1.17.0" + flutter: ">=3.0.0" diff --git a/packages/example/pubspec.yaml b/packages/example/pubspec.yaml index 2526f6f..7afba88 100644 --- a/packages/example/pubspec.yaml +++ b/packages/example/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: fl_query: path: ../fl_query http: ^0.13.4 + flutter_hooks: ^0.18.5 dev_dependencies: flutter_test: diff --git a/packages/fl_query/lib/fl_query.dart b/packages/fl_query/lib/fl_query.dart index 676f93d..5bf0401 100644 --- a/packages/fl_query/lib/fl_query.dart +++ b/packages/fl_query/lib/fl_query.dart @@ -1,9 +1,9 @@ library fl_query; -export 'query.dart'; -export 'query_bowl.dart'; -export 'query_builder.dart'; -export 'mutation.dart'; -export 'mutation_builder.dart'; -export 'models/query_job.dart'; -export 'models/mutation_job.dart'; +export 'src/query.dart'; +export 'src/query_bowl.dart'; +export 'src/query_builder.dart'; +export 'src/mutation.dart'; +export 'src/mutation_builder.dart'; +export 'src/models/query_job.dart'; +export 'src/models/mutation_job.dart'; diff --git a/packages/fl_query/lib/fl_query_hooks.dart b/packages/fl_query/lib/fl_query_hooks.dart new file mode 100644 index 0000000..6886efb --- /dev/null +++ b/packages/fl_query/lib/fl_query_hooks.dart @@ -0,0 +1,4 @@ +library fl_query_hooks; + +export 'src/hooks/use_query.dart'; +export 'src/hooks/use_mutation.dart'; diff --git a/packages/fl_query/lib/base_operation.dart b/packages/fl_query/lib/src/base_operation.dart similarity index 100% rename from packages/fl_query/lib/base_operation.dart rename to packages/fl_query/lib/src/base_operation.dart diff --git a/packages/fl_query/lib/src/hooks/use_mutation.dart b/packages/fl_query/lib/src/hooks/use_mutation.dart new file mode 100644 index 0000000..513ec53 --- /dev/null +++ b/packages/fl_query/lib/src/hooks/use_mutation.dart @@ -0,0 +1,116 @@ +import 'package:fl_query/src/models/mutation_job.dart'; +import 'package:fl_query/src/mutation.dart'; +import 'package:fl_query/src/query_bowl.dart'; +import 'package:fl_query/src/utils.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +Mutation useMutation({ + required MutationJob job, + + /// Called when the query returns new data, on query + /// refetch or query gets expired + MutationListener? onData, + + /// Called when the query returns error + MutationListener? onError, + + /// called right before the mutation is about to run + /// + /// perfect scenario for doing optimistic updates + MutationListener? onMutate, + List? keys, +}) { + return use(_UseMutation( + job: job, + onData: onData, + onError: onError, + onMutate: onMutate, + keys: keys, + )); +} + +class _UseMutation extends Hook> { + final MutationJob job; + + /// Called when the query returns new data, on query + /// refetch or query gets expired + final MutationListener? onData; + + /// Called when the query returns error + final MutationListener? onError; + + /// called right before the mutation is about to run + /// + /// perfect scenario for doing optimistic updates + final MutationListener? onMutate; + const _UseMutation({ + required this.job, + this.onData, + this.onError, + this.onMutate, + super.keys, + }); + + @override + HookState, Hook>> createState() => + _UseMutationHookState(); +} + +class _UseMutationHookState + extends HookState, _UseMutation> { + late QueryBowl queryBowl; + late final ValueKey uKey; + late Mutation mutation; + + @override + void initHook() { + super.initHook(); + uKey = ValueKey(uuid.v4()); + mutation = Mutation.fromOptions(hook.job); + WidgetsBinding.instance.addPostFrameCallback((_) { + queryBowl = QueryBowl.of(context); + mutation = queryBowl.addMutation( + mutation, + onData: hook.onData, + onError: hook.onError, + onMutate: hook.onMutate, + key: uKey, + ); + }); + } + + @override + void didUpdateHook(_UseMutation oldHook) { + if (oldHook.onData != hook.onData && oldHook.onData != null) { + mutation.onDataListeners.remove(oldHook.onData); + if (hook.onData != null) mutation.onDataListeners.add(hook.onData!); + } + if (oldHook.onError != hook.onError && oldHook.onError != null) { + mutation.onErrorListeners.remove(oldHook.onError); + if (hook.onError != null) mutation.onErrorListeners.add(hook.onError!); + } + if (oldHook.onMutate != hook.onMutate && oldHook.onMutate != null) { + mutation.onMutateListeners.remove(oldHook.onMutate); + if (hook.onMutate != null) mutation.onMutateListeners.add(hook.onMutate!); + } + super.didUpdateHook(oldHook); + } + + @override + void dispose() { + mutation.unmount(uKey); + if (hook.onData != null) mutation.onDataListeners.remove(hook.onData); + if (hook.onError != null) mutation.onErrorListeners.remove(hook.onError); + if (hook.onMutate != null) mutation.onMutateListeners.remove(hook.onMutate); + } + + @override + Mutation build(BuildContext context) { + queryBowl = QueryBowl.of(context); + return queryBowl.getMutation(mutation.mutationKey) ?? mutation; + } + + @override + String get debugLabel => 'useQuery'; +} diff --git a/packages/fl_query/lib/src/hooks/use_query.dart b/packages/fl_query/lib/src/hooks/use_query.dart new file mode 100644 index 0000000..ea74d72 --- /dev/null +++ b/packages/fl_query/lib/src/hooks/use_query.dart @@ -0,0 +1,122 @@ +import 'package:fl_query/src/models/query_job.dart'; +import 'package:fl_query/src/query.dart'; +import 'package:fl_query/src/query_bowl.dart'; +import 'package:fl_query/src/utils.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +Query useQuery({ + required QueryJob job, + required Outside externalData, + + /// Called when the query returns new data, on query + /// refetch or query gets expired + QueryListener? onData, + + /// Called when the query returns error + QueryListener? onError, + List? keys, +}) { + return use(_UseQuery( + externalData: externalData, + job: job, + onData: onData, + onError: onError, + keys: keys, + )); +} + +class _UseQuery extends Hook> { + final QueryJob job; + final Outside externalData; + + /// Called when the query returns new data, on query + /// refetch or query gets expired + final QueryListener? onData; + + /// Called when the query returns error + final QueryListener? onError; + const _UseQuery({ + required this.job, + required this.externalData, + this.onData, + this.onError, + super.keys, + }); + + @override + HookState, Hook>> createState() => + _UseQueryHookState(); +} + +class _UseQueryHookState + extends HookState, _UseQuery> { + late QueryBowl queryBowl; + late final ValueKey uKey; + late Query query; + + @override + void initHook() { + super.initHook(); + uKey = ValueKey(uuid.v4()); + query = Query.fromOptions( + hook.job, + externalData: hook.externalData, + ); + WidgetsBinding.instance.addPostFrameCallback((_) async { + query = QueryBowl.of(context).addQuery( + query, + key: uKey, + onData: hook.onData, + onError: hook.onError, + ); + final hasExternalDataChanged = query.externalData != null && + query.prevUsedExternalData != null && + !isShallowEqual(query.externalData!, query.prevUsedExternalData!); + (query.fetched && query.refetchOnMount == true) || hasExternalDataChanged + ? await query.refetch() + : await query.fetch(); + }); + } + + @override + void didUpdateHook(_UseQuery oldHook) { + if (oldHook.externalData != null && + hook.externalData != null && + !isShallowEqual(oldHook.externalData!, hook.externalData!)) { + QueryBowl.of(context).fetchQuery( + hook.job, + externalData: hook.externalData, + onData: hook.onData, + onError: hook.onError, + key: uKey, + ); + } else { + if (oldHook.onData != hook.onData && oldHook.onData != null) { + query.onDataListeners.remove(oldHook.onData); + if (hook.onData != null) query.onDataListeners.add(hook.onData!); + } + if (oldHook.onError != hook.onError && oldHook.onError != null) { + query.onErrorListeners.remove(oldHook.onError); + if (hook.onError != null) query.onErrorListeners.add(hook.onError!); + } + } + super.didUpdateHook(oldHook); + } + + @override + void dispose() { + query.unmount(uKey); + if (hook.onData != null) query.onDataListeners.remove(hook.onData); + if (hook.onError != null) query.onErrorListeners.remove(hook.onError); + } + + @override + Query build(BuildContext context) { + queryBowl = QueryBowl.of(context); + return queryBowl.getQuery(query.queryKey) ?? query; + } + + @override + String get debugLabel => 'useQuery'; +} diff --git a/packages/fl_query/lib/models/mutation_job.dart b/packages/fl_query/lib/src/models/mutation_job.dart similarity index 96% rename from packages/fl_query/lib/models/mutation_job.dart rename to packages/fl_query/lib/src/models/mutation_job.dart index 4483c5c..9d7f9a0 100644 --- a/packages/fl_query/lib/models/mutation_job.dart +++ b/packages/fl_query/lib/src/models/mutation_job.dart @@ -1,4 +1,4 @@ -import 'package:fl_query/mutation.dart'; +import 'package:fl_query/fl_query.dart'; class MutationJob { String _mutationKey; diff --git a/packages/fl_query/lib/models/query_job.dart b/packages/fl_query/lib/src/models/query_job.dart similarity index 97% rename from packages/fl_query/lib/models/query_job.dart rename to packages/fl_query/lib/src/models/query_job.dart index 23c8b4e..f4f11e3 100644 --- a/packages/fl_query/lib/models/query_job.dart +++ b/packages/fl_query/lib/src/models/query_job.dart @@ -1,4 +1,4 @@ -import 'package:fl_query/query.dart'; +import 'package:fl_query/src/query.dart'; class QueryJob { // all params diff --git a/packages/fl_query/lib/mutation.dart b/packages/fl_query/lib/src/mutation.dart similarity index 97% rename from packages/fl_query/lib/mutation.dart rename to packages/fl_query/lib/src/mutation.dart index 0fced36..26f839d 100644 --- a/packages/fl_query/lib/mutation.dart +++ b/packages/fl_query/lib/src/mutation.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'package:fl_query/base_operation.dart'; -import 'package:fl_query/models/mutation_job.dart'; +import 'package:fl_query/src/base_operation.dart'; +import 'package:fl_query/src/models/mutation_job.dart'; import 'package:flutter/widgets.dart'; enum MutationStatus { diff --git a/packages/fl_query/lib/mutation_builder.dart b/packages/fl_query/lib/src/mutation_builder.dart similarity index 93% rename from packages/fl_query/lib/mutation_builder.dart rename to packages/fl_query/lib/src/mutation_builder.dart index ac3ab6a..95280a4 100644 --- a/packages/fl_query/lib/mutation_builder.dart +++ b/packages/fl_query/lib/src/mutation_builder.dart @@ -1,7 +1,7 @@ -import 'package:fl_query/models/mutation_job.dart'; -import 'package:fl_query/mutation.dart'; -import 'package:fl_query/query_bowl.dart'; -import 'package:fl_query/utils.dart'; +import 'package:fl_query/src/models/mutation_job.dart'; +import 'package:fl_query/src/mutation.dart'; +import 'package:fl_query/src/query_bowl.dart'; +import 'package:fl_query/src/utils.dart'; import 'package:flutter/widgets.dart'; class MutationBuilder extends StatefulWidget { diff --git a/packages/fl_query/lib/query.dart b/packages/fl_query/lib/src/query.dart similarity index 98% rename from packages/fl_query/lib/query.dart rename to packages/fl_query/lib/src/query.dart index 23523c9..b63a590 100644 --- a/packages/fl_query/lib/query.dart +++ b/packages/fl_query/lib/src/query.dart @@ -1,7 +1,7 @@ import 'dart:async'; -import 'package:fl_query/base_operation.dart'; -import 'package:fl_query/models/query_job.dart'; +import 'package:fl_query/src/base_operation.dart'; +import 'package:fl_query/src/models/query_job.dart'; import 'package:flutter/widgets.dart'; enum QueryStatus { diff --git a/packages/fl_query/lib/query_bowl.dart b/packages/fl_query/lib/src/query_bowl.dart similarity index 98% rename from packages/fl_query/lib/query_bowl.dart rename to packages/fl_query/lib/src/query_bowl.dart index 4268c44..1d36e3f 100644 --- a/packages/fl_query/lib/query_bowl.dart +++ b/packages/fl_query/lib/src/query_bowl.dart @@ -1,10 +1,10 @@ import 'dart:async'; -import 'package:fl_query/models/query_job.dart'; -import 'package:fl_query/mutation.dart'; -import 'package:fl_query/query.dart'; +import 'package:fl_query/src/models/query_job.dart'; +import 'package:fl_query/src/mutation.dart'; +import 'package:fl_query/src/query.dart'; +import 'package:fl_query/src/utils.dart'; import 'package:collection/collection.dart'; -import 'package:fl_query/utils.dart'; import 'package:flutter/widgets.dart'; class QueryBowlScope extends StatefulWidget { diff --git a/packages/fl_query/lib/query_builder.dart b/packages/fl_query/lib/src/query_builder.dart similarity index 94% rename from packages/fl_query/lib/query_builder.dart rename to packages/fl_query/lib/src/query_builder.dart index caf37c1..7a699b0 100644 --- a/packages/fl_query/lib/query_builder.dart +++ b/packages/fl_query/lib/src/query_builder.dart @@ -1,7 +1,7 @@ -import 'package:fl_query/models/query_job.dart'; -import 'package:fl_query/query.dart'; -import 'package:fl_query/query_bowl.dart'; -import 'package:fl_query/utils.dart'; +import 'package:fl_query/src/models/query_job.dart'; +import 'package:fl_query/src/query.dart'; +import 'package:fl_query/src/query_bowl.dart'; +import 'package:fl_query/src/utils.dart'; import 'package:flutter/widgets.dart'; class QueryBuilder extends StatefulWidget { diff --git a/packages/fl_query/lib/utils.dart b/packages/fl_query/lib/src/utils.dart similarity index 96% rename from packages/fl_query/lib/utils.dart rename to packages/fl_query/lib/src/utils.dart index b68b46a..3589c76 100644 --- a/packages/fl_query/lib/utils.dart +++ b/packages/fl_query/lib/src/utils.dart @@ -1,4 +1,4 @@ -import 'package:fl_query/query.dart'; +import 'package:fl_query/src/query.dart'; import 'package:uuid/uuid.dart'; Future callQueryListeners(Set> listeners, T data) { diff --git a/packages/fl_query/pubspec.yaml b/packages/fl_query/pubspec.yaml index e763929..ad44c47 100644 --- a/packages/fl_query/pubspec.yaml +++ b/packages/fl_query/pubspec.yaml @@ -19,6 +19,7 @@ dev_dependencies: sdk: flutter flutter_lints: ^2.0.0 mocktail: ^0.3.0 + flutter_hooks: ^0.18.5 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/packages/fl_query/test/query_test.dart b/packages/fl_query/test/query_test.dart index 4456980..12567be 100644 --- a/packages/fl_query/test/query_test.dart +++ b/packages/fl_query/test/query_test.dart @@ -1,7 +1,7 @@ import 'dart:math'; -import 'package:fl_query/models/query_job.dart'; -import 'package:fl_query/query.dart'; +import 'package:fl_query/src/models/query_job.dart'; +import 'package:fl_query/src/query.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart';