fix: fix playback button

This commit is contained in:
JohnMark Sill 2022-02-16 22:24:54 -06:00
parent 376830cf6e
commit db2423cd0f
5 changed files with 94 additions and 56 deletions

View File

@ -1,5 +1,5 @@
import { h } from 'preact'; import { h } from 'preact';
import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks'; import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { useApiHost } from '../../api'; import { useApiHost } from '../../api';
interface OnTimeUpdateEvent { interface OnTimeUpdateEvent {
@ -66,23 +66,40 @@ export const HistoryVideo = ({
} }
}, [id, videoHeight]); }, [id, videoHeight]);
const playVideo = (video: HTMLMediaElement) => {
const videoHasNotLoaded = video.readyState <= 1;
if (videoHasNotLoaded) {
video.load();
}
video.play().catch((e) => {
console.error('Fail', e);
});
};
useEffect(() => { useEffect(() => {
const playVideo = (video: HTMLMediaElement) => {
console.debug('playVideo: attempt playback');
video
.play()
.then(() => {
console.debug('playVideo: video started');
})
.catch((e) => {
console.error('Fail', { e });
});
};
const attemptPlayVideo = (video: HTMLMediaElement) => {
const videoHasNotLoaded = video.readyState <= 1;
console.debug('playVideo', { videoHasNotLoaded });
if (videoHasNotLoaded) {
console.debug('playVideo: attempt to load video');
video.oncanplay = () => {
console.debug('onLoad: video loaded');
playVideo(video);
};
video.load();
} else {
playVideo(video);
}
};
const video = videoRef.current; const video = videoRef.current;
const videoExists = !isNullOrUndefined(video); const videoExists = !isNullOrUndefined(video);
if (videoExists) { if (videoExists) {
console.log('check should start', { videoIsPlaying });
if (videoIsPlaying) { if (videoIsPlaying) {
playVideo(video); attemptPlayVideo(video);
} else { } else {
video.pause(); video.pause();
} }
@ -110,28 +127,24 @@ export const HistoryVideo = ({
[videoIsPlaying] [videoIsPlaying]
); );
const Video = useCallback(() => { const videoPropertiesIsUndefined = isNullOrUndefined(videoProperties);
const videoPropertiesIsUndefined = isNullOrUndefined(videoProperties); if (videoPropertiesIsUndefined) {
if (videoPropertiesIsUndefined) { return <div style={{ height: `${videoHeight}px`, width: '100%' }}></div>;
return <div style={{ height: `${videoHeight}px`, width: '100%' }}></div>; }
} const { posterUrl, videoUrl, height } = videoProperties;
const { posterUrl, videoUrl, height } = videoProperties; return (
return ( <video
<video ref={videoRef}
ref={videoRef} onTimeUpdate={onTimeUpdateHandler}
onTimeUpdate={onTimeUpdateHandler} onPause={onPause}
onPause={onPause} onPlay={onPlay}
onPlay={onPlay} poster={posterUrl}
poster={posterUrl} preload='metadata'
preload='metadata' controls
controls style={height ? { minHeight: `${height}px` } : {}}
style={height ? { minHeight: `${height}px` } : {}} playsInline
playsInline >
> <source type='application/vnd.apple.mpegurl' src={videoUrl} />
<source type='application/vnd.apple.mpegurl' src={videoUrl} /> </video>
</video> );
);
}, [videoProperties, videoHeight, videoRef]);
return <Video />;
}; };

View File

@ -2,12 +2,12 @@ import { Fragment, h } from 'preact';
import { useEffect, useState } from 'preact/hooks'; import { useEffect, useState } from 'preact/hooks';
import { useEvents } from '../../api'; import { useEvents } from '../../api';
import { useSearchString } from '../../hooks/useSearchString'; import { useSearchString } from '../../hooks/useSearchString';
import { HistoryHeader } from './HistoryHeader';
import Timeline from '../Timeline/Timeline';
import { HistoryVideo } from './HistoryVideo';
import { TimelineEvent } from '../Timeline/TimelineEvent';
import { TimelineChangeEvent } from '../Timeline/TimelineChangeEvent';
import { getNowYesterdayInLong } from '../../utils/dateUtil'; import { getNowYesterdayInLong } from '../../utils/dateUtil';
import Timeline from '../Timeline/Timeline';
import { TimelineChangeEvent } from '../Timeline/TimelineChangeEvent';
import { TimelineEvent } from '../Timeline/TimelineEvent';
import { HistoryHeader } from './HistoryHeader';
import { HistoryVideo } from './HistoryVideo';
export default function HistoryViewer({ camera }) { export default function HistoryViewer({ camera }) {
const { searchString } = useSearchString(500, `camera=${camera}&after=${getNowYesterdayInLong()}`); const { searchString } = useSearchString(500, `camera=${camera}&after=${getNowYesterdayInLong()}`);
@ -38,10 +38,6 @@ export default function HistoryViewer({ camera }) {
} }
}; };
const handlePlay = () => {
setIsPlaying((previous) => !previous);
};
const onPlayHandler = () => { const onPlayHandler = () => {
setIsPlaying(true); setIsPlaying(true);
}; };
@ -50,9 +46,10 @@ export default function HistoryViewer({ camera }) {
setIsPlaying(false); setIsPlaying(false);
}; };
const handlePrevious = () => {}; const onPlayPauseHandler = (isPlaying: boolean) => {
console.debug('onPlayPauseHandler: setting isPlaying', { isPlaying });
const handleNext = () => {}; setIsPlaying(isPlaying);
};
return ( return (
<Fragment> <Fragment>
@ -72,7 +69,12 @@ export default function HistoryViewer({ camera }) {
</div> </div>
</Fragment> </Fragment>
<Timeline events={timelineEvents} onChange={handleTimelineChange} /> <Timeline
events={timelineEvents}
isPlaying={isPlaying}
onChange={handleTimelineChange}
onPlayPause={onPlayPauseHandler}
/>
</Fragment> </Fragment>
); );
} }

View File

@ -9,10 +9,12 @@ import { TimelineEventBlock } from './TimelineEventBlock';
interface TimelineProps { interface TimelineProps {
events: TimelineEvent[]; events: TimelineEvent[];
isPlaying: boolean;
onChange: (event: TimelineChangeEvent) => void; onChange: (event: TimelineChangeEvent) => void;
onPlayPause: (isPlaying: boolean) => void;
} }
export default function Timeline({ events, onChange }: TimelineProps) { export default function Timeline({ events, isPlaying, onChange, onPlayPause }: TimelineProps) {
const timelineContainerRef = useRef<HTMLDivElement>(undefined); const timelineContainerRef = useRef<HTMLDivElement>(undefined);
const [timeline, setTimeline] = useState<TimelineEventBlock[]>([]); const [timeline, setTimeline] = useState<TimelineEventBlock[]>([]);
@ -235,7 +237,10 @@ export default function Timeline({ events, onChange }: TimelineProps) {
setMarkerTime(getCurrentMarkerTime()); setMarkerTime(getCurrentMarkerTime());
}; };
const onPlayPauseHandler = () => {}; const onPlayPauseHandler = (isPlaying: boolean) => {
onPlayPause(isPlaying);
};
const onPreviousHandler = () => { const onPreviousHandler = () => {
if (currentEvent) { if (currentEvent) {
const previousEvent = timeline[currentEvent.index - 1]; const previousEvent = timeline[currentEvent.index - 1];
@ -284,6 +289,7 @@ export default function Timeline({ events, onChange }: TimelineProps) {
</div> </div>
<TimelineControls <TimelineControls
disabled={disabledControls} disabled={disabledControls}
isPlaying={isPlaying}
onPrevious={onPreviousHandler} onPrevious={onPreviousHandler}
onPlayPause={onPlayPauseHandler} onPlayPause={onPlayPauseHandler}
onNext={onNextHandler} onNext={onNextHandler}

View File

@ -1,5 +1,6 @@
import { h } from 'preact'; import { h } from 'preact';
import Next from '../../icons/Next'; import Next from '../../icons/Next';
import Pause from '../../icons/Pause';
import Play from '../../icons/Play'; import Play from '../../icons/Play';
import Previous from '../../icons/Previous'; import Previous from '../../icons/Previous';
import { BubbleButton } from '../BubbleButton'; import { BubbleButton } from '../BubbleButton';
@ -13,26 +14,29 @@ export interface DisabledControls {
interface TimelineControlsProps { interface TimelineControlsProps {
disabled: DisabledControls; disabled: DisabledControls;
className?: string; className?: string;
onPlayPause: () => void; isPlaying: boolean;
onPlayPause: (isPlaying: boolean) => void;
onNext: () => void; onNext: () => void;
onPrevious: () => void; onPrevious: () => void;
} }
export const TimelineControls = ({ export const TimelineControls = ({
disabled, disabled,
isPlaying,
onPlayPause, onPlayPause,
onNext, onNext,
onPrevious, onPrevious,
className = '', className = '',
}: TimelineControlsProps) => { }: TimelineControlsProps) => {
const onPlayClickHandler = () => {
onPlayPause(!isPlaying);
};
return ( return (
<div className={`flex space-x-2 self-center ${className}`}> <div className={`flex space-x-2 self-center ${className}`}>
<BubbleButton variant='secondary' onClick={onPrevious} disabled={disabled.previous}> <BubbleButton variant='secondary' onClick={onPrevious} disabled={disabled.previous}>
<Previous /> <Previous />
</BubbleButton> </BubbleButton>
<BubbleButton onClick={onPlayPause}> <BubbleButton onClick={onPlayClickHandler}>{!isPlaying ? <Play /> : <Pause />}</BubbleButton>
<Play />
</BubbleButton>
<BubbleButton variant='secondary' onClick={onNext} disabled={disabled.next}> <BubbleButton variant='secondary' onClick={onNext} disabled={disabled.next}>
<Next /> <Next />
</BubbleButton> </BubbleButton>

13
web/src/icons/Pause.jsx Normal file
View File

@ -0,0 +1,13 @@
import { h } from 'preact';
import { memo } from 'preact/compat';
export function Pause({ className = '' }) {
return (
<svg height='24' viewBox='0 0 24 24' width='24' className={className}>
<path d='M0 0h24v24H0V0z' fill='none' />
<path d='M6 19h4V5H6v14zm8-14v14h4V5h-4z' className='fill-current' />
</svg>
);
}
export default memo(Pause);