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:flutter/widgets.dart'; class MutationBuilder extends StatefulWidget { final Function(BuildContext, Mutation) builder; 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 MutationBuilder({ required this.job, required this.builder, this.onData, this.onError, this.onMutate, Key? key, }) : super(key: key); @override State> createState() => _MutationBuilderState(); } class _MutationBuilderState extends State> { late QueryBowl queryBowl; late ValueKey uKey; late Mutation mutation; @override void initState() { super.initState(); uKey = ValueKey(uuid.v4()); mutation = Mutation.fromOptions(widget.job); WidgetsBinding.instance.addPostFrameCallback((_) { queryBowl = QueryBowl.of(context); mutation = queryBowl.addMutation( mutation, onData: widget.onData, onError: widget.onError, onMutate: widget.onMutate, key: uKey, ); }); } @override void didUpdateWidget(covariant MutationBuilder oldWidget) { if (oldWidget.onData != widget.onData && oldWidget.onData != null) { mutation.onDataListeners.remove(oldWidget.onData); if (widget.onData != null) mutation.onDataListeners.add(widget.onData!); } if (oldWidget.onError != widget.onError && oldWidget.onError != null) { mutation.onErrorListeners.remove(oldWidget.onError); if (widget.onError != null) mutation.onErrorListeners.add(widget.onError!); } if (oldWidget.onMutate != widget.onMutate && oldWidget.onMutate != null) { mutation.onMutateListeners.remove(oldWidget.onMutate); if (widget.onMutate != null) mutation.onMutateListeners.add(widget.onMutate!); } super.didUpdateWidget(oldWidget); } @override void dispose() { mutation.unmount(uKey); if (widget.onData != null) mutation.onDataListeners.remove(widget.onData); if (widget.onError != null) mutation.onErrorListeners.remove(widget.onError); if (widget.onMutate != null) mutation.onMutateListeners.remove(widget.onMutate); super.dispose(); } @override Widget build(BuildContext context) { queryBowl = QueryBowl.of(context); final latestMutation = queryBowl.getMutation(mutation.mutationKey) ?? mutation; return widget.builder(context, latestMutation); } }