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.
 
 
 
 
 

154 lines
4.1 KiB

import {useContext, useEffect, useMemo, useState} from "react";
import RuntimeContext from "../../contexts/RuntimeContext";
import {WorkoutStatus} from "../../models/Workouts";
import {faArrowUpRightDots, faFastForward, faPause, faPlay, faStop} from "@fortawesome/free-solid-svg-icons";
import {useKey, usePlusMinus} from "../../hooks/keyboard";
import {Boi} from "../../primitives/boi/Boi";
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
warning?: boolean
onClick(): void
}
const skipMessages = ["Ikke hopp over", "Hopp over straks", "Hopp over nå"];
export function ControlsBoi() {
const {workout, disconnect, start, stop, setLevel, skip} = useContext(RuntimeContext);
const lastState = useLastState();
const [mode, setMode] = useState<"default" | "level" | "skip" | "disconnect">("default");
const [nextSkip, setNextSkip] = useState(-1);
const [lastTime, setLastTime] = useState(0);
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) {
const text = nextSkip > 0 ? `${nextSkip - lastTime} sek.` : "";
btnList.push({icon: faFastForward, text, warning: nextSkip >= 0, onClick: () => setMode("skip")});
} else {
btnList.push({icon: faArrowUpRightDots, onClick: () => setMode("level")});
}
}
if (isStopped) {
btnList.push({icon: faStop, onClick: () => {
disconnect();
setMode("disconnect");
}});
}
return btnList;
}, [workout, start, stop, disconnect, skip, nextSkip, lastTime]);
let length = options.length;
if (mode === "level") length = 32;
if (mode === "skip") length = 3;
const [sel, setSel] = usePlusMinus(length);
useKey("Enter", () => {
if (mode !== "default") {
if (mode === "level") {
setLevel(sel + 1);
} else if (mode === "skip") {
if (sel === 1) {
setNextSkip(lastTime + 60 - (lastTime % 60));
} else if (sel === 2) {
setNextSkip(0);
} else {
setNextSkip(-1);
}
}
setSel(0);
setMode("default");
} else {
if (options[sel]) {
options[sel].onClick();
} else if (options.length > 0) {
options[0].onClick()
}
}
setSel(0);
}, [options, lastTime, 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);
}
}, [lastState, mode]);
useEffect(() => {
if (lastState?.time) {
setLastTime(lastState.time!);
}
}, [lastState]);
useEffect(() => {
if (nextSkip !== -1 && (nextSkip === 0 || nextSkip <= lastTime)) {
setNextSkip(-1);
skip();
}
}, [lastTime, nextSkip]);
useEffect(() => {
if (mode === "default") {
setSel(0);
}
}, [mode]);
if (mode === "level") {
return <MessageBoi text={`${sel + 1} +/-`}/>;
}
if (mode === "skip") {
return <MessageBoi text={`${skipMessages[sel]} +/-`}/>;
}
if (mode === "disconnect") {
return <MessageBoi text="Kobler fra..."/>
}
return (
<Boi vertical="top" horizontal="right" style={{fontSize: "2vmax"}}>
{options.map((o, i) => (
<Blob key={i} color={(o.warning && lastTime % 2 === 0) ? "yellow" : (sel === i ? "indigo" : "gray")} onClick={o.onClick}>
<BlobText>
{o.icon && <Icon value={o.icon}/>} {o.text}
</BlobText>
</Blob>
))}
</Boi>
);
}