import React, { useState, useRef, useEffect } from 'react'; import { FeedEntry } from '../../types'; import { Play, Pause, RotateCcw, RotateCw, X, ChevronDown, Volume2, } from 'lucide-react'; interface DockedAudioPlayerProps { entry: FeedEntry | null; streamUrl: string | null; isPlaying: boolean; onTogglePlay: () => void; onClose: () => void; } export const DockedAudioPlayer: React.FC = ({ entry, streamUrl, isPlaying, onTogglePlay, onClose, }) => { const [isExpanded, setIsExpanded] = useState(false); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [playbackRate, setPlaybackRate] = useState(1); const audioRef = useRef(null); useEffect(() => { if (!streamUrl) return; if (!audioRef.current) { audioRef.current = new Audio(); } const audio = audioRef.current; audio.src = streamUrl; audio.playbackRate = playbackRate; const updateTime = () => setCurrentTime(audio.currentTime); const updateDuration = () => setDuration(audio.duration || 0); const handleEnded = () => onTogglePlay(); audio.addEventListener('timeupdate', updateTime); audio.addEventListener('loadedmetadata', updateDuration); audio.addEventListener('ended', handleEnded); if (isPlaying) { audio.play().catch(() => {}); } return () => { audio.removeEventListener('timeupdate', updateTime); audio.removeEventListener('loadedmetadata', updateDuration); audio.removeEventListener('ended', handleEnded); audio.pause(); }; }, [streamUrl]); useEffect(() => { if (!audioRef.current) return; if (isPlaying) { audioRef.current.play().catch(() => {}); } else { audioRef.current.pause(); } }, [isPlaying]); useEffect(() => { if (audioRef.current) { audioRef.current.playbackRate = playbackRate; } }, [playbackRate]); if (!entry || !streamUrl) return null; const handleSeek = (newTime: number) => { if (audioRef.current) { audioRef.current.currentTime = newTime; setCurrentTime(newTime); } }; const handleSkip = (seconds: number) => { if (audioRef.current) { const nextTime = Math.max(0, Math.min(audioRef.current.currentTime + seconds, duration)); audioRef.current.currentTime = nextTime; setCurrentTime(nextTime); } }; const formatTime = (secs: number) => { if (isNaN(secs)) return '0:00'; const m = Math.floor(secs / 60); const s = Math.floor(secs % 60); return `${m}:${s < 10 ? '0' : ''}${s}`; }; const progressPercent = duration > 0 ? (currentTime / duration) * 100 : 0; return ( <> {/* Docked Mini Player (Fixed above Bottom Navigation Bar) */}
setIsExpanded(true)}>
{entry.title}
e.stopPropagation()}>
{/* Expanded Full Player Sheet */} {isExpanded && (
setIsExpanded(false)}>
e.stopPropagation()}>
Now Playing

{entry.title}

{entry.feed_title}
{/* Scrubber */}
handleSeek(parseFloat(e.target.value))} className="audio-scrubber-slider" />
{formatTime(currentTime)} {formatTime(duration)}
{/* Play Controls */}
{/* Speed Selector */}
{[0.75, 1.0, 1.25, 1.5, 2.0].map((rate) => ( ))}
)} ); };