122 lines
3.1 KiB
Dart
122 lines
3.1 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 bool showInlineError;
|
|
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,
|
|
this.showInlineError = false,
|
|
});
|
|
|
|
@override
|
|
State<_AsyncMixin> createState() => _AsyncMixinState();
|
|
}
|
|
|
|
class _AsyncMixinState extends State<_AsyncMixin> {
|
|
AsyncActionController? _own;
|
|
AsyncActionController get _controller =>
|
|
widget.controller ?? (_own ??= AsyncActionController());
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller.addListener(_onControllerChange);
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(covariant _AsyncMixin oldWidget) {
|
|
super.didUpdateWidget(oldWidget);
|
|
if (oldWidget.controller != widget.controller) {
|
|
(oldWidget.controller ?? _own)?.removeListener(_onControllerChange);
|
|
_controller.addListener(_onControllerChange);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.removeListener(_onControllerChange);
|
|
_own?.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) {
|
|
Haptics.success();
|
|
widget.onSuccess?.call();
|
|
} else if (_controller.error != null) {
|
|
Haptics.error();
|
|
widget.onError?.call(_controller.error!);
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final busy = _controller.busy;
|
|
final child = widget.builder(
|
|
context,
|
|
busy,
|
|
busy || widget.onPressed == null ? null : _trigger,
|
|
);
|
|
if (!widget.showInlineError) return child;
|
|
return _InlineErrorWrapper(controller: _controller, child: child);
|
|
}
|
|
}
|
|
|
|
class _InlineErrorWrapper extends StatelessWidget {
|
|
final AsyncActionController controller;
|
|
final Widget child;
|
|
const _InlineErrorWrapper({required this.controller, required this.child});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: controller,
|
|
builder: (context, _) {
|
|
final err = controller.error;
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
child,
|
|
if (err != null) ...[
|
|
const SizedBox(height: 8),
|
|
Semantics(
|
|
liveRegion: true,
|
|
container: true,
|
|
child: Text(
|
|
err,
|
|
textAlign: TextAlign.center,
|
|
style: _asyncErrorTextStyle(context),
|
|
),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|