'use client'; import * as React from 'react'; import { Play, Pause, Square, SkipBack, Volume2, VolumeX, Circle, AlignVerticalJustifyStart, AlignVerticalJustifyEnd, Layers } from 'lucide-react'; import { Button } from '@/components/ui/Button'; import { Slider } from '@/components/ui/Slider'; import { cn } from '@/lib/utils/cn'; export interface PlaybackControlsProps { isPlaying: boolean; isPaused: boolean; currentTime: number; duration: number; volume: number; onPlay: () => void; onPause: () => void; onStop: () => void; onSeek: (time: number, autoPlay?: boolean) => void; onVolumeChange: (volume: number) => void; disabled?: boolean; className?: string; currentTimeFormatted?: string; durationFormatted?: string; isRecording?: boolean; onStartRecording?: () => void; onStopRecording?: () => void; punchInEnabled?: boolean; punchInTime?: number; punchOutTime?: number; onPunchInEnabledChange?: (enabled: boolean) => void; onPunchInTimeChange?: (time: number) => void; onPunchOutTimeChange?: (time: number) => void; overdubEnabled?: boolean; onOverdubEnabledChange?: (enabled: boolean) => void; } export function PlaybackControls({ isPlaying, isPaused, currentTime, duration, volume, onPlay, onPause, onStop, onSeek, onVolumeChange, disabled = false, className, currentTimeFormatted, durationFormatted, isRecording = false, onStartRecording, onStopRecording, punchInEnabled = false, punchInTime = 0, punchOutTime = 0, onPunchInEnabledChange, onPunchInTimeChange, onPunchOutTimeChange, overdubEnabled = false, onOverdubEnabledChange, }: PlaybackControlsProps) { const [isMuted, setIsMuted] = React.useState(false); const [previousVolume, setPreviousVolume] = React.useState(volume); const handlePlayPause = () => { if (isPlaying) { onPause(); } else { onPlay(); } }; const handleMuteToggle = () => { if (isMuted) { onVolumeChange(previousVolume); setIsMuted(false); } else { setPreviousVolume(volume); onVolumeChange(0); setIsMuted(true); } }; const handleVolumeChange = (newVolume: number) => { onVolumeChange(newVolume); if (newVolume === 0) { setIsMuted(true); } else { setIsMuted(false); } }; const progress = duration > 0 ? (currentTime / duration) * 100 : 0; return (
{/* Timeline Slider */}
onSeek(parseFloat(e.target.value), false)} onMouseUp={(e) => onSeek(parseFloat((e.target as HTMLInputElement).value), true)} onTouchEnd={(e) => onSeek(parseFloat((e.target as HTMLInputElement).value), true)} disabled={disabled || duration === 0} className={cn( 'w-full h-2 bg-secondary rounded-lg appearance-none cursor-pointer', 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', 'disabled:opacity-50 disabled:cursor-not-allowed', '[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4', '[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary', '[&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:transition-colors', '[&::-webkit-slider-thumb]:hover:bg-primary/90', '[&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:rounded-full', '[&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:cursor-pointer' )} style={{ background: `linear-gradient(to right, var(--color-primary) ${progress}%, var(--color-secondary) ${progress}%)`, }} />
{currentTimeFormatted || '00:00'} {durationFormatted || '00:00'}
{/* Punch In/Out Times - Show when enabled */} {punchInEnabled && onPunchInTimeChange && onPunchOutTimeChange && (
onPunchInTimeChange(parseFloat(e.target.value))} className="flex-1 px-2 py-1 bg-background border border-border rounded text-xs font-mono" />
onPunchOutTimeChange(parseFloat(e.target.value))} className="flex-1 px-2 py-1 bg-background border border-border rounded text-xs font-mono" />
)} {/* Transport Controls */}
{/* Record Button */} {(onStartRecording || onStopRecording) && ( <> {/* Recording Options */}
{/* Punch In/Out Toggle */} {onPunchInEnabledChange && ( )} {/* Overdub Mode Toggle */} {onOverdubEnabledChange && ( )}
)}
{/* Volume Control */}
); }