agora-appbuilder-core 4.1.10-beta.1 → 4.1.11
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/Utils/isBotUser.ts +1 -1
- package/template/android/app/build.gradle +0 -7
- package/template/bridge/rtc/webNg/RtcEngine.ts +2 -2
- package/template/bridge/rtm/web/Types.ts +0 -183
- package/template/bridge/rtm/web/index.ts +488 -450
- package/template/customization-api/typeDefinition.ts +0 -1
- package/template/defaultConfig.js +3 -4
- package/template/global.d.ts +0 -1
- package/template/ios/Podfile +0 -41
- package/template/package.json +5 -5
- package/template/src/AppRoutes.tsx +3 -3
- package/template/src/ai-agent/components/ControlButtons.tsx +1 -1
- package/template/src/assets/font-styles.css +1 -33
- 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 -8
- package/template/src/atoms/DropDownMulti.tsx +80 -29
- package/template/src/atoms/Dropdown.tsx +0 -5
- package/template/src/atoms/Input.tsx +2 -1
- package/template/src/atoms/TertiaryButton.tsx +1 -1
- package/template/src/atoms/UserAvatar.tsx +1 -1
- package/template/src/components/ChatContext.ts +3 -5
- package/template/src/components/Controls.tsx +167 -208
- package/template/src/components/DeviceConfigure.tsx +1 -1
- package/template/src/components/EventsConfigure.tsx +168 -118
- package/template/src/components/Navbar.tsx +11 -14
- package/template/src/components/RTMConfigure.tsx +819 -32
- package/template/src/components/beauty-effect/useBeautyEffects.tsx +13 -50
- package/template/src/components/chat/chatConfigure.tsx +1 -7
- package/template/src/components/chat-messages/useChatMessages.tsx +11 -43
- package/template/src/components/controls/useControlPermissionMatrix.tsx +4 -32
- package/template/src/components/participants/AllHostParticipants.tsx +2 -10
- package/template/src/components/participants/Participant.tsx +1 -7
- package/template/src/components/participants/UserActionMenuOptions.tsx +2 -12
- 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 +16 -15
- package/template/src/components/precall/joinWaitingRoomBtn.tsx +31 -17
- package/template/src/components/precall/textInput.tsx +45 -22
- package/template/src/components/precall/usePreCall.tsx +7 -0
- package/template/src/components/recordings/RecordingsDateTable.tsx +2 -3
- package/template/src/components/room-info/useRoomInfo.tsx +5 -0
- package/template/src/components/useUserPreference.tsx +12 -39
- package/template/src/components/virtual-background/useVB.tsx +0 -18
- package/template/src/components/whiteboard/WhiteboardConfigure.tsx +0 -27
- package/template/src/language/default-labels/videoCallScreenLabels.ts +27 -11
- package/template/src/logger/AppBuilderLogger.tsx +3 -11
- package/template/src/pages/VideoCall.tsx +518 -171
- package/template/src/pages/video-call/ActionSheetContent.tsx +77 -77
- package/template/src/pages/video-call/SidePanelHeader.tsx +81 -53
- package/template/src/pages/video-call/VideoCallScreen.tsx +0 -18
- package/template/src/pages/video-call/VideoCallScreenWrapper.tsx +1 -0
- package/template/src/rtm/RTMEngine.ts +37 -262
- package/template/src/rtm/utils.ts +1 -68
- package/template/src/rtm-events/constants.ts +7 -40
- package/template/src/rtm-events-api/Events.ts +39 -158
- package/template/src/subComponents/ChatBubble.tsx +3 -3
- package/template/src/subComponents/ChatContainer.tsx +9 -19
- package/template/src/subComponents/LocalAudioMute.tsx +2 -2
- package/template/src/subComponents/LocalVideoMute.tsx +2 -2
- package/template/src/subComponents/SidePanelEnum.tsx +0 -1
- 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 +754 -11
- 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/subComponents/chat/ChatSendButton.tsx +0 -1
- package/template/src/subComponents/screenshare/ScreenshareButton.tsx +0 -16
- package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +1 -1
- package/template/src/subComponents/waiting-rooms/WaitingRoomControls.tsx +4 -7
- package/template/src/utils/SdkEvents.ts +3 -0
- package/template/src/utils/useEndCall.ts +4 -4
- package/template/src/utils/useMuteToggleLocal.ts +10 -14
- package/template/src/utils/useSpeechToText.ts +31 -20
- package/template/bridge/rtm/web/index-legacy.ts +0 -540
- package/template/src/components/RTMConfigure-legacy.tsx +0 -848
- package/template/src/components/UserGlobalPreferenceProvider.tsx +0 -227
- package/template/src/components/breakout-room/BreakoutRoomPanel.tsx +0 -58
- package/template/src/components/breakout-room/context/BreakoutRoomContext.tsx +0 -2508
- package/template/src/components/breakout-room/events/BreakoutRoomEventsConfigure.tsx +0 -272
- package/template/src/components/breakout-room/events/constants.ts +0 -17
- package/template/src/components/breakout-room/hoc/BreakoutRoomNameRenderer.tsx +0 -68
- package/template/src/components/breakout-room/hooks/useBreakoutRoomExit.ts +0 -49
- package/template/src/components/breakout-room/state/reducer.ts +0 -522
- package/template/src/components/breakout-room/state/types.ts +0 -54
- package/template/src/components/breakout-room/ui/BreakoutMeetingTitle.tsx +0 -60
- package/template/src/components/breakout-room/ui/BreakoutRoomActionMenu.tsx +0 -136
- package/template/src/components/breakout-room/ui/BreakoutRoomAnnouncementModal.tsx +0 -135
- package/template/src/components/breakout-room/ui/BreakoutRoomGroupSettings.tsx +0 -588
- package/template/src/components/breakout-room/ui/BreakoutRoomMainRoomUsers.tsx +0 -142
- package/template/src/components/breakout-room/ui/BreakoutRoomMemberActionMenu.tsx +0 -122
- package/template/src/components/breakout-room/ui/BreakoutRoomParticipants.tsx +0 -124
- package/template/src/components/breakout-room/ui/BreakoutRoomRaiseHand.tsx +0 -65
- package/template/src/components/breakout-room/ui/BreakoutRoomRenameModal.tsx +0 -227
- package/template/src/components/breakout-room/ui/BreakoutRoomSettings.tsx +0 -140
- package/template/src/components/breakout-room/ui/BreakoutRoomTransition.tsx +0 -52
- package/template/src/components/breakout-room/ui/BreakoutRoomView.tsx +0 -193
- package/template/src/components/breakout-room/ui/ExitBreakoutRoomIconButton.tsx +0 -79
- package/template/src/components/breakout-room/ui/ParticipantManualAssignmentModal.tsx +0 -638
- package/template/src/components/breakout-room/ui/SelectParticipantAssignmentStrategy.tsx +0 -57
- package/template/src/components/common/Dividers.tsx +0 -53
- package/template/src/components/controls/toolbar-items/ExitBreakoutRoomToolbarItem.tsx +0 -13
- package/template/src/components/raise-hand/RaiseHandButton.tsx +0 -50
- package/template/src/components/raise-hand/RaiseHandProvider.tsx +0 -308
- package/template/src/components/raise-hand/index.ts +0 -14
- package/template/src/components/room-info/useCurrentRoomInfo.tsx +0 -42
- package/template/src/components/room-info/useSetBreakoutRoomInfo.tsx +0 -64
- package/template/src/pages/video-call/BreakoutVideoCall.tsx +0 -213
- package/template/src/pages/video-call/VideoCallContent.tsx +0 -211
- package/template/src/pages/video-call/VideoCallStateWrapper.tsx +0 -495
- package/template/src/rtm/RTMConfigureBreakoutRoomProvider.tsx +0 -882
- package/template/src/rtm/RTMConfigureMainRoomProvider.tsx +0 -757
- package/template/src/rtm/RTMCoreProvider.tsx +0 -419
- package/template/src/rtm/RTMGlobalStateProvider.tsx +0 -706
- package/template/src/rtm/RTMStatusBanner.tsx +0 -99
- package/template/src/rtm/constants.ts +0 -12
- package/template/src/rtm/hooks/useMainRoomUserDisplayName.ts +0 -45
- package/template/src/rtm/rtm-presence-utils.ts +0 -344
- package/template/src/subComponents/chat/ChatAnnouncementView.tsx +0 -65
- package/template/src/utils/useDebouncedCallback.tsx +0 -20
|
@@ -8,12 +8,21 @@ import {
|
|
|
8
8
|
import React from 'react';
|
|
9
9
|
|
|
10
10
|
import ThemeConfig from '../../../src/theme';
|
|
11
|
+
import {useCaption} from './useCaption';
|
|
11
12
|
import hexadecimalTransparency from '../../../src/utils/hexadecimalTransparency';
|
|
12
13
|
import {isAndroid, isMobileUA} from '../../utils/common';
|
|
14
|
+
import {getUserTranslatedText, getLanguageLabel, LanguageType} from './utils';
|
|
15
|
+
|
|
16
|
+
type TranslationItem = {
|
|
17
|
+
lang: string;
|
|
18
|
+
text: string;
|
|
19
|
+
isFinal: boolean;
|
|
20
|
+
};
|
|
13
21
|
|
|
14
22
|
interface CaptionTextProps {
|
|
15
23
|
user: string;
|
|
16
24
|
value: string;
|
|
25
|
+
translations?: TranslationItem[];
|
|
17
26
|
activeSpeakersCount: number;
|
|
18
27
|
isActiveSpeaker?: boolean;
|
|
19
28
|
activelinesAvailable?: number;
|
|
@@ -22,6 +31,9 @@ interface CaptionTextProps {
|
|
|
22
31
|
setInActiveLinesAvaialble?: React.Dispatch<React.SetStateAction<number>>;
|
|
23
32
|
captionUserStyle?: TextStyle;
|
|
24
33
|
captionTextStyle?: TextStyle;
|
|
34
|
+
speakerUid?: string | number;
|
|
35
|
+
userLocalUid?: string | number;
|
|
36
|
+
spokenLanguageCode?: LanguageType;
|
|
25
37
|
}
|
|
26
38
|
|
|
27
39
|
const DESKTOP_LINE_HEIGHT = 28;
|
|
@@ -31,6 +43,7 @@ const MAX_CAPTIONS_LINES_ALLOWED = 3;
|
|
|
31
43
|
const CaptionText = ({
|
|
32
44
|
user,
|
|
33
45
|
value,
|
|
46
|
+
translations = [],
|
|
34
47
|
activeSpeakersCount,
|
|
35
48
|
isActiveSpeaker = false,
|
|
36
49
|
activelinesAvailable,
|
|
@@ -39,8 +52,12 @@ const CaptionText = ({
|
|
|
39
52
|
setInActiveLinesAvaialble,
|
|
40
53
|
captionUserStyle = {},
|
|
41
54
|
captionTextStyle = {},
|
|
55
|
+
speakerUid,
|
|
56
|
+
userLocalUid,
|
|
57
|
+
spokenLanguageCode,
|
|
42
58
|
}: CaptionTextProps) => {
|
|
43
59
|
const isMobile = isMobileUA();
|
|
60
|
+
const {translationConfig, captionViewMode} = useCaption();
|
|
44
61
|
|
|
45
62
|
const LINE_HEIGHT = isMobile ? MOBILE_LINE_HEIGHT : DESKTOP_LINE_HEIGHT;
|
|
46
63
|
|
|
@@ -82,6 +99,63 @@ const CaptionText = ({
|
|
|
82
99
|
*
|
|
83
100
|
*/
|
|
84
101
|
|
|
102
|
+
// Get the appropriate source text for display based on viewer's language preferences
|
|
103
|
+
const viewerSourceLanguage = translationConfig.source[0];
|
|
104
|
+
// const localUserText = value;
|
|
105
|
+
// const remoteUserTranslatedText: {
|
|
106
|
+
// text: string,
|
|
107
|
+
// langcode: LanguageType
|
|
108
|
+
// } = () => {
|
|
109
|
+
// const matchingTranslation = translations.find(
|
|
110
|
+
// t => t.lang === viewerSourceLanguage,
|
|
111
|
+
// );
|
|
112
|
+
// if (matchingTranslation?.text) {
|
|
113
|
+
// return matchingTranslation.text;
|
|
114
|
+
// }
|
|
115
|
+
// return value;
|
|
116
|
+
// };
|
|
117
|
+
|
|
118
|
+
const displayTranslatedViewText = getUserTranslatedText(
|
|
119
|
+
value,
|
|
120
|
+
translations,
|
|
121
|
+
viewerSourceLanguage,
|
|
122
|
+
speakerUid,
|
|
123
|
+
userLocalUid,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* ROBUST TEXT EXTRACTION LOGIC
|
|
128
|
+
* Problem: value and translationText contain FULL accumulated text (can be 1000+ chars)
|
|
129
|
+
* Solution: Extract only the latest portion that fits in allocated lines
|
|
130
|
+
* - With translation: 2 lines source (~100-120 chars) + 1 line translation (~50-75 chars)
|
|
131
|
+
* - Without translation: 3 lines source (~150-180 chars)
|
|
132
|
+
*/
|
|
133
|
+
const getLatestTextPortion = (text: string, maxChars: number) => {
|
|
134
|
+
if (!text || text.length <= maxChars) return text;
|
|
135
|
+
|
|
136
|
+
// Take last maxChars, try to find sentence boundary for cleaner cut
|
|
137
|
+
const portion = text.slice(-maxChars);
|
|
138
|
+
const sentenceMatch = portion.match(/[.!?]\s+/);
|
|
139
|
+
|
|
140
|
+
// If we find a sentence boundary after position 10, start from there
|
|
141
|
+
if (sentenceMatch && sentenceMatch.index > 10) {
|
|
142
|
+
return portion.slice(sentenceMatch.index + sentenceMatch[0].length);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Otherwise just return the last maxChars
|
|
146
|
+
return portion;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Adjust char limits based on mobile vs desktop (mobile has smaller font)
|
|
150
|
+
const sourceCharLimit =
|
|
151
|
+
captionViewMode === 'original-and-translated'
|
|
152
|
+
? isMobile
|
|
153
|
+
? 50
|
|
154
|
+
: 70 // 1 line for source when showing original + translation below
|
|
155
|
+
: isMobile
|
|
156
|
+
? 150
|
|
157
|
+
: 180; // 3 lines for source in translated mode (uses full space)
|
|
158
|
+
|
|
85
159
|
return (
|
|
86
160
|
<View
|
|
87
161
|
style={[
|
|
@@ -125,17 +199,36 @@ const CaptionText = ({
|
|
|
125
199
|
)) * LINE_HEIGHT,
|
|
126
200
|
},
|
|
127
201
|
]}>
|
|
202
|
+
{/* Combined source and translation text */}
|
|
128
203
|
<Text
|
|
129
204
|
onLayout={handleTextLayout}
|
|
130
205
|
style={[
|
|
131
206
|
styles.captionText,
|
|
207
|
+
styles.transcriptionText,
|
|
132
208
|
isMobile
|
|
133
209
|
? styles.mobileCaptionFontSize
|
|
134
210
|
: styles.desktopCaptionFontSize,
|
|
135
211
|
isAndroid() && {lineHeight: MOBILE_LINE_HEIGHT - 2},
|
|
136
212
|
captionTextStyle,
|
|
137
213
|
]}>
|
|
138
|
-
{
|
|
214
|
+
{/* Default view when view mode is : translated */}
|
|
215
|
+
<Text style={styles.languageLabel}>
|
|
216
|
+
({displayTranslatedViewText.langCode}
|
|
217
|
+
):{' '}
|
|
218
|
+
</Text>
|
|
219
|
+
{getLatestTextPortion(
|
|
220
|
+
displayTranslatedViewText.value,
|
|
221
|
+
sourceCharLimit,
|
|
222
|
+
)}
|
|
223
|
+
{/* View mode when "Original and Translated" is selected - show original for remote users only */}
|
|
224
|
+
{speakerUid !== userLocalUid &&
|
|
225
|
+
captionViewMode === 'original-and-translated' && (
|
|
226
|
+
<>
|
|
227
|
+
{'\n'}
|
|
228
|
+
<Text style={styles.languageLabel}>(Original): </Text>
|
|
229
|
+
{getLatestTextPortion(value, sourceCharLimit)}
|
|
230
|
+
</>
|
|
231
|
+
)}
|
|
139
232
|
</Text>
|
|
140
233
|
</View>
|
|
141
234
|
</View>
|
|
@@ -155,8 +248,8 @@ const styles = StyleSheet.create({
|
|
|
155
248
|
},
|
|
156
249
|
|
|
157
250
|
captionTextContainerStyle: {
|
|
158
|
-
overflow: 'hidden',
|
|
159
251
|
width: '100%',
|
|
252
|
+
overflow: 'hidden',
|
|
160
253
|
position: 'relative',
|
|
161
254
|
},
|
|
162
255
|
|
|
@@ -168,6 +261,14 @@ const styles = StyleSheet.create({
|
|
|
168
261
|
bottom: 0,
|
|
169
262
|
},
|
|
170
263
|
|
|
264
|
+
transcriptionText: {
|
|
265
|
+
marginBottom: 2,
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
languageLabel: {
|
|
269
|
+
color: $config.FONT_COLOR + ThemeConfig.EmphasisPlus.low,
|
|
270
|
+
},
|
|
271
|
+
|
|
171
272
|
captionUserName: {
|
|
172
273
|
fontWeight: '600',
|
|
173
274
|
fontFamily: ThemeConfig.FontFamily.sansPro,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {SetStateAction
|
|
1
|
+
import React, {SetStateAction} from 'react';
|
|
2
2
|
import {StyleSheet, Text, View} from 'react-native';
|
|
3
3
|
import Spacer from '../../atoms/Spacer';
|
|
4
4
|
import Popup from '../../atoms/Popup';
|
|
@@ -6,50 +6,124 @@ import TertiaryButton from '../../atoms/TertiaryButton';
|
|
|
6
6
|
import PrimaryButton from '../../atoms/PrimaryButton';
|
|
7
7
|
import ThemeConfig from '../../theme';
|
|
8
8
|
import {useIsDesktop} from '../../utils/common';
|
|
9
|
-
import {useCaption} from './useCaption';
|
|
9
|
+
import {LanguageTranslationConfig, useCaption} from './useCaption';
|
|
10
|
+
import Dropdown from '../../atoms/Dropdown';
|
|
10
11
|
import DropdownMulti from '../../atoms/DropDownMulti';
|
|
11
12
|
import hexadecimalTransparency from '../../utils/hexadecimalTransparency';
|
|
12
13
|
import Loading from '../Loading';
|
|
13
|
-
import {LanguageType} from './utils';
|
|
14
|
+
import {LanguageType, langData, hasConfigChanged} from './utils';
|
|
14
15
|
import {useString} from '../../utils/useString';
|
|
16
|
+
import {useLocalUid} from '../../../agora-rn-uikit';
|
|
17
|
+
// import {useRoomInfo} from '../../components/room-info/useRoomInfo';
|
|
15
18
|
import {
|
|
16
|
-
sttChangeLanguagePopupDropdownError,
|
|
17
|
-
sttChangeLanguagePopupDropdownInfo,
|
|
18
19
|
sttChangeLanguagePopupHeading,
|
|
19
20
|
sttChangeLanguagePopupPrimaryBtnText,
|
|
20
|
-
sttChangeLanguagePopupSubHeading,
|
|
21
21
|
sttLanguageChangeInProgress,
|
|
22
|
+
sttChangeLanguagePopupDropdownInfo,
|
|
22
23
|
} from '../../language/default-labels/videoCallScreenLabels';
|
|
23
24
|
import {cancelText} from '../../language/default-labels/commonLabels';
|
|
24
25
|
|
|
25
26
|
interface LanguageSelectorPopup {
|
|
26
27
|
modalVisible: boolean;
|
|
27
28
|
setModalVisible: React.Dispatch<SetStateAction<boolean>>;
|
|
28
|
-
onConfirm: (
|
|
29
|
-
isFirstTimePopupOpen?: boolean;
|
|
29
|
+
onConfirm: (inputTranslationConfig: LanguageTranslationConfig) => void;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const LanguageSelectorPopup = (props: LanguageSelectorPopup) => {
|
|
33
|
-
const {isFirstTimePopupOpen = false} = props;
|
|
34
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
|
35
33
|
const isDesktop = useIsDesktop()('popup');
|
|
36
34
|
const heading = useString<boolean>(sttChangeLanguagePopupHeading);
|
|
37
|
-
const subHeading = useString(sttChangeLanguagePopupSubHeading)();
|
|
38
35
|
const cancelBtnLabel = useString(cancelText)();
|
|
39
36
|
const ConfirmBtnLabel = useString(sttChangeLanguagePopupPrimaryBtnText)();
|
|
40
|
-
const ddError = useString(sttChangeLanguagePopupDropdownError)();
|
|
41
|
-
const ddInfo = useString(sttChangeLanguagePopupDropdownInfo)();
|
|
42
37
|
const languageChangeInProgress = useString(sttLanguageChangeInProgress)();
|
|
43
|
-
const
|
|
44
|
-
useCaption();
|
|
38
|
+
const maxLangValInfo = useString(sttChangeLanguagePopupDropdownInfo)();
|
|
45
39
|
|
|
40
|
+
const {
|
|
41
|
+
translationConfig,
|
|
42
|
+
isLangChangeInProgress,
|
|
43
|
+
isSTTActive,
|
|
44
|
+
remoteSpokenLanguages,
|
|
45
|
+
} = useCaption();
|
|
46
|
+
const localUid = useLocalUid();
|
|
47
|
+
console.log(
|
|
48
|
+
'[STT_PER_USER_BOT] remoteSpokenLanguages',
|
|
49
|
+
remoteSpokenLanguages,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// const {sttLanguage} = useRoomInfo();
|
|
46
53
|
const [error, setError] = React.useState<boolean>(false);
|
|
47
|
-
const [
|
|
48
|
-
|
|
54
|
+
const [isTargetOpen, setIsTargetOpen] = React.useState(false);
|
|
55
|
+
|
|
56
|
+
const [inputTranslationConfig, setInputTranslationConfig] =
|
|
57
|
+
React.useState<LanguageTranslationConfig>({
|
|
58
|
+
source: [],
|
|
59
|
+
targets: [],
|
|
60
|
+
});
|
|
61
|
+
|
|
49
62
|
const isNotValidated =
|
|
50
|
-
|
|
63
|
+
inputTranslationConfig?.source.length === 0 ||
|
|
64
|
+
inputTranslationConfig?.targets.length === 0 ||
|
|
65
|
+
inputTranslationConfig?.targets.length > 10;
|
|
66
|
+
|
|
67
|
+
// Create source language options with "None" prepended
|
|
68
|
+
const sourceLanguageOptions = React.useMemo(() => {
|
|
69
|
+
// return [{label: 'None', value: 'none'}, ...langData];
|
|
70
|
+
return [...langData];
|
|
71
|
+
}, []);
|
|
72
|
+
|
|
73
|
+
// All remote languages except for own user
|
|
74
|
+
const suggestedRemoteTargetLangs = React.useMemo(() => {
|
|
75
|
+
const remoteLangs = Object.entries(remoteSpokenLanguages)
|
|
76
|
+
.filter(([uid, lang]) => uid !== String(localUid) && lang)
|
|
77
|
+
.map(([, lang]) => lang);
|
|
78
|
+
|
|
79
|
+
return Array.from(new Set(remoteLangs));
|
|
80
|
+
}, [remoteSpokenLanguages, localUid]);
|
|
81
|
+
|
|
82
|
+
// Initialize or update source/targets dynamically when modal opens
|
|
83
|
+
React.useEffect(() => {
|
|
84
|
+
if (!props.modalVisible) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.log(
|
|
88
|
+
'[STT_PER_USER_BOT] language selecter popup opened',
|
|
89
|
+
translationConfig,
|
|
90
|
+
);
|
|
51
91
|
|
|
52
|
-
|
|
92
|
+
const mergedTargets = Array.from(
|
|
93
|
+
new Set([
|
|
94
|
+
...(translationConfig.targets || []),
|
|
95
|
+
...suggestedRemoteTargetLangs,
|
|
96
|
+
]),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
setInputTranslationConfig({
|
|
100
|
+
source: translationConfig.source,
|
|
101
|
+
targets: mergedTargets,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
console.log('[STT_PER_USER_BOT] mergedTargets —', mergedTargets);
|
|
105
|
+
console.log(
|
|
106
|
+
'[STT_PER_USER_BOT] all target langs —',
|
|
107
|
+
suggestedRemoteTargetLangs,
|
|
108
|
+
);
|
|
109
|
+
}, [props.modalVisible, translationConfig, suggestedRemoteTargetLangs]);
|
|
110
|
+
|
|
111
|
+
const onConfirmPress = async () => {
|
|
112
|
+
if (isNotValidated) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log('[LANG_SELECTOR] Confirm pressed:', {
|
|
117
|
+
inputTranslationConfig,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
props?.onConfirm(inputTranslationConfig);
|
|
122
|
+
// props.setModalVisible(false);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
console.error('[LANG_SELECTOR] Error confirming STT config:', err);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
53
127
|
|
|
54
128
|
return (
|
|
55
129
|
<Popup
|
|
@@ -57,8 +131,7 @@ const LanguageSelectorPopup = (props: LanguageSelectorPopup) => {
|
|
|
57
131
|
setModalVisible={props.setModalVisible}
|
|
58
132
|
showCloseIcon={true}
|
|
59
133
|
contentContainerStyle={styles.contentContainer}
|
|
60
|
-
title={heading(
|
|
61
|
-
subtitle={subHeading}>
|
|
134
|
+
title={heading(isSTTActive ? false : true)}>
|
|
62
135
|
{isLangChangeInProgress ? (
|
|
63
136
|
<View style={styles.changeInProgress}>
|
|
64
137
|
<Loading
|
|
@@ -70,35 +143,74 @@ const LanguageSelectorPopup = (props: LanguageSelectorPopup) => {
|
|
|
70
143
|
</View>
|
|
71
144
|
) : (
|
|
72
145
|
<>
|
|
146
|
+
{/* Source Language */}
|
|
147
|
+
<View>
|
|
148
|
+
<Text style={styles.labelText}>
|
|
149
|
+
What language will you speak in this meeting?
|
|
150
|
+
</Text>
|
|
151
|
+
<Spacer size={8} />
|
|
152
|
+
<Dropdown
|
|
153
|
+
label="Select language"
|
|
154
|
+
data={sourceLanguageOptions}
|
|
155
|
+
selectedValue={inputTranslationConfig.source[0] || ''}
|
|
156
|
+
onSelect={item =>
|
|
157
|
+
setInputTranslationConfig(prev => ({
|
|
158
|
+
...prev,
|
|
159
|
+
source: [item.value as LanguageType],
|
|
160
|
+
}))
|
|
161
|
+
}
|
|
162
|
+
enabled={true}
|
|
163
|
+
/>
|
|
164
|
+
<Spacer size={2} />
|
|
165
|
+
<Text style={styles.infoText}>
|
|
166
|
+
Captions and transcript will appear in this language for you.
|
|
167
|
+
</Text>
|
|
168
|
+
</View>
|
|
169
|
+
|
|
170
|
+
<Spacer size={20} />
|
|
171
|
+
|
|
172
|
+
{/* Target Languages */}
|
|
73
173
|
<View>
|
|
174
|
+
<Text style={styles.labelText}>
|
|
175
|
+
Spoken languages in the meeting
|
|
176
|
+
</Text>
|
|
177
|
+
<Spacer size={8} />
|
|
74
178
|
<DropdownMulti
|
|
75
|
-
selectedValues={
|
|
76
|
-
setSelectedValues={
|
|
77
|
-
|
|
78
|
-
|
|
179
|
+
selectedValues={inputTranslationConfig.targets}
|
|
180
|
+
setSelectedValues={(val: LanguageType[]) =>
|
|
181
|
+
setInputTranslationConfig(prev => ({
|
|
182
|
+
...prev,
|
|
183
|
+
targets: val,
|
|
184
|
+
}))
|
|
79
185
|
}
|
|
186
|
+
defaultSelectedValues={inputTranslationConfig.targets}
|
|
80
187
|
error={error}
|
|
81
188
|
setError={setError}
|
|
82
|
-
isOpen={
|
|
83
|
-
setIsOpen={
|
|
189
|
+
isOpen={isTargetOpen}
|
|
190
|
+
setIsOpen={setIsTargetOpen}
|
|
191
|
+
maxAllowedSelection={10}
|
|
192
|
+
protectedLanguages={Array.from(
|
|
193
|
+
new Set([...suggestedRemoteTargetLangs]),
|
|
194
|
+
)}
|
|
84
195
|
/>
|
|
196
|
+
<Spacer size={2} />
|
|
197
|
+
<Text style={styles.infoText}>
|
|
198
|
+
Auto populated by spoken languages of other users once they join
|
|
199
|
+
the room.
|
|
200
|
+
</Text>
|
|
85
201
|
</View>
|
|
86
202
|
<Spacer size={8} />
|
|
87
|
-
|
|
88
|
-
{
|
|
89
|
-
|
|
203
|
+
{inputTranslationConfig?.targets.length === 10 && (
|
|
204
|
+
<Text style={[styles.subHeading, styles.errorTxt]}>
|
|
205
|
+
{maxLangValInfo}
|
|
206
|
+
</Text>
|
|
207
|
+
)}
|
|
90
208
|
<Spacer size={32} />
|
|
91
209
|
<View
|
|
92
210
|
style={isDesktop ? styles.btnContainer : styles.btnContainerMobile}>
|
|
93
211
|
<View style={isDesktop && {flex: 1}}>
|
|
94
212
|
<TertiaryButton
|
|
95
|
-
containerStyle={
|
|
96
|
-
width: '100%',
|
|
97
|
-
height: 48,
|
|
98
|
-
paddingVertical: 12,
|
|
99
|
-
paddingHorizontal: 12,
|
|
100
|
-
borderRadius: ThemeConfig.BorderRadius.medium,
|
|
101
|
-
}}
|
|
213
|
+
containerStyle={styles.button}
|
|
102
214
|
text={cancelBtnLabel}
|
|
103
215
|
textStyle={styles.btnText}
|
|
104
216
|
onPress={() => props.setModalVisible(false)}
|
|
@@ -110,30 +222,14 @@ const LanguageSelectorPopup = (props: LanguageSelectorPopup) => {
|
|
|
110
222
|
/>
|
|
111
223
|
<View style={isDesktop && {flex: 1}}>
|
|
112
224
|
<PrimaryButton
|
|
113
|
-
containerStyle={
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
paddingVertical: 12,
|
|
119
|
-
paddingHorizontal: 12,
|
|
120
|
-
}}
|
|
121
|
-
disabled={selectedValues.length === 0}
|
|
225
|
+
containerStyle={styles.button}
|
|
226
|
+
disabled={
|
|
227
|
+
isNotValidated ||
|
|
228
|
+
!hasConfigChanged(translationConfig, inputTranslationConfig)
|
|
229
|
+
}
|
|
122
230
|
text={ConfirmBtnLabel}
|
|
123
231
|
textStyle={styles.btnText}
|
|
124
|
-
onPress={
|
|
125
|
-
console.log(selectedValues);
|
|
126
|
-
console.log(language);
|
|
127
|
-
|
|
128
|
-
if (selectedValues.length === 0) {
|
|
129
|
-
// setError(true);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
const lang1 = language.slice().sort().toString();
|
|
133
|
-
const lang2 = selectedValues.slice().sort().toString();
|
|
134
|
-
const isLangChanged = lang1 !== lang2 || !isSTTActive;
|
|
135
|
-
props.onConfirm(isLangChanged, selectedValues);
|
|
136
|
-
}}
|
|
232
|
+
onPress={onConfirmPress}
|
|
137
233
|
/>
|
|
138
234
|
</View>
|
|
139
235
|
</View>
|
|
@@ -152,26 +248,41 @@ const styles = StyleSheet.create({
|
|
|
152
248
|
justifyContent: 'center',
|
|
153
249
|
alignItems: 'center',
|
|
154
250
|
},
|
|
155
|
-
btnText: {
|
|
156
|
-
fontWeight: '600',
|
|
157
|
-
fontSize: 16,
|
|
158
|
-
lineHeight: 24,
|
|
159
|
-
},
|
|
160
251
|
btnContainerMobile: {
|
|
161
252
|
flexDirection: 'column-reverse',
|
|
162
253
|
},
|
|
163
254
|
contentContainer: {
|
|
164
255
|
padding: 24,
|
|
165
|
-
maxWidth:
|
|
256
|
+
maxWidth: 500,
|
|
166
257
|
width: '100%',
|
|
167
258
|
},
|
|
168
|
-
|
|
169
|
-
|
|
259
|
+
button: {
|
|
260
|
+
width: '100%',
|
|
261
|
+
minWidth: 'auto',
|
|
262
|
+
height: 48,
|
|
263
|
+
paddingVertical: 12,
|
|
264
|
+
paddingHorizontal: 12,
|
|
265
|
+
borderRadius: ThemeConfig.BorderRadius.medium,
|
|
266
|
+
},
|
|
267
|
+
btnText: {
|
|
170
268
|
fontWeight: '600',
|
|
171
|
-
fontSize:
|
|
269
|
+
fontSize: 16,
|
|
172
270
|
lineHeight: 24,
|
|
271
|
+
},
|
|
272
|
+
labelText: {
|
|
273
|
+
fontFamily: ThemeConfig.FontFamily.sansPro,
|
|
274
|
+
fontWeight: '400',
|
|
275
|
+
fontSize: ThemeConfig.FontSize.small,
|
|
276
|
+
lineHeight: 20,
|
|
173
277
|
color: $config.FONT_COLOR,
|
|
174
278
|
},
|
|
279
|
+
infoText: {
|
|
280
|
+
fontFamily: ThemeConfig.FontFamily.sansPro,
|
|
281
|
+
fontWeight: '400',
|
|
282
|
+
fontSize: ThemeConfig.FontSize.tiny,
|
|
283
|
+
lineHeight: 12,
|
|
284
|
+
color: $config.SEMANTIC_NEUTRAL,
|
|
285
|
+
},
|
|
175
286
|
subHeading: {
|
|
176
287
|
fontFamily: ThemeConfig.FontFamily.sansPro,
|
|
177
288
|
fontWeight: '400',
|
|
@@ -179,7 +290,6 @@ const styles = StyleSheet.create({
|
|
|
179
290
|
lineHeight: 20,
|
|
180
291
|
color: $config.FONT_COLOR + hexadecimalTransparency['70%'],
|
|
181
292
|
},
|
|
182
|
-
|
|
183
293
|
errorTxt: {
|
|
184
294
|
color: $config.SEMANTIC_WARNING,
|
|
185
295
|
fontWeight: '600',
|
|
@@ -36,6 +36,7 @@ import DownloadTranscriptBtn from './DownloadTranscriptBtn';
|
|
|
36
36
|
import {useString} from '../../../src/utils/useString';
|
|
37
37
|
import {
|
|
38
38
|
sttSettingSpokenLanguageText,
|
|
39
|
+
sttSettingTranslationLanguageText,
|
|
39
40
|
sttTranscriptPanelNoSearchResultsFoundText,
|
|
40
41
|
sttTranscriptPanelSearchText,
|
|
41
42
|
sttTranscriptPanelViewLatestText,
|
|
@@ -50,11 +51,6 @@ type NativeStreamMessageArgs = [{}, number, number, Uint8Array, number, number];
|
|
|
50
51
|
type StreamMessageArgs = WebStreamMessageArgs | NativeStreamMessageArgs;
|
|
51
52
|
|
|
52
53
|
const Transcript = (props: TranscriptProps) => {
|
|
53
|
-
const settingSpokenLanguageLabel = useString(sttSettingSpokenLanguageText)();
|
|
54
|
-
const searchText = useString(sttTranscriptPanelSearchText)();
|
|
55
|
-
const noresults = useString(sttTranscriptPanelNoSearchResultsFoundText)();
|
|
56
|
-
const viewlatest = useString(sttTranscriptPanelViewLatestText)();
|
|
57
|
-
|
|
58
54
|
const isSmall = useIsSmall();
|
|
59
55
|
const {currentLayout} = useLayout();
|
|
60
56
|
const {showHeader = true} = props;
|
|
@@ -63,9 +59,20 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
63
59
|
isLangChangeInProgress,
|
|
64
60
|
isSTTListenerAdded,
|
|
65
61
|
setIsSTTListenerAdded,
|
|
62
|
+
getBotOwnerUid,
|
|
63
|
+
isSTTActive,
|
|
66
64
|
} = useCaption();
|
|
67
65
|
|
|
66
|
+
const settingSpokenLanguageLabel = useString(sttSettingSpokenLanguageText)();
|
|
67
|
+
const settingTranslationLanguageLabel = useString<boolean>(
|
|
68
|
+
sttSettingTranslationLanguageText,
|
|
69
|
+
)(isSTTActive);
|
|
70
|
+
const searchText = useString(sttTranscriptPanelSearchText)();
|
|
71
|
+
const noresults = useString(sttTranscriptPanelNoSearchResultsFoundText)();
|
|
72
|
+
const viewlatest = useString(sttTranscriptPanelViewLatestText)();
|
|
73
|
+
|
|
68
74
|
const data = meetingTranscript; // Object.entries(transcript);
|
|
75
|
+
console.log('[STT_PER_USER_BOT] meetingTranscript data: ', data);
|
|
69
76
|
|
|
70
77
|
const [showButton, setShowButton] = React.useState(false);
|
|
71
78
|
|
|
@@ -103,6 +110,19 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
103
110
|
|
|
104
111
|
const renderItem = ({item}) => {
|
|
105
112
|
return item.uid.toString().indexOf('langUpdate') !== -1 ? (
|
|
113
|
+
<View style={styles.langChangeContainer}>
|
|
114
|
+
<ImageIcon
|
|
115
|
+
iconType="plain"
|
|
116
|
+
iconSize={20}
|
|
117
|
+
tintColor={$config.PRIMARY_ACTION_BRAND_COLOR}
|
|
118
|
+
name={'globe'}
|
|
119
|
+
/>
|
|
120
|
+
|
|
121
|
+
<Text style={styles.langChange}>
|
|
122
|
+
{defaultContent[item?.uid?.split('-')[1]]?.name + ' ' + item.text}
|
|
123
|
+
</Text>
|
|
124
|
+
</View>
|
|
125
|
+
) : item.uid.toString().indexOf('translationUpdate') !== -1 ? (
|
|
106
126
|
<View style={styles.langChangeContainer}>
|
|
107
127
|
<ImageIcon
|
|
108
128
|
iconType="plain"
|
|
@@ -112,15 +132,17 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
112
132
|
/>
|
|
113
133
|
|
|
114
134
|
<Text style={styles.langChange}>
|
|
115
|
-
{defaultContent[item?.uid?.split('-')[1]]
|
|
135
|
+
{defaultContent[item?.uid?.split('-')[1]]?.name + ' has ' + item.text}
|
|
116
136
|
</Text>
|
|
117
137
|
</View>
|
|
118
138
|
) : (
|
|
119
139
|
<TranscriptText
|
|
120
|
-
user={defaultContent[item.uid]
|
|
140
|
+
user={defaultContent[getBotOwnerUid(item.uid)]?.name || 'Speaker'}
|
|
121
141
|
time={item?.time}
|
|
122
142
|
value={item.text}
|
|
143
|
+
translations={item.translations}
|
|
123
144
|
searchQuery={searchQuery}
|
|
145
|
+
selectedTranslationLanguage={item.selectedTranslationLanguage}
|
|
124
146
|
/>
|
|
125
147
|
);
|
|
126
148
|
};
|
|
@@ -164,9 +186,20 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
164
186
|
const handleSearch = (text: string) => {
|
|
165
187
|
setSearchQuery(text);
|
|
166
188
|
// Filter the data based on the search query
|
|
167
|
-
const filteredResults = meetingTranscript.filter(item =>
|
|
168
|
-
|
|
169
|
-
|
|
189
|
+
const filteredResults = meetingTranscript.filter(item => {
|
|
190
|
+
const searchText = text.toLowerCase();
|
|
191
|
+
// Search in original text
|
|
192
|
+
if (item.text.toLowerCase().includes(searchText)) {
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
// Search in translations if available
|
|
196
|
+
if (item.translations) {
|
|
197
|
+
return item.translations.some(translation =>
|
|
198
|
+
translation.text.toLowerCase().includes(searchText),
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
});
|
|
170
203
|
setShowButton(false);
|
|
171
204
|
setSearchResults(filteredResults);
|
|
172
205
|
// Scroll to the top of the FlatList when searching
|
|
@@ -180,6 +213,7 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
180
213
|
};
|
|
181
214
|
|
|
182
215
|
const handleStreamMessageCallback = (...args: StreamMessageArgs) => {
|
|
216
|
+
console.log('[STT_PER_USER_BOT] handleStreamMessageCallback', args);
|
|
183
217
|
setIsSTTListenerAdded(true);
|
|
184
218
|
if (isWebInternal()) {
|
|
185
219
|
const [uid, data] = args as WebStreamMessageArgs;
|
|
@@ -260,7 +294,7 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
260
294
|
{isLangChangeInProgress ? (
|
|
261
295
|
<View style={{flex: 1}}>
|
|
262
296
|
<Loading
|
|
263
|
-
text={
|
|
297
|
+
text={settingTranslationLanguageLabel}
|
|
264
298
|
background="transparent"
|
|
265
299
|
indicatorColor={$config.FONT_COLOR + hexadecimalTransparency['70%']}
|
|
266
300
|
textColor={$config.FONT_COLOR + hexadecimalTransparency['70%']}
|
|
@@ -438,6 +472,7 @@ export const styles = StyleSheet.create({
|
|
|
438
472
|
langChangeContainer: {
|
|
439
473
|
marginBottom: 20,
|
|
440
474
|
flexDirection: 'row',
|
|
475
|
+
alignItems: 'center',
|
|
441
476
|
},
|
|
442
477
|
footer: {
|
|
443
478
|
borderWidth: 1,
|