189 lines
5.8 KiB
Dart
189 lines
5.8 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:qhd_prevention/services/update_service.dart';
|
|
|
|
/// 显示“发现新版本”确认对话框,点击更新后会弹出下载进度弹窗
|
|
Future<void> showUpdateConfirmDialog(BuildContext context, {
|
|
required String apkUrl,
|
|
String title = '发现新版本',
|
|
String content = '检测到新版本,是否立即更新?',
|
|
String updateButtonText = '更新',
|
|
String cancelButtonText = '稍后',
|
|
}) async {
|
|
final confirmed = await showDialog<bool>(
|
|
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<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('取消'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|