mirror of
https://github.com/koel/koel
synced 2024-11-14 00:17:13 +00:00
fix: song controls disappear during filtering (#1864)
This commit is contained in:
parent
167494ce6d
commit
63f2dc5241
9 changed files with 32 additions and 17 deletions
|
@ -66,7 +66,7 @@ export default abstract class UnitTestCase {
|
||||||
commonStore.state.uses_i_tunes = true
|
commonStore.state.uses_i_tunes = true
|
||||||
commonStore.state.supports_batch_downloading = true
|
commonStore.state.supports_batch_downloading = true
|
||||||
commonStore.state.supports_transcoding = true
|
commonStore.state.supports_transcoding = true
|
||||||
cb && cb()
|
cb?.()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ export default abstract class UnitTestCase {
|
||||||
cleanup()
|
cleanup()
|
||||||
this.restoreAllMocks()
|
this.restoreAllMocks()
|
||||||
this.disablePlusEdition()
|
this.disablePlusEdition()
|
||||||
cb && cb()
|
cb?.()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default (faker: Faker): Podcast => {
|
||||||
description: faker.lorem.paragraph(),
|
description: faker.lorem.paragraph(),
|
||||||
author: faker.name.findName(),
|
author: faker.name.findName(),
|
||||||
subscribed_at: faker.date.past().toISOString(),
|
subscribed_at: faker.date.past().toISOString(),
|
||||||
created_at: faker.date.past().toISOString(),
|
last_played_at: faker.date.past().toISOString(),
|
||||||
state: {
|
state: {
|
||||||
current_episode: null,
|
current_episode: null,
|
||||||
progresses: {},
|
progresses: {},
|
||||||
|
|
|
@ -194,6 +194,11 @@ watch(playlistId, async id => {
|
||||||
// reset this config value to its default to not cause rows to be mal-rendered
|
// reset this config value to its default to not cause rows to be mal-rendered
|
||||||
listConfig.collaborative = false
|
listConfig.collaborative = false
|
||||||
|
|
||||||
|
// Since this component is responsible for all playlists, reset these values
|
||||||
|
// so that they're not shared between lists
|
||||||
|
songs.value = []
|
||||||
|
selectedPlayables.value = []
|
||||||
|
|
||||||
if (playlist.value) {
|
if (playlist.value) {
|
||||||
await fetchDetails()
|
await fetchDetails()
|
||||||
listConfig.collaborative = playlist.value.is_collaborative
|
listConfig.collaborative = playlist.value.is_collaborative
|
||||||
|
|
|
@ -4,10 +4,10 @@ import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||||
import factory from '@/__tests__/factory'
|
import factory from '@/__tests__/factory'
|
||||||
import { arrayify } from '@/utils/helpers'
|
import { arrayify } from '@/utils/helpers'
|
||||||
import {
|
import {
|
||||||
|
FilteredPlayablesKey,
|
||||||
PlayableListConfigKey,
|
PlayableListConfigKey,
|
||||||
PlayableListContextKey,
|
PlayableListContextKey,
|
||||||
PlayableListSortFieldKey,
|
PlayableListSortFieldKey,
|
||||||
PlayablesKey,
|
|
||||||
SelectedPlayablesKey,
|
SelectedPlayablesKey,
|
||||||
SongListSortOrderKey,
|
SongListSortOrderKey,
|
||||||
} from '@/symbols'
|
} from '@/symbols'
|
||||||
|
@ -54,7 +54,7 @@ new class extends UnitTestCase {
|
||||||
SongListHeader: this.stub('song-list-header'),
|
SongListHeader: this.stub('song-list-header'),
|
||||||
},
|
},
|
||||||
provide: {
|
provide: {
|
||||||
[<symbol>PlayablesKey]: [ref(songs)],
|
[<symbol>FilteredPlayablesKey]: [ref(songs)],
|
||||||
[<symbol>SelectedPlayablesKey]: [ref(selectedPlayables), (value: Playable[]) => (selectedPlayables = value)],
|
[<symbol>SelectedPlayablesKey]: [ref(selectedPlayables), (value: Playable[]) => (selectedPlayables = value)],
|
||||||
[<symbol>PlayableListConfigKey]: [config],
|
[<symbol>PlayableListConfigKey]: [config],
|
||||||
[<symbol>PlayableListContextKey]: [context],
|
[<symbol>PlayableListContextKey]: [context],
|
||||||
|
|
|
@ -48,10 +48,10 @@ import { queueStore } from '@/stores/queueStore'
|
||||||
import { useDraggable, useDroppable } from '@/composables/useDragAndDrop'
|
import { useDraggable, useDroppable } from '@/composables/useDragAndDrop'
|
||||||
import { playbackService } from '@/services/playbackService'
|
import { playbackService } from '@/services/playbackService'
|
||||||
import {
|
import {
|
||||||
|
FilteredPlayablesKey,
|
||||||
PlayableListConfigKey,
|
PlayableListConfigKey,
|
||||||
PlayableListContextKey,
|
PlayableListContextKey,
|
||||||
PlayableListSortFieldKey,
|
PlayableListSortFieldKey,
|
||||||
PlayablesKey,
|
|
||||||
SelectedPlayablesKey,
|
SelectedPlayablesKey,
|
||||||
} from '@/symbols'
|
} from '@/symbols'
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ const emit = defineEmits<{
|
||||||
const { startDragging } = useDraggable('playables')
|
const { startDragging } = useDraggable('playables')
|
||||||
const { getDroppedData, acceptsDrop } = useDroppable(['playables'])
|
const { getDroppedData, acceptsDrop } = useDroppable(['playables'])
|
||||||
|
|
||||||
const [playables] = requireInjection<[Ref<Playable[]>]>(PlayablesKey)
|
const [playables] = requireInjection<[Ref<Playable[]>]>(FilteredPlayablesKey)
|
||||||
const [selectedPlayables, setSelectedPlayables] = requireInjection<[Ref<Playable[]>, Closure]>(SelectedPlayablesKey)
|
const [selectedPlayables, setSelectedPlayables] = requireInjection<[Ref<Playable[]>, Closure]>(SelectedPlayablesKey)
|
||||||
const [sortField] = requireInjection<[Ref<MaybeArray<PlayableListSortField>>, Closure]>(PlayableListSortFieldKey)
|
const [sortField] = requireInjection<[Ref<MaybeArray<PlayableListSortField>>, Closure]>(PlayableListSortFieldKey)
|
||||||
const [config] = requireInjection<[Partial<PlayableListConfig>]>(PlayableListConfigKey, [{}])
|
const [config] = requireInjection<[Partial<PlayableListConfig>]>(PlayableListConfigKey, [{}])
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { ref } from 'vue'
|
||||||
import { expect, it } from 'vitest'
|
import { expect, it } from 'vitest'
|
||||||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||||
import factory from '@/__tests__/factory'
|
import factory from '@/__tests__/factory'
|
||||||
import { PlayablesKey, SelectedPlayablesKey } from '@/symbols'
|
import { FilteredPlayablesKey, PlayablesKey, SelectedPlayablesKey } from '@/symbols'
|
||||||
import SongListControls from './SongListControls.vue'
|
import SongListControls from './SongListControls.vue'
|
||||||
|
|
||||||
new class extends UnitTestCase {
|
new class extends UnitTestCase {
|
||||||
|
@ -79,6 +79,7 @@ new class extends UnitTestCase {
|
||||||
global: {
|
global: {
|
||||||
provide: {
|
provide: {
|
||||||
[<symbol>PlayablesKey]: [ref(songs)],
|
[<symbol>PlayablesKey]: [ref(songs)],
|
||||||
|
[<symbol>FilteredPlayablesKey]: [ref(songs)],
|
||||||
[<symbol>SelectedPlayablesKey]: [ref(take(songs, selectedSongCount))],
|
[<symbol>SelectedPlayablesKey]: [ref(take(songs, selectedSongCount))],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<BtnGroup uppercase>
|
<BtnGroup uppercase>
|
||||||
<template v-if="altPressed">
|
<template v-if="altPressed">
|
||||||
<Btn
|
<Btn
|
||||||
v-if="selectedPlayables.length < 2 && playables.length"
|
v-if="selectedPlayables.length < 2 && filteredPlayables.length"
|
||||||
v-koel-tooltip.bottom
|
v-koel-tooltip.bottom
|
||||||
class="btn-play-all"
|
class="btn-play-all"
|
||||||
highlight
|
highlight
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<Btn
|
<Btn
|
||||||
v-if="selectedPlayables.length < 2 && playables.length"
|
v-if="selectedPlayables.length < 2 && filteredPlayables.length"
|
||||||
v-koel-tooltip.bottom
|
v-koel-tooltip.bottom
|
||||||
class="btn-shuffle-all"
|
class="btn-shuffle-all"
|
||||||
data-testid="btn-shuffle-all"
|
data-testid="btn-shuffle-all"
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
</Btn>
|
</Btn>
|
||||||
</BtnGroup>
|
</BtnGroup>
|
||||||
|
|
||||||
<BtnGroup v-if="config.filter && playables.length">
|
<BtnGroup v-if="config.filter && allPlayables.length">
|
||||||
<SongListFilter @change="filter" />
|
<SongListFilter @change="filter" />
|
||||||
</BtnGroup>
|
</BtnGroup>
|
||||||
</div>
|
</div>
|
||||||
|
@ -103,7 +103,7 @@ import { faPlay, faRandom, faRotateRight, faTrashCan } from '@fortawesome/free-s
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue'
|
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue'
|
||||||
import { OnClickOutside } from '@vueuse/components'
|
import { OnClickOutside } from '@vueuse/components'
|
||||||
import { PlayablesKey, SelectedPlayablesKey } from '@/symbols'
|
import { FilteredPlayablesKey, PlayablesKey, SelectedPlayablesKey } from '@/symbols'
|
||||||
import { requireInjection } from '@/utils/helpers'
|
import { requireInjection } from '@/utils/helpers'
|
||||||
import { useFloatingUi } from '@/composables/useFloatingUi'
|
import { useFloatingUi } from '@/composables/useFloatingUi'
|
||||||
|
|
||||||
|
@ -123,7 +123,8 @@ const SongListFilter = defineAsyncComponent(() => import('@/components/song/song
|
||||||
|
|
||||||
const config = toRef(props, 'config')
|
const config = toRef(props, 'config')
|
||||||
|
|
||||||
const [playables] = requireInjection<[Ref<Playable[]>]>(PlayablesKey)
|
const [allPlayables] = requireInjection<[Ref<Playable[]>]>(PlayablesKey)
|
||||||
|
const [filteredPlayables] = requireInjection<[Ref<Playable[]>]>(FilteredPlayablesKey)
|
||||||
const [selectedPlayables] = requireInjection(SelectedPlayablesKey)
|
const [selectedPlayables] = requireInjection(SelectedPlayablesKey)
|
||||||
|
|
||||||
const addToButton = ref<InstanceType<typeof Btn>>()
|
const addToButton = ref<InstanceType<typeof Btn>>()
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { useFuzzySearch } from '@/composables/useFuzzySearch'
|
||||||
import { useRouter } from '@/composables/useRouter'
|
import { useRouter } from '@/composables/useRouter'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
FilteredPlayablesKey,
|
||||||
PlayableListConfigKey,
|
PlayableListConfigKey,
|
||||||
PlayableListContextKey,
|
PlayableListContextKey,
|
||||||
PlayableListSortFieldKey,
|
PlayableListSortFieldKey,
|
||||||
|
@ -40,7 +41,7 @@ export const useSongList = (
|
||||||
config = reactive(config)
|
config = reactive(config)
|
||||||
context = reactive(context)
|
context = reactive(context)
|
||||||
|
|
||||||
const { isCurrentScreen, go } = useRouter()
|
const { isCurrentScreen, go, url } = useRouter()
|
||||||
|
|
||||||
const fuzzy = config.filterable
|
const fuzzy = config.filterable
|
||||||
? useFuzzySearch(playables, [
|
? useFuzzySearch(playables, [
|
||||||
|
@ -64,12 +65,15 @@ export const useSongList = (
|
||||||
if (!config.sortable) {
|
if (!config.sortable) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCurrentScreen('Artist', 'Album')) {
|
if (isCurrentScreen('Artist', 'Album')) {
|
||||||
return 'track'
|
return 'track'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCurrentScreen('Search.Songs', 'Queue', 'RecentlyPlayed')) {
|
if (isCurrentScreen('Search.Songs', 'Queue', 'RecentlyPlayed')) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'title'
|
return 'title'
|
||||||
})())
|
})())
|
||||||
|
|
||||||
|
@ -108,9 +112,11 @@ export const useSongList = (
|
||||||
if (!commonStore.state.allows_download) {
|
if (!commonStore.state.allows_download) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playables.value.length === 0) {
|
if (playables.value.length === 0) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return playables.value.length === 1 || commonStore.state.supports_batch_downloading
|
return playables.value.length === 1 || commonStore.state.supports_batch_downloading
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -127,7 +133,7 @@ export const useSongList = (
|
||||||
|
|
||||||
const playAll = (shuffle: boolean) => {
|
const playAll = (shuffle: boolean) => {
|
||||||
playbackService.queueAndPlay(getPlayablesToPlay(), shuffle)
|
playbackService.queueAndPlay(getPlayablesToPlay(), shuffle)
|
||||||
go('queue')
|
go(url('queue'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const playSelected = (shuffle: boolean) => playbackService.queueAndPlay(selectedPlayables.value, shuffle)
|
const playSelected = (shuffle: boolean) => playbackService.queueAndPlay(selectedPlayables.value, shuffle)
|
||||||
|
@ -185,7 +191,8 @@ export const useSongList = (
|
||||||
|
|
||||||
eventBus.on('SONGS_DELETED', deletedSongs => (playables.value = differenceBy(playables.value, deletedSongs, 'id')))
|
eventBus.on('SONGS_DELETED', deletedSongs => (playables.value = differenceBy(playables.value, deletedSongs, 'id')))
|
||||||
|
|
||||||
provideReadonly(PlayablesKey, filteredPlayables, false)
|
provideReadonly(PlayablesKey, playables, false)
|
||||||
|
provideReadonly(FilteredPlayablesKey, filteredPlayables, false)
|
||||||
provideReadonly(SelectedPlayablesKey, selectedPlayables, false)
|
provideReadonly(SelectedPlayablesKey, selectedPlayables, false)
|
||||||
provideReadonly(PlayableListConfigKey, config)
|
provideReadonly(PlayableListConfigKey, config)
|
||||||
provideReadonly(PlayableListContextKey, context)
|
provideReadonly(PlayableListContextKey, context)
|
||||||
|
|
|
@ -11,7 +11,8 @@ export const OverlayKey: InjectionKey<Ref<InstanceType<typeof Overlay>>> = Symbo
|
||||||
export const DialogBoxKey: InjectionKey<Ref<InstanceType<typeof DialogBox>>> = Symbol('DialogBox')
|
export const DialogBoxKey: InjectionKey<Ref<InstanceType<typeof DialogBox>>> = Symbol('DialogBox')
|
||||||
export const MessageToasterKey: InjectionKey<Ref<InstanceType<typeof MessageToaster>>> = Symbol('MessageToaster')
|
export const MessageToasterKey: InjectionKey<Ref<InstanceType<typeof MessageToaster>>> = Symbol('MessageToaster')
|
||||||
|
|
||||||
export const PlayablesKey: ReadonlyInjectionKey<Ref<Playable[]>> | InjectionKey<Ref<Playable[]>> = Symbol('Playables')
|
export const PlayablesKey: ReadonlyInjectionKey<Ref<Playable[]>> | InjectionKey<Ref<Playable[]>> = Symbol('PlayablesKey')
|
||||||
|
export const FilteredPlayablesKey: ReadonlyInjectionKey<Ref<Playable[]>> | InjectionKey<Ref<Playable[]>> = Symbol('FilteredPlayablesKey')
|
||||||
export const CurrentPlayableKey: InjectionKey<Ref<Playable | undefined>> = Symbol('CurrentPlayable')
|
export const CurrentPlayableKey: InjectionKey<Ref<Playable | undefined>> = Symbol('CurrentPlayable')
|
||||||
export const SelectedPlayablesKey: ReadonlyInjectionKey<Ref<Playable[]>> = Symbol('SelectedPlayables')
|
export const SelectedPlayablesKey: ReadonlyInjectionKey<Ref<Playable[]>> = Symbol('SelectedPlayables')
|
||||||
export const PlayableListConfigKey: ReadonlyInjectionKey<Partial<PlayableListConfig>> = Symbol('SongListConfig')
|
export const PlayableListConfigKey: ReadonlyInjectionKey<Partial<PlayableListConfig>> = Symbol('SongListConfig')
|
||||||
|
|
Loading…
Reference in a new issue