blob: f4518aedb92e7f9eb7573214e747731ca68b4ac6 [file] [log] [blame]
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
typedef AsyncVoidCallback = Future<void> Function();
/// An [ElevatedButton] whose [onPressed] returns a [Future], and which
/// overlays a progress indicator when the button is pressed until the
/// future completes.
///
/// Technically this violates the Material design guidelines six ways
/// to Sunday but...
class ProgressButton extends StatefulWidget {
const ProgressButton({super.key, this.child, this.onPressed});
final Widget? child;
final AsyncVoidCallback? onPressed;
@override
State<ProgressButton> createState() => _ProgressButtonState();
}
class _ProgressButtonState extends State<ProgressButton> {
bool _busy = false;
void _handlePressed() async {
if (_busy) {
return;
}
setState(() {
_busy = true;
});
try {
await widget.onPressed!();
} finally {
if (mounted) {
setState(() {
_busy = false;
});
}
}
}
static const Widget _progressIndicator = Padding(
padding: EdgeInsets.all(12.0),
child: Center(
child: AspectRatio(aspectRatio: 1.0, child: CircularProgressIndicator()),
),
);
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ElevatedButton(
onPressed:
_busy // dartfmt will soon require this new formatting
? null
: widget.onPressed !=
null // dartfmt will soon require this new formatting
? _handlePressed
: null,
child: widget.child,
),
if (_busy)
const Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
bottom: 0.0,
child: _progressIndicator,
),
],
);
}
}