(feat): add preview button to the call settings page
This commit is contained in:
parent
45e7591e40
commit
5a26c2d401
1 changed files with 59 additions and 17 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import {
|
import {
|
||||||
|
Button,
|
||||||
Label,
|
Label,
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
|
|
@ -7,8 +8,10 @@ import {
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@methanium/ui";
|
} from "@methanium/ui";
|
||||||
import { settingsStorageDefaults } from "@tensamin/shared/settings";
|
import { settingsStorageDefaults } from "@tensamin/shared/settings";
|
||||||
|
import { playSound, stopSound } from "@tensamin/shared/sounds";
|
||||||
import { useStorage } from "@tensamin/storage/context";
|
import { useStorage } from "@tensamin/storage/context";
|
||||||
import { useEffect, useState } from "react";
|
import { Play, Square } from "lucide-react";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
type CallJingle = (typeof settingsStorageDefaults)["settings.call_jingle"];
|
type CallJingle = (typeof settingsStorageDefaults)["settings.call_jingle"];
|
||||||
|
|
||||||
|
|
@ -19,33 +22,72 @@ const jingleLabels: Record<CallJingle, string> = {
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const { load, save } = useStorage();
|
const { load, save } = useStorage();
|
||||||
|
const preview = useRef<HTMLAudioElement>(null);
|
||||||
const [jingle, setJingle] = useState<CallJingle>(
|
const [jingle, setJingle] = useState<CallJingle>(
|
||||||
settingsStorageDefaults["settings.call_jingle"],
|
settingsStorageDefaults["settings.call_jingle"],
|
||||||
);
|
);
|
||||||
|
const [isPreviewing, setIsPreviewing] = useState(false);
|
||||||
|
|
||||||
|
function stopPreview() {
|
||||||
|
stopSound(preview.current);
|
||||||
|
preview.current = null;
|
||||||
|
setIsPreviewing(false);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void load("settings.call_jingle").then(setJingle);
|
void load("settings.call_jingle").then(setJingle);
|
||||||
}, [load]);
|
}, [load]);
|
||||||
|
|
||||||
|
useEffect(() => () => stopSound(preview.current), []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex max-w-md flex-col gap-2">
|
<div className="flex max-w-md flex-col gap-2">
|
||||||
<Label htmlFor="call-jingle">Outgoing call jingle</Label>
|
<Label htmlFor="call-jingle">Outgoing call jingle</Label>
|
||||||
<Select
|
<div className="flex gap-2">
|
||||||
value={jingle}
|
<Select
|
||||||
onValueChange={(value) => {
|
value={jingle}
|
||||||
const nextJingle = value ?? "jingle_1";
|
onValueChange={(value) => {
|
||||||
setJingle(nextJingle);
|
const nextJingle = value ?? "jingle_1";
|
||||||
void save("settings.call_jingle", nextJingle);
|
stopPreview();
|
||||||
}}
|
setJingle(nextJingle);
|
||||||
>
|
void save("settings.call_jingle", nextJingle);
|
||||||
<SelectTrigger className="w-full" id="call-jingle">
|
}}
|
||||||
<SelectValue>{jingleLabels[jingle]}</SelectValue>
|
>
|
||||||
</SelectTrigger>
|
<SelectTrigger className="w-full" id="call-jingle">
|
||||||
<SelectContent className="p-1">
|
<SelectValue>{jingleLabels[jingle]}</SelectValue>
|
||||||
<SelectItem value="jingle_1">Jingle 1</SelectItem>
|
</SelectTrigger>
|
||||||
<SelectItem value="jingle_2">Jingle 2</SelectItem>
|
<SelectContent className="p-1">
|
||||||
</SelectContent>
|
<SelectItem value="jingle_1">Jingle 1</SelectItem>
|
||||||
</Select>
|
<SelectItem value="jingle_2">Jingle 2</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
aria-label={isPreviewing ? "Stop jingle preview" : "Preview jingle"}
|
||||||
|
title={isPreviewing ? "Stop preview" : "Preview jingle"}
|
||||||
|
onClick={() => {
|
||||||
|
if (isPreviewing) {
|
||||||
|
stopPreview();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const audio = playSound(
|
||||||
|
jingle === "jingle_2" ? "call_jingle_2" : "call_jingle_1",
|
||||||
|
);
|
||||||
|
preview.current = audio;
|
||||||
|
setIsPreviewing(true);
|
||||||
|
audio.addEventListener(
|
||||||
|
"ended",
|
||||||
|
() => {
|
||||||
|
if (preview.current === audio) stopPreview();
|
||||||
|
},
|
||||||
|
{ once: true },
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isPreviewing ? <Square /> : <Play />}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue