Merge c640dc5ec5
into 3d64ca37e7
commit
7a1fd82ddd
|
@ -3,7 +3,10 @@
|
||||||
<layout-aside id="left" />
|
<layout-aside id="left" />
|
||||||
<div id="right">
|
<div id="right">
|
||||||
<layout-toolbar id="toolbar" />
|
<layout-toolbar id="toolbar" />
|
||||||
<layout-view id="view" />
|
<div class="middle">
|
||||||
|
<layout-view id="view" />
|
||||||
|
<layout-play-list-window v-if="isShowPlaylist" id="playlist" @close="closePlaylist" />
|
||||||
|
</div>
|
||||||
<layout-play-bar id="player" />
|
<layout-play-bar id="player" />
|
||||||
</div>
|
</div>
|
||||||
<layout-icons />
|
<layout-icons />
|
||||||
|
@ -18,45 +21,32 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted } from '@common/utils/vueTools'
|
import { onMounted } from '@common/utils/vueTools'
|
||||||
// import BubbleCursor from '@common/utils/effects/cursor-effects/bubbleCursor'
|
|
||||||
// import '@common/utils/effects/snow.min'
|
|
||||||
import useApp from '@renderer/core/useApp'
|
import useApp from '@renderer/core/useApp'
|
||||||
|
import { isShowPlaylist } from '@renderer/store/player/state'
|
||||||
|
import { setShowPlaylist } from '@renderer/store/player/action'
|
||||||
|
|
||||||
|
const closePlaylist = () => {
|
||||||
|
setShowPlaylist(false)
|
||||||
|
}
|
||||||
|
|
||||||
useApp()
|
useApp()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.getElementById('root').style.display = 'block'
|
document.getElementById('root').style.display = 'block'
|
||||||
|
|
||||||
// const styles = getComputedStyle(document.documentElement)
|
|
||||||
// window.lxData.bubbleCursor = new BubbleCursor({
|
|
||||||
// fillStyle: styles.getPropertyValue('--color-primary-alpha-900'),
|
|
||||||
// strokeStyle: styles.getPropertyValue('--color-primary-alpha-700'),
|
|
||||||
// })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// onBeforeUnmount(() => {
|
|
||||||
// window.lxData.bubbleCursor?.destroy()
|
|
||||||
// })
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import './assets/styles/index.less';
|
@import './assets/styles/index.less';
|
||||||
@import './assets/styles/layout.less';
|
@import './assets/styles/layout.less';
|
||||||
|
|
||||||
html {
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
html, body {
|
html, body {
|
||||||
// overflow: hidden;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
|
||||||
user-select: none;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
#root {
|
#root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -69,58 +59,6 @@ body {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.disableAnimation * {
|
|
||||||
transition: none !important;
|
|
||||||
animation: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transparent {
|
|
||||||
background: transparent;
|
|
||||||
padding: @shadow-app;
|
|
||||||
// #waiting-mask {
|
|
||||||
// border-radius: @radius-border;
|
|
||||||
// left: @shadow-app;
|
|
||||||
// right: @shadow-app;
|
|
||||||
// top: @shadow-app;
|
|
||||||
// bottom: @shadow-app;
|
|
||||||
// }
|
|
||||||
#body {
|
|
||||||
border-radius: @radius-border;
|
|
||||||
}
|
|
||||||
#root {
|
|
||||||
box-shadow: 0 0 @shadow-app rgba(0, 0, 0, 0.5);
|
|
||||||
border-radius: @radius-border;
|
|
||||||
}
|
|
||||||
// #container {
|
|
||||||
// border-radius: @radius-border;
|
|
||||||
// background-color: transparent;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
.disableTransparent {
|
|
||||||
background-color: var(--color-content-background);
|
|
||||||
|
|
||||||
#body {
|
|
||||||
border: 1Px solid var(--color-primary-light-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
#right {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// #view { // 偏移5px距离解决非透明模式下右侧滚动条无法拖动的问题
|
|
||||||
// margin-right: 5Px;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
.fullscreen {
|
|
||||||
background-color: var(--color-content-background);
|
|
||||||
|
|
||||||
#right {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -132,17 +70,21 @@ body {
|
||||||
flex: none;
|
flex: none;
|
||||||
width: @width-app-left;
|
width: @width-app-left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#right {
|
#right {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-direction: column;
|
||||||
transition: background-color @transition-normal;
|
|
||||||
background-color: var(--color-main-background);
|
background-color: var(--color-main-background);
|
||||||
|
|
||||||
border-top-left-radius: @radius-border;
|
border-top-left-radius: @radius-border;
|
||||||
border-bottom-left-radius: @radius-border;
|
border-bottom-left-radius: @radius-border;
|
||||||
overflow: hidden;
|
}
|
||||||
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1);
|
|
||||||
|
.middle {
|
||||||
|
flex: auto;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
min-height: 0;
|
||||||
}
|
}
|
||||||
#toolbar, #player {
|
#toolbar, #player {
|
||||||
flex: none;
|
flex: none;
|
||||||
|
@ -157,12 +99,15 @@ body {
|
||||||
.view-container {
|
.view-container {
|
||||||
transition: opacity @transition-normal;
|
transition: opacity @transition-normal;
|
||||||
}
|
}
|
||||||
#root.show-modal > .view-container {
|
#playlist {
|
||||||
opacity: .9;
|
position: absolute;
|
||||||
}
|
top: 0;
|
||||||
#view.show-modal > .view-container {
|
right: 0;
|
||||||
opacity: .2;
|
width: 320px;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 1000;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 0 10px rgba(0,0,0,0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<template>
|
||||||
|
<button class="playlist-button" @click="togglePlaylist">
|
||||||
|
🎵 播放列表
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { isShowPlaylist } from '@renderer/store/player/state'
|
||||||
|
import { setShowPlaylist } from '@renderer/store/player/action'
|
||||||
|
const togglePlaylist = () => {
|
||||||
|
setShowPlaylist(!isShowPlaylist.value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.playlist-button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #4caf50;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.playlist-button:hover {
|
||||||
|
background-color: #45a049;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -43,7 +43,7 @@
|
||||||
</button>
|
</button>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div :class="$style.setting">
|
<div :class="$style.setting">
|
||||||
<button :class="$style.btn" :aria-label="$t('player__play_toggle_mode_list_loop')" @click="toggleMode('listLoop')">
|
<button :class="$style.btn" :aria-label="$t('player__play_toggle_mode_list_loop')" @click="toggleMode('listLoop')"><!-- //todo直接把顺序播放删了然后把图标接到播放列表头上,反正这个模式和列表循环一模一样 -->
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 24 24" space="preserve">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 24 24" space="preserve">
|
||||||
<use xlink:href="#icon-list-loop" />
|
<use xlink:href="#icon-list-loop" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
<common-volume-btn />
|
<common-volume-btn />
|
||||||
<common-toggle-play-mode-btn />
|
<common-toggle-play-mode-btn />
|
||||||
<common-list-add-modal v-model:show="isShowAddMusicTo" :music-info="playMusicInfo.musicInfo" />
|
<common-list-add-modal v-model:show="isShowAddMusicTo" :music-info="playMusicInfo.musicInfo" />
|
||||||
|
<common-play-list-button />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
<template>
|
||||||
|
<div class="playlist-window">
|
||||||
|
<button class="close-button" @click="emitClose">✖</button>
|
||||||
|
<h2 class="title">播放列表</h2>
|
||||||
|
<div class="song-list">
|
||||||
|
<div
|
||||||
|
v-for="(song, index) in songs"
|
||||||
|
:key="index"
|
||||||
|
class="song-item"
|
||||||
|
:class="[
|
||||||
|
{ active: currentPlayIndexValue === index },
|
||||||
|
{ selected: selectedIndex === index || rightClickSelectedIndex === index }
|
||||||
|
]"
|
||||||
|
@click="handleListItemClick(index)"
|
||||||
|
@contextmenu.prevent="handleListItemRightClick(index, $event)"
|
||||||
|
>
|
||||||
|
<div class="song-index">{{ index + 1 }}</div>
|
||||||
|
<div class="song-info">
|
||||||
|
<div class="song-title">{{ song.title }}</div>
|
||||||
|
<div class="song-meta">{{ song.artist }} · {{ song.album }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, toRef } from 'vue'
|
||||||
|
import { tempPlayList, currentPlaybackOrder, currentPlayIndex } from '@renderer/store/player/state'
|
||||||
|
|
||||||
|
// 为了模板里更方便使用 .value,这里取一个普通变量
|
||||||
|
const currentPlayIndexValue = toRef(currentPlayIndex, 'value')
|
||||||
|
|
||||||
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
|
// 把 ref 数组转成本地 reactive 引用
|
||||||
|
const playlist = ref(tempPlayList)
|
||||||
|
|
||||||
|
// 计算渲染顺序后的歌曲信息列表
|
||||||
|
const songs = computed(() => {
|
||||||
|
const showlist = []
|
||||||
|
for (const idx of currentPlaybackOrder.value) {
|
||||||
|
const info = playlist.value[idx]
|
||||||
|
if (info?.musicInfo) {
|
||||||
|
showlist.push({
|
||||||
|
title: info.musicInfo.name,
|
||||||
|
artist: info.musicInfo.singer,
|
||||||
|
album: info.musicInfo.meta.albumName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return showlist
|
||||||
|
})
|
||||||
|
|
||||||
|
// 本地控制的“选中”索引
|
||||||
|
const selectedIndex = ref(null)
|
||||||
|
const rightClickSelectedIndex = ref(null)
|
||||||
|
|
||||||
|
// 点击选中
|
||||||
|
function handleListItemClick(index) {
|
||||||
|
selectedIndex.value = index
|
||||||
|
// 也可以在这里改变 currentPlayIndex
|
||||||
|
currentPlayIndex.value = index
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右键选中
|
||||||
|
function handleListItemRightClick(index, event) {
|
||||||
|
rightClickSelectedIndex.value = index
|
||||||
|
// 这里你可以记录 event.clientX/Y 来显示菜单
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭按钮
|
||||||
|
function emitClose() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.playlist-window {
|
||||||
|
background-color: #222;
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 320px;
|
||||||
|
max-height: 80%;
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关闭按钮 */
|
||||||
|
.close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
background: transparent;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题 */
|
||||||
|
.title {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 歌曲列表容器 */
|
||||||
|
.song-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 交替背景:奇数白色,偶数浅灰 */
|
||||||
|
.song-item:nth-child(2n-1) {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
.song-item:nth-child(2n) {
|
||||||
|
background-color: #f5f5f5; /* 很浅的灰 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 通用样式 */
|
||||||
|
.song-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
|
color: black; /* 字体统一黑色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hover 状态稍微加深一下 */
|
||||||
|
.song-item:hover {
|
||||||
|
background-color: #eaeaea!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当前播放项高亮(深灰) */
|
||||||
|
.active {
|
||||||
|
background-color: #EBEBEB ;
|
||||||
|
color: black ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选中(左键或右键)状态,更深的灰 */
|
||||||
|
.selected {
|
||||||
|
background-color: #ebebeb ;
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 序号 */
|
||||||
|
.song-index {
|
||||||
|
width: 24px;
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #666666;
|
||||||
|
font-size: 14px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 歌曲信息 */
|
||||||
|
.song-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题 */
|
||||||
|
.song-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 元信息(歌手 · 专辑) */
|
||||||
|
.song-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #444444;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -17,7 +17,7 @@ export default ({ selectedList, props, removeAllSelect, emit }: {
|
||||||
}) => {
|
}) => {
|
||||||
let clickTime = 0
|
let clickTime = 0
|
||||||
let clickIndex = -1
|
let clickIndex = -1
|
||||||
|
// todo 待接管
|
||||||
const handlePlayMusic = async(index: number, single: boolean) => {
|
const handlePlayMusic = async(index: number, single: boolean) => {
|
||||||
let targetSong = props.list[index]
|
let targetSong = props.list[index]
|
||||||
const defaultListMusics = await getListMusics(defaultList.id)
|
const defaultListMusics = await getListMusics(defaultList.id)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { isEmpty, setPause, setPlay, setResource, setStop } from '@renderer/plugins/player'
|
import { isEmpty, setPause, setPlay, setResource, setStop } from '@renderer/plugins/player'
|
||||||
import { isPlay, playedList, playInfo, playMusicInfo, tempPlayList, musicInfo as _musicInfo } from '@renderer/store/player/state'
|
import { isPlay, playedList, playInfo, playMusicInfo, tempPlayList, musicInfo as _musicInfo, currentPlayIndex, currentPlaybackOrder } from '@renderer/store/player/state'
|
||||||
import {
|
import {
|
||||||
getList,
|
getList,
|
||||||
clearPlayedList,
|
clearPlayedList,
|
||||||
|
@ -148,6 +148,7 @@ export const setMusicUrl = (musicInfo: LX.Music.MusicInfo | LX.Download.ListItem
|
||||||
|
|
||||||
// 恢复上次播放的状态
|
// 恢复上次播放的状态
|
||||||
const handleRestorePlay = async(restorePlayInfo: LX.Player.SavedPlayInfo) => {
|
const handleRestorePlay = async(restorePlayInfo: LX.Player.SavedPlayInfo) => {
|
||||||
|
// todo 恢复软件关闭时tempplaylist的状态
|
||||||
const musicInfo = playMusicInfo.musicInfo
|
const musicInfo = playMusicInfo.musicInfo
|
||||||
if (!musicInfo) return
|
if (!musicInfo) return
|
||||||
|
|
||||||
|
@ -243,7 +244,7 @@ export const playListById = (listId: string, id: string) => {
|
||||||
// pause()
|
// pause()
|
||||||
const musicInfo = getList(listId).find(m => m.id == id)
|
const musicInfo = getList(listId).find(m => m.id == id)
|
||||||
if (!musicInfo) return
|
if (!musicInfo) return
|
||||||
setPlayMusicInfo(listId, musicInfo)
|
setPlayMusicInfo(listId, musicInfo)//todo 设置播放音乐
|
||||||
if (appSetting['player.isAutoCleanPlayedList'] || prevListId != listId) clearPlayedList()
|
if (appSetting['player.isAutoCleanPlayedList'] || prevListId != listId) clearPlayedList()
|
||||||
clearTempPlayeList()
|
clearTempPlayeList()
|
||||||
handlePlay()
|
handlePlay()
|
||||||
|
@ -258,7 +259,7 @@ export const playList = (listId: string, index: number) => {
|
||||||
const prevListId = playInfo.playerListId
|
const prevListId = playInfo.playerListId
|
||||||
setPlayListId(listId)
|
setPlayListId(listId)
|
||||||
// pause()
|
// pause()
|
||||||
setPlayMusicInfo(listId, getList(listId)[index])
|
setPlayMusicInfo(listId, getList(listId)[index])//todo 设置播放音乐
|
||||||
if (appSetting['player.isAutoCleanPlayedList'] || prevListId != listId) clearPlayedList()
|
if (appSetting['player.isAutoCleanPlayedList'] || prevListId != listId) clearPlayedList()
|
||||||
clearTempPlayeList()
|
clearTempPlayeList()
|
||||||
handlePlay()
|
handlePlay()
|
||||||
|
@ -339,7 +340,7 @@ export const getNextPlayMusicInfo = async(): Promise<LX.Player.PlayMusicInfo | n
|
||||||
nextIndex = playerIndex === filteredList.length - 1 ? 0 : playerIndex + 1
|
nextIndex = playerIndex === filteredList.length - 1 ? 0 : playerIndex + 1
|
||||||
break
|
break
|
||||||
case 'random':
|
case 'random':
|
||||||
nextIndex = getRandom(0, filteredList.length)
|
nextIndex = getRandom(0, filteredList.length)//todo
|
||||||
break
|
break
|
||||||
case 'list':
|
case 'list':
|
||||||
nextIndex = playerIndex === filteredList.length - 1 ? -1 : playerIndex + 1
|
nextIndex = playerIndex === filteredList.length - 1 ? -1 : playerIndex + 1
|
||||||
|
@ -364,9 +365,9 @@ export const getNextPlayMusicInfo = async(): Promise<LX.Player.PlayMusicInfo | n
|
||||||
return nextPlayMusicInfo
|
return nextPlayMusicInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePlayNext = (playMusicInfo: LX.Player.PlayMusicInfo) => {
|
export const handlePlayNext = (playMusicInfo: LX.Player.PlayMusicInfo) => {
|
||||||
// pause()
|
// pause()
|
||||||
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)
|
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)//todo 设置播放音乐
|
||||||
handlePlay()
|
handlePlay()
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -376,14 +377,41 @@ const handlePlayNext = (playMusicInfo: LX.Player.PlayMusicInfo) => {
|
||||||
*/
|
*/
|
||||||
export const playNext = async(isAutoToggle = false): Promise<void> => {
|
export const playNext = async(isAutoToggle = false): Promise<void> => {
|
||||||
console.log('skip next', isAutoToggle)
|
console.log('skip next', isAutoToggle)
|
||||||
|
let togglePlayMethod = appSetting['player.togglePlayMethod']
|
||||||
|
if (!isAutoToggle) {
|
||||||
|
switch (togglePlayMethod) {
|
||||||
|
case 'list':
|
||||||
|
case 'singleLoop':
|
||||||
|
case 'none':
|
||||||
|
togglePlayMethod = 'listLoop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (togglePlayMethod) {
|
||||||
|
case 'listLoop':
|
||||||
|
currentPlayIndex.value++
|
||||||
|
// bug 实际上不是列表循环...
|
||||||
|
break
|
||||||
|
case 'random':
|
||||||
|
currentPlayIndex.value++
|
||||||
|
break
|
||||||
|
case 'list':
|
||||||
|
currentPlayIndex.value++
|
||||||
|
break
|
||||||
|
case 'singleLoop':
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
currentPlayIndex.value = -1
|
||||||
|
console.log('stop toggle play', togglePlayMethod, isAutoToggle)
|
||||||
|
return
|
||||||
|
}
|
||||||
if (tempPlayList.length) { // 如果稍后播放列表存在歌曲则直接播放改列表的歌曲
|
if (tempPlayList.length) { // 如果稍后播放列表存在歌曲则直接播放改列表的歌曲
|
||||||
const playMusicInfo = tempPlayList[0]
|
const playMusicInfo = tempPlayList[currentPlaybackOrder.value[currentPlayIndex.value]]
|
||||||
removeTempPlayList(0)
|
// removeTempPlayList(0)
|
||||||
handlePlayNext(playMusicInfo)
|
handlePlayNext(playMusicInfo)
|
||||||
console.log('play temp list')
|
console.log('play temp list')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
////////////预计此处往下的代码失去作用(被接管)/////////////
|
||||||
if (playMusicInfo.musicInfo == null) {
|
if (playMusicInfo.musicInfo == null) {
|
||||||
handleToggleStop()
|
handleToggleStop()
|
||||||
console.log('musicInfo empty')
|
console.log('musicInfo empty')
|
||||||
|
@ -447,32 +475,32 @@ export const playNext = async(isAutoToggle = false): Promise<void> => {
|
||||||
if (playerIndex == -1 && filteredList.length) playerIndex = 0
|
if (playerIndex == -1 && filteredList.length) playerIndex = 0
|
||||||
let nextIndex = playerIndex
|
let nextIndex = playerIndex
|
||||||
|
|
||||||
let togglePlayMethod = appSetting['player.togglePlayMethod']
|
// let togglePlayMethod = appSetting['player.togglePlayMethod']
|
||||||
if (!isAutoToggle) {
|
// if (!isAutoToggle) {
|
||||||
switch (togglePlayMethod) {
|
// switch (togglePlayMethod) {
|
||||||
case 'list':
|
// case 'list':
|
||||||
case 'singleLoop':
|
// case 'singleLoop':
|
||||||
case 'none':
|
// case 'none':
|
||||||
togglePlayMethod = 'listLoop'
|
// togglePlayMethod = 'listLoop'
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
switch (togglePlayMethod) {
|
// switch (togglePlayMethod) {
|
||||||
case 'listLoop':
|
// case 'listLoop':
|
||||||
nextIndex = playerIndex === filteredList.length - 1 ? 0 : playerIndex + 1
|
// nextIndex = playerIndex === filteredList.length - 1 ? 0 : playerIndex + 1
|
||||||
break
|
// break
|
||||||
case 'random':
|
// case 'random':
|
||||||
nextIndex = getRandom(0, filteredList.length)
|
// nextIndex = getRandom(0, filteredList.length)
|
||||||
break
|
// break
|
||||||
case 'list':
|
// case 'list':
|
||||||
nextIndex = playerIndex === filteredList.length - 1 ? -1 : playerIndex + 1
|
// nextIndex = playerIndex === filteredList.length - 1 ? -1 : playerIndex + 1
|
||||||
break
|
// break
|
||||||
case 'singleLoop':
|
// case 'singleLoop':
|
||||||
break
|
// break
|
||||||
default:
|
// default:
|
||||||
nextIndex = -1
|
// nextIndex = -1
|
||||||
console.log('stop toggle play', togglePlayMethod, isAutoToggle)
|
// console.log('stop toggle play', togglePlayMethod, isAutoToggle)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
if (nextIndex < 0) {
|
if (nextIndex < 0) {
|
||||||
console.log('next index empty')
|
console.log('next index empty')
|
||||||
return
|
return
|
||||||
|
@ -489,6 +517,42 @@ export const playNext = async(isAutoToggle = false): Promise<void> => {
|
||||||
* 上一曲
|
* 上一曲
|
||||||
*/
|
*/
|
||||||
export const playPrev = async(isAutoToggle = false): Promise<void> => {
|
export const playPrev = async(isAutoToggle = false): Promise<void> => {
|
||||||
|
// todo 重复代码块,可以提取
|
||||||
|
let togglePlayMethod = appSetting['player.togglePlayMethod']
|
||||||
|
if (!isAutoToggle) {
|
||||||
|
switch (togglePlayMethod) {
|
||||||
|
case 'list':
|
||||||
|
case 'singleLoop':
|
||||||
|
case 'none':
|
||||||
|
togglePlayMethod = 'listLoop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (togglePlayMethod) {
|
||||||
|
case 'listLoop':
|
||||||
|
currentPlayIndex.value--
|
||||||
|
// bug 实际上不是列表循环...
|
||||||
|
break
|
||||||
|
case 'random':
|
||||||
|
currentPlayIndex.value--
|
||||||
|
break
|
||||||
|
case 'list':
|
||||||
|
currentPlayIndex.value--
|
||||||
|
break
|
||||||
|
case 'singleLoop':
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
currentPlayIndex.value = -1
|
||||||
|
console.log('stop toggle play', togglePlayMethod, isAutoToggle)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentPlayIndex.value > 0) { // 如果稍后播放列表存在歌曲则直接播放改列表的歌曲
|
||||||
|
const playMusicInfo = tempPlayList[currentPlaybackOrder.value[currentPlayIndex.value]]
|
||||||
|
// removeTempPlayList(0)
|
||||||
|
handlePlayNext(playMusicInfo)
|
||||||
|
console.log('play temp list')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
////////////预计此处往下的代码失去作用(被接管)/////////////
|
||||||
if (playMusicInfo.musicInfo == null) {
|
if (playMusicInfo.musicInfo == null) {
|
||||||
handleToggleStop()
|
handleToggleStop()
|
||||||
return
|
return
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
playMusicInfo,
|
playMusicInfo,
|
||||||
playedList,
|
playedList,
|
||||||
tempPlayList,
|
tempPlayList,
|
||||||
|
isShowPlaylist,
|
||||||
} from './state'
|
} from './state'
|
||||||
import { getListMusicsFromCache } from '@renderer/store/list/action'
|
import { getListMusicsFromCache } from '@renderer/store/list/action'
|
||||||
import { downloadList } from '@renderer/store/download/state'
|
import { downloadList } from '@renderer/store/download/state'
|
||||||
|
@ -61,6 +62,10 @@ export const setShowPlayerDetail = (val: boolean) => {
|
||||||
isShowPlayerDetail.value = val
|
isShowPlayerDetail.value = val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const setShowPlaylist = (val: boolean) => {
|
||||||
|
isShowPlaylist.value = val
|
||||||
|
}
|
||||||
|
|
||||||
export const setShowPlayComment = (val: boolean) => {
|
export const setShowPlayComment = (val: boolean) => {
|
||||||
isShowPlayComment.value = val
|
isShowPlayComment.value = val
|
||||||
}
|
}
|
||||||
|
@ -223,8 +228,10 @@ export const clearPlayedList = () => {
|
||||||
/**
|
/**
|
||||||
* 添加歌曲到稍后播放列表
|
* 添加歌曲到稍后播放列表
|
||||||
* @param list 歌曲列表
|
* @param list 歌曲列表
|
||||||
*/
|
*///todo
|
||||||
export const addTempPlayList = (list: LX.Player.TempPlayListItem[]) => {
|
export const addTempPlayList = (list: LX.Player.TempPlayListItem[]) => {
|
||||||
|
// todo 添加到下一首播放而不是到最后一首
|
||||||
|
// todo 重复歌曲不添加
|
||||||
const topList: Array<Omit<LX.Player.TempPlayListItem, 'top'>> = []
|
const topList: Array<Omit<LX.Player.TempPlayListItem, 'top'>> = []
|
||||||
const bottomList = list.filter(({ isTop, ...musicInfo }) => {
|
const bottomList = list.filter(({ isTop, ...musicInfo }) => {
|
||||||
if (isTop) {
|
if (isTop) {
|
||||||
|
@ -236,7 +243,8 @@ export const addTempPlayList = (list: LX.Player.TempPlayListItem[]) => {
|
||||||
if (topList.length) arrUnshift(tempPlayList, topList.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true })))
|
if (topList.length) arrUnshift(tempPlayList, topList.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true })))
|
||||||
if (bottomList.length) arrPush(tempPlayList, bottomList.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true })))
|
if (bottomList.length) arrPush(tempPlayList, bottomList.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true })))
|
||||||
|
|
||||||
if (!playMusicInfo.musicInfo) void playNext()
|
// if (!playMusicInfo.musicInfo) void playNext()
|
||||||
|
// 造成了奇怪的bug
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 从稍后播放列表移除歌曲
|
* 从稍后播放列表移除歌曲
|
||||||
|
|
|
@ -36,6 +36,8 @@ export const statusText = ref('')
|
||||||
|
|
||||||
export const isShowPlayerDetail = ref(false)
|
export const isShowPlayerDetail = ref(false)
|
||||||
|
|
||||||
|
export const isShowPlaylist = ref(false)
|
||||||
|
|
||||||
export const isShowPlayComment = ref(false)
|
export const isShowPlayComment = ref(false)
|
||||||
|
|
||||||
export const isShowLrcSelectContent = ref(false)
|
export const isShowLrcSelectContent = ref(false)
|
||||||
|
@ -69,5 +71,9 @@ export const playedList = window.lxData.playedList = shallowReactive<LX.Player.P
|
||||||
|
|
||||||
export const tempPlayList = shallowReactive<LX.Player.PlayMusicInfo[]>([])
|
export const tempPlayList = shallowReactive<LX.Player.PlayMusicInfo[]>([])
|
||||||
|
|
||||||
|
export const currentPlayIndex = ref<number>(0)
|
||||||
|
|
||||||
|
export const currentPlaybackOrder = ref<number[]>([])
|
||||||
|
|
||||||
window.lxData.playInfo = playInfo
|
window.lxData.playInfo = playInfo
|
||||||
window.lxData.playMusicInfo = playMusicInfo
|
window.lxData.playMusicInfo = playMusicInfo
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
computed,
|
computed,
|
||||||
} from '@common/utils/vueTools'
|
} from '@common/utils/vueTools'
|
||||||
import { useI18n } from '@renderer/plugins/i18n'
|
import { useI18n } from '@renderer/plugins/i18n'
|
||||||
|
import { tempPlayList, currentPlayIndex, currentPlaybackOrder } from '@renderer/store/player/state'
|
||||||
|
|
||||||
// const playNextModes = [
|
// const playNextModes = [
|
||||||
// 'listLoop',
|
// 'listLoop',
|
||||||
|
@ -28,6 +29,21 @@ export default () => {
|
||||||
if (mode == appSetting['player.togglePlayMethod']) return
|
if (mode == appSetting['player.togglePlayMethod']) return
|
||||||
// let index = playNextModes.indexOf(appSetting['player.togglePlayMethod'])
|
// let index = playNextModes.indexOf(appSetting['player.togglePlayMethod'])
|
||||||
// if (++index >= playNextModes.length) index = 0
|
// if (++index >= playNextModes.length) index = 0
|
||||||
|
const N = tempPlayList.length
|
||||||
|
const prevPlayIndex = currentPlaybackOrder.value[currentPlayIndex.value]
|
||||||
|
if (mode === 'random') {
|
||||||
|
currentPlayIndex.value = 0
|
||||||
|
const allIndexes = Array.from({ length: N }, (_, i) => i).filter(i => i !== prevPlayIndex)
|
||||||
|
for (let i = allIndexes.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1))
|
||||||
|
;[allIndexes[i], allIndexes[j]] = [allIndexes[j], allIndexes[i]]
|
||||||
|
}
|
||||||
|
currentPlaybackOrder.value = [prevPlayIndex, ...allIndexes]
|
||||||
|
} else {
|
||||||
|
currentPlaybackOrder.value = Array.from({ length: N }, (_, i) => i)
|
||||||
|
currentPlayIndex.value = prevPlayIndex
|
||||||
|
}
|
||||||
|
// todo 因为只有此函数会修改播放类别,所以直接在这里应用修改效果
|
||||||
setTogglePlayMode(mode)
|
setTogglePlayMode(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { LIST_IDS } from '@common/constants'
|
||||||
|
|
||||||
export default ({ selectedList, list, listAll, removeAllSelect }) => {
|
export default ({ selectedList, list, listAll, removeAllSelect }) => {
|
||||||
const handlePlayMusic = (index) => {
|
const handlePlayMusic = (index) => {
|
||||||
|
// todo 待接管
|
||||||
playList(LIST_IDS.DOWNLOAD, listAll.value.indexOf(list.value[index]))
|
playList(LIST_IDS.DOWNLOAD, listAll.value.indexOf(list.value[index]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,43 @@
|
||||||
import { addTempPlayList } from '@renderer/store/player/action'
|
import { addTempPlayList, clearTempPlayeList, getList } from '@renderer/store/player/action'
|
||||||
import { playList } from '@renderer/core/player'
|
import { tempPlayList, currentPlayIndex, currentPlaybackOrder } from '@renderer/store/player/state'
|
||||||
|
import { handlePlayNext } from '@renderer/core/player'
|
||||||
|
import { appSetting } from '@renderer/store/setting'
|
||||||
|
// import { arrShuffle } from '@common/utils/common'
|
||||||
|
// setup 函数或组件初始化中
|
||||||
|
|
||||||
|
|
||||||
export default ({ props, selectedList, list, removeAllSelect }) => {
|
export default ({ props, selectedList, list, removeAllSelect }) => {
|
||||||
let clickTime = 0
|
let clickTime = 0
|
||||||
let clickIndex = -1
|
let clickIndex = -1
|
||||||
|
|
||||||
const handlePlayMusic = (index) => {
|
const handlePlayMusic = (index) => {
|
||||||
playList(props.listId, index)
|
currentPlayIndex.value = 0
|
||||||
|
if (tempPlayList.length > 0) { // 双击操作会切换到当前歌单
|
||||||
|
clearTempPlayeList()
|
||||||
|
}
|
||||||
|
const currentchooselist = getList(props.listId)
|
||||||
|
for (let music of currentchooselist) {
|
||||||
|
addTempPlayList([{ listId: props.listId, musicInfo: music }])
|
||||||
|
}
|
||||||
|
// todo 重复代码块,可提取
|
||||||
|
const N = tempPlayList.length
|
||||||
|
if (appSetting['player.togglePlayMethod'] === 'random') {
|
||||||
|
const allIndexes = Array.from({ length: N }, (_, i) => i).filter(i => i !== index)
|
||||||
|
for (let i = allIndexes.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1))
|
||||||
|
;[allIndexes[i], allIndexes[j]] = [allIndexes[j], allIndexes[i]]
|
||||||
|
}
|
||||||
|
currentPlaybackOrder.value = [index, ...allIndexes]
|
||||||
|
} else {
|
||||||
|
currentPlaybackOrder.value = Array.from({ length: N }, (_, i) => i)
|
||||||
|
currentPlayIndex.value = index
|
||||||
|
}
|
||||||
|
const playMusicInfo = tempPlayList[currentPlaybackOrder.value[currentPlayIndex.value]]
|
||||||
|
handlePlayNext(playMusicInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePlayMusicLater = (index, single) => {
|
const handlePlayMusicLater = (index, single) => {
|
||||||
|
// todo 修改播放歌曲逻辑
|
||||||
if (selectedList.value.length && !single) {
|
if (selectedList.value.length && !single) {
|
||||||
addTempPlayList(selectedList.value.map(s => ({ listId: props.listId, musicInfo: s })))
|
addTempPlayList(selectedList.value.map(s => ({ listId: props.listId, musicInfo: s })))
|
||||||
removeAllSelect()
|
removeAllSelect()
|
||||||
|
|
Loading…
Reference in New Issue