@@ -18,7 +18,8 @@ import {
1818import DeleteIcon from '@mui/icons-material/Delete' ;
1919import PlayArrowIcon from '@mui/icons-material/PlayArrow' ;
2020import PauseIcon from '@mui/icons-material/Pause' ;
21- import { FaForwardStep , FaEarListen } from 'react-icons/fa6' ;
21+ import ArrowForwardIcon from '@mui/icons-material/ArrowForward' ;
22+ import { FaEarListen } from 'react-icons/fa6' ;
2223import { useContext , useEffect , useMemo , useRef , useState } from 'react' ;
2324import {
2425 ArtifactTypeSlug ,
@@ -64,11 +65,18 @@ import DiscussionPanel from '../../components/Discussions/DiscussionPanel';
6465import PassageDetailMobileLayout from './mobile/PassageDetailMobileLayout' ;
6566import MobileWorkflowSteps from './mobile/MobileWorkflowSteps' ;
6667import PassageAudioHeaderMobile from './mobile/PassageAudioHeaderMobile' ;
68+ import HighlightButton from './mobile/HighlightButton' ;
6769import SegmentStatusMobile from './mobile/SegmentStatusMobile' ;
6870import PassageDetailMobileFooter from './mobile/PassageDetailMobileFooter' ;
6971import { WSAudioPlayerControls } from '../WSAudioPlayer' ;
7072import { parseRegions } from '../../crud/useWavesurferRegions' ;
7173
74+ enum Activity {
75+ Listen ,
76+ Record ,
77+ Next ,
78+ }
79+
7280const PlayerRow = styled ( Box ) < BoxProps > ( ( ) => ( {
7381 width : '100%' ,
7482 '& audio' : {
@@ -121,6 +129,7 @@ export function PassageDetailItem(props: IProps) {
121129 const [ organization ] = useGlobal ( 'organization' ) ;
122130 const [ plan ] = useGlobal ( 'plan' ) ; //will be constant here
123131 const { fetchMediaUrl, mediaState } = useFetchMediaUrl ( reporter ) ;
132+ const [ activity , setActivity ] = useState < Activity > ( Activity . Listen ) ;
124133 const [ statusText , setStatusText ] = useState ( '' ) ;
125134 const [ canSave , setCanSave ] = useState ( false ) ;
126135 const [ defaultFilename , setDefaultFileName ] = useState ( '' ) ;
@@ -406,14 +415,38 @@ export function PassageDetailItem(props: IProps) {
406415 setRecording ( recorderRecordingRef . current || recorderPlayingRef . current ) ;
407416 } ;
408417 const handleRecorderRecording = ( recording : boolean ) => {
418+ const wasRecording = recorderRecordingRef . current ;
409419 recorderRecordingRef . current = recording ;
410420 updateRecorderBusy ( ) ;
421+ if ( wasRecording && ! recording ) {
422+ setActivity ( Activity . Next ) ;
423+ }
411424 } ;
412425 const handleRecorderPlayStatus = ( playing : boolean ) => {
413426 recorderPlayingRef . current = playing ;
414427 setIsRecorderPlaying ( playing ) ;
415428 updateRecorderBusy ( ) ;
416429 } ;
430+ const handleSegmentFinished = ( ) => {
431+ if ( segments ) {
432+ setActivity ( Activity . Record ) ;
433+ }
434+ } ;
435+ const nextSegmentPlayTimerRef = useRef < ReturnType < typeof setTimeout > | null > (
436+ null
437+ ) ;
438+ const handleNextSegmentClick = ( ) => {
439+ setActivity ( Activity . Next ) ;
440+ playerControlsRef . current ?. nextSegment ( ) ;
441+ if ( nextSegmentPlayTimerRef . current ) {
442+ clearTimeout ( nextSegmentPlayTimerRef . current ) ;
443+ }
444+ nextSegmentPlayTimerRef . current = setTimeout ( ( ) => {
445+ if ( ! playerControlsRef . current ?. isPlaying ( ) ) {
446+ playerControlsRef . current ?. togglePlay ( ) ;
447+ }
448+ } , 75 ) ;
449+ } ;
417450 const onSegmentParamChange = (
418451 params : IRegionParams ,
419452 teamDefault : boolean
@@ -474,6 +507,7 @@ export function PassageDetailItem(props: IProps) {
474507 ? SaveSegments . showSaveButton
475508 : undefined
476509 }
510+ forceRegionOnly = { Boolean ( segments ) }
477511 defaultSegParams = { segParams }
478512 suggestedSegments = { segString }
479513 verses = { verses }
@@ -492,6 +526,7 @@ export function PassageDetailItem(props: IProps) {
492526 hideSegmentControls = { false }
493527 onProgress = { setPlayerProgress }
494528 onDuration = { setPlayerDuration }
529+ onSegmentFinished = { handleSegmentFinished }
495530 onInteraction = { ( ) => {
496531 showSegmentsChangedMessage ( ) ;
497532 userSegmentInteractionRef . current = true ;
@@ -596,24 +631,34 @@ export function PassageDetailItem(props: IProps) {
596631 justifyContent : 'center' ,
597632 alignItems : 'center' ,
598633 width : '100%' ,
634+ gap : 1 ,
599635 py : 1 ,
600636 } }
601637 >
602- < IconButton
603- aria-label = "Listen"
604- onClick = { ( ) => playerControlsRef . current ?. togglePlay ( ) }
638+ < HighlightButton
639+ ariaLabel = "Listen"
640+ onClick = { ( ) => {
641+ setActivity ( Activity . Listen ) ;
642+ playerControlsRef . current ?. togglePlay ( ) ;
643+ } }
644+ disabled = { false }
645+ highlight = { activity === Activity . Listen }
605646 >
606647 < FaEarListen />
607- </ IconButton >
648+ </ HighlightButton >
608649 < RecordButton
609650 recording = { recorderRecordingRef . current }
610651 oneTryOnly = { true }
611- onClick = { ( ) => recorderControlsRef . current ?. toggleRecord ( ) }
652+ onClick = { ( ) => {
653+ setActivity ( Activity . Record ) ;
654+ recorderControlsRef . current ?. toggleRecord ( ) ;
655+ } }
612656 disabled = { playing }
613657 isSmall = { false }
614658 showText = { Boolean ( currentSegmentMediaId ) }
615659 hasRecording = { Boolean ( currentSegmentMediaId ) }
616660 isStopLogic = { true }
661+ active = { activity === Activity . Record }
617662 />
618663 { canSave && (
619664 < PriButton
@@ -629,12 +674,16 @@ export function PassageDetailItem(props: IProps) {
629674 { ts . save }
630675 </ PriButton >
631676 ) }
632- < IconButton
633- aria-label = "Next Segment"
634- onClick = { ( ) => playerControlsRef . current ?. nextSegment ( ) }
677+ < HighlightButton
678+ ariaLabel = "Next Segment"
679+ onClick = { ( ) => {
680+ handleNextSegmentClick ( ) ;
681+ } }
682+ disabled = { false }
683+ highlight = { activity === Activity . Next }
635684 >
636- < FaForwardStep />
637- </ IconButton >
685+ < ArrowForwardIcon />
686+ </ HighlightButton >
638687 </ Box >
639688 </ >
640689 ) ;
@@ -651,12 +700,17 @@ export function PassageDetailItem(props: IProps) {
651700 playing = { playing }
652701 progress = { playerProgress }
653702 duration = { playerDuration }
654- onTogglePlay = { ( ) => playerControlsRef . current ?. togglePlay ( ) }
703+ onTogglePlay = { ( ) => {
704+ setActivity ( Activity . Listen ) ;
705+ playerControlsRef . current ?. togglePlay ( ) ;
706+ } }
655707 onPrevSegment = { ( ) => playerControlsRef . current ?. prevSegment ( ) }
656- onNextSegment = { ( ) => playerControlsRef . current ?. nextSegment ( ) }
657- highlightPrev = { currentSegmentIndex > 1 }
708+ onNextSegment = { handleNextSegmentClick }
709+ highlightPlay = { activity === Activity . Listen }
710+ highlightPrev = { false }
658711 highlightNext = {
659- currentSegmentIndex > 0 && currentSegmentIndex < segmentCount
712+ activity === Activity . Next &&
713+ currentSegmentIndex < segmentCount
660714 }
661715 />
662716 </ >
@@ -740,6 +794,7 @@ export function PassageDetailItem(props: IProps) {
740794 ? SaveSegments . showSaveButton
741795 : undefined
742796 }
797+ forceRegionOnly = { Boolean ( segments ) }
743798 defaultSegParams = { segParams }
744799 suggestedSegments = { segString }
745800 verses = { verses }
@@ -762,6 +817,7 @@ export function PassageDetailItem(props: IProps) {
762817 showSegmentsChangedMessage ( ) ;
763818 userSegmentInteractionRef . current = true ;
764819 } }
820+ onSegmentFinished = { handleSegmentFinished }
765821 />
766822 < Box >
767823 < Box sx = { rowProp } >
0 commit comments