import 'package:comunic/ui/widgets/safe_state.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:flutter/material.dart'; /// Widget that can be used to easily implement fetch of remote ressources /// /// @author Pierre Hubert class AsyncScreenWidget extends StatefulWidget { /// Reload function /// /// Can be an asynchronous function that takes no arguments and throw an /// [Exception] in case of failure /// /// You do not need to call [State.setState] on this function, it is /// automatically done by this widget final Future Function() onReload; /// Build function /// /// This function will be called whenever [isReady] becomes true final Widget Function() onBuild; /// Error message that will be shown in case of error final String errorMessage; const AsyncScreenWidget({ Key key, @required this.onReload, @required this.onBuild, @required this.errorMessage, }) : assert(onReload != null), assert(onBuild != null), assert(errorMessage != null), super(key: key); @override AsyncScreenWidgetState createState() => AsyncScreenWidgetState(); } class AsyncScreenWidgetState extends SafeState { bool error = false; bool ready = false; @override void initState() { refresh(); super.initState(); } @override Widget build(BuildContext context) { // In case of error if (error) return buildErrorCard(widget.errorMessage, actions: [ MaterialButton( onPressed: () => refresh(), child: Text(tr("Try again").toUpperCase()), ) ]); // Show loading states if (!ready) return buildCenteredProgressBar(); // The widget is ready, show it return RefreshIndicator( child: widget.onBuild(), onRefresh: () => refresh(), ); } /// Refresh this screen Future refresh() async { try { setState(() { error = false; ready = false; }); // Call parent method await widget.onReload(); setState(() { ready = true; }); } catch (e, stack) { print(e); print(stack); setState(() { error = true; }); } } }