fix(app): load more bookmarks as the list scrolls (#2556)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-06 21:05:57 +02:00
1 parent d91b5bec66
commit fbf0f6adfe
16 files changed
+322 -57

No files matched your search

@@ -2,14 +2,23 @@
import {Message} from '@app/features/messaging/models/MessagingMessage';
import type {SavedMessageEntry, SavedMessageMissingEntry} from '@app/features/messaging/models/SavedMessageEntry';
import {SAVED_MESSAGES_PAGE_SIZE} from '@fluxer/constants/src/LimitConstants';
import type {Channel} from '@fluxer/schema/src/domains/channel/ChannelSchemas';
import type {Message as WireMessage} from '@fluxer/schema/src/domains/message/MessageResponseSchemas';
import {makeAutoObservable} from 'mobx';
function byIdDescending(a: {id: string}, b: {id: string}): number {
return b.id > a.id ? 1 : a.id > b.id ? -1 : 0;
}
class SavedMessages {
savedMessages: Array<Message> = [];
missingSavedMessages: Array<SavedMessageMissingEntry> = [];
fetched = false;
hasMore = true;
isLoadingMore = false;
cursor: string | null = null;
private fetchGeneration = 0;
constructor() {
makeAutoObservable(this, {}, {autoBind: true});
@@ -26,27 +35,74 @@ class SavedMessages {
return this.missingSavedMessages.slice();
}
fetchSuccess(entries: ReadonlyArray<SavedMessageEntry>): void {
this.savedMessages = entries
getHasMore(): boolean {
return this.hasMore;
}
getIsLoadingMore(): boolean {
return this.isLoadingMore;
}
getCursor(): string | null {
return this.cursor;
}
handleFetchPending(): number {
this.isLoadingMore = true;
this.fetchGeneration++;
return this.fetchGeneration;
}
fetchSuccess(requestId: number, entries: ReadonlyArray<SavedMessageEntry>, append: boolean): void {
if (requestId !== this.fetchGeneration) return;
const available = entries
.filter((entry) => entry.status === 'available' && entry.message)
.map((entry) => entry.message!)
.sort((a, b) => (b.id > a.id ? 1 : a.id > b.id ? -1 : 0));
this.missingSavedMessages = entries
.map((entry) => entry.message!);
const missing = entries
.filter((entry) => entry.status === 'missing_permissions' || entry.message === null)
.map((entry) => entry.toMissingEntry());
if (append) {
const knownMessageIds = new Set(this.savedMessages.map((message) => message.id));
const knownMissingIds = new Set(this.missingSavedMessages.map((entry) => entry.id));
this.savedMessages = [
...this.savedMessages,
...available.filter((message) => !knownMessageIds.has(message.id)),
].sort(byIdDescending);
this.missingSavedMessages = [
...this.missingSavedMessages,
...missing.filter((entry) => !knownMissingIds.has(entry.id)),
];
} else {
this.savedMessages = available.sort(byIdDescending);
this.missingSavedMessages = missing;
}
if (entries.length > 0) {
this.cursor = entries[entries.length - 1].messageId;
}
this.hasMore = entries.length === SAVED_MESSAGES_PAGE_SIZE;
this.isLoadingMore = false;
this.fetched = true;
}
fetchError(): void {
fetchError(requestId: number, append: boolean): void {
if (requestId !== this.fetchGeneration) return;
this.isLoadingMore = false;
if (append) return;
this.reset();
}
private reset(): void {
this.savedMessages = [];
this.missingSavedMessages = [];
this.fetched = false;
this.hasMore = true;
this.isLoadingMore = false;
this.cursor = null;
}
handleGatewayReady(): void {
this.savedMessages = [];
this.missingSavedMessages = [];
this.fetched = false;
this.reset();
this.fetchGeneration++;
}
handleChannelDelete(channel: Channel): void {