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;