fix: proper seeking behavior with optional auto-play

Complete rewrite of seeking logic to support both scrubbing and
click-to-play functionality with proper state management.

Changes:
1. Added autoPlay parameter to seek() methods across the stack
2. Waveform behavior:
   - Click and drag → scrubs WITHOUT auto-play during drag
   - Mouse up after drag → auto-plays from release position
   - This allows smooth scrubbing while dragging
3. Timeline slider behavior:
   - onChange → seeks WITHOUT auto-play (smooth dragging)
   - onMouseUp/onTouchEnd → auto-plays from final position
4. Transport button state now correctly syncs with playback state

Technical implementation:
- player.seek(time, autoPlay) - autoPlay defaults to false
- If autoPlay=true OR was already playing → continues playback
- If autoPlay=false AND wasn't playing → just seeks (isPaused=true)
- useAudioPlayer.seek() now reads actual player state after seeking

User experience:
✓ Click on waveform → music plays from that position
✓ Drag on waveform → scrubs smoothly, plays on release
✓ Drag timeline slider → scrubs smoothly, plays on release
✓ Transport buttons show correct state (Play/Pause)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-17 17:30:11 +01:00
parent 9aac873b53
commit 10d2921147
4 changed files with 44 additions and 18 deletions

View File

@@ -14,7 +14,7 @@ export interface UseAudioPlayerReturn {
play: () => Promise<void>;
pause: () => void;
stop: () => void;
seek: (time: number) => Promise<void>;
seek: (time: number, autoPlay?: boolean) => Promise<void>;
// Volume control
setVolume: (volume: number) => void;
@@ -159,14 +159,16 @@ export function useAudioPlayer(): UseAudioPlayerReturn {
}, [player]);
const seek = React.useCallback(
async (time: number) => {
async (time: number, autoPlay: boolean = false) => {
if (!player) return;
await player.seek(time);
await player.seek(time, autoPlay);
setCurrentTime(time);
// Seek now auto-starts playback, so update state accordingly
setIsPlaying(true);
setIsPaused(false);
// Update state based on what actually happened
const state = player.getState();
setIsPlaying(state.isPlaying);
setIsPaused(state.isPaused);
},
[player]
);