diff --git a/lang/main.json b/lang/main.json index b9be2e6c6ad6..2e852358e1e4 100644 --- a/lang/main.json +++ b/lang/main.json @@ -1360,6 +1360,7 @@ "failedToStart": "Transcribing failed to start", "labelToolTip": "The meeting is being transcribed", "off": "Transcribing stopped", + "on": "Transcribing started", "pending": "Preparing to transcribe the meeting...", "sourceLanguageDesc": "Currently the meeting language is set to {{sourceLanguage}}.
You can change it from ", "sourceLanguageHere": "here", diff --git a/modules/API/API.js b/modules/API/API.js index 77a77c15d36f..c784369fff48 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -1975,6 +1975,19 @@ class API { }); } + /** + * Notify external application (if API is enabled) that transcribing has started or stopped. + * + * @param {boolean} on - True if transcribing is on, false otherwise. + * @returns {void} + */ + notifyTranscribingStatusChanged(on) { + this._sendEvent({ + name: 'transcribing-status-changed', + on + }); + } + /** * Notify external application (if API is enabled) that the user received * a transcription chunk. diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 002fc0742537..ce9807021837 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -160,6 +160,7 @@ const events = { 'suspend-detected': 'suspendDetected', 'tile-view-changed': 'tileViewChanged', 'toolbar-button-clicked': 'toolbarButtonClicked', + 'transcribing-status-changed': 'transcribingStatusChanged', 'transcription-chunk-received': 'transcriptionChunkReceived', 'whiteboard-status-changed': 'whiteboardStatusChanged' }; diff --git a/react/features/notifications/constants.ts b/react/features/notifications/constants.ts index 0d7a838fcf0c..996a601c2381 100644 --- a/react/features/notifications/constants.ts +++ b/react/features/notifications/constants.ts @@ -112,3 +112,10 @@ export const SILENT_JOIN_THRESHOLD = 30; * Amount of participants beyond which no left notification will be emitted. */ export const SILENT_LEFT_THRESHOLD = 30; + +/** + * The identifier for the transcriber notifications. + * + * @type {string} + */ +export const TRANSCRIBING_NOTIFICATION_ID = 'TRANSCRIBING_NOTIFICATION'; diff --git a/react/features/transcribing/actionTypes.ts b/react/features/transcribing/actionTypes.ts index df2346f441a5..f777d233670d 100644 --- a/react/features/transcribing/actionTypes.ts +++ b/react/features/transcribing/actionTypes.ts @@ -32,17 +32,3 @@ export const _TRANSCRIBER_LEFT = 'TRANSCRIBER_LEFT'; */ export const _POTENTIAL_TRANSCRIBER_JOINED = 'POTENTIAL_TRANSCRIBER_JOINED'; - -/** - * The type of Redux action which sets the pending transcribing notification UID - * to use it for when hiding the notification is necessary, or unsets it when - * undefined (or no param) is passed. - * - * { - * type: SET_PENDING_TRANSCRIBING_NOTIFICATION_UID, - * uid: ?number - * } - * @public - */ -export const SET_PENDING_TRANSCRIBING_NOTIFICATION_UID - = 'SET_PENDING_TRANSCRIBING_NOTIFICATION_UID'; diff --git a/react/features/transcribing/actions.ts b/react/features/transcribing/actions.ts index db4e8828e6a3..1569829bb285 100644 --- a/react/features/transcribing/actions.ts +++ b/react/features/transcribing/actions.ts @@ -1,9 +1,10 @@ -import { IStore } from '../app/types'; -import { hideNotification, showErrorNotification, showNotification } from '../notifications/actions'; -import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants'; +import { showErrorNotification, showNotification } from '../notifications/actions'; +import { + NOTIFICATION_TIMEOUT_TYPE, + TRANSCRIBING_NOTIFICATION_ID +} from '../notifications/constants'; import { - SET_PENDING_TRANSCRIBING_NOTIFICATION_UID, _POTENTIAL_TRANSCRIBER_JOINED, _TRANSCRIBER_JOINED, _TRANSCRIBER_LEFT @@ -61,54 +62,28 @@ export function potentialTranscriberJoined(participantId: string) { * Signals that the pending transcribing notification should be shown on the * screen. * - * @returns {Function} + * @returns {showNotification} */ export function showPendingTranscribingNotification() { - return async (dispatch: IStore['dispatch']) => { - const notification = await dispatch(showNotification({ - descriptionKey: 'transcribing.pending', - titleKey: 'dialog.transcribing' - }, NOTIFICATION_TIMEOUT_TYPE.LONG)); - - if (notification) { - dispatch(setPendingTranscribingNotificationUid(notification.uid)); - } - }; -} - -/** - * Sets UID of the the pending transcribing notification to use it when hiding - * the notification is necessary, or unsets it when undefined (or no param) is - * passed. - * - * @param {?number} uid - The UID of the notification. - * @returns {{ - * type: SET_PENDING_TRANSCRIBING_NOTIFICATION_UID, - * uid: number - * }} - */ -export function setPendingTranscribingNotificationUid(uid?: string) { - return { - type: SET_PENDING_TRANSCRIBING_NOTIFICATION_UID, - uid - }; + return showNotification({ + descriptionKey: 'transcribing.pending', + titleKey: 'dialog.transcribing', + uid: TRANSCRIBING_NOTIFICATION_ID + }, NOTIFICATION_TIMEOUT_TYPE.LONG); } /** - * Signals that the pending transcribing notification should be removed from the + * Signals that the started transcribing notification should be shown on the * screen. * - * @returns {Function} + * @returns {showNotification} */ -export function hidePendingTranscribingNotification() { - return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { - const { pendingNotificationUid } = getState()['features/transcribing']; - - if (pendingNotificationUid) { - dispatch(hideNotification(pendingNotificationUid)); - dispatch(setPendingTranscribingNotificationUid()); - } - }; +export function showStartedTranscribingNotification() { + return showNotification({ + descriptionKey: 'transcribing.on', + titleKey: 'dialog.transcribing', + uid: TRANSCRIBING_NOTIFICATION_ID + }, NOTIFICATION_TIMEOUT_TYPE.SHORT); } /** @@ -120,7 +95,8 @@ export function hidePendingTranscribingNotification() { export function showStoppedTranscribingNotification() { return showNotification({ descriptionKey: 'transcribing.off', - titleKey: 'dialog.transcribing' + titleKey: 'dialog.transcribing', + uid: TRANSCRIBING_NOTIFICATION_ID }, NOTIFICATION_TIMEOUT_TYPE.SHORT); } @@ -133,6 +109,7 @@ export function showStoppedTranscribingNotification() { export function showTranscribingError() { return showErrorNotification({ descriptionKey: 'transcribing.error', - titleKey: 'transcribing.failedToStart' + titleKey: 'transcribing.failedToStart', + uid: TRANSCRIBING_NOTIFICATION_ID }, NOTIFICATION_TIMEOUT_TYPE.LONG); } diff --git a/react/features/transcribing/middleware.ts b/react/features/transcribing/middleware.ts index 0122afa20123..1638b8253745 100644 --- a/react/features/transcribing/middleware.ts +++ b/react/features/transcribing/middleware.ts @@ -1,11 +1,10 @@ -import { batch } from 'react-redux'; - import { HIDDEN_PARTICIPANT_JOINED, HIDDEN_PARTICIPANT_LEFT, PARTICIPANT_UPDATED } from '../base/participants/actionTypes'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; +import { SET_REQUESTING_SUBTITLES } from '../subtitles/actionTypes'; import { toggleRequestingSubtitles } from '../subtitles/actions.any'; import { @@ -13,8 +12,9 @@ import { _TRANSCRIBER_LEFT } from './actionTypes'; import { - hidePendingTranscribingNotification, potentialTranscriberJoined, + showPendingTranscribingNotification, + showStartedTranscribingNotification, showStoppedTranscribingNotification, transcriberJoined, transcriberLeft @@ -29,62 +29,82 @@ const TRANSCRIBER_DISPLAY_NAME = 'Transcriber'; * @returns {Function} */ // eslint-disable-next-line no-unused-vars -MiddlewareRegistry.register(store => next => action => { +MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { const { + isTranscribing, transcriberJID, potentialTranscriberJIDs - } = store.getState()['features/transcribing']; + } = getState()['features/transcribing']; switch (action.type) { + case _TRANSCRIBER_JOINED: { + notifyTranscribingStatusChanged(true); + dispatch(showStartedTranscribingNotification()); + + const state = getState(); + const { transcription } = state['features/base/config']; + const { _requestingSubtitles } = state['features/subtitles']; + + if (!_requestingSubtitles && !transcription?.disableStartForAll) { + dispatch(toggleRequestingSubtitles()); + } + break; + } case _TRANSCRIBER_LEFT: { - store.dispatch(showStoppedTranscribingNotification()); - const state = store.getState(); + notifyTranscribingStatusChanged(false); + dispatch(showStoppedTranscribingNotification()); + + const state = getState(); const { transcription } = state['features/base/config']; const { _requestingSubtitles } = state['features/subtitles']; if (_requestingSubtitles && !transcription?.disableStartForAll) { - store.dispatch(toggleRequestingSubtitles()); + dispatch(toggleRequestingSubtitles()); } break; } case HIDDEN_PARTICIPANT_JOINED: - if (action.displayName - && action.displayName === TRANSCRIBER_DISPLAY_NAME) { - store.dispatch(transcriberJoined(action.id)); + if (action.displayName === TRANSCRIBER_DISPLAY_NAME) { + dispatch(transcriberJoined(action.id)); } else { - store.dispatch(potentialTranscriberJoined(action.id)); + dispatch(potentialTranscriberJoined(action.id)); } break; case HIDDEN_PARTICIPANT_LEFT: if (action.id === transcriberJID) { - store.dispatch(transcriberLeft(action.id)); + dispatch(transcriberLeft(action.id)); } break; case PARTICIPANT_UPDATED: { const { participant } = action; - if (potentialTranscriberJIDs.includes(participant.id) - && participant.name === TRANSCRIBER_DISPLAY_NAME) { - batch(() => { - store.dispatch(transcriberJoined(participant.id)); - store.dispatch(hidePendingTranscribingNotification()); - }); + if (potentialTranscriberJIDs.includes(participant.id) && participant.name === TRANSCRIBER_DISPLAY_NAME) { + dispatch(transcriberJoined(participant.id)); } break; } - case _TRANSCRIBER_JOINED: { - const state = store.getState(); - const { transcription } = state['features/base/config']; - const { _requestingSubtitles } = state['features/subtitles']; - - if (!_requestingSubtitles && !transcription?.disableStartForAll) { - store.dispatch(toggleRequestingSubtitles()); + case SET_REQUESTING_SUBTITLES: + if (action.enabled && !isTranscribing) { + dispatch(showPendingTranscribingNotification()); } + break; - } + } return next(action); }); + +/** + * Notify external application (if API is enabled) that transcribing has started or stopped. + * + * @param {boolean} on - True if transcribing is on, false otherwise. + * @returns {void} + */ +function notifyTranscribingStatusChanged(on: boolean) { + if (typeof APP !== 'undefined') { + APP.API.notifyTranscribingStatusChanged(on); + } +} diff --git a/react/features/transcribing/reducer.ts b/react/features/transcribing/reducer.ts index e619c9946454..c219590b6375 100644 --- a/react/features/transcribing/reducer.ts +++ b/react/features/transcribing/reducer.ts @@ -1,7 +1,6 @@ import ReducerRegistry from '../base/redux/ReducerRegistry'; import { - SET_PENDING_TRANSCRIBING_NOTIFICATION_UID, _POTENTIAL_TRANSCRIBER_JOINED, _TRANSCRIBER_JOINED, _TRANSCRIBER_LEFT @@ -12,7 +11,6 @@ import { * * @returns {{ * isTranscribing: boolean, - * isDialing: boolean, * transcriberJID: null, * potentialTranscriberJIDs: Array * }} @@ -28,20 +26,6 @@ function _getInitialState() { */ isTranscribing: false, - /** - * Indicates whether the transcriber has been dialed into the room and - * we're currently awaiting successful joining or failure of joining. - * - * @type {boolean} - */ - isDialing: false, - - /** - * Indicates whether the transcribing feature is in the process of - * terminating; the transcriber has been told to leave. - */ - isTerminating: false, - /** * The JID of the active transcriber. * @@ -59,10 +43,7 @@ function _getInitialState() { } export interface ITranscribingState { - isDialing: boolean; - isTerminating: boolean; isTranscribing: boolean; - pendingNotificationUid?: string; potentialTranscriberJIDs: string[]; transcriberJID?: string | null; } @@ -77,13 +58,11 @@ ReducerRegistry.register('features/transcribing', return { ...state, isTranscribing: true, - isDialing: false, transcriberJID: action.transcriberJID }; case _TRANSCRIBER_LEFT: return { ...state, - isTerminating: false, isTranscribing: false, transcriberJID: undefined, potentialTranscriberJIDs: [] @@ -91,14 +70,7 @@ ReducerRegistry.register('features/transcribing', case _POTENTIAL_TRANSCRIBER_JOINED: return { ...state, - potentialTranscriberJIDs: - [ action.transcriberJID ] - .concat(state.potentialTranscriberJIDs) - }; - case SET_PENDING_TRANSCRIBING_NOTIFICATION_UID: - return { - ...state, - pendingNotificationUid: action.uid + potentialTranscriberJIDs: [ action.transcriberJID, ...state.potentialTranscriberJIDs ] }; default: return state;