162 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'dart:async';
 | |
| import 'package:flutter/material.dart';
 | |
| import 'package:qhd_prevention/services/update_service.dart';
 | |
| 
 | |
| /// 显示“发现新版本”确认对话框,点击更新后会弹出下载进度弹窗
 | |
| Future<void> showUpdateConfirm(BuildContext context, {
 | |
|   required String apkUrl,
 | |
| 
 | |
| }) async {
 | |
|   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<DownloadProgressDialog> createState() => _DownloadProgressDialogState();
 | |
| }
 | |
| 
 | |
| class _DownloadProgressDialogState extends State<DownloadProgressDialog> {
 | |
|   final UpdateService _service = UpdateService();
 | |
|   StreamSubscription<UpdateEvent>? _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('取消'),
 | |
|           ),
 | |
|         ],
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| }
 |