mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-10 13:15:25 +03:00
Show frigate features in bottom sheet on mobile
This commit is contained in:
parent
bd70bf1c31
commit
5f25f29d7e
@ -8,12 +8,15 @@ import {
|
||||
import CameraFeatureToggle from "@/components/dynamic/CameraFeatureToggle";
|
||||
import LivePlayer from "@/components/player/LivePlayer";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||
@ -39,6 +42,7 @@ import {
|
||||
FaAngleLeft,
|
||||
FaAngleRight,
|
||||
FaAngleUp,
|
||||
FaCog,
|
||||
FaCompress,
|
||||
FaExpand,
|
||||
FaMicrophone,
|
||||
@ -70,19 +74,6 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) {
|
||||
const [{ width: windowWidth, height: windowHeight }] =
|
||||
useResizeObserver(window);
|
||||
|
||||
// camera features
|
||||
|
||||
const { payload: detectState, send: sendDetect } = useDetectState(
|
||||
camera.name,
|
||||
);
|
||||
const { payload: recordState, send: sendRecord } = useRecordingsState(
|
||||
camera.name,
|
||||
);
|
||||
const { payload: snapshotState, send: sendSnapshot } = useSnapshotsState(
|
||||
camera.name,
|
||||
);
|
||||
const { payload: audioState, send: sendAudio } = useAudioState(camera.name);
|
||||
|
||||
// click overlay for ptzs
|
||||
|
||||
const [clickOverlay, setClickOverlay] = useState(false);
|
||||
@ -264,42 +255,11 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) {
|
||||
title={`${audio ? "Disable" : "Enable"} Camera Audio`}
|
||||
onClick={() => setAudio(!audio)}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
className="p-2 md:p-0"
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={detectState == "ON" ? MdPersonSearch : MdPersonOff}
|
||||
isActive={detectState == "ON"}
|
||||
title={`${detectState == "ON" ? "Disable" : "Enable"} Detect`}
|
||||
onClick={() => sendDetect(detectState == "ON" ? "OFF" : "ON")}
|
||||
<FrigateCameraFeatures
|
||||
camera={camera.name}
|
||||
audioDetectEnabled={camera.audio.enabled_in_config}
|
||||
fullscreen={fullscreen}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
className="p-2 md:p-0"
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={recordState == "ON" ? LuVideo : LuVideoOff}
|
||||
isActive={recordState == "ON"}
|
||||
title={`${recordState == "ON" ? "Disable" : "Enable"} Recording`}
|
||||
onClick={() => sendRecord(recordState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
className="p-2 md:p-0"
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={snapshotState == "ON" ? MdPhotoCamera : MdNoPhotography}
|
||||
isActive={snapshotState == "ON"}
|
||||
title={`${snapshotState == "ON" ? "Disable" : "Enable"} Snapshots`}
|
||||
onClick={() =>
|
||||
sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")
|
||||
}
|
||||
/>
|
||||
{camera.audio.enabled_in_config && (
|
||||
<CameraFeatureToggle
|
||||
className="p-2 md:p-0"
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={audioState == "ON" ? LuEar : LuEarOff}
|
||||
isActive={audioState == "ON"}
|
||||
title={`${audioState == "ON" ? "Disable" : "Enable"} Audio Detect`}
|
||||
onClick={() => sendAudio(audioState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
@ -532,3 +492,145 @@ function PtzControlPanel({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type FrigateCameraFeaturesProps = {
|
||||
camera: string;
|
||||
audioDetectEnabled: boolean;
|
||||
fullscreen: boolean;
|
||||
};
|
||||
function FrigateCameraFeatures({
|
||||
camera,
|
||||
audioDetectEnabled,
|
||||
fullscreen,
|
||||
}: FrigateCameraFeaturesProps) {
|
||||
const { payload: detectState, send: sendDetect } = useDetectState(camera);
|
||||
const { payload: recordState, send: sendRecord } = useRecordingsState(camera);
|
||||
const { payload: snapshotState, send: sendSnapshot } =
|
||||
useSnapshotsState(camera);
|
||||
const { payload: audioState, send: sendAudio } = useAudioState(camera);
|
||||
|
||||
// desktop shows icons part of row
|
||||
if (isDesktop) {
|
||||
return (
|
||||
<>
|
||||
<CameraFeatureToggle
|
||||
className="p-2 md:p-0"
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={detectState == "ON" ? MdPersonSearch : MdPersonOff}
|
||||
isActive={detectState == "ON"}
|
||||
title={`${detectState == "ON" ? "Disable" : "Enable"} Detect`}
|
||||
onClick={() => sendDetect(detectState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
className="p-2 md:p-0"
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={recordState == "ON" ? LuVideo : LuVideoOff}
|
||||
isActive={recordState == "ON"}
|
||||
title={`${recordState == "ON" ? "Disable" : "Enable"} Recording`}
|
||||
onClick={() => sendRecord(recordState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
className="p-2 md:p-0"
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={snapshotState == "ON" ? MdPhotoCamera : MdNoPhotography}
|
||||
isActive={snapshotState == "ON"}
|
||||
title={`${snapshotState == "ON" ? "Disable" : "Enable"} Snapshots`}
|
||||
onClick={() => sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
{audioDetectEnabled && (
|
||||
<CameraFeatureToggle
|
||||
className="p-2 md:p-0"
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={audioState == "ON" ? LuEar : LuEarOff}
|
||||
isActive={audioState == "ON"}
|
||||
title={`${audioState == "ON" ? "Disable" : "Enable"} Audio Detect`}
|
||||
onClick={() => sendAudio(audioState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// mobile doesn't show settings in fullscreen view
|
||||
if (fullscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<Drawer>
|
||||
<DrawerTrigger>
|
||||
<CameraFeatureToggle
|
||||
className="p-2"
|
||||
variant="primary"
|
||||
Icon={FaCog}
|
||||
isActive={false}
|
||||
title={`${camera} Settings`}
|
||||
/>
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="px-2 py-4 flex flex-col gap-3 rounded-2xl">
|
||||
<div className="flex justify-between items-center gap-1">
|
||||
<Label
|
||||
className="w-full mx-2 text-secondary-foreground capitalize cursor-pointer"
|
||||
htmlFor={"camera-detect"}
|
||||
>
|
||||
Object Detection
|
||||
</Label>
|
||||
<Switch
|
||||
id={"camera-detect"}
|
||||
checked={detectState == "ON"}
|
||||
onCheckedChange={() =>
|
||||
sendDetect(detectState == "ON" ? "OFF" : "ON")
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between items-center gap-1">
|
||||
<Label
|
||||
className="w-full mx-2 text-secondary-foreground capitalize cursor-pointer"
|
||||
htmlFor={"camera-record"}
|
||||
>
|
||||
Recording
|
||||
</Label>
|
||||
<Switch
|
||||
id={"camera-record"}
|
||||
checked={recordState == "ON"}
|
||||
onCheckedChange={() =>
|
||||
sendRecord(recordState == "ON" ? "OFF" : "ON")
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between items-center gap-1">
|
||||
<Label
|
||||
className="w-full mx-2 text-secondary-foreground capitalize cursor-pointer"
|
||||
htmlFor={"camera-snapshot"}
|
||||
>
|
||||
Snapshots
|
||||
</Label>
|
||||
<Switch
|
||||
id={"camera-snapshot"}
|
||||
checked={snapshotState == "ON"}
|
||||
onCheckedChange={() =>
|
||||
sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{audioDetectEnabled && (
|
||||
<div className="flex justify-between items-center gap-1">
|
||||
<Label
|
||||
className="w-full mx-2 text-secondary-foreground capitalize cursor-pointer"
|
||||
htmlFor={"camera-audio-detect"}
|
||||
>
|
||||
Audio Detection
|
||||
</Label>
|
||||
<Switch
|
||||
id={"camera-audio-detect"}
|
||||
checked={audioState == "ON"}
|
||||
onCheckedChange={() =>
|
||||
sendAudio(audioState == "ON" ? "OFF" : "ON")
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user