1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-10-23 15:03:22 +00:00
comunicmobile/lib/ui/widgets/async_screen_widget.dart
2020-04-27 19:08:19 +02:00

104 lines
2.5 KiB
Dart

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<void> 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;
/// Specify whether old data can be kept or not while updating this widget
final bool showOldDataWhileUpdating;
const AsyncScreenWidget({
Key key,
@required this.onReload,
@required this.onBuild,
@required this.errorMessage,
this.showOldDataWhileUpdating = false,
}) : assert(onReload != null),
assert(onBuild != null),
assert(errorMessage != null),
assert(showOldDataWhileUpdating != null),
super(key: key);
@override
AsyncScreenWidgetState createState() => AsyncScreenWidgetState();
}
class AsyncScreenWidgetState extends SafeState<AsyncScreenWidget> {
bool error = false;
bool ready = false;
bool didFirstLoad = 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<void> refresh() async {
try {
setState(() {
error = false;
ready = widget.showOldDataWhileUpdating && didFirstLoad;
});
// Call parent method
await widget.onReload();
setState(() {
ready = true;
didFirstLoad = true;
});
} catch (e, stack) {
print(e);
print(stack);
setState(() {
error = true;
});
}
}
}