diff --git a/src/application/services/useNoteList.ts b/src/application/services/useNoteList.ts index 1d29b6ea..5b96a03d 100644 --- a/src/application/services/useNoteList.ts +++ b/src/application/services/useNoteList.ts @@ -69,7 +69,7 @@ export default function (onlyCreatedByUser = false): UseNoteListComposableState const isLoading = ref(false); /** - * Get note list + * Get note list (metadata only, covers are not downloaded) * @param page - number of pages */ const load = async (page: number): Promise => { @@ -82,6 +82,47 @@ export default function (onlyCreatedByUser = false): UseNoteListComposableState return list; }; + /** + * Load cover images for all notes in the list in the background + * Updates each note's cover reactively as it arrives + */ + const loadCovers = async (): Promise => { + if (isEmpty(noteList.value)) { + return; + } + + const list = noteList.value; + const items = list.items; + + await Promise.all(items.map(async (item, index) => { + /** + * If cover is null, the note has no cover image + */ + if (item.cover === null) { + return; + } + + /** + * If cover is already a blob URL, it was already loaded + */ + if (item.cover.startsWith('blob:')) { + return; + } + + const url = await noteListService.loadCover(item.id, item.cover); + + if (url !== null) { + /** + * Update the specific note's cover reactively so the card renders the image + */ + list.items[index] = { + ...item, + cover: url, + }; + } + })); + }; + /** * Load next page of the notes */ @@ -102,6 +143,12 @@ export default function (onlyCreatedByUser = false): UseNoteListComposableState } else { noteList.value = loadedNotes; } + + /** + * Kick off cover downloads in the background + * List is already rendered, covers will appear one by one as they load + */ + loadCovers().catch(console.error); }; /** diff --git a/src/domain/noteList.service.ts b/src/domain/noteList.service.ts index 87367b41..941161c0 100644 --- a/src/domain/noteList.service.ts +++ b/src/domain/noteList.service.ts @@ -20,54 +20,31 @@ export default class NoteListService { } /** - * Returns note list - * @todo - move loading images data logic to separate service for optimization + * Returns note list with metadata only (covers are not downloaded) * @param page - number of current pages * @param onlyCreatedByUser - if true, returns notes created by the user * @returns list of notes */ public async getNoteList(page: number, onlyCreatedByUser = false): Promise { - const noteList = await this.repository.getNoteList(page, onlyCreatedByUser); - - /** - * Note list with valid image urls in cover - */ - const parsedNoteList: NoteList = { - items: [], - }; - - for (const note of noteList.items) { - /** - * If note has no cover, we have no need to load it - */ - if (note.cover === null) { - parsedNoteList.items.push(note); - continue; - } - - /** - * Cover object url for passing to the element - */ - let objUrl: string | null = null; + return await this.repository.getNoteList(page, onlyCreatedByUser); + } - try { - const imageData = await this.noteAttachmentRepository.load(note.id, note.cover); + /** + * Load cover image for a single note and return its blob URL + * @param noteId - Note identifier + * @param coverKey - Cover file key on server + * @returns Blob URL for the cover image, or null on error + */ + public async loadCover(noteId: string, coverKey: string): Promise { + try { + const imageData = await this.noteAttachmentRepository.load(noteId, coverKey); - /** - * Make url from blob data - */ - // eslint-disable-next-line n/no-unsupported-features/node-builtins - objUrl = URL.createObjectURL(imageData); - } catch { - console.log('Error while loading cover for note ', note.id); - } + // eslint-disable-next-line n/no-unsupported-features/node-builtins + return URL.createObjectURL(imageData); + } catch { + console.log('Error while loading cover for note ', noteId); - parsedNoteList.items.push({ - ...note, - cover: objUrl, - }); + return null; } - - return parsedNoteList; } } diff --git a/src/presentation/components/note-list/NoteList.vue b/src/presentation/components/note-list/NoteList.vue index e1574f92..d51ac81e 100644 --- a/src/presentation/components/note-list/NoteList.vue +++ b/src/presentation/components/note-list/NoteList.vue @@ -15,7 +15,7 @@