Fix latest releases bug

This commit is contained in:
franzap
2026-04-10 22:39:41 -03:00
parent cb470bf67d
commit 85aea3bccf
+56 -44
View File
@@ -31,12 +31,12 @@ class LatestReleasesState {
}); });
factory LatestReleasesState.loading() => const LatestReleasesState( factory LatestReleasesState.loading() => const LatestReleasesState(
firstPage: [], firstPage: [],
olderPages: [], olderPages: [],
appsByIdentifier: {}, appsByIdentifier: {},
isLoadingMore: false, isLoadingMore: false,
hasMore: true, hasMore: true,
); );
bool get isLoading => bool get isLoading =>
firstPage.isEmpty && olderPages.isEmpty && error == null; firstPage.isEmpty && olderPages.isEmpty && error == null;
@@ -50,15 +50,14 @@ class LatestReleasesState {
bool? isLoadingMore, bool? isLoadingMore,
bool? hasMore, bool? hasMore,
Object? error, Object? error,
}) => }) => LatestReleasesState(
LatestReleasesState( firstPage: firstPage ?? this.firstPage,
firstPage: firstPage ?? this.firstPage, olderPages: olderPages ?? this.olderPages,
olderPages: olderPages ?? this.olderPages, appsByIdentifier: appsByIdentifier ?? this.appsByIdentifier,
appsByIdentifier: appsByIdentifier ?? this.appsByIdentifier, isLoadingMore: isLoadingMore ?? this.isLoadingMore,
isLoadingMore: isLoadingMore ?? this.isLoadingMore, hasMore: hasMore ?? this.hasMore,
hasMore: hasMore ?? this.hasMore, error: error,
error: error, );
);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -78,18 +77,19 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
_sub = ref.listen( _sub = ref.listen(
query<Release>( query<Release>(
limit: _kPageSize, limit: _kPageSize,
where: (r) => r.event.getTagSetValues('f').contains('android-arm64-v8a'),
source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: true), source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: true),
subscriptionPrefix: 'app-latest-releases', subscriptionPrefix: 'app-latest-releases',
), ),
(_, next) async { (_, next) async {
if (next is StorageData<Release>) { if (next is StorageData<Release>) {
final liveIds = next.models.map((r) => r.id).toSet(); final liveIds = next.models.map((r) => r.id).toSet();
final filteredOlder = final filteredOlder = state.olderPages
state.olderPages.where((r) => !liveIds.contains(r.id)).toList(); .where((r) => !liveIds.contains(r.id))
.toList();
final unresolved = next.models final unresolved = next.models
.where((r) => .where(
!state.appsByIdentifier.containsKey(r.appIdentifier)) (r) => !state.appsByIdentifier.containsKey(r.appIdentifier),
)
.toList(); .toList();
final apps = await _resolveRelated(unresolved); final apps = await _resolveRelated(unresolved);
if (mounted) { if (mounted) {
@@ -127,20 +127,17 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
subscriptionPrefix: 'app-latest-releases-older', subscriptionPrefix: 'app-latest-releases-older',
); );
final filtered = releases if (releases.isEmpty) {
.where((r) => r.event.getTagSetValues('f').contains('android-arm64-v8a'))
.toList();
if (filtered.isEmpty) {
state = state.copyWith(isLoadingMore: false, hasMore: false); state = state.copyWith(isLoadingMore: false, hasMore: false);
return; return;
} }
final apps = await _resolveRelated(filtered); final apps = await _resolveRelated(releases);
final existingIds = all.map((r) => r.id).toSet(); final existingIds = all.map((r) => r.id).toSet();
final unique = final unique = releases
filtered.where((r) => !existingIds.contains(r.id)).toList(); .where((r) => !existingIds.contains(r.id))
.toList();
state = state.copyWith( state = state.copyWith(
olderPages: [...state.olderPages, ...unique], olderPages: [...state.olderPages, ...unique],
appsByIdentifier: {...state.appsByIdentifier, ...apps}, appsByIdentifier: {...state.appsByIdentifier, ...apps},
@@ -158,8 +155,9 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
if (releases.isEmpty) return const {}; if (releases.isEmpty) return const {};
final storage = ref.read(storageNotifierProvider.notifier); final storage = ref.read(storageNotifierProvider.notifier);
final assetIds = final assetIds = releases
releases.expand((r) => r.event.getTagSetValues('e')).toSet(); .expand((r) => r.event.getTagSetValues('e'))
.toSet();
final appIds = releases final appIds = releases
.map((r) => r.appIdentifier) .map((r) => r.appIdentifier)
.where((id) => id.isNotEmpty) .where((id) => id.isNotEmpty)
@@ -170,7 +168,9 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
storage.query( storage.query(
RequestFilter<SoftwareAsset>( RequestFilter<SoftwareAsset>(
ids: assetIds, ids: assetIds,
tags: {'#f': {'android-arm64-v8a'}}, tags: {
'#f': {'android-arm64-v8a'},
},
).toRequest(), ).toRequest(),
source: const LocalAndRemoteSource( source: const LocalAndRemoteSource(
relays: 'AppCatalog', relays: 'AppCatalog',
@@ -180,9 +180,7 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
), ),
if (appIds.isNotEmpty) if (appIds.isNotEmpty)
storage.query( storage.query(
RequestFilter<App>( RequestFilter<App>(tags: {'#d': appIds}).toRequest(),
tags: {'#d': appIds, '#f': {'android-arm64-v8a'}},
).toRequest(),
source: const LocalAndRemoteSource( source: const LocalAndRemoteSource(
relays: 'AppCatalog', relays: 'AppCatalog',
stream: false, stream: false,
@@ -194,11 +192,19 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
if (appIds.isEmpty) return const {}; if (appIds.isEmpty) return const {};
final apps = appIds final apps = appIds
.expand((id) => storage.querySync( .expand(
RequestFilter<App>(tags: {'#d': {id}}, limit: 1).toRequest(), (id) => storage.querySync(
)) RequestFilter<App>(
tags: {
'#d': {id},
},
limit: 1,
).toRequest(),
),
)
.cast<App>() .cast<App>()
.toList(); .toList();
'${apps.map((a) => a.identifier).toList()}';
await loadAuthors(storage, apps, 'app-latest-releases-authors'); await loadAuthors(storage, apps, 'app-latest-releases-authors');
return {for (final app in apps) app.identifier: app}; return {for (final app in apps) app.identifier: app};
@@ -213,8 +219,8 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
final latestReleasesProvider = final latestReleasesProvider =
StateNotifierProvider<LatestReleasesNotifier, LatestReleasesState>((ref) { StateNotifierProvider<LatestReleasesNotifier, LatestReleasesState>((ref) {
return LatestReleasesNotifier(ref); return LatestReleasesNotifier(ref);
}); });
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Widget // Widget
@@ -264,6 +270,7 @@ class LatestReleasesContainer extends HookConsumerWidget {
ref.read(latestReleasesProvider.notifier).loadMore(); ref.read(latestReleasesProvider.notifier).loadMore();
} }
} }
scrollController.addListener(onScroll); scrollController.addListener(onScroll);
return () => scrollController.removeListener(onScroll); return () => scrollController.removeListener(onScroll);
}, [scrollController, state]); }, [scrollController, state]);
@@ -288,7 +295,13 @@ class LatestReleasesContainer extends HookConsumerWidget {
if (state.isLoadingMore) if (state.isLoadingMore)
const Padding( const Padding(
padding: EdgeInsets.all(16.0), padding: EdgeInsets.all(16.0),
child: Center(child: CircularProgressIndicator()), child: Center(
child: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 5),
),
),
), ),
], ],
const SizedBox(height: 24), const SizedBox(height: 24),
@@ -313,10 +326,9 @@ class LatestReleasesContainer extends HookConsumerWidget {
child: Text( child: Text(
'LATEST RELEASES', 'LATEST RELEASES',
style: context.textTheme.labelLarge?.copyWith( style: context.textTheme.labelLarge?.copyWith(
color: Theme.of(context) color: Theme.of(
.colorScheme context,
.onSurface ).colorScheme.onSurface.withValues(alpha: 0.85),
.withValues(alpha: 0.85),
letterSpacing: 1.5, letterSpacing: 1.5,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),