lx-music-desktop/src/renderer-lyric/components/layout/LyricHorizontal/useLyric.js

223 lines
6.2 KiB
JavaScript

import { ref, onMounted, onBeforeUnmount, watch, nextTick } from '@common/utils/vueTools'
import { scrollTo } from '@common/utils/renderer'
import { lyric } from '@lyric/store/lyric'
import { isPlay, setting } from '@lyric/store/state'
import { invalidateShadow, setWindowBounds } from '@lyric/utils/ipc'
const getOffsetTop = (contentHeight, lineHeight) => {
switch (setting['desktopLyric.scrollAlign']) {
case 'top': return 0
default: return contentHeight * 0.5 - lineHeight / 2
}
}
export default (isComputeHeight) => {
const dom_lyric = ref(null)
const dom_lyric_text = ref(null)
const isMsDown = ref(false)
let isStopScroll = false
const winEvent = {
isMsDown: false,
msDownX: 0,
msDownY: 0,
}
let msDownY = 0
let msDownScrollY = 0
let timeout = null
let cancelScrollFn
let dom_lines
let line_heights
let isSetedLines = false
let prevActiveLine = 0
const handleScrollLrc = (duration = 300) => {
if (!dom_lines?.length || !dom_lyric.value) return
if (isStopScroll) return
let dom_p = dom_lines[lyric.line]
if (dom_p) {
let offset = 0
if (isComputeHeight.value) {
let prevLineHeight = line_heights[prevActiveLine] ?? 0
offset = prevActiveLine < lyric.line ? ((dom_lines[prevActiveLine]?.clientHeight ?? 0) - prevLineHeight) : 0
// console.log(prevActiveLine, dom_lines[prevActiveLine]?.clientHeight ?? 0, prevLineHeight, offset)
}
cancelScrollFn = scrollTo(dom_lyric.value, dom_p ? (dom_p.offsetTop - offset - getOffsetTop(dom_lyric.value.clientHeight, dom_p.clientHeight)) : 0, duration, () => {
invalidateShadow()
})
} else {
cancelScrollFn = scrollTo(dom_lyric.value, 0, duration, () => {
invalidateShadow()
})
}
}
const clearLyricScrollTimeout = () => {
if (!timeout) return
clearTimeout(timeout)
timeout = null
}
const startLyricScrollTimeout = () => {
clearLyricScrollTimeout()
timeout = setTimeout(() => {
timeout = null
isStopScroll = false
if (!isPlay.value) return
handleScrollLrc()
}, 3000)
}
const handleLyricDown = (target, x, y) => {
if (target.classList.contains('font-lrc') ||
target.parentNode.classList.contains('font-lrc') ||
target.classList.contains('extended') ||
target.parentNode.classList.contains('extended')
) {
if (delayScrollTimeout) {
clearTimeout(delayScrollTimeout)
delayScrollTimeout = null
}
isMsDown.value = true
msDownY = y
msDownScrollY = dom_lyric.value.scrollTop
} else {
winEvent.isMsDown = true
winEvent.msDownX = x
winEvent.msDownY = y
}
}
const handleLyricMouseDown = event => {
handleLyricDown(event.target, event.clientX, event.clientY)
}
const handleLyricTouchStart = event => {
if (event.changedTouches.length) {
const touch = event.changedTouches[0]
handleLyricDown(event.target, touch.clientX, touch.clientY)
}
}
const handleMouseMsUp = () => {
isMsDown.value = false
winEvent.isMsDown = false
}
const handleMove = (x, y) => {
if (isMsDown.value) {
isStopScroll ||= true
if (cancelScrollFn) {
cancelScrollFn()
cancelScrollFn = null
}
dom_lyric.value.scrollTop = msDownScrollY + msDownY - y
startLyricScrollTimeout()
} else if (winEvent.isMsDown) {
setWindowBounds({
x: x - winEvent.msDownX,
y: y - winEvent.msDownY,
w: window.innerWidth,
h: window.innerHeight,
})
}
}
const handleMouseMsMove = event => {
handleMove(event.clientX, event.clientY)
}
const handleTouchMove = (e) => {
if (e.changedTouches.length) {
const touch = e.changedTouches[0]
handleMove(touch.clientX, touch.clientY)
}
}
const handleWheel = (event) => {
console.log(event.deltaY)
if (cancelScrollFn) {
cancelScrollFn()
cancelScrollFn = null
}
dom_lyric.value.scrollTop = dom_lyric.value.scrollTop + event.deltaY
startLyricScrollTimeout()
}
const setLyric = (lines) => {
const dom_line_content = document.createDocumentFragment()
for (const line of lines) {
dom_line_content.appendChild(line.dom_line)
}
dom_lyric_text.value.textContent = ''
dom_lyric_text.value.appendChild(dom_line_content)
nextTick(() => {
dom_lines = dom_lyric.value.querySelectorAll('.line-content')
line_heights = Array.from(dom_lines).map(l => l.clientHeight)
handleScrollLrc()
})
}
const initLrc = (lines, oLines) => {
prevActiveLine = 0
isSetedLines = true
if (oLines) {
if (lines.length) {
setLyric(lines)
} else {
cancelScrollFn = scrollTo(dom_lyric.value, 0, 300, () => {
invalidateShadow()
if (lyric.lines !== lines) return
setLyric(lines)
}, 50)
}
} else {
setLyric(lines)
}
}
let delayScrollTimeout
const scrollLine = (line, oldLine) => {
setImmediate(() => {
prevActiveLine = line
})
if (line < 0 || !lyric.lines.length) return
if (line == 0 && isSetedLines) return isSetedLines = false
isSetedLines &&= false
if (oldLine == null || line - oldLine != 1) return handleScrollLrc()
if (setting['desktopLyric.isDelayScroll']) {
delayScrollTimeout = setTimeout(() => {
delayScrollTimeout = null
handleScrollLrc(600)
}, 600)
} else {
handleScrollLrc()
}
}
watch(() => lyric.lines, initLrc)
watch(() => lyric.line, scrollLine)
onMounted(() => {
document.addEventListener('mousemove', handleMouseMsMove)
document.addEventListener('mouseup', handleMouseMsUp)
document.addEventListener('touchmove', handleTouchMove)
document.addEventListener('touchend', handleMouseMsUp)
initLrc(lyric.lines, null)
})
onBeforeUnmount(() => {
document.removeEventListener('mousemove', handleMouseMsMove)
document.removeEventListener('mouseup', handleMouseMsUp)
document.removeEventListener('touchmove', handleTouchMove)
document.removeEventListener('touchend', handleMouseMsUp)
})
return {
dom_lyric,
dom_lyric_text,
isMsDown,
handleLyricMouseDown,
handleLyricTouchStart,
handleWheel,
}
}