Add:Experimental collapse series for library option #322

This commit is contained in:
advplyr 2022-01-24 18:03:54 -06:00
parent 5bd6c8f553
commit d8cc0b57a5
8 changed files with 96 additions and 50 deletions

View File

@ -142,14 +142,6 @@ export default {
this.$eventBus.$emit('bookshelf-clear-selection')
this.isAllSelected = false
},
// toggleSelectAll() {
// if (this.isAllSelected) {
// this.cancelSelectionMode()
// } else {
// this.$eventBus.$emit('bookshelf-select-all')
// this.isAllSelected = true
// }
// },
toggleBatchRead() {
this.$store.commit('setProcessingBatch', true)
var newIsRead = !this.selectedIsRead

View File

@ -29,6 +29,7 @@
<div class="flex-grow hidden md:inline-block" />
<!-- <ui-text-input v-show="showSortFilters" v-model="keywordFilter" @input="keywordFilterInput" placeholder="Keyword Filter" :padding-y="1.5" clearable class="text-xs w-40 hidden md:block" /> -->
<ui-checkbox v-if="showExperimentalFeatures" v-model="settings.collapseSeries" label="Collapse Series" checkbox-bg="bg" check-color="white" small class="mr-2" @input="updateCollapseSeries" />
<controls-filter-select v-show="showSortFilters" v-model="settings.filterBy" class="w-48 h-7.5 ml-4" @change="updateFilter" />
<controls-order-select v-show="showSortFilters" v-model="settings.orderBy" :descending.sync="settings.orderDesc" class="w-48 h-7.5 ml-4" @change="updateOrder" />
<!-- <div v-show="showSortFilters" class="h-7 ml-4 flex border border-white border-opacity-25 rounded-md">
@ -72,6 +73,9 @@ export default {
}
},
computed: {
showExperimentalFeatures() {
return this.$store.state.showExperimentalFeatures
},
isGridMode() {
return this.viewMode === 'grid'
},
@ -87,14 +91,6 @@ export default {
if (this.page === 'collections') return 'Collections'
return ''
},
// _keywordFilter: {
// get() {
// return this.$store.state.audiobooks.keywordFilter
// },
// set(val) {
// this.$store.commit('audiobooks/setKeywordFilter', val)
// }
// },
paramId() {
return this.$route.params ? this.$route.params.id || '' : ''
},
@ -124,6 +120,9 @@ export default {
updateFilter() {
this.saveSettings()
},
updateCollapseSeries() {
this.saveSettings()
},
saveSettings() {
this.$store.dispatch('user/updateUserSettings', this.settings)
},

View File

@ -105,6 +105,9 @@ export default {
filterBy() {
return this.$store.getters['user/getUserSetting']('filterBy')
},
collapseSeries() {
return this.$store.getters['user/getUserSetting']('collapseSeries')
},
coverAspectRatio() {
return this.$store.getters['getServerSetting']('coverAspectRatio')
},
@ -207,19 +210,6 @@ export default {
this.isSelectionMode = false
this.isSelectAll = false
},
selectAllEntities() {
this.isSelectAll = true
if (this.entityName === 'books' || this.entityName === 'series-books') {
var allAvailableEntityIds = this.entities.map((ent) => ent.id).filter((ent) => !!ent)
this.$store.commit('setSelectedAudiobooks', allAvailableEntityIds)
}
for (const key in this.entityComponentRefs) {
if (this.entityIndexesMounted.includes(Number(key))) {
this.entityComponentRefs[key].selected = true
}
}
},
selectEntity(entity) {
if (this.entityName === 'books' || this.entityName === 'series-books') {
this.$store.commit('toggleAudiobookSelected', entity.id)
@ -255,6 +245,7 @@ export default {
console.error('failed to fetch books', error)
return null
})
console.log('payload', payload)
this.isFetchingEntities = false
if (this.pendingReset) {
this.pendingReset = false
@ -392,6 +383,9 @@ export default {
searchParams.set('sort', this.orderBy)
searchParams.set('desc', this.orderDesc ? 1 : 0)
}
if (this.collapseSeries) {
searchParams.set('collapseseries', 1)
}
}
return searchParams.toString()
},
@ -524,7 +518,6 @@ export default {
})
this.$eventBus.$on('bookshelf-clear-selection', this.clearSelectedEntities)
this.$eventBus.$on('bookshelf-select-all', this.selectAllEntities)
this.$eventBus.$on('socket_init', this.socketInit)
this.$store.commit('user/addSettingsListener', { id: 'lazy-bookshelf', meth: this.settingsUpdated })
@ -546,7 +539,6 @@ export default {
bookshelf.removeEventListener('scroll', this.scroll)
}
this.$eventBus.$off('bookshelf-clear-selection', this.clearSelectedEntities)
this.$eventBus.$off('bookshelf-select-all', this.selectAllEntities)
this.$eventBus.$off('socket_init', this.socketInit)
this.$store.commit('user/removeSettingsListener', 'lazy-bookshelf')

View File

@ -12,6 +12,8 @@
<p class="truncate text-gray-400" :style="{ fontSize: 0.8 * sizeMultiplier + 'rem' }">{{ authorFL }}</p>
</div>
<div v-if="booksInSeries" class="absolute z-20 top-1.5 right-1.5 rounded-md leading-3 text-sm p-1 font-semibold text-white flex items-center justify-center" style="background-color: #cd9d49dd">{{ booksInSeries }}</div>
<div class="w-full h-full absolute top-0 left-0 rounded overflow-hidden z-10">
<div v-show="audiobook && !imageReady" class="absolute top-0 left-0 w-full h-full flex items-center justify-center" :style="{ padding: sizeMultiplier * 0.5 + 'rem' }">
<p :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }" class="font-book text-gray-300 text-center">{{ title }}</p>
@ -113,6 +115,9 @@ export default {
_audiobook() {
return this.audiobook || {}
},
book() {
return this._audiobook.book || {}
},
placeholderUrl() {
return '/book_placeholder.jpg'
},
@ -122,6 +127,12 @@ export default {
audiobookId() {
return this._audiobook.id
},
series() {
return this.book.series
},
libraryId() {
return this._audiobook.libraryId
},
hasEbook() {
return this._audiobook.numEbooks
},
@ -131,8 +142,9 @@ export default {
processingBatch() {
return this.store.state.processingBatch
},
book() {
return this._audiobook.book || {}
booksInSeries() {
// Only added to audiobook object when collapseSeries is enabled
return this._audiobook.booksInSeries
},
hasCover() {
return !!this.book.cover
@ -321,7 +333,10 @@ export default {
this.selectBtnClick()
} else {
var router = this.$router || this.$nuxt.$router
if (router) router.push(`/audiobook/${this.audiobookId}`)
if (router) {
if (this.booksInSeries) router.push(`/library/${this.libraryId}/series/${this.$encode(this.series)}`)
else router.push(`/audiobook/${this.audiobookId}`)
}
}
},
editClick() {

View File

@ -1,10 +1,10 @@
<template>
<label class="flex justify-start items-start">
<div class="bg-white border-2 rounded border-gray-400 flex flex-shrink-0 justify-center items-center focus-within:border-blue-500" :class="wrapperClass">
<input v-model="selected" type="checkbox" class="opacity-0 absolute" />
<svg v-if="selected" class="fill-current text-green-500 pointer-events-none" :class="svgClass" viewBox="0 0 20 20"><path d="M0 11l2-2 5 5L18 3l2 2L7 18z" /></svg>
<label class="flex justify-start items-center cursor-pointer">
<div class="border-2 rounded border-gray-400 flex flex-shrink-0 justify-center items-center" :class="wrapperClass">
<input v-model="selected" type="checkbox" class="opacity-0 absolute cursor-pointer" />
<svg v-if="selected" class="fill-current pointer-events-none" :class="svgClass" viewBox="0 0 20 20"><path d="M0 11l2-2 5 5L18 3l2 2L7 18z" /></svg>
</div>
<div v-if="label" class="select-none">{{ label }}</div>
<div v-if="label" class="select-none pl-1 text-gray-100" :class="labelClass">{{ label }}</div>
</label>
</template>
@ -12,8 +12,16 @@
export default {
props: {
value: Boolean,
label: Boolean,
small: Boolean
label: String,
small: Boolean,
checkboxBg: {
type: String,
default: 'white'
},
checkColor: {
type: String,
default: 'green-500'
}
},
data() {
return {}
@ -28,12 +36,22 @@ export default {
}
},
wrapperClass() {
if (this.small) return 'w-4 h-4'
return 'w-6 h-6'
var classes = [`bg-${this.checkboxBg}`]
if (this.small) classes.push('w-4 h-4')
else classes.push('w-6 h-6')
return classes.join(' ')
},
labelClass() {
if (this.small) return 'text-sm'
return ''
},
svgClass() {
if (this.small) return 'w-3 h-3'
return 'w-4 h-4'
var classes = [`text-${this.checkColor}`]
if (this.small) classes.push('w-3 h-3')
else classes.push('w-4 h-4')
return classes.join(' ')
}
},
methods: {},

View File

@ -8,7 +8,8 @@ export const state = () => ({
orderDesc: false,
filterBy: 'all',
playbackRate: 1,
bookshelfCoverSize: 120
bookshelfCoverSize: 120,
collapseSeries: false
},
settingsListeners: [],
collections: [],

View File

@ -98,7 +98,6 @@ class LibraryController {
audiobooks = libraryHelpers.getFiltered(audiobooks, req.query.filter, req.user)
}
if (req.query.sort) {
var orderByNumber = req.query.sort === 'book.volumeNumber'
var direction = req.query.desc === '1' ? 'desc' : 'asc'
@ -120,6 +119,7 @@ class LibraryController {
}
// api/libraries/:id/books/all
// TODO: Optimize this method, audiobooks are iterated through several times but can be combined
getBooksForLibrary2(req, res) {
var libraryId = req.library.id
@ -132,7 +132,8 @@ class LibraryController {
sortBy: req.query.sort,
sortDesc: req.query.desc === '1',
filterBy: req.query.filter,
minified: req.query.minified === '1'
minified: req.query.minified === '1',
collapseseries: req.query.collapseseries === '1'
}
if (payload.filterBy) {
@ -148,11 +149,38 @@ class LibraryController {
})
}
if (payload.collapseseries) {
var series = {}
// Group abs by series
for (let i = 0; i < audiobooks.length; i++) {
var ab = audiobooks[i]
if (ab.book.series) {
if (!series[ab.book.series]) series[ab.book.series] = []
series[ab.book.series].push(ab)
}
}
// Sort series by volume number and filter out all but the first book in series
var seriesBooksToKeep = Object.values(series).map((_series) => {
var sorted = naturalSort(_series).asc(_ab => _ab.book.volumeNumber)
return sorted[0].id
})
// Add "booksInSeries" field to audiobook payload
audiobooks = audiobooks.filter(ab => !ab.book.series || seriesBooksToKeep.includes(ab.id)).map(ab => {
var abJson = payload.minified ? ab.toJSONMinified() : ab.toJSONExpanded()
if (ab.book.series) abJson.booksInSeries = series[ab.book.series].length
return abJson
})
payload.total = audiobooks.length
} else {
audiobooks = audiobooks.map(ab => payload.minified ? ab.toJSONMinified() : ab.toJSONExpanded())
}
if (payload.limit) {
var startIndex = payload.page * payload.limit
audiobooks = audiobooks.slice(startIndex, startIndex + payload.limit)
}
payload.results = audiobooks.map(ab => payload.minified ? ab.toJSONMinified() : ab.toJSONExpanded())
payload.results = audiobooks
res.json(payload)
}

View File

@ -55,7 +55,8 @@ class User {
orderDesc: false,
filterBy: 'all',
playbackRate: 1,
bookshelfCoverSize: 120
bookshelfCoverSize: 120,
collapseSeries: false
}
}