@@ -2,6 +2,7 @@ import { FastForward, Pause, Play, Rewind } from "@phosphor-icons/react";
22import { Box , Button , Flex , Text } from "@radix-ui/themes" ;
33import { useCallback , useEffect , useRef , useState } from "react" ;
44import { useHotkeys } from "react-hotkeys-hook" ;
5+ import { useRecordingStore } from "../stores/recordingStore" ;
56
67interface AudioPlayerProps {
78 recordingId : string ;
@@ -15,13 +16,21 @@ function formatTime(seconds: number): string {
1516}
1617
1718export function AudioPlayer ( { recordingId, duration } : AudioPlayerProps ) {
18- const [ isPlaying , setIsPlaying ] = useState ( false ) ;
19+ const currentlyPlayingId = useRecordingStore (
20+ ( state ) => state . currentlyPlayingId ,
21+ ) ;
22+ const setCurrentlyPlaying = useRecordingStore (
23+ ( state ) => state . setCurrentlyPlaying ,
24+ ) ;
25+ const isPlaying = currentlyPlayingId === recordingId ;
26+
1927 const [ currentTime , setCurrentTime ] = useState ( 0 ) ;
2028 const [ playbackRate , setPlaybackRate ] = useState ( 1 ) ;
2129 const [ isReady , setIsReady ] = useState ( false ) ;
2230 const audioRef = useRef < HTMLAudioElement | null > ( null ) ;
2331 const audioUrlRef = useRef < string | null > ( null ) ;
2432
33+ // Load audio file once when component mounts
2534 useEffect ( ( ) => {
2635 let mounted = true ;
2736 setIsReady ( false ) ;
@@ -37,7 +46,6 @@ export function AudioPlayer({ recordingId, duration }: AudioPlayerProps) {
3746
3847 const audio = new Audio ( url ) ;
3948
40- // Wait for metadata to load
4149 await new Promise < void > ( ( resolve ) => {
4250 audio . addEventListener ( "loadedmetadata" , ( ) => resolve ( ) , {
4351 once : true ,
@@ -48,25 +56,18 @@ export function AudioPlayer({ recordingId, duration }: AudioPlayerProps) {
4856
4957 audioRef . current = audio ;
5058
59+ // Only track time and ended - don't sync play/pause state from audio element
5160 audio . addEventListener ( "timeupdate" , ( ) => {
5261 if ( mounted ) setCurrentTime ( audio . currentTime ) ;
5362 } ) ;
5463
5564 audio . addEventListener ( "ended" , ( ) => {
5665 if ( mounted ) {
57- setIsPlaying ( false ) ;
66+ setCurrentlyPlaying ( null ) ;
5867 setCurrentTime ( 0 ) ;
5968 }
6069 } ) ;
6170
62- audio . addEventListener ( "pause" , ( ) => {
63- if ( mounted ) setIsPlaying ( false ) ;
64- } ) ;
65-
66- audio . addEventListener ( "play" , ( ) => {
67- if ( mounted ) setIsPlaying ( true ) ;
68- } ) ;
69-
7071 setIsReady ( true ) ;
7172 } catch ( error ) {
7273 console . error ( "Failed to load audio:" , error ) ;
@@ -85,17 +86,27 @@ export function AudioPlayer({ recordingId, duration }: AudioPlayerProps) {
8586 URL . revokeObjectURL ( audioUrlRef . current ) ;
8687 }
8788 } ;
88- } , [ recordingId ] ) ;
89+ } , [ recordingId , setCurrentlyPlaying ] ) ;
8990
90- const togglePlayPause = useCallback ( ( ) => {
91- if ( ! audioRef . current ) return ;
91+ // Sync audio element state with global playing state
92+ useEffect ( ( ) => {
93+ const audio = audioRef . current ;
94+ if ( ! audio ) return ;
9295
9396 if ( isPlaying ) {
94- audioRef . current . pause ( ) ;
97+ audio . play ( ) . catch ( ( err ) => {
98+ console . error ( "Failed to play audio:" , err ) ;
99+ setCurrentlyPlaying ( null ) ;
100+ } ) ;
95101 } else {
96- audioRef . current . play ( ) ;
102+ audio . pause ( ) ;
97103 }
98- } , [ isPlaying ] ) ;
104+ } , [ isPlaying , setCurrentlyPlaying ] ) ;
105+
106+ const togglePlayPause = useCallback ( ( ) => {
107+ if ( ! isReady ) return ;
108+ setCurrentlyPlaying ( isPlaying ? null : recordingId ) ;
109+ } , [ isPlaying , isReady , recordingId , setCurrentlyPlaying ] ) ;
99110
100111 const cyclePlaybackRate = useCallback ( ( ) => {
101112 if ( ! audioRef . current ) return ;
0 commit comments