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
This commit is contained in:
Gauthier Roebroeck 2020-08-27 16:47:21 +08:00
parent bb7e31e02e
commit 5fe015ede0
5 changed files with 69 additions and 35 deletions

View file

@ -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) {

View file

@ -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)',
}

View file

@ -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'),
]

View file

@ -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]

View file

@ -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 @@
</v-list-item>
<v-list-item>
<settings-switch v-model="doublePages" label="Double pages"></settings-switch>
<settings-select
:items="pageLayouts"
v-model="pageLayout"
label="Page layout"
/>
</v-list-item>
</div>
@ -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