You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AbstractCaptions.tsx 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import React, { Component, ReactElement } from 'react';
  2. import { IReduxState } from '../../app/types';
  3. /**
  4. * {@code AbstractCaptions} Properties.
  5. */
  6. export interface IAbstractCaptionsProps {
  7. /**
  8. * Whether local participant is requesting to see subtitles.
  9. */
  10. _requestingSubtitles: boolean;
  11. /**
  12. * Transcript texts formatted with participant's name and final content.
  13. * Mapped by id just to have the keys for convenience during the rendering
  14. * process.
  15. */
  16. _transcripts?: Map<string, string>;
  17. }
  18. /**
  19. * Abstract React {@code Component} which can display speech-to-text results
  20. * from Jigasi as subtitles.
  21. */
  22. export class AbstractCaptions<P extends IAbstractCaptionsProps> extends Component<P> {
  23. /**
  24. * Implements React's {@link Component#render()}.
  25. *
  26. * @inheritdoc
  27. * @returns {ReactElement}
  28. */
  29. render(): any {
  30. const { _requestingSubtitles, _transcripts } = this.props;
  31. if (!_requestingSubtitles || !_transcripts || !_transcripts.size) {
  32. return null;
  33. }
  34. const paragraphs = [];
  35. // @ts-ignore
  36. for (const [ id, text ] of _transcripts ?? []) {
  37. paragraphs.push(this._renderParagraph(id, text));
  38. }
  39. // @ts-ignore
  40. return this._renderSubtitlesContainer(paragraphs);
  41. }
  42. /**
  43. * Renders the transcription text.
  44. *
  45. * @abstract
  46. * @param {string} _id - The ID of the transcript message from which the
  47. * {@code text} has been created.
  48. * @param {string} _text - Subtitles text formatted with the participant's
  49. * name.
  50. * @protected
  51. * @returns {ReactElement} - The React element which displays the text.
  52. */
  53. _renderParagraph(_id: string, _text: string) {
  54. return <></>;
  55. }
  56. /**
  57. * Renders the subtitles container.
  58. *
  59. * @abstract
  60. * @param {Array<ReactElement>} _el - An array of elements created
  61. * for each subtitle using the {@link _renderParagraph} method.
  62. * @protected
  63. * @returns {ReactElement} - The subtitles container.
  64. */
  65. _renderSubtitlesContainer(_el: Array<ReactElement>) {
  66. return <></>;
  67. }
  68. }
  69. /**
  70. * Formats the transcript messages into text by prefixing participant's name to
  71. * avoid duplicating the effort on platform specific component.
  72. *
  73. * @param {Object} state - The redux state.
  74. * @private
  75. * @returns {Map<string, string>} - Formatted transcript subtitles mapped by
  76. * transcript message IDs.
  77. */
  78. function _constructTranscripts(state: IReduxState): Map<string, string> {
  79. const { _transcriptMessages } = state['features/subtitles'];
  80. const transcripts = new Map();
  81. for (const [ id, transcriptMessage ] of _transcriptMessages) {
  82. if (transcriptMessage) {
  83. let text = `${transcriptMessage.participantName}: `;
  84. if (transcriptMessage.final) {
  85. text += transcriptMessage.final;
  86. } else {
  87. const stable = transcriptMessage.stable || '';
  88. const unstable = transcriptMessage.unstable || '';
  89. text += stable + unstable;
  90. }
  91. transcripts.set(id, text);
  92. }
  93. }
  94. return transcripts;
  95. }
  96. /**
  97. * Maps the transcriptionSubtitles in the redux state to the associated props of
  98. * {@code AbstractCaptions}.
  99. *
  100. * @param {Object} state - The redux state.
  101. * @private
  102. * @returns {{
  103. * _requestingSubtitles: boolean,
  104. * _transcripts: Map<string, string>
  105. * }}
  106. */
  107. export function _abstractMapStateToProps(state: IReduxState) {
  108. const { _requestingSubtitles } = state['features/subtitles'];
  109. const transcripts = _constructTranscripts(state);
  110. return {
  111. _requestingSubtitles,
  112. // avoid re-renders by setting to prop new empty Map instances.
  113. _transcripts: transcripts.size === 0 ? undefined : transcripts
  114. };
  115. }