feat: infinite query listenable add and cache event stream
This commit is contained in:
@@ -40,6 +40,15 @@ class _InfiniteQueryPageWidgetState extends State<InfiniteQueryPageWidget> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Infinite Query'),
|
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>(
|
body: InfiniteQueryBuilder<PagedProducts, ClientException, String, int>(
|
||||||
const ValueKey("products"),
|
const ValueKey("products"),
|
||||||
(page) async {
|
(page) async {
|
||||||
|
|||||||
@@ -14,3 +14,4 @@ export 'src/core/query.dart';
|
|||||||
export 'src/widgets/query_builder.dart';
|
export 'src/widgets/query_builder.dart';
|
||||||
export 'src/widgets/query_listenable.dart';
|
export 'src/widgets/query_listenable.dart';
|
||||||
export 'src/widgets/infinite_query_builder.dart';
|
export 'src/widgets/infinite_query_builder.dart';
|
||||||
|
export 'src/widgets/infinite_query_listenable.dart';
|
||||||
|
|||||||
@@ -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/infinite_query.dart';
|
||||||
import 'package:fl_query/src/core/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 {
|
class QueryCache {
|
||||||
final Set<Query> _queries;
|
final Set<Query> _queries;
|
||||||
final Set<InfiniteQuery> _infiniteQueries;
|
final Set<InfiniteQuery> _infiniteQueries;
|
||||||
|
|
||||||
final Duration cacheDuration;
|
final Duration cacheDuration;
|
||||||
|
|
||||||
|
final _eventController = StreamController<QueryCacheEvent>.broadcast();
|
||||||
|
|
||||||
QueryCache({
|
QueryCache({
|
||||||
this.cacheDuration = DefaultConstants.cacheDuration,
|
this.cacheDuration = DefaultConstants.cacheDuration,
|
||||||
}) : _queries = Set<Query>(),
|
}) : _queries = Set<Query>(),
|
||||||
@@ -25,19 +41,33 @@ class QueryCache {
|
|||||||
UnmodifiableSetView<InfiniteQuery> get infiniteQueries =>
|
UnmodifiableSetView<InfiniteQuery> get infiniteQueries =>
|
||||||
UnmodifiableSetView(_infiniteQueries);
|
UnmodifiableSetView(_infiniteQueries);
|
||||||
|
|
||||||
|
Stream<QueryCacheEvent> get events => _eventController.stream;
|
||||||
|
|
||||||
void addQuery(Query query) {
|
void addQuery(Query query) {
|
||||||
_queries.add(query);
|
_queries.add(query);
|
||||||
|
_eventController.add(
|
||||||
|
QueryCacheEvent(QueryCacheEventType.addQuery, query),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addInfiniteQuery(InfiniteQuery query) {
|
void addInfiniteQuery(InfiniteQuery query) {
|
||||||
_infiniteQueries.add(query);
|
_infiniteQueries.add(query);
|
||||||
|
_eventController.add(
|
||||||
|
QueryCacheEvent(QueryCacheEventType.addInfiniteQuery, query),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeQuery(Query query) {
|
void removeQuery(Query query) {
|
||||||
_queries.remove(query);
|
_queries.remove(query);
|
||||||
|
_eventController.add(
|
||||||
|
QueryCacheEvent(QueryCacheEventType.removeQuery, query),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeInfiniteQuery(InfiniteQuery query) {
|
void removeInfiniteQuery(InfiniteQuery query) {
|
||||||
_infiniteQueries.remove(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:fl_query/fl_query.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fl_query/src/widgets/state_notifier_listenable.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,
|
Query<DataType, ErrorType, KeyType>? query,
|
||||||
);
|
);
|
||||||
|
|
||||||
class QueryListenable<DataType, ErrorType, KeyType> extends StatelessWidget {
|
class QueryListenable<DataType, ErrorType, KeyType> extends StatefulWidget {
|
||||||
final ValueKey<KeyType> queryKey;
|
final ValueKey<KeyType> queryKey;
|
||||||
final QueryListenableBuilder<DataType, ErrorType, KeyType> builder;
|
final QueryListenableBuilder<DataType, ErrorType, KeyType> builder;
|
||||||
const QueryListenable(
|
const QueryListenable(
|
||||||
@@ -16,19 +18,52 @@ class QueryListenable<DataType, ErrorType, KeyType> extends StatelessWidget {
|
|||||||
super.key,
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final query = QueryClient.of(context)
|
final query = QueryClient.of(context)
|
||||||
.getQuery<DataType, ErrorType, KeyType>(queryKey);
|
.getQuery<DataType, ErrorType, KeyType>(widget.queryKey);
|
||||||
|
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
return builder(context, null);
|
return widget.builder(context, null);
|
||||||
}
|
}
|
||||||
return StateNotifierListenable<QueryState<DataType, ErrorType>>(
|
return StateNotifierListenable<QueryState<DataType, ErrorType>>(
|
||||||
notifier: query,
|
notifier: query,
|
||||||
builder: (context, notifier) {
|
builder: (context, notifier) {
|
||||||
final query = notifier as Query<DataType, ErrorType, KeyType>;
|
final query = notifier as Query<DataType, ErrorType, KeyType>;
|
||||||
return builder(context, query);
|
return widget.builder(context, query);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user