import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'update_cubit.dart'; import 'update_state.dart'; import 'version_check_service.dart'; /// 更新对话框(带完整流程提示) class UpdateDialog extends StatelessWidget { final AppVersionInfo versionInfo; const UpdateDialog({super.key, required this.versionInfo}); @override Widget build(BuildContext context) { return BlocListener( listener: (context, state) { if (state is UpdateSuccess) { Navigator.of(context).pop(); if (versionInfo.updateType == 'patch') { _showRestartDialog(context); } } else if (state is UpdateFailure) { Navigator.of(context).pop(); String errorMessage = state.error; bool showApkPath = false; String? apkPath; if (errorMessage.contains('APK 文件位于:')) { final parts = errorMessage.split('APK 文件位于:'); if (parts.length > 1) { apkPath = parts[1].trim(); showApkPath = true; errorMessage = '您取消了安装'; } } _showErrorDialog(context, errorMessage, showApkPath: showApkPath, apkPath: apkPath); } }, child: AlertDialog( title: const Text('发现新版本'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('版本号: ${versionInfo.version}'), const SizedBox(height: 8), Text('更新类型: ${versionInfo.updateType == "patch" ? "差量更新" : "整包更新"}'), const SizedBox(height: 8), if (versionInfo.forceUpdate) Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(4), ), child: const Text( '⚠️ 强制更新', style: TextStyle(color: Colors.red), ), ), const SizedBox(height: 12), const Text('更新内容:', style: TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 4), Text(versionInfo.updateDesc.isEmpty ? '优化用户体验,修复已知问题' : versionInfo.updateDesc), ], ), ), actions: [ if (!versionInfo.forceUpdate) TextButton( onPressed: () { context.read().cancelUpdate(); Navigator.of(context).pop(); }, child: const Text('稍后'), ), BlocBuilder( builder: (context, state) { if (state is UpdateDownloading) { return Column( mainAxisSize: MainAxisSize.min, children: [ Text( state.isPatch ? '⬇️ 正在下载补丁...' : '⬇️ 正在下载 APK...', style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), SizedBox( width: 60, height: 60, child: Stack( alignment: Alignment.center, children: [ CircularProgressIndicator( value: state.progress, strokeWidth: 3, ), Text('${(state.progress * 100).toInt()}%'), ], ), ), ], ); } else if (state is UpdateClearingVersion) { return const Column( mainAxisSize: MainAxisSize.min, children: [ Text('✅ 版本号清理完成', style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold)), SizedBox(height: 4), Text('正在调起安装页面...', style: TextStyle(fontSize: 12)), SizedBox(height: 8), CircularProgressIndicator(), ], ); } else if (state is UpdateReadyToInstall) { return ElevatedButton.icon( onPressed: () { context.read().triggerInstall(state.apkPath); }, icon: const Icon(Icons.install_mobile), label: const Text('去安装'), ); } else if (state is UpdateInstalling) { return Column( mainAxisSize: MainAxisSize.min, children: [ const Text('📦 正在打开安装页面...', style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold)), const SizedBox(height: 4), const Text('请在系统安装界面确认安装', style: TextStyle(fontSize: 12)), const SizedBox(height: 8), const CircularProgressIndicator(), ], ); } else { return ElevatedButton( onPressed: () { if (versionInfo.updateType == 'patch' && versionInfo.patchUrl != null) { context.read().applyPatch( versionInfo.patchUrl!, versionInfo.version, versionInfo.versionCode, md5: versionInfo.patchMd5, ); } else if (versionInfo.apkUrl != null) { context.read().downloadAndInstallApk(versionInfo.apkUrl!); } }, child: const Text('立即更新'), ); } }, ), ], ), ); } void _showRestartDialog(BuildContext context) { showDialog( context: context, barrierDismissible: false, builder: (ctx) => AlertDialog( title: const Text('更新完成'), content: const Text('差量更新已应用,需要重启应用才能生效。\n是否立即重启?'), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(), child: const Text('稍后'), ), ElevatedButton( onPressed: () { Navigator.of(ctx).pop(); SystemNavigator.pop(); }, child: const Text('立即重启'), ), ], ), ); } void _showErrorDialog(BuildContext context, String message, {bool showApkPath = false, String? apkPath}) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('更新提示'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(message), if (showApkPath && apkPath != null) ...[ const SizedBox(height: 12), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(6), border: Border.all(color: Colors.blue.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '📁 APK 文件位置', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 13), ), const SizedBox(height: 6), Text( apkPath, style: const TextStyle(fontSize: 11, fontFamily: 'monospace'), ), const SizedBox(height: 6), const Text( '您可以到该目录手动点击 APK 文件进行安装', style: TextStyle(fontSize: 11, color: Colors.grey), ), ], ), ), ], ], ), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(), child: const Text('确定'), ), ], ), ); } } /// 显示整包更新提示(在浏览器中下载) class FullApkUpdateDialog extends StatelessWidget { final AppVersionInfo versionInfo; const FullApkUpdateDialog({super.key, required this.versionInfo}); @override Widget build(BuildContext context) { return AlertDialog( title: const Text('发现新版本'), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('版本号: ${versionInfo.version}'), const SizedBox(height: 8), const Text('更新类型: 整包更新'), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.orange.shade50, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.orange.shade200), ), child: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '📱 整包更新步骤', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14), ), SizedBox(height: 8), Text( '1️⃣ 点击"立即下载"打开浏览器\n' '2️⃣ 等待 APK 下载完成\n' '3️⃣ 手动安装新版本的 APK\n' '4️⃣ 安装完成后,卸载旧版本 APP\n' '5️⃣ 重新打开新版本 APP', style: TextStyle(fontSize: 13, height: 1.6), ), ], ), ), const SizedBox(height: 12), if (versionInfo.updateDesc.isNotEmpty) ...[ const Text('更新内容:', style: TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 4), Text(versionInfo.updateDesc), ], ], ), ), actions: [ if (!versionInfo.forceUpdate) TextButton( onPressed: () { context.read().cancelUpdate(); Navigator.of(context).pop(); }, child: const Text('稍后'), ), ElevatedButton( onPressed: () { if (versionInfo.apkUrl != null) { // 🔥 调用新方法:浏览器下载 + 清除补丁记录 context.read().fullApkUpdateWithBrowser(versionInfo.apkUrl!); Navigator.of(context).pop(); // 显示后续引导弹窗 _showManualInstallGuide(context); } }, child: const Text('立即下载'), ), ], ); } /// 显示手动安装引导弹窗 void _showManualInstallGuide(BuildContext context) { Future.delayed(const Duration(milliseconds: 500), () { showDialog( context: context, barrierDismissible: false, builder: (ctx) => AlertDialog( title: const Text('🔔 重要提示'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '请在浏览器中完成以下操作:', style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 12), const Text('✅ 等待 APK 下载完成'), const SizedBox(height: 8), const Text('✅ 点击 APK 文件进行安装'), const SizedBox(height: 8), const Text('✅ 安装完成后,卸载当前旧版本'), const SizedBox(height: 8), const Text('✅ 重新打开新版本 APP'), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(6), border: Border.all(color: Colors.red.shade200), ), child: const Text( '⚠️ 注意:必须先卸载旧版本,否则无法正常使用新功能!', style: TextStyle(color: Colors.red, fontSize: 12), ), ), ], ), actions: [ ElevatedButton( onPressed: () { Navigator.of(ctx).pop(); }, child: const Text('我知道了'), ), ], ), ); }); } }