diff --git a/.cursor/rules/api_platform.mdc b/.cursor/rules/api_platform.mdc index 0e4c168..879e0db 100644 --- a/.cursor/rules/api_platform.mdc +++ b/.cursor/rules/api_platform.mdc @@ -1,6 +1,6 @@ --- description: -globs: +globs: *.php alwaysApply: false --- ``` diff --git a/.cursor/rules/architecture.mdc b/.cursor/rules/architecture.mdc index c86b0f1..b085125 100644 --- a/.cursor/rules/architecture.mdc +++ b/.cursor/rules/architecture.mdc @@ -1,7 +1,7 @@ --- description: -globs: -alwaysApply: true +globs: *.php +alwaysApply: false --- # Architecture Hexagonale de Mangarr diff --git a/.cursor/rules/jobs.mdc b/.cursor/rules/jobs.mdc index bfffdf3..275b398 100644 --- a/.cursor/rules/jobs.mdc +++ b/.cursor/rules/jobs.mdc @@ -1,6 +1,6 @@ --- description: -globs: +globs: *.php alwaysApply: false --- # Architecture des Jobs dans Mangarr diff --git a/.cursor/rules/persistence.mdc b/.cursor/rules/persistence.mdc index 800503d..14696b8 100644 --- a/.cursor/rules/persistence.mdc +++ b/.cursor/rules/persistence.mdc @@ -1,6 +1,6 @@ --- description: -globs: +globs: *.php alwaysApply: false --- # Persistence dans l'Architecture Hexagonale diff --git a/.cursor/rules/tests.mdc b/.cursor/rules/tests.mdc index 7cdc928..0e5b039 100644 --- a/.cursor/rules/tests.mdc +++ b/.cursor/rules/tests.mdc @@ -1,6 +1,6 @@ --- description: -globs: +globs: *.php alwaysApply: false --- # Tests de Mangarr diff --git a/assets/vue/app/domain/reader/application/store/readerStore.js b/assets/vue/app/domain/reader/application/store/readerStore.js index e3d2360..0492a46 100644 --- a/assets/vue/app/domain/reader/application/store/readerStore.js +++ b/assets/vue/app/domain/reader/application/store/readerStore.js @@ -12,7 +12,8 @@ export const useReaderStore = defineStore('reader', { isLoading: false, error: null, pages: [], - totalPages: 0 + totalPages: 0, + loadedPages: new Set() // Garder une trace des pages déjà chargées }), getters: { @@ -38,11 +39,17 @@ export const useReaderStore = defineStore('reader', { // Initialiser le tableau avec des placeholders this.pages = new Array(pagesData.totalItems).fill(null); this.totalPages = pagesData.totalItems; + this.loadedPages.clear(); // Charger la première page if (this.totalPages > 0) { this.currentPage = 0; - await this.loadCurrentPageData(); + await this.loadPageData(0); + + // En mode infini, précharger les premières pages + if (this.readingMode === 'infinite') { + await this.preloadNextPages(0); + } } } catch (error) { this.error = error.message; @@ -51,23 +58,23 @@ export const useReaderStore = defineStore('reader', { } }, - async loadCurrentPageData() { - if (!this.currentChapter) { + async loadPageData(pageIndex) { + if (!this.currentChapter || pageIndex < 0 || pageIndex >= this.totalPages) { return; } - if (this.currentPage < 0 || this.currentPage >= this.totalPages) { + // Si la page est déjà chargée, ne rien faire + if (this.loadedPages.has(pageIndex)) { return; } - const pageNumber = this.currentPage + 1; // Convertir en 1-based pour l'API + const pageNumber = pageIndex + 1; // Convertir en 1-based pour l'API - if (this.pages[this.currentPage]?.base64Content) { - return; - } + // Marquer la page comme en cours de chargement + const newPages = [...this.pages]; + newPages[pageIndex] = { loading: true }; + this.pages = newPages; - this.isLoading = true; - this.error = null; try { const repository = new ApiChapterRepository(); const pageData = await repository.getChapterPage(this.currentChapter.id, pageNumber); @@ -77,39 +84,73 @@ export const useReaderStore = defineStore('reader', { throw new Error("Données de page invalides reçues de l'API"); } - // Créer une nouvelle référence du tableau pour déclencher la réactivité - const newPages = [...this.pages]; - newPages[this.currentPage] = { + // Mettre à jour la page + const updatedPages = [...this.pages]; + updatedPages[pageIndex] = { id: pageData.id, pageNumber: pageData.pageNumber, base64Content: pageData.base64Content, mimeType: pageData.mimeType, dimensions: pageData.dimensions }; - this.pages = newPages; + this.pages = updatedPages; + this.loadedPages.add(pageIndex); } catch (error) { - this.error = error.message; - } finally { - this.isLoading = false; + console.error(`Erreur lors du chargement de la page ${pageNumber}:`, error); + // Marquer la page comme en erreur + const errorPages = [...this.pages]; + errorPages[pageIndex] = { error: error.message }; + this.pages = errorPages; + } + }, + + async preloadNextPages(startIndex, count = 3) { + const promises = []; + for (let i = 1; i <= count; i++) { + const pageIndex = startIndex + i; + if (pageIndex < this.totalPages) { + promises.push(this.loadPageData(pageIndex)); + } + } + await Promise.all(promises); + }, + + async handlePageVisible(pageIndex) { + if (pageIndex !== this.currentPage) { + this.currentPage = pageIndex; + // Précharger les pages suivantes + if (this.readingMode === 'infinite') { + await this.preloadNextPages(pageIndex); + } } }, async nextPage() { if (!this.isLastPage) { this.currentPage++; - await this.loadCurrentPageData(); + await this.loadPageData(this.currentPage); } }, async previousPage() { if (!this.isFirstPage) { this.currentPage--; - await this.loadCurrentPageData(); + await this.loadPageData(this.currentPage); } }, - setReadingMode(mode) { + async setReadingMode(mode) { + if (mode === this.readingMode) return; + this.readingMode = mode; + + // S'assurer que la page courante est chargée + await this.loadPageData(this.currentPage); + + // Si on passe en mode infini, précharger les pages suivantes + if (mode === 'infinite') { + await this.preloadNextPages(this.currentPage); + } }, setReadingDirection(direction) { diff --git a/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue b/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue index 84d5ed3..f677e88 100644 --- a/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue +++ b/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue @@ -9,43 +9,44 @@