Dynamically scale the slider height when hovering + other UI tweaks (#11042)

* Make no thumb slider height dynamic

* Use existing switch component

* Use existing switch component for general filter content

* Show message when no reordings found for time

* Don't show while scrubbing

* Fix key error

* Fix background color for controls on motion page
This commit is contained in:
Nicolas Mowen
2024-04-19 16:12:03 -06:00
committed by GitHub
parent fe4fb645d3
commit bfefed4d6e
8 changed files with 77 additions and 103 deletions

View File

@@ -520,6 +520,7 @@ export function VideoPreview({
const onStopManualSeek = useCallback(() => {
setTimeout(() => {
setIgnoreClick(false);
setHoverTimeout(undefined);
if (isSafari || (isFirefox && isMobile)) {
setManualPlayback(true);
@@ -565,7 +566,7 @@ export function VideoPreview({
{showProgress && (
<NoThumbSlider
ref={sliderRef}
className="absolute inset-x-0 bottom-0 z-30"
className={`absolute inset-x-0 bottom-0 z-30 cursor-col-resize ${hoverTimeout != undefined ? "h-4" : "h-2"}`}
value={[progress]}
onValueChange={onManualSeek}
onValueCommit={onStopManualSeek}
@@ -740,7 +741,7 @@ export function InProgressPreview({
{showProgress && (
<NoThumbSlider
ref={sliderRef}
className="absolute inset-x-0 bottom-0 z-30"
className={`absolute inset-x-0 bottom-0 z-30 cursor-col-resize ${manualFrame ? "h-4" : "h-2"}`}
value={[key]}
onValueChange={onManualSeek}
onValueCommit={onStopManualSeek}

View File

@@ -1,7 +1,7 @@
import { Recording } from "@/types/record";
import { DynamicPlayback } from "@/types/playback";
import { PreviewController } from "../PreviewPlayer";
import { Timeline } from "@/types/timeline";
import { TimeRange, Timeline } from "@/types/timeline";
type PlayerMode = "playback" | "scrubbing";
@@ -10,11 +10,13 @@ export class DynamicVideoController {
public camera = "";
private playerController: HTMLVideoElement;
private previewController: PreviewController;
private setNoRecording: (noRecs: boolean) => void;
private setFocusedItem: (timeline: Timeline) => void;
private playerMode: PlayerMode = "playback";
// playback
private recordings: Recording[] = [];
private timeRange: TimeRange = { after: 0, before: 0 };
private annotationOffset: number;
private timeToStart: number | undefined = undefined;
@@ -24,6 +26,7 @@ export class DynamicVideoController {
previewController: PreviewController,
annotationOffset: number,
defaultMode: PlayerMode,
setNoRecording: (noRecs: boolean) => void,
setFocusedItem: (timeline: Timeline) => void,
) {
this.camera = camera;
@@ -31,11 +34,13 @@ export class DynamicVideoController {
this.previewController = previewController;
this.annotationOffset = annotationOffset;
this.playerMode = defaultMode;
this.setNoRecording = setNoRecording;
this.setFocusedItem = setFocusedItem;
}
newPlayback(newPlayback: DynamicPlayback) {
this.recordings = newPlayback.recordings;
this.timeRange = newPlayback.timeRange;
if (this.timeToStart) {
this.seekToTimestamp(this.timeToStart);
@@ -52,12 +57,17 @@ export class DynamicVideoController {
}
seekToTimestamp(time: number, play: boolean = false) {
if (time < this.timeRange.after || time > this.timeRange.before) {
this.timeToStart = time;
return;
}
if (
this.recordings.length == 0 ||
time < this.recordings[0].start_time ||
time > this.recordings[this.recordings.length - 1].end_time
) {
this.timeToStart = time;
this.setNoRecording(true);
return;
}
@@ -90,6 +100,8 @@ export class DynamicVideoController {
} else {
this.playerController.pause();
}
} else {
console.log(`seek time is 0`);
}
}

View File

@@ -45,6 +45,7 @@ export default function DynamicVideoPlayer({
const playerRef = useRef<HTMLVideoElement | null>(null);
const [previewController, setPreviewController] =
useState<PreviewController | null>(null);
const [noRecording, setNoRecording] = useState(false);
const controller = useMemo(() => {
if (!config || !playerRef.current || !previewController) {
return undefined;
@@ -56,6 +57,7 @@ export default function DynamicVideoPlayer({
previewController,
(config.cameras[camera]?.detect?.annotation_offset || 0) / 1000,
isScrubbing ? "scrubbing" : "playback",
setNoRecording,
() => {},
);
// we only want to fire once when players are ready
@@ -92,9 +94,11 @@ export default function DynamicVideoPlayer({
return () => {
if (loadingTimeout) {
clearTimeout(loadingTimeout)
clearTimeout(loadingTimeout);
}
}
};
// we only want trigger when scrubbing state changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [camera, isScrubbing]);
const onPlayerLoaded = useCallback(() => {
@@ -149,6 +153,7 @@ export default function DynamicVideoPlayer({
controller.newPlayback({
recordings: recordings ?? [],
timeRange,
});
// we only want this to change when recordings update
@@ -175,6 +180,7 @@ export default function DynamicVideoPlayer({
}
setIsLoading(false);
setNoRecording(false);
}}
/>
<PreviewPlayer
@@ -188,9 +194,14 @@ export default function DynamicVideoPlayer({
setPreviewController(previewController);
}}
/>
{isLoading && (
{isLoading && !noRecording && (
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
)}
{!isScrubbing && noRecording && (
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
No recordings found for this time
</div>
)}
</>
);
}