Skip to content

Instantly share code, notes, and snippets.

@caseycrogers
Created November 8, 2024 17:54
Show Gist options
  • Select an option

  • Save caseycrogers/68d4f29a2917dfa59563fc6bf7eecaf0 to your computer and use it in GitHub Desktop.

Select an option

Save caseycrogers/68d4f29a2917dfa59563fc6bf7eecaf0 to your computer and use it in GitHub Desktop.
class ActionLogger extends StatefulWidget implements ActionDetails {
const ActionLogger({
super.key,
required this.async,
required this.prefix,
required this.name,
required this.parameters,
this.priority = kDefaultButtonPriority,
required this.onError,
required this.builder,
});
final bool async;
@override
final String? prefix;
@override
final String name;
@override
final Map<String, Object>? parameters;
@override
final int priority;
@override
final void Function(Object error)? onError;
final Widget Function(
BuildContext context,
FutureOr<void> Function(FutureOrCallback?, int) wrap,
) builder;
@override
State<ActionLogger> createState() => _ActionLoggerState();
}
class _ActionLoggerState extends State<ActionLogger> {
FutureOr<void>? _actionFuture;
@override
Widget build(BuildContext context) {
final Widget child = widget.builder(context, wrap);
if (!widget.async) {
return child;
}
return Stack(
children: [
Positioned.fill(
child: Opacity(
opacity: _actionFuture != null ? 1 : 0,
child: Padding(
padding: EdgeInsets.all(context.gutterSmall),
child: const Center(
child: CircularProgressIndicator(),
),
),
),
),
AnimatedOpacity(
duration: const Duration(milliseconds: 100),
opacity: _actionFuture != null ? 0 : 1,
child: child,
),
],
);
}
Future<void> wrap(FutureOrCallback? action, int priority) async {
if (action == null) {
return;
}
try {
// This could be customized by making it a static method that you set in
// your app's main function.
unawaited(Analytics.instance._logEvent(
priority: priority,
name: widget.prefix == null
? widget.name
: '${widget.prefix}_${widget.name}',
parameters: widget.parameters,
));
final FutureOr<void> maybeFuture = action();
if (maybeFuture is Future<void>) {
_actionFuture = maybeFuture.whenComplete(() {
_actionFuture = null;
if (mounted) {
setState(() {});
}
});
setState(() {});
} else {
return;
}
await _actionFuture;
} catch (error) {
// Wrap this in try catch to ensure that it doesn't replace the original
// error in the event that it throws.
try {
widget.onError?.call(error);
} catch (e, stack) {
FlutterError.onError!(
FlutterErrorDetails(
exception: error,
stack: stack,
),
);
}
rethrow;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment