feat: infinite query listenable add and cache event stream

This commit is contained in:
Kingkor Roy Tirtho
2023-02-21 12:47:34 +06:00
parent efa2c81505
commit 783a2737b1
5 changed files with 158 additions and 4 deletions
@@ -40,6 +40,15 @@ class _InfiniteQueryPageWidgetState extends State<InfiniteQueryPageWidget> {
appBar: AppBar(
title: const Text('Infinite Query'),
),
floatingActionButton: InfiniteQueryListenable(const ValueKey("products"),
builder: (context, query) {
return FloatingActionButton(
onPressed: () {
query?.fetchNext();
},
child: Text(query?.pages.length.toString() ?? "-69"),
);
}),
body: InfiniteQueryBuilder<PagedProducts, ClientException, String, int>(
const ValueKey("products"),
(page) async {
+1
View File
@@ -14,3 +14,4 @@ export 'src/core/query.dart';
export 'src/widgets/query_builder.dart';
export 'src/widgets/query_listenable.dart';
export 'src/widgets/infinite_query_builder.dart';
export 'src/widgets/infinite_query_listenable.dart';
+30
View File
@@ -5,12 +5,28 @@ import 'package:fl_query/src/collections/default_configs.dart';
import 'package:fl_query/src/core/infinite_query.dart';
import 'package:fl_query/src/core/query.dart';
enum QueryCacheEventType {
addQuery,
addInfiniteQuery,
removeQuery,
removeInfiniteQuery,
}
class QueryCacheEvent {
final QueryCacheEventType type;
final Object data;
QueryCacheEvent(this.type, this.data);
}
class QueryCache {
final Set<Query> _queries;
final Set<InfiniteQuery> _infiniteQueries;
final Duration cacheDuration;
final _eventController = StreamController<QueryCacheEvent>.broadcast();
QueryCache({
this.cacheDuration = DefaultConstants.cacheDuration,
}) : _queries = Set<Query>(),
@@ -25,19 +41,33 @@ class QueryCache {
UnmodifiableSetView<InfiniteQuery> get infiniteQueries =>
UnmodifiableSetView(_infiniteQueries);
Stream<QueryCacheEvent> get events => _eventController.stream;
void addQuery(Query query) {
_queries.add(query);
_eventController.add(
QueryCacheEvent(QueryCacheEventType.addQuery, query),
);
}
void addInfiniteQuery(InfiniteQuery query) {
_infiniteQueries.add(query);
_eventController.add(
QueryCacheEvent(QueryCacheEventType.addInfiniteQuery, query),
);
}
void removeQuery(Query query) {
_queries.remove(query);
_eventController.add(
QueryCacheEvent(QueryCacheEventType.removeQuery, query),
);
}
void removeInfiniteQuery(InfiniteQuery query) {
_infiniteQueries.remove(query);
_eventController.add(
QueryCacheEvent(QueryCacheEventType.removeInfiniteQuery, query),
);
}
}
@@ -0,0 +1,79 @@
import 'dart:async';
import 'package:fl_query/fl_query.dart';
import 'package:flutter/material.dart';
import 'package:fl_query/src/widgets/state_notifier_listenable.dart';
typedef InfiniteQueryListenableBuilder<DataType, ErrorType, KeyType, PageType>
= Widget Function(
BuildContext context,
InfiniteQuery<DataType, ErrorType, KeyType, PageType>? query,
);
class InfiniteQueryListenable<DataType, ErrorType, KeyType, PageType>
extends StatefulWidget {
final ValueKey<KeyType> queryKey;
final InfiniteQueryListenableBuilder<DataType, ErrorType, KeyType, PageType>
builder;
const InfiniteQueryListenable(
this.queryKey, {
required this.builder,
super.key,
});
@override
State<InfiniteQueryListenable<DataType, ErrorType, KeyType, PageType>>
createState() => _InfiniteQueryListenableState<DataType, ErrorType,
KeyType, PageType>();
}
class _InfiniteQueryListenableState<DataType, ErrorType, KeyType, PageType>
extends State<
InfiniteQueryListenable<DataType, ErrorType, KeyType, PageType>> {
StreamSubscription<QueryCacheEvent>? _subscription;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_subscription = QueryClient.of(context).cache.events.listen((event) {
switch (event.type) {
case QueryCacheEventType.addInfiniteQuery:
case QueryCacheEventType.removeInfiniteQuery:
if (mounted &&
(event.data as InfiniteQuery).key == widget.queryKey) {
setState(() {});
}
break;
default:
}
});
});
}
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final query = QueryClient.of(context)
.getInfiniteQuery<DataType, ErrorType, KeyType, PageType>(
widget.queryKey);
if (query == null) {
return widget.builder(context, null);
}
return StateNotifierListenable<
InfiniteQueryState<DataType, ErrorType, PageType>>(
notifier: query,
builder: (context, notifier) {
final query =
notifier as InfiniteQuery<DataType, ErrorType, KeyType, PageType>;
return widget.builder(context, query);
},
);
}
}
@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:fl_query/fl_query.dart';
import 'package:flutter/material.dart';
import 'package:fl_query/src/widgets/state_notifier_listenable.dart';
@@ -7,7 +9,7 @@ typedef QueryListenableBuilder<DataType, ErrorType, KeyType> = Widget Function(
Query<DataType, ErrorType, KeyType>? query,
);
class QueryListenable<DataType, ErrorType, KeyType> extends StatelessWidget {
class QueryListenable<DataType, ErrorType, KeyType> extends StatefulWidget {
final ValueKey<KeyType> queryKey;
final QueryListenableBuilder<DataType, ErrorType, KeyType> builder;
const QueryListenable(
@@ -16,19 +18,52 @@ class QueryListenable<DataType, ErrorType, KeyType> extends StatelessWidget {
super.key,
});
@override
State<QueryListenable<DataType, ErrorType, KeyType>> createState() =>
_QueryListenableState<DataType, ErrorType, KeyType>();
}
class _QueryListenableState<DataType, ErrorType, KeyType>
extends State<QueryListenable<DataType, ErrorType, KeyType>> {
StreamSubscription<QueryCacheEvent>? _subscription;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_subscription = QueryClient.of(context).cache.events.listen((event) {
switch (event.type) {
case QueryCacheEventType.addQuery:
case QueryCacheEventType.removeQuery:
if (mounted && (event.data as Query).key == widget.queryKey) {
setState(() {});
}
break;
default:
}
});
});
}
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final query = QueryClient.of(context)
.getQuery<DataType, ErrorType, KeyType>(queryKey);
.getQuery<DataType, ErrorType, KeyType>(widget.queryKey);
if (query == null) {
return builder(context, null);
return widget.builder(context, null);
}
return StateNotifierListenable<QueryState<DataType, ErrorType>>(
notifier: query,
builder: (context, notifier) {
final query = notifier as Query<DataType, ErrorType, KeyType>;
return builder(context, query);
return widget.builder(context, query);
},
);
}