/* eslint-disable jsx-a11y/media-has-caption */ import React, { ReactNode, useCallback, useRef, useState } from 'react'; import { Badge, Chip, Icon, IconButton, Icons, ProgressBar, Spinner, Text, toRem } from 'folds'; import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment'; import { Range } from 'react-range'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { getFileSrcUrl } from './util'; import { IAudioInfo } from '../../../../types/matrix/common'; import { PlayTimeCallback, useMediaLoading, useMediaPlay, useMediaPlayTimeCallback, useMediaSeek, useMediaVolume, } from '../../../hooks/media'; import { useThrottle } from '../../../hooks/useThrottle'; import { secondsToMinutesAndSeconds } from '../../../utils/common'; import { mxcUrlToHttp } from '../../../utils/matrix'; import { useSpecVersions } from '../../../hooks/useSpecVersions'; const PLAY_TIME_THROTTLE_OPS = { wait: 500, immediate: true, }; type RenderMediaControlProps = { after: ReactNode; leftControl: ReactNode; rightControl: ReactNode; children: ReactNode; }; export type AudioContentProps = { mimeType: string; url: string; info: IAudioInfo; encInfo?: EncryptedAttachmentInfo; renderMediaControl: (props: RenderMediaControlProps) => ReactNode; }; export function AudioContent({ mimeType, url, info, encInfo, renderMediaControl, }: AudioContentProps) { const mx = useMatrixClient(); const { versions } = useSpecVersions(); const useAuthentication = versions.includes('v1.11'); const [srcState, loadSrc] = useAsyncCallback( useCallback( () => getFileSrcUrl(mxcUrlToHttp(mx, url, useAuthentication) ?? '', mimeType, encInfo), [mx, url, useAuthentication, mimeType, encInfo] ) ); const audioRef = useRef(null); const [currentTime, setCurrentTime] = useState(0); // duration in seconds. (NOTE: info.duration is in milliseconds) const infoDuration = info.duration ?? 0; const [duration, setDuration] = useState((infoDuration >= 0 ? infoDuration : 0) / 1000); const getAudioRef = useCallback(() => audioRef.current, []); const { loading } = useMediaLoading(getAudioRef); const { playing, setPlaying } = useMediaPlay(getAudioRef); const { seek } = useMediaSeek(getAudioRef); const { volume, mute, setMute, setVolume } = useMediaVolume(getAudioRef); const handlePlayTimeCallback: PlayTimeCallback = useCallback((d, ct) => { setDuration(d); setCurrentTime(ct); }, []); useMediaPlayTimeCallback( getAudioRef, useThrottle(handlePlayTimeCallback, PLAY_TIME_THROTTLE_OPS) ); const handlePlay = () => { if (srcState.status === AsyncStatus.Success) { setPlaying(!playing); } else if (srcState.status !== AsyncStatus.Loading) { loadSrc(); } }; return renderMediaControl({ after: ( seek(values[0])} renderTrack={(params) => (
{params.children}
)} renderThumb={(params) => ( )} /> ), leftControl: ( <> ) : ( ) } > {playing ? 'Pause' : 'Play'} {`${secondsToMinutesAndSeconds( currentTime )} / ${secondsToMinutesAndSeconds(duration)}`} ), rightControl: ( <> setMute(!mute)} aria-pressed={mute} > setVolume(values[0])} renderTrack={(params) => (
{params.children}
)} renderThumb={(params) => ( )} /> ), children: ( ), }); }