mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-07-25 21:24:42 +02:00
Add:Progress for comics #738
This commit is contained in:
parent
c8b5cefeb5
commit
543ac209e4
7 changed files with 236 additions and 51 deletions
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<modals-modal v-model="show" :width="300" height="100%">
|
||||
<modals-modal v-model="show" :width="width" height="100%">
|
||||
<template #outer>
|
||||
<div v-if="title" class="absolute top-8 left-4 z-40" style="max-width: 80%">
|
||||
<p class="text-white text-xl truncate">{{ title }}</p>
|
||||
|
@ -9,9 +9,9 @@
|
|||
<div class="w-full h-full overflow-hidden absolute top-0 left-0 flex items-center justify-center" @click="show = false">
|
||||
<div ref="container" class="w-full overflow-x-hidden overflow-y-auto bg-primary rounded-lg border border-white border-opacity-20 p-2" style="max-height: 75%" @click.stop>
|
||||
<ul class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
|
||||
<template v-for="item in items">
|
||||
<template v-for="item in itemsToShow">
|
||||
<slot :name="item.value" :item="item" :selected="item.value === selected">
|
||||
<li :key="item.value" class="text-gray-50 select-none relative py-4 cursor-pointer hover:bg-black-400" :class="selected === item.value ? 'bg-success bg-opacity-10' : ''" role="option" @click="clickedOption(item.value)">
|
||||
<li :key="item.value" :ref="`item-${item.value}`" class="text-gray-50 select-none relative cursor-pointer hover:bg-black-400" :class="selected === item.value ? 'bg-success bg-opacity-10' : ''" :style="{ paddingTop: itemPaddingY, paddingBottom: itemPaddingY }" role="option" @click="clickedOption(item.value)">
|
||||
<div class="relative flex items-center px-3">
|
||||
<span v-if="item.icon" class="material-icons-outlined text-xl mr-2 text-white text-opacity-80">{{ item.icon }}</span>
|
||||
<p class="font-normal block truncate text-base text-white text-opacity-80">{{ item.text }}</p>
|
||||
|
@ -34,11 +34,27 @@ export default {
|
|||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
selected: String // optional
|
||||
selected: [String, Number], // optional
|
||||
itemPaddingY: {
|
||||
type: String,
|
||||
default: '16px'
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 300
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
show: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (newVal) this.$nextTick(this.init)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
show: {
|
||||
get() {
|
||||
|
@ -47,11 +63,32 @@ export default {
|
|||
set(val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
},
|
||||
itemsToShow() {
|
||||
return this.items.map((i) => {
|
||||
if (typeof i === 'string') {
|
||||
return {
|
||||
text: i,
|
||||
value: i
|
||||
}
|
||||
}
|
||||
return i
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickedOption(action) {
|
||||
this.$emit('action', action)
|
||||
},
|
||||
init() {
|
||||
if (this.selected && this.$refs[`item-${this.selected}`]?.[0]) {
|
||||
// Set scroll position so that selected item is in the center
|
||||
const containerOffset = this.$refs.container.offsetTop + this.$refs.container.clientHeight / 2
|
||||
const scrollAmount = this.$refs[`item-${this.selected}`][0].offsetTop - containerOffset
|
||||
this.$refs.container.scrollTo({
|
||||
top: scrollAmount
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
<template>
|
||||
<div id="comic-reader" class="w-full h-full relative">
|
||||
<div v-show="showPageMenu" v-click-outside="clickOutsideObj" class="pagemenu absolute top-12 right-16 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-52">
|
||||
<div v-for="(file, index) in pages" :key="file" class="w-full cursor-pointer hover:bg-black-200 px-2 py-1" :class="page === index ? 'bg-black-200' : ''" @click.stop="setPage(index)">
|
||||
<p class="text-sm truncate">{{ file }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showInfoMenu" v-click-outside="clickedOutsideInfoMenu" class="pagemenu absolute top-12 right-0 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-full" @click.stop.prevent>
|
||||
<div v-show="showInfoMenu" v-click-outside="clickedOutside" class="pagemenu absolute top-8 left-0 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-full" @click.stop.prevent>
|
||||
<div v-for="key in comicMetadataKeys" :key="key" class="w-full px-2 py-1">
|
||||
<p class="text-xs">
|
||||
<strong>{{ key }}</strong>
|
||||
|
@ -14,14 +9,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="comicMetadata" class="absolute top-0 right-3 bg-bg text-gray-100 border-b border-l border-r border-gray-400 hover:bg-black-200 cursor-pointer rounded-b-md w-10 h-9 flex items-center justify-center text-center z-20" @mousedown.prevent @click.stop.prevent="clickShowInfoMenu">
|
||||
<span class="material-icons text-lg">more</span>
|
||||
<div v-if="comicMetadata" id="btn-metadata" class="absolute top-0 left-14 bg-bg text-gray-100 border-b border-l border-r border-gray-400 hover:bg-black-200 cursor-pointer rounded-b-md w-8 h-7 flex items-center justify-center text-center z-20" @mousedown.prevent @click.stop.prevent="clickShowInfoMenu">
|
||||
<span class="material-icons text-base pointer-events-none">more</span>
|
||||
</div>
|
||||
<div class="absolute top-0 right-16 bg-bg text-gray-100 border-b border-l border-r border-gray-400 hover:bg-black-200 cursor-pointer rounded-b-md w-10 h-9 flex items-center justify-center text-center z-20" @mousedown.prevent @mouseup.prevent @click.stop.prevent="clickShowPageMenu">
|
||||
<span class="material-icons text-lg">menu</span>
|
||||
<div v-if="numPages" id="btn-pages" class="absolute top-0 left-3 bg-bg text-gray-100 border-b border-l border-r border-gray-400 hover:bg-black-200 cursor-pointer rounded-b-md w-8 h-7 flex items-center justify-center text-center z-20" @mousedown.prevent @mouseup.prevent @click.stop.prevent="clickShowPageMenu">
|
||||
<span class="material-icons text-base pointer-events-none">menu</span>
|
||||
</div>
|
||||
<div class="absolute top-0 left-3 bg-bg text-gray-100 border-b border-l border-r border-gray-400 rounded-b-md px-2 h-9 flex items-center text-center z-20" @click.stop>
|
||||
<p class="font-mono">{{ page + 1 }} / {{ numPages }}</p>
|
||||
<div v-if="numPages" class="absolute top-0 right-3 bg-bg text-gray-100 border-b border-l border-r border-gray-400 rounded-b-md px-2 h-7 flex items-center text-center z-20" @click.stop>
|
||||
<p class="text-sm">{{ page }} / {{ numPages }}</p>
|
||||
</div>
|
||||
|
||||
<div class="overflow-hidden m-auto comicwrapper relative">
|
||||
|
@ -33,6 +28,8 @@
|
|||
<ui-loading-indicator />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<modals-dialog v-model="showPageMenu" :items="pageItems" :selected="page" :width="360" item-padding-y="8px" @action="setPage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -51,7 +48,9 @@ export default {
|
|||
libraryItem: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
isLocal: Boolean,
|
||||
keepProgress: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -66,11 +65,7 @@ export default {
|
|||
loadTimeout: null,
|
||||
loadedFirstPage: false,
|
||||
comicMetadata: null,
|
||||
clickOutsideObj: {
|
||||
handler: this.clickedOutside,
|
||||
events: ['mousedown'],
|
||||
isActive: true
|
||||
}
|
||||
pageMenuWidth: 256
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -85,17 +80,112 @@ export default {
|
|||
userToken() {
|
||||
return this.$store.getters['user/getToken']
|
||||
},
|
||||
libraryItemId() {
|
||||
return this.libraryItem?.id
|
||||
},
|
||||
localLibraryItem() {
|
||||
if (this.isLocal) return this.libraryItem
|
||||
return this.libraryItem.localLibraryItem || null
|
||||
},
|
||||
localLibraryItemId() {
|
||||
return this.localLibraryItem?.id
|
||||
},
|
||||
serverLibraryItemId() {
|
||||
if (!this.isLocal) return this.libraryItem.id
|
||||
// Check if local library item is connected to the current server
|
||||
if (!this.libraryItem.serverAddress || !this.libraryItem.libraryItemId) return null
|
||||
if (this.$store.getters['user/getServerAddress'] === this.libraryItem.serverAddress) {
|
||||
return this.libraryItem.libraryItemId
|
||||
}
|
||||
return null
|
||||
},
|
||||
comicMetadataKeys() {
|
||||
return this.comicMetadata ? Object.keys(this.comicMetadata) : []
|
||||
},
|
||||
canGoNext() {
|
||||
return this.page < this.numPages - 1
|
||||
return this.page < this.numPages
|
||||
},
|
||||
canGoPrev() {
|
||||
return this.page > 0
|
||||
return this.page > 1
|
||||
},
|
||||
userItemProgress() {
|
||||
if (this.isLocal) return this.localItemProgress
|
||||
return this.serverItemProgress
|
||||
},
|
||||
localItemProgress() {
|
||||
return this.$store.getters['globals/getLocalMediaProgressById'](this.localLibraryItemId)
|
||||
},
|
||||
serverItemProgress() {
|
||||
return this.$store.getters['user/getUserMediaProgress'](this.serverLibraryItemId)
|
||||
},
|
||||
savedPage() {
|
||||
if (!this.keepProgress) return 0
|
||||
|
||||
// Validate ebookLocation is a number
|
||||
if (!this.userItemProgress?.ebookLocation || isNaN(this.userItemProgress.ebookLocation)) return 0
|
||||
return Number(this.userItemProgress.ebookLocation)
|
||||
},
|
||||
selectedCleanedPage() {
|
||||
return this.cleanedPageNames[this.page - 1]
|
||||
},
|
||||
cleanedPageNames() {
|
||||
return (
|
||||
this.pages?.map((p) => {
|
||||
if (p.length > 40) {
|
||||
let firstHalf = p.slice(0, 18)
|
||||
let lastHalf = p.slice(p.length - 17)
|
||||
return `${firstHalf} ... ${lastHalf}`
|
||||
}
|
||||
return p
|
||||
}) || []
|
||||
)
|
||||
},
|
||||
pageItems() {
|
||||
let index = 1
|
||||
return this.cleanedPageNames.map((p) => {
|
||||
return {
|
||||
text: p,
|
||||
value: index++
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async updateProgress() {
|
||||
if (!this.keepProgress) return
|
||||
|
||||
if (!this.numPages) {
|
||||
console.error('Num pages not loaded')
|
||||
return
|
||||
}
|
||||
if (this.savedPage === this.page) {
|
||||
return
|
||||
}
|
||||
|
||||
const payload = {
|
||||
ebookLocation: String(this.page),
|
||||
ebookProgress: Math.max(0, Math.min(1, (Number(this.page) - 1) / Number(this.numPages)))
|
||||
}
|
||||
|
||||
// Update local item
|
||||
if (this.localLibraryItemId) {
|
||||
const localPayload = {
|
||||
localLibraryItemId: this.localLibraryItemId,
|
||||
...payload
|
||||
}
|
||||
const localResponse = await this.$db.updateLocalEbookProgress(localPayload)
|
||||
if (localResponse.localMediaProgress) {
|
||||
this.$store.commit('globals/updateLocalMediaProgress', localResponse.localMediaProgress)
|
||||
}
|
||||
}
|
||||
|
||||
// Update server item
|
||||
if (this.serverLibraryItemId) {
|
||||
this.$axios.$patch(`/api/me/progress/${this.serverLibraryItemId}`, payload).catch((error) => {
|
||||
console.error('ComicReader.updateProgress failed:', error)
|
||||
})
|
||||
}
|
||||
},
|
||||
clickShowInfoMenu() {
|
||||
this.showInfoMenu = !this.showInfoMenu
|
||||
this.showPageMenu = false
|
||||
|
@ -104,11 +194,10 @@ export default {
|
|||
this.showPageMenu = !this.showPageMenu
|
||||
this.showInfoMenu = false
|
||||
},
|
||||
clickedOutside() {
|
||||
this.showPageMenu = false
|
||||
},
|
||||
clickedOutsideInfoMenu() {
|
||||
this.showInfoMenu = false
|
||||
clickedOutside(e) {
|
||||
if (e.target?.id == 'btn-metadata') return
|
||||
|
||||
if (this.showInfoMenu) this.showInfoMenu = false
|
||||
},
|
||||
next() {
|
||||
if (!this.canGoNext) return
|
||||
|
@ -118,13 +207,15 @@ export default {
|
|||
if (!this.canGoPrev) return
|
||||
this.setPage(this.page - 1)
|
||||
},
|
||||
setPage(index) {
|
||||
if (index < 0 || index > this.numPages - 1) {
|
||||
setPage(page) {
|
||||
if (page <= 0 || page > this.numPages) {
|
||||
return
|
||||
}
|
||||
this.showPageMenu = false
|
||||
const filename = this.pages[index]
|
||||
this.page = index
|
||||
const filename = this.pages[page - 1]
|
||||
this.page = page
|
||||
|
||||
this.updateProgress()
|
||||
return this.extractFile(filename)
|
||||
},
|
||||
setLoadTimeout() {
|
||||
|
@ -154,7 +245,6 @@ export default {
|
|||
},
|
||||
async extract() {
|
||||
this.loading = true
|
||||
console.log('Extracting', this.url)
|
||||
|
||||
var buff = await this.$axios.$get(this.url, {
|
||||
responseType: 'blob',
|
||||
|
@ -176,9 +266,28 @@ export default {
|
|||
|
||||
this.numPages = this.pages.length
|
||||
|
||||
// Calculate page menu size
|
||||
const largestFilename = this.cleanedPageNames
|
||||
.map((p) => p)
|
||||
.sort((a, b) => a.length - b.length)
|
||||
.pop()
|
||||
const pEl = document.createElement('p')
|
||||
pEl.innerText = largestFilename
|
||||
pEl.style.fontSize = '0.875rem'
|
||||
pEl.style.opacity = 0
|
||||
pEl.style.position = 'absolute'
|
||||
document.body.appendChild(pEl)
|
||||
const textWidth = pEl.getBoundingClientRect()?.width
|
||||
if (textWidth) {
|
||||
this.pageMenuWidth = textWidth + (16 + 5 + 2 + 5)
|
||||
}
|
||||
pEl.remove()
|
||||
|
||||
if (this.pages.length) {
|
||||
this.loading = false
|
||||
await this.setPage(0)
|
||||
|
||||
const startPage = this.savedPage > 0 && this.savedPage <= this.numPages ? this.savedPage : 1
|
||||
await this.setPage(startPage)
|
||||
this.loadedFirstPage = true
|
||||
} else {
|
||||
this.$toast.error('Unable to extract pages')
|
||||
|
@ -206,7 +315,6 @@ export default {
|
|||
return flattenObject(filesObject)
|
||||
},
|
||||
async extractXmlFile(filename) {
|
||||
console.log('extracting xml filename', filename)
|
||||
try {
|
||||
var file = await this.filesObject[filename].extract()
|
||||
var reader = new FileReader()
|
||||
|
@ -272,7 +380,7 @@ export default {
|
|||
}
|
||||
|
||||
.pagemenu {
|
||||
max-height: calc(100% - 80px);
|
||||
max-height: calc(100% - 20px);
|
||||
}
|
||||
.comicimg {
|
||||
height: 100%;
|
||||
|
|
|
@ -21,7 +21,8 @@ export default {
|
|||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
isLocal: Boolean
|
||||
isLocal: Boolean,
|
||||
keepProgress: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -83,6 +84,13 @@ export default {
|
|||
},
|
||||
localStorageLocationsKey() {
|
||||
return `ebookLocations-${this.libraryItemId}`
|
||||
},
|
||||
savedEbookLocation() {
|
||||
if (!this.keepProgress) return null
|
||||
if (!this.userItemProgress?.ebookLocation) return null
|
||||
// Validate ebookLocation is an epubcfi
|
||||
if (!String(this.userItemProgress.ebookLocation).startsWith('epubcfi')) return null
|
||||
return this.userItemProgress.ebookLocation
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -107,6 +115,8 @@ export default {
|
|||
* @param {string} payload.ebookProgress - eBook Progress Percentage
|
||||
*/
|
||||
async updateProgress(payload) {
|
||||
if (!this.keepProgress) return
|
||||
|
||||
// Update local item
|
||||
if (this.localLibraryItemId) {
|
||||
const localPayload = {
|
||||
|
@ -213,7 +223,7 @@ export default {
|
|||
},
|
||||
/** @param {string} location - CFI of the new location */
|
||||
relocated(location) {
|
||||
if (this.userItemProgress?.ebookLocation === location.start.cfi) {
|
||||
if (this.savedEbookLocation === location.start.cfi) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -255,10 +265,10 @@ export default {
|
|||
})
|
||||
|
||||
// load saved progress
|
||||
reader.rendition.display(this.userItemProgress?.ebookLocation || reader.book.locations.start)
|
||||
reader.rendition.display(this.savedEbookLocation || reader.book.locations.start)
|
||||
|
||||
// load style
|
||||
reader.rendition.themes.default({ '*': { color: '#fff!important', 'background-color': 'rgb(35 35 35)!important' } })
|
||||
reader.rendition.themes.default({ '*': { color: '#fff!important', 'background-color': 'rgb(35 35 35)!important' }, a: { color: '#fff!important' } })
|
||||
|
||||
reader.book.ready.then(() => {
|
||||
// set up event listeners
|
||||
|
|
|
@ -39,7 +39,8 @@ export default {
|
|||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
isLocal: Boolean
|
||||
isLocal: Boolean,
|
||||
keepProgress: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -92,7 +93,11 @@ export default {
|
|||
return this.$store.getters['user/getUserMediaProgress'](this.serverLibraryItemId)
|
||||
},
|
||||
savedPage() {
|
||||
return Number(this.userItemProgress?.ebookLocation || 0)
|
||||
if (!this.keepProgress) return 0
|
||||
|
||||
// Validate ebookLocation is a number
|
||||
if (!this.userItemProgress?.ebookLocation || isNaN(this.userItemProgress.ebookLocation)) return 0
|
||||
return Number(this.userItemProgress.ebookLocation)
|
||||
},
|
||||
pdfDocInitParams() {
|
||||
return {
|
||||
|
@ -105,10 +110,13 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
async updateProgress() {
|
||||
if (!this.keepProgress) return
|
||||
|
||||
if (!this.numPages) {
|
||||
console.error('Num pages not loaded')
|
||||
return
|
||||
}
|
||||
|
||||
const payload = {
|
||||
ebookLocation: String(this.page),
|
||||
ebookProgress: Math.max(0, Math.min(1, (Number(this.page) - 1) / Number(this.numPages)))
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="flex-grow" />
|
||||
<span class="material-icons text-xl text-white" @click.stop="show = false">close</span>
|
||||
</div>
|
||||
<component v-if="readerComponentName" ref="readerComponent" :is="readerComponentName" :url="ebookUrl" :library-item="selectedLibraryItem" :is-local="isLocal" />
|
||||
<component v-if="readerComponentName" ref="readerComponent" :is="readerComponentName" :url="ebookUrl" :library-item="selectedLibraryItem" :is-local="isLocal" :keep-progress="keepProgress" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -62,10 +62,19 @@ export default {
|
|||
return null
|
||||
},
|
||||
ebookFile() {
|
||||
return this.media?.ebookFile || null
|
||||
// ebook file id is passed when reading a supplementary ebook
|
||||
if (this.ebookFileId) {
|
||||
return this.selectedLibraryItem.libraryFiles.find((lf) => lf.ino === this.ebookFileId)
|
||||
}
|
||||
return this.media.ebookFile
|
||||
},
|
||||
ebookFormat() {
|
||||
return this.ebookFile?.ebookFormat || null
|
||||
if (!this.ebookFile) return null
|
||||
// Use file extension for supplementary ebook
|
||||
if (!this.ebookFile.ebookFormat) {
|
||||
return this.ebookFile.metadata.ext.toLowerCase().slice(1)
|
||||
}
|
||||
return this.ebookFile.ebookFormat
|
||||
},
|
||||
ebookType() {
|
||||
if (this.isMobi) return 'mobi'
|
||||
|
@ -98,10 +107,20 @@ export default {
|
|||
return Capacitor.convertFileSrc(this.localContentUrl)
|
||||
}
|
||||
const serverAddress = this.$store.getters['user/getServerAddress']
|
||||
|
||||
if (this.ebookFileId) {
|
||||
return `${serverAddress}/api/items/${this.selectedLibraryItem.id}/ebook/${this.ebookFileId}`
|
||||
}
|
||||
return `${serverAddress}/api/items/${this.selectedLibraryItem.id}/ebook`
|
||||
},
|
||||
playerLibraryItemId() {
|
||||
return this.$store.state.playerLibraryItemId
|
||||
},
|
||||
keepProgress() {
|
||||
return this.$store.state.ereaderKeepProgress
|
||||
},
|
||||
ebookFileId() {
|
||||
return this.$store.state.ereaderFileId
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -130,11 +149,9 @@ export default {
|
|||
}
|
||||
|
||||
if (this.touchendX < this.touchstartX) {
|
||||
console.log('swiped left')
|
||||
this.next()
|
||||
}
|
||||
if (this.touchendX > this.touchstartX) {
|
||||
console.log('swiped right')
|
||||
this.prev()
|
||||
}
|
||||
},
|
||||
|
|
|
@ -483,9 +483,9 @@ export default {
|
|||
readBook() {
|
||||
if (this.localLibraryItem?.media?.ebookFile) {
|
||||
// Has local ebook file
|
||||
this.$store.commit('openReader', this.localLibraryItem)
|
||||
this.$store.commit('showReader', { libraryItem: this.localLibraryItem, keepProgress: true })
|
||||
} else {
|
||||
this.$store.commit('openReader', this.libraryItem)
|
||||
this.$store.commit('showReader', { libraryItem: this.libraryItem, keepProgress: true })
|
||||
}
|
||||
},
|
||||
playAtTimestamp(seconds) {
|
||||
|
|
|
@ -20,6 +20,8 @@ export const state = () => ({
|
|||
hasStoragePermission: false,
|
||||
selectedLibraryItem: null,
|
||||
showReader: false,
|
||||
ereaderKeepProgress: false,
|
||||
ereaderFileId: null,
|
||||
showSideDrawer: false,
|
||||
isNetworkListenerInit: false,
|
||||
serverSettings: null,
|
||||
|
@ -145,8 +147,11 @@ export const mutations = {
|
|||
setIsNetworkUnmetered(state, val) {
|
||||
state.isNetworkUnmetered = val
|
||||
},
|
||||
openReader(state, libraryItem) {
|
||||
showReader(state, { libraryItem, keepProgress, fileId }) {
|
||||
state.selectedLibraryItem = libraryItem
|
||||
state.ereaderKeepProgress = keepProgress
|
||||
state.ereaderFileId = fileId
|
||||
|
||||
state.showReader = true
|
||||
},
|
||||
setShowReader(state, val) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue