Files
SlimeVR-Server/gui/src/components/onboarding/pages/mounting/ManualMounting.tsx
2022-11-25 18:05:36 +03:00

118 lines
4.2 KiB
TypeScript

import Quaternion from 'quaternion';
import { useMemo, useState } from 'react';
import { AssignTrackerRequestT, BodyPart, RpcMessage } from 'solarxr-protocol';
import { FlatDeviceTracker } from '../../../../hooks/app';
import { useOnboarding } from '../../../../hooks/onboarding';
import { useTrackers } from '../../../../hooks/tracker';
import { useWebsocketAPI } from '../../../../hooks/websocket-api';
import { QuaternionToQuatT } from '../../../../maths/quaternion';
import { ArrowLink } from '../../../commons/ArrowLink';
import { Button } from '../../../commons/Button';
import { TipBox } from '../../../commons/TipBox';
import { Typography } from '../../../commons/Typography';
import { BodyAssignment } from '../../BodyAssignment';
import { MountingSelectionMenu } from './MountingSelectionMenu';
export function ManualMountingPage() {
const { applyProgress, skipSetup, state } = useOnboarding();
const { sendRPCPacket } = useWebsocketAPI();
const [selectedRole, setSelectRole] = useState<BodyPart>(BodyPart.NONE);
applyProgress(0.7);
const { useAssignedTrackers } = useTrackers();
const assignedTrackers = useAssignedTrackers();
const trackerPartGrouped = useMemo(
() =>
assignedTrackers.reduce<{ [key: number]: FlatDeviceTracker[] }>(
(curr, td) => {
const key = td.tracker.info?.bodyPart || BodyPart.NONE;
return {
...curr,
[key]: [...(curr[key] || []), td],
};
},
{}
),
[assignedTrackers]
);
const onDirectionSelected = (mountingOrientation: number) => {
(trackerPartGrouped[selectedRole] || []).forEach((td) => {
const assignreq = new AssignTrackerRequestT();
assignreq.bodyPosition = td.tracker.info?.bodyPart || BodyPart.NONE;
assignreq.mountingRotation = QuaternionToQuatT(
Quaternion.fromEuler(0, +mountingOrientation, 0)
);
assignreq.trackerId = td.tracker.trackerId;
sendRPCPacket(RpcMessage.AssignTrackerRequest, assignreq);
});
setSelectRole(BodyPart.NONE);
};
return (
<>
<MountingSelectionMenu
isOpen={selectedRole !== BodyPart.NONE}
onClose={() => setSelectRole(BodyPart.NONE)}
onDirectionSelected={onDirectionSelected}
></MountingSelectionMenu>
<div className="flex flex-col gap-5 h-full items-center w-full justify-center">
<div className="flex flex-col w-full h-full justify-center items-center">
<div className="flex md:gap-8">
<div className="flex flex-col w-full max-w-md gap-3">
{!state.alonePage && (
<ArrowLink to="/onboarding/enter-vr" direction="left">
Go Back to Enter VR
</ArrowLink>
)}
<Typography variant="main-title">Manual Mounting</Typography>
<Typography color="secondary">
Click on every tracker and select which way they are mounted
</Typography>
<TipBox>
Not sure which tracker is which? Shake a tracker and it will
highlight the corresponding item.
</TipBox>
</div>
<div className="flex flex-col flex-grow gap-3 rounded-xl fill-background-50">
<BodyAssignment
onlyAssigned={true}
advanced={true}
onRoleSelected={setSelectRole}
></BodyAssignment>
</div>
</div>
</div>
<div className="w-full pb-4 flex flex-row">
<div className="flex flex-grow">
{!state.alonePage && (
<Button variant="secondary" to="/" onClick={skipSetup}>
Skip setup
</Button>
)}
</div>
<div className="flex gap-3">
<Button
variant="secondary"
state={{ alonePage: state.alonePage }}
to="/onboarding/mounting/auto"
>
Automatic mounting
</Button>
{!state.alonePage && (
<Button variant="primary" to="/onboarding/reset-tutorial">
Next step
</Button>
)}
</div>
</div>
</div>
</>
);
}