You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
2.7 KiB
106 lines
2.7 KiB
import {useContext, useEffect, useMemo, useState} from "react";
|
|
import RuntimeContext from "../../contexts/RuntimeContext";
|
|
import {WorkoutStatus} from "../../models/Workouts";
|
|
import {faPause, faPlay} from "@fortawesome/free-solid-svg-icons";
|
|
import {useKey, usePlusMinus} from "../../hooks/keyboard";
|
|
import {Boi} from "../../primitives/boi/Boi";
|
|
import {TitleLine} from "../../primitives/misc/Misc";
|
|
import Blob, {BlobText} from "../../primitives/blob/Blob";
|
|
import {Icon} from "../../primitives/Shared";
|
|
import {useLastState} from "./hooks";
|
|
import {IconDefinition} from "@fortawesome/fontawesome-svg-core";
|
|
import MessageBoi from "./MessageBoi";
|
|
|
|
interface Option {
|
|
icon?: IconDefinition
|
|
text?: string
|
|
|
|
onClick(): void
|
|
}
|
|
|
|
export function ControlsBoi() {
|
|
const {workout, disconnect, start, stop, setLevel} = useContext(RuntimeContext);
|
|
const lastState = useLastState();
|
|
|
|
const [mode, setMode] = useState<"default" | "level">("default");
|
|
|
|
const options: Option[] = useMemo(() => {
|
|
if (!workout) return [];
|
|
|
|
const isStopped = workout.status === WorkoutStatus.Connected || workout.status === WorkoutStatus.Stopped;
|
|
|
|
const btnList: Option[] = [];
|
|
if (isStopped) {
|
|
btnList.push({icon: faPlay, onClick: start})
|
|
}
|
|
|
|
if (workout.status === WorkoutStatus.Started) {
|
|
btnList.push({icon: faPause, onClick: stop});
|
|
|
|
if (!workout.program) {
|
|
btnList.push({
|
|
text: "Motstand", onClick: () => {
|
|
setMode("level");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (isStopped) {
|
|
btnList.push({text: "Avslutt", onClick: disconnect});
|
|
}
|
|
|
|
return btnList;
|
|
}, [workout]);
|
|
|
|
const [sel, setSel] = usePlusMinus(mode === "level" ? 32 : options.length);
|
|
|
|
useKey("Enter", () => {
|
|
if (mode === "level") {
|
|
setLevel(sel + 1);
|
|
setSel(0);
|
|
setMode("default");
|
|
} else {
|
|
if (options[sel]) {
|
|
options[sel].onClick();
|
|
}
|
|
}
|
|
|
|
setSel(0);
|
|
}, [options, sel]);
|
|
|
|
useKey("Escape", () => {
|
|
if (!workout) return;
|
|
|
|
const isStopped = workout.status === WorkoutStatus.Connected || workout.status === WorkoutStatus.Stopped;
|
|
|
|
if (isStopped) {
|
|
disconnect();
|
|
}
|
|
|
|
}, [workout, disconnect]);
|
|
|
|
useEffect(() => {
|
|
if (lastState?.level && mode === "level") {
|
|
setSel(lastState.level - 1);
|
|
}
|
|
}, [mode]);
|
|
|
|
if (mode === "level") {
|
|
return (
|
|
<MessageBoi text={`${sel + 1} +/-`}/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Boi vertical="top" horizontal="right" style={{fontSize: "2vmax"}}>
|
|
{options.map((o, i) => (
|
|
<Blob key={i} color={sel === i ? "indigo" : "gray"} onClick={o.onClick}>
|
|
<BlobText>
|
|
{o.icon && <Icon value={o.icon}/>} {o.text}
|
|
</BlobText>
|
|
</Blob>
|
|
))}
|
|
</Boi>
|
|
);
|
|
}
|