Skip to content

Commit 3143d0b

Browse files
authored
Merge pull request #945 from revisit-studies/hotfix-screen-recording-replay-and-sync
Fix screen recording replay and sync with provenance timeline
2 parents 37ac9aa + 51ab59a commit 3143d0b

3 files changed

Lines changed: 34 additions & 14 deletions

File tree

src/analysis/individualStudy/thinkAloud/ThinkAloudFooter.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ async function getTags(storageEngine: StorageEngine | undefined, type: 'particip
6262
}
6363

6464
export function ThinkAloudFooter({
65-
visibleParticipants, rawTranscript, currentShownTranscription, width, onTimeUpdate, isReplay, editedTranscript, currentTrial, saveProvenance, jumpedToLine = 0, studyId, setHasAudio, storageEngine,
65+
visibleParticipants, rawTranscript, currentShownTranscription, width, onTimeUpdate, isReplay, editedTranscript, currentTrial, saveProvenance, jumpedToLine = 0, studyId, setHasAudio, storageEngine, forceMute, onAnalysisIsPlayingChange, onProvenanceTimelineChange,
6666
} : {
67-
visibleParticipants: string[], rawTranscript: TranscribedAudio | null, currentShownTranscription: number | null, width: number, onTimeUpdate: (n: number) => void, isReplay: boolean, editedTranscript?: EditedText[], currentTrial: string, saveProvenance: (prov: unknown) => void, jumpedToLine?: number, studyId: string, setHasAudio: (b: boolean) => void, storageEngine: StorageEngine | undefined,
67+
visibleParticipants: string[], rawTranscript: TranscribedAudio | null, currentShownTranscription: number | null, width: number, onTimeUpdate: (n: number) => void, isReplay: boolean, editedTranscript?: EditedText[], currentTrial: string, saveProvenance: (prov: unknown) => void, jumpedToLine?: number, studyId: string, setHasAudio: (b: boolean) => void, storageEngine: StorageEngine | undefined, forceMute?: boolean, onAnalysisIsPlayingChange?: (b: boolean) => void, onProvenanceTimelineChange?: (n: number)=> void,
6868
}) {
6969
const auth = useAuth();
7070

@@ -80,7 +80,9 @@ export function ThinkAloudFooter({
8080

8181
const { value: allParticipantTags, execute: pullAllParticipantTags } = useAsync(getTags, [storageEngine, 'participant']);
8282
const [analysisIsPlaying, _setAnalysisIsPlaying] = useState(false);
83-
const [isMuted, setIsMuted] = useState(true);
83+
84+
const [_isMuted, setIsMuted] = useState(true);
85+
const isMuted = forceMute ? true : _isMuted;
8486

8587
const [audioUrl, setAudioUrl] = useState<string | null>(null);
8688
const [screenRecordingUrl, setScreenRecordingUrl] = useState<string | null>(null);
@@ -142,7 +144,9 @@ export function ThinkAloudFooter({
142144
setIsMuted(true);
143145
}
144146
_setAnalysisIsPlaying(playing);
145-
}, []);
147+
148+
onAnalysisIsPlayingChange && onAnalysisIsPlayingChange(playing);
149+
}, [onAnalysisIsPlayingChange]);
146150

147151
const [transcriptLines, setTranscriptLines] = useState<TranscriptLinesWithTimes[] | null>(null);
148152

@@ -278,15 +282,15 @@ export function ThinkAloudFooter({
278282
<AppShell.Footer zIndex={101} withBorder={false}>
279283
<Stack style={{ backgroundColor: 'var(--mantine-color-blue-1)', height: '100%' }} gap={5} justify="center">
280284

281-
<AudioProvenanceVis isMuted={isMuted} setHasAudio={setHasAudio} jumpedToAudioTime={jumpedToTime} speed={speed} setSpeed={setSpeed} saveProvenance={saveProvenance} analysisIsPlaying={analysisIsPlaying} setAnalysisIsPlaying={setAnalysisIsPlaying} setTime={onTimeUpdate} setTimeString={(_t) => setTimeString(_t)} answers={participant ? participant.answers : {}} taskName={currentTrial} context={isReplay ? 'provenanceVis' : 'audioAnalysis'} />
285+
<AudioProvenanceVis isMuted={isMuted} setHasAudio={setHasAudio} jumpedToAudioTime={jumpedToTime} speed={speed} setSpeed={setSpeed} saveProvenance={saveProvenance} analysisIsPlaying={analysisIsPlaying} setAnalysisIsPlaying={setAnalysisIsPlaying} setTime={onTimeUpdate} setTimeString={(_t) => setTimeString(_t)} answers={participant ? participant.answers : {}} taskName={currentTrial} context={isReplay ? 'provenanceVis' : 'audioAnalysis'} onProvenanceTimelineChange={onProvenanceTimelineChange} />
282286
{xScale && transcriptLines ? <TranscriptSegmentsVis startTime={xScale.domain()[0]} xScale={xScale} transcriptLines={transcriptLines} currentShownTranscription={currentShownTranscription || 0} /> : null }
283287

284288
<Group gap="xs" style={{ width: '100%' }} justify="center" wrap="nowrap">
285289
<Group wrap="nowrap">
286290
<Text ff="monospace" style={{ textAlign: 'right' }} mt="lg" c="dimmed">{timeString}</Text>
287291

288292
<Tooltip label="Play">
289-
<ActionIcon mt={25} size="xl" variant="light" onClick={() => { setAnalysisIsPlaying(!analysisIsPlaying); setIsMuted(!isMuted); }}>
293+
<ActionIcon mt={25} size="xl" variant="light" onClick={() => { setAnalysisIsPlaying(!analysisIsPlaying); setIsMuted(!_isMuted); }}>
290294
{analysisIsPlaying ? <IconPlayerPauseFilled /> : <IconPlayerPlayFilled /> }
291295
</ActionIcon>
292296
</Tooltip>

src/components/audioAnalysis/AudioProvenanceVis.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ function safe<T>(p: Promise<T>): Promise<T | null> {
3131
}
3232

3333
export function AudioProvenanceVis({
34-
setTimeString, answers, setTime, taskName, context, saveProvenance, analysisIsPlaying, setAnalysisIsPlaying, speed, jumpedToAudioTime, setHasAudio, setSpeed, isMuted,
35-
}: { setTimeString: (time: string) => void; answers: Record<string, StoredAnswer>, setTime: (time: number) => void, taskName: string, context: 'audioAnalysis' | 'provenanceVis', saveProvenance: ((state: unknown) => void), analysisIsPlaying: boolean, setAnalysisIsPlaying: (b: boolean) => void, speed: number, jumpedToAudioTime: number, setHasAudio: (b: boolean) => void, setSpeed: (n: number) => void, isMuted: boolean }) {
34+
setTimeString, answers, setTime, taskName, context, saveProvenance, analysisIsPlaying, setAnalysisIsPlaying, speed, jumpedToAudioTime, setHasAudio, setSpeed, isMuted, onProvenanceTimelineChange,
35+
}: { setTimeString: (time: string) => void; answers: Record<string, StoredAnswer>, setTime: (time: number) => void, taskName: string, context: 'audioAnalysis' | 'provenanceVis', saveProvenance: ((state: unknown) => void), analysisIsPlaying: boolean, setAnalysisIsPlaying: (b: boolean) => void, speed: number, jumpedToAudioTime: number, setHasAudio: (b: boolean) => void, setSpeed: (n: number) => void, isMuted: boolean, onProvenanceTimelineChange?: (n: number) => void }) {
3636
const [searchParams, setSearchParams] = useSearchParams();
3737
const participantId = useMemo(() => searchParams.get('participantId') || '', [searchParams]);
3838

@@ -139,6 +139,7 @@ export function AudioProvenanceVis({
139139
}
140140

141141
setPlayTime(n);
142+
onProvenanceTimelineChange && onProvenanceTimelineChange(n - startTime);
142143

143144
if (wavesurfer.current && percent !== undefined && !Number.isNaN(percent)) {
144145
setTimeout(() => {
@@ -149,7 +150,7 @@ export function AudioProvenanceVis({
149150
if (setTime) {
150151
setTime(n);
151152
}
152-
}, [setAnalysisIsPlaying, setTime, startTime, totalAudioLength]);
153+
}, [setAnalysisIsPlaying, setTime, startTime, totalAudioLength, onProvenanceTimelineChange]);
153154

154155
useEffect(() => {
155156
_setPlayTime(startTime + jumpedToAudioTime * 1000 + 1, undefined);

src/components/interface/AnalysisFooter.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { useDispatch } from 'react-redux';
21
import { useParams } from 'react-router';
32

3+
import { useCallback } from 'react';
44
import { useAsync } from '../../store/hooks/useAsync';
55

66
import { useStorageEngine } from '../../storage/storageEngineHooks';
77
import { StorageEngine } from '../../storage/engines/types';
88
import { ThinkAloudFooter } from '../../analysis/individualStudy/thinkAloud/ThinkAloudFooter';
99
import { useCurrentIdentifier } from '../../routes/utils';
10-
import { useStoreActions } from '../../store/store';
10+
import { useStoreActions, useStoreDispatch } from '../../store/store';
11+
import { useRecordingConfig } from '../../store/hooks/useRecordingConfig';
1112

1213
function getAllParticipantsNames(storageEngine: StorageEngine | undefined) {
1314
if (storageEngine) {
@@ -23,16 +24,30 @@ export function AnalysisFooter({ setHasAudio }: {setHasAudio: (b: boolean) => vo
2324

2425
const identifier = useCurrentIdentifier();
2526

26-
const dispatch = useDispatch();
27+
const storeDispatch = useStoreDispatch();
28+
29+
const { currentComponentHasScreenRecording } = useRecordingConfig();
2730

2831
const { studyId } = useParams();
2932

3033
const {
3134
saveAnalysisState,
3235
} = useStoreActions();
3336

37+
const { setAnalysisIsPlaying, setProvenanceJumpTime } = useStoreActions();
38+
39+
const handleProvenanceTimelineChange = useCallback((n: number) => {
40+
storeDispatch(setProvenanceJumpTime(n));
41+
}, [storeDispatch, setProvenanceJumpTime]);
42+
43+
const handleAnalysisIsPlayingChange = useCallback((isPlaying: boolean) => {
44+
storeDispatch(setAnalysisIsPlaying(isPlaying));
45+
}, [storeDispatch, setAnalysisIsPlaying]);
46+
47+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
48+
const saveProvenance = useCallback((prov: any) => storeDispatch(saveAnalysisState(prov)), [storeDispatch, saveAnalysisState]);
49+
3450
return (
35-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
36-
<ThinkAloudFooter storageEngine={storageEngine} setHasAudio={setHasAudio} studyId={studyId || ''} currentTrial={identifier} isReplay visibleParticipants={allParticipants || []} rawTranscript={null} currentShownTranscription={null} width={3000} onTimeUpdate={() => {}} saveProvenance={(prov: any) => dispatch(saveAnalysisState(prov))} />
51+
<ThinkAloudFooter storageEngine={storageEngine} setHasAudio={setHasAudio} studyId={studyId || ''} currentTrial={identifier} isReplay visibleParticipants={allParticipants || []} rawTranscript={null} currentShownTranscription={null} width={3000} onTimeUpdate={() => {}} saveProvenance={saveProvenance} onProvenanceTimelineChange={handleProvenanceTimelineChange} onAnalysisIsPlayingChange={handleAnalysisIsPlayingChange} forceMute={currentComponentHasScreenRecording} />
3752
);
3853
}

0 commit comments

Comments
 (0)