mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-12-20 19:06:06 +01:00
Add:Support for shift selecting multiple library items #1020
This commit is contained in:
parent
4cf43bc105
commit
77139c7256
@ -16,10 +16,10 @@
|
||||
<!-- Alternate plain view -->
|
||||
<div v-else-if="isAlternativeBookshelfView" class="w-full mb-24">
|
||||
<template v-for="(shelf, index) in shelves">
|
||||
<widgets-item-slider v-if="shelf.type === 'book' || shelf.type === 'podcast'" :key="index + '.'" :items="shelf.entities" :continue-listening-shelf="shelf.id === 'continue-listening'" :height="232 * sizeMultiplier" class="bookshelf-row pl-8 my-6">
|
||||
<widgets-item-slider v-if="shelf.type === 'book' || shelf.type === 'podcast'" :key="index + '.'" :items="shelf.entities" :continue-listening-shelf="shelf.id === 'continue-listening'" :height="232 * sizeMultiplier" class="bookshelf-row pl-8 my-6" @selectEntity="(payload) => selectEntity(payload, index)">
|
||||
<p class="font-semibold text-gray-100" :style="{ fontSize: sizeMultiplier + 'rem' }">{{ shelf.label }}</p>
|
||||
</widgets-item-slider>
|
||||
<widgets-episode-slider v-else-if="shelf.type === 'episode'" :key="index + '.'" :items="shelf.entities" :continue-listening-shelf="shelf.id === 'continue-listening'" :height="232 * sizeMultiplier" class="bookshelf-row pl-8 my-6">
|
||||
<widgets-episode-slider v-else-if="shelf.type === 'episode'" :key="index + '.'" :items="shelf.entities" :continue-listening-shelf="shelf.id === 'continue-listening'" :height="232 * sizeMultiplier" class="bookshelf-row pl-8 my-6" @selectEntity="(payload) => selectEntity(payload, index)">
|
||||
<p class="font-semibold text-gray-100" :style="{ fontSize: sizeMultiplier + 'rem' }">{{ shelf.label }}</p>
|
||||
</widgets-episode-slider>
|
||||
<widgets-series-slider v-else-if="shelf.type === 'series'" :key="index + '.'" :items="shelf.entities" :height="232 * sizeMultiplier" class="bookshelf-row pl-8 my-6">
|
||||
@ -33,7 +33,7 @@
|
||||
<!-- Regular bookshelf view -->
|
||||
<div v-else class="w-full">
|
||||
<template v-for="(shelf, index) in shelves">
|
||||
<app-book-shelf-row :key="index" :index="index" :shelf="shelf" :size-multiplier="sizeMultiplier" :book-cover-width="bookCoverWidth" :book-cover-aspect-ratio="coverAspectRatio" :continue-listening-shelf="shelf.id === 'continue-listening'" />
|
||||
<app-book-shelf-row :key="index" :index="index" :shelf="shelf" :size-multiplier="sizeMultiplier" :book-cover-width="bookCoverWidth" :book-cover-aspect-ratio="coverAspectRatio" :continue-listening-shelf="shelf.id === 'continue-listening'" @selectEntity="(payload) => selectEntity(payload, index)" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@ -54,7 +54,8 @@ export default {
|
||||
keywordFilterTimeout: null,
|
||||
scannerParseSubtitle: false,
|
||||
wrapperClientWidth: 0,
|
||||
shelves: []
|
||||
shelves: [],
|
||||
lastItemIndexSelected: -1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -87,9 +88,64 @@ export default {
|
||||
sizeMultiplier() {
|
||||
var baseSize = this.isCoverSquareAspectRatio ? 192 : 120
|
||||
return this.bookCoverWidth / baseSize
|
||||
},
|
||||
selectedLibraryItems() {
|
||||
return this.$store.state.selectedLibraryItems || []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectEntity({ entity, shiftKey }, shelfIndex) {
|
||||
const shelf = this.shelves[shelfIndex]
|
||||
const entityShelfIndex = shelf.entities.findIndex((ent) => ent.id === entity.id)
|
||||
const indexOf = shelf.shelfStartIndex + entityShelfIndex
|
||||
|
||||
const lastLastItemIndexSelected = this.lastItemIndexSelected
|
||||
if (!this.selectedLibraryItems.includes(entity.id)) {
|
||||
this.lastItemIndexSelected = indexOf
|
||||
} else {
|
||||
this.lastItemIndexSelected = -1
|
||||
}
|
||||
|
||||
if (shiftKey && lastLastItemIndexSelected >= 0) {
|
||||
var loopStart = indexOf
|
||||
var loopEnd = lastLastItemIndexSelected
|
||||
if (indexOf > lastLastItemIndexSelected) {
|
||||
loopStart = lastLastItemIndexSelected
|
||||
loopEnd = indexOf
|
||||
}
|
||||
|
||||
const flattenedEntitiesArray = []
|
||||
this.shelves.map((s) => flattenedEntitiesArray.push(...s.entities))
|
||||
|
||||
var isSelecting = false
|
||||
// If any items in this range is not selected then select all otherwise unselect all
|
||||
for (let i = loopStart; i <= loopEnd; i++) {
|
||||
const thisEntity = flattenedEntitiesArray[i]
|
||||
if (thisEntity) {
|
||||
if (!this.selectedLibraryItems.includes(thisEntity.id)) {
|
||||
isSelecting = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isSelecting) this.lastItemIndexSelected = indexOf
|
||||
|
||||
for (let i = loopStart; i <= loopEnd; i++) {
|
||||
const thisEntity = flattenedEntitiesArray[i]
|
||||
if (thisEntity) {
|
||||
this.$store.commit('setLibraryItemSelected', { libraryItemId: thisEntity.id, selected: isSelecting })
|
||||
} else {
|
||||
console.error('Invalid entity index', i)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.$store.commit('toggleLibraryItemSelected', entity.id)
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$eventBus.$emit('item-selected', entity)
|
||||
})
|
||||
},
|
||||
async init() {
|
||||
this.wrapperClientWidth = this.$refs.wrapper ? this.$refs.wrapper.clientWidth : 0
|
||||
|
||||
@ -110,6 +166,12 @@ export default {
|
||||
console.error('Failed to fetch categories', error)
|
||||
return []
|
||||
})
|
||||
|
||||
let totalEntityCount = 0
|
||||
for (const shelf of categories) {
|
||||
shelf.shelfStartIndex = totalEntityCount
|
||||
totalEntityCount += shelf.entities.length
|
||||
}
|
||||
this.shelves = categories
|
||||
},
|
||||
async setShelvesFromSearch() {
|
||||
|
@ -138,11 +138,8 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
selectItem(libraryItem) {
|
||||
this.$store.commit('toggleLibraryItemSelected', libraryItem.id)
|
||||
this.$nextTick(() => {
|
||||
this.$eventBus.$emit('item-selected', libraryItem)
|
||||
})
|
||||
selectItem(payload) {
|
||||
this.$emit('selectEntity', payload)
|
||||
},
|
||||
itemSelectedEvt() {
|
||||
this.updateSelectionMode(this.isSelectionMode)
|
||||
|
@ -61,7 +61,8 @@ export default {
|
||||
keywordFilter: null,
|
||||
currScrollTop: 0,
|
||||
resizeTimeout: null,
|
||||
mountWindowWidth: 0
|
||||
mountWindowWidth: 0,
|
||||
lastItemIndexSelected: -1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -212,9 +213,55 @@ export default {
|
||||
this.updateBookSelectionMode(false)
|
||||
this.isSelectionMode = false
|
||||
},
|
||||
selectEntity(entity) {
|
||||
selectEntity(entity, shiftKey) {
|
||||
if (this.entityName === 'books' || this.entityName === 'series-books') {
|
||||
var indexOf = this.entities.findIndex((ent) => ent && ent.id === entity.id)
|
||||
const lastLastItemIndexSelected = this.lastItemIndexSelected
|
||||
if (!this.selectedLibraryItems.includes(entity.id)) {
|
||||
this.lastItemIndexSelected = indexOf
|
||||
} else {
|
||||
this.lastItemIndexSelected = -1
|
||||
}
|
||||
|
||||
if (shiftKey && lastLastItemIndexSelected >= 0) {
|
||||
var loopStart = indexOf
|
||||
var loopEnd = lastLastItemIndexSelected
|
||||
if (indexOf > lastLastItemIndexSelected) {
|
||||
loopStart = lastLastItemIndexSelected
|
||||
loopEnd = indexOf
|
||||
}
|
||||
|
||||
var isSelecting = false
|
||||
// If any items in this range is not selected then select all otherwise unselect all
|
||||
for (let i = loopStart; i <= loopEnd; i++) {
|
||||
const thisEntity = this.entities[i]
|
||||
if (thisEntity && !thisEntity.collapsedSeries) {
|
||||
if (!this.selectedLibraryItems.includes(thisEntity.id)) {
|
||||
isSelecting = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isSelecting) this.lastItemIndexSelected = indexOf
|
||||
|
||||
for (let i = loopStart; i <= loopEnd; i++) {
|
||||
const thisEntity = this.entities[i]
|
||||
if (thisEntity.collapsedSeries) {
|
||||
console.warn('Ignoring collapsed series')
|
||||
continue
|
||||
}
|
||||
|
||||
const entityComponentRef = this.entityComponentRefs[i]
|
||||
if (thisEntity && entityComponentRef) {
|
||||
entityComponentRef.selected = isSelecting
|
||||
this.$store.commit('setLibraryItemSelected', { libraryItemId: thisEntity.id, selected: isSelecting })
|
||||
} else {
|
||||
console.error('Invalid entity index', i)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.$store.commit('toggleLibraryItemSelected', entity.id)
|
||||
}
|
||||
|
||||
var newIsSelectionMode = !!this.selectedLibraryItems.length
|
||||
if (this.isSelectionMode !== newIsSelectionMode) {
|
||||
@ -229,6 +276,9 @@ export default {
|
||||
this.entityComponentRefs[key].setSelectionMode(isSelectionMode)
|
||||
}
|
||||
}
|
||||
if (!isSelectionMode) {
|
||||
this.lastItemIndexSelected = -1
|
||||
}
|
||||
},
|
||||
async fetchEntites(page = 0) {
|
||||
var startIndex = page * this.booksPerFetch
|
||||
|
@ -719,10 +719,10 @@ export default {
|
||||
console.log('Got library itemn', libraryItem)
|
||||
this.store.commit('showEReader', libraryItem)
|
||||
},
|
||||
selectBtnClick() {
|
||||
selectBtnClick(evt) {
|
||||
if (this.processingBatch) return
|
||||
this.selected = !this.selected
|
||||
this.$emit('select', this.libraryItem)
|
||||
this.$emit('select', { entity: this.libraryItem, shiftKey: evt.shiftKey })
|
||||
},
|
||||
async play() {
|
||||
var eventBus = this.$eventBus || this.$nuxt.$eventBus
|
||||
|
@ -94,11 +94,8 @@ export default {
|
||||
this.$store.commit('setBookshelfBookIds', itemIds)
|
||||
this.$store.commit('showEditModal', libraryItem)
|
||||
},
|
||||
selectItem(libraryItem) {
|
||||
this.$store.commit('toggleLibraryItemSelected', libraryItem.id)
|
||||
this.$nextTick(() => {
|
||||
this.$eventBus.$emit('item-selected', libraryItem)
|
||||
})
|
||||
selectItem(payload) {
|
||||
this.$emit('selectEntity', payload)
|
||||
},
|
||||
itemSelectedEvt() {
|
||||
this.updateSelectionMode(this.isSelectionMode)
|
||||
|
@ -74,11 +74,8 @@ export default {
|
||||
this.$store.commit('setBookshelfBookIds', itemIds)
|
||||
this.$store.commit('showEditModal', libraryItem)
|
||||
},
|
||||
selectItem(libraryItem) {
|
||||
this.$store.commit('toggleLibraryItemSelected', libraryItem.id)
|
||||
this.$nextTick(() => {
|
||||
this.$eventBus.$emit('item-selected', libraryItem)
|
||||
})
|
||||
selectItem(payload) {
|
||||
this.$emit('selectEntity', payload)
|
||||
},
|
||||
itemSelectedEvt() {
|
||||
this.updateSelectionMode(this.isSelectionMode)
|
||||
|
@ -68,8 +68,8 @@ export default {
|
||||
this.$on('edit', (entity) => {
|
||||
if (_this.editEntity) _this.editEntity(entity)
|
||||
})
|
||||
this.$on('select', (entity) => {
|
||||
if (_this.selectEntity) _this.selectEntity(entity)
|
||||
this.$on('select', ({ entity, shiftKey }) => {
|
||||
if (_this.selectEntity) _this.selectEntity(entity, shiftKey)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user