完成集成新的登录接口的更换使用 完成集成用户的场站列表接口 完成开发设计选择场站项为全局属性 完成我的页面的个人信息的集成和详情页面的开发 完成设备页面的中无人机机场的列表接口对接入和个项页面的布局的优化 完成设备页面的中无人机机场的详情接口的对接和使用和页面的更新布局
321 lines
12 KiB
Dart
321 lines
12 KiB
Dart
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<UpdateCubit, UpdateState>(
|
|
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<UpdateCubit>().cancelUpdate();
|
|
Navigator.of(context).pop();
|
|
},
|
|
child: const Text('稍后'),
|
|
),
|
|
BlocBuilder<UpdateCubit, UpdateState>(
|
|
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<UpdateCubit>().triggerInstall(state.apkPath);
|
|
},
|
|
icon: const Icon(Icons.install_mobile),
|
|
label: const Text('去安装'),
|
|
);
|
|
} else if (state is UpdateInstalling) {
|
|
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 {
|
|
return ElevatedButton(
|
|
onPressed: () {
|
|
if (versionInfo.updateType == 'patch' && versionInfo.patchUrl != null) {
|
|
context.read<UpdateCubit>().applyPatch(
|
|
versionInfo.patchUrl!,
|
|
versionInfo.version,
|
|
versionInfo.versionCode,
|
|
md5: versionInfo.patchMd5,
|
|
);
|
|
} else if (versionInfo.apkUrl != null) {
|
|
context.read<UpdateCubit>().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.blue.shade50,
|
|
borderRadius: BorderRadius.circular(8),
|
|
border: Border.all(color: Colors.blue.shade200),
|
|
),
|
|
child: const Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'📱 整包更新说明',
|
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
|
|
),
|
|
SizedBox(height: 8),
|
|
Text(
|
|
'• 点击"立即下载"将在浏览器中打开下载链接\n'
|
|
'• 下载完成后请手动安装 APK\n'
|
|
'• 安装完成后重启应用即可',
|
|
style: TextStyle(fontSize: 13, height: 1.5),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
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<UpdateCubit>().cancelUpdate();
|
|
Navigator.of(context).pop();
|
|
},
|
|
child: const Text('稍后'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
if (versionInfo.apkUrl != null) {
|
|
context.read<UpdateCubit>().downloadAndInstallApk(versionInfo.apkUrl!);
|
|
Navigator.of(context).pop();
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('正在浏览器中打开下载链接...'),
|
|
duration: Duration(seconds: 2),
|
|
),
|
|
);
|
|
}
|
|
},
|
|
child: const Text('立即下载'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|