LoadingButton
import 'package:flutter/material.dart';
enum LoadingState {
init,
loading,
success,
failed,
}
class LoadingButton extends StatefulWidget {
final double indicatorSize;
final Future<void> Function() onPressed;
final EdgeInsetsGeometry padding;
final Widget child;
final Function doSuccess;
final Function(dynamic) doError;
final bool disable;
LoadingButton({
Key key,
@required this.onPressed,
this.indicatorSize = 24.0,
this.padding = EdgeInsets.zero,
this.child,
this.doSuccess,
this.doError,
this.disable = false
}) : super(key: key);
@override
State<StatefulWidget> createState() => _LoadingButtonState();
}
class _LoadingButtonState extends State<LoadingButton> {
LoadingState _state = LoadingState.init;
@override
Widget build(BuildContext context) {
return FlatButton(
padding: widget.padding,
onPressed: () async {
if (_state != LoadingState.init || widget.disable == true) return;
setState(() {
_state = LoadingState.loading;
});
LoadingResults results = await LoadingHelper.run(widget.onPressed);
await delay(1000);
if (results.isSuccess) {
_state = LoadingState.success;
if(widget.doSuccess != null) widget.doSuccess();
} else {
_state = LoadingState.failed;
if(widget.doError != null) widget.doError(results.error);
}
setState(() { });
await delay(1000);
_state = LoadingState.init;
setState(() { });
},
child: stateView()
);
}
Widget stateView() {
switch(_state) {
case LoadingState.init : return widget.child;
case LoadingState.loading : return SizedBox(child: CircularProgressIndicator(strokeWidth: 2,), width: widget.indicatorSize, height: widget.indicatorSize,);
case LoadingState.success : return Icon(Icons.check, size: widget.indicatorSize, color: Colors.green,);
case LoadingState.failed : return Icon(Icons.clear, size: widget.indicatorSize, color: Colors.red,);
default : return Container();
}
}
}
class LoadingResults {
bool isSuccess;
dynamic error;
LoadingResults(this.isSuccess, this.error);
}
class LoadingHelper {
static Future<LoadingResults> run(Function run, {int timeout}) async {
bool isLoading = false;
if ((timeout ?? 1) > 0) {
delay(timeout ?? 60 * 1000).then((_) async {
if (isLoading)
return LoadingResults(false, "Timeout error");
});
}
try {
await run();
return LoadingResults(true, null);
} catch (e) {
return LoadingResults(false, e);
}
}
}