mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Persist selected camera group for live (#10448)
* Persist camera group selected * Cleanup
This commit is contained in:
parent
a660e3ae27
commit
2decdeadb4
@ -6,9 +6,8 @@ import {
|
|||||||
import { isDesktop } from "react-device-detect";
|
import { isDesktop } from "react-device-detect";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { MdHome } from "react-icons/md";
|
import { MdHome } from "react-icons/md";
|
||||||
import useOverlayState from "@/hooks/use-overlay-state";
|
import { usePersistedOverlayState } from "@/hooks/use-overlay-state";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { useCallback, useMemo, useState } from "react";
|
import { useCallback, useMemo, useState } from "react";
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
||||||
import { getIconForGroup } from "@/utils/iconUtil";
|
import { getIconForGroup } from "@/utils/iconUtil";
|
||||||
@ -31,7 +30,6 @@ type CameraGroupSelectorProps = {
|
|||||||
};
|
};
|
||||||
export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
|
export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
|
||||||
const { data: config } = useSWR<FrigateConfig>("config");
|
const { data: config } = useSWR<FrigateConfig>("config");
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
// tooltip
|
// tooltip
|
||||||
|
|
||||||
@ -54,7 +52,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
|
|||||||
|
|
||||||
// groups
|
// groups
|
||||||
|
|
||||||
const [group, setGroup] = useOverlayState("cameraGroup");
|
const [group, setGroup] = usePersistedOverlayState("cameraGroup");
|
||||||
|
|
||||||
const groups = useMemo(() => {
|
const groups = useMemo(() => {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
@ -89,7 +87,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
|
|||||||
: "text-muted-foreground bg-secondary focus:text-muted-foreground focus:bg-secondary"
|
: "text-muted-foreground bg-secondary focus:text-muted-foreground focus:bg-secondary"
|
||||||
}
|
}
|
||||||
size="xs"
|
size="xs"
|
||||||
onClick={() => (group ? navigate(-1) : null)}
|
onClick={() => (group ? setGroup(undefined, true) : null)}
|
||||||
onMouseEnter={() => (isDesktop ? showTooltip("home") : null)}
|
onMouseEnter={() => (isDesktop ? showTooltip("home") : null)}
|
||||||
onMouseLeave={() => (isDesktop ? showTooltip(undefined) : null)}
|
onMouseLeave={() => (isDesktop ? showTooltip(undefined) : null)}
|
||||||
>
|
>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useCallback, useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
import { usePersistence } from "./use-persistence";
|
||||||
|
|
||||||
export default function useOverlayState<S extends string>(
|
export default function useOverlayState<S extends string>(
|
||||||
key: string,
|
key: string,
|
||||||
@ -27,3 +28,38 @@ export default function useOverlayState<S extends string>(
|
|||||||
|
|
||||||
return [overlayStateValue ?? defaultValue, setOverlayStateValue];
|
return [overlayStateValue ?? defaultValue, setOverlayStateValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function usePersistedOverlayState<S extends string>(
|
||||||
|
key: string,
|
||||||
|
defaultValue: S | undefined = undefined,
|
||||||
|
): [S | undefined, (value: S | undefined, replace?: boolean) => void] {
|
||||||
|
const [persistedValue, setPersistedValue] = usePersistence<S>(
|
||||||
|
key,
|
||||||
|
defaultValue,
|
||||||
|
);
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const currentLocationState = location.state;
|
||||||
|
|
||||||
|
const setOverlayStateValue = useCallback(
|
||||||
|
(value: S | undefined, replace: boolean = false) => {
|
||||||
|
setPersistedValue(value);
|
||||||
|
const newLocationState = { ...currentLocationState };
|
||||||
|
newLocationState[key] = value;
|
||||||
|
navigate(location.pathname, { state: newLocationState, replace });
|
||||||
|
},
|
||||||
|
// we know that these deps are correct
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[key, navigate],
|
||||||
|
);
|
||||||
|
|
||||||
|
const overlayStateValue = useMemo<S | undefined>(
|
||||||
|
() => location.state && location.state[key],
|
||||||
|
[location, key],
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
overlayStateValue ?? persistedValue ?? defaultValue,
|
||||||
|
setOverlayStateValue,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { get as getData, set as setData } from "idb-keyval";
|
|||||||
|
|
||||||
type usePersistenceReturn<S> = [
|
type usePersistenceReturn<S> = [
|
||||||
value: S | undefined,
|
value: S | undefined,
|
||||||
setValue: (value: S) => void,
|
setValue: (value: S | undefined) => void,
|
||||||
loaded: boolean,
|
loaded: boolean,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ export function usePersistence<S>(
|
|||||||
const [loaded, setLoaded] = useState<boolean>(false);
|
const [loaded, setLoaded] = useState<boolean>(false);
|
||||||
|
|
||||||
const setValue = useCallback(
|
const setValue = useCallback(
|
||||||
(value: S) => {
|
(value: S | undefined) => {
|
||||||
setInternalValue(value);
|
setInternalValue(value);
|
||||||
async function update() {
|
async function update() {
|
||||||
await setData(key, value);
|
await setData(key, value);
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import useOverlayState from "@/hooks/use-overlay-state";
|
import useOverlayState, {
|
||||||
|
usePersistedOverlayState,
|
||||||
|
} from "@/hooks/use-overlay-state";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import LiveCameraView from "@/views/live/LiveCameraView";
|
import LiveCameraView from "@/views/live/LiveCameraView";
|
||||||
import LiveDashboardView from "@/views/live/LiveDashboardView";
|
import LiveDashboardView from "@/views/live/LiveDashboardView";
|
||||||
@ -9,7 +11,7 @@ function Live() {
|
|||||||
const { data: config } = useSWR<FrigateConfig>("config");
|
const { data: config } = useSWR<FrigateConfig>("config");
|
||||||
|
|
||||||
const [selectedCameraName, setSelectedCameraName] = useOverlayState("camera");
|
const [selectedCameraName, setSelectedCameraName] = useOverlayState("camera");
|
||||||
const [cameraGroup] = useOverlayState("cameraGroup");
|
const [cameraGroup] = usePersistedOverlayState("cameraGroup");
|
||||||
|
|
||||||
const includesBirdseye = useMemo(() => {
|
const includesBirdseye = useMemo(() => {
|
||||||
if (config && cameraGroup) {
|
if (config && cameraGroup) {
|
||||||
|
Loading…
Reference in New Issue
Block a user