我的列表新增拖动调整位置功能
parent
b783c0c227
commit
028c2f9f03
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "lx-music-desktop",
|
"name": "lx-music-desktop",
|
||||||
"version": "1.16.0-beta9",
|
"version": "1.16.0-beta10",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "lx-music-desktop",
|
"name": "lx-music-desktop",
|
||||||
"version": "1.16.0-beta9",
|
"version": "1.16.0-beta10",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bufferutil": "^4.0.5",
|
"bufferutil": "^4.0.5",
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
"node-id3": "^0.2.3",
|
"node-id3": "^0.2.3",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"socket.io": "^4.4.0",
|
"socket.io": "^4.4.0",
|
||||||
|
"sortablejs": "^1.14.0",
|
||||||
"utf-8-validate": "^5.0.7",
|
"utf-8-validate": "^5.0.7",
|
||||||
"vue": "^3.2.23",
|
"vue": "^3.2.23",
|
||||||
"vue-i18n": "^9.2.0-beta.22",
|
"vue-i18n": "^9.2.0-beta.22",
|
||||||
|
@ -17261,6 +17262,11 @@
|
||||||
"ms": "^2.1.1"
|
"ms": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sortablejs": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||||
|
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
|
||||||
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||||
|
@ -33557,6 +33563,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sortablejs": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||||
|
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
|
||||||
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||||
|
|
|
@ -245,6 +245,7 @@
|
||||||
"node-id3": "^0.2.3",
|
"node-id3": "^0.2.3",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"socket.io": "^4.4.0",
|
"socket.io": "^4.4.0",
|
||||||
|
"sortablejs": "^1.14.0",
|
||||||
"utf-8-validate": "^5.0.7",
|
"utf-8-validate": "^5.0.7",
|
||||||
"vue": "^3.2.23",
|
"vue": "^3.2.23",
|
||||||
"vue-i18n": "^9.2.0-beta.22",
|
"vue-i18n": "^9.2.0-beta.22",
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
- 新增将播放与下载的歌词转换为繁体中文选项,默认关闭,可在设置-播放设置中开启
|
- 新增将播放与下载的歌词转换为繁体中文选项,默认关闭,可在设置-播放设置中开启
|
||||||
- 现在已允许进入临时播放列表,即:使用歌单详情页、排行榜名称右键菜单的“播放”按钮播放歌曲时,可右击播放封面进入此临时列表
|
- 现在已允许进入临时播放列表,即:使用歌单详情页、排行榜名称右键菜单的“播放”按钮播放歌曲时,可右击播放封面进入此临时列表
|
||||||
- 播放详情页新增音频可视化功能(实验性)
|
- 播放详情页新增音频可视化功能(实验性)
|
||||||
|
- 我的列表新增拖动调整位置功能,按住Ctrl键(Mac上对应Command键)的时候将进入“拖动模式”,此时可以拖动列表的位置来调整顺序
|
||||||
|
|
||||||
### 优化
|
### 优化
|
||||||
|
|
||||||
|
@ -24,6 +25,10 @@
|
||||||
|
|
||||||
- 现在使用繁体中文语言时将不再自动转换歌词,转换行为将由上面新增的转换开关控制
|
- 现在使用繁体中文语言时将不再自动转换歌词,转换行为将由上面新增的转换开关控制
|
||||||
|
|
||||||
|
### 移除
|
||||||
|
|
||||||
|
- 移除我的列表右键菜单的“上移、下移列表”功能,调整改用新增的拖动功能去点赞位置
|
||||||
|
|
||||||
### 其他
|
### 其他
|
||||||
|
|
||||||
- 升级vue到 3.x
|
- 升级vue到 3.x
|
||||||
|
|
|
@ -110,15 +110,13 @@
|
||||||
"lists__import_part_button_confirm": "Overwrite",
|
"lists__import_part_button_confirm": "Overwrite",
|
||||||
"lists__import_part_confirm": "The imported list ({importName}) has the same ID as the local list ({localName}). Do you overwrite the local list?",
|
"lists__import_part_confirm": "The imported list ({importName}) has the same ID as the local list ({localName}). Do you overwrite the local list?",
|
||||||
"lists__import_part_desc": "Select list file",
|
"lists__import_part_desc": "Select list file",
|
||||||
"lists__movedown": "Move Down",
|
|
||||||
"lists__moveup": "Move Up",
|
|
||||||
"lists__new_list_btn": "Create list",
|
"lists__new_list_btn": "Create list",
|
||||||
"lists__new_list_input": "New list...",
|
"lists__new_list_input": "New list...",
|
||||||
"lists__remove": "Remove",
|
"lists__remove": "Remove",
|
||||||
"lists__remove_tip": "Do you really want to remove {name}?",
|
"lists__remove_tip": "Do you really want to remove {name}?",
|
||||||
"lists__remove_tip_button": "Yes, that's right",
|
"lists__remove_tip_button": "Yes, that's right",
|
||||||
"lists__rename": "Rename",
|
"lists__rename": "Rename",
|
||||||
"lists__sort_list": "Sort",
|
"lists__sort_list": "Sort songs",
|
||||||
"lists__sync": "Update",
|
"lists__sync": "Update",
|
||||||
"load_list_file_error_detail": "We have helped you back up the old list file to {path}\nIt is stored in JSON format, you can try to repair and restore it manually\n\nError details: {detail}",
|
"load_list_file_error_detail": "We have helped you back up the old list file to {path}\nIt is stored in JSON format, you can try to repair and restore it manually\n\nError details: {detail}",
|
||||||
"load_list_file_error_title": "Error loading playlist data",
|
"load_list_file_error_title": "Error loading playlist data",
|
||||||
|
|
|
@ -110,15 +110,13 @@
|
||||||
"lists__import_part_button_confirm": "覆盖掉",
|
"lists__import_part_button_confirm": "覆盖掉",
|
||||||
"lists__import_part_confirm": "导入的列表({importName})与本地列表({localName})的ID相同,是否覆盖本地列表?",
|
"lists__import_part_confirm": "导入的列表({importName})与本地列表({localName})的ID相同,是否覆盖本地列表?",
|
||||||
"lists__import_part_desc": "选择列表文件",
|
"lists__import_part_desc": "选择列表文件",
|
||||||
"lists__movedown": "下移",
|
|
||||||
"lists__moveup": "上移",
|
|
||||||
"lists__new_list_btn": "新建列表",
|
"lists__new_list_btn": "新建列表",
|
||||||
"lists__new_list_input": "新列表...",
|
"lists__new_list_input": "新列表...",
|
||||||
"lists__remove": "删除",
|
"lists__remove": "删除",
|
||||||
"lists__remove_tip": "你真的想要移除 {name} 吗?",
|
"lists__remove_tip": "你真的想要移除 {name} 吗?",
|
||||||
"lists__remove_tip_button": "是的 没错",
|
"lists__remove_tip_button": "是的 没错",
|
||||||
"lists__rename": "重命名",
|
"lists__rename": "重命名",
|
||||||
"lists__sort_list": "排序",
|
"lists__sort_list": "排序歌曲",
|
||||||
"lists__sync": "更新",
|
"lists__sync": "更新",
|
||||||
"load_list_file_error_detail": "我们已经帮你把旧的列表文件备份到{path}\n它以 JSON 格式存储,你可以尝试手动修复并恢复它\n\n错误详情:{detail}",
|
"load_list_file_error_detail": "我们已经帮你把旧的列表文件备份到{path}\n它以 JSON 格式存储,你可以尝试手动修复并恢复它\n\n错误详情:{detail}",
|
||||||
"load_list_file_error_title": "播放列表数据加载错误(建议到GitHub或加群反馈)",
|
"load_list_file_error_title": "播放列表数据加载错误(建议到GitHub或加群反馈)",
|
||||||
|
|
|
@ -110,15 +110,13 @@
|
||||||
"lists__import_part_button_confirm": "覆蓋掉",
|
"lists__import_part_button_confirm": "覆蓋掉",
|
||||||
"lists__import_part_confirm": "導入的列表({importName})與本地列表({localName})的ID相同,是否覆蓋本地列表?",
|
"lists__import_part_confirm": "導入的列表({importName})與本地列表({localName})的ID相同,是否覆蓋本地列表?",
|
||||||
"lists__import_part_desc": "選擇列表文件",
|
"lists__import_part_desc": "選擇列表文件",
|
||||||
"lists__movedown": "下移",
|
|
||||||
"lists__moveup": "上移",
|
|
||||||
"lists__new_list_btn": "新建列表",
|
"lists__new_list_btn": "新建列表",
|
||||||
"lists__new_list_input": "新列表...",
|
"lists__new_list_input": "新列表...",
|
||||||
"lists__remove": "刪除",
|
"lists__remove": "刪除",
|
||||||
"lists__remove_tip": "你真的想要移除 {name} 嗎?",
|
"lists__remove_tip": "你真的想要移除 {name} 嗎?",
|
||||||
"lists__remove_tip_button": "是的 沒錯",
|
"lists__remove_tip_button": "是的 沒錯",
|
||||||
"lists__rename": "重命名",
|
"lists__rename": "重命名",
|
||||||
"lists__sort_list": "排序",
|
"lists__sort_list": "排序歌曲",
|
||||||
"lists__sync": "更新",
|
"lists__sync": "更新",
|
||||||
"load_list_file_error_detail": "我們已經幫你把舊的列表文件備份到{path}\n它以 JSON 格式存儲,你可以嘗試手動修復並恢復它\n\n錯誤詳情:{detail}",
|
"load_list_file_error_detail": "我們已經幫你把舊的列表文件備份到{path}\n它以 JSON 格式存儲,你可以嘗試手動修復並恢復它\n\n錯誤詳情:{detail}",
|
||||||
"load_list_file_error_title": "播放列表數據加載錯誤",
|
"load_list_file_error_title": "播放列表數據加載錯誤",
|
||||||
|
|
|
@ -50,10 +50,14 @@ const registerMin = () => rendererSend(NAMES.mainWindow.min)
|
||||||
const registerMinToggle = () => rendererSend(NAMES.mainWindow.min_toggle)
|
const registerMinToggle = () => rendererSend(NAMES.mainWindow.min_toggle)
|
||||||
const registerHideToggle = () => rendererSend(NAMES.mainWindow.hide_toggle)
|
const registerHideToggle = () => rendererSend(NAMES.mainWindow.hide_toggle)
|
||||||
|
|
||||||
|
const setClearDownKeys = () => keyBind.clearDownKeys()
|
||||||
|
|
||||||
eventHub.on(baseName.min, registerMin)
|
eventHub.on(baseName.min, registerMin)
|
||||||
eventHub.on(baseName.max, () => rendererSend(NAMES.mainWindow.max))
|
eventHub.on(baseName.max, () => rendererSend(NAMES.mainWindow.max))
|
||||||
eventHub.on(baseName.close, () => rendererSend(NAMES.mainWindow.close))
|
eventHub.on(baseName.close, () => rendererSend(NAMES.mainWindow.close))
|
||||||
|
|
||||||
|
eventHub.on(baseName.setClearDownKeys, setClearDownKeys)
|
||||||
|
|
||||||
const registerCommonEvents = () => {
|
const registerCommonEvents = () => {
|
||||||
eventHub.on(hotKeyNamesCommon.close.action, registerQuit)
|
eventHub.on(hotKeyNamesCommon.close.action, registerQuit)
|
||||||
eventHub.on(hotKeyNamesCommon.min.action, registerMin)
|
eventHub.on(hotKeyNamesCommon.min.action, registerMin)
|
||||||
|
|
|
@ -3,6 +3,9 @@ const names = {
|
||||||
key_down: 'key_down',
|
key_down: 'key_down',
|
||||||
bindKey: 'bindKey',
|
bindKey: 'bindKey',
|
||||||
unbindKey: 'unbindKey',
|
unbindKey: 'unbindKey',
|
||||||
|
dragStart: 'dragStart',
|
||||||
|
dragEnd: 'dragEnd',
|
||||||
|
setClearDownKeys: 'setClearDownKeys',
|
||||||
focus: 'focus',
|
focus: 'focus',
|
||||||
min: 'min',
|
min: 'min',
|
||||||
max: 'max',
|
max: 'max',
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import tips from './Tips'
|
import tips from './Tips'
|
||||||
import { debounce } from '../../utils'
|
import { debounce } from '../../utils'
|
||||||
|
import { base as eventBaseName } from '@renderer/event/names'
|
||||||
|
|
||||||
let instance
|
let instance
|
||||||
let prevTips
|
let prevTips
|
||||||
let prevX = 0
|
let prevX = 0
|
||||||
let prevY = 0
|
let prevY = 0
|
||||||
|
let isDraging = false
|
||||||
|
|
||||||
const getTips = el =>
|
const getTips = el =>
|
||||||
el
|
el
|
||||||
|
@ -16,6 +18,7 @@ const getTips = el =>
|
||||||
: null
|
: null
|
||||||
|
|
||||||
const showTips = debounce(event => {
|
const showTips = debounce(event => {
|
||||||
|
if (isDraging) return
|
||||||
let msg = getTips(event.target)
|
let msg = getTips(event.target)
|
||||||
if (!msg) return
|
if (!msg) return
|
||||||
prevTips = msg
|
prevTips = msg
|
||||||
|
@ -46,6 +49,7 @@ const setTips = tips => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateTips = event => {
|
const updateTips = event => {
|
||||||
|
if (isDraging) return
|
||||||
if (!instance) return showTips(event)
|
if (!instance) return showTips(event)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let msg = getTips(event.target)
|
let msg = getTips(event.target)
|
||||||
|
@ -56,7 +60,7 @@ const updateTips = event => {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.addEventListener('mousemove', event => {
|
document.body.addEventListener('mousemove', event => {
|
||||||
if (event.x == prevX && event.y == prevY) return
|
if ((event.x == prevX && event.y == prevY) || isDraging) return
|
||||||
prevX = event.x
|
prevX = event.x
|
||||||
prevY = event.y
|
prevY = event.y
|
||||||
hideTips()
|
hideTips()
|
||||||
|
@ -66,3 +70,12 @@ document.body.addEventListener('mousemove', event => {
|
||||||
document.body.addEventListener('click', updateTips)
|
document.body.addEventListener('click', updateTips)
|
||||||
|
|
||||||
document.body.addEventListener('contextmenu', updateTips)
|
document.body.addEventListener('contextmenu', updateTips)
|
||||||
|
|
||||||
|
window.eventHub.on(eventBaseName.dragStart, () => {
|
||||||
|
isDraging = true
|
||||||
|
hideTips()
|
||||||
|
})
|
||||||
|
|
||||||
|
window.eventHub.on(eventBaseName.dragEnd, () => {
|
||||||
|
isDraging = false
|
||||||
|
})
|
||||||
|
|
|
@ -352,16 +352,6 @@ const mutations = {
|
||||||
list.name = name
|
list.name = name
|
||||||
window.eventHub.emit(eventListNames.listChange, [id])
|
window.eventHub.emit(eventListNames.listChange, [id])
|
||||||
},
|
},
|
||||||
moveupUserList(state, { id, isSync }) {
|
|
||||||
const index = userLists.findIndex(l => l.id == id)
|
|
||||||
if (index < 0) return
|
|
||||||
this.commit('list/setUserListPosition', { id, position: index - 1 })
|
|
||||||
},
|
|
||||||
movedownUserList(state, { id, isSync }) {
|
|
||||||
const index = userLists.findIndex(l => l.id == id)
|
|
||||||
if (index < 0) return
|
|
||||||
this.commit('list/setUserListPosition', { id, position: index + 1 })
|
|
||||||
},
|
|
||||||
setUserListPosition(state, { id, position, isSync }) {
|
setUserListPosition(state, { id, position, isSync }) {
|
||||||
if (!isSync) {
|
if (!isSync) {
|
||||||
window.eventHub.emit(eventSyncName.send_action_list, {
|
window.eventHub.emit(eventSyncName.send_action_list, {
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import Sortable, { AutoScroll } from 'sortablejs/modular/sortable.core.esm'
|
||||||
|
import { onMounted } from '@renderer/utils/vueTools'
|
||||||
|
import { base as eventBaseName } from '@renderer/event/names'
|
||||||
|
|
||||||
|
Sortable.mount(new AutoScroll())
|
||||||
|
|
||||||
|
const noop = () => {}
|
||||||
|
|
||||||
|
export default ({ dom_list, dragingItemClassName, filter, onUpdate, onStart = noop, onEnd = noop }) => {
|
||||||
|
let sortable
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
sortable = Sortable.create(dom_list.value, {
|
||||||
|
animation: 150,
|
||||||
|
disabled: true,
|
||||||
|
forceFallback: false,
|
||||||
|
filter: filter ? '.' + filter : null,
|
||||||
|
ghostClass: dragingItemClassName,
|
||||||
|
onUpdate(event) {
|
||||||
|
onUpdate(event.newIndex, event.oldIndex)
|
||||||
|
},
|
||||||
|
onMove(event) {
|
||||||
|
return filter ? !event.related.classList.contains(filter) : true
|
||||||
|
},
|
||||||
|
onChoose() {
|
||||||
|
onStart()
|
||||||
|
},
|
||||||
|
onUnchoose() {
|
||||||
|
onEnd()
|
||||||
|
// 处于拖动状态期间,键盘事件无法监听,拖动结束手动清理按下的键
|
||||||
|
window.eventHub.emit(eventBaseName.setClearDownKeys)
|
||||||
|
},
|
||||||
|
onStart(event) {
|
||||||
|
window.eventHub.emit(eventBaseName.dragStart)
|
||||||
|
},
|
||||||
|
onEnd(event) {
|
||||||
|
window.eventHub.emit(eventBaseName.dragEnd)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
setDisabled(enable) {
|
||||||
|
if (!sortable) return
|
||||||
|
sortable.option('disabled', enable)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,18 +8,18 @@
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<ul class="scroll" :class="$style.listsContent" ref="dom_lists_list">
|
<ul class="scroll" :class="[$style.listsContent, { [$style.sortable]: keyEvent.isModDown }]" ref="dom_lists_list">
|
||||||
<li :class="[$style.listsItem, {[$style.active]: defaultList.id == listId}]" :tips="defaultList.name"
|
<li class="default-list" :class="[$style.listsItem, {[$style.active]: defaultList.id == listId}]" :tips="defaultList.name"
|
||||||
@contextmenu="handleListsItemRigthClick($event, -2)" @click="handleListToggle(defaultList.id)"
|
@contextmenu="handleListsItemRigthClick($event, -2)" @click="handleListToggle(defaultList.id)"
|
||||||
>
|
>
|
||||||
<span :class="$style.listsLabel">{{defaultList.name}}</span>
|
<span :class="$style.listsLabel">{{defaultList.name}}</span>
|
||||||
</li>
|
</li>
|
||||||
<li :class="[$style.listsItem, {[$style.active]: loveList.id == listId}]" :tips="loveList.name"
|
<li class="default-list" :class="[$style.listsItem, {[$style.active]: loveList.id == listId}]" :tips="loveList.name"
|
||||||
@contextmenu="handleListsItemRigthClick($event, -1)" @click="handleListToggle(loveList.id)">
|
@contextmenu="handleListsItemRigthClick($event, -1)" @click="handleListToggle(loveList.id)">
|
||||||
<span :class="$style.listsLabel">{{loveList.name}}</span>
|
<span :class="$style.listsLabel">{{loveList.name}}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="user-list"
|
<li class="user-list"
|
||||||
:class="[$style.listsItem, {[$style.active]:item.id == listId}, {[$style.clicked]: listsData.rightClickItemIndex == index}, {[$style.fetching]: fetchingListStatus[item.id]}]"
|
:class="[$style.listsItem, {[$style.active]:item.id == listId}, {[$style.clicked]: listsData.rightClickItemIndex == index}, {[$style.fetching]: fetchingListStatus[item.id]}]" :data-index="index"
|
||||||
@contextmenu="handleListsItemRigthClick($event, index)" :tips="item.name" v-for="(item, index) in userLists" :key="item.id"
|
@contextmenu="handleListsItemRigthClick($event, index)" :tips="item.name" v-for="(item, index) in userLists" :key="item.id"
|
||||||
>
|
>
|
||||||
<span :class="$style.listsLabel" @click="handleListToggle(item.id, index + 2)">{{item.name}}</span>
|
<span :class="$style.listsLabel" @click="handleListToggle(item.id, index + 2)">{{item.name}}</span>
|
||||||
|
@ -46,8 +46,9 @@ import musicSdk from '@renderer/utils/music'
|
||||||
import DuplicateMusicModal from './DuplicateMusicModal'
|
import DuplicateMusicModal from './DuplicateMusicModal'
|
||||||
import ListSortModal from './ListSortModal'
|
import ListSortModal from './ListSortModal'
|
||||||
import { defaultList, loveList, userLists } from '@renderer/core/share/list'
|
import { defaultList, loveList, userLists } from '@renderer/core/share/list'
|
||||||
import { computed } from '@renderer/utils/vueTools'
|
import { ref, computed, useCommit, useCssModule } from '@renderer/utils/vueTools'
|
||||||
import { getList } from '@renderer/core/share/utils'
|
import { getList } from '@renderer/core/share/utils'
|
||||||
|
import useDarg from '@renderer/utils/compositions/useDrag'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MyLists',
|
name: 'MyLists',
|
||||||
|
@ -62,12 +63,27 @@ export default {
|
||||||
ListSortModal,
|
ListSortModal,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
const dom_lists_list = ref(null)
|
||||||
const lists = computed(() => [defaultList, loveList, ...userLists])
|
const lists = computed(() => [defaultList, loveList, ...userLists])
|
||||||
|
const setUserListPosition = useCommit('list', 'setUserListPosition')
|
||||||
|
|
||||||
|
const styles = useCssModule()
|
||||||
|
const { setDisabled } = useDarg({
|
||||||
|
dom_list: dom_lists_list,
|
||||||
|
dragingItemClassName: styles.dragingItem,
|
||||||
|
filter: 'default-list',
|
||||||
|
onUpdate(newIndex, oldIndex) {
|
||||||
|
setUserListPosition({ id: lists.value[oldIndex].id, position: newIndex - 2 })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
defaultList,
|
defaultList,
|
||||||
loveList,
|
loveList,
|
||||||
userLists,
|
userLists,
|
||||||
lists,
|
lists,
|
||||||
|
dom_lists_list,
|
||||||
|
setDisabledSort: setDisabled,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['show-menu'],
|
emits: ['show-menu'],
|
||||||
|
@ -84,8 +100,6 @@ export default {
|
||||||
import: true,
|
import: true,
|
||||||
export: true,
|
export: true,
|
||||||
sync: false,
|
sync: false,
|
||||||
moveup: true,
|
|
||||||
movedown: true,
|
|
||||||
remove: true,
|
remove: true,
|
||||||
},
|
},
|
||||||
rightClickItemIndex: -1,
|
rightClickItemIndex: -1,
|
||||||
|
@ -99,6 +113,9 @@ export default {
|
||||||
fetchingListStatus: {},
|
fetchingListStatus: {},
|
||||||
selectedDuplicateListInfo: {},
|
selectedDuplicateListInfo: {},
|
||||||
selectedSortListInfo: {},
|
selectedSortListInfo: {},
|
||||||
|
keyEvent: {
|
||||||
|
isModDown: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -114,16 +131,16 @@ export default {
|
||||||
action: 'sync',
|
action: 'sync',
|
||||||
disabled: !this.listsData.itemMenuControl.sync,
|
disabled: !this.listsData.itemMenuControl.sync,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: this.$t('lists__duplicate'),
|
|
||||||
action: 'duplicate',
|
|
||||||
disabled: !this.listsData.itemMenuControl.duplicate,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: this.$t('lists__sort_list'),
|
name: this.$t('lists__sort_list'),
|
||||||
action: 'sort',
|
action: 'sort',
|
||||||
disabled: !this.listsData.itemMenuControl.sort,
|
disabled: !this.listsData.itemMenuControl.sort,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: this.$t('lists__duplicate'),
|
||||||
|
action: 'duplicate',
|
||||||
|
disabled: !this.listsData.itemMenuControl.duplicate,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: this.$t('lists__import'),
|
name: this.$t('lists__import'),
|
||||||
action: 'import',
|
action: 'import',
|
||||||
|
@ -134,16 +151,6 @@ export default {
|
||||||
action: 'export',
|
action: 'export',
|
||||||
disabled: !this.listsData.itemMenuControl.export,
|
disabled: !this.listsData.itemMenuControl.export,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: this.$t('lists__moveup'),
|
|
||||||
action: 'moveup',
|
|
||||||
disabled: !this.listsData.itemMenuControl.moveup,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: this.$t('lists__movedown'),
|
|
||||||
action: 'movedown',
|
|
||||||
disabled: !this.listsData.itemMenuControl.movedown,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: this.$t('lists__remove'),
|
name: this.$t('lists__remove'),
|
||||||
action: 'remove',
|
action: 'remove',
|
||||||
|
@ -171,13 +178,17 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.setListsScroll()
|
this.setListsScroll()
|
||||||
|
window.eventHub.on('key_mod_down', this.handle_key_mod_down)
|
||||||
|
window.eventHub.on('key_mod_up', this.handle_key_mod_up)
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
window.eventHub.off('key_mod_down', this.handle_key_mod_down)
|
||||||
|
window.eventHub.off('key_mod_up', this.handle_key_mod_up)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations('list', [
|
...mapMutations('list', [
|
||||||
'setUserListName',
|
'setUserListName',
|
||||||
'createUserList',
|
'createUserList',
|
||||||
'moveupUserList',
|
|
||||||
'movedownUserList',
|
|
||||||
'removeUserList',
|
'removeUserList',
|
||||||
'setPrevSelectListId',
|
'setPrevSelectListId',
|
||||||
'setList',
|
'setList',
|
||||||
|
@ -186,20 +197,37 @@ export default {
|
||||||
...mapActions('leaderboard', {
|
...mapActions('leaderboard', {
|
||||||
getBoardListAll: 'getListAll',
|
getBoardListAll: 'getListAll',
|
||||||
}),
|
}),
|
||||||
|
handle_key_mod_down() {
|
||||||
|
if (!this.keyEvent.isModDown) {
|
||||||
|
this.keyEvent.isModDown = true
|
||||||
|
this.setDisabledSort(false)
|
||||||
|
const dom_target = this.dom_lists_list.querySelector('.' + this.$style.editing)
|
||||||
|
if (dom_target) this.handleListsSave(dom_target.dataset.index)
|
||||||
|
}
|
||||||
|
if (this.listsData.isShowItemMenu) this.hideListsMenu()
|
||||||
|
},
|
||||||
|
handle_key_mod_up() {
|
||||||
|
if (this.keyEvent.isModDown) {
|
||||||
|
this.keyEvent.isModDown = false
|
||||||
|
this.setDisabledSort(true)
|
||||||
|
}
|
||||||
|
},
|
||||||
setListsScroll() {
|
setListsScroll() {
|
||||||
let target = this.$refs.dom_lists_list.querySelector('.' + this.$style.active)
|
let target = this.dom_lists_list.querySelector('.' + this.$style.active)
|
||||||
if (!target) return
|
if (!target) return
|
||||||
let offsetTop = target.offsetTop
|
let offsetTop = target.offsetTop
|
||||||
let location = offsetTop - 150
|
let location = offsetTop - 150
|
||||||
if (location > 0) this.$refs.dom_lists_list.scrollTop = location
|
if (location > 0) this.dom_lists_list.scrollTop = location
|
||||||
},
|
},
|
||||||
handleListsSave(index, event) {
|
handleListsSave(index) {
|
||||||
let dom_target = this.$refs.dom_lists_list.querySelector('.' + this.$style.editing)
|
let dom_target = this.dom_lists_list.querySelector('.' + this.$style.editing)
|
||||||
if (dom_target) dom_target.classList.remove(this.$style.editing)
|
if (!dom_target) return
|
||||||
let name = event.target.value.trim()
|
dom_target.classList.remove(this.$style.editing)
|
||||||
|
const dom_input = dom_target.querySelector('.' + this.$style.listsInput)
|
||||||
|
let name = dom_input.value.trim()
|
||||||
const targetList = userLists[index]
|
const targetList = userLists[index]
|
||||||
if (name.length) return this.setUserListName({ id: targetList.id, name })
|
if (name.length) return this.setUserListName({ id: targetList.id, name })
|
||||||
event.target.value = targetList.name
|
dom_input.value = targetList.name
|
||||||
},
|
},
|
||||||
handleListsCreate(event) {
|
handleListsCreate(event) {
|
||||||
if (event.target.readonly) return
|
if (event.target.readonly) return
|
||||||
|
@ -242,22 +270,18 @@ export default {
|
||||||
this.listsData.itemMenuControl.rename = false
|
this.listsData.itemMenuControl.rename = false
|
||||||
this.listsData.itemMenuControl.remove = false
|
this.listsData.itemMenuControl.remove = false
|
||||||
this.listsData.itemMenuControl.sync = false
|
this.listsData.itemMenuControl.sync = false
|
||||||
this.listsData.itemMenuControl.moveup = false
|
|
||||||
this.listsData.itemMenuControl.movedown = false
|
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
this.listsData.itemMenuControl.rename = true
|
this.listsData.itemMenuControl.rename = true
|
||||||
this.listsData.itemMenuControl.remove = true
|
this.listsData.itemMenuControl.remove = true
|
||||||
source = userLists[index].source
|
source = userLists[index].source
|
||||||
this.listsData.itemMenuControl.sync = !!source && !!musicSdk[source]?.songList
|
this.listsData.itemMenuControl.sync = !!source && !!musicSdk[source]?.songList
|
||||||
this.listsData.itemMenuControl.moveup = index > 0
|
|
||||||
this.listsData.itemMenuControl.movedown = index < userLists.length - 1
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
this.listsData.itemMenuControl.sort = !!getList(this.getTargetListInfo(index)?.id).length
|
this.listsData.itemMenuControl.sort = !!getList(this.getTargetListInfo(index)?.id).length
|
||||||
this.listsData.rightClickItemIndex = index
|
this.listsData.rightClickItemIndex = index
|
||||||
this.listsData.menuLocation.x = event.currentTarget.offsetLeft + event.offsetX
|
this.listsData.menuLocation.x = event.currentTarget.offsetLeft + event.offsetX
|
||||||
this.listsData.menuLocation.y = event.currentTarget.offsetTop + event.offsetY - this.$refs.dom_lists_list.scrollTop
|
this.listsData.menuLocation.y = event.currentTarget.offsetTop + event.offsetY - this.dom_lists_list.scrollTop
|
||||||
this.$emit('show-menu')
|
this.$emit('show-menu')
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.listsData.isShowItemMenu = true
|
this.listsData.isShowItemMenu = true
|
||||||
|
@ -275,7 +299,7 @@ export default {
|
||||||
let dom
|
let dom
|
||||||
switch (action && action.action) {
|
switch (action && action.action) {
|
||||||
case 'rename':
|
case 'rename':
|
||||||
dom = this.$refs.dom_lists_list.querySelectorAll('.user-list')[index]
|
dom = this.dom_lists_list.querySelectorAll('.user-list')[index]
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
dom.classList.add(this.$style.editing)
|
dom.classList.add(this.$style.editing)
|
||||||
dom.querySelector('input').focus()
|
dom.querySelector('input').focus()
|
||||||
|
@ -298,12 +322,6 @@ export default {
|
||||||
case 'sync':
|
case 'sync':
|
||||||
this.handleSyncSourceList(index)
|
this.handleSyncSourceList(index)
|
||||||
break
|
break
|
||||||
case 'moveup':
|
|
||||||
this.moveupUserList({ id: userLists[index].id })
|
|
||||||
break
|
|
||||||
case 'movedown':
|
|
||||||
this.movedownUserList({ id: userLists[index].id })
|
|
||||||
break
|
|
||||||
case 'remove':
|
case 'remove':
|
||||||
this.$dialog.confirm({
|
this.$dialog.confirm({
|
||||||
message: this.$t('lists__remove_tip', { name: userLists[index].name }),
|
message: this.$t('lists__remove_tip', { name: userLists[index].name }),
|
||||||
|
@ -475,6 +493,22 @@ export default {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow-y: scroll !important;
|
overflow-y: scroll !important;
|
||||||
// border-right: 1px solid rgba(0, 0, 0, 0.12);
|
// border-right: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
|
||||||
|
&.sortable {
|
||||||
|
* {
|
||||||
|
-webkit-user-drag: element;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listsItem {
|
||||||
|
&:hover, &.active, &.selected, &.clicked {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dragingItem {
|
||||||
|
background-color: @color-theme_2-hover !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.listsItem {
|
.listsItem {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -565,6 +599,15 @@ each(@themes, {
|
||||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.listsContent {
|
||||||
|
&.sortable {
|
||||||
|
.listsItem {
|
||||||
|
&.dragingItem {
|
||||||
|
background-color: ~'@{color-@{value}-theme_2-hover}' !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.listsNew {
|
.listsNew {
|
||||||
background-color: ~'@{color-@{value}-theme_2-hover}';
|
background-color: ~'@{color-@{value}-theme_2-hover}';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue