// @flow import { Component } from 'react'; /** * {@code AbstractCaptions} properties. */ export type AbstractCaptionsProps = { /** * Whether local participant is requesting to see subtitles. */ _requestingSubtitles: boolean, /** * Transcript texts formatted with participant's name and final content. * Mapped by id just to have the keys for convenience during the rendering * process. */ _transcripts: ?Map }; /** * Abstract React {@code Component} which can display speech-to-text results * from Jigasi as subtitles. */ export class AbstractCaptions extends Component

{ /** * Implements React's {@link Component#render()}. * * @inheritdoc * @returns {React$Element} */ render() { const { _requestingSubtitles, _transcripts } = this.props; if (!_requestingSubtitles || !_transcripts || !_transcripts.size) { return null; } const paragraphs = []; for (const [ id, text ] of _transcripts) { paragraphs.push(this._renderParagraph(id, text)); } return this._renderSubtitlesContainer(paragraphs); } /** * Renders the transcription text. * * @abstract * @param {string} id - The ID of the transcript message from which the * {@code text} has been created. * @param {string} text - Subtitles text formatted with the participant's * name. * @protected * @returns {React$Element} - The React element which displays the text. */ _renderParagraph: (id: string, text: string) => React$Element<*>; /** * Renders the subtitles container. * * @abstract * @param {Array} paragraphs - An array of elements created * for each subtitle using the {@link _renderParagraph} method. * @protected * @returns {React$Element} - The subtitles container. */ _renderSubtitlesContainer: (Array>) => React$Element<*>; } /** * Formats the transcript messages into text by prefixing participant's name to * avoid duplicating the effort on platform specific component. * * @param {Object} state - The redux state. * @private * @returns {Map} - Formatted transcript subtitles mapped by * transcript message IDs. */ function _constructTranscripts(state: Object): Map { const { _transcriptMessages } = state['features/subtitles']; const transcripts = new Map(); for (const [ id, transcriptMessage ] of _transcriptMessages) { if (transcriptMessage) { let text = `${transcriptMessage.participantName}: `; if (transcriptMessage.final) { text += transcriptMessage.final; } else { const stable = transcriptMessage.stable || ''; const unstable = transcriptMessage.unstable || ''; text += stable + unstable; } transcripts.set(id, text); } } return transcripts; } /** * Maps the transcriptionSubtitles in the redux state to the associated props of * {@code AbstractCaptions}. * * @param {Object} state - The redux state. * @private * @returns {{ * _requestingSubtitles: boolean, * _transcripts: Map * }} */ export function _abstractMapStateToProps(state: Object) { const { _requestingSubtitles } = state['features/subtitles']; const transcripts = _constructTranscripts(state); return { _requestingSubtitles, // avoid rerenders by setting to props new empty Map instances. _transcripts: transcripts.size === 0 ? undefined : transcripts }; }