|
@@ -1,27 +1,28 @@
|
|
|
-import { useState, useEffect, useRef } from "react";
|
|
|
-import { VideoJsPlayer } from "video.js";
|
|
|
+import { useState, useEffect, useRef } from 'react'
|
|
|
+import { VideoJsPlayer } from 'video.js'
|
|
|
|
|
|
-import { ITraining } from "../../training/types";
|
|
|
-import { getExerciseList, getTrainingTime, getPosition } from "../utils";
|
|
|
+import { ITraining } from '../../training/types'
|
|
|
+import { getExerciseList, getTrainingTime, getPosition } from '../utils'
|
|
|
|
|
|
-import Countdown from "./Countdown";
|
|
|
-import VideoPlayer from "./VideoPlayer";
|
|
|
-import AudioPlayer from "./AudioPlayer";
|
|
|
-import { IExerciseItem } from "../types";
|
|
|
-import { Howl } from "howler";
|
|
|
-import { useTimer } from "../hooks";
|
|
|
+import Countdown from './Countdown'
|
|
|
+import VideoPlayer from './VideoPlayer'
|
|
|
+import AudioPlayer from './AudioPlayer'
|
|
|
+import { IExerciseItem } from '../types'
|
|
|
+import { Howl } from 'howler'
|
|
|
+import { useTimer } from '../hooks'
|
|
|
+import theme from '../../styles/theme'
|
|
|
|
|
|
const Timer = ({ training }: { training: ITraining }) => {
|
|
|
- const [time, timer] = useTimer({ tickPeriod: 100 });
|
|
|
+ const [time, timer] = useTimer({ tickPeriod: 100 })
|
|
|
|
|
|
const [state, setState] = useState({
|
|
|
exerciseList: [] as IExerciseItem[],
|
|
|
totalTime: 0
|
|
|
- });
|
|
|
+ })
|
|
|
|
|
|
const rosie = useRef(
|
|
|
new Howl({
|
|
|
- src: ["/media/ROSIE.mp3"],
|
|
|
+ src: ['/media/ROSIE.mp3'],
|
|
|
sprite: {
|
|
|
ttt: [114, 2956 - 114],
|
|
|
five: [10211, 10883 - 10211],
|
|
@@ -36,16 +37,16 @@ const Timer = ({ training }: { training: ITraining }) => {
|
|
|
thirty: [27027, 28250 - 27027]
|
|
|
}
|
|
|
})
|
|
|
- );
|
|
|
+ )
|
|
|
|
|
|
useEffect(() => {
|
|
|
//console.log("effect 1");
|
|
|
- rosie.current.play("ttt");
|
|
|
- const exerciseList = getExerciseList(training.blocks);
|
|
|
- console.log(exerciseList);
|
|
|
- const totalTime = getTrainingTime(exerciseList);
|
|
|
- setState({ ...state, exerciseList, totalTime });
|
|
|
- }, [training]);
|
|
|
+ rosie.current.play('ttt')
|
|
|
+ const exerciseList = getExerciseList(training.blocks)
|
|
|
+ console.log(exerciseList)
|
|
|
+ const totalTime = getTrainingTime(exerciseList)
|
|
|
+ setState({ ...state, exerciseList, totalTime })
|
|
|
+ }, [training])
|
|
|
|
|
|
//console.log("is it over?", time, state.totalTime, trainingOver);
|
|
|
|
|
@@ -54,85 +55,70 @@ const Timer = ({ training }: { training: ITraining }) => {
|
|
|
previousExercise,
|
|
|
nextExercise,
|
|
|
exerciseTime
|
|
|
- } = getPosition(state.exerciseList, timer.time);
|
|
|
+ } = getPosition(state.exerciseList, timer.time)
|
|
|
//console.log("aaa", time, currentExercise);
|
|
|
|
|
|
useEffect(() => {
|
|
|
- if (time > state.totalTime) stopTimer();
|
|
|
+ if (time > state.totalTime) stopTimer()
|
|
|
const countdown = currentExercise
|
|
|
? currentExercise.duration + currentExercise.offset - timer.intTime + 1
|
|
|
- : 0;
|
|
|
+ : 0
|
|
|
if (timer.running && rosie.current && !rosie.current.playing()) {
|
|
|
if (exerciseTime < 1) {
|
|
|
- if (currentExercise && currentExercise.exercise !== "Rest")
|
|
|
- rosie.current.play("go");
|
|
|
- else rosie.current.play("rest");
|
|
|
- } else if (countdown === 90) rosie.current.play("ninety");
|
|
|
- else if (countdown === 60) rosie.current.play("sixty");
|
|
|
- else if (countdown === 30) rosie.current.play("thirty");
|
|
|
- else if (countdown === 5) rosie.current.play("five");
|
|
|
- else if (countdown === 4) rosie.current.play("four");
|
|
|
- else if (countdown === 3) rosie.current.play("three");
|
|
|
- else if (countdown === 2) rosie.current.play("two");
|
|
|
- else if (countdown === 1) rosie.current.play("one");
|
|
|
+ if (currentExercise && currentExercise.exercise !== 'Rest')
|
|
|
+ rosie.current.play('go')
|
|
|
+ else rosie.current.play('rest')
|
|
|
+ } else if (countdown === 90) rosie.current.play('ninety')
|
|
|
+ else if (countdown === 60) rosie.current.play('sixty')
|
|
|
+ else if (countdown === 30) rosie.current.play('thirty')
|
|
|
+ else if (countdown === 5) rosie.current.play('five')
|
|
|
+ else if (countdown === 4) rosie.current.play('four')
|
|
|
+ else if (countdown === 3) rosie.current.play('three')
|
|
|
+ else if (countdown === 2) rosie.current.play('two')
|
|
|
+ else if (countdown === 1) rosie.current.play('one')
|
|
|
}
|
|
|
- }, [time, timer.running]);
|
|
|
+ }, [time, timer.running])
|
|
|
|
|
|
- const video: { current: VideoJsPlayer | undefined } = useRef();
|
|
|
+ const video: { current: VideoJsPlayer | undefined } = useRef()
|
|
|
//const audio: { current: Howl | undefined } = useRef();
|
|
|
|
|
|
function startTimer() {
|
|
|
- if (time >= state.totalTime) return;
|
|
|
- timer.start();
|
|
|
- if (video.current) video.current.play();
|
|
|
+ if (time >= state.totalTime) return
|
|
|
+ timer.start()
|
|
|
+ if (video.current) video.current.play()
|
|
|
//if (audio.current) audio.current.play();
|
|
|
//console.log("Timer started.");
|
|
|
}
|
|
|
|
|
|
function stopTimer() {
|
|
|
- timer.stop();
|
|
|
- if (video.current) video.current.pause();
|
|
|
+ timer.stop()
|
|
|
+ if (video.current) video.current.pause()
|
|
|
//if (audio.current) audio.current.pause();
|
|
|
//console.log("stopped");
|
|
|
}
|
|
|
|
|
|
function forward() {
|
|
|
if (nextExercise) {
|
|
|
- timer.setTime(nextExercise.offset);
|
|
|
+ timer.setTime(nextExercise.offset)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function back() {
|
|
|
if (previousExercise) {
|
|
|
- timer.setTime(previousExercise.offset);
|
|
|
+ timer.setTime(previousExercise.offset)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const videoSrc =
|
|
|
currentExercise && currentExercise.video
|
|
|
? currentExercise.video
|
|
|
- : "/media/block0.mp4";
|
|
|
+ : '/media/block0.mp4'
|
|
|
//console.log("current state:", currentExercise, state);
|
|
|
|
|
|
return (
|
|
|
- <>
|
|
|
- <div>
|
|
|
- {/*<label htmlFor="rest">Rest</label>
|
|
|
- <input type="number" min="25" max="60" step="5" defaultValue="25" />*/}
|
|
|
- <button onClick={back} disabled={timer.running}>
|
|
|
- back
|
|
|
- </button>
|
|
|
- <button onClick={timer.running ? stopTimer : startTimer}>
|
|
|
- {timer.running ? "stop" : "start"}
|
|
|
- </button>
|
|
|
- <button onClick={forward} disabled={timer.running}>
|
|
|
- forward
|
|
|
- </button>
|
|
|
- </div>
|
|
|
- <div className="content">
|
|
|
- <h1>
|
|
|
- {(currentExercise && currentExercise.toplevelBlock) || "Torture"}
|
|
|
- </h1>
|
|
|
+ <div id='timer'>
|
|
|
+ <h1>{(currentExercise && currentExercise.toplevelBlock) || 'Torture'}</h1>
|
|
|
+ <div id='flow'>
|
|
|
<Countdown
|
|
|
seconds={
|
|
|
currentExercise ? currentExercise.duration - exerciseTime : 0
|
|
@@ -143,59 +129,112 @@ const Timer = ({ training }: { training: ITraining }) => {
|
|
|
}
|
|
|
onClick={timer.running ? stopTimer : startTimer}
|
|
|
/>
|
|
|
- <div className="header">current exercise</div>
|
|
|
- <div className="exercise">
|
|
|
- {currentExercise ? currentExercise.exercise : "😎"}
|
|
|
- </div>
|
|
|
- <div className="header">next up</div>
|
|
|
- <div className="exercise">
|
|
|
- {nextExercise ? nextExercise.exercise : "😎"}
|
|
|
+ <div id='controls'>
|
|
|
+ {/*<label htmlFor="rest">Rest</label>
|
|
|
+ <input type="number" min="25" max="60" step="5" defaultValue="25" />*/}
|
|
|
+ <button onClick={back} disabled={timer.running}>
|
|
|
+ back
|
|
|
+ </button>
|
|
|
+ <button onClick={timer.running ? stopTimer : startTimer}>
|
|
|
+ {timer.running ? 'stop' : 'start'}
|
|
|
+ </button>
|
|
|
+ <button onClick={forward} disabled={timer.running}>
|
|
|
+ forward
|
|
|
+ </button>
|
|
|
</div>
|
|
|
+ <h2>current exercise</h2>
|
|
|
+ <p className='exercise'>
|
|
|
+ {currentExercise ? currentExercise.exercise : '😎'}
|
|
|
+ </p>
|
|
|
+ <h2>next up</h2>
|
|
|
+ <p className='exercise'>
|
|
|
+ {nextExercise ? nextExercise.exercise : '😎'}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div id='description'>
|
|
|
<VideoPlayer
|
|
|
src={videoSrc}
|
|
|
getVideoHandle={(videoHandle: VideoJsPlayer) =>
|
|
|
(video.current = videoHandle)
|
|
|
}
|
|
|
/>
|
|
|
+ <p className='description'>
|
|
|
+ {currentExercise && currentExercise.description}
|
|
|
+ </p>
|
|
|
</div>
|
|
|
|
|
|
<style jsx>{`
|
|
|
- .content {
|
|
|
+ #timer {
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
- .header {
|
|
|
+ #timer h1 {
|
|
|
+ margin: 0 auto 0.8rem auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ #flow h2 {
|
|
|
margin-top: 0.4em;
|
|
|
font-size: 90%;
|
|
|
+ font-weight: 300;
|
|
|
+ text-transform: uppercase;
|
|
|
+ margin: auto;
|
|
|
}
|
|
|
|
|
|
- .exercise {
|
|
|
+ #flow p {
|
|
|
font-size: 110%;
|
|
|
font-weight: 900;
|
|
|
+ margin: 0 auto 0.8em auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ #controls {
|
|
|
+ margin-bottom: 0.4rem;
|
|
|
}
|
|
|
|
|
|
- :global(.content .video-js) {
|
|
|
- margin: 20px auto;
|
|
|
+ button {
|
|
|
+ margin: 0.3rem;
|
|
|
+ padding: 0.3rem;
|
|
|
+ min-width: 6rem;
|
|
|
+ border: none;
|
|
|
+ background-color: ${theme.colors.darkblue};
|
|
|
+ color: ${theme.colors.offWhite};
|
|
|
+ cursor: pointer;
|
|
|
}
|
|
|
|
|
|
- @media (min-width: 700px) {
|
|
|
- .content {
|
|
|
- text-align: center;
|
|
|
+ @media (min-width: 768px) {
|
|
|
+ #timer {
|
|
|
display: grid;
|
|
|
- grid-auto-flow: dense;
|
|
|
- grid-template-columns: 1fr auto;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
}
|
|
|
- .content h1 {
|
|
|
+ h1 {
|
|
|
+ margin: 0 auto 1.4rem auto;
|
|
|
grid-column: 1/3;
|
|
|
}
|
|
|
+
|
|
|
+ #flow h2 {
|
|
|
+ margin-bottom: 0.6rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ #controls,
|
|
|
+ #flow p {
|
|
|
+ margin-bottom: 1.4rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ button {
|
|
|
+ padding: 0.6rem;
|
|
|
+ margin: 0.6rem;
|
|
|
+ }
|
|
|
+
|
|
|
.header,
|
|
|
.exercise {
|
|
|
grid-column: 1/2;
|
|
|
}
|
|
|
+ .description {
|
|
|
+ grid-column: 2/3;
|
|
|
+ }
|
|
|
}
|
|
|
`}</style>
|
|
|
- </>
|
|
|
- );
|
|
|
-};
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
|
|
|
-export default Timer;
|
|
|
+export default Timer
|