Files
observer/flutter_app/lib/update/update_screen.dart
T
2026-08-25 16:52:55 +08:00

78 lines
2.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
/// 强制更新页:检测到新版本时的全屏阻塞页。
/// PopScope 禁返回(Android 系统返回 / iOS 边缘滑动均不可退出),
/// 仅「立即更新」跳转系统浏览器下载 APK。
/// 点击更新时回调 onUpdateAccepted(调用方持久化服务器版本号,
/// 使 APK 版本号不递增时也不反复提示)。
class UpdateScreen extends StatelessWidget {
final String version;
final String url;
final String notes;
final VoidCallback? onUpdateAccepted;
const UpdateScreen({
super.key,
required this.version,
required this.url,
this.notes = '',
this.onUpdateAccepted,
});
Future<void> _launch() async {
onUpdateAccepted?.call();
final uri = Uri.tryParse(url);
if (uri == null) return;
try {
await launchUrl(uri, mode: LaunchMode.externalApplication);
} catch (_) {
// 跳转失败保持页面,用户可重试
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return PopScope(
canPop: false,
child: Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.system_update_alt,
size: 64, color: theme.colorScheme.primary),
const SizedBox(height: 16),
Text('发现新版本 $version',
style: theme.textTheme.headlineSmall),
const SizedBox(height: 12),
if (notes.isNotEmpty)
Text(notes,
textAlign: TextAlign.center,
style: const TextStyle(height: 1.6)),
const SizedBox(height: 24),
FilledButton.icon(
onPressed: _launch,
icon: const Icon(Icons.download),
label: const Text('立即更新'),
style: FilledButton.styleFrom(
minimumSize: const Size(200, 48),
textStyle: const TextStyle(fontSize: 16),
),
),
const SizedBox(height: 12),
Text('不更新将无法继续使用',
style: theme.textTheme.bodySmall
?.copyWith(color: theme.colorScheme.error)),
],
),
),
),
),
);
}
}