Files
Client/lib/widget/async_actions/async_mixin.dart
T

110 lines
3.0 KiB
Dart

part of '../async_action_button.dart';
class _AsyncMixin extends StatefulWidget {
final AsyncActionCallback? onPressed;
final AsyncActionController? controller;
final AsyncErrorBuilder? errorBuilder;
final void Function(String message)? onError;
final VoidCallback? onSuccess;
final Widget Function(BuildContext context, bool busy, VoidCallback? handler) builder;
const _AsyncMixin({
required this.onPressed,
required this.builder,
this.controller,
this.errorBuilder,
this.onError,
this.onSuccess,
});
@override
State<_AsyncMixin> createState() => _AsyncMixinState();
}
class _AsyncMixinState extends State<_AsyncMixin> {
late final AsyncActionController _internal;
AsyncActionController get _controller => widget.controller ?? _internal;
@override
void initState() {
super.initState();
if (widget.controller == null) {
_internal = AsyncActionController();
}
_controller.addListener(_onControllerChange);
}
@override
void didUpdateWidget(covariant _AsyncMixin oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) {
(oldWidget.controller ?? _internal).removeListener(_onControllerChange);
_controller.addListener(_onControllerChange);
}
}
@override
void dispose() {
_controller.removeListener(_onControllerChange);
if (widget.controller == null) {
_internal.dispose();
}
super.dispose();
}
void _onControllerChange() {
if (mounted) setState(() {});
}
Future<void> _trigger() async {
final action = widget.onPressed;
if (action == null) return;
final success = await _controller.run(action, errorBuilder: widget.errorBuilder);
if (!mounted) return;
if (success) {
widget.onSuccess?.call();
} else if (widget.onError != null && _controller.error != null) {
widget.onError!(_controller.error!);
}
}
@override
Widget build(BuildContext context) {
final handler = widget.onPressed == null ? null : _trigger;
return widget.builder(context, _controller.busy, _controller.busy ? null : handler);
}
}
class _InlineErrorWrapper extends StatelessWidget {
final AsyncActionController? controller;
final Widget child;
const _InlineErrorWrapper({required this.controller, required this.child});
@override
Widget build(BuildContext context) {
final c = controller;
if (c == null) return child;
return AnimatedBuilder(
animation: c,
builder: (context, _) {
final err = c.error;
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
child,
if (err != null) ...[
const SizedBox(height: 8),
Text(
err,
textAlign: TextAlign.center,
style: TextStyle(color: Theme.of(context).colorScheme.error, fontSize: 13),
),
],
],
);
},
);
}
}