put stream selection inside dropdown on desktop

This commit is contained in:
Josh Hawkins 2024-12-21 19:32:34 -06:00
parent 78581229f5
commit 33a1f82fe8

View File

@ -55,11 +55,11 @@ import {
FaMicrophone, FaMicrophone,
FaMicrophoneSlash, FaMicrophoneSlash,
} from "react-icons/fa"; } from "react-icons/fa";
import { CiStreamOff, CiStreamOn } from "react-icons/ci";
import { GiSpeaker, GiSpeakerOff } from "react-icons/gi"; import { GiSpeaker, GiSpeakerOff } from "react-icons/gi";
import { TbViewfinder, TbViewfinderOff } from "react-icons/tb"; import { TbViewfinder, TbViewfinderOff } from "react-icons/tb";
import { IoIosWarning, IoMdArrowRoundBack } from "react-icons/io"; import { IoIosWarning, IoMdArrowRoundBack } from "react-icons/io";
import { import {
LuCog,
LuEar, LuEar,
LuEarOff, LuEarOff,
LuHistory, LuHistory,
@ -69,6 +69,7 @@ import {
} from "react-icons/lu"; } from "react-icons/lu";
import { import {
MdNoPhotography, MdNoPhotography,
MdOutlineRestartAlt,
MdPersonOff, MdPersonOff,
MdPersonSearch, MdPersonSearch,
MdPhotoCamera, MdPhotoCamera,
@ -87,13 +88,9 @@ import {
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
} from "@/components/ui/select"; } from "@/components/ui/select";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { usePersistence } from "@/hooks/use-persistence"; import { usePersistence } from "@/hooks/use-persistence";
import { TooltipPortal } from "@radix-ui/react-tooltip"; import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
type LiveCameraViewProps = { type LiveCameraViewProps = {
config?: FrigateConfig; config?: FrigateConfig;
@ -489,6 +486,8 @@ export default function LiveCameraView({
preferredLiveMode={preferredLiveMode} preferredLiveMode={preferredLiveMode}
playInBackground={playInBackground ?? false} playInBackground={playInBackground ?? false}
setPlayInBackground={setPlayInBackground} setPlayInBackground={setPlayInBackground}
isRestreamed={isRestreamed ?? false}
setLowBandwidth={setLowBandwidth}
/> />
</div> </div>
</TooltipProvider> </TooltipProvider>
@ -790,6 +789,8 @@ type FrigateCameraFeaturesProps = {
preferredLiveMode: string; preferredLiveMode: string;
playInBackground: boolean; playInBackground: boolean;
setPlayInBackground: (value: boolean | undefined) => void; setPlayInBackground: (value: boolean | undefined) => void;
isRestreamed: boolean;
setLowBandwidth: React.Dispatch<React.SetStateAction<boolean>>;
}; };
function FrigateCameraFeatures({ function FrigateCameraFeatures({
camera, camera,
@ -802,6 +803,8 @@ function FrigateCameraFeatures({
preferredLiveMode, preferredLiveMode,
playInBackground, playInBackground,
setPlayInBackground, setPlayInBackground,
isRestreamed,
setLowBandwidth,
}: FrigateCameraFeaturesProps) { }: FrigateCameraFeaturesProps) {
const { payload: detectState, send: sendDetect } = useDetectState( const { payload: detectState, send: sendDetect } = useDetectState(
camera.name, camera.name,
@ -866,54 +869,106 @@ function FrigateCameraFeatures({
} }
/> />
)} )}
<CameraFeatureToggle {isRestreamed && (
className="p-2 md:p-0" <DropdownMenu modal={false}>
variant={fullscreen ? "overlay" : "primary"} <DropdownMenuTrigger>
Icon={playInBackground ? CiStreamOn : CiStreamOff} <div
isActive={playInBackground ?? false} className={cn(
title={`${playInBackground ? "Disable" : "Enable"} Background Playback`} "flex flex-col items-center justify-center rounded-lg bg-secondary p-2 text-secondary-foreground md:p-0",
onClick={() => setPlayInBackground(!playInBackground)} )}
/> >
{Object.values(camera.live.streams).length > 1 && ( <LuCog
<Select className={`text-secondary-foreground" size-5 md:m-[6px]`}
value={streamName} />
onValueChange={(value) => { </div>
setStreamName?.(value); </DropdownMenuTrigger>
}} <DropdownMenuContent className="max-w-96">
> <div className="flex flex-col gap-5 p-4">
<SelectTrigger className="w-full"> {Object.values(camera.live.streams).length > 1 && (
{preferredLiveMode == "jsmpeg" && ( <div className="flex flex-col gap-1">
<Tooltip> <Label htmlFor="streaming-method" className="">
<TooltipTrigger> Stream
<IoIosWarning className="mr-1 size-5 text-danger" /> </Label>
</TooltipTrigger> <Select
<TooltipPortal> value={streamName}
<TooltipContent className="max-w-52"> onValueChange={(value) => {
Live view is in low-bandwidth mode due to buffering or setStreamName?.(value);
stream errors }}
</TooltipContent> >
</TooltipPortal> <SelectTrigger className="w-full">
</Tooltip> {Object.keys(camera.live.streams).find(
)} (key) => camera.live.streams[key] === streamName,
{Object.keys(camera.live.streams).find( )}
(key) => camera.live.streams[key] === streamName, </SelectTrigger>
)}
</SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
{Object.entries(camera.live.streams).map(([stream, name]) => ( {Object.entries(camera.live.streams).map(
<SelectItem ([stream, name]) => (
key={stream} <SelectItem
className="cursor-pointer" key={stream}
value={name} className="cursor-pointer"
> value={name}
{stream} >
</SelectItem> {stream}
))} </SelectItem>
</SelectGroup> ),
</SelectContent> )}
</Select> </SelectGroup>
</SelectContent>
</Select>
{preferredLiveMode == "jsmpeg" && isRestreamed && (
<div className="flex flex-col items-center gap-3">
<div className="flex flex-row items-center gap-2">
<IoIosWarning className="mr-1 size-8 text-danger" />
<p className="text-sm">
Live view is in low-bandwidth mode due to buffering
or stream errors.
</p>
</div>
<Button
className={`flex items-center gap-2.5 rounded-lg`}
aria-label="Reset the stream"
variant="outline"
size="sm"
onClick={() => setLowBandwidth(false)}
>
<MdOutlineRestartAlt className="size-5 text-primary-variant" />
<div className="text-primary-variant">
Reset stream
</div>
</Button>
</div>
)}
</div>
)}
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between">
<Label
className="mx-0 cursor-pointer text-primary"
htmlFor="backgroundplay"
>
Play in background
</Label>
<Switch
className="ml-1"
id="backgroundplay"
checked={playInBackground}
onCheckedChange={(checked) =>
setPlayInBackground(checked)
}
/>
</div>
<p className="text-sm text-muted-foreground">
Enable this option to continue streaming when the player is
hidden.
</p>
</div>
</div>
</DropdownMenuContent>
</DropdownMenu>
)} )}
</> </>
); );
@ -973,16 +1028,9 @@ function FrigateCameraFeatures({
} }
/> />
)} )}
<FilterSwitch
label="Play in Background"
isChecked={playInBackground}
onCheckedChange={(checked) => {
setPlayInBackground(checked);
}}
/>
{Object.values(camera.live.streams).length > 1 && ( {Object.values(camera.live.streams).length > 1 && (
<div className="mt-1 p-2"> <div className="mt-1 p-2">
<div className="mb-1 text-sm">Live stream selection</div> <div className="mb-1 text-sm">Stream</div>
<Select <Select
value={streamName} value={streamName}
onValueChange={(value) => { onValueChange={(value) => {
@ -990,9 +1038,6 @@ function FrigateCameraFeatures({
}} }}
> >
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
{preferredLiveMode == "jsmpeg" && (
<IoIosWarning className="mr-1 size-5 text-danger" />
)}
{Object.keys(camera.live.streams).find( {Object.keys(camera.live.streams).find(
(key) => camera.live.streams[key] === streamName, (key) => camera.live.streams[key] === streamName,
)} )}
@ -1012,8 +1057,45 @@ function FrigateCameraFeatures({
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
</Select> </Select>
{preferredLiveMode == "jsmpeg" && isRestreamed && (
<div className="mt-2 flex flex-col items-center gap-3">
<div className="flex flex-row items-center gap-2">
<IoIosWarning className="mr-1 size-8 text-danger" />
<p className="text-sm">
Live view is in low-bandwidth mode due to buffering or
stream errors.
</p>
</div>
<Button
className={`flex items-center gap-2.5 rounded-lg`}
aria-label="Reset the stream"
variant="outline"
size="sm"
onClick={() => setLowBandwidth(false)}
>
<MdOutlineRestartAlt className="size-5 text-primary-variant" />
<div className="text-primary-variant">Reset stream</div>
</Button>
</div>
)}
</div> </div>
)} )}
{isRestreamed && (
<>
<FilterSwitch
label="Play in Background"
isChecked={playInBackground}
onCheckedChange={(checked) => {
setPlayInBackground(checked);
}}
/>
<p className="mx-2 -mt-2 text-sm text-muted-foreground">
Enable this option to continue streaming when the player is
hidden.
</p>
</>
)}
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
); );