126 lines
4.0 KiB
Dart
126 lines
4.0 KiB
Dart
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<UpdateDialog> createState() => _UpdateDialogState();
|
|
}
|
|
|
|
class _UpdateDialogState extends ConsumerState<UpdateDialog> {
|
|
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<void> _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<void> _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 (_) {}
|
|
}
|
|
}
|