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,15 +869,26 @@ 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)} )}
>
<LuCog
className={`text-secondary-foreground" size-5 md:m-[6px]`}
/> />
</div>
</DropdownMenuTrigger>
<DropdownMenuContent className="max-w-96">
<div className="flex flex-col gap-5 p-4">
{Object.values(camera.live.streams).length > 1 && ( {Object.values(camera.live.streams).length > 1 && (
<div className="flex flex-col gap-1">
<Label htmlFor="streaming-method" className="">
Stream
</Label>
<Select <Select
value={streamName} value={streamName}
onValueChange={(value) => { onValueChange={(value) => {
@ -882,19 +896,6 @@ function FrigateCameraFeatures({
}} }}
> >
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
{preferredLiveMode == "jsmpeg" && (
<Tooltip>
<TooltipTrigger>
<IoIosWarning className="mr-1 size-5 text-danger" />
</TooltipTrigger>
<TooltipPortal>
<TooltipContent className="max-w-52">
Live view is in low-bandwidth mode due to buffering or
stream errors
</TooltipContent>
</TooltipPortal>
</Tooltip>
)}
{Object.keys(camera.live.streams).find( {Object.keys(camera.live.streams).find(
(key) => camera.live.streams[key] === streamName, (key) => camera.live.streams[key] === streamName,
)} )}
@ -902,7 +903,8 @@ function FrigateCameraFeatures({
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
{Object.entries(camera.live.streams).map(([stream, name]) => ( {Object.entries(camera.live.streams).map(
([stream, name]) => (
<SelectItem <SelectItem
key={stream} key={stream}
className="cursor-pointer" className="cursor-pointer"
@ -910,10 +912,63 @@ function FrigateCameraFeatures({
> >
{stream} {stream}
</SelectItem> </SelectItem>
))} ),
)}
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
</Select> </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,7 +1057,44 @@ 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> </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>
)}
{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>