import 'package:fluent_ui/fluent_ui.dart'; import 'package:pixes/components/md.dart'; import 'package:pixes/components/message.dart'; import 'package:pixes/foundation/app.dart'; import 'package:pixes/network/download.dart'; import 'package:pixes/utils/translation.dart'; import '../network/network.dart'; class BatchDownloadButton extends StatelessWidget { const BatchDownloadButton({super.key, required this.request}); final Future>> Function() request; @override Widget build(BuildContext context) { return Button( child: const Icon( MdIcons.download, size: 20, ), onPressed: () { showDialog( context: context, barrierDismissible: false, barrierColor: Colors.transparent, useRootNavigator: false, builder: (context) => _DownloadDialog(request)); }, ); } } class _DownloadDialog extends StatefulWidget { const _DownloadDialog(this.request); final Future>> Function() request; @override State<_DownloadDialog> createState() => _DownloadDialogState(); } class _DownloadDialogState extends State<_DownloadDialog> { int maxCount = 30; int currentCount = 0; bool loading = false; bool cancel = false; @override Widget build(BuildContext context) { return ContentDialog( title: Text("Batch download".tl), content: SizedBox( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ if (!loading) Text('${"Maximum number of downloads".tl}:'), if (loading) Text("${"Current quantity".tl}: $currentCount"), const SizedBox( height: 16, ), SizedBox( height: 42, width: 196, child: NumberBox( value: maxCount, onChanged: (value) { if (!loading) { setState(() => maxCount = value ?? maxCount); } }, allowExpressions: true, mode: SpinButtonPlacementMode.inline, smallChange: 10, largeChange: 30, clearButton: false, ), ), ], ).paddingVertical(8), ), actions: [ Button( child: Text("Cancel".tl), onPressed: () { cancel = true; context.pop(); }), if (!loading) FilledButton(onPressed: load, child: Text("Continue".tl)) else FilledButton( onPressed: () {}, child: const SizedBox( height: 20, width: 64, child: Center( child: SizedBox.square( dimension: 18, child: ProgressRing( strokeWidth: 1.6, ), ), ), )) ], ); } void load() async { setState(() { loading = true; }); var request = widget.request(); List all = []; String? nextUrl; int retryCount = 0; while (nextUrl != "end" && all.length < maxCount) { if (nextUrl != null) { request = Network().getIllustsWithNextUrl(nextUrl); } var res = await request; if (cancel || !mounted) { return; } if (res.error) { retryCount++; if (retryCount > 3) { setState(() { loading = false; }); showToast(context, message: "Error".tl); return; } await Future.delayed(Duration(seconds: 1 << retryCount)); continue; } all.addAll(res.data); setState(() { currentCount = all.length; }); nextUrl = res.subData ?? "end"; } int i = 0; for (var illust in all) { if (i > maxCount) break; DownloadManager().addDownloadingTask(illust); i++; } context.pop(); } }