feat(ui): Enhance EDID settings with loading state (#691)

* feat(ui): Enhance EDID settings with loading state and Fieldset component

* fix(ui): Improve notifications and adjust styling in custom EDID component

* fix(ui): specify JsonRpcResponse type
This commit is contained in:
Adam Shiervani 2025-09-08 11:38:49 +02:00 committed by GitHub
parent 8fbad0112e
commit c98592a412
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 92 additions and 73 deletions

View File

@ -1,15 +1,16 @@
import { useState, useEffect } from "react"; import { useEffect, useState } from "react";
import { Button } from "@/components/Button"; import { Button } from "@/components/Button";
import { TextAreaWithLabel } from "@/components/TextArea"; import { TextAreaWithLabel } from "@/components/TextArea";
import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc"; import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc";
import { SettingsPageHeader } from "@components/SettingsPageheader"; import { SettingsPageHeader } from "@components/SettingsPageheader";
import { useSettingsStore } from "@/hooks/stores"; import { useSettingsStore } from "@/hooks/stores";
import { SelectMenuBasic } from "@components/SelectMenuBasic";
import notifications from "../notifications"; import Fieldset from "@components/Fieldset";
import { SelectMenuBasic } from "../components/SelectMenuBasic"; import notifications from "@/notifications";
import { SettingsItem } from "./devices.$id.settings"; import { SettingsItem } from "./devices.$id.settings";
const defaultEdid = const defaultEdid =
"00ffffffffffff0052620188008888881c150103800000780a0dc9a05747982712484c00000001010101010101010101010101010101023a801871382d40582c4500c48e2100001e011d007251d01e206e285500c48e2100001e000000fc00543734392d6648443732300a20000000fd00147801ff1d000a202020202020017b"; "00ffffffffffff0052620188008888881c150103800000780a0dc9a05747982712484c00000001010101010101010101010101010101023a801871382d40582c4500c48e2100001e011d007251d01e206e285500c48e2100001e000000fc00543734392d6648443732300a20000000fd00147801ff1d000a202020202020017b";
const edids = [ const edids = [
@ -50,21 +51,27 @@ export default function SettingsVideoRoute() {
const [streamQuality, setStreamQuality] = useState("1"); const [streamQuality, setStreamQuality] = useState("1");
const [customEdidValue, setCustomEdidValue] = useState<string | null>(null); const [customEdidValue, setCustomEdidValue] = useState<string | null>(null);
const [edid, setEdid] = useState<string | null>(null); const [edid, setEdid] = useState<string | null>(null);
const [edidLoading, setEdidLoading] = useState(false);
// Video enhancement settings from store // Video enhancement settings from store
const { const {
videoSaturation, setVideoSaturation, videoSaturation,
videoBrightness, setVideoBrightness, setVideoSaturation,
videoContrast, setVideoContrast videoBrightness,
setVideoBrightness,
videoContrast,
setVideoContrast,
} = useSettingsStore(); } = useSettingsStore();
useEffect(() => { useEffect(() => {
setEdidLoading(true);
send("getStreamQualityFactor", {}, (resp: JsonRpcResponse) => { send("getStreamQualityFactor", {}, (resp: JsonRpcResponse) => {
if ("error" in resp) return; if ("error" in resp) return;
setStreamQuality(String(resp.result)); setStreamQuality(String(resp.result));
}); });
send("getEDID", {}, (resp: JsonRpcResponse) => { send("getEDID", {}, (resp: JsonRpcResponse) => {
setEdidLoading(false);
if ("error" in resp) { if ("error" in resp) {
notifications.error(`Failed to get EDID: ${resp.error.data || "Unknown error"}`); notifications.error(`Failed to get EDID: ${resp.error.data || "Unknown error"}`);
return; return;
@ -89,7 +96,10 @@ export default function SettingsVideoRoute() {
}, [send]); }, [send]);
const handleStreamQualityChange = (factor: string) => { const handleStreamQualityChange = (factor: string) => {
send("setStreamQualityFactor", { factor: Number(factor) }, (resp: JsonRpcResponse) => { send(
"setStreamQualityFactor",
{ factor: Number(factor) },
(resp: JsonRpcResponse) => {
if ("error" in resp) { if ("error" in resp) {
notifications.error( notifications.error(
`Failed to set stream quality: ${resp.error.data || "Unknown error"}`, `Failed to set stream quality: ${resp.error.data || "Unknown error"}`,
@ -97,20 +107,25 @@ export default function SettingsVideoRoute() {
return; return;
} }
notifications.success(`Stream quality set to ${streamQualityOptions.find(x => x.value === factor)?.label}`); notifications.success(
`Stream quality set to ${streamQualityOptions.find(x => x.value === factor)?.label}`,
);
setStreamQuality(factor); setStreamQuality(factor);
}); },
);
}; };
const handleEDIDChange = (newEdid: string) => { const handleEDIDChange = (newEdid: string) => {
setEdidLoading(true);
send("setEDID", { edid: newEdid }, (resp: JsonRpcResponse) => { send("setEDID", { edid: newEdid }, (resp: JsonRpcResponse) => {
setEdidLoading(false);
if ("error" in resp) { if ("error" in resp) {
notifications.error(`Failed to set EDID: ${resp.error.data || "Unknown error"}`); notifications.error(`Failed to set EDID: ${resp.error.data || "Unknown error"}`);
return; return;
} }
notifications.success( notifications.success(
`EDID set successfully to ${edids.find(x => x.value === newEdid)?.label}`, `EDID set successfully to ${edids.find(x => x.value === newEdid)?.label ?? "the custom EDID"}`,
); );
// Update the EDID value in the UI // Update the EDID value in the UI
setEdid(newEdid); setEdid(newEdid);
@ -158,7 +173,7 @@ export default function SettingsVideoRoute() {
step="0.1" step="0.1"
value={videoSaturation} value={videoSaturation}
onChange={e => setVideoSaturation(parseFloat(e.target.value))} onChange={e => setVideoSaturation(parseFloat(e.target.value))}
className="w-32 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700" className="h-2 w-32 cursor-pointer appearance-none rounded-lg bg-gray-200 dark:bg-gray-700"
/> />
</SettingsItem> </SettingsItem>
@ -173,7 +188,7 @@ export default function SettingsVideoRoute() {
step="0.1" step="0.1"
value={videoBrightness} value={videoBrightness}
onChange={e => setVideoBrightness(parseFloat(e.target.value))} onChange={e => setVideoBrightness(parseFloat(e.target.value))}
className="w-32 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700" className="h-2 w-32 cursor-pointer appearance-none rounded-lg bg-gray-200 dark:bg-gray-700"
/> />
</SettingsItem> </SettingsItem>
@ -188,7 +203,7 @@ export default function SettingsVideoRoute() {
step="0.1" step="0.1"
value={videoContrast} value={videoContrast}
onChange={e => setVideoContrast(parseFloat(e.target.value))} onChange={e => setVideoContrast(parseFloat(e.target.value))}
className="w-32 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700" className="h-2 w-32 cursor-pointer appearance-none rounded-lg bg-gray-200 dark:bg-gray-700"
/> />
</SettingsItem> </SettingsItem>
@ -205,10 +220,11 @@ export default function SettingsVideoRoute() {
/> />
</div> </div>
</div> </div>
<Fieldset disabled={edidLoading} className="space-y-2">
<SettingsItem <SettingsItem
title="EDID" title="EDID"
description="Adjust the EDID settings for the display" description="Adjust the EDID settings for the display"
loading={edidLoading}
> >
<SelectMenuBasic <SelectMenuBasic
size="SM" size="SM"
@ -245,12 +261,14 @@ export default function SettingsVideoRoute() {
size="SM" size="SM"
theme="primary" theme="primary"
text="Set Custom EDID" text="Set Custom EDID"
loading={edidLoading}
onClick={() => handleEDIDChange(customEdidValue)} onClick={() => handleEDIDChange(customEdidValue)}
/> />
<Button <Button
size="SM" size="SM"
theme="light" theme="light"
text="Restore to default" text="Restore to default"
loading={edidLoading}
onClick={() => { onClick={() => {
setCustomEdidValue(null); setCustomEdidValue(null);
handleEDIDChange(defaultEdid); handleEDIDChange(defaultEdid);
@ -259,6 +277,7 @@ export default function SettingsVideoRoute() {
</div> </div>
</> </>
)} )}
</Fieldset>
</div> </div>
</div> </div>
</div> </div>