agora-appbuilder-core 4.1.9 → 4.1.11-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +1 -3
- package/template/agora-rn-uikit/src/Contexts/RtcContext.tsx +1 -2
- package/template/agora-rn-uikit/src/Reducer/index.ts +0 -2
- package/template/agora-rn-uikit/src/Rtc/Join.tsx +11 -25
- package/template/agora-rn-uikit/src/RtcConfigure.tsx +1 -14
- package/template/agora-rn-uikit/src/Utils/isBotUser.ts +1 -1
- package/template/android/app/build.gradle +0 -7
- package/template/bridge/rtm/web/Types.ts +0 -183
- package/template/bridge/rtm/web/index.ts +491 -423
- package/template/defaultConfig.js +3 -3
- package/template/ios/Podfile +0 -41
- package/template/package.json +5 -5
- package/template/src/assets/font-styles.css +4 -0
- package/template/src/assets/fonts/icomoon.ttf +0 -0
- package/template/src/assets/selection.json +1 -1
- package/template/src/atoms/ActionMenu.tsx +93 -13
- package/template/src/atoms/CustomIcon.tsx +1 -0
- package/template/src/atoms/DropDownMulti.tsx +80 -29
- package/template/src/atoms/Input.tsx +2 -1
- package/template/src/components/Controls.tsx +148 -143
- package/template/src/components/EventsConfigure.tsx +152 -97
- package/template/src/components/RTMConfigure.tsx +426 -644
- package/template/src/components/precall/joinCallBtn.native.tsx +7 -2
- package/template/src/components/precall/joinCallBtn.tsx +7 -2
- package/template/src/components/precall/joinWaitingRoomBtn.native.tsx +8 -3
- package/template/src/components/precall/joinWaitingRoomBtn.tsx +22 -4
- package/template/src/components/precall/textInput.tsx +45 -22
- package/template/src/components/precall/usePreCall.tsx +7 -0
- package/template/src/components/room-info/useRoomInfo.tsx +5 -0
- package/template/src/language/default-labels/videoCallScreenLabels.ts +27 -4
- package/template/src/pages/video-call/ActionSheetContent.tsx +77 -77
- package/template/src/pages/video-call/SidePanelHeader.tsx +81 -36
- package/template/src/rtm/RTMEngine.ts +33 -130
- package/template/src/rtm-events/constants.ts +6 -0
- package/template/src/rtm-events-api/Events.ts +30 -106
- package/template/src/subComponents/caption/Caption.tsx +48 -7
- package/template/src/subComponents/caption/CaptionContainer.tsx +324 -51
- package/template/src/subComponents/caption/CaptionIcon.tsx +35 -34
- package/template/src/subComponents/caption/CaptionText.tsx +103 -2
- package/template/src/subComponents/caption/LanguageSelectorPopup.tsx +179 -69
- package/template/src/subComponents/caption/Transcript.tsx +46 -11
- package/template/src/subComponents/caption/TranscriptIcon.tsx +27 -35
- package/template/src/subComponents/caption/TranscriptText.tsx +78 -3
- package/template/src/subComponents/caption/proto/ptoto.js +38 -4
- package/template/src/subComponents/caption/proto/test.proto +34 -19
- package/template/src/subComponents/caption/useCaption.tsx +753 -10
- package/template/src/subComponents/caption/useSTTAPI.tsx +118 -205
- package/template/src/subComponents/caption/useStreamMessageUtils.native.ts +152 -33
- package/template/src/subComponents/caption/useStreamMessageUtils.ts +165 -34
- package/template/src/subComponents/caption/utils.ts +171 -3
- package/template/src/utils/SdkEvents.ts +3 -0
- package/template/src/utils/useEndCall.ts +3 -5
- package/template/src/utils/useSpeechToText.ts +31 -20
- package/template/agora-rn-uikit/src/Reducer/Spotlight.ts +0 -11
- package/template/agora-rn-uikit/src/Reducer/UserBanned.ts +0 -11
- package/template/bridge/rtm/web/index-legacy.ts +0 -540
- package/template/src/components/RTMConfigure-legacy.tsx +0 -848
|
@@ -8,7 +8,11 @@ import {isWebInternal} from '../../utils/common';
|
|
|
8
8
|
import useStreamMessageUtils from './useStreamMessageUtils';
|
|
9
9
|
import hexadecimalTransparency from '../../utils/hexadecimalTransparency';
|
|
10
10
|
import {useString} from '../../utils/useString';
|
|
11
|
-
import {
|
|
11
|
+
import {useLocalUid} from '../../../agora-rn-uikit';
|
|
12
|
+
import {
|
|
13
|
+
sttSettingSpokenLanguageText,
|
|
14
|
+
sttSettingTranslationLanguageText,
|
|
15
|
+
} from '../../language/default-labels/videoCallScreenLabels';
|
|
12
16
|
|
|
13
17
|
export type WebStreamMessageArgs = [number, Uint8Array];
|
|
14
18
|
export type NativeStreamMessageArgs = [
|
|
@@ -33,13 +37,22 @@ const Caption: React.FC<CaptionProps> = ({
|
|
|
33
37
|
const {RtcEngineUnsafe} = useRtc();
|
|
34
38
|
const {
|
|
35
39
|
isLangChangeInProgress,
|
|
40
|
+
isTranslationChangeInProgress,
|
|
36
41
|
captionObj, //state for current live caption for all users
|
|
37
42
|
isSTTListenerAdded,
|
|
38
43
|
setIsSTTListenerAdded,
|
|
39
44
|
activeSpeakerRef,
|
|
40
45
|
prevSpeakerRef,
|
|
46
|
+
getBotOwnerUid,
|
|
47
|
+
isSTTActive,
|
|
48
|
+
translationConfig,
|
|
49
|
+
remoteSpokenLanguages,
|
|
41
50
|
} = useCaption();
|
|
51
|
+
const currentUserUid = useLocalUid();
|
|
42
52
|
const ssLabel = useString(sttSettingSpokenLanguageText)();
|
|
53
|
+
const stLabel = useString<boolean>(sttSettingTranslationLanguageText)(
|
|
54
|
+
isSTTActive,
|
|
55
|
+
);
|
|
43
56
|
const {streamMessageCallback} = useStreamMessageUtils();
|
|
44
57
|
const {defaultContent} = useContent();
|
|
45
58
|
|
|
@@ -66,18 +79,20 @@ const Caption: React.FC<CaptionProps> = ({
|
|
|
66
79
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
67
80
|
}, []);
|
|
68
81
|
|
|
69
|
-
if (isLangChangeInProgress)
|
|
82
|
+
if (isLangChangeInProgress || isTranslationChangeInProgress) {
|
|
70
83
|
return (
|
|
71
84
|
<Loading
|
|
72
|
-
text={
|
|
85
|
+
text={stLabel}
|
|
73
86
|
background="transparent"
|
|
74
87
|
indicatorColor={$config.FONT_COLOR + hexadecimalTransparency['70%']}
|
|
75
88
|
textColor={$config.FONT_COLOR + hexadecimalTransparency['70%']}
|
|
76
89
|
/>
|
|
77
90
|
);
|
|
91
|
+
}
|
|
78
92
|
|
|
79
|
-
console.log('
|
|
80
|
-
console.log('prev current uid ', prevSpeakerRef.current);
|
|
93
|
+
console.log('[STT_PER_USER_BOT] speaker uid', activeSpeakerRef.current);
|
|
94
|
+
console.log('[STT_PER_USER_BOT] prev current uid ', prevSpeakerRef.current);
|
|
95
|
+
console.log('[STT_PER_USER_BOT] captionObj ', captionObj);
|
|
81
96
|
|
|
82
97
|
const speakerCount = prevSpeakerRef.current === '' ? 1 : 2;
|
|
83
98
|
|
|
@@ -104,8 +119,12 @@ const Caption: React.FC<CaptionProps> = ({
|
|
|
104
119
|
{captionObj[prevSpeakerRef.current] &&
|
|
105
120
|
captionObj[prevSpeakerRef.current].text ? (
|
|
106
121
|
<CaptionText
|
|
107
|
-
user={
|
|
122
|
+
user={
|
|
123
|
+
defaultContent[getBotOwnerUid(prevSpeakerRef.current)]?.name ||
|
|
124
|
+
'Speaker'
|
|
125
|
+
}
|
|
108
126
|
value={captionObj[prevSpeakerRef.current].text}
|
|
127
|
+
translations={captionObj[prevSpeakerRef.current].translations}
|
|
109
128
|
activeSpeakersCount={speakerCount}
|
|
110
129
|
isActiveSpeaker={false}
|
|
111
130
|
activelinesAvailable={activelinesAvailable}
|
|
@@ -114,6 +133,15 @@ const Caption: React.FC<CaptionProps> = ({
|
|
|
114
133
|
setInActiveLinesAvaialble={setInActiveLinesAvaialble}
|
|
115
134
|
captionUserStyle={captionUserStyle}
|
|
116
135
|
captionTextStyle={captionTextStyle}
|
|
136
|
+
speakerUid={getBotOwnerUid(prevSpeakerRef.current)}
|
|
137
|
+
userLocalUid={currentUserUid}
|
|
138
|
+
spokenLanguageCode={
|
|
139
|
+
getBotOwnerUid(prevSpeakerRef.current) === currentUserUid
|
|
140
|
+
? translationConfig.source[0]
|
|
141
|
+
: remoteSpokenLanguages[
|
|
142
|
+
getBotOwnerUid(prevSpeakerRef.current)
|
|
143
|
+
]
|
|
144
|
+
}
|
|
117
145
|
/>
|
|
118
146
|
) : (
|
|
119
147
|
<></>
|
|
@@ -121,8 +149,12 @@ const Caption: React.FC<CaptionProps> = ({
|
|
|
121
149
|
{captionObj[activeSpeakerRef.current] &&
|
|
122
150
|
captionObj[activeSpeakerRef.current].text ? (
|
|
123
151
|
<CaptionText
|
|
124
|
-
user={
|
|
152
|
+
user={
|
|
153
|
+
defaultContent[getBotOwnerUid(activeSpeakerRef.current)]
|
|
154
|
+
?.name || 'Speaker'
|
|
155
|
+
}
|
|
125
156
|
value={captionObj[activeSpeakerRef.current].text}
|
|
157
|
+
translations={captionObj[activeSpeakerRef.current].translations}
|
|
126
158
|
activeSpeakersCount={speakerCount}
|
|
127
159
|
isActiveSpeaker={true}
|
|
128
160
|
activelinesAvailable={activelinesAvailable}
|
|
@@ -131,6 +163,15 @@ const Caption: React.FC<CaptionProps> = ({
|
|
|
131
163
|
setInActiveLinesAvaialble={setInActiveLinesAvaialble}
|
|
132
164
|
captionUserStyle={captionUserStyle}
|
|
133
165
|
captionTextStyle={captionTextStyle}
|
|
166
|
+
speakerUid={getBotOwnerUid(activeSpeakerRef.current)}
|
|
167
|
+
userLocalUid={currentUserUid}
|
|
168
|
+
spokenLanguageCode={
|
|
169
|
+
getBotOwnerUid(activeSpeakerRef.current) === currentUserUid
|
|
170
|
+
? translationConfig.source[0]
|
|
171
|
+
: remoteSpokenLanguages[
|
|
172
|
+
getBotOwnerUid(activeSpeakerRef.current)
|
|
173
|
+
]
|
|
174
|
+
}
|
|
134
175
|
/>
|
|
135
176
|
) : (
|
|
136
177
|
<></>
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import React from 'react';
|
|
10
10
|
|
|
11
11
|
import Caption from './Caption';
|
|
12
|
-
import {useCaption} from './useCaption';
|
|
12
|
+
import {useCaption, LanguageTranslationConfig} from './useCaption';
|
|
13
13
|
import ThemeConfig from '../../../src/theme';
|
|
14
14
|
import {
|
|
15
15
|
calculatePosition,
|
|
@@ -27,6 +27,8 @@ import LanguageSelectorPopup from './LanguageSelectorPopup';
|
|
|
27
27
|
import useSTTAPI from './useSTTAPI';
|
|
28
28
|
import useGetName from '../../utils/useGetName';
|
|
29
29
|
import {useRoomInfo} from 'customization-api';
|
|
30
|
+
import {useLocalUid} from '../../../agora-rn-uikit';
|
|
31
|
+
import {getLanguageLabel} from './utils';
|
|
30
32
|
import {
|
|
31
33
|
SIDE_PANEL_MAX_WIDTH,
|
|
32
34
|
SIDE_PANEL_GAP,
|
|
@@ -35,11 +37,13 @@ import {
|
|
|
35
37
|
MOBILE_CAPTION_CONTAINER_HEIGHT,
|
|
36
38
|
} from '../../../src/components/CommonStyles';
|
|
37
39
|
import useCaptionWidth from './useCaptionWidth';
|
|
38
|
-
import {LanguageType} from './utils';
|
|
40
|
+
import {LanguageType, langData, mergeTranslationConfigs} from './utils';
|
|
39
41
|
import hexadecimalTransparency from '../../utils/hexadecimalTransparency';
|
|
40
42
|
import {useString} from '../../utils/useString';
|
|
41
43
|
import {
|
|
42
44
|
sttChangeSpokenLanguageText,
|
|
45
|
+
sttOriginalTranslatedText,
|
|
46
|
+
sttStopTranslationText,
|
|
43
47
|
toolbarItemCaptionText,
|
|
44
48
|
} from '../../language/default-labels/videoCallScreenLabels';
|
|
45
49
|
import {logger, LogSource} from '../../logger/AppBuilderLogger';
|
|
@@ -56,8 +60,11 @@ const CaptionContainer: React.FC<CaptionContainerProps> = ({
|
|
|
56
60
|
captionTextStyle = {},
|
|
57
61
|
}) => {
|
|
58
62
|
const moreIconRef = React.useRef<View>(null);
|
|
63
|
+
const langSelectIconRef = React.useRef<View>(null);
|
|
59
64
|
const [actionMenuVisible, setActionMenuVisible] =
|
|
60
65
|
React.useState<boolean>(false);
|
|
66
|
+
const [langActionMenuVisible, setLangActionMenuVisible] =
|
|
67
|
+
React.useState<boolean>(false);
|
|
61
68
|
const [isHovered, setIsHovered] = React.useState<boolean>(false);
|
|
62
69
|
const isDesktop = useIsDesktop();
|
|
63
70
|
const isSmall = useIsSmall();
|
|
@@ -115,11 +122,23 @@ const CaptionContainer: React.FC<CaptionContainerProps> = ({
|
|
|
115
122
|
btnRef={moreIconRef}
|
|
116
123
|
/>
|
|
117
124
|
|
|
125
|
+
{/* <TranslateActionMenu
|
|
126
|
+
actionMenuVisible={langActionMenuVisible}
|
|
127
|
+
setActionMenuVisible={setLangActionMenuVisible}
|
|
128
|
+
btnRef={langSelectIconRef}
|
|
129
|
+
/> */}
|
|
130
|
+
|
|
118
131
|
{(isHovered || isMobileUA()) && !isLangChangeInProgress && (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
132
|
+
<>
|
|
133
|
+
{/* <LanguageSelectMenu
|
|
134
|
+
ref={langSelectIconRef}
|
|
135
|
+
setActionMenuVisible={setLangActionMenuVisible}
|
|
136
|
+
/> */}
|
|
137
|
+
<MoreMenu
|
|
138
|
+
ref={moreIconRef}
|
|
139
|
+
setActionMenuVisible={setActionMenuVisible}
|
|
140
|
+
/>
|
|
141
|
+
</>
|
|
123
142
|
)}
|
|
124
143
|
|
|
125
144
|
<Caption
|
|
@@ -199,6 +218,55 @@ const MoreMenu = React.forwardRef<View, MoreMenuProps>((props, ref) => {
|
|
|
199
218
|
);
|
|
200
219
|
});
|
|
201
220
|
|
|
221
|
+
const LanguageSelectMenu = React.forwardRef<View, MoreMenuProps>(
|
|
222
|
+
(props, ref) => {
|
|
223
|
+
const {setActionMenuVisible} = props;
|
|
224
|
+
const isMobile = isMobileUA();
|
|
225
|
+
return (
|
|
226
|
+
<View
|
|
227
|
+
ref={ref}
|
|
228
|
+
collapsable={false}
|
|
229
|
+
style={{
|
|
230
|
+
width: 32,
|
|
231
|
+
height: 32,
|
|
232
|
+
alignSelf: 'center',
|
|
233
|
+
justifyContent: 'center',
|
|
234
|
+
alignItems: 'center',
|
|
235
|
+
borderRadius: 20,
|
|
236
|
+
position: 'absolute',
|
|
237
|
+
right: isMobile ? 45 : 50,
|
|
238
|
+
top: isMobile ? 3 : 8,
|
|
239
|
+
zIndex: 999,
|
|
240
|
+
}}>
|
|
241
|
+
<IconButton
|
|
242
|
+
hoverEffect={true}
|
|
243
|
+
hoverEffectStyle={{
|
|
244
|
+
backgroundColor:
|
|
245
|
+
$config.CARD_LAYER_5_COLOR + hexadecimalTransparency['25%'],
|
|
246
|
+
borderRadius: 20,
|
|
247
|
+
}}
|
|
248
|
+
iconProps={{
|
|
249
|
+
iconType: 'plain',
|
|
250
|
+
name: 'lang-select',
|
|
251
|
+
iconSize: isMobile ? 18 : 20,
|
|
252
|
+
tintColor: $config.SECONDARY_ACTION_COLOR,
|
|
253
|
+
iconContainerStyle: {
|
|
254
|
+
padding: isMobile ? 6 : 8,
|
|
255
|
+
borderRadius: 20,
|
|
256
|
+
backgroundColor: isMobile
|
|
257
|
+
? $config.CARD_LAYER_5_COLOR + hexadecimalTransparency['25%']
|
|
258
|
+
: 'transparent',
|
|
259
|
+
},
|
|
260
|
+
}}
|
|
261
|
+
onPress={() => {
|
|
262
|
+
setActionMenuVisible(true);
|
|
263
|
+
}}
|
|
264
|
+
/>
|
|
265
|
+
</View>
|
|
266
|
+
);
|
|
267
|
+
},
|
|
268
|
+
);
|
|
269
|
+
|
|
202
270
|
interface CaptionsActionMenuProps {
|
|
203
271
|
actionMenuVisible: boolean;
|
|
204
272
|
setActionMenuVisible: (actionMenuVisible: boolean) => void;
|
|
@@ -209,9 +277,15 @@ const CaptionsActionMenu = (props: CaptionsActionMenuProps) => {
|
|
|
209
277
|
const {actionMenuVisible, setActionMenuVisible, btnRef} = props;
|
|
210
278
|
const {
|
|
211
279
|
setIsCaptionON,
|
|
212
|
-
language: prevLang,
|
|
280
|
+
// language: prevLang,
|
|
213
281
|
isLangChangeInProgress,
|
|
214
|
-
setLanguage,
|
|
282
|
+
// setLanguage,
|
|
283
|
+
// selectedTranslationLanguage,
|
|
284
|
+
updateSTTBotSession,
|
|
285
|
+
translationConfig,
|
|
286
|
+
handleTranslateConfigChange,
|
|
287
|
+
captionViewMode,
|
|
288
|
+
setCaptionViewMode,
|
|
215
289
|
} = useCaption();
|
|
216
290
|
const actionMenuitems: ActionMenuItem[] = [];
|
|
217
291
|
const [modalPosition, setModalPosition] = React.useState({});
|
|
@@ -219,32 +293,51 @@ const CaptionsActionMenu = (props: CaptionsActionMenuProps) => {
|
|
|
219
293
|
const {width: globalWidth, height: globalHeight} = useWindowDimensions();
|
|
220
294
|
const [isLanguagePopupOpen, setLanguagePopup] =
|
|
221
295
|
React.useState<boolean>(false);
|
|
222
|
-
const {restart} = useSTTAPI();
|
|
223
|
-
const username = useGetName();
|
|
224
|
-
const {
|
|
225
|
-
|
|
226
|
-
|
|
296
|
+
// const {restart} = useSTTAPI();
|
|
297
|
+
// const username = useGetName();
|
|
298
|
+
// const {
|
|
299
|
+
// data: {isHost},
|
|
300
|
+
// sttLanguage,
|
|
301
|
+
// } = useRoomInfo();
|
|
227
302
|
|
|
228
303
|
const changeSpokenLangLabel = useString<boolean>(
|
|
229
304
|
sttChangeSpokenLanguageText,
|
|
230
305
|
)();
|
|
306
|
+
const sttStopTranslationLabel = useString<boolean>(sttStopTranslationText)();
|
|
307
|
+
const sttOriginalTranslatedLabel = useString(sttOriginalTranslatedText)();
|
|
231
308
|
|
|
232
309
|
const hideCaptionLabel = useString<boolean>(toolbarItemCaptionText)(true);
|
|
233
310
|
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
311
|
+
// Anyone can start/stop stt
|
|
312
|
+
actionMenuitems.push({
|
|
313
|
+
icon: 'globe',
|
|
314
|
+
iconColor: $config.SECONDARY_ACTION_COLOR,
|
|
315
|
+
textColor: $config.FONT_COLOR,
|
|
316
|
+
title: changeSpokenLangLabel + ' ',
|
|
317
|
+
disabled: isLangChangeInProgress,
|
|
318
|
+
onPress: () => {
|
|
319
|
+
setActionMenuVisible(false);
|
|
320
|
+
setLanguagePopup(true);
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Stop Translation (not STT bot, pass empty targets)
|
|
325
|
+
actionMenuitems.push({
|
|
326
|
+
icon: 'lang-select',
|
|
327
|
+
iconColor: $config.SECONDARY_ACTION_COLOR,
|
|
328
|
+
textColor: $config.FONT_COLOR,
|
|
329
|
+
title: sttStopTranslationLabel,
|
|
330
|
+
disabled: isLangChangeInProgress,
|
|
331
|
+
onPress: async () => {
|
|
332
|
+
setActionMenuVisible(false);
|
|
333
|
+
await updateSTTBotSession({
|
|
334
|
+
source: translationConfig.source,
|
|
335
|
+
targets: [], // Empty targets = no translation
|
|
336
|
+
});
|
|
337
|
+
},
|
|
338
|
+
});
|
|
247
339
|
|
|
340
|
+
// Hide Caption Panel
|
|
248
341
|
actionMenuitems.push({
|
|
249
342
|
icon: 'captions-off',
|
|
250
343
|
iconColor: $config.SECONDARY_ACTION_COLOR,
|
|
@@ -256,32 +349,32 @@ const CaptionsActionMenu = (props: CaptionsActionMenuProps) => {
|
|
|
256
349
|
},
|
|
257
350
|
});
|
|
258
351
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
352
|
+
// View Mode Options
|
|
353
|
+
actionMenuitems.push({
|
|
354
|
+
icon: 'lang-translate',
|
|
355
|
+
iconColor: $config.SECONDARY_ACTION_COLOR,
|
|
356
|
+
endIcon:
|
|
357
|
+
captionViewMode === 'original-and-translated' ? 'tick-fill' : undefined,
|
|
358
|
+
endIconColor: $config.SEMANTIC_SUCCESS,
|
|
359
|
+
textColor: $config.FONT_COLOR,
|
|
360
|
+
title: sttOriginalTranslatedLabel,
|
|
361
|
+
onPress: () => {
|
|
362
|
+
setCaptionViewMode(
|
|
363
|
+
captionViewMode === 'translated'
|
|
364
|
+
? 'original-and-translated'
|
|
365
|
+
: 'translated',
|
|
266
366
|
);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
'STT',
|
|
279
|
-
'Error in restarting',
|
|
280
|
-
error,
|
|
281
|
-
);
|
|
282
|
-
// Handle the error case
|
|
283
|
-
});
|
|
284
|
-
}
|
|
367
|
+
setActionMenuVisible(false);
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
const onLanguageChange = async (
|
|
372
|
+
inputTranslateConfig: LanguageTranslationConfig,
|
|
373
|
+
) => {
|
|
374
|
+
setLanguagePopup(false);
|
|
375
|
+
try {
|
|
376
|
+
await handleTranslateConfigChange(inputTranslateConfig);
|
|
377
|
+
} catch (error) {}
|
|
285
378
|
};
|
|
286
379
|
|
|
287
380
|
React.useEffect(() => {
|
|
@@ -310,6 +403,7 @@ const CaptionsActionMenu = (props: CaptionsActionMenuProps) => {
|
|
|
310
403
|
);
|
|
311
404
|
}
|
|
312
405
|
}, [actionMenuVisible]);
|
|
406
|
+
|
|
313
407
|
return (
|
|
314
408
|
<>
|
|
315
409
|
<ActionMenu
|
|
@@ -328,6 +422,185 @@ const CaptionsActionMenu = (props: CaptionsActionMenuProps) => {
|
|
|
328
422
|
);
|
|
329
423
|
};
|
|
330
424
|
|
|
425
|
+
export interface TranslateActionMenuProps {
|
|
426
|
+
actionMenuVisible: boolean;
|
|
427
|
+
setActionMenuVisible: (actionMenuVisible: boolean) => void;
|
|
428
|
+
btnRef: React.RefObject<View>;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export const TranslateActionMenu = (props: TranslateActionMenuProps) => {
|
|
432
|
+
const {actionMenuVisible, setActionMenuVisible, btnRef} = props;
|
|
433
|
+
const [modalPosition, setModalPosition] = React.useState({});
|
|
434
|
+
const [isPosCalculated, setIsPosCalculated] = React.useState(false);
|
|
435
|
+
const {width: globalWidth, height: globalHeight} = useWindowDimensions();
|
|
436
|
+
const {
|
|
437
|
+
language: currentSpokenLanguages,
|
|
438
|
+
selectedTranslationLanguage,
|
|
439
|
+
setSelectedTranslationLanguage,
|
|
440
|
+
setMeetingTranscript,
|
|
441
|
+
translationConfig,
|
|
442
|
+
} = useCaption();
|
|
443
|
+
const {update} = useSTTAPI();
|
|
444
|
+
const localUid = useLocalUid();
|
|
445
|
+
const {sttLanguage} = useRoomInfo();
|
|
446
|
+
|
|
447
|
+
// Reset selected translation language if there are no targets configured
|
|
448
|
+
const targetLanguages = translationConfig?.targets || [];
|
|
449
|
+
React.useEffect(() => {
|
|
450
|
+
if (targetLanguages.length === 0 && selectedTranslationLanguage !== '') {
|
|
451
|
+
setSelectedTranslationLanguage('');
|
|
452
|
+
}
|
|
453
|
+
}, [
|
|
454
|
+
targetLanguages.length,
|
|
455
|
+
selectedTranslationLanguage,
|
|
456
|
+
setSelectedTranslationLanguage,
|
|
457
|
+
]);
|
|
458
|
+
|
|
459
|
+
const actionMenuitems: ActionMenuItem[] = [];
|
|
460
|
+
|
|
461
|
+
actionMenuitems.push({
|
|
462
|
+
iconColor: $config.SECONDARY_ACTION_COLOR,
|
|
463
|
+
textColor: $config.FONT_COLOR,
|
|
464
|
+
title: 'Add Another Translation',
|
|
465
|
+
iconPosition: 'end',
|
|
466
|
+
disabled: true,
|
|
467
|
+
onPress: () => {},
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
const handleTranslationToggle = (targetLanguage: string) => {
|
|
471
|
+
// Simply update the selected translation language locally
|
|
472
|
+
// No API call needed - we're just switching between already-configured target languages
|
|
473
|
+
// const prevTranslationLanguage = selectedTranslationLanguage;
|
|
474
|
+
setSelectedTranslationLanguage(targetLanguage);
|
|
475
|
+
|
|
476
|
+
// // Add translation language change notification to transcript
|
|
477
|
+
// const getLanguageName = (langCode: string) => {
|
|
478
|
+
// if (!langCode) return '';
|
|
479
|
+
// const lang = langData.find(data => data.value === langCode);
|
|
480
|
+
// return lang ? lang.label : langCode;
|
|
481
|
+
// };
|
|
482
|
+
|
|
483
|
+
// const actionText =
|
|
484
|
+
// targetLanguage === ''
|
|
485
|
+
// ? 'turned off translation'
|
|
486
|
+
// : prevTranslationLanguage === ''
|
|
487
|
+
// ? `set the translation language to "${getLanguageName(targetLanguage)}"`
|
|
488
|
+
// : `changed the translation language from "${getLanguageName(
|
|
489
|
+
// prevTranslationLanguage,
|
|
490
|
+
// )}" to "${getLanguageName(targetLanguage)}"`;
|
|
491
|
+
|
|
492
|
+
// setMeetingTranscript(prev => [
|
|
493
|
+
// ...prev,
|
|
494
|
+
// {
|
|
495
|
+
// name: 'translationUpdate',
|
|
496
|
+
// time: new Date().getTime(),
|
|
497
|
+
// uid: `translationUpdate-${localUid}`,
|
|
498
|
+
// text: actionText,
|
|
499
|
+
// },
|
|
500
|
+
// ]);
|
|
501
|
+
|
|
502
|
+
setActionMenuVisible(false);
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// Check if there are any target languages configured
|
|
506
|
+
if (targetLanguages.length === 0) {
|
|
507
|
+
// No target languages - show a disabled message
|
|
508
|
+
actionMenuitems.push({
|
|
509
|
+
icon: undefined,
|
|
510
|
+
iconColor: $config.FONT_COLOR,
|
|
511
|
+
textColor: $config.FONT_COLOR + hexadecimalTransparency['50%'],
|
|
512
|
+
title: 'No languages configured',
|
|
513
|
+
iconPosition: 'end',
|
|
514
|
+
disabled: true,
|
|
515
|
+
onPress: () => {},
|
|
516
|
+
});
|
|
517
|
+
} else {
|
|
518
|
+
// Show "Off" option and target languages
|
|
519
|
+
actionMenuitems.push({
|
|
520
|
+
icon: selectedTranslationLanguage === '' ? 'tick-fill' : undefined,
|
|
521
|
+
iconColor: $config.PRIMARY_ACTION_BRAND_COLOR,
|
|
522
|
+
textColor: $config.FONT_COLOR,
|
|
523
|
+
title: 'Off',
|
|
524
|
+
iconPosition: 'end',
|
|
525
|
+
onPress: () => handleTranslationToggle(''),
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
// Add selected translation language right after "Off" if one is selected
|
|
529
|
+
if (selectedTranslationLanguage && selectedTranslationLanguage !== '') {
|
|
530
|
+
const selectedLanguage = langData.find(
|
|
531
|
+
lang => lang.value === selectedTranslationLanguage,
|
|
532
|
+
);
|
|
533
|
+
if (selectedLanguage) {
|
|
534
|
+
actionMenuitems.push({
|
|
535
|
+
icon: 'tick-fill',
|
|
536
|
+
iconColor: $config.PRIMARY_ACTION_BRAND_COLOR,
|
|
537
|
+
textColor: $config.FONT_COLOR,
|
|
538
|
+
title: selectedLanguage.label,
|
|
539
|
+
iconPosition: 'end',
|
|
540
|
+
onPress: () => handleTranslationToggle(selectedLanguage.value),
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Add remaining Translation language options from translationConfig.targets (excluding the selected one)
|
|
546
|
+
targetLanguages.forEach(targetLangCode => {
|
|
547
|
+
if (targetLangCode !== selectedTranslationLanguage) {
|
|
548
|
+
const language = langData.find(lang => lang.value === targetLangCode);
|
|
549
|
+
if (language) {
|
|
550
|
+
actionMenuitems.push({
|
|
551
|
+
icon: undefined,
|
|
552
|
+
iconColor: $config.PRIMARY_ACTION_BRAND_COLOR,
|
|
553
|
+
textColor: $config.FONT_COLOR,
|
|
554
|
+
title: language.label,
|
|
555
|
+
iconPosition: 'end',
|
|
556
|
+
onPress: () => handleTranslationToggle(language.value),
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
React.useEffect(() => {
|
|
564
|
+
if (actionMenuVisible) {
|
|
565
|
+
btnRef?.current?.measure(
|
|
566
|
+
(
|
|
567
|
+
_fx: number,
|
|
568
|
+
_fy: number,
|
|
569
|
+
localWidth: number,
|
|
570
|
+
localHeight: number,
|
|
571
|
+
px: number,
|
|
572
|
+
py: number,
|
|
573
|
+
) => {
|
|
574
|
+
const data = calculatePosition({
|
|
575
|
+
px,
|
|
576
|
+
py,
|
|
577
|
+
localWidth,
|
|
578
|
+
localHeight,
|
|
579
|
+
globalHeight,
|
|
580
|
+
globalWidth,
|
|
581
|
+
});
|
|
582
|
+
setModalPosition(data);
|
|
583
|
+
setIsPosCalculated(true);
|
|
584
|
+
},
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
}, [actionMenuVisible]);
|
|
588
|
+
|
|
589
|
+
return (
|
|
590
|
+
<ActionMenu
|
|
591
|
+
from={'translation'}
|
|
592
|
+
actionMenuVisible={actionMenuVisible && isPosCalculated}
|
|
593
|
+
setActionMenuVisible={setActionMenuVisible}
|
|
594
|
+
modalPosition={modalPosition}
|
|
595
|
+
items={actionMenuitems}
|
|
596
|
+
containerStyle={{
|
|
597
|
+
maxHeight: Math.min(440, globalHeight * 0.6),
|
|
598
|
+
width: 220,
|
|
599
|
+
}}
|
|
600
|
+
/>
|
|
601
|
+
);
|
|
602
|
+
};
|
|
603
|
+
|
|
331
604
|
export default CaptionContainer;
|
|
332
605
|
|
|
333
606
|
const styles = StyleSheet.create({
|