Files
jizhi/frontend/lib/shared/update/update_models.dart
T
2026-07-24 23:11:20 +08:00

100 lines
2.8 KiB
Dart

class AppRelease {
final String id;
final String versionName;
final int buildNumber;
final String downloadUrl;
final String releaseNotes;
final String? sha256;
final int? fileSize;
final DateTime? publishedAt;
const AppRelease({
required this.id,
required this.versionName,
required this.buildNumber,
required this.downloadUrl,
required this.releaseNotes,
required this.sha256,
required this.fileSize,
required this.publishedAt,
});
factory AppRelease.fromJson(Map<String, dynamic> json) {
final id = json['id']?.toString().trim() ?? '';
final versionName = json['versionName']?.toString().trim() ?? '';
final buildNumber = (json['buildNumber'] as num?)?.toInt() ?? -1;
final downloadUrl = json['downloadUrl']?.toString().trim() ?? '';
if (id.isEmpty ||
versionName.isEmpty ||
buildNumber < 0 ||
downloadUrl.isEmpty) {
throw const FormatException('更新服务返回了不完整的版本信息');
}
return AppRelease(
id: id,
versionName: versionName,
buildNumber: buildNumber,
downloadUrl: downloadUrl,
releaseNotes: json['releaseNotes']?.toString().trim() ?? '',
sha256: json['sha256']?.toString().trim().nullIfEmpty,
fileSize: (json['fileSize'] as num?)?.toInt(),
publishedAt: DateTime.tryParse(json['publishedAt']?.toString() ?? ''),
);
}
}
class UpdateCheckResponse {
final bool hasUpdate;
final bool forceUpdate;
final AppRelease? release;
const UpdateCheckResponse({
required this.hasUpdate,
required this.forceUpdate,
required this.release,
});
factory UpdateCheckResponse.fromJson(Map<String, dynamic> json) {
final releaseJson = json['release'];
final release = releaseJson is Map
? AppRelease.fromJson(Map<String, dynamic>.from(releaseJson))
: null;
final hasUpdate = json['hasUpdate'] == true;
if (hasUpdate && release == null) {
throw const FormatException('更新服务未返回目标版本');
}
return UpdateCheckResponse(
hasUpdate: hasUpdate,
forceUpdate: json['forceUpdate'] == true,
release: release,
);
}
}
extension on String {
String? get nullIfEmpty => isEmpty ? null : this;
}
class UpdatePolicy {
UpdatePolicy._();
static AppRelease? availableRelease(
UpdateCheckResponse response, {
required int currentBuild,
}) {
final release = response.release;
if (!response.hasUpdate || release == null) return null;
return release.buildNumber > currentBuild ? release : null;
}
static bool shouldPresent({
required AppRelease release,
required bool forced,
required bool manual,
required String? ignoredReleaseId,
}) {
if (forced || manual) return true;
return ignoredReleaseId != release.id;
}
}