diff --git a/packages/fl_query/example/lib/main.dart b/packages/fl_query/example/lib/main.dart index 5316166..3e27f51 100644 --- a/packages/fl_query/example/lib/main.dart +++ b/packages/fl_query/example/lib/main.dart @@ -21,6 +21,18 @@ class MainApp extends StatelessWidget { final value = Random().nextInt(200000); return MaterialApp( home: Scaffold( + floatingActionButton: QueryListenable( + const ValueKey('hello'), builder: (context, query) { + if (query == null) { + return const SizedBox(); + } + return FloatingActionButton( + onPressed: () { + query.refresh(); + }, + child: Text(query.data ?? 'No Data'), + ); + }), body: QueryBuilder( const ValueKey('hello'), () { diff --git a/packages/fl_query/lib/fl_query.dart b/packages/fl_query/lib/fl_query.dart index 4baea9c..094f00f 100644 --- a/packages/fl_query/lib/fl_query.dart +++ b/packages/fl_query/lib/fl_query.dart @@ -12,3 +12,4 @@ export 'src/core/provider.dart'; export 'src/core/query.dart'; export 'src/widgets/query_builder.dart'; +export 'src/widgets/query_listenable.dart'; diff --git a/packages/fl_query/lib/src/widgets/query_listenable.dart b/packages/fl_query/lib/src/widgets/query_listenable.dart new file mode 100644 index 0000000..36f8d7c --- /dev/null +++ b/packages/fl_query/lib/src/widgets/query_listenable.dart @@ -0,0 +1,35 @@ +import 'package:fl_query/fl_query.dart'; +import 'package:flutter/material.dart'; +import 'package:fl_query/src/widgets/state_notifier_listenable.dart'; + +typedef QueryListenableBuilder = Widget Function( + BuildContext context, + Query? query, +); + +class QueryListenable extends StatelessWidget { + final ValueKey queryKey; + final QueryListenableBuilder builder; + const QueryListenable( + this.queryKey, { + required this.builder, + super.key, + }); + + @override + Widget build(BuildContext context) { + final query = QueryClient.of(context) + .getQuery(queryKey); + + if (query == null) { + return builder(context, null); + } + return StateNotifierListenable>( + notifier: query, + builder: (context, notifier) { + final query = notifier as Query; + return builder(context, query); + }, + ); + } +} diff --git a/packages/fl_query/lib/src/widgets/state_notifier_listenable.dart b/packages/fl_query/lib/src/widgets/state_notifier_listenable.dart new file mode 100644 index 0000000..bc99653 --- /dev/null +++ b/packages/fl_query/lib/src/widgets/state_notifier_listenable.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:state_notifier/state_notifier.dart'; + +typedef StateNotifierListenableBuilder = Widget Function( + BuildContext context, + StateNotifier value, +); + +class StateNotifierListenable extends StatefulWidget { + final StateNotifier notifier; + final StateNotifierListenableBuilder builder; + const StateNotifierListenable({ + required this.notifier, + required this.builder, + super.key, + }); + + @override + State> createState() => + _StateNotifierListenableState(); +} + +class _StateNotifierListenableState + extends State> { + VoidCallback? removeListener; + + void initialize() { + removeListener = widget.notifier.addListener((_) { + setState(() {}); + }); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + initialize(); + }); + } + + @override + void dispose() { + removeListener?.call(); + super.dispose(); + } + + @override + void didUpdateWidget(covariant StateNotifierListenable oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.notifier != widget.notifier) { + removeListener?.call(); + initialize(); + } + } + + @override + Widget build(BuildContext context) { + return widget.builder(context, widget.notifier); + } +}