From 5fe015ede0329ed85b39b78f11d55150214f65bf Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Thu, 27 Aug 2020 16:47:21 +0800 Subject: [PATCH] feat(webreader): add double page no cover layout this layout displays double spreads, but doesn't place the first/last page as single this commit also fixes a bug where the penultimate page would be missing in double pages for books with an odd number of pages closes #103 --- .../src/components/readers/PagedReader.vue | 30 +++++++--- komga-webui/src/functions/reader.ts | 8 ++- .../src/functions/shortcuts/paged-reader.ts | 4 +- komga-webui/src/types/enum-reader.ts | 6 ++ komga-webui/src/views/BookReader.vue | 56 +++++++++++-------- 5 files changed, 69 insertions(+), 35 deletions(-) diff --git a/komga-webui/src/components/readers/PagedReader.vue b/komga-webui/src/components/readers/PagedReader.vue index 37e06b0f8..5a0e2aab4 100644 --- a/komga-webui/src/components/readers/PagedReader.vue +++ b/komga-webui/src/components/readers/PagedReader.vue @@ -77,7 +77,7 @@ import { isPageLandscape } from '@/functions/page' import Vue from 'vue' import { ReadingDirection } from '@/types/enum-books' -import { ScaleType } from '@/types/enum-reader' +import { PagedReaderLayout, ScaleType } from '@/types/enum-reader' import { shortcutsLTR, shortcutsRTL, shortcutsVertical } from '@/functions/shortcuts/paged-reader' export default Vue.extend({ @@ -97,8 +97,8 @@ export default Vue.extend({ type: Number, required: true, }, - doublePages: { - type: Boolean, + pageLayout: { + type: String as () => PagedReaderLayout, required: true, }, animations: { @@ -131,7 +131,7 @@ export default Vue.extend({ page (val) { this.carouselPage = this.toSpreadIndex(val) }, - doublePages: { + pageLayout: { handler () { const current = this.page this.spreads = this.buildSpreads() @@ -186,6 +186,9 @@ export default Vue.extend({ canNext (): boolean { return this.currentSlide < this.slidesCount }, + isDoublePages (): boolean { + return this.pageLayout === PagedReaderLayout.DOUBLE_PAGES || this.pageLayout === PagedReaderLayout.DOUBLE_NO_COVER + }, }, methods: { keyPressed (e: KeyboardEvent) { @@ -193,10 +196,15 @@ export default Vue.extend({ }, buildSpreads (): PageDtoWithUrl[][] { if (this.pages.length === 0) return [] - if (this.doublePages) { + if (this.isDoublePages) { const spreads = [] - spreads.push([this.pages[0]]) - const pages = this.$_.drop(this.$_.dropRight(this.pages)) as PageDtoWithUrl[] + let pages: PageDtoWithUrl[] + if (this.pageLayout === PagedReaderLayout.DOUBLE_PAGES) { + spreads.push([this.pages[0]]) + pages = this.$_.drop(this.$_.dropRight(this.pages)) + } else { + pages = this.$_.cloneDeep(this.pages) + } while (pages.length > 0) { const p = pages.shift() as PageDtoWithUrl if (isPageLandscape(p)) { @@ -210,10 +218,14 @@ export default Vue.extend({ } else { spreads.push([p, p2]) } + } else { + spreads.push([p]) } } } - spreads.push([this.pages[this.pages.length - 1]]) + if (this.pageLayout === PagedReaderLayout.DOUBLE_PAGES) { + spreads.push([this.pages[this.pages.length - 1]]) + } return spreads } else { return this.pages.map(p => [p]) @@ -270,7 +282,7 @@ export default Vue.extend({ }, toSpreadIndex (i: number): number { if (this.spreads.length > 0) { - if (this.doublePages) { + if (this.isDoublePages) { for (let j = 0; j < this.spreads.length; j++) { for (let k = 0; k < this.spreads[j].length; k++) { if (this.spreads[j][k].number === i) { diff --git a/komga-webui/src/functions/reader.ts b/komga-webui/src/functions/reader.ts index a71c8664b..6ebb410c8 100644 --- a/komga-webui/src/functions/reader.ts +++ b/komga-webui/src/functions/reader.ts @@ -1,4 +1,4 @@ -import { ContinuousScaleType, ScaleType } from '@/types/enum-reader' +import { ContinuousScaleType, PagedReaderLayout, ScaleType } from '@/types/enum-reader' import { ReadingDirection } from '@/types/enum-books' export const ScaleTypeText = { @@ -16,3 +16,9 @@ export const ReadingDirectionText = { [ReadingDirection.VERTICAL]: 'Vertical', [ReadingDirection.WEBTOON]: 'Webtoon', } + +export const PagedReaderLayoutText = { + [PagedReaderLayout.SINGLE_PAGE]: 'Single page', + [PagedReaderLayout.DOUBLE_PAGES]: 'Double pages', + [PagedReaderLayout.DOUBLE_NO_COVER]: 'Double pages (no cover)', +} diff --git a/komga-webui/src/functions/shortcuts/paged-reader.ts b/komga-webui/src/functions/shortcuts/paged-reader.ts index fee07e23d..8bfb62bf7 100644 --- a/komga-webui/src/functions/shortcuts/paged-reader.ts +++ b/komga-webui/src/functions/shortcuts/paged-reader.ts @@ -34,7 +34,7 @@ export const shortcutsVertical = [ ] export const shortcutsSettingsPaged = [ - new Shortcut('Toggle double pages', - (ctx: any) => ctx.toggleDoublePages() + new Shortcut('Cycle page layout', + (ctx: any) => ctx.cyclePageLayout() , 'd'), ] diff --git a/komga-webui/src/types/enum-reader.ts b/komga-webui/src/types/enum-reader.ts index d4a39b6c7..31dba0338 100644 --- a/komga-webui/src/types/enum-reader.ts +++ b/komga-webui/src/types/enum-reader.ts @@ -10,5 +10,11 @@ export enum ContinuousScaleType { ORIGINAL = 'original' } +export enum PagedReaderLayout { + SINGLE_PAGE = 'single', + DOUBLE_PAGES = 'double', + DOUBLE_NO_COVER = 'double_no_cover' +} + export const PaddingPercentage: number[] = [0, 5, 10, 15, 20, 25, 30, 35, 40] diff --git a/komga-webui/src/views/BookReader.vue b/komga-webui/src/views/BookReader.vue index 333841aac..6a805f36c 100644 --- a/komga-webui/src/views/BookReader.vue +++ b/komga-webui/src/views/BookReader.vue @@ -103,7 +103,7 @@ :pages="pages" :page.sync="page" :reading-direction="readingDirection" - :double-pages="doublePages" + :page-layout="pageLayout" :scale="scale" :animations="animations" :swipe="swipe" @@ -193,7 +193,11 @@ - + @@ -273,8 +277,8 @@ import Vue from 'vue' import { Location } from 'vue-router' import PagedReader from '@/components/readers/PagedReader.vue' import ContinuousReader from '@/components/readers/ContinuousReader.vue' -import { ContinuousScaleType, PaddingPercentage, ScaleType } from '@/types/enum-reader' -import { ReadingDirectionText, ScaleTypeText } from '@/functions/reader' +import { ContinuousScaleType, PaddingPercentage, PagedReaderLayout, ScaleType } from '@/types/enum-reader' +import { PagedReaderLayoutText, ReadingDirectionText, ScaleTypeText } from '@/functions/reader' import { shortcutsLTR, shortcutsRTL, @@ -289,7 +293,7 @@ const cookieFit = 'webreader.fit' const cookieContinuousReaderFit = 'webreader.continuousReaderFit' const cookieContinuousReaderPadding = 'webreader.continuousReaderPadding' const cookieReadingDirection = 'webreader.readingDirection' -const cookieDoublePages = 'webreader.doublePages' +const cookiePageLayout = 'webreader.pageLayout' const cookieSwipe = 'webreader.swipe' const cookieAnimations = 'webreader.animations' const cookieBackground = 'webreader.background' @@ -327,7 +331,7 @@ export default Vue.extend({ showHelp: false, goToPage: 1, settings: { - doublePages: false, + pageLayout: PagedReaderLayout.SINGLE_PAGE, swipe: true, animations: true, scale: ScaleType.SCREEN, @@ -354,6 +358,10 @@ export default Vue.extend({ text: ScaleTypeText[x], value: x, })), + pageLayouts: Object.values(PagedReaderLayout).map(x => ({ + text: PagedReaderLayoutText[x], + value: x, + })), paddingPercentages: Object.values(PaddingPercentage).map(x => ({ text: x === 0 ? 'None' : `${x}%`, value: x, @@ -380,8 +388,8 @@ export default Vue.extend({ this.loadFromCookie(cookieAnimations, (v) => { this.animations = (v === 'true') }) - this.loadFromCookie(cookieDoublePages, (v) => { - this.doublePages = (v === 'true') + this.loadFromCookie(cookiePageLayout, (v) => { + this.pageLayout = v }) this.loadFromCookie(cookieSwipe, (v) => { this.swipe = (v === 'true') @@ -423,12 +431,6 @@ export default Vue.extend({ this.goToPage = val this.markProgress(val) }, - async book (val) { - if (this.$_.has(val, 'name')) { - this.series = await this.$komgaSeries.getOneSeries(val.seriesId) - document.title = `Komga - ${getBookTitleCompact(val.metadata.title, this.series.metadata.title)}` - } - }, }, computed: { continuousReader (): boolean { @@ -538,13 +540,15 @@ export default Vue.extend({ } }, }, - doublePages: { - get: function (): boolean { - return this.settings.doublePages + pageLayout: { + get: function (): PagedReaderLayout { + return this.settings.pageLayout }, - set: function (doublePages: boolean): void { - this.settings.doublePages = doublePages - this.$cookies.set(cookieDoublePages, doublePages, Infinity) + set: function (pageLayout: PagedReaderLayout): void { + if (Object.values(PagedReaderLayout).includes(pageLayout)) { + this.settings.pageLayout = pageLayout + this.$cookies.set(cookiePageLayout, pageLayout, Infinity) + } }, }, swipe: { @@ -563,6 +567,9 @@ export default Vue.extend({ }, async setup (bookId: string, page: number) { this.book = await this.$komgaBooks.getBook(bookId) + this.series = await this.$komgaSeries.getOneSeries(this.book.seriesId) + document.title = `Komga - ${getBookTitleCompact(this.book.metadata.title, this.series.metadata.title)}` + const pageDtos = (await this.$komgaBooks.getBookPages(bookId)) pageDtos.forEach((p: any) => p['url'] = this.getPageUrl(p)) this.pages = pageDtos as PageDtoWithUrl[] @@ -684,10 +691,13 @@ export default Vue.extend({ this.sendNotification(`Cycling Side Padding: ${text}`) } }, - toggleDoublePages () { + cyclePageLayout () { if (this.continuousReader) return - this.doublePages = !this.doublePages - this.sendNotification(`${this.doublePages ? 'Enabled' : 'Disabled'} Double Pages`) + const enumValues = Object.values(PagedReaderLayout) + const i = (enumValues.indexOf(this.settings.pageLayout) + 1) % (enumValues.length) + this.pageLayout = enumValues[i] + const text = PagedReaderLayoutText[this.pageLayout] + this.sendNotification(`Cycling Page Layout: ${text}`) }, toggleToolbars () { this.showToolbars = !this.showToolbars