1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 04:49:21 +00:00
comunicmobile/lib/ui/widgets/async_screen_widget.dart
2022-03-11 16:40:56 +01:00

114 lines
2.7 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;
/// Widget to use while we are refreshing
///
/// This widget is optional
final Widget? loadingWidget;
/// Widget to use in case of error
///
/// This widget is optional
final Widget? errorWidget;
const AsyncScreenWidget({
Key? key,
required this.onReload,
required this.onBuild,
required this.errorMessage,
this.showOldDataWhileUpdating = false,
this.loadingWidget,
this.errorWidget,
}) : 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 widget.errorWidget ??
buildErrorCard(widget.errorMessage, actions: [
MaterialButton(
textColor: Colors.white,
onPressed: () => refresh(),
child: Text(tr("Try again")!.toUpperCase()),
)
]);
// Show loading states
if (!ready) return widget.loadingWidget ?? 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;
});
}
}
}