Skip to content

Commit

Permalink
Ui Tweaks (#10920)
Browse files Browse the repository at this point in the history
* Cleanup live activity indicators for cameras

* Rename to reviews and redirect events to reviews

* Use reviews

* Remove plural

* Simplify recordings view

* Adjust icon
  • Loading branch information
NickM-27 authored Apr 10, 2024
1 parent 503dfba commit 3d43c5e
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 137 deletions.
4 changes: 3 additions & 1 deletion web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { isDesktop, isMobile } from "react-device-detect";
import Statusbar from "./components/Statusbar";
import Bottombar from "./components/navigation/Bottombar";
import { Suspense, lazy } from "react";
import { Redirect } from "./components/navigation/Redirect";

const Live = lazy(() => import("@/pages/Live"));
const Events = lazy(() => import("@/pages/Events"));
Expand Down Expand Up @@ -35,7 +36,8 @@ function App() {
<Suspense>
<Routes>
<Route path="/" element={<Live />} />
<Route path="/events" element={<Events />} />
<Route path="/events" element={<Redirect to="/review" />} />
<Route path="/review" element={<Events />} />
<Route path="/export" element={<Export />} />
<Route path="/plus" element={<SubmitPlus />} />
<Route path="/system" element={<System />} />
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/card/AnimatedEventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function AnimatedEventCard({ event }: AnimatedEventCardProps) {

const navigate = useNavigate();
const onOpenReview = useCallback(() => {
navigate("events", {
navigate("review", {
state: {
severity: event.severity,
recording: {
Expand Down
14 changes: 14 additions & 0 deletions web/src/components/navigation/Redirect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

type RedirectProps = {
to: string;
};
export function Redirect({ to }: RedirectProps) {
const navigate = useNavigate();

useEffect(() => {
navigate(to);
}, [to, navigate]);
return <div />;
}
208 changes: 104 additions & 104 deletions web/src/components/player/HlsVideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const unsupportedErrorCodes = [
];

type HlsVideoPlayerProps = {
className: string;
children?: ReactNode;
videoRef: MutableRefObject<HTMLVideoElement | null>;
visible: boolean;
Expand All @@ -31,7 +30,6 @@ type HlsVideoPlayerProps = {
onPlaying?: () => void;
};
export default function HlsVideoPlayer({
className,
children,
videoRef,
visible,
Expand Down Expand Up @@ -91,116 +89,118 @@ export default function HlsVideoPlayer({

return (
<TransformWrapper minScale={1.0}>
<div
className={`relative ${className ?? ""} ${visible ? "visible" : "hidden"}`}
onMouseOver={
isDesktop
? () => {
setControls(true);
}
: undefined
}
onMouseOut={
isDesktop
? () => {
setControls(controlsOpen);
}
: undefined
}
onClick={isDesktop ? undefined : () => setControls(!controls)}
<TransformComponent
wrapperStyle={{
position: "relative",
display: visible ? undefined : "none",
width: "100%",
height: "100%",
}}
contentStyle={{
width: "100%",
height: isMobile ? "100%" : undefined,
}}
>
<TransformComponent
wrapperStyle={{
width: "100%",
height: "100%",
}}
contentStyle={{
width: "100%",
height: isMobile ? "100%" : undefined,
}}
>
<video
ref={videoRef}
className={`size-full bg-black rounded-2xl ${loadedMetadata ? "" : "invisible"}`}
preload="auto"
autoPlay
controls={false}
playsInline
muted
onPlay={() => {
setIsPlaying(true);

if (isMobile) {
setControls(true);
setMobileCtrlTimeout(
setTimeout(() => setControls(false), 4000),
);
}
}}
onPlaying={onPlaying}
onPause={() => {
setIsPlaying(false);

if (isMobile && mobileCtrlTimeout) {
clearTimeout(mobileCtrlTimeout);
}
}}
onTimeUpdate={() =>
onTimeUpdate && videoRef.current
? onTimeUpdate(videoRef.current.currentTime)
: undefined
}
onLoadedData={onPlayerLoaded}
onLoadedMetadata={() => setLoadedMetadata(true)}
onEnded={onClipEnded}
onError={(e) => {
if (
!hlsRef.current &&
// @ts-expect-error code does exist
unsupportedErrorCodes.includes(e.target.error.code) &&
videoRef.current
) {
setLoadedMetadata(false);
setUseHlsCompat(true);
}
}}
/>
</TransformComponent>
<VideoControls
className="absolute bottom-5 left-1/2 -translate-x-1/2"
video={videoRef.current}
isPlaying={isPlaying}
show={controls}
controlsOpen={controlsOpen}
setControlsOpen={setControlsOpen}
playbackRate={videoRef.current?.playbackRate ?? 1}
hotKeys={hotKeys}
onPlayPause={(play) => {
if (!videoRef.current) {
return;
}

if (play) {
videoRef.current.play();
} else {
videoRef.current.pause();
<video
ref={videoRef}
className={`size-full bg-black rounded-2xl ${loadedMetadata ? "" : "invisible"}`}
preload="auto"
autoPlay
controls={false}
playsInline
muted
onPlay={() => {
setIsPlaying(true);

if (isMobile) {
setControls(true);
setMobileCtrlTimeout(setTimeout(() => setControls(false), 4000));
}
}}
onSeek={(diff) => {
const currentTime = videoRef.current?.currentTime;
onPlaying={onPlaying}
onPause={() => {
setIsPlaying(false);

if (!videoRef.current || !currentTime) {
return;
if (isMobile && mobileCtrlTimeout) {
clearTimeout(mobileCtrlTimeout);
}

videoRef.current.currentTime = Math.max(0, currentTime + diff);
}}
onSetPlaybackRate={(rate) =>
videoRef.current ? (videoRef.current.playbackRate = rate) : null
onTimeUpdate={() =>
onTimeUpdate && videoRef.current
? onTimeUpdate(videoRef.current.currentTime)
: undefined
}
onLoadedData={onPlayerLoaded}
onLoadedMetadata={() => setLoadedMetadata(true)}
onEnded={onClipEnded}
onError={(e) => {
if (
!hlsRef.current &&
// @ts-expect-error code does exist
unsupportedErrorCodes.includes(e.target.error.code) &&
videoRef.current
) {
setLoadedMetadata(false);
setUseHlsCompat(true);
}
}}
/>
{children}
</div>
<div
className="absolute inset-0"
onMouseOver={
isDesktop
? () => {
setControls(true);
}
: undefined
}
onMouseOut={
isDesktop
? () => {
setControls(controlsOpen);
}
: undefined
}
onClick={isDesktop ? undefined : () => setControls(!controls)}
>
<div className={`size-full relative ${visible ? "" : "hidden"}`}>
<VideoControls
className="absolute bottom-5 left-1/2 -translate-x-1/2"
video={videoRef.current}
isPlaying={isPlaying}
show={controls}
controlsOpen={controlsOpen}
setControlsOpen={setControlsOpen}
playbackRate={videoRef.current?.playbackRate ?? 1}
hotKeys={hotKeys}
onPlayPause={(play) => {
if (!videoRef.current) {
return;
}

if (play) {
videoRef.current.play();
} else {
videoRef.current.pause();
}
}}
onSeek={(diff) => {
const currentTime = videoRef.current?.currentTime;

if (!videoRef.current || !currentTime) {
return;
}

videoRef.current.currentTime = Math.max(0, currentTime + diff);
}}
onSetPlaybackRate={(rate) =>
videoRef.current ? (videoRef.current.playbackRate = rate) : null
}
/>
{children}
</div>
</div>
</TransformComponent>
</TransformWrapper>
);
}
16 changes: 2 additions & 14 deletions web/src/components/player/LivePlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import MSEPlayer from "./MsePlayer";
import JSMpegPlayer from "./JSMpegPlayer";
import { MdCircle } from "react-icons/md";
import { useCameraActivity } from "@/hooks/use-camera-activity";
import { useRecordingsState } from "@/api/ws";
import { LivePlayerMode } from "@/types/live";
import useCameraLiveMode from "@/hooks/use-camera-live-mode";
import CameraActivityIndicator from "../indicators/CameraActivityIndicator";

type LivePlayerProps = {
cameraRef?: (ref: HTMLDivElement | null) => void;
Expand Down Expand Up @@ -41,8 +39,7 @@ export default function LivePlayer({
}: LivePlayerProps) {
// camera activity

const { activeMotion, activeAudio, activeTracking } =
useCameraActivity(cameraConfig);
const { activeMotion, activeTracking } = useCameraActivity(cameraConfig);

const cameraActive = useMemo(
() =>
Expand Down Expand Up @@ -72,8 +69,6 @@ export default function LivePlayer({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [cameraActive, liveReady]);

const { payload: recording } = useRecordingsState(cameraConfig.name);

// camera still state

const stillReloadInterval = useMemo(() => {
Expand Down Expand Up @@ -171,15 +166,8 @@ export default function LivePlayer({
/>
</div>

<div className="absolute right-2 bottom-2 w-[40px]">
{(activeMotion ||
(cameraConfig.audio.enabled_in_config && activeAudio)) && (
<CameraActivityIndicator />
)}
</div>

<div className="absolute right-2 top-2 size-4">
{recording == "ON" && (
{activeMotion && (
<MdCircle className="size-2 drop-shadow-md shadow-danger text-danger animate-pulse" />
)}
</div>
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/player/VideoControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export default function VideoControls({
className={`px-4 py-2 flex justify-between items-center gap-8 text-primary z-50 bg-background/60 rounded-lg ${className ?? ""}`}
>
{video && features.volume && (
<div className="flex justify-normal items-center gap-2">
<div className="flex justify-normal items-center gap-2 cursor-pointer">
<VolumeIcon
className="size-5"
onClick={(e: React.MouseEvent) => {
Expand Down
1 change: 0 additions & 1 deletion web/src/components/player/dynamic/DynamicVideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ export default function DynamicVideoPlayer({
return (
<>
<HlsVideoPlayer
className={className ?? ""}
videoRef={playerRef}
visible={!(isScrubbing || isLoading)}
currentSource={source}
Expand Down
11 changes: 1 addition & 10 deletions web/src/hooks/use-camera-activity.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
useAudioActivity,
useFrigateEvents,
useMotionActivity,
} from "@/api/ws";
import { useFrigateEvents, useMotionActivity } from "@/api/ws";
import { CameraConfig } from "@/types/frigateConfig";
import { MotionData, ReviewSegment } from "@/types/review";
import { useEffect, useMemo, useState } from "react";
Expand All @@ -11,7 +7,6 @@ import { useTimelineUtils } from "./use-timeline-utils";
type useCameraActivityReturn = {
activeTracking: boolean;
activeMotion: boolean;
activeAudio: boolean;
};

export function useCameraActivity(
Expand All @@ -25,7 +20,6 @@ export function useCameraActivity(

const { payload: detectingMotion } = useMotionActivity(camera.name);
const { payload: event } = useFrigateEvents();
const { payload: audioRms } = useAudioActivity(camera.name);

useEffect(() => {
if (!event) {
Expand Down Expand Up @@ -63,9 +57,6 @@ export function useCameraActivity(
return {
activeTracking: hasActiveObjects,
activeMotion: detectingMotion == "ON",
activeAudio: camera.audio.enabled_in_config
? audioRms >= camera.audio.min_volume
: false,
};
}

Expand Down
Loading

0 comments on commit 3d43c5e

Please sign in to comment.