Files
fl-query/packages/fl_query/lib/src/widgets/query_builder.dart
T
2023-02-23 10:58:31 +06:00

184 lines
5.2 KiB
Dart

import 'dart:async';
import 'package:fl_query/src/collections/default_configs.dart';
import 'package:fl_query/src/collections/json_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/core/client.dart';
import 'package:fl_query/src/core/query.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/diagnostics.dart';
typedef QueryBuilderFn<DataType, ErrorType, KeyType> = Widget Function(
BuildContext context,
Query<DataType, ErrorType, KeyType> query,
);
class QueryBuilder<DataType, ErrorType, KeyType> extends StatefulWidget {
final QueryFn<DataType> queryFn;
final ValueKey<KeyType> queryKey;
final DataType? initial;
final RetryConfig retryConfig;
final RefreshConfig refreshConfig;
final JsonConfig<DataType>? jsonConfig;
final ValueChanged<DataType>? onData;
final ValueChanged<ErrorType>? onError;
// widget specific
final bool enabled;
final QueryBuilderFn<DataType, ErrorType, KeyType> builder;
const QueryBuilder(
this.queryKey,
this.queryFn, {
required this.builder,
this.initial,
this.retryConfig = DefaultConstants.retryConfig,
this.refreshConfig = DefaultConstants.refreshConfig,
this.jsonConfig,
this.onData,
this.onError,
this.enabled = true,
super.key,
}) : assert(
(jsonConfig != null && enabled) || jsonConfig == null,
'jsonConfig is only supported when enabled is true',
);
@override
State<QueryBuilder<DataType, ErrorType, KeyType>> createState() =>
_QueryBuilderState<DataType, ErrorType, KeyType>();
}
class _QueryBuilderState<DataType, ErrorType, KeyType>
extends State<QueryBuilder<DataType, ErrorType, KeyType>> {
Query<DataType, ErrorType, KeyType>? query;
VoidCallback? removeListener;
StreamSubscription<DataType>? dataSubscription;
StreamSubscription<ErrorType>? errorSubscription;
void update(_) {
if (mounted) setState(() {});
}
Future<void> initialize() async {
setState(() {
query = QueryClient.of(context).createQuery(
widget.queryKey,
widget.queryFn,
initial: widget.initial,
retryConfig: widget.retryConfig,
refreshConfig: widget.refreshConfig,
jsonConfig: widget.jsonConfig,
);
if (widget.onData != null)
dataSubscription = query!.dataStream.listen(widget.onData);
if (widget.onData != null)
errorSubscription = query!.errorStream.listen(widget.onError);
removeListener = query!.addListener(update);
});
if (widget.enabled) {
await query!.fetch();
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
await initialize();
});
}
@override
void dispose() {
dataSubscription?.cancel();
errorSubscription?.cancel();
removeListener?.call();
super.dispose();
}
@override
void didUpdateWidget(
QueryBuilder<DataType, ErrorType, KeyType> oldWidget,
) {
super.didUpdateWidget(oldWidget);
if (oldWidget.queryKey != widget.queryKey) {
dataSubscription?.cancel();
errorSubscription?.cancel();
removeListener?.call();
initialize();
return;
} else if (oldWidget.enabled != widget.enabled && widget.enabled) {
query!.fetch();
}
if (oldWidget.queryFn != widget.queryFn) {
query!.updateQueryFn(widget.queryFn);
}
if (oldWidget.onData != widget.onData) {
dataSubscription?.cancel();
if (widget.onData != null)
dataSubscription = query!.dataStream.listen(widget.onData);
}
if (oldWidget.onError != widget.onError) {
errorSubscription?.cancel();
if (widget.onError != null)
errorSubscription = query!.errorStream.listen(widget.onError);
}
}
@override
Widget build(BuildContext context) {
if (query == null) {
return const SizedBox.shrink();
}
return widget.builder(context, query!);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(
DiagnosticsProperty<Query<DataType, ErrorType, KeyType>>('query', query),
);
properties.add(
DiagnosticsProperty<ValueKey<KeyType>>('queryKey', widget.queryKey),
);
properties.add(
DiagnosticsProperty<QueryBuilderFn<DataType, ErrorType, KeyType>>(
'builder', widget.builder),
);
properties.add(DiagnosticsProperty<DataType>('initial', widget.initial));
properties.add(
DiagnosticsProperty<RetryConfig>('retryConfig', widget.retryConfig),
);
properties.add(
DiagnosticsProperty<RefreshConfig>(
'refreshConfig',
widget.refreshConfig,
),
);
properties.add(
DiagnosticsProperty<JsonConfig<DataType>>(
'jsonConfig',
widget.jsonConfig,
),
);
properties.add(
DiagnosticsProperty<ValueChanged<DataType>>('onData', widget.onData),
);
properties.add(
DiagnosticsProperty<ValueChanged<ErrorType>>('onError', widget.onError),
);
properties.add(DiagnosticsProperty<bool>('enabled', widget.enabled));
}
}