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.
214 lines
7.2 KiB
214 lines
7.2 KiB
import Page, {PageFlexRow} from "../primitives/page/Page";
|
|
import {useCallback, useContext, useEffect, useMemo, useState} from "react";
|
|
import RuntimeContext from "../contexts/RuntimeContext";
|
|
import {useNavigate} from "react-router";
|
|
import LoadingPage from "./LoadingPage";
|
|
import DeviceContext from "../contexts/DeviceContext";
|
|
import ProgramContext from "../contexts/ProgramContext";
|
|
import {Device} from "../models/Devices";
|
|
import {Program, subTitleOfProgram} from "../models/Programs";
|
|
import {useKey, usePlusMinus} from "../hooks/keyboard";
|
|
import {FluffyValue, TitleLine, Value} from "../primitives/misc/Misc";
|
|
import Blob, {BlobText, BlobTextLine} from "../primitives/blob/Blob";
|
|
import {Icon} from "../primitives/Shared";
|
|
import {faClose, faPlay} from "@fortawesome/free-solid-svg-icons";
|
|
import {stateString, WorkoutStatus} from "../models/Workouts";
|
|
import {Boi} from "../primitives/boi/Boi";
|
|
import {useLastState} from "./runtime/hooks";
|
|
import {ControlsBoi} from "./runtime/ControlsBoi";
|
|
import MessageBoi from "./runtime/MessageBoi";
|
|
import ProgramBoi from "./runtime/ProgramBoi";
|
|
import MilestoneBoi from "./runtime/MilestoneBoi";
|
|
import {useKpm} from "../hooks/kpm";
|
|
import useLocalStorage from "../hooks/storage";
|
|
|
|
function PlayPage(): JSX.Element {
|
|
const {active, ready, ended, workout, reset, resume} = useContext(RuntimeContext);
|
|
const navigate = useNavigate();
|
|
|
|
useEffect(() => {
|
|
if (!active) {
|
|
resume();
|
|
}
|
|
}, [active, resume]);
|
|
|
|
useEffect(() => {
|
|
if (active && ended && workout) {
|
|
navigate(`/workouts/${workout.id}`, {replace: true});
|
|
reset();
|
|
}
|
|
}, [active, ready, ended, workout]);
|
|
|
|
if (active && ready && workout === null) {
|
|
return <CreatePlayPage/>;
|
|
}
|
|
|
|
if (active && workout !== null) {
|
|
return <RunPlayPage/>;
|
|
}
|
|
|
|
return <LoadingPage minimal text="Starter økt"/>;
|
|
}
|
|
|
|
const noProgram: Program = {
|
|
id: "",
|
|
name: "Uten program",
|
|
steps: [{index: 0, values: {}, duration: undefined}],
|
|
}
|
|
|
|
function CreatePlayPage(): JSX.Element {
|
|
const {devices} = useContext(DeviceContext);
|
|
const {programs} = useContext(ProgramContext);
|
|
const {create} = useContext(RuntimeContext);
|
|
const programWithFake = useMemo(() => programs ? [noProgram, ...programs] : null, [programs]);
|
|
const navigate = useNavigate();
|
|
|
|
const [device, setDevice] = useState<Device | null>(null);
|
|
const [program, setProgram] = useState<Program | null>(null);
|
|
|
|
const [sel, setSel] = usePlusMinus((device ? (program ? 2 : programWithFake?.length) : devices?.length) || 1);
|
|
|
|
const confirmSelection = useCallback((idx: number) => {
|
|
if (program && device) {
|
|
if (idx === 0) {
|
|
create({deviceId: device.id, programId: program.id || undefined, test: false})
|
|
} else {
|
|
navigate("/");
|
|
}
|
|
} else if (device && programWithFake) {
|
|
setProgram(programWithFake[idx] || null);
|
|
setSel(0);
|
|
} else if (devices !== null) {
|
|
setDevice(devices[idx] || null);
|
|
setSel(0);
|
|
}
|
|
}, [create, device, program, devices, programWithFake]);
|
|
|
|
useKey("Enter", () => {
|
|
confirmSelection(sel);
|
|
}, [confirmSelection, sel]);
|
|
|
|
useKey("Escape", () => {
|
|
navigate("/");
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (devices && devices.length === 0) {
|
|
navigate("/");
|
|
}
|
|
}, [devices]);
|
|
|
|
if (devices === null) {
|
|
return <LoadingPage minimal text="Henter enheter"/>
|
|
} else if (programWithFake === null) {
|
|
return <LoadingPage minimal text="Henter programmer"/>
|
|
}
|
|
|
|
return (
|
|
<Page background={"2046"}>
|
|
{device === null && (
|
|
<Boi vertical="center" horizontal="center" style={{fontSize: undefined}}>
|
|
<TitleLine>Velg enhet</TitleLine>
|
|
{devices.map((d, i) => (
|
|
<Blob key={d.id} onClick={() => confirmSelection(i)} color={sel === i ? "indigo" : "gray"}>
|
|
<BlobText>
|
|
<BlobTextLine>{d.name}</BlobTextLine>
|
|
<BlobTextLine secondary>{d.connectionString}</BlobTextLine>
|
|
</BlobText>
|
|
</Blob>
|
|
))}
|
|
</Boi>
|
|
)}
|
|
|
|
{device !== null && program === null && (
|
|
<Boi vertical="center" horizontal="center" style={{fontSize: undefined}}>
|
|
<TitleLine>Velg program</TitleLine>
|
|
{programWithFake.map((p, i) => (
|
|
<Blob key={p.id} onClick={() => confirmSelection(i)} color={sel === i ? "indigo" : "gray"}>
|
|
<BlobText>
|
|
<BlobTextLine>{p.name}</BlobTextLine>
|
|
<BlobTextLine secondary>{subTitleOfProgram(p)}</BlobTextLine>
|
|
</BlobText>
|
|
</Blob>
|
|
))}
|
|
</Boi>
|
|
)}
|
|
|
|
{device && program && (
|
|
<Boi vertical="center" horizontal="center" style={{fontSize: undefined}}>
|
|
<TitleLine>Oppsumering</TitleLine>
|
|
{device && (
|
|
<Blob>
|
|
<BlobText>
|
|
<BlobTextLine>{device.name}</BlobTextLine>
|
|
<BlobTextLine secondary>{device.connectionString}</BlobTextLine>
|
|
</BlobText>
|
|
</Blob>
|
|
)}
|
|
{program && (
|
|
<Blob>
|
|
<BlobText>
|
|
<BlobTextLine>{program.name}</BlobTextLine>
|
|
<BlobTextLine secondary>{subTitleOfProgram(program)}</BlobTextLine>
|
|
</BlobText>
|
|
</Blob>
|
|
)}
|
|
<PageFlexRow>
|
|
{device && program && (
|
|
<>
|
|
<Blob onClick={() => confirmSelection(0)} color={sel === 0 ? "indigo" : "gray"}>
|
|
<BlobText>
|
|
<Icon value={faPlay}/> Start
|
|
</BlobText>
|
|
</Blob>
|
|
<Blob onClick={() => confirmSelection(1)} color={sel === 1 ? "indigo" : "gray"}>
|
|
<BlobText>
|
|
<Icon value={faClose}/> Avbryt
|
|
</BlobText>
|
|
</Blob>
|
|
</>
|
|
)}
|
|
</PageFlexRow>
|
|
</Boi>
|
|
)}
|
|
</Page>
|
|
);
|
|
}
|
|
|
|
function RunPlayPage(): JSX.Element {
|
|
const {workout} = useContext(RuntimeContext);
|
|
const lastState = useLastState();
|
|
const kpm = useKpm();
|
|
const [statPos] = useLocalStorage<"left" | "right">("stats.position", "left");
|
|
|
|
if (!workout || workout.status === WorkoutStatus.Created) {
|
|
return <LoadingPage minimal/>;
|
|
}
|
|
|
|
return (
|
|
<Page title="YKonsole" background={"2046"}>
|
|
<ControlsBoi/>
|
|
{lastState && (
|
|
<Boi vertical="center" horizontal={statPos} style={{padding: "0.5vmax", paddingBottom: "0"}}>
|
|
<span style={{fontSize: "125%"}}>
|
|
<FluffyValue raw={lastState} valueKey="time"/>
|
|
</span>
|
|
<FluffyValue raw={lastState} valueKey="calories"/>
|
|
<FluffyValue raw={lastState} valueKey="distance"/>
|
|
<FluffyValue raw={lastState} valueKey="level"/>
|
|
<FluffyValue raw={lastState} valueKey="rpmSpeed"/>
|
|
{kpm > 0 && <FluffyValue raw={kpm} valueKey="kpm"/>}
|
|
<FluffyValue raw={lastState} valueKey="pulse"/>
|
|
</Boi>
|
|
)}
|
|
{workout?.status === WorkoutStatus.Connected && <MessageBoi text="Trykk Enter for å begynne"/>}
|
|
{workout?.status === WorkoutStatus.Stopped && <MessageBoi text="Pause"/>}
|
|
{workout.program && workout.program.steps.length > 0 && <ProgramBoi/>}
|
|
<MilestoneBoi/>
|
|
</Page>
|
|
);
|
|
}
|
|
|
|
|
|
|
|
export default PlayPage;
|