Podcast home page shelves for currently listening episodes, newest episodes. Podcast episode card

This commit is contained in:
advplyr 2022-04-22 19:31:11 -05:00
parent 84fb7ce8b3
commit 5d12cc3f23
10 changed files with 164 additions and 100 deletions

View file

@ -7,6 +7,11 @@
<cards-lazy-book-card :key="entity.id" :ref="`shelf-book-${entity.id}`" :index="index" :width="bookCoverWidth" :height="bookCoverHeight" :book-cover-aspect-ratio="bookCoverAspectRatio" :book-mount="entity" class="relative mx-2" @hook:updated="updatedBookCard" @select="selectItem" @edit="editBook" />
</template>
</div>
<div v-if="shelf.type === 'episode'" class="flex items-center">
<template v-for="(entity, index) in shelf.entities">
<cards-lazy-book-card :key="entity.recentEpisode.id" :ref="`shelf-episode-${entity.recentEpisode.id}`" :index="index" :width="bookCoverWidth" :height="bookCoverHeight" :book-cover-aspect-ratio="bookCoverAspectRatio" :book-mount="entity" class="relative mx-2" @hook:updated="updatedBookCard" @select="selectItem" @edit="editEpisode" />
</template>
</div>
<div v-if="shelf.type === 'series'" class="flex items-center">
<template v-for="entity in shelf.entities">
<cards-lazy-series-card :key="entity.name" :series-mount="entity" :height="bookCoverHeight" :width="bookCoverWidth * 2" :book-cover-aspect-ratio="bookCoverAspectRatio" class="relative mx-2" @hook:updated="updatedBookCard" />
@ -70,11 +75,6 @@ export default {
selectedAuthor: null
}
},
watch: {
isSelectionMode(newVal) {
this.updateSelectionMode(newVal)
}
},
computed: {
bookCoverHeight() {
return this.bookCoverWidth * this.bookCoverAspectRatio
@ -103,9 +103,14 @@ export default {
this.$store.commit('setBookshelfBookIds', bookIds)
this.$store.commit('showEditModal', audiobook)
},
editEpisode({ libraryItem, episode }) {
this.$store.commit('setSelectedLibraryItem', libraryItem)
this.$store.commit('globals/setSelectedEpisode', episode)
this.$store.commit('globals/setShowEditPodcastEpisodeModal', true)
},
updateSelectionMode(val) {
var selectedLibraryItems = this.$store.state.selectedLibraryItems
if (this.shelf.type === 'book') {
if (this.shelf.type === 'book' || this.shelf.type === 'podcast') {
this.shelf.entities.forEach((ent) => {
var component = this.$refs[`shelf-book-${ent.id}`]
if (!component || !component.length) return
@ -113,10 +118,24 @@ export default {
component.setSelectionMode(val)
component.selected = selectedLibraryItems.includes(ent.id)
})
} else if (this.shelf.type === 'episode') {
this.shelf.entities.forEach((ent) => {
var component = this.$refs[`shelf-episode-${ent.recentEpisode.id}`]
if (!component || !component.length) return
component = component[0]
component.setSelectionMode(val)
component.selected = selectedLibraryItems.includes(ent.id)
})
}
},
selectItem(libraryItem) {
this.$store.commit('toggleLibraryItemSelected', libraryItem.id)
this.$nextTick(() => {
this.$eventBus.$emit('item-selected', libraryItem)
})
},
itemSelectedEvt() {
this.updateSelectionMode(this.isSelectionMode)
},
scrolled() {
clearTimeout(this.scrollTimer)
@ -160,6 +179,12 @@ export default {
this.canScrollLeft = false
}
}
},
mounted() {
this.$eventBus.$on('item-selected', this.itemSelectedEvt)
},
beforeDestroy() {
this.$eventBus.$off('item-selected', this.itemSelectedEvt)
}
}
</script>

View file

@ -35,8 +35,8 @@
</div>
</div>
<!-- No progress shown for collapsed series in library and podcasts -->
<div v-if="!booksInSeries && !isPodcast" class="absolute bottom-0 left-0 h-1 shadow-sm max-w-full z-10 rounded-b" :class="itemIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: width * userProgressPercent + 'px' }"></div>
<!-- No progress shown for collapsed series in library and podcasts (unless showing podcast episode) -->
<div v-if="!booksInSeries && (!isPodcast || episodeProgress)" class="absolute bottom-0 left-0 h-1 shadow-sm max-w-full z-10 rounded-b" :class="itemIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: width * userProgressPercent + 'px' }"></div>
<!-- Overlay is not shown if collapsing series in library -->
<div v-show="!booksInSeries && libraryItem && (isHovering || isSelectionMode || isMoreMenuOpen)" class="w-full h-full absolute top-0 left-0 z-10 bg-black rounded hidden md:block" :class="overlayWrapperClasslist">
@ -60,7 +60,7 @@
<span class="material-icons" :class="selected ? 'text-yellow-400' : ''" :style="{ fontSize: 1.25 * sizeMultiplier + 'rem' }">{{ selected ? 'radio_button_checked' : 'radio_button_unchecked' }}</span>
</div>
<div ref="moreIcon" v-show="!isSelectionMode" class="hidden md:block absolute cursor-pointer hover:text-yellow-300" :style="{ bottom: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem' }" @click.stop.prevent="clickShowMore">
<div ref="moreIcon" v-show="!isSelectionMode && !recentEpisode" class="hidden md:block absolute cursor-pointer hover:text-yellow-300" :style="{ bottom: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem' }" @click.stop.prevent="clickShowMore">
<span class="material-icons" :style="{ fontSize: 1.2 * sizeMultiplier + 'rem' }">more_vert</span>
</div>
</div>
@ -77,13 +77,18 @@
</div>
</ui-tooltip>
<!-- Volume number -->
<!-- Series sequence -->
<div v-if="seriesSequence && showSequence && !isHovering && !isSelectionMode" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-10" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }">
<p :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">#{{ seriesSequence }}</p>
</div>
<!-- Podcast Episode # -->
<div v-if="recentEpisodeNumber && !isHovering && !isSelectionMode" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-10" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }">
<p :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">Episode #{{ recentEpisodeNumber }}</p>
</div>
<!-- Podcast Num Episodes -->
<div v-if="numEpisodes && !isHovering && !isSelectionMode" class="absolute rounded-full bg-black bg-opacity-90 box-shadow-md z-10 flex items-center justify-center" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', width: 1.25 * sizeMultiplier + 'rem', height: 1.25 * sizeMultiplier + 'rem' }">
<div v-else-if="numEpisodes && !isHovering && !isSelectionMode" class="absolute rounded-full bg-black bg-opacity-90 box-shadow-md z-10 flex items-center justify-center" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', width: 1.25 * sizeMultiplier + 'rem', height: 1.25 * sizeMultiplier + 'rem' }">
<p :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">{{ numEpisodes }}</p>
</div>
</div>
@ -190,6 +195,17 @@ export default {
processingBatch() {
return this.store.state.processingBatch
},
recentEpisode() {
// Only added to item when getting currently listening podcasts
return this._libraryItem.recentEpisode
},
recentEpisodeNumber() {
if (!this.recentEpisode) return null
if (this.recentEpisode.episode) {
return this.recentEpisode.episode.replace(/^#/, '')
}
return this.recentEpisode.index
},
collapsedSeries() {
// Only added to item object when collapseSeries is enabled
return this._libraryItem.collapsedSeries
@ -240,7 +256,13 @@ export default {
if (this.orderBy === 'size') return 'Size: ' + this.$bytesPretty(this._libraryItem.size)
return null
},
episodeProgress() {
// Only used on home page currently listening podcast shelf
if (!this.recentEpisode) return null
return this.store.getters['user/getUserMediaProgress'](this.libraryItemId, this.recentEpisode.id)
},
userProgress() {
if (this.episodeProgress) return this.episodeProgress
return this.store.getters['user/getUserMediaProgress'](this.libraryItemId)
},
userProgressPercent() {
@ -259,7 +281,7 @@ export default {
return !this.isSelectionMode && this.showExperimentalFeatures && !this.showPlayButton && this.hasEbook
},
showPlayButton() {
return !this.isSelectionMode && !this.isMissing && !this.isInvalid && this.numTracks && !this.isStreaming
return !this.isSelectionMode && !this.isMissing && !this.isInvalid && !this.isStreaming && (this.numTracks || this.recentEpisode)
},
showSmallEBookIcon() {
return !this.isSelectionMode && this.showExperimentalFeatures && this.hasEbook
@ -406,6 +428,9 @@ export default {
}
},
editClick() {
if (this.recentEpisode) {
return this.$emit('edit', { libraryItem: this.libraryItem, episode: this.recentEpisode })
}
this.$emit('edit', this.libraryItem)
},
toggleFinished() {
@ -529,7 +554,8 @@ export default {
play() {
var eventBus = this.$eventBus || this.$nuxt.$eventBus
eventBus.$emit('play-item', {
libraryItemId: this.libraryItemId
libraryItemId: this.libraryItemId,
episodeId: this.recentEpisode ? this.recentEpisode.id : null
})
},
mouseover() {

View file

@ -35,17 +35,6 @@
<script>
export default {
props: {
value: Boolean,
libraryItem: {
type: Object,
default: () => {}
},
episode: {
type: Object,
default: () => {}
}
},
data() {
return {
processing: false,
@ -72,12 +61,18 @@ export default {
computed: {
show: {
get() {
return this.value
return this.$store.state.globals.showEditPodcastEpisode
},
set(val) {
this.$emit('input', val)
this.$store.commit('globals/setShowEditPodcastEpisodeModal', val)
}
},
libraryItem() {
return this.$store.state.selectedLibraryItem
},
episode() {
return this.$store.state.globals.selectedEpisode
},
episodeId() {
return this.episode ? this.episode.id : null
},

View file

@ -16,8 +16,6 @@
</template>
</transition-group>
</draggable>
<modals-podcast-edit-episode v-model="showEditEpisodeModal" :library-item="libraryItem" :episode="selectedEpisode" />
</div>
</template>
@ -40,8 +38,6 @@ export default {
sortDesc: true,
drag: false,
episodesCopy: [],
selectedEpisode: null,
showEditEpisodeModal: false,
orderChanged: false,
savingOrder: false
}
@ -97,8 +93,9 @@ export default {
return false
},
editEpisode(episode) {
this.selectedEpisode = episode
this.showEditEpisodeModal = true
this.$store.commit('setSelectedLibraryItem', this.libraryItem)
this.$store.commit('globals/setSelectedEpisode', episode)
this.$store.commit('globals/setShowEditPodcastEpisodeModal', true)
},
draggableUpdate() {
this.orderChanged = this.checkHasOrderChanged()