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.
 
 
 
 
 

204 lines
6.7 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 {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";
function PlayPage(): JSX.Element {
const {active, ready, ended, workout, reset, resume} = useContext(RuntimeContext);
const navigate = useNavigate();
useEffect(() => {
if (!active) {
resume();
} else if (active && ended) {
if (workout) {
navigate(`/workouts/${workout.id}`, {replace: true});
reset();
}
}
}, [active, ready, ended, workout, resume]);
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();
if (!workout || workout.status === WorkoutStatus.Created) {
return <LoadingPage minimal/>;
}
return (
<Page title="YKonsole" background={"2046"}>
<ControlsBoi/>
{lastState && (
<Boi vertical="center" horizontal="left" style={{padding: "0.5vmax", paddingBottom: "0"}}>
<Value raw={lastState} valueKey="time"/>
<br/>
<Value raw={lastState} valueKey="calories"/>
<br/>
<Value raw={lastState} valueKey="distance"/>
<br/>
<Value raw={lastState} valueKey="level"/>
</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/>}
</Page>
);
}
export default PlayPage;