diff --git a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt index 38f13bc4..94698d15 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/MainActivity.kt @@ -12,10 +12,10 @@ import android.util.Log import androidx.core.app.ActivityCompat import com.anggrayudi.storage.SimpleStorage import com.anggrayudi.storage.SimpleStorageHelper -import com.audiobookshelf.app.plugins.AbsDatabase import com.audiobookshelf.app.managers.DbManager import com.audiobookshelf.app.player.PlayerNotificationService import com.audiobookshelf.app.plugins.AbsAudioPlayer +import com.audiobookshelf.app.plugins.AbsDatabase import com.audiobookshelf.app.plugins.AbsDownloader import com.audiobookshelf.app.plugins.AbsFileSystem import com.getcapacitor.BridgeActivity diff --git a/components/readers/ComicReader.vue b/components/readers/ComicReader.vue index 1aaa36ce..a5927f80 100644 --- a/components/readers/ComicReader.vue +++ b/components/readers/ComicReader.vue @@ -1,23 +1,17 @@ @@ -148,6 +147,9 @@ export default { value: index++ } }) + }, + playerLibraryItemId() { + return this.$store.state.playerLibraryItemId } }, methods: { @@ -191,14 +193,10 @@ export default { this.showPageMenu = false }, clickShowPageMenu() { + if (!this.numPages) return this.showPageMenu = !this.showPageMenu this.showInfoMenu = false }, - clickedOutside(e) { - if (e.target?.id == 'btn-metadata') return - - if (this.showInfoMenu) this.showInfoMenu = false - }, next() { if (!this.canGoNext) return this.setPage(this.page + 1) @@ -289,6 +287,10 @@ export default { const startPage = this.savedPage > 0 && this.savedPage <= this.numPages ? this.savedPage : 1 await this.setPage(startPage) this.loadedFirstPage = true + + this.$emit('loaded', { + hasMetadata: this.comicMetadata + }) } else { this.$toast.error('Unable to extract pages') this.loading = false @@ -379,9 +381,6 @@ export default { padding-top: 36px; } -.pagemenu { - max-height: calc(100% - 20px); -} .comicimg { height: 100%; margin: auto; diff --git a/components/readers/EpubReader.vue b/components/readers/EpubReader.vue index 47df38cf..b9b461fc 100644 --- a/components/readers/EpubReader.vue +++ b/components/readers/EpubReader.vue @@ -2,11 +2,9 @@
-
-

epub

+
- -

{{ progress }}%

+

{{ progress }}%

@@ -66,11 +64,11 @@ export default { return this.$store.state.playerLibraryItemId }, readerHeightOffset() { - return this.playerLibraryItemId ? 196 : 96 + return this.playerLibraryItemId ? 156 : 56 }, /** @returns {Array} */ chapters() { - return this.book ? this.book.navigation.toc : [] + return this.book?.navigation?.toc || [] }, userItemProgress() { if (this.isLocal) return this.localItemProgress @@ -283,6 +281,13 @@ export default { console.log('Display error', err) }) + reader.rendition.on('touchstart', (event) => { + this.$emit('touchstart', event) + }) + reader.rendition.on('touchend', (event) => { + this.$emit('touchend', event) + }) + // load ebook cfi locations const savedLocations = this.loadLocations() if (savedLocations) { diff --git a/components/readers/MobiReader.vue b/components/readers/MobiReader.vue index 02fabba5..40f3f8f5 100644 --- a/components/readers/MobiReader.vue +++ b/components/readers/MobiReader.vue @@ -3,10 +3,6 @@
-
-

mobi

-
-
diff --git a/components/readers/PdfReader.vue b/components/readers/PdfReader.vue index 845f02d5..3cd2731c 100644 --- a/components/readers/PdfReader.vue +++ b/components/readers/PdfReader.vue @@ -1,5 +1,5 @@ @@ -47,7 +46,9 @@ export default { rotate: 0, loadedRatio: 0, page: 1, - numPages: 0 + numPages: 0, + windowWidth: 0, + windowHeight: 0 } }, computed: { @@ -71,10 +72,16 @@ export default { return null }, pdfWidth() { - return this.pdfHeight * 0.6667 + if (this.windowWidth > this.windowHeight) { + // Landscape + return this.windowHeight * 0.6 + } else { + // Portrait + return this.windowWidth + } }, pdfHeight() { - return window.innerHeight - 120 + return this.pdfWidth * 1.667 }, canGoNext() { return this.page < this.numPages @@ -106,6 +113,9 @@ export default { Authorization: `Bearer ${this.userToken}` } } + }, + playerLibraryItemId() { + return this.$store.state.playerLibraryItemId } }, methods: { @@ -161,8 +171,32 @@ export default { }, error(err) { console.error(err) + }, + screenOrientationChange() { + this.windowWidth = window.innerWidth + this.windowHeight = window.innerHeight } }, - mounted() {} + mounted() { + this.windowWidth = window.innerWidth + this.windowHeight = window.innerHeight + + if (screen.orientation) { + // Not available on ios + screen.orientation.addEventListener('change', this.screenOrientationChange) + } else { + document.addEventListener('orientationchange', this.screenOrientationChange) + } + window.addEventListener('resize', this.screenOrientationChange) + }, + beforeDestroy() { + if (screen.orientation) { + // Not available on ios + screen.orientation.removeEventListener('change', this.screenOrientationChange) + } else { + document.removeEventListener('orientationchange', this.screenOrientationChange) + } + window.removeEventListener('resize', this.screenOrientationChange) + } } \ No newline at end of file diff --git a/components/readers/Reader.vue b/components/readers/Reader.vue index a8c14ed2..5ba41bb3 100644 --- a/components/readers/Reader.vue +++ b/components/readers/Reader.vue @@ -1,11 +1,18 @@ @@ -19,16 +26,26 @@ export default { touchstartY: 0, touchendX: 0, touchendY: 0, - touchstartTime: 0 + touchstartTime: 0, + touchIdentifier: null, + showingToolbar: false, + showTOCModal: false, + showSettingsModal: false, + comicHasMetadata: false, + chapters: [] } }, watch: { show: { handler(newVal) { if (newVal) { + this.showingToolbar = false + this.comicHasMetadata = false this.registerListeners() + this.$showHideStatusBar(false) } else { this.unregisterListeners() + this.$showHideStatusBar(true) } } } @@ -124,6 +141,25 @@ export default { } }, methods: { + readerLoaded(data) { + if (this.isComic) { + this.comicHasMetadata = data.hasMetadata + } + }, + clickMetadataBtn() { + this.$refs.readerComponent?.clickShowInfoMenu() + }, + clickTOCBtn() { + if (this.isComic) { + this.$refs.readerComponent?.clickShowPageMenu?.() + } else { + this.chapters = this.$refs.readerComponent?.chapters || [] + this.showTOCModal = true + } + }, + clickSettingsBtn() { + this.showSettingsModal = true + }, next() { if (this.$refs.readerComponent && this.$refs.readerComponent.next) { this.$refs.readerComponent.next() @@ -135,7 +171,7 @@ export default { } }, handleGesture() { - // Touch must be less than 1s. Must be > 100px drag and X distance > Y distance + // Touch must be less than 1s. Must be > 60px drag and X distance > Y distance const touchTimeMs = Date.now() - this.touchstartTime if (touchTimeMs >= 1000) { console.log('Touch too long', touchTimeMs) @@ -144,10 +180,16 @@ export default { const touchDistanceX = Math.abs(this.touchendX - this.touchstartX) const touchDistanceY = Math.abs(this.touchendY - this.touchstartY) - if (touchDistanceX < 60 || touchDistanceY > touchDistanceX) { + const touchDistance = Math.sqrt(Math.pow(this.touchstartX - this.touchendX, 2) + Math.pow(this.touchstartY - this.touchendY, 2)) + if (touchDistance < 60) { + this.toggleToolbar() return } + if (touchDistanceX < 60 || touchDistanceY > touchDistanceX) { + return + } + this.hideToolbar() if (this.touchendX < this.touchstartX) { this.next() } @@ -155,12 +197,31 @@ export default { this.prev() } }, + showToolbar() { + this.showingToolbar = true + }, + hideToolbar() { + this.showingToolbar = false + }, + toggleToolbar() { + if (this.showingToolbar) this.hideToolbar() + else this.showToolbar() + }, touchstart(e) { + // Ignore rapid touch + if (this.touchstartTime && Date.now() - this.touchstartTime < 250) { + return + } + this.touchstartX = e.touches[0].screenX this.touchstartY = e.touches[0].screenY this.touchstartTime = Date.now() + this.touchIdentifier = e.touches[0].identifier }, touchend(e) { + if (this.touchIdentifier !== e.changedTouches[0].identifier) { + return + } this.touchendX = e.changedTouches[0].screenX this.touchendY = e.changedTouches[0].screenY this.handleGesture() diff --git a/layouts/default.vue b/layouts/default.vue index c48f39c6..bd6e8bba 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -60,6 +60,9 @@ export default { playerIsOpen() { return this.$store.state.playerLibraryItemId }, + readerIsOpen() { + return this.$store.state.showReader + }, routeName() { return this.$route.name }, diff --git a/plugins/init.client.js b/plugins/init.client.js index 46d9e07b..ac03891c 100644 --- a/plugins/init.client.js +++ b/plugins/init.client.js @@ -16,6 +16,14 @@ if (Capacitor.getPlatform() != 'web') { setStatusBarStyleDark() } +Vue.prototype.$showHideStatusBar = async (show) => { + if (show) { + StatusBar.show() + } else { + StatusBar.hide() + } +} + Vue.prototype.$isDev = process.env.NODE_ENV !== 'production' Vue.prototype.$getAndroidSDKVersion = async () => {