import 'dart:async'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../../common/theme/spacing.dart'; import '../application/update_progress.dart'; import '../application/update_service.dart'; import '../data/update_api_client.dart'; class UpdateDialog extends ConsumerStatefulWidget { const UpdateDialog({super.key, required this.upgrade, required this.source}); final UpgradeInfo upgrade; final UpgradeCheckSource source; @override ConsumerState createState() => _UpdateDialogState(); } class _UpdateDialogState extends ConsumerState { bool _clickReported = false; @override Widget build(BuildContext context) { ensureUpdateProgressListener(context); final colorScheme = ShadTheme.of(context).colorScheme; final progress = ref.watch(updateProgressProvider); final forced = widget.upgrade.force == 1; final canStart = progress == null || progress <= 0 || progress == 1; final version = widget.upgrade.latestVersion.trim().isEmpty ? widget.upgrade.versionCode : widget.upgrade.latestVersion; return PopScope( canPop: !forced, child: SafeArea( top: false, child: Padding( padding: const EdgeInsets.fromLTRB(22, 28, 22, 20), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( '发现新版本 V$version', textAlign: TextAlign.center, style: TextStyle( color: colorScheme.foreground, fontSize: 18, fontWeight: FontWeight.w600, ), ), if (widget.upgrade.message.trim().isNotEmpty) ...[ const SizedBox(height: 12), Text( widget.upgrade.message, style: TextStyle( color: colorScheme.mutedForeground, fontSize: 14, height: 1.6, ), ), ], const SizedBox(height: Spacing.sectionGap), if (canStart) FilledButton( onPressed: () => _startUpdate(progress), child: Text(progress == 1 ? '安装此版本' : '升级此版本'), ) else LinearProgressIndicator( value: progress.clamp(0, 1), color: colorScheme.primary, backgroundColor: colorScheme.muted, ), if (!forced && !canStart) ...[ const SizedBox(height: 10), TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('转后台下载'), ), ], if (!forced) ...[ const SizedBox(height: 6), TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('稍后再说'), ), ], ], ), ), ), ); } Future _startUpdate(double? progress) async { if (!_clickReported) { _clickReported = true; unawaited(_reportClick()); } final localPackage = ref.read(updateUrlProvider); if (progress == 1 && localPackage != null && localPackage.isNotEmpty) { await UpdateService.install(localPackage); return; } await UpdateService.startUpdate(widget.upgrade.url); } Future _reportClick() async { if (widget.upgrade.versionCode.isEmpty) return; try { await ref .read(updateApiClientProvider) .reportClick( buildId: widget.upgrade.versionCode, source: widget.source == UpgradeCheckSource.manual ? 'manual' : 'auto', ); } catch (_) {} } }