feat: synchronize sorting

This commit is contained in:
Phan An 2022-07-05 17:09:20 +02:00
parent bd5cd1e621
commit 64c6eebdcd
No known key found for this signature in database
GPG key ID: A81E4477F0BB6FDC
5 changed files with 58 additions and 35 deletions

View file

@ -86,7 +86,7 @@ let initialized = false
const fetchSongs = async () => { const fetchSongs = async () => {
await favoriteStore.fetch() await favoriteStore.fetch()
await nextTick() await nextTick()
sort('title', 'asc') sort()
} }
eventBus.on('LOAD_MAIN_CONTENT', async (view: MainViewName) => { eventBus.on('LOAD_MAIN_CONTENT', async (view: MainViewName) => {

View file

@ -47,8 +47,7 @@
<template v-else> <template v-else>
The playlist is currently empty. The playlist is currently empty.
<span class="d-block secondary"> <span class="d-block secondary">
Drag songs into its name in the sidebar Drag songs into its name in the sidebar or use the &quot;Add To&quot; button to fill it up.
or use the &quot;Add To&quot; button to fill it up.
</span> </span>
</template> </template>
</ScreenEmptyState> </ScreenEmptyState>
@ -57,7 +56,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { difference } from 'lodash' import { difference } from 'lodash'
import { defineAsyncComponent, nextTick, ref, toRef } from 'vue' import { defineAsyncComponent, ref, toRef } from 'vue'
import { alerts, eventBus, pluralize } from '@/utils' import { alerts, eventBus, pluralize } from '@/utils'
import { commonStore, playlistStore, songStore } from '@/stores' import { commonStore, playlistStore, songStore } from '@/stores'
import { downloadService } from '@/services' import { downloadService } from '@/services'
@ -107,8 +106,7 @@ const fetchSongs = async () => {
loading.value = true loading.value = true
playlistSongs.value = await songStore.fetchForPlaylist(playlist.value!) playlistSongs.value = await songStore.fetchForPlaylist(playlist.value!)
loading.value = false loading.value = false
await nextTick() sort()
sort('title', 'asc')
} }
eventBus.on({ eventBus.on({

View file

@ -17,8 +17,8 @@
@click="sort('track')" @click="sort('track')"
> >
# #
<i v-show="currentSortField === 'track' && sortOrder === 'asc'" class="fa fa-angle-down"></i> <i v-show="sortField === 'track' && sortOrder === 'asc'" class="fa fa-angle-down"></i>
<i v-show="currentSortField === 'track' && sortOrder === 'desc'" class="fa fa-angle-up"></i> <i v-show="sortField === 'track' && sortOrder === 'desc'" class="fa fa-angle-up"></i>
</span> </span>
<span <span
v-if="config.columns.includes('title')" v-if="config.columns.includes('title')"
@ -27,8 +27,8 @@
@click="sort('title')" @click="sort('title')"
> >
Title Title
<i v-show="currentSortField === 'title' && sortOrder === 'asc'" class="fa fa-angle-down"></i> <i v-show="sortField === 'title' && sortOrder === 'asc'" class="fa fa-angle-down"></i>
<i v-show="currentSortField === 'title' && sortOrder === 'desc'" class="fa fa-angle-up"></i> <i v-show="sortField === 'title' && sortOrder === 'desc'" class="fa fa-angle-up"></i>
</span> </span>
<span <span
v-if="config.columns.includes('artist')" v-if="config.columns.includes('artist')"
@ -37,8 +37,8 @@
@click="sort('artist_name')" @click="sort('artist_name')"
> >
Artist Artist
<i v-show="currentSortField === 'artist_name' && sortOrder === 'asc'" class="fa fa-angle-down"></i> <i v-show="sortField === 'artist_name' && sortOrder === 'asc'" class="fa fa-angle-down"></i>
<i v-show="currentSortField === 'artist_name' && sortOrder === 'desc'" class="fa fa-angle-up"></i> <i v-show="sortField === 'artist_name' && sortOrder === 'desc'" class="fa fa-angle-up"></i>
</span> </span>
<span <span
v-if="config.columns.includes('album')" v-if="config.columns.includes('album')"
@ -47,8 +47,8 @@
@click="sort('album_name')" @click="sort('album_name')"
> >
Album Album
<i v-show="currentSortField === 'album_name' && sortOrder === 'asc'" class="fa fa-angle-down"></i> <i v-show="sortField === 'album_name' && sortOrder === 'asc'" class="fa fa-angle-down"></i>
<i v-show="currentSortField === 'album_name' && sortOrder === 'desc'" class="fa fa-angle-up"></i> <i v-show="sortField === 'album_name' && sortOrder === 'desc'" class="fa fa-angle-up"></i>
</span> </span>
<span <span
v-if="config.columns.includes('length')" v-if="config.columns.includes('length')"
@ -56,8 +56,8 @@
data-testid="header-length" data-testid="header-length"
@click="sort('length')" @click="sort('length')"
> >
<i v-show="currentSortField === 'length' && sortOrder === 'asc'" class="fa fa-angle-down"></i> <i v-show="sortField === 'length' && sortOrder === 'asc'" class="fa fa-angle-down"></i>
<i v-show="currentSortField === 'length' && sortOrder === 'desc'" class="fa fa-angle-up"></i> <i v-show="sortField === 'length' && sortOrder === 'desc'" class="fa fa-angle-up"></i>
&nbsp;<i class="duration-header fa fa-clock-o"></i> &nbsp;<i class="duration-header fa fa-clock-o"></i>
</span> </span>
<span class="favorite"></span> <span class="favorite"></span>
@ -87,7 +87,14 @@ import isMobile from 'ismobilejs'
import { findIndex } from 'lodash' import { findIndex } from 'lodash'
import { computed, defineAsyncComponent, inject, onMounted, ref, watch } from 'vue' import { computed, defineAsyncComponent, inject, onMounted, ref, watch } from 'vue'
import { $, eventBus, startDragging } from '@/utils' import { $, eventBus, startDragging } from '@/utils'
import { SelectedSongsKey, SongListConfigKey, SongListTypeKey, SongsKey } from '@/symbols' import {
SelectedSongsKey,
SongListConfigKey,
SongListSortFieldKey,
SongListSortOrderKey,
SongListTypeKey,
SongsKey
} from '@/symbols'
const VirtualScroller = defineAsyncComponent(() => import('@/components/ui/VirtualScroller.vue')) const VirtualScroller = defineAsyncComponent(() => import('@/components/ui/VirtualScroller.vue'))
const SongListItem = defineAsyncComponent(() => import('@/components/song/SongListItem.vue')) const SongListItem = defineAsyncComponent(() => import('@/components/song/SongListItem.vue'))
@ -97,10 +104,11 @@ const emit = defineEmits(['press:enter', 'press:delete', 'reorder', 'sort', 'scr
const items = inject(SongsKey, ref([])) const items = inject(SongsKey, ref([]))
const type = inject(SongListTypeKey, 'all-songs') const type = inject(SongListTypeKey, 'all-songs')
const selectedSongs = inject(SelectedSongsKey, ref([])) const selectedSongs = inject(SelectedSongsKey, ref([]))
const sortField = inject(SongListSortFieldKey, ref('title'))
const sortOrder = inject(SongListSortOrderKey, ref('asc'))
const lastSelectedRow = ref<SongRow>() const lastSelectedRow = ref<SongRow>()
const sortFields = ref<SongListSortField[]>([]) const sortFields = ref<SongListSortField[]>([])
const sortOrder = ref<SortOrder>('asc')
const songRows = ref<SongRow[]>([]) const songRows = ref<SongRow[]>([])
const allowReordering = type === 'queue' const allowReordering = type === 'queue'
@ -116,12 +124,6 @@ const config = computed((): SongListConfig => {
}, inject(SongListConfigKey, {})) }, inject(SongListConfigKey, {}))
}) })
const currentSortField = ref<SongListSortField | null>((() => {
if (type === 'album' || type === 'artist') return 'track'
if (type === 'search-results') return null
return config.value.sortable ? 'title' : null
})())
/** /**
* Since song objects themselves are shared by all song lists, we can't use them directly to * Since song objects themselves are shared by all song lists, we can't use them directly to
* determine their selection status (selected/unselected). Therefore, for each song list, we * determine their selection status (selected/unselected). Therefore, for each song list, we
@ -144,7 +146,7 @@ const sort = (field: SongListSortField) => {
return return
} }
currentSortField.value = field sortField.value = field
sortOrder.value = sortOrder.value === 'asc' ? 'desc' : 'asc' sortOrder.value = sortOrder.value === 'asc' ? 'desc' : 'asc'
emit('sort', field, sortOrder.value) emit('sort', field, sortOrder.value)

View file

@ -1,4 +1,4 @@
import { computed, getCurrentInstance, provide, reactive, Ref, ref } from 'vue' import { computed, provide, reactive, Ref, ref } from 'vue'
import isMobile from 'ismobilejs' import isMobile from 'ismobilejs'
import { orderBy } from 'lodash' import { orderBy } from 'lodash'
@ -9,14 +9,20 @@ import router from '@/router'
import ControlsToggle from '@/components/ui/ScreenControlsToggle.vue' import ControlsToggle from '@/components/ui/ScreenControlsToggle.vue'
import SongList from '@/components/song/SongList.vue' import SongList from '@/components/song/SongList.vue'
import SongListControls from '@/components/song/SongListControls.vue' import SongListControls from '@/components/song/SongListControls.vue'
import { SelectedSongsKey, SongListConfigKey, SongListTypeKey, SongsKey } from '@/symbols' import {
SelectedSongsKey,
SongListConfigKey,
SongListSortFieldKey,
SongListSortOrderKey,
SongListTypeKey,
SongsKey
} from '@/symbols'
export const useSongList = ( export const useSongList = (
songs: Ref<Song[]>, songs: Ref<Song[]>,
type: SongListType, type: SongListType,
config: Partial<SongListConfig> = {} config: Partial<SongListConfig> = {}
) => { ) => {
const vm = getCurrentInstance()
const songList = ref<InstanceType<typeof SongList>>() const songList = ref<InstanceType<typeof SongList>>()
const isPhone = isMobile.phone const isPhone = isMobile.phone
@ -50,32 +56,47 @@ export const useSongList = (
router.go('/queue') router.go('/queue')
} }
const sort = (sortField: SongListSortField | null, sortOrder: SortOrder) => { const sortField = ref<SongListSortField | null>(((): SongListSortField | null => {
if (!sortField) return if (type === 'album' || type === 'artist') return 'track'
if (type === 'search-results') return null
return config.sortable ? 'title' : null
})())
let sortFields: SongListSortField[] = [sortField] const sortOrder = ref<SortOrder>('asc')
if (sortField === 'track') { const sort = (by: SongListSortField | null = sortField.value, order: SortOrder = sortOrder.value) => {
if (!by) return
sortField.value = by
sortOrder.value = order
let sortFields: SongListSortField[] = [by]
if (by === 'track') {
sortFields.push('disc', 'title') sortFields.push('disc', 'title')
} else if (sortField === 'album_name') { } else if (by === 'album_name') {
sortFields.push('artist_name', 'track', 'disc', 'title') sortFields.push('artist_name', 'track', 'disc', 'title')
} else if (sortField === 'artist_name') { } else if (by === 'artist_name') {
sortFields.push('album_name', 'track', 'disc', 'title') sortFields.push('album_name', 'track', 'disc', 'title')
} }
songs.value = orderBy(songs.value, sortFields, sortOrder) songs.value = orderBy(songs.value, sortFields, order)
} }
provide(SongListTypeKey, type) provide(SongListTypeKey, type)
provide(SongsKey, songs) provide(SongsKey, songs)
provide(SelectedSongsKey, selectedSongs) provide(SelectedSongsKey, selectedSongs)
provide(SongListConfigKey, reactive(config)) provide(SongListConfigKey, reactive(config))
provide(SongListSortFieldKey, sortField)
provide(SongListSortOrderKey, sortOrder)
return { return {
SongList, SongList,
SongListControls, SongListControls,
ControlsToggle, ControlsToggle,
songs, songs,
sortField,
sortOrder,
duration, duration,
songList, songList,
selectedSongs, selectedSongs,

View file

@ -4,3 +4,5 @@ export const SongListTypeKey: InjectionKey<SongListType> = Symbol('SongListType'
export const SongsKey: InjectionKey<Ref<Song[]>> = Symbol('Songs') export const SongsKey: InjectionKey<Ref<Song[]>> = Symbol('Songs')
export const SelectedSongsKey: InjectionKey<Ref<Song[]>> = Symbol('SelectedSongs') export const SelectedSongsKey: InjectionKey<Ref<Song[]>> = Symbol('SelectedSongs')
export const SongListConfigKey: InjectionKey<Partial<SongListConfig>> = Symbol('SongListConfig') export const SongListConfigKey: InjectionKey<Partial<SongListConfig>> = Symbol('SongListConfig')
export const SongListSortFieldKey: InjectionKey<Ref<SongListSortField>> = Symbol('SongListSortField')
export const SongListSortOrderKey: InjectionKey<Ref<SortOrder>> = Symbol('SongListSortOrder')