diff --git a/bigbluebutton-html5/imports/ui/components/captions/pad/component.jsx b/bigbluebutton-html5/imports/ui/components/captions/pad/component.jsx index c00838945b..75c8d3c751 100644 --- a/bigbluebutton-html5/imports/ui/components/captions/pad/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/captions/pad/component.jsx @@ -21,6 +21,22 @@ const intlMessages = defineMessages({ id: 'app.captions.pad.ownership', description: 'Label for taking ownership of closed captions pad', }, + dictationStart: { + id: 'app.captions.pad.dictationStart', + description: 'Label for starting speech recognition', + }, + dictationStop: { + id: 'app.captions.pad.dictationStop', + description: 'Label for stoping speech recognition', + }, + dictationOnDesc: { + id: 'app.captions.pad.dictationOnDesc', + description: 'Aria description for button that turns on speech recognition', + }, + dictationOffDesc: { + id: 'app.captions.pad.dictationOffDesc', + description: 'Aria description for button that turns off speech recognition', + }, }); const propTypes = { @@ -31,26 +47,23 @@ const propTypes = { name: PropTypes.string.isRequired, amIModerator: PropTypes.bool.isRequired, editCaptions: PropTypes.func.isRequired, + initVoiceRecognition: PropTypes.func.isRequired, intl: PropTypes.shape({ formatMessage: PropTypes.func.isRequired, }).isRequired, }; - class Pad extends Component { - constructor() { - super(); + constructor(props) { + super(props); + this.state = { listening: false, text: '', }; - const SR = window.SpeechRecognition || window.webkitSpeechRecognition; - this.recognition = new SR(); - - this.recognition.continuous = true; - this.recognition.interimResults = true; - this.recognition.lang = 'en-CA'; + const { initVoiceRecognition } = props; + this.recognition = initVoiceRecognition(); this.toggleListen = this.toggleListen.bind(this); this.handleListen = this.handleListen.bind(this); @@ -62,12 +75,13 @@ class Pad extends Component { listening, } = this.state; - if (nextState.text !== text && nextState.text !== '') { - return true; - } - if (nextState.listening !== listening) { + const padTextUpdate = nextState.text !== text && nextState.text !== ''; + const listeningUpdate = nextState.listening !== listening; + + if (padTextUpdate || listeningUpdate) { return true; } + return false; } @@ -160,11 +174,23 @@ class Pad extends Component { className={styles.hideBtn} /> - { this.toggleListen(); }} - label="Voice Recognition" - color="primary" - /> + + { this.toggleListen(); }} + label={listening + ? intl.formatMessage(intlMessages.dictationStop) + : intl.formatMessage(intlMessages.dictationStart) + } + aria-describedby="dictationBtnDesc" + color="primary" + /> + + {listening + ? intl.formatMessage(intlMessages.dictationOffDesc) + : intl.formatMessage(intlMessages.dictationOnDesc) + } + + {CaptionsService.canIOwnThisPad(ownerId) ? ( { const { name } = caption ? caption.locale : ''; + const initVoiceRecognition = (lang = 'en-CA') => { + const SR = window.SpeechRecognition || window.webkitSpeechRecognition; + let recognition = null; + if (SR) { + recognition = new SR(); + recognition.continuous = true; + recognition.interimResults = true; + recognition.lang = lang; + } + return recognition; + }; + return { locale, name, @@ -38,5 +50,6 @@ export default withTracker(() => { readOnlyPadId, amIModerator: CaptionsService.amIModerator(), editCaptions, + initVoiceRecognition, }; })(PadContainer); diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json index 3ebef4a788..1d2d938dd4 100755 --- a/bigbluebutton-html5/private/locales/en.json +++ b/bigbluebutton-html5/private/locales/en.json @@ -33,6 +33,10 @@ "app.captions.pad.hide": "Hide closed captions", "app.captions.pad.tip": "Press Esc to focus editor toolbar", "app.captions.pad.ownership": "Take ownership", + "app.captions.pad.dictationStart": "Start Dictation", + "app.captions.pad.dictationStop": "Stop Dictation", + "app.captions.pad.dictationOnDesc": "Turns speech recognition on", + "app.captions.pad.dictationOffDesc": "Turns speech recognition off", "app.note.title": "Shared Notes", "app.note.label": "Note", "app.note.hideNoteLabel": "Hide note",