diff --git a/frontend/src/App/App.css b/frontend/src/App/App.css index 7f94c89..c27890f 100644 --- a/frontend/src/App/App.css +++ b/frontend/src/App/App.css @@ -28,6 +28,10 @@ } } +.page { + margin-top: 20px; +} + body { text-align: left; font-family: "Roboto"; @@ -36,7 +40,7 @@ body { color: #2c3e50; /* margin-right: 2em; margin-left: 2em; */ - margin-bottom: 100px; + /* margin-bottom: 100px; */ } a { @@ -83,11 +87,13 @@ hr { /* background-color: #ff0000; */ border-top: 1px solid #f1f3f4; } +.page-intro { + margin-bottom: 20px; +} .topnav { height: 64px; background-color: #22a7f0; - margin-bottom: 34px; color: white; font-weight: 400; font-size: 18px; @@ -99,10 +105,32 @@ hr { /* margin-top: 10px; */ } -.top-container { +.top-container { + display: flex; + justify-content: center; + flex-wrap: wrap; + position: absolute; + top: 64px; + left: 0; + right: 0; + bottom: 0; + padding: 100px 150px 100px 150px; + background-color: rgba(0, 0, 0, 0.8); + z-index: 100; +} + +.top-container-info { display: flex; justify-content: space-between; flex-wrap: wrap; + padding: 50px 50px 0 50px; + background-color: white; + border-radius: 5px; +} + +.info-btn { + margin: 20px 20px 0px 20px; + height: 50px; } .key-icon { @@ -180,19 +208,20 @@ hr { display: flex; justify-content: space-between; flex-wrap: wrap; + padding-bottom: 10px; } .total-hours { - margin: 0px 30px 40px 0px; - padding: 40px 50px 40px 50px; + margin: 0px 30px 0px 0px; + padding: 20px 50px 20px 50px; background-color: #f1f3f4; border-radius: 6px; flex: 1; } .speech-rate { - margin: 0px 0px 40px 0px; - padding: 40px 50px 40px 50px; + margin: 0px 0px 0px 0px; + padding: 20px 50px 20px 50px; background-color: #f1f3f4; border-radius: 6px; flex: 1; @@ -268,6 +297,12 @@ hr { cursor: pointer; } +.btn-disabled { + cursor: initial !important; + background-color: #D3D3D3 !important; + color: #2c3e50 !important; +} + .btn:hover { background-color: #FD8E4C; } @@ -433,8 +468,9 @@ input::placeholder { .feedback-ball-red { background-color: rgb(228, 63, 70); - width: 100px; - height: 30px; + /* width: 100px; */ + /* height: 30px; */ + padding: 0px 5px 0px 5px; border-radius: 5px; position: absolute; top: 10px; @@ -445,7 +481,8 @@ input::placeholder { .feedback-ball-green { background-color: rgb(37, 162, 78); - width: 100px; + /* width: 100px; */ + padding: 0px 5px 0px 5px; height: 30px; border-radius: 5px; position: absolute; @@ -467,7 +504,8 @@ input::placeholder { .feedback-ball-red-t { background-color: rgb(228, 63, 70); - width: 100px; + /* width: 100px; */ + padding: 0px 5px 0px 5px; height: 30px; border-radius: 5px; font-size: large; @@ -477,7 +515,8 @@ input::placeholder { .feedback-ball-green-t { background-color: rgb(37, 162, 78); - width: 100px; + /* width: 100px; */ + padding: 0px 5px 0px 5px; height: 30px; border-radius: 5px; font-size: large; @@ -509,6 +548,10 @@ input::placeholder { /* height: 100%; */ } +.wave-container { + background-color: #222222; + width: 100%; +} #analyser, #wavedisplay { @@ -519,12 +562,11 @@ input::placeholder { } #waveform { - margin-bottom: 35px; + /* margin-bottom: 35px; */ } .wavedisplay { width: 100%; height: 128px; - margin-bottom: 1.75em; margin-top: -32px; } @@ -559,9 +601,8 @@ canvas { #controls { text-align: center; - padding-top: 0; padding-bottom: 27px; - /* margin: 10px; */ + margin-top: 28px; /* margin-top: 2vh; */ /* background-color: red; */ } @@ -614,3 +655,15 @@ canvas { border-radius: 6px; /* line-height: 2; */ } + +.indicator-container { + background-color: #222222; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + margin-top: -12px; + height: 5vh; + display: flex; + justify-content: center; + align-items: center; + color: white; +} \ No newline at end of file diff --git a/frontend/src/App/Intro.js b/frontend/src/App/Intro.js index 532ae3e..7fe3da1 100644 --- a/frontend/src/App/Intro.js +++ b/frontend/src/App/Intro.js @@ -20,7 +20,7 @@ class Intro extends Component { render() { return ( -
+

Mimic Recording Studio

Help us build the voice(s) of Mycroft!

diff --git a/frontend/src/App/Record.js b/frontend/src/App/Record.js index f8cf8f1..0667086 100644 --- a/frontend/src/App/Record.js +++ b/frontend/src/App/Record.js @@ -24,12 +24,13 @@ class Record extends Component { displayWav: false, blob: undefined, play: false, - prompt: "...error loading prompt...", + prompt: "*error loading prompt... is the backend running?*", language: "", promptNum: 0, totalTime: 0, totalCharLen: 0, - audioLen: 0 + audioLen: 0, + showPopup: true }; this.uuid = getUUID(); @@ -49,7 +50,12 @@ class Record extends Component { return (

Mimic Recording Studio

- + -
+
{this.state.displayWav ? this.renderWave() : this.renderVisualizer()}
- +
+ {this.state.shouldRecord + ? "Read Now [Esc] to cancel" + : "[Spacebar] to Start Recording [R] to review [->] for next"} +
); } + dismissPopup = () => { + this.setState({ + showPopup: false + }); + }; + requestPrompts = uuid => { getPrompt(uuid) .then(res => res.json()) @@ -180,9 +212,25 @@ class Record extends Component { } } - // play wav - if (event.keyCode === 80) { + // esc key code + if (event.keyCode === 27) { event.preventDefault(); + + // resets all states + this.setState({ + shouldRecord: false, + displayWav: false, + blob: undefined, + promptNum: 0, + totalTime: 0, + totalCharLen: 0, + audioLen: 0, + play: false + }); + } + + // play wav + if (event.keyCode === 82) { this.playWav(); } @@ -196,11 +244,11 @@ class Record extends Component { setTimeout(() => { this.setState((state, props) => { return { - shouldRecord: !state.shouldRecord, + shouldRecord: true, play: false }; }); - }, 200); + }, 500); }; onNext = () => { @@ -241,54 +289,65 @@ class Record extends Component { class TopContainer extends Component { render() { + return this.props.show ? this.renderContainer() : null; + } + + renderContainer = () => { return (
-
- -

HINTS

-
    -
  • - space will - start recording -
  • -
  • Recording will auto-stop after you speak
  • -
  • - p will play recorded - audio -
  • -
  • - -> will go to - next prompt -
  • -
-
-
-
-
-

RECORDER

-   - {this.props.userName} +
+
+ +

HINTS

+
    +
  • + space will + start recording +
  • +
  • Recording will auto-stop after you speak
  • +
  • + p will play + recorded audio +
  • +
  • + -> will go to + next prompt +
  • +
+
+
+
+
+

RECORDER

+   + {this.props.userName} +
+
-
+
+

+ It is very important that the recorded words{" "} + + match the text in the script exactly + + . If you accidentally deviate from the script or are unsure, + please record the prompt again. +

-
-

- It is very important that the recorded words{" "} - - match the text in the script exactly - - . If you accidentally deviate from the script or are unsure, please - record the prompt again. -

-
+ +
); - } - + }; + handleClick = () => { - this.props.route("/tutorial") - } + this.props.route("/tutorial"); + }; } export default Record; diff --git a/frontend/src/App/components/PhraseBox.js b/frontend/src/App/components/PhraseBox.js index 8ade739..196da0e 100644 --- a/frontend/src/App/components/PhraseBox.js +++ b/frontend/src/App/components/PhraseBox.js @@ -1,60 +1,64 @@ import React, { Component } from "react"; -import PropTypes from 'prop-types'; +import PropTypes from "prop-types"; class PhraseBox extends Component { - render() { + render() { + return ( +
+
+ {this.renderFeedback()} + {this.props.prompt} +
+
+ ); + } + + renderFeedback = () => { + if (this.props.promptNum < 20 || this.props.audioLen === 0) { + return ""; + } else { + const speechRate = this.props.prompt.length / this.props.audioLen; + const avgSpeechRate = ( + this.props.totalCharLen / this.props.totalTime + ).toFixed(1); + // allow deviation of 25% of speechRate from average speech rate + if (this.determinePace(avgSpeechRate, speechRate)) { + return
Consistent Pace
; + } else if (speechRate < avgSpeechRate) { + return ( +
Slower than your average
+ ); + } else { return ( -
-
- {this.renderFeedback()} - {this.props.prompt} -
-
+
Faster than your average
); + } } + }; - renderFeedback = () => { - if (this.props.promptNum < 20 || this.props.audioLen === 0) { - return "" - } else { - const speechRate = this.props.prompt.length / this.props.audioLen; - const avgSpeechRate = ( - this.props.totalCharLen / this.props.totalTime - ).toFixed(1); - // allow deviation of 25% of speechRate from average speech rate - if (this.determinePace(avgSpeechRate, speechRate)) { - return
Good Pace
; - } else if (speechRate < avgSpeechRate) { - return
Too Slow
; - } else { - return
Too Fast
; - } - } - }; - - determinePace = (avgSpeechRate, speechRate) => { - if (this.props.prompt.length <= 25) { - return ( - avgSpeechRate * 0.5 < speechRate && speechRate < avgSpeechRate * 1.5 - ); - } else if (this.props.prompt.length <= 125) { - return ( - avgSpeechRate * 0.75 < speechRate && speechRate < avgSpeechRate * 1.25 - ); - } else { - return ( - avgSpeechRate * 0.85 < speechRate && speechRate < avgSpeechRate * 1.15 - ); - } - }; + determinePace = (avgSpeechRate, speechRate) => { + if (this.props.prompt.length <= 25) { + return ( + avgSpeechRate * 0.5 < speechRate && speechRate < avgSpeechRate * 1.5 + ); + } else if (this.props.prompt.length <= 125) { + return ( + avgSpeechRate * 0.75 < speechRate && speechRate < avgSpeechRate * 1.25 + ); + } else { + return ( + avgSpeechRate * 0.85 < speechRate && speechRate < avgSpeechRate * 1.15 + ); + } + }; } PhraseBox.propTypes = { - prompt: PropTypes.string, - promptNum: PropTypes.number, - audioLen: PropTypes.number, - totalCharLen: PropTypes.number, - totalTime: PropTypes.number -} + prompt: PropTypes.string, + promptNum: PropTypes.number, + audioLen: PropTypes.number, + totalCharLen: PropTypes.number, + totalTime: PropTypes.number +}; export default PhraseBox; diff --git a/frontend/src/App/components/Wave.js b/frontend/src/App/components/Wave.js index 331a685..bde71af 100644 --- a/frontend/src/App/components/Wave.js +++ b/frontend/src/App/components/Wave.js @@ -4,6 +4,8 @@ import PropTypes from 'prop-types'; class Wave extends Component { componentDidMount() { + document.addEventListener("keydown", this.handleKeyDown, false); + const { waveColor, blob } = this.props; this.wavesurfer = WaveSurfer.create({ container: "#waveform", @@ -18,7 +20,17 @@ class Wave extends Component { componentDidUpdate() { if (this.props.play) { + console.log("play") this.wavesurfer.play(); + } else { + console.log("pausing") + this.wavesurfer.pause(); + } + } + + handleKeyDown = (event) => { + if (event.keyCode === 27) { + this.wavesurfer.pause() } }