Adding Scaling and padding to the Webreader's webtoon mode (#266)

* feat(webreader): adding scale type original to webtoon mode

* fix(webreader): correcting scale type used for continuous reader

* feat(webreader): adding setting for side padding to webtoon mode

* feat(webreader): adding shortcut for side padding and new values

* refactor: update padding percentage data type to number array

* fix: correcting type issues after previous refactor

* fix: images not showing if page has no dimension

width and height on pages are not guaranteed

* refactor: add new enum values to ScaleTypeText

previous behavior worked only because the values of ScaleType and ContinuousScaleType are the same

* refactor: simplify conditions

fullWidthReader was only used for the continuous reader
settings inside a reader type are not conditional

* refactor: rearrange shortcuts

continuous reader did not have specific settings
this rearranges shortcuts for the help menu

Co-authored-by: Gauthier Roebroeck <gauthier.roebroeck@gmail.com>
This commit is contained in:
edwinbadillo 2020-08-12 10:01:48 -04:00 committed by GitHub
parent 90e5fc945a
commit 6faeb2ab2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 163 additions and 16 deletions

View file

@ -7,9 +7,10 @@
:key="`page${i}`"
:alt="`Page ${page.number}`"
:src="shouldLoad(i) ? page.url : undefined"
:height="page.height / (page.width / $vuetify.breakpoint.width)"
:width="$vuetify.breakpoint.width"
:height="calcHeight(page)"
:width="calcWidth(page)"
:id="`page${page.number}`"
style="margin: 0 auto;"
v-intersect="onIntersect"
/>
</div>
@ -36,6 +37,7 @@
<script lang="ts">
import Vue from 'vue'
import { ContinuousScaleType } from '@/types/enum-reader'
export default Vue.extend({
name: 'ContinuousReader',
@ -60,6 +62,14 @@ export default Vue.extend({
type: Number,
required: true,
},
scale: {
type: String as () => ContinuousScaleType,
required: true,
},
sidePadding: {
type: Number,
required: true,
},
},
watch: {
pages: {
@ -97,6 +107,9 @@ export default Vue.extend({
if (this.animations) return undefined
return { duration: 0 }
},
totalSidePadding (): number {
return this.sidePadding * 2
},
},
methods: {
onScroll (e: any) {
@ -114,6 +127,28 @@ export default Vue.extend({
shouldLoad (page: number): boolean {
return page == 0 || this.seen[page] || Math.abs((this.currentPage - 1) - page) <= 2
},
calcHeight (page: PageDtoWithUrl): number | undefined {
switch (this.scale) {
case ContinuousScaleType.WIDTH:
if (page.height && page.width)
return page.height / (page.width / (this.$vuetify.breakpoint.width - (this.$vuetify.breakpoint.width * this.totalSidePadding) / 100))
return undefined
case ContinuousScaleType.ORIGINAL:
return page.height || undefined
default:
return undefined
}
},
calcWidth (page: PageDtoWithUrl): number | undefined {
switch (this.scale) {
case ContinuousScaleType.WIDTH:
return this.$vuetify.breakpoint.width - (this.$vuetify.breakpoint.width * this.totalSidePadding) / 100
case ContinuousScaleType.ORIGINAL:
return page.width || undefined
default:
return undefined
}
},
centerClick () {
this.$emit('menu')
},

View file

@ -1,11 +1,13 @@
import { ScaleType } from '@/types/enum-reader'
import { ContinuousScaleType, ScaleType } from '@/types/enum-reader'
import { ReadingDirection } from '@/types/enum-books'
export const ScaleTypeText = {
[ScaleType.SCREEN]: 'Fit screen',
[ScaleType.HEIGHT]: 'Fit height',
[ScaleType.WIDTH]: 'Fit width',
[ContinuousScaleType.WIDTH]: 'Fit width',
[ScaleType.ORIGINAL]: 'Original',
[ContinuousScaleType.ORIGINAL]: 'Original',
}
export const ReadingDirectionText = {

View file

@ -14,9 +14,6 @@ export const shortcutsSettings = [
new Shortcut('Webtoon',
(ctx: any) => ctx.changeReadingDir(ReadingDirection.WEBTOON)
, 'w'),
new Shortcut('Toggle double pages',
(ctx: any) => ctx.toggleDoublePages()
, 'd'),
new Shortcut('Cycle scale',
(ctx: any) => ctx.cycleScale()
, 'c'),

View file

@ -0,0 +1,7 @@
import { Shortcut } from '@/types/shortcuts'
export const shortcutsSettingsContinuous = [
new Shortcut('Cycle side padding',
(ctx: any) => ctx.cycleSidePadding()
, 'p'),
]

View file

@ -32,3 +32,9 @@ export const shortcutsVertical = [
ctx.verticalNext()
}, 'ArrowDown', '↓'),
]
export const shortcutsSettingsPaged = [
new Shortcut('Toggle double pages',
(ctx: any) => ctx.toggleDoublePages()
, 'd'),
]

View file

@ -4,3 +4,10 @@ export enum ScaleType {
HEIGHT = 'height',
ORIGINAL = 'original'
}
export enum ContinuousScaleType {
WIDTH = 'width',
ORIGINAL = 'original'
}
export const PaddingPercentage: number[] = [0, 5, 10, 15, 20, 25, 30, 35, 40]

View file

@ -91,6 +91,8 @@
:pages="pages"
:page.sync="page"
:animations="animations"
:scale="continuousScale"
:sidePadding="sidePadding"
@menu="toggleToolbars()"
@jump-previous="jumpToPrevious()"
@jump-next="jumpToNext()"
@ -162,6 +164,24 @@
</settings-select>
</v-list-item>
<div v-if="continuousReader">
<v-subheader class="font-weight-black text-h6">Webtoon</v-subheader>
<v-list-item>
<settings-select
:items="continuousScaleTypes"
v-model="continuousScale"
label="Scale type"
/>
</v-list-item>
<v-list-item>
<settings-select
:items="paddingPercentages"
v-model="sidePadding"
label="Side padding"
/>
</v-list-item>
</div>
<div v-if="!continuousReader">
<v-subheader class="font-weight-black text-h6">Paged</v-subheader>
<v-list-item>
@ -253,13 +273,21 @@ import Vue from 'vue'
import { Location } from 'vue-router'
import PagedReader from '@/components/readers/PagedReader.vue'
import ContinuousReader from '@/components/readers/ContinuousReader.vue'
import { ScaleType } from '@/types/enum-reader'
import { ContinuousScaleType, PaddingPercentage, ScaleType } from '@/types/enum-reader'
import { ReadingDirectionText, ScaleTypeText } from '@/functions/reader'
import { shortcutsLTR, shortcutsRTL, shortcutsVertical } from '@/functions/shortcuts/paged-reader'
import {
shortcutsLTR,
shortcutsRTL,
shortcutsSettingsPaged,
shortcutsVertical,
} from '@/functions/shortcuts/paged-reader'
import { shortcutsMenus, shortcutsSettings } from '@/functions/shortcuts/bookreader'
import { shortcutsAll } from '@/functions/shortcuts/reader'
import { shortcutsSettingsContinuous } from '@/functions/shortcuts/continuous-reader'
const cookieFit = 'webreader.fit'
const cookieContinuousReaderFit = 'webreader.continuousReaderFit'
const cookieContinuousReaderPadding = 'webreader.continuousReaderPadding'
const cookieReadingDirection = 'webreader.readingDirection'
const cookieDoublePages = 'webreader.doublePages'
const cookieSwipe = 'webreader.swipe'
@ -303,6 +331,8 @@ export default Vue.extend({
swipe: true,
animations: true,
scale: ScaleType.SCREEN,
continuousScale: ContinuousScaleType.WIDTH,
sidePadding: 0,
readingDirection: ReadingDirection.LEFT_TO_RIGHT,
backgroundColor: 'black',
},
@ -320,6 +350,14 @@ export default Vue.extend({
text: ScaleTypeText[x],
value: x,
})),
continuousScaleTypes: Object.values(ContinuousScaleType).map(x => ({
text: ScaleTypeText[x],
value: x,
})),
paddingPercentages: Object.values(PaddingPercentage).map(x => ({
text: x === 0 ? 'None' : `${x}%`,
value: x,
})),
backgroundColors: [
{ text: 'White', value: 'white' },
{ text: 'Black', value: 'black' },
@ -332,7 +370,7 @@ export default Vue.extend({
this.supportedMediaTypes.push('image/webp')
}
})
this.shortcuts = this.$_.keyBy([...shortcutsSettings, ...shortcutsMenus, ...shortcutsAll], x => x.key)
this.shortcuts = this.$_.keyBy([...shortcutsSettings, ...shortcutsSettingsPaged, ...shortcutsSettingsContinuous, ...shortcutsMenus, ...shortcutsAll], x => x.key)
window.addEventListener('keydown', this.keyPressed)
},
async mounted () {
@ -351,6 +389,12 @@ export default Vue.extend({
this.loadFromCookie(cookieFit, (v) => {
this.scale = v
})
this.loadFromCookie(cookieContinuousReaderFit, (v) => {
this.continuousScale = v
})
this.loadFromCookie(cookieContinuousReaderPadding, (v) => {
this.sidePadding = parseInt(v)
})
this.loadFromCookie(cookieBackground, (v) => {
this.backgroundColor = v
})
@ -390,6 +434,12 @@ export default Vue.extend({
continuousReader (): boolean {
return this.readingDirection === ReadingDirection.WEBTOON
},
fullWidthReader (): boolean {
if (this.continuousReader) {
return this.continuousScale === ContinuousScaleType.WIDTH
}
return this.scale === ScaleType.WIDTH
},
progress (): number {
return this.page / this.pagesCount * 100
},
@ -417,9 +467,15 @@ export default Vue.extend({
default:
nav.push(...shortcutsAll)
}
let settings = [...shortcutsSettings]
if (this.continuousReader) {
settings.push(...shortcutsSettingsContinuous)
} else {
settings.push(...shortcutsSettingsPaged)
}
return {
'Reader Navigation': nav,
'Settings': shortcutsSettings,
'Settings': settings,
'Menus': shortcutsMenus,
}
},
@ -444,6 +500,28 @@ export default Vue.extend({
}
},
},
continuousScale: {
get: function (): ContinuousScaleType {
return this.settings.continuousScale
},
set: function (scale: ContinuousScaleType): void {
if (Object.values(ContinuousScaleType).includes(scale)) {
this.settings.continuousScale = scale
this.$cookies.set(cookieContinuousReaderFit, scale, Infinity)
}
},
},
sidePadding: {
get: function (): number {
return this.settings.sidePadding
},
set: function (padding: number): void {
if (PaddingPercentage.includes(padding)) {
this.settings.sidePadding = padding
this.$cookies.set(cookieContinuousReaderPadding, padding, Infinity)
}
},
},
backgroundColor: {
get: function (): string {
return this.settings.backgroundColor
@ -590,12 +668,27 @@ export default Vue.extend({
this.sendNotification(`Changing Reading Direction to: ${text}`)
},
cycleScale () {
if (this.continuousReader) return
const enumValues = Object.values(ScaleType)
const i = (enumValues.indexOf(this.settings.scale) + 1) % (enumValues.length)
this.scale = enumValues[i]
const text = ScaleTypeText[this.scale]
this.sendNotification(`Cycling Scale: ${text}`)
if (this.continuousReader) {
const enumValues = Object.values(ContinuousScaleType)
const i = (enumValues.indexOf(this.settings.continuousScale) + 1) % (enumValues.length)
this.continuousScale = enumValues[i]
const text = ScaleTypeText[this.continuousScale]
this.sendNotification(`Cycling Scale: ${text}`)
} else {
const enumValues = Object.values(ScaleType)
const i = (enumValues.indexOf(this.settings.scale) + 1) % (enumValues.length)
this.scale = enumValues[i]
const text = ScaleTypeText[this.scale]
this.sendNotification(`Cycling Scale: ${text}`)
}
},
cycleSidePadding () {
if (this.continuousReader) {
const i = (PaddingPercentage.indexOf(this.settings.sidePadding) + 1) % (PaddingPercentage.length)
this.sidePadding = PaddingPercentage[i]
const text = this.sidePadding === 0 ? 'None' : `${this.sidePadding}%`
this.sendNotification(`Cycling Side Padding: ${text}`)
}
},
toggleDoublePages () {
if (this.continuousReader) return