mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 12:38:24 +00:00
Support new NIP format
This commit is contained in:
@@ -43,7 +43,11 @@ class AppDetailScreen extends HookConsumerWidget {
|
||||
'#f': {platform},
|
||||
},
|
||||
limit: 1,
|
||||
and: (a) => {a.latestRelease, a.latestRelease.value?.latestMetadata},
|
||||
and: (a) => {
|
||||
a.latestRelease,
|
||||
a.latestRelease.value?.latestMetadata,
|
||||
a.latestRelease.value?.latestAsset,
|
||||
},
|
||||
// stream=true ensures cached/local results render immediately; remote
|
||||
// results will merge in as they arrive.
|
||||
source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: false),
|
||||
|
||||
@@ -86,6 +86,7 @@ class _AppStackContentWithApps extends HookConsumerWidget {
|
||||
and: (app) => {
|
||||
app.latestRelease,
|
||||
app.latestRelease.value?.latestMetadata,
|
||||
app.latestRelease.value?.latestAsset,
|
||||
},
|
||||
source: const LocalAndRemoteSource(relays: 'AppCatalog'),
|
||||
subscriptionPrefix: 'app-stack-apps-${stack!.identifier}',
|
||||
|
||||
@@ -164,6 +164,7 @@ class _SearchResultsSection extends HookConsumerWidget {
|
||||
and: (app) => {
|
||||
app.latestRelease,
|
||||
app.latestRelease.value?.latestMetadata,
|
||||
app.latestRelease.value?.latestAsset,
|
||||
},
|
||||
// Force the search to hit the default relay group (relay.zapstore.dev)
|
||||
// so a connection appears in Debug Info when searching.
|
||||
|
||||
@@ -43,6 +43,7 @@ class UserScreen extends HookConsumerWidget {
|
||||
and: (app) => {
|
||||
app.latestRelease,
|
||||
app.latestRelease.value?.latestMetadata,
|
||||
app.latestRelease.value?.latestAsset,
|
||||
},
|
||||
source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: false),
|
||||
subscriptionPrefix: 'user-apps',
|
||||
|
||||
@@ -80,6 +80,7 @@ class CategorizedAppsNotifier extends Notifier<CategorizedApps> {
|
||||
and: (app) => {
|
||||
app.latestRelease,
|
||||
app.latestRelease.value?.latestMetadata,
|
||||
app.latestRelease.value?.latestAsset,
|
||||
},
|
||||
source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: true),
|
||||
andSource: const LocalAndRemoteSource(
|
||||
|
||||
@@ -38,8 +38,10 @@ extension AppExt on App {
|
||||
ref.read(packageManagerProvider.notifier).isInstalled(identifier);
|
||||
|
||||
/// Latest file metadata associated to the latest release
|
||||
/// Prefers SoftwareAsset (new format) over FileMetadata (old format)
|
||||
/// Note: assumes latest metadata has been loaded for the current platform
|
||||
FileMetadata? get latestFileMetadata =>
|
||||
latestRelease.value?.latestAsset.value ??
|
||||
latestRelease.value?.latestMetadata.value;
|
||||
|
||||
/// Whether there is an update available for the installed app
|
||||
@@ -79,3 +81,30 @@ extension AppExt on App {
|
||||
extension WidgetRefExt on WidgetRef {
|
||||
Ref get ref => read(Provider((ref) => ref));
|
||||
}
|
||||
|
||||
/// Extension to handle both old and new format certificate hashes
|
||||
extension FileMetadataExt on FileMetadata {
|
||||
/// Returns the APK certificate hash, checking new format first then old
|
||||
/// New format (SoftwareAsset): apkCertificateHashes (Set)
|
||||
/// Old format (FileMetadata): apkSignatureHash (String?)
|
||||
String? get certificateHash {
|
||||
// Try new format first (SoftwareAsset has apkCertificateHashes)
|
||||
if (this is SoftwareAsset) {
|
||||
final hashes = (this as SoftwareAsset).apkCertificateHashes;
|
||||
if (hashes.isNotEmpty) return hashes.first;
|
||||
}
|
||||
// Fall back to old format
|
||||
return apkSignatureHash;
|
||||
}
|
||||
|
||||
/// Returns all APK certificate hashes
|
||||
Set<String> get certificateHashes {
|
||||
// Try new format first
|
||||
if (this is SoftwareAsset) {
|
||||
final hashes = (this as SoftwareAsset).apkCertificateHashes;
|
||||
if (hashes.isNotEmpty) return hashes;
|
||||
}
|
||||
// Fall back to old format (single hash as set)
|
||||
return apkSignatureHash != null ? {apkSignatureHash!} : {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,7 +718,7 @@ class DebugVersionsSection extends HookConsumerWidget {
|
||||
final releasesState = ref.watch(
|
||||
query<Release>(
|
||||
tags: app.event.addressableIdTagMap,
|
||||
and: (release) => {release.latestMetadata},
|
||||
and: (release) => {release.latestMetadata, release.latestAsset},
|
||||
source: LocalAndRemoteSource(relays: 'AppCatalog', stream: false),
|
||||
subscriptionPrefix: 'debug-releases',
|
||||
),
|
||||
|
||||
@@ -82,8 +82,8 @@ class AppInfoTable extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
if (fileMetadata?.apkSignatureHash != null) {
|
||||
final full = fileMetadata!.apkSignatureHash!;
|
||||
if (fileMetadata?.certificateHash != null) {
|
||||
final full = fileMetadata!.certificateHash!;
|
||||
rows.add(
|
||||
_InfoRow(
|
||||
label: 'Certificate hash',
|
||||
|
||||
@@ -719,8 +719,7 @@ class InstallButton extends ConsumerWidget {
|
||||
final updateVersion = app.latestFileMetadata?.version ?? 'Unknown';
|
||||
final currentVersion = installedPackage?.version ?? 'Unknown';
|
||||
final currentCertHash = installedPackage?.signatureHash ?? 'Unknown';
|
||||
final updateCertHash =
|
||||
app.latestFileMetadata?.apkSignatureHash ?? 'Unknown';
|
||||
final updateCertHash = app.latestFileMetadata?.certificateHash ?? 'Unknown';
|
||||
|
||||
// Get author profile
|
||||
final author = app.author.value;
|
||||
|
||||
@@ -60,7 +60,10 @@ class LatestReleasesContainer extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Text(
|
||||
'LATEST RELEASES',
|
||||
style: context.textTheme.labelLarge?.copyWith(
|
||||
@@ -286,6 +289,7 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
|
||||
and: (app) => {
|
||||
app.latestRelease,
|
||||
app.latestRelease.value?.latestMetadata,
|
||||
app.latestRelease.value?.latestAsset,
|
||||
},
|
||||
// NOTE: It must stream=true
|
||||
source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: true),
|
||||
@@ -358,7 +362,7 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
|
||||
source: const RemoteSource(stream: false),
|
||||
);
|
||||
|
||||
// Load file metadata for the releases
|
||||
// Load file metadata for the releases (old format)
|
||||
if (releases.isNotEmpty) {
|
||||
await ref.storage.query(
|
||||
Request<FileMetadata>(
|
||||
@@ -369,6 +373,16 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
|
||||
),
|
||||
source: const RemoteSource(stream: false),
|
||||
);
|
||||
// Load software assets for the releases (new format)
|
||||
await ref.storage.query(
|
||||
Request<SoftwareAsset>(
|
||||
releases
|
||||
.map((r) => r.latestAsset.req?.filters.firstOrNull)
|
||||
.nonNulls
|
||||
.toList(),
|
||||
),
|
||||
source: const RemoteSource(stream: false),
|
||||
);
|
||||
}
|
||||
|
||||
// Load release authors from different relay group (social)
|
||||
|
||||
Reference in New Issue
Block a user