add waveform playerbar slider

This commit is contained in:
jeffvli
2025-11-18 02:41:17 -08:00
parent 142a6d6512
commit 7b9007c699
13 changed files with 1162 additions and 56 deletions
@@ -2,6 +2,7 @@ import formatDuration from 'format-duration';
import { useEffect, useRef, useState } from 'react';
import styles from './playerbar-slider.module.css';
import { PlayerbarWaveform } from './playerbar-waveform';
import { MpvPlayer } from '/@/renderer/features/player/audio-player/mpv-player';
import { WebPlayer } from '/@/renderer/features/player/audio-player/web-player';
@@ -14,14 +15,16 @@ import {
usePlayerSong,
usePlayerTimestamp,
} from '/@/renderer/store';
import { PlayerbarSliderType, usePlayerbarSlider } from '/@/renderer/store/settings.store';
import { Slider, SliderProps } from '/@/shared/components/slider/slider';
import { Text } from '/@/shared/components/text/text';
import { PlaybackSelectors } from '/@/shared/constants/playback-selectors';
import { PlayerType } from '/@/shared/types/types';
export const PlayerbarSlider = ({ ...props }: SliderProps) => {
export const PlayerbarSlider = () => {
const playbackType = usePlaybackType();
const currentSong = usePlayerSong();
const playerbarSlider = usePlayerbarSlider();
const songDuration = currentSong?.duration ? currentSong.duration / 1000 : 0;
const [isSeeking, setIsSeeking] = useState(false);
@@ -52,6 +55,8 @@ export const PlayerbarSlider = ({ ...props }: SliderProps) => {
useRemote();
const isWaveform = playerbarSlider?.type === PlayerbarSliderType.WAVEFORM;
return (
<>
<div className={styles.sliderContainer}>
@@ -68,38 +73,40 @@ export const PlayerbarSlider = ({ ...props }: SliderProps) => {
</Text>
</div>
<div className={styles.sliderWrapper}>
<CustomPlayerbarSlider
{...props}
label={(value) => formatDuration(value * 1000)}
max={songDuration}
min={0}
onChange={(e) => {
// Cancel any pending timeout if user starts seeking again
if (seekTimeoutRef.current) {
clearTimeout(seekTimeoutRef.current);
seekTimeoutRef.current = null;
}
setIsSeeking(true);
setSeekValue(e);
}}
onChangeEnd={(e) => {
setSeekValue(e);
handleSeekToTimestamp(e);
{isWaveform ? (
<PlayerbarWaveform />
) : (
<CustomPlayerbarSlider
label={(value) => formatDuration(value * 1000)}
max={songDuration}
min={0}
onChange={(e) => {
// Cancel any pending timeout if user starts seeking again
if (seekTimeoutRef.current) {
clearTimeout(seekTimeoutRef.current);
seekTimeoutRef.current = null;
}
setIsSeeking(true);
setSeekValue(e);
}}
onChangeEnd={(e) => {
setSeekValue(e);
handleSeekToTimestamp(e);
// Delay resetting isSeeking to allow currentTime to catch up
// This prevents the slider from flickering back and forth
seekTimeoutRef.current = setTimeout(() => {
setIsSeeking(false);
seekTimeoutRef.current = null;
}, 300);
}}
onClick={(e) => {
e?.stopPropagation();
}}
size={6}
value={!isSeeking ? currentTime : seekValue}
w="100%"
/>
// Delay resetting isSeeking to allow currentTime to catch up
seekTimeoutRef.current = setTimeout(() => {
setIsSeeking(false);
seekTimeoutRef.current = null;
}, 300);
}}
onClick={(e) => {
e?.stopPropagation();
}}
size={6}
value={!isSeeking ? currentTime : seekValue}
w="100%"
/>
)}
</div>
<div className={styles.sliderValueWrapper}>
<Text