mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-02 09:15:22 +03:00
fix: fix playback button
This commit is contained in:
parent
376830cf6e
commit
db2423cd0f
@ -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 />;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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
13
web/src/icons/Pause.jsx
Normal 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);
|
||||||
Loading…
Reference in New Issue
Block a user