diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index e74edf60c..b5361edee 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -781,6 +781,8 @@ "playerbarWaveformRadius": "waveform radius", "preferLocalLyrics_description": "prefer local lyrics over remote lyrics when available", "preferLocalLyrics": "prefer local lyrics", + "showLyricsInSidebar_description": "a panel will be added to the attached play queue that displays the lyrics", + "showLyricsInSidebar": "show lyrics in attached play queue", "preservePitch_description": "preserves pitch when modifying playback speed", "preservePitch": "preserve pitch", "preventSleepOnPlayback_description": "prevent the display from sleeping while music is playing", diff --git a/src/renderer/features/lyrics/synchronized-lyrics.tsx b/src/renderer/features/lyrics/synchronized-lyrics.tsx index f702b4cb2..8ffce1f18 100644 --- a/src/renderer/features/lyrics/synchronized-lyrics.tsx +++ b/src/renderer/features/lyrics/synchronized-lyrics.tsx @@ -1,12 +1,17 @@ import clsx from 'clsx'; import isElectron from 'is-electron'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef } from 'react'; import styles from './synchronized-lyrics.module.css'; import { LyricLine } from '/@/renderer/features/lyrics/lyric-line'; -import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events'; -import { useLyricsSettings, usePlaybackType, usePlayerActions } from '/@/renderer/store'; +import { + useLyricsSettings, + usePlaybackType, + usePlayerActions, + usePlayerStatus, +} from '/@/renderer/store'; +import { usePlayerTimestamp } from '/@/renderer/store/timestamp.store'; import { FullLyricsMetadata, SynchronizedLyricsArray } from '/@/shared/types/domain-types'; import { PlayerStatus, PlayerType } from '/@/shared/types/types'; @@ -30,10 +35,8 @@ export const SynchronizedLyrics = ({ const playbackType = usePlaybackType(); const settings = useLyricsSettings(); const { mediaSeekToTimestamp } = usePlayerActions(); - - // State for player status and timestamp from events - const [status, setStatus] = useState(PlayerStatus.PAUSED); - const [timestamp, setTimestamp] = useState(0); + const status = usePlayerStatus(); + const timestamp = usePlayerTimestamp(); const handleSeek = useCallback( (time: number) => { @@ -154,23 +157,6 @@ export const SynchronizedLyrics = ({ setCurrentLyricRef.current = setCurrentLyric; }, [setCurrentLyric]); - // Subscribe to player events - usePlayerEvents( - { - onPlayerProgress: (properties) => { - setTimestamp(properties.timestamp); - }, - onPlayerSeekToTimestamp: (properties) => { - // When seeking, update timestamp immediately - setTimestamp(properties.timestamp); - }, - onPlayerStatus: (properties) => { - setStatus(properties.status); - }, - }, - [], - ); - useEffect(() => { // Copy the follow settings into a ref that can be accessed in the timeout followRef.current = settings.follow; diff --git a/src/renderer/features/now-playing/components/sidebar-play-queue.module.css b/src/renderer/features/now-playing/components/sidebar-play-queue.module.css new file mode 100644 index 000000000..e8e8dc1cf --- /dev/null +++ b/src/renderer/features/now-playing/components/sidebar-play-queue.module.css @@ -0,0 +1,27 @@ +.play-queue-section { + display: flex; + flex: 1; + flex-direction: column; + min-height: 0; + overflow: hidden; +} + +.lyrics-section { + position: relative; + display: flex; + flex: 0 0 300px; + flex-direction: column; + min-height: 200px; + max-height: 400px; + overflow: hidden; + background: var(--theme-colors-background); +} + +.lyrics-section :global(.synchronized-lyrics) { + padding: 2rem 0 4rem !important; + transform: translateY(0) !important; +} + +.lyrics-section :global(.synchronized-lyrics .lyric-line) { + padding: 0.25rem 0; +} diff --git a/src/renderer/features/now-playing/components/sidebar-play-queue.tsx b/src/renderer/features/now-playing/components/sidebar-play-queue.tsx index f15ef4ca8..201621646 100644 --- a/src/renderer/features/now-playing/components/sidebar-play-queue.tsx +++ b/src/renderer/features/now-playing/components/sidebar-play-queue.tsx @@ -1,14 +1,21 @@ import { useRef, useState } from 'react'; +import styles from './sidebar-play-queue.module.css'; + import { ItemListHandle } from '/@/renderer/components/item-list/types'; +import { Lyrics } from '/@/renderer/features/lyrics/lyrics'; import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queue'; import { PlayQueueListControls } from '/@/renderer/features/now-playing/components/play-queue-list-controls'; +import { useLyricsSettings } from '/@/renderer/store'; +import { Divider } from '/@/shared/components/divider/divider'; +import { Flex } from '/@/shared/components/flex/flex'; import { Stack } from '/@/shared/components/stack/stack'; import { ItemListKey } from '/@/shared/types/types'; export const SidebarPlayQueue = () => { const tableRef = useRef(null); const [search, setSearch] = useState(undefined); + const { showLyricsInSidebar } = useLyricsSettings(); return ( @@ -18,7 +25,23 @@ export const SidebarPlayQueue = () => { tableRef={tableRef} type={ItemListKey.SIDE_QUEUE} /> - + +
+ +
+ {showLyricsInSidebar && ( + <> + +
+ +
+ + )} +
); }; diff --git a/src/renderer/features/settings/components/general/lyric-settings.tsx b/src/renderer/features/settings/components/general/lyric-settings.tsx index aafdeeb74..ffee58f21 100644 --- a/src/renderer/features/settings/components/general/lyric-settings.tsx +++ b/src/renderer/features/settings/components/general/lyric-settings.tsx @@ -43,6 +43,27 @@ export const LyricSettings = () => { }), title: t('setting.followLyric', { postProcess: 'sentenceCase' }), }, + { + control: ( + { + setSettings({ + lyrics: { + ...settings, + showLyricsInSidebar: e.currentTarget.checked, + }, + }); + }} + /> + ), + description: t('setting.showLyricsInSidebar', { + context: 'description', + postProcess: 'sentenceCase', + }), + title: t('setting.showLyricsInSidebar', { postProcess: 'sentenceCase' }), + }, { control: (