runWithProgress<T> function
Future<T>
runWithProgress<T>(
- BuildContext context,
- String message,
- Future<
T> task(- ValueChanged<
double> onProgress
- ValueChanged<
- ValueListenable<
String> ? status,
Modal progress for long on-device jobs. task receives a progress
callback (0..1); the dialog shows a spinner until it reports one.
status, when given, replaces message as the job moves through steps.
Implementation
Future<T> runWithProgress<T>(
BuildContext context,
String message,
Future<T> Function(ValueChanged<double> onProgress) task, {
ValueListenable<String>? status,
}) async {
final progress = ValueNotifier<double?>(null);
final navigator = Navigator.of(context, rootNavigator: true);
var open = true;
showDialog<void>(
context: context,
barrierDismissible: false,
useRootNavigator: true,
// Themed explicitly: [context] may sit above the editor's dark theme.
builder: (context) => VideoEditorTheme.wrap(PopScope(
canPop: false,
child: AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: VideoEditorSpacing.sm),
ValueListenableBuilder<double?>(
valueListenable: progress,
builder: (context, value, _) => Column(
children: [
SizedBox(
width: 48,
height: 48,
child: CircularProgressIndicator(value: value, strokeWidth: 3),
),
if (value != null) ...[
const SizedBox(height: VideoEditorSpacing.sm),
Text(
'${(value * 100).round()}%',
style: VideoEditorTextStyles.monoTimecode,
),
],
],
),
),
const SizedBox(height: VideoEditorSpacing.md),
ValueListenableBuilder<String>(
valueListenable: status ?? ValueNotifier(message),
builder: (context, value, _) => Text(
value,
textAlign: TextAlign.center,
style: VideoEditorTextStyles.body,
),
),
const SizedBox(height: VideoEditorSpacing.xs),
const Text(
'Runs on your device — keep the app open.',
textAlign: TextAlign.center,
style: VideoEditorTextStyles.caption,
),
],
),
),
)),
).whenComplete(() => open = false);
try {
return await task((value) => progress.value = value.clamp(0.0, 1.0));
} finally {
// The notifier is left to the GC: the dialog may still be animating out.
if (open && navigator.mounted) navigator.pop();
}
}