110 lines
3.0 KiB
Dart
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),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|