100 lines
2.8 KiB
Dart
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;
|
|
}
|
|
}
|