import 'dart:async'; import 'package:flutter/material.dart'; import 'package:qhd_prevention/services/update_service.dart'; /// 显示“发现新版本”确认对话框,点击更新后会弹出下载进度弹窗 Future showUpdateConfirmDialog(BuildContext context, { required String apkUrl, String title = '发现新版本', String content = '检测到新版本,是否立即更新?', String updateButtonText = '更新', String cancelButtonText = '稍后', }) async { final confirmed = await showDialog( context: context, barrierDismissible: false, builder: (ctx) { return AlertDialog( title: Text(title), content: Text(content), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(false), child: Text(cancelButtonText), ), ElevatedButton( onPressed: () => Navigator.of(ctx).pop(true), child: Text(updateButtonText), ), ], ); }, ); if (confirmed == true) { // 跳出下载进度弹窗(阻塞式,直到弹窗被关闭) await showDialog( context: context, barrierDismissible: false, builder: (ctx) => DownloadProgressDialog(apkUrl: apkUrl), ); } } /// 下载进度弹窗(会在 initState 里自动开始下载) class DownloadProgressDialog extends StatefulWidget { final String apkUrl; final String? apkFileName; const DownloadProgressDialog({Key? key, required this.apkUrl, this.apkFileName}) : super(key: key); @override State createState() => _DownloadProgressDialogState(); } class _DownloadProgressDialogState extends State { final UpdateService _service = UpdateService(); StreamSubscription? _sub; double _progress = 0.0; String _statusText = '准备下载...'; bool _isWorking = true; // 下载或安装过程中禁止重复操作 @override void initState() { super.initState(); // 监听状态流 _sub = _service.statusStream.listen((event) { // 根据事件更新 UI setState(() { switch (event.state) { case UpdateState.idle: _statusText = '空闲'; break; case UpdateState.starting: _statusText = '准备中...'; break; case UpdateState.downloading: _statusText = '下载中...'; break; case UpdateState.completed: _statusText = '下载完成,正在准备安装...'; break; case UpdateState.installing: _statusText = '发起安装...'; break; case UpdateState.installed: _statusText = '已触发安装'; break; case UpdateState.failed: _statusText = '失败: ${event.message ?? ''}'; break; case UpdateState.canceled: _statusText = '已取消'; break; } }); // 根据不同状态决定是否关闭弹窗或提示 if (event.state == UpdateState.installing || event.state == UpdateState.installed) { // 已发起安装,关闭弹窗让系统安装界面出现 if (mounted) Future.delayed(const Duration(milliseconds: 300), () { if (mounted) Navigator.of(context).pop(); }); } else if (event.state == UpdateState.failed) { // 显示错误并在短时间后自动关闭弹窗 _isWorking = false; Future.delayed(const Duration(milliseconds: 800), () { if (mounted) Navigator.of(context).pop(); if (mounted) ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('更新失败:${event.message ?? '未知错误'}')), ); }); } else if (event.state == UpdateState.canceled) { _isWorking = false; if (mounted) { Future.delayed(const Duration(milliseconds: 200), () { if (mounted) Navigator.of(context).pop(); if (mounted) ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('下载已取消')), ); }); } } }); // 监听进度 ValueNotifier _service.progress.addListener(_onProgressChanged); // 启动下载 _service.downloadAndInstall(apkUrl: widget.apkUrl, apkFileName: widget.apkFileName); } void _onProgressChanged() { setState(() { _progress = _service.progress.value; }); } @override void dispose() { _sub?.cancel(); _service.progress.removeListener(_onProgressChanged); super.dispose(); } void _onCancel() { if (!_isWorking) { // 如果已经不是工作中,直接关闭 if (Navigator.of(context).canPop()) Navigator.of(context).pop(); return; } // 取消下载 _service.cancelDownload(); // 标记为非工作中(后续状态回调会关闭并提示) _isWorking = false; } @override Widget build(BuildContext context) { final percent = (_progress * 100).clamp(0.0, 100.0); return WillPopScope( onWillPop: () async => false, // 禁止物理返回 child: AlertDialog( title: const Text('正在更新'), content: Column( mainAxisSize: MainAxisSize.min, children: [ LinearProgressIndicator(value: _progress), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('${percent.toStringAsFixed(1)}%'), Flexible(child: Text(_statusText, overflow: TextOverflow.ellipsis, textAlign: TextAlign.right)), ], ), ], ), actions: [ TextButton( onPressed: _onCancel, child: const Text('取消'), ), ], ), ); } }