mirror of
https://github.com/owntone/owntone-server.git
synced 2025-11-11 14:30:20 -05:00
[web] Refactor lists to improve performance
Reduces the number of Vue components that need to be created/managed. Instead of a Vue component for each item, we now only have one Vue component for the whole list of items.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="albums_list.indexList" />
|
||||
<index-button-list :index="albums.indexList" />
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
@@ -44,17 +44,20 @@
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<dropdown-menu v-model="sort" :options="sort_options" />
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Albums</p>
|
||||
<p class="heading">{{ albums_list.sortedAndFiltered.length }} Albums</p>
|
||||
<p class="heading">{{ albums.count }} Albums</p>
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
<list-albums :albums="albums_list" />
|
||||
<list-albums :albums="albums" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
@@ -68,7 +71,7 @@ import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import DropdownMenu from '@/components/DropdownMenu.vue'
|
||||
import webapi from '@/webapi'
|
||||
import * as types from '@/store/mutation_types'
|
||||
import Albums from '@/lib/Albums'
|
||||
import { bySortName, byYear, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -76,16 +79,7 @@ const dataObject = {
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.albums = response.data
|
||||
vm.index_list = [
|
||||
...new Set(
|
||||
vm.albums.items
|
||||
.filter(
|
||||
(album) => !vm.$store.state.hide_singles || album.track_count > 2
|
||||
)
|
||||
.map((album) => album.name_sort.charAt(0).toUpperCase())
|
||||
)
|
||||
]
|
||||
vm.albums_list = new GroupByList(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +98,9 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (this.albums.items.length > 0) {
|
||||
if (!this.albums_list.isEmpty()) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
@@ -118,19 +113,53 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
albums: { items: [] },
|
||||
sort_options: ['Name', 'Recently added', 'Recently released']
|
||||
albums_list: new GroupByList(),
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Recently added',
|
||||
options: byYear('time_added', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'Recently released',
|
||||
options: byYear('date_released', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
albums_list() {
|
||||
return new Albums(this.albums.items, {
|
||||
hideSingles: this.hide_singles,
|
||||
hideSpotify: this.hide_spotify,
|
||||
sort: this.sort,
|
||||
group: true
|
||||
})
|
||||
albums() {
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
)
|
||||
this.albums_list.group(groupBy.options, [
|
||||
(album) => !this.hide_singles || album.track_count <= 2,
|
||||
(album) => !this.hide_spotify || album.data_kind !== 'spotify'
|
||||
])
|
||||
|
||||
return this.albums_list
|
||||
},
|
||||
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
get() {
|
||||
return this.$store.state.albums_sort
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit(types.ALBUMS_SORT, value)
|
||||
}
|
||||
},
|
||||
|
||||
spotify_enabled() {
|
||||
@@ -153,15 +182,6 @@ export default {
|
||||
set(value) {
|
||||
this.$store.commit(types.HIDE_SPOTIFY, value)
|
||||
}
|
||||
},
|
||||
|
||||
sort: {
|
||||
get() {
|
||||
return this.$store.state.albums_sort
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit(types.ALBUMS_SORT, value)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<dropdown-menu v-model="sort" :options="sort_options" />
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -36,7 +39,7 @@
|
||||
>{{ artist.track_count }} tracks</a
|
||||
>
|
||||
</p>
|
||||
<list-albums :albums="albums_list" />
|
||||
<list-albums :albums="albums" :hide_group_title="true" />
|
||||
<modal-dialog-artist
|
||||
:show="show_artist_details_modal"
|
||||
:artist="artist"
|
||||
@@ -53,7 +56,7 @@ import ModalDialogArtist from '@/components/ModalDialogArtist.vue'
|
||||
import DropdownMenu from '@/components/DropdownMenu.vue'
|
||||
import webapi from '@/webapi'
|
||||
import * as types from '@/store/mutation_types'
|
||||
import Albums from '@/lib/Albums'
|
||||
import { bySortName, byYear, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -65,7 +68,7 @@ const dataObject = {
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.artist = response[0].data
|
||||
vm.albums = response[1].data
|
||||
vm.albums_list = new GroupByList(response[1].data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,22 +97,39 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
artist: {},
|
||||
albums: { items: [] },
|
||||
albums_list: new GroupByList(),
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Release date',
|
||||
options: byYear('date_released', {
|
||||
direction: 'asc',
|
||||
defaultValue: '0000'
|
||||
})
|
||||
}
|
||||
],
|
||||
|
||||
sort_options: ['Name', 'Release date'],
|
||||
show_artist_details_modal: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
albums_list() {
|
||||
return new Albums(this.albums.items, {
|
||||
sort: this.sort,
|
||||
group: false
|
||||
})
|
||||
albums() {
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
)
|
||||
this.albums_list.group(groupBy.options)
|
||||
|
||||
return this.albums_list
|
||||
},
|
||||
|
||||
sort: {
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
get() {
|
||||
return this.$store.state.artist_albums_sort
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="artists_list.indexList" />
|
||||
<index-button-list :index="artists.indexList" />
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
@@ -44,19 +44,20 @@
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<dropdown-menu v-model="sort" :options="sort_options" />
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Artists</p>
|
||||
<p class="heading">
|
||||
{{ artists_list.sortedAndFiltered.length }} Artists
|
||||
</p>
|
||||
<p class="heading">{{ artists.count }} Artists</p>
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
<list-artists :artists="artists_list" />
|
||||
<list-artists :artists="artists" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
@@ -70,7 +71,7 @@ import ListArtists from '@/components/ListArtists.vue'
|
||||
import DropdownMenu from '@/components/DropdownMenu.vue'
|
||||
import webapi from '@/webapi'
|
||||
import * as types from '@/store/mutation_types'
|
||||
import Artists from '@/lib/Artists'
|
||||
import { bySortName, byYear, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -78,7 +79,7 @@ const dataObject = {
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.artists = response.data
|
||||
vm.artists_list = new GroupByList(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +98,9 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (this.artists.items.length > 0) {
|
||||
if (!this.artists_list.isEmpty()) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
@@ -111,19 +113,54 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
artists: { items: [] },
|
||||
sort_options: ['Name', 'Recently added']
|
||||
// Original data from API call
|
||||
artists_list: new GroupByList(),
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Recently added',
|
||||
options: byYear('time_added', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
artists_list() {
|
||||
return new Artists(this.artists.items, {
|
||||
hideSingles: this.hide_singles,
|
||||
hideSpotify: this.hide_spotify,
|
||||
sort: this.sort,
|
||||
group: true
|
||||
})
|
||||
// Wraps GroupByList and updates it if filter or sort changes
|
||||
artists() {
|
||||
if (!this.artists_list) {
|
||||
return []
|
||||
}
|
||||
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
)
|
||||
this.artists_list.group(groupBy.options, [
|
||||
(artist) =>
|
||||
!this.hide_singles || artist.track_count <= artist.album_count * 2,
|
||||
(artist) => !this.hide_spotify || artist.data_kind !== 'spotify'
|
||||
])
|
||||
|
||||
return this.artists_list
|
||||
},
|
||||
|
||||
// List for the drop down menu
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
get() {
|
||||
return this.$store.state.artists_sort
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit(types.ARTISTS_SORT, value)
|
||||
}
|
||||
},
|
||||
|
||||
spotify_enabled() {
|
||||
@@ -146,23 +183,10 @@ export default {
|
||||
set(value) {
|
||||
this.$store.commit(types.HIDE_SPOTIFY, value)
|
||||
}
|
||||
},
|
||||
|
||||
sort: {
|
||||
get() {
|
||||
return this.$store.state.artists_sort
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit(types.ARTISTS_SORT, value)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
scrollToTop: function () {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||
}
|
||||
}
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,16 +4,14 @@
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="albums_list.indexList" />
|
||||
<index-button-list :index="albums.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Audiobooks</p>
|
||||
<p class="heading">
|
||||
{{ albums_list.sortedAndFiltered.length }} Audiobooks
|
||||
</p>
|
||||
<p class="heading">{{ albums.count }} Audiobooks</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="albums_list" />
|
||||
<list-albums :albums="albums" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
@@ -25,7 +23,7 @@ import IndexButtonList from '@/components/IndexButtonList.vue'
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import webapi from '@/webapi'
|
||||
import Albums from '@/lib/Albums'
|
||||
import { bySortName, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -33,7 +31,8 @@ const dataObject = {
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.albums = response.data
|
||||
vm.albums = new GroupByList(response.data)
|
||||
vm.albums.group(bySortName('name_sort'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +50,12 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (!this.albums.isEmpty()) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
const vm = this
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.set(vm, response)
|
||||
@@ -61,16 +65,7 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
albums: { items: [] }
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
albums_list() {
|
||||
return new Albums(this.albums.items, {
|
||||
sort: 'Name',
|
||||
group: true
|
||||
})
|
||||
albums: new GroupByList()
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ artist.album_count }} albums
|
||||
</p>
|
||||
<list-albums :albums="albums.items" />
|
||||
<list-albums :albums="albums" />
|
||||
<modal-dialog-artist
|
||||
:show="show_artist_details_modal"
|
||||
:artist="artist"
|
||||
@@ -40,6 +40,7 @@ import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ModalDialogArtist from '@/components/ModalDialogArtist.vue'
|
||||
import webapi from '@/webapi'
|
||||
import { GroupByList } from '../lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -51,7 +52,7 @@ const dataObject = {
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.artist = response[0].data
|
||||
vm.albums = response[1].data
|
||||
vm.albums = new GroupByList(response[1].data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +65,12 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (!this.albums.isEmpty()) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
const vm = this
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.set(vm, response)
|
||||
@@ -75,7 +81,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
artist: {},
|
||||
albums: {},
|
||||
albums: new GroupByList(),
|
||||
|
||||
show_artist_details_modal: false
|
||||
}
|
||||
|
||||
@@ -4,17 +4,15 @@
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="artists_list.indexList" />
|
||||
<index-button-list :index="artists.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Authors</p>
|
||||
<p class="heading">
|
||||
{{ artists_list.sortedAndFiltered.length }} Authors
|
||||
</p>
|
||||
<p class="heading">{{ artists.count }} Authors</p>
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
<list-artists :artists="artists_list" />
|
||||
<list-artists :artists="artists" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
@@ -26,7 +24,7 @@ import TabsAudiobooks from '@/components/TabsAudiobooks.vue'
|
||||
import IndexButtonList from '@/components/IndexButtonList.vue'
|
||||
import ListArtists from '@/components/ListArtists.vue'
|
||||
import webapi from '@/webapi'
|
||||
import Artists from '@/lib/Artists'
|
||||
import { bySortName, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -34,7 +32,7 @@ const dataObject = {
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.artists = response.data
|
||||
vm.artists_list = new GroupByList(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +50,12 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (!this.artists_list.isEmpty()) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
const vm = this
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.set(vm, response)
|
||||
@@ -62,16 +65,17 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
artists: { items: [] }
|
||||
artists_list: new GroupByList()
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
artists_list() {
|
||||
return new Artists(this.artists.items, {
|
||||
sort: 'Name',
|
||||
group: true
|
||||
})
|
||||
artists() {
|
||||
if (!this.artists_list) {
|
||||
return []
|
||||
}
|
||||
this.artists_list.group(bySortName('name_sort'))
|
||||
return this.artists_list
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<p class="heading">albums</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="recently_added.items" />
|
||||
<list-albums :albums="recently_added" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav class="level">
|
||||
@@ -54,6 +54,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import webapi from '@/webapi'
|
||||
import { GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -74,7 +75,7 @@ const dataObject = {
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.recently_added = response[0].data.albums
|
||||
vm.recently_added = new GroupByList(response[0].data.albums)
|
||||
vm.recently_played = response[1].data.tracks
|
||||
}
|
||||
}
|
||||
@@ -88,6 +89,7 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
const vm = this
|
||||
dataObject.load(to).then((response) => {
|
||||
@@ -98,7 +100,7 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
recently_added: { items: [] },
|
||||
recently_added: [],
|
||||
recently_played: { items: [] },
|
||||
|
||||
show_track_details_modal: false,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<p class="heading">albums</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="albums_list" />
|
||||
<list-albums :albums="recently_added" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
@@ -20,7 +20,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import webapi from '@/webapi'
|
||||
import store from '@/store'
|
||||
import Albums from '@/lib/Albums'
|
||||
import { byDateSinceToday, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -34,7 +34,13 @@ const dataObject = {
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.recently_added = response.data.albums
|
||||
vm.recently_added = new GroupByList(response.data.albums)
|
||||
vm.recently_added.group(
|
||||
byDateSinceToday('time_added', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +53,12 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (!this.recently_added.isEmpty()) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
const vm = this
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.set(vm, response)
|
||||
@@ -57,18 +68,7 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
recently_added: { items: [] }
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
albums_list() {
|
||||
return new Albums(this.recently_added.items, {
|
||||
hideSingles: false,
|
||||
hideSpotify: false,
|
||||
sort: 'Recently added (browse)',
|
||||
group: true
|
||||
})
|
||||
recently_added: new GroupByList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="index_list" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ name }}
|
||||
@@ -27,28 +24,11 @@
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ composer_albums.total }} albums |
|
||||
{{ albums_list.total }} albums |
|
||||
<a class="has-text-link" @click="open_tracks">tracks</a>
|
||||
</p>
|
||||
<list-item-albums
|
||||
v-for="album in composer_albums.items"
|
||||
:key="album.id"
|
||||
:album="album"
|
||||
@click="open_album(album)"
|
||||
>
|
||||
<template #actions>
|
||||
<a @click="open_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><i class="mdi mdi-dots-vertical mdi-18px"
|
||||
/></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-albums>
|
||||
<modal-dialog-album
|
||||
:show="show_details_modal"
|
||||
:album="selected_album"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<list-albums :albums="albums_list" :hide_group_title="true" />
|
||||
|
||||
<modal-dialog-composer
|
||||
:show="show_composer_details_modal"
|
||||
:composer="{ name: name }"
|
||||
@@ -61,10 +41,10 @@
|
||||
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ListItemAlbums from '@/components/ListItemAlbum.vue'
|
||||
import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ModalDialogComposer from '@/components/ModalDialogComposer.vue'
|
||||
import webapi from '@/webapi'
|
||||
import { GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -73,7 +53,7 @@ const dataObject = {
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.name = vm.$route.params.composer
|
||||
vm.composer_albums = response.data.albums
|
||||
vm.albums_list = new GroupByList(response.data.albums)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +61,7 @@ export default {
|
||||
name: 'PageComposer',
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ListItemAlbums,
|
||||
ModalDialogAlbum,
|
||||
ListAlbums,
|
||||
ModalDialogComposer
|
||||
},
|
||||
|
||||
@@ -102,29 +81,13 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
composer_albums: { items: [] },
|
||||
show_details_modal: false,
|
||||
selected_album: {},
|
||||
|
||||
albums_list: new GroupByList(),
|
||||
show_composer_details_modal: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
index_list() {
|
||||
return [
|
||||
...new Set(
|
||||
this.composer_albums.items.map((album) =>
|
||||
album.name_sort.charAt(0).toUpperCase()
|
||||
)
|
||||
)
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
open_tracks: function () {
|
||||
this.show_details_modal = false
|
||||
this.$router.push({
|
||||
name: 'ComposerTracks',
|
||||
params: { composer: this.name }
|
||||
@@ -136,15 +99,6 @@ export default {
|
||||
'composer is "' + this.name + '" and media_kind is music',
|
||||
true
|
||||
)
|
||||
},
|
||||
|
||||
open_album: function (album) {
|
||||
this.$router.push({ path: '/music/albums/' + album.id })
|
||||
},
|
||||
|
||||
open_dialog: function (album) {
|
||||
this.selected_album = album
|
||||
this.show_details_modal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="index_list" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ composer }}
|
||||
@@ -30,25 +27,7 @@
|
||||
<a class="has-text-link" @click="open_albums">albums</a> |
|
||||
{{ tracks.total }} tracks
|
||||
</p>
|
||||
<list-item-track
|
||||
v-for="(track, index) in rated_tracks"
|
||||
:key="track.id"
|
||||
:track="track"
|
||||
@click="play_track(index)"
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><i class="mdi mdi-dots-vertical mdi-18px"
|
||||
/></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-track>
|
||||
<modal-dialog-track
|
||||
:show="show_details_modal"
|
||||
:track="selected_track"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<list-tracks :tracks="tracks.items" :expression="play_expression" />
|
||||
<modal-dialog-composer
|
||||
:show="show_composer_details_modal"
|
||||
:composer="{ name: composer }"
|
||||
@@ -61,8 +40,7 @@
|
||||
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ListItemTrack from '@/components/ListItemTrack.vue'
|
||||
import ModalDialogTrack from '@/components/ModalDialogTrack.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogComposer from '@/components/ModalDialogComposer.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
@@ -81,8 +59,7 @@ export default {
|
||||
name: 'PageComposerTracks',
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ListItemTrack,
|
||||
ModalDialogTrack,
|
||||
ListTracks,
|
||||
ModalDialogComposer
|
||||
},
|
||||
|
||||
@@ -104,30 +81,13 @@ export default {
|
||||
tracks: { items: [] },
|
||||
composer: '',
|
||||
|
||||
min_rating: 0,
|
||||
|
||||
show_details_modal: false,
|
||||
selected_track: {},
|
||||
|
||||
show_composer_details_modal: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
index_list() {
|
||||
return [
|
||||
...new Set(
|
||||
this.tracks.items.map((track) =>
|
||||
track.title_sort.charAt(0).toUpperCase()
|
||||
)
|
||||
)
|
||||
]
|
||||
},
|
||||
|
||||
rated_tracks() {
|
||||
return this.tracks.items.filter(
|
||||
(track) => track.rating >= this.min_rating
|
||||
)
|
||||
play_expression() {
|
||||
return 'composer is "' + this.composer + '" and media_kind is music'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -141,30 +101,7 @@ export default {
|
||||
},
|
||||
|
||||
play: function () {
|
||||
webapi.player_play_expression(
|
||||
'composer is "' + this.composer + '" and media_kind is music',
|
||||
true
|
||||
)
|
||||
},
|
||||
|
||||
play_track: function (position) {
|
||||
webapi.player_play_expression(
|
||||
'composer is "' + this.composer + '" and media_kind is music',
|
||||
false,
|
||||
position
|
||||
)
|
||||
},
|
||||
|
||||
show_rating: function (rating) {
|
||||
if (rating === 0.5) {
|
||||
rating = 0
|
||||
}
|
||||
this.min_rating = Math.ceil(rating) * 20
|
||||
},
|
||||
|
||||
open_dialog: function (track) {
|
||||
this.selected_track = track
|
||||
this.show_details_modal = true
|
||||
webapi.player_play_expression(this.play_expression, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,14 @@
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="composers_list.indexList" />
|
||||
<index-button-list :index="composers.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ heading }}
|
||||
</p>
|
||||
<p class="title is-4">Composers</p>
|
||||
<p class="heading">{{ composers.total }} composers</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-composers :composers="composers_list" />
|
||||
<list-composers :composers="composers" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
@@ -25,7 +23,7 @@ import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import IndexButtonList from '@/components/IndexButtonList.vue'
|
||||
import ListComposers from '@/components/ListComposers.vue'
|
||||
import webapi from '@/webapi'
|
||||
import Composers from '@/lib/Composers'
|
||||
import { byName, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -33,13 +31,8 @@ const dataObject = {
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
if (response.data.composers) {
|
||||
vm.composers = response.data.composers
|
||||
vm.heading = vm.$route.params.genre
|
||||
} else {
|
||||
vm.composers = response.data
|
||||
vm.heading = 'Composers'
|
||||
}
|
||||
vm.composers = new GroupByList(response.data)
|
||||
vm.composers.group(byName('name_sort'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +45,12 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (!this.composers.isEmpty()) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
const vm = this
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.set(vm, response)
|
||||
@@ -62,46 +60,11 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
composers: { items: [] },
|
||||
heading: '',
|
||||
|
||||
show_details_modal: false,
|
||||
selected_composer: {}
|
||||
composers: new GroupByList()
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
index_list() {
|
||||
return [
|
||||
...new Set(
|
||||
this.composers.items.map((composer) =>
|
||||
composer.name.charAt(0).toUpperCase()
|
||||
)
|
||||
)
|
||||
]
|
||||
},
|
||||
|
||||
composers_list() {
|
||||
return new Composers(this.composers.items, {
|
||||
sort: 'Name',
|
||||
group: true
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
open_composer: function (composer) {
|
||||
this.$router.push({
|
||||
name: 'ComposerAlbums',
|
||||
params: { composer: composer.name }
|
||||
})
|
||||
},
|
||||
|
||||
open_dialog: function (composer) {
|
||||
this.selected_composer = composer
|
||||
this.show_details_modal = true
|
||||
}
|
||||
}
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -24,94 +24,21 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div
|
||||
v-if="$route.query.directory"
|
||||
class="media"
|
||||
@click="open_parent_directory()"
|
||||
>
|
||||
<figure class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<i class="mdi mdi-subdirectory-arrow-left" />
|
||||
</span>
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">..</h1>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</div>
|
||||
<list-directories :directories="files.directories" />
|
||||
|
||||
<list-item-directory
|
||||
v-for="directory in files.directories"
|
||||
:key="directory.path"
|
||||
:directory="directory"
|
||||
@click="open_directory(directory)"
|
||||
>
|
||||
<template #actions>
|
||||
<a @click="open_directory_dialog(directory)">
|
||||
<span class="icon has-text-dark"
|
||||
><i class="mdi mdi-dots-vertical mdi-18px"
|
||||
/></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-directory>
|
||||
<list-playlists :playlists="files.playlists.items" />
|
||||
|
||||
<list-item-playlist
|
||||
v-for="playlist in files.playlists.items"
|
||||
:key="playlist.id"
|
||||
:playlist="playlist"
|
||||
@click="open_playlist(playlist)"
|
||||
>
|
||||
<template #icon>
|
||||
<span class="icon">
|
||||
<i class="mdi mdi-library-music" />
|
||||
</span>
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click="open_playlist_dialog(playlist)">
|
||||
<span class="icon has-text-dark"
|
||||
><i class="mdi mdi-dots-vertical mdi-18px"
|
||||
/></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-playlist>
|
||||
|
||||
<list-item-track
|
||||
v-for="(track, index) in files.tracks.items"
|
||||
:key="track.id"
|
||||
:track="track"
|
||||
@click="play_track(index)"
|
||||
>
|
||||
<template #icon>
|
||||
<span class="icon">
|
||||
<i class="mdi mdi-file-outline" />
|
||||
</span>
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click="open_track_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><i class="mdi mdi-dots-vertical mdi-18px"
|
||||
/></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-track>
|
||||
<list-tracks
|
||||
:tracks="files.tracks.items"
|
||||
:expression="play_expression"
|
||||
:show_icon="true"
|
||||
/>
|
||||
|
||||
<modal-dialog-directory
|
||||
:show="show_directory_details_modal"
|
||||
:directory="selected_directory"
|
||||
@close="show_directory_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-playlist
|
||||
:show="show_playlist_details_modal"
|
||||
:playlist="selected_playlist"
|
||||
@close="show_playlist_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-track
|
||||
:show="show_track_details_modal"
|
||||
:track="selected_track"
|
||||
@close="show_track_details_modal = false"
|
||||
/>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
@@ -119,12 +46,9 @@
|
||||
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ListItemDirectory from '@/components/ListItemDirectory.vue'
|
||||
import ListItemPlaylist from '@/components/ListItemPlaylist.vue'
|
||||
import ListItemTrack from '@/components/ListItemTrack.vue'
|
||||
import ModalDialogDirectory from '@/components/ModalDialogDirectory.vue'
|
||||
import ModalDialogPlaylist from '@/components/ModalDialogPlaylist.vue'
|
||||
import ModalDialogTrack from '@/components/ModalDialogTrack.vue'
|
||||
import ListDirectories from '@/components/ListDirectories.vue'
|
||||
import ListPlaylists from '@/components/ListPlaylists.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
@@ -154,12 +78,9 @@ export default {
|
||||
name: 'PageFiles',
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ListItemDirectory,
|
||||
ListItemPlaylist,
|
||||
ListItemTrack,
|
||||
ModalDialogDirectory,
|
||||
ModalDialogPlaylist,
|
||||
ModalDialogTrack
|
||||
ListDirectories,
|
||||
ListPlaylists,
|
||||
ListTracks
|
||||
},
|
||||
|
||||
beforeRouteEnter(to, from, next) {
|
||||
@@ -181,16 +102,7 @@ export default {
|
||||
directories: [],
|
||||
tracks: { items: [] },
|
||||
playlists: { items: [] }
|
||||
},
|
||||
|
||||
show_directory_details_modal: false,
|
||||
selected_directory: {},
|
||||
|
||||
show_playlist_details_modal: false,
|
||||
selected_playlist: {},
|
||||
|
||||
show_track_details_modal: false,
|
||||
selected_track: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -200,72 +112,18 @@ export default {
|
||||
return this.$route.query.directory
|
||||
}
|
||||
return '/'
|
||||
},
|
||||
|
||||
play_expression() {
|
||||
return (
|
||||
'path starts with "' + this.current_directory + '" order by path asc'
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
open_parent_directory: function () {
|
||||
const parent = this.current_directory.slice(
|
||||
0,
|
||||
this.current_directory.lastIndexOf('/')
|
||||
)
|
||||
if (
|
||||
parent === '' ||
|
||||
this.$store.state.config.directories.includes(this.current_directory)
|
||||
) {
|
||||
this.$router.push({ path: '/files' })
|
||||
} else {
|
||||
this.$router.push({
|
||||
path: '/files',
|
||||
query: {
|
||||
directory: this.current_directory.slice(
|
||||
0,
|
||||
this.current_directory.lastIndexOf('/')
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
open_directory: function (directory) {
|
||||
this.$router.push({
|
||||
path: '/files',
|
||||
query: { directory: directory.path }
|
||||
})
|
||||
},
|
||||
|
||||
open_directory_dialog: function (directory) {
|
||||
this.selected_directory = directory
|
||||
this.show_directory_details_modal = true
|
||||
},
|
||||
|
||||
play: function () {
|
||||
webapi.player_play_expression(
|
||||
'path starts with "' + this.current_directory + '" order by path asc',
|
||||
false
|
||||
)
|
||||
},
|
||||
|
||||
play_track: function (position) {
|
||||
webapi.player_play_uri(
|
||||
this.files.tracks.items.map((a) => a.uri).join(','),
|
||||
false,
|
||||
position
|
||||
)
|
||||
},
|
||||
|
||||
open_track_dialog: function (track) {
|
||||
this.selected_track = track
|
||||
this.show_track_details_modal = true
|
||||
},
|
||||
|
||||
open_playlist: function (playlist) {
|
||||
this.$router.push({ path: '/playlists/' + playlist.id + '/tracks' })
|
||||
},
|
||||
|
||||
open_playlist_dialog: function (playlist) {
|
||||
this.selected_playlist = playlist
|
||||
this.show_playlist_details_modal = true
|
||||
webapi.player_play_expression(this.play_expression, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="index_list" />
|
||||
<index-button-list :index="albums_list.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
@@ -27,10 +27,10 @@
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ genre_albums.total }} albums |
|
||||
{{ albums_list.total }} albums |
|
||||
<a class="has-text-link" @click="open_tracks">tracks</a>
|
||||
</p>
|
||||
<list-albums :albums="genre_albums.items" />
|
||||
<list-albums :albums="albums_list" />
|
||||
<modal-dialog-genre
|
||||
:show="show_genre_details_modal"
|
||||
:genre="{ name: name }"
|
||||
@@ -47,6 +47,7 @@ import IndexButtonList from '@/components/IndexButtonList.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ModalDialogGenre from '@/components/ModalDialogGenre.vue'
|
||||
import webapi from '@/webapi'
|
||||
import { bySortName, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -55,7 +56,8 @@ const dataObject = {
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.name = vm.$route.params.genre
|
||||
vm.genre_albums = response.data.albums
|
||||
vm.albums_list = new GroupByList(response.data.albums)
|
||||
vm.albums_list.group(bySortName('name_sort'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +76,10 @@ export default {
|
||||
})
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
if (!this.albums_list.isEmpty()) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
const vm = this
|
||||
dataObject.load(to).then((response) => {
|
||||
dataObject.set(vm, response)
|
||||
@@ -84,24 +90,12 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
genre_albums: { items: [] },
|
||||
albums_list: new GroupByList(),
|
||||
|
||||
show_genre_details_modal: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
index_list() {
|
||||
return [
|
||||
...new Set(
|
||||
this.genre_albums.items.map((album) =>
|
||||
album.name.charAt(0).toUpperCase()
|
||||
)
|
||||
)
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
open_tracks: function () {
|
||||
this.show_details_modal = false
|
||||
@@ -113,11 +107,6 @@ export default {
|
||||
'genre is "' + this.name + '" and media_kind is music',
|
||||
true
|
||||
)
|
||||
},
|
||||
|
||||
open_dialog: function (album) {
|
||||
this.selected_album = album
|
||||
this.show_details_modal = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,32 +4,14 @@
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="index_list" />
|
||||
<index-button-list :index="genres.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Genres</p>
|
||||
<p class="heading">{{ genres.total }} genres</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-item-genre
|
||||
v-for="genre in genres.items"
|
||||
:key="genre.name"
|
||||
:genre="genre"
|
||||
@click="open_genre(genre)"
|
||||
>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_dialog(genre)">
|
||||
<span class="icon has-text-dark"
|
||||
><i class="mdi mdi-dots-vertical mdi-18px"
|
||||
/></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-genre>
|
||||
<modal-dialog-genre
|
||||
:show="show_details_modal"
|
||||
:genre="selected_genre"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<list-genres :genres="genres" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
@@ -39,9 +21,9 @@
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import TabsMusic from '@/components/TabsMusic.vue'
|
||||
import IndexButtonList from '@/components/IndexButtonList.vue'
|
||||
import ListItemGenre from '@/components/ListItemGenre.vue'
|
||||
import ModalDialogGenre from '@/components/ModalDialogGenre.vue'
|
||||
import ListGenres from '@/components/ListGenres.vue'
|
||||
import webapi from '@/webapi'
|
||||
import { byName, GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -50,6 +32,8 @@ const dataObject = {
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.genres = response.data
|
||||
vm.genres = new GroupByList(response.data)
|
||||
vm.genres.group(byName('name_sort'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +43,7 @@ export default {
|
||||
ContentWithHeading,
|
||||
TabsMusic,
|
||||
IndexButtonList,
|
||||
ListItemGenre,
|
||||
ModalDialogGenre
|
||||
ListGenres
|
||||
},
|
||||
|
||||
beforeRouteEnter(to, from, next) {
|
||||
@@ -78,33 +61,13 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
genres: { items: [] },
|
||||
|
||||
show_details_modal: false,
|
||||
selected_genre: {}
|
||||
genres: new GroupByList()
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
index_list() {
|
||||
return [
|
||||
...new Set(
|
||||
this.genres.items.map((genre) => genre.name.charAt(0).toUpperCase())
|
||||
)
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
|
||||
methods: {
|
||||
open_genre: function (genre) {
|
||||
this.$router.push({ name: 'Genre', params: { genre: genre.name } })
|
||||
},
|
||||
|
||||
open_dialog: function (genre) {
|
||||
this.selected_genre = genre
|
||||
this.show_details_modal = true
|
||||
}
|
||||
}
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -27,27 +27,9 @@
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ album.track_count }} tracks
|
||||
</p>
|
||||
<list-item-track
|
||||
v-for="track in tracks"
|
||||
:key="track.id"
|
||||
:track="track"
|
||||
@click="play_track(track)"
|
||||
>
|
||||
<template #progress>
|
||||
<progress-bar :max="track.length_ms" :value="track.seek_ms" />
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><i class="mdi mdi-dots-vertical mdi-18px"
|
||||
/></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-track>
|
||||
<modal-dialog-track
|
||||
:show="show_details_modal"
|
||||
:track="selected_track"
|
||||
@close="show_details_modal = false"
|
||||
<list-tracks
|
||||
:tracks="tracks"
|
||||
:show_progress="true"
|
||||
@play-count-changed="reload_tracks"
|
||||
/>
|
||||
<modal-dialog-album
|
||||
@@ -81,11 +63,9 @@
|
||||
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ListItemTrack from '@/components/ListItemTrack.vue'
|
||||
import ModalDialogTrack from '@/components/ModalDialogTrack.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ModalDialogAlbum from '@/components/ModalDialogAlbum.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import ProgressBar from '@/components/ProgressBar.vue'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
const dataObject = {
|
||||
@@ -106,11 +86,9 @@ export default {
|
||||
name: 'PagePodcast',
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ListItemTrack,
|
||||
ModalDialogTrack,
|
||||
ListTracks,
|
||||
ModalDialogAlbum,
|
||||
ModalDialog,
|
||||
ProgressBar
|
||||
ModalDialog
|
||||
},
|
||||
|
||||
beforeRouteEnter(to, from, next) {
|
||||
@@ -131,9 +109,6 @@ export default {
|
||||
album: {},
|
||||
tracks: [],
|
||||
|
||||
show_details_modal: false,
|
||||
selected_track: {},
|
||||
|
||||
show_album_details_modal: false,
|
||||
|
||||
show_remove_podcast_modal: false,
|
||||
@@ -152,15 +127,6 @@ export default {
|
||||
webapi.player_play_uri(this.album.uri, false)
|
||||
},
|
||||
|
||||
play_track: function (track) {
|
||||
webapi.player_play_uri(track.uri, false)
|
||||
},
|
||||
|
||||
open_dialog: function (track) {
|
||||
this.selected_track = track
|
||||
this.show_details_modal = true
|
||||
},
|
||||
|
||||
open_remove_podcast_dialog: function () {
|
||||
this.show_album_details_modal = false
|
||||
webapi.library_track_playlists(this.tracks[0].id).then(({ data }) => {
|
||||
|
||||
@@ -15,27 +15,9 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-item-track
|
||||
v-for="track in new_episodes.items"
|
||||
:key="track.id"
|
||||
:track="track"
|
||||
@click="play_track(track)"
|
||||
>
|
||||
<template #progress>
|
||||
<progress-bar :max="track.length_ms" :value="track.seek_ms" />
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click="open_track_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><i class="mdi mdi-dots-vertical mdi-18px"
|
||||
/></span>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-track>
|
||||
<modal-dialog-track
|
||||
:show="show_track_details_modal"
|
||||
:track="selected_track"
|
||||
@close="show_track_details_modal = false"
|
||||
<list-tracks
|
||||
:tracks="new_episodes.items"
|
||||
:show_progress="true"
|
||||
@play-count-changed="reload_new_episodes"
|
||||
/>
|
||||
</template>
|
||||
@@ -64,7 +46,7 @@
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums
|
||||
:albums="albums.items"
|
||||
:albums="albums"
|
||||
@play-count-changed="reload_new_episodes()"
|
||||
@podcast-deleted="reload_podcasts()"
|
||||
/>
|
||||
@@ -80,13 +62,12 @@
|
||||
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ListItemTrack from '@/components/ListItemTrack.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ModalDialogTrack from '@/components/ModalDialogTrack.vue'
|
||||
import ModalDialogAddRss from '@/components/ModalDialogAddRss.vue'
|
||||
import ProgressBar from '@/components/ProgressBar.vue'
|
||||
import * as types from '@/store/mutation_types'
|
||||
import webapi from '@/webapi'
|
||||
import { GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
const dataObject = {
|
||||
load: function (to) {
|
||||
@@ -97,7 +78,7 @@ const dataObject = {
|
||||
},
|
||||
|
||||
set: function (vm, response) {
|
||||
vm.albums = response[0].data
|
||||
vm.albums = new GroupByList(response[0].data)
|
||||
vm.new_episodes = response[1].data.tracks
|
||||
}
|
||||
}
|
||||
@@ -106,11 +87,9 @@ export default {
|
||||
name: 'PagePodcasts',
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ListItemTrack,
|
||||
ListTracks,
|
||||
ListAlbums,
|
||||
ModalDialogTrack,
|
||||
ModalDialogAddRss,
|
||||
ProgressBar
|
||||
ModalDialogAddRss
|
||||
},
|
||||
|
||||
beforeRouteEnter(to, from, next) {
|
||||
@@ -118,6 +97,7 @@ export default {
|
||||
next((vm) => dataObject.set(vm, response))
|
||||
})
|
||||
},
|
||||
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
const vm = this
|
||||
dataObject.load(to).then((response) => {
|
||||
@@ -128,13 +108,10 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
albums: { items: [] },
|
||||
albums: [],
|
||||
new_episodes: { items: [] },
|
||||
|
||||
show_url_modal: false,
|
||||
|
||||
show_track_details_modal: false,
|
||||
selected_track: {}
|
||||
show_url_modal: false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -145,15 +122,6 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
play_track: function (track) {
|
||||
webapi.player_play_uri(track.uri, false)
|
||||
},
|
||||
|
||||
open_track_dialog: function (track) {
|
||||
this.selected_track = track
|
||||
this.show_track_details_modal = true
|
||||
},
|
||||
|
||||
mark_all_played: function () {
|
||||
this.new_episodes.items.forEach((ep) => {
|
||||
webapi.library_track_update(ep.id, { play_count: 'increment' })
|
||||
@@ -173,7 +141,7 @@ export default {
|
||||
|
||||
reload_podcasts: function () {
|
||||
webapi.library_albums('podcast').then(({ data }) => {
|
||||
this.albums = data
|
||||
this.albums = new GroupByList(data)
|
||||
this.reload_new_episodes()
|
||||
})
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<p class="title is-4">Artists</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-artists :artists="artists.items" />
|
||||
<list-artists :artists="artists" :hide_group_title="true" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav v-if="show_all_artists_button" class="level">
|
||||
@@ -105,7 +105,7 @@
|
||||
<p class="title is-4">Albums</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="albums.items" />
|
||||
<list-albums :albums="albums" :hide_group_title="true" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav v-if="show_all_albums_button" class="level">
|
||||
@@ -183,7 +183,7 @@
|
||||
<p class="title is-4">Podcasts</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="podcasts.items" />
|
||||
<list-albums :albums="podcasts" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav v-if="show_all_podcasts_button" class="level">
|
||||
@@ -209,7 +209,7 @@
|
||||
<p class="title is-4">Audiobooks</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="audiobooks.items" />
|
||||
<list-albums :albums="audiobooks" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav v-if="show_all_audiobooks_button" class="level">
|
||||
@@ -242,6 +242,7 @@ import ListComposers from '@/components/ListComposers.vue'
|
||||
import ListPlaylists from '@/components/ListPlaylists.vue'
|
||||
import webapi from '@/webapi'
|
||||
import * as types from '@/store/mutation_types'
|
||||
import { GroupByList } from '@/lib/GroupByList'
|
||||
|
||||
export default {
|
||||
name: 'PageSearch',
|
||||
@@ -261,12 +262,12 @@ export default {
|
||||
search_query: '',
|
||||
|
||||
tracks: { items: [], total: 0 },
|
||||
artists: { items: [], total: 0 },
|
||||
albums: { items: [], total: 0 },
|
||||
artists: new GroupByList(),
|
||||
albums: new GroupByList(),
|
||||
composers: { items: [], total: 0 },
|
||||
playlists: { items: [], total: 0 },
|
||||
audiobooks: { items: [], total: 0 },
|
||||
podcasts: { items: [], total: 0 }
|
||||
audiobooks: new GroupByList(),
|
||||
podcasts: new GroupByList()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -393,8 +394,8 @@ export default {
|
||||
|
||||
webapi.search(searchParams).then(({ data }) => {
|
||||
this.tracks = data.tracks ? data.tracks : { items: [], total: 0 }
|
||||
this.artists = data.artists ? data.artists : { items: [], total: 0 }
|
||||
this.albums = data.albums ? data.albums : { items: [], total: 0 }
|
||||
this.artists = new GroupByList(data.artists)
|
||||
this.albums = new GroupByList(data.albums)
|
||||
this.composers = data.composers
|
||||
? data.composers
|
||||
: { items: [], total: 0 }
|
||||
@@ -431,7 +432,7 @@ export default {
|
||||
}
|
||||
|
||||
webapi.search(searchParams).then(({ data }) => {
|
||||
this.audiobooks = data.albums ? data.albums : { items: [], total: 0 }
|
||||
this.audiobooks = new GroupByList(data.albums)
|
||||
})
|
||||
},
|
||||
|
||||
@@ -462,7 +463,7 @@ export default {
|
||||
}
|
||||
|
||||
webapi.search(searchParams).then(({ data }) => {
|
||||
this.podcasts = data.albums ? data.albums : { items: [], total: 0 }
|
||||
this.podcasts = new GroupByList(data.albums)
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user