mirror of
https://github.com/gotson/komga.git
synced 2025-12-22 00:13:30 +01:00
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:
parent
bb7e31e02e
commit
5fe015ede0
5 changed files with 69 additions and 35 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue