From e4cc62ec0b685efb23581cff66c70c7f5f22a0c7 Mon Sep 17 00:00:00 2001 From: franzap <_@franzap.com> Date: Fri, 23 Jan 2026 17:10:38 -0300 Subject: [PATCH] Prefix subscriptions with app- (we need it for the relay) --- lib/screens/search_screen.dart | 2 +- lib/screens/updates_screen.dart | 6 +- lib/screens/user_screen.dart | 2 +- lib/services/updates_service.dart | 2 +- lib/widgets/app_detail_widgets.dart | 2 +- lib/widgets/app_stack_container.dart | 68 +++++++++++++--------- lib/widgets/latest_releases_container.dart | 6 +- spec/guidelines/ARCHITECTURE.md | 4 ++ 8 files changed, 55 insertions(+), 37 deletions(-) diff --git a/lib/screens/search_screen.dart b/lib/screens/search_screen.dart index 3592314..de21796 100644 --- a/lib/screens/search_screen.dart +++ b/lib/screens/search_screen.dart @@ -172,7 +172,7 @@ class _SearchResultsSection extends HookConsumerWidget { // Force the search to hit the default relay group (relay.zapstore.dev) // so a connection appears in Debug Info when searching. source: const RemoteSource(relays: 'AppCatalog', stream: false), - subscriptionPrefix: 'search-results', + subscriptionPrefix: 'app-search-results', ), ); diff --git a/lib/screens/updates_screen.dart b/lib/screens/updates_screen.dart index f82f2a6..c565103 100644 --- a/lib/screens/updates_screen.dart +++ b/lib/screens/updates_screen.dart @@ -40,9 +40,9 @@ class _ConnectionStatusIndicator extends ConsumerWidget { final poolState = ref.watch(poolStateProvider); final subscriptions = poolState?.subscriptions ?? {}; - // Filter to only "updates" subscription + // Filter to only "app-updates" subscription final updatesSubs = subscriptions.entries - .where((e) => e.key.startsWith('updates')) + .where((e) => e.key.startsWith('app-updates')) .map((e) => e.value); // Check relay status for updates subscription only @@ -189,7 +189,7 @@ class _UpdatesListBodyWithInstallingAppIds extends ConsumerWidget { tags: {'#d': installingAppIds}, and: (app) => {app.latestRelease.query()}, source: const LocalAndRemoteSource(relays: 'AppCatalog'), - subscriptionPrefix: 'installing-apps', + subscriptionPrefix: 'app-installing-apps', ), ); diff --git a/lib/screens/user_screen.dart b/lib/screens/user_screen.dart index ff1d154..abab0a8 100644 --- a/lib/screens/user_screen.dart +++ b/lib/screens/user_screen.dart @@ -49,7 +49,7 @@ class UserScreen extends HookConsumerWidget { ), }, source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: false), - subscriptionPrefix: 'user-apps', + subscriptionPrefix: 'app-user-apps', ), ); diff --git a/lib/services/updates_service.dart b/lib/services/updates_service.dart index 1a5942b..1d6ac14 100644 --- a/lib/services/updates_service.dart +++ b/lib/services/updates_service.dart @@ -104,7 +104,7 @@ class CategorizedAppsNotifier extends Notifier { ), }, source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: true), - subscriptionPrefix: 'updates', + subscriptionPrefix: 'app-updates', ), ); diff --git a/lib/widgets/app_detail_widgets.dart b/lib/widgets/app_detail_widgets.dart index 6025c8b..22855f1 100644 --- a/lib/widgets/app_detail_widgets.dart +++ b/lib/widgets/app_detail_widgets.dart @@ -735,7 +735,7 @@ class DebugVersionsSection extends HookConsumerWidget { tags: app.event.addressableIdTagMap, and: (release) => {release.latestMetadata.query(), release.latestAsset.query()}, source: LocalAndRemoteSource(relays: 'AppCatalog', stream: false), - subscriptionPrefix: 'debug-releases', + subscriptionPrefix: 'app-debug-releases', ), ); diff --git a/lib/widgets/app_stack_container.dart b/lib/widgets/app_stack_container.dart index 5b642dd..c5acd40 100644 --- a/lib/widgets/app_stack_container.dart +++ b/lib/widgets/app_stack_container.dart @@ -31,11 +31,7 @@ String? _extractIdentifier(String addressableId) { List _getPreviewIdentifiers(AppStack stack) { final rawTags = _getRawAppTagValues(stack).toList() ..shuffle(Random(stack.id.hashCode)); - return rawTags - .take(3) - .map(_extractIdentifier) - .whereType() - .toList(); + return rawTags.take(3).map(_extractIdentifier).whereType().toList(); } /// Sort app stacks: franzap/following first, then by recency @@ -67,10 +63,12 @@ List _sortStacks( others.sort((a, b) => b.event.createdAt.compareTo(a.event.createdAt)); return [...followed, ...others]; } else { - final franzapStacks = - stacks.where((s) => s.pubkey == kFranzapPubkey).toList(); - final otherStacks = - stacks.where((s) => s.pubkey != kFranzapPubkey).toList(); + final franzapStacks = stacks + .where((s) => s.pubkey == kFranzapPubkey) + .toList(); + final otherStacks = stacks + .where((s) => s.pubkey != kFranzapPubkey) + .toList(); franzapStacks.shuffle(random); otherStacks.sort((a, b) => b.event.createdAt.compareTo(a.event.createdAt)); @@ -198,8 +196,10 @@ class AppStackContainer extends HookConsumerWidget { scrollController.position.maxScrollExtent - 200) { // Load more if we haven't shown all stacks yet if (visibleCount.value < sortedStacks.length) { - visibleCount.value = (visibleCount.value + _kBatchSize) - .clamp(0, sortedStacks.length); + visibleCount.value = (visibleCount.value + _kBatchSize).clamp( + 0, + sortedStacks.length, + ); } } } @@ -231,9 +231,13 @@ class AppStackContainer extends HookConsumerWidget { if (col * 2 < displayedStacks.length) _StackCard( stack: displayedStacks[col * 2], - author: authorsMap[displayedStacks[col * 2].event.pubkey], - isAuthorLoading: isAuthorLoading(displayedStacks[col * 2].event.pubkey), - previewIdentifiers: stackPreviewIds[displayedStacks[col * 2].id] ?? [], + author: + authorsMap[displayedStacks[col * 2].event.pubkey], + isAuthorLoading: isAuthorLoading( + displayedStacks[col * 2].event.pubkey, + ), + previewIdentifiers: + stackPreviewIds[displayedStacks[col * 2].id] ?? [], appsMap: appsMap, ), // Bottom item @@ -241,9 +245,16 @@ class AppStackContainer extends HookConsumerWidget { const SizedBox(height: 10), _StackCard( stack: displayedStacks[col * 2 + 1], - author: authorsMap[displayedStacks[col * 2 + 1].event.pubkey], - isAuthorLoading: isAuthorLoading(displayedStacks[col * 2 + 1].event.pubkey), - previewIdentifiers: stackPreviewIds[displayedStacks[col * 2 + 1].id] ?? [], + author: + authorsMap[displayedStacks[col * 2 + 1] + .event + .pubkey], + isAuthorLoading: isAuthorLoading( + displayedStacks[col * 2 + 1].event.pubkey, + ), + previewIdentifiers: + stackPreviewIds[displayedStacks[col * 2 + 1].id] ?? + [], appsMap: appsMap, ), ], @@ -450,9 +461,7 @@ class _AppIconsRow extends StatelessWidget { aspectRatio: 1, child: Container( decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .surfaceContainerHighest + color: Theme.of(context).colorScheme.surfaceContainerHighest .withValues(alpha: 0.8), borderRadius: BorderRadius.circular(10), ), @@ -481,10 +490,9 @@ class _AppIconsRow extends StatelessWidget { aspectRatio: 1, child: Container( decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .surfaceContainerHighest - .withValues(alpha: 0.5), + color: Theme.of( + context, + ).colorScheme.surfaceContainerHighest.withValues(alpha: 0.5), borderRadius: BorderRadius.circular(10), ), ), @@ -520,10 +528,14 @@ class _AppIconTile extends StatelessWidget { fit: BoxFit.cover, fadeInDuration: const Duration(milliseconds: 200), placeholder: (_, __) => Container( - color: Theme.of(context).colorScheme.surfaceContainerHighest, + color: Theme.of( + context, + ).colorScheme.surfaceContainerHighest, ), errorWidget: (_, __, ___) => Container( - color: Theme.of(context).colorScheme.surfaceContainerHighest, + color: Theme.of( + context, + ).colorScheme.surfaceContainerHighest, child: const Icon( Icons.broken_image_outlined, size: 16, @@ -532,7 +544,9 @@ class _AppIconTile extends StatelessWidget { ), ) : Container( - color: Theme.of(context).colorScheme.surfaceContainerHighest, + color: Theme.of( + context, + ).colorScheme.surfaceContainerHighest, child: const Icon( Icons.apps_outlined, size: 16, diff --git a/lib/widgets/latest_releases_container.dart b/lib/widgets/latest_releases_container.dart index d9dd42c..968824f 100644 --- a/lib/widgets/latest_releases_container.dart +++ b/lib/widgets/latest_releases_container.dart @@ -321,7 +321,7 @@ class LatestReleasesNotifier extends StateNotifier { }, // NOTE: It must stream=true source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: true), - subscriptionPrefix: 'latest', + subscriptionPrefix: 'app-latest', ), (previous, next) async { // Always mirror storage state and ensure olderApps don't duplicate the live head @@ -446,9 +446,9 @@ class _LatestReleasesStatusDot extends ConsumerWidget { final poolState = ref.watch(poolStateProvider); final subscriptions = poolState?.subscriptions ?? {}; - // Filter to only "latest" subscription + // Filter to only "app-latest" subscription final latestSubs = subscriptions.entries - .where((e) => e.key.startsWith('latest')) + .where((e) => e.key.startsWith('app-latest')) .map((e) => e.value); // Check relay status for latest subscription diff --git a/spec/guidelines/ARCHITECTURE.md b/spec/guidelines/ARCHITECTURE.md index 5af9916..031bebe 100644 --- a/spec/guidelines/ARCHITECTURE.md +++ b/spec/guidelines/ARCHITECTURE.md @@ -95,4 +95,8 @@ onPressed: () async { } ``` +### Subscription prefix naming + +All queries using the `AppCatalog` relay group MUST prefix their `subscriptionPrefix` with `app-`. This is used in the backend. + For detailed API, see models/purplebase READMEs in pub cache.