fix: resolve playroom UI state inconsistency when page loses focus

When lyrics are enabled and the page loses focus while playing a song without lyrics,
then plays a song with lyrics, returning to the page caused controller and lyrics
layout to become misaligned. Added page focus handlers to sync UI state correctly.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Astrian Zheng 2025-06-04 20:54:54 +10:00
parent ab5f021bf8
commit 92093ef80d
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA
2 changed files with 128 additions and 0 deletions

View File

@ -543,8 +543,39 @@ watch(() => props.lrcSrc, async (newSrc) => {
}
}, { immediate: true })
//
let handleVisibilityChange: (() => void) | null = null
//
function setupPageFocusHandlers() {
handleVisibilityChange = () => {
if (document.hidden) {
//
if (scrollTween) scrollTween.pause()
if (highlightTween) highlightTween.pause()
} else {
//
if (scrollTween && scrollTween.paused()) scrollTween.resume()
if (highlightTween && highlightTween.paused()) highlightTween.resume()
//
nextTick(() => {
if (currentLineIndex.value >= 0 && autoScroll.value && !userScrolling.value) {
scrollToLine(currentLineIndex.value, false) // 使
}
})
}
}
document.addEventListener('visibilitychange', handleVisibilityChange)
}
//
onMounted(() => {
//
setupPageFocusHandlers()
//
if (controlPanel.value) {
gsap.fromTo(controlPanel.value,
@ -577,6 +608,11 @@ onUnmounted(() => {
if (scrollTween) scrollTween.kill()
if (highlightTween) highlightTween.kill()
if (userScrollTimeout) clearTimeout(userScrollTimeout)
//
if (handleVisibilityChange) {
document.removeEventListener('visibilitychange', handleVisibilityChange)
}
})
//

View File

@ -83,6 +83,9 @@ onMounted(async () => {
thumbUpdate()
setupEntranceAnimations()
//
setupPageFocusHandlers()
})
function timeFormatter(time: number) {
@ -419,9 +422,98 @@ watch(() => [preferences.presentLyrics, getCurrentTrack()?.song.lyricUrl], (newV
}
}, { immediate: true })
//
let handleVisibilityChange: (() => void) | null = null
let handlePageFocus: (() => void) | null = null
onUnmounted(() => {
//
if (handleVisibilityChange) {
document.removeEventListener('visibilitychange', handleVisibilityChange)
}
if (handlePageFocus) {
window.removeEventListener('focus', handlePageFocus)
}
})
//
function setupPageFocusHandlers() {
handleVisibilityChange = () => {
if (document.hidden) {
//
console.log('[Playroom] 页面失去焦点,暂停动画')
} else {
//
console.log('[Playroom] 页面重新获得焦点,同步状态')
nextTick(() => {
resyncLyricsState()
})
}
}
handlePageFocus = () => {
console.log('[Playroom] 窗口获得焦点,同步状态')
nextTick(() => {
resyncLyricsState()
})
}
//
document.addEventListener('visibilitychange', handleVisibilityChange)
window.addEventListener('focus', handlePageFocus)
}
//
function resyncLyricsState() {
const currentTrack = getCurrentTrack()
if (!currentTrack) return
console.log('[Playroom] 重新同步歌词状态')
//
if (controllerRef.value) {
gsap.set(controllerRef.value, {
marginLeft: '0rem',
marginRight: '0rem'
})
}
if (lyricsSection.value) {
gsap.set(lyricsSection.value, {
opacity: 1,
x: 0,
y: 0,
scale: 1
})
}
//
const shouldShowLyrics = preferences.presentLyrics && currentTrack.song.lyricUrl ? true : false
if (shouldShowLyrics !== presentLyrics.value) {
console.log(`[Playroom] 歌词状态不一致,重新设置: ${presentLyrics.value} -> ${shouldShowLyrics}`)
//
presentLyrics.value = shouldShowLyrics
//
if (shouldShowLyrics) {
nextTick(() => {
const tl = gsap.timeline()
tl.from(controllerRef.value, {
marginRight: '-40rem',
duration: 0.4,
ease: "power2.out"
}).fromTo(lyricsSection.value,
{ opacity: 0, x: 50, scale: 0.95 },
{ opacity: 1, x: 0, scale: 1, duration: 0.5, ease: "power2.out" },
"-=0.2"
)
})
}
}
}
// New: Watch for track changes and animate
watch(() => playQueueStore.currentIndex, () => {
if (albumCover.value) {