From 5a5569cf2ce30266bb987363f71b6a510e98396a Mon Sep 17 00:00:00 2001 From: "ext.jeremy.guillot@maxicoffee.domains" Date: Sun, 6 Jul 2025 15:55:55 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20ajout=20de=20la=20gestion=20des=20doubl?= =?UTF-8?q?es=20pages=20pour=20le=20lecteur,=20incluant=20des=20param?= =?UTF-8?q?=C3=A8tres=20de=20d=C3=A9tection=20automatique,=20des=20modes?= =?UTF-8?q?=20d'affichage=20et=20des=20pr=C3=A9f=C3=A9rences=20sauvegard?= =?UTF-8?q?=C3=A9es.=20Am=C3=A9lioration=20de=20l'interface=20utilisateur?= =?UTF-8?q?=20pour=20int=C3=A9grer=20ces=20nouvelles=20fonctionnalit=C3=A9?= =?UTF-8?q?s.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reader/application/store/readerStore.js | 123 ++++- .../presentation/components/ChapterReader.vue | 123 ++++- .../components/InfiniteReader.vue | 76 ++- .../components/ReaderControls.vue | 86 +++- .../presentation/components/ReaderPage.vue | 308 ++++++++++- .../components/ReaderSettings.vue | 481 +++++++++++++++++- .../components/SingleModeReader.vue | 11 + templates/base.html.twig | 1 + templates/vue/index.html.twig | 4 +- 9 files changed, 1150 insertions(+), 63 deletions(-) diff --git a/assets/vue/app/domain/reader/application/store/readerStore.js b/assets/vue/app/domain/reader/application/store/readerStore.js index 1305a45..75a02a3 100644 --- a/assets/vue/app/domain/reader/application/store/readerStore.js +++ b/assets/vue/app/domain/reader/application/store/readerStore.js @@ -13,7 +13,14 @@ export const useReaderStore = defineStore('reader', { error: null, pages: [], totalPages: 0, - loadedPages: new Set() // Garder une trace des pages déjà chargées + loadedPages: new Set(), // Garder une trace des pages déjà chargées + + // Paramètres pour les doubles pages + doublePageSettings: { + autoDetect: true, + mobileMode: 'rotate', // 'rotate', 'scroll', 'normal' + detectionThreshold: 1.2 // Ratio largeur/hauteur pour détecter une double page + } }), getters: { @@ -21,7 +28,24 @@ export const useReaderStore = defineStore('reader', { isLastPage: state => state.currentPage === state.totalPages - 1, currentPageData: state => state.pages[state.currentPage], hasPreviousChapter: state => Boolean(state.currentChapter?.navigation?.previousChapter), - hasNextChapter: state => Boolean(state.currentChapter?.navigation?.nextChapter) + hasNextChapter: state => Boolean(state.currentChapter?.navigation?.nextChapter), + + // Getters pour les doubles pages + effectiveDoublePageMode: (state) => { + // Si la détection automatique est désactivée, retourner 'normal' + if (!state.doublePageSettings.autoDetect) { + return 'normal'; + } + return state.doublePageSettings.mobileMode; + }, + + // Préférences sauvegardées dans localStorage + savedPreferences: (state) => ({ + readingMode: state.readingMode, + readingDirection: state.readingDirection, + zoom: state.zoom, + doublePageSettings: state.doublePageSettings + }) }, actions: { @@ -145,6 +169,7 @@ export const useReaderStore = defineStore('reader', { if (mode === this.readingMode) return; this.readingMode = mode; + this.savePreferences(); // S'assurer que la page courante est chargée await this.loadPageData(this.currentPage); @@ -157,10 +182,44 @@ export const useReaderStore = defineStore('reader', { setReadingDirection(direction) { this.readingDirection = direction; + this.savePreferences(); }, - setZoom(level) { - this.zoom = level; + setZoom(zoom) { + this.zoom = Math.max(0.5, Math.min(2, zoom)); + this.savePreferences(); + }, + + // Nouvelles actions pour les doubles pages + setDoublePageMode(mode) { + if (['rotate', 'scroll', 'normal'].includes(mode)) { + this.doublePageSettings.mobileMode = mode; + this.savePreferences(); + } + }, + + setDoublePageAutoDetect(enabled) { + this.doublePageSettings.autoDetect = enabled; + this.savePreferences(); + }, + + setDoublePageDetectionThreshold(threshold) { + this.doublePageSettings.detectionThreshold = Math.max(1.0, Math.min(3.0, threshold)); + this.savePreferences(); + }, + + updateDoublePageSettings(settings) { + this.doublePageSettings = { + ...this.doublePageSettings, + ...settings + }; + this.savePreferences(); + }, + + async goToNextChapter() { + if (this.currentChapter?.navigation?.nextChapter) { + await this.loadChapter(this.currentChapter.navigation.nextChapter); + } }, async goToPreviousChapter() { @@ -175,10 +234,60 @@ export const useReaderStore = defineStore('reader', { } }, - async goToNextChapter() { - if (this.currentChapter?.navigation?.nextChapter) { - await this.loadChapter(this.currentChapter.navigation.nextChapter); + // Gestion de la persistance des préférences + savePreferences() { + try { + const preferences = { + readingMode: this.readingMode, + readingDirection: this.readingDirection, + zoom: this.zoom, + doublePageSettings: this.doublePageSettings + }; + localStorage.setItem('mangarr-reader-preferences', JSON.stringify(preferences)); + } catch (error) { + console.error('Erreur lors de la sauvegarde des préférences:', error); } + }, + + loadPreferences() { + try { + const stored = localStorage.getItem('mangarr-reader-preferences'); + if (stored) { + const preferences = JSON.parse(stored); + + // Appliquer les préférences sauvegardées + if (preferences.readingMode) this.readingMode = preferences.readingMode; + if (preferences.readingDirection) this.readingDirection = preferences.readingDirection; + if (typeof preferences.zoom === 'number') this.zoom = preferences.zoom; + + // Migration: si l'ancien doublePageMode existe, le migrer vers mobileMode + if (preferences.doublePageMode && ['rotate', 'scroll', 'normal'].includes(preferences.doublePageMode)) { + this.doublePageSettings.mobileMode = preferences.doublePageMode; + } + + if (preferences.doublePageSettings) { + this.doublePageSettings = { + ...this.doublePageSettings, + ...preferences.doublePageSettings + }; + } + } + } catch (error) { + console.error('Erreur lors du chargement des préférences:', error); + } + }, + + // Réinitialiser les préférences + resetPreferences() { + this.readingMode = 'single'; + this.readingDirection = 'ltr'; + this.zoom = 1; + this.doublePageSettings = { + autoDetect: true, + mobileMode: 'rotate', + detectionThreshold: 1.2 + }; + this.savePreferences(); } } }); diff --git a/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue b/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue index 749c53b..7a4f74d 100644 --- a/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue +++ b/assets/vue/app/domain/reader/presentation/components/ChapterReader.vue @@ -16,34 +16,54 @@ :is-first-page="store.isFirstPage" :is-last-page="store.isLastPage" :available-chapters="availableChapters" + :settings-open="settingsOpen" @previous="store.previousPage" @next="store.nextPage" - @chapter-selected="handleChapterSelected" /> + @chapter-selected="handleChapterSelected" + @toggle-settings="toggleSettings" /> + @zoom-out="zoomOut" + @zoom-change="handleZoomChange" + @double-page-mode-change="handleDoublePageModeChange" + @double-page-auto-detect-change="handleDoublePageAutoDetectChange" + @detection-threshold-change="handleDetectionThresholdChange" + @reset-preferences="handleResetPreferences" + @button-click="resetButtonsTimer" /> diff --git a/assets/vue/app/domain/reader/presentation/components/InfiniteReader.vue b/assets/vue/app/domain/reader/presentation/components/InfiniteReader.vue index 901115d..9d8fbc3 100644 --- a/assets/vue/app/domain/reader/presentation/components/InfiniteReader.vue +++ b/assets/vue/app/domain/reader/presentation/components/InfiniteReader.vue @@ -12,7 +12,7 @@
{{ page.error }}
- + @@ -30,7 +30,7 @@ leave-to-class="opacity-0 translate-y-5 scale-75" >