agora-appbuilder-core 4.0.29-beta-24 → 4.0.29-beta-25

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agora-appbuilder-core",
3
- "version": "4.0.29-beta-24",
3
+ "version": "4.0.29-beta-25",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -85,3 +85,4 @@ export {default as TranscriptPanel} from '../src/subComponents/caption/Transcrip
85
85
  export type {TranscriptProps} from '../src/subComponents/caption/Transcript';
86
86
  export {default as CaptionPanel} from '../src/subComponents/caption/CaptionContainer';
87
87
  export {default as VBPreview} from '../src/components/virtual-background/VideoPreview';
88
+ export {default as Toast} from '../react-native-toast-message';
@@ -9,6 +9,8 @@ import {
9
9
  TouchableOpacity,
10
10
  ViewStyle,
11
11
  useWindowDimensions,
12
+ StyleProp,
13
+ TextStyle,
12
14
  } from 'react-native';
13
15
  import React, {SetStateAction, useState} from 'react';
14
16
 
@@ -32,6 +34,7 @@ export interface ActionMenuItem {
32
34
  iconColor: string;
33
35
  textColor: string;
34
36
  title: string;
37
+ titleStyle?: StyleProp<TextStyle>;
35
38
  label?: string;
36
39
  toggleStatus?: boolean;
37
40
  onPress: () => void;
@@ -97,6 +100,7 @@ const ActionMenu = (props: ActionMenuProps) => {
97
100
  onHoverCallback = undefined,
98
101
  onHoverContent = undefined,
99
102
  iconSize = 20,
103
+ titleStyle = {},
100
104
  } = item;
101
105
  return (
102
106
  <PlatformWrapper key={props.from + '_' + title + index}>
@@ -175,7 +179,11 @@ const ActionMenu = (props: ActionMenuProps) => {
175
179
  )}
176
180
  </View>
177
181
  <Text
178
- style={[styles.text, textColor ? {color: textColor} : {}]}>
182
+ style={[
183
+ styles.text,
184
+ titleStyle,
185
+ textColor ? {color: textColor} : {},
186
+ ]}>
179
187
  {label || title}
180
188
  </Text>
181
189
  {toggleStatus !== undefined && toggleStatus !== null ? (
@@ -6,6 +6,7 @@ import {
6
6
  Platform,
7
7
  StyleSheet,
8
8
  TextStyle,
9
+ ViewStyle,
9
10
  } from 'react-native';
10
11
 
11
12
  import ThemeConfig from '../theme';
@@ -17,6 +18,9 @@ interface CheckboxProps {
17
18
  onChange: (checked: boolean) => void;
18
19
  labelStye?: TextStyle;
19
20
  disabled?: boolean;
21
+ containerStyle?: ViewStyle;
22
+ checkBoxStyle?: ViewStyle;
23
+ tickColor?: string;
20
24
  }
21
25
 
22
26
  const Checkbox: React.FC<CheckboxProps> = ({
@@ -25,6 +29,9 @@ const Checkbox: React.FC<CheckboxProps> = ({
25
29
  onChange,
26
30
  disabled = false,
27
31
  labelStye = {},
32
+ containerStyle = {},
33
+ checkBoxStyle = {},
34
+ tickColor = $config.FONT_COLOR,
28
35
  }) => {
29
36
  const [isChecked, setIsChecked] = useState(checked);
30
37
 
@@ -40,15 +47,21 @@ const Checkbox: React.FC<CheckboxProps> = ({
40
47
  };
41
48
 
42
49
  return (
43
- <TouchableOpacity onPress={handleCheckboxToggle} style={styles.container}>
50
+ <TouchableOpacity
51
+ onPress={handleCheckboxToggle}
52
+ style={(styles.container, containerStyle)}>
44
53
  <View
45
- style={[styles.checkboxContainer, isChecked && styles.fillSelected]}>
54
+ style={[
55
+ styles.checkboxContainer,
56
+ checkBoxStyle,
57
+ isChecked && styles.fillSelected,
58
+ ]}>
46
59
  {isChecked && (
47
60
  <ImageIcon
48
61
  iconType="plain"
49
62
  name={'tick'}
50
63
  iconSize={8}
51
- tintColor={$config.FONT_COLOR}
64
+ tintColor={tickColor}
52
65
  />
53
66
  )}
54
67
  </View>
@@ -76,6 +89,7 @@ const styles = StyleSheet.create({
76
89
  borderColor: $config.SEMANTIC_NEUTRAL,
77
90
  justifyContent: 'center',
78
91
  alignItems: 'center',
92
+ borderRadius: 1,
79
93
  },
80
94
  checkIcon: {
81
95
  position: 'absolute',
@@ -31,6 +31,7 @@ const TertiaryButton = (props: ButtonProps) => {
31
31
  iconName,
32
32
  iconSize = 26,
33
33
  iconColor = $config.PRIMARY_ACTION_TEXT_COLOR,
34
+ disabled = false,
34
35
  ...rest
35
36
  } = props;
36
37
  const [isHovered, setIsHovered] = useState(false);
@@ -38,16 +39,17 @@ const TertiaryButton = (props: ButtonProps) => {
38
39
  return (
39
40
  <PlatformWrapper setIsHovered={setIsHovered}>
40
41
  <TouchableOpacity
41
- ref={(ref) => props?.setRef && props.setRef(ref)}
42
+ ref={ref => props?.setRef && props.setRef(ref)}
42
43
  style={[
43
44
  styles.container,
44
- isHovered
45
+ isHovered && !disabled
45
46
  ? {
46
47
  backgroundColor:
47
48
  $config.CARD_LAYER_5_COLOR + hexadecimalTransparency['15%'],
48
49
  }
49
50
  : {},
50
51
  props?.containerStyle,
52
+ disabled ? styles.disabledContainer : {},
51
53
  ]}
52
54
  {...rest}>
53
55
  <View style={styles.flexRow}>
@@ -57,11 +59,18 @@ const TertiaryButton = (props: ButtonProps) => {
57
59
  iconSize={iconSize}
58
60
  iconType="plain"
59
61
  name={iconName}
60
- tintColor={iconColor}
62
+ tintColor={disabled ? $config.SEMANTIC_NEUTRAL : iconColor}
61
63
  />
62
64
  </View>
63
65
  )}
64
- <Text style={[styles.text, props?.textStyle]}>{text}</Text>
66
+ <Text
67
+ style={[
68
+ styles.text,
69
+ props?.textStyle,
70
+ disabled ? styles.disabledText : {},
71
+ ]}>
72
+ {text}
73
+ </Text>
65
74
  </View>
66
75
  </TouchableOpacity>
67
76
  </PlatformWrapper>
@@ -105,4 +114,11 @@ const styles = StyleSheet.create({
105
114
  fontSize: ThemeConfig.FontSize.small,
106
115
  fontWeight: '600',
107
116
  },
117
+ disabledContainer: {
118
+ borderColor: $config.SEMANTIC_NEUTRAL,
119
+ cursor: 'default',
120
+ },
121
+ disabledText: {
122
+ color: $config.SEMANTIC_NEUTRAL,
123
+ },
108
124
  });
@@ -6,10 +6,16 @@ interface SwitchProps {
6
6
  isEnabled: boolean;
7
7
  disabled?: boolean;
8
8
  toggleSwitch: (isEnabled: boolean) => void;
9
+ circleColor?: string;
9
10
  }
10
11
 
11
12
  const Toggle = (props: SwitchProps) => {
12
- const {isEnabled, toggleSwitch, disabled = false} = props;
13
+ const {
14
+ isEnabled,
15
+ toggleSwitch,
16
+ disabled = false,
17
+ circleColor = $config.CARD_LAYER_1_COLOR,
18
+ } = props;
13
19
  return (
14
20
  <View>
15
21
  <CustomSwitch
@@ -21,8 +27,8 @@ const Toggle = (props: SwitchProps) => {
21
27
  disabled={false}
22
28
  backgroundActive={$config.PRIMARY_ACTION_BRAND_COLOR}
23
29
  backgroundInactive={$config.SEMANTIC_NEUTRAL}
24
- circleActiveColor={$config.CARD_LAYER_1_COLOR}
25
- circleInActiveColor={$config.CARD_LAYER_1_COLOR}
30
+ circleActiveColor={circleColor}
31
+ circleInActiveColor={circleColor}
26
32
  // renderInsideCircle={() => <CustomComponent />} // custom component to render inside the Switch circle (Text, Image, etc.)
27
33
  changeValueImmediately={true} // if rendering inside circle, change state immediately or wait for animation to complete
28
34
  innerCircleStyle={{
@@ -65,7 +65,7 @@ const CustomSidePanelView = (props: CustomSidePanelViewInterface) => {
65
65
  {showHeader && (
66
66
  <CustomSidePanelHeader name={name} title={title} onClose={onClose} />
67
67
  )}
68
- <ScrollView style={[style.bodyContainer]}>
68
+ <ScrollView contentContainerStyle={[style.bodyContainer]}>
69
69
  {CustomSidePanelContent ? <CustomSidePanelContent /> : <></>}
70
70
  </ScrollView>
71
71
  </View>
@@ -75,7 +75,6 @@ const CustomSidePanelView = (props: CustomSidePanelViewInterface) => {
75
75
  const style = StyleSheet.create({
76
76
  bodyContainer: {
77
77
  flex: 1,
78
- padding: 20,
79
78
  },
80
79
  });
81
80
 
@@ -54,6 +54,7 @@ import {
54
54
  import {useString} from '../utils/useString';
55
55
  import useEndCall from '../utils/useEndCall';
56
56
  import {logger, LogSource} from '../logger/AppBuilderLogger';
57
+ import {useIsRecordingBot} from '../subComponents/recording/useIsRecordingBot';
57
58
 
58
59
  interface Props {
59
60
  children: React.ReactNode;
@@ -68,6 +69,7 @@ const EventsConfigure: React.FC<Props> = ({
68
69
  setSttAutoStarted,
69
70
  sttAutoStarted,
70
71
  }) => {
72
+ const {isRecordingBot} = useIsRecordingBot();
71
73
  const isSTTAlreadyActiveRef = useRef(undefined);
72
74
  // mute user audio
73
75
  const hostMutedUserAudioToastHeadingTT = useString<I18nMuteType>(
@@ -270,6 +272,7 @@ const EventsConfigure: React.FC<Props> = ({
270
272
  //auto start stt
271
273
  useEffect(() => {
272
274
  if (
275
+ !isRecordingBot &&
273
276
  $config.ENABLE_CAPTION &&
274
277
  $config.STT_AUTO_START &&
275
278
  callActive &&
@@ -279,7 +282,9 @@ const EventsConfigure: React.FC<Props> = ({
279
282
  ) {
280
283
  //host will start the caption
281
284
  if (isHost && roomId?.host && !isSTTAlreadyActiveRef.current) {
282
- logger.log(LogSource.Internals, 'STT', 'STT_AUTO_START triggered');
285
+ logger.log(LogSource.Internals, 'STT', 'STT_AUTO_START triggered', {
286
+ uidWhoTriggered: localUid,
287
+ });
283
288
  //start with default language
284
289
  startSpeechToText(['en-US'])
285
290
  .then(() => {
@@ -289,7 +294,7 @@ const EventsConfigure: React.FC<Props> = ({
289
294
  .catch(err => {
290
295
  logger.log(
291
296
  LogSource.Internals,
292
- 'RECORDING',
297
+ 'STT',
293
298
  'STT_AUTO_START failed',
294
299
  err,
295
300
  );
@@ -301,12 +306,13 @@ const EventsConfigure: React.FC<Props> = ({
301
306
  logger.log(
302
307
  LogSource.Internals,
303
308
  'STT',
304
- 'STT_AUTO_START triggered already by some other host success',
309
+ 'STT_AUTO_START already triggered by some other host',
305
310
  );
306
311
  setSttAutoStarted(true);
307
312
  }
308
313
  }
309
314
  }, [
315
+ isRecordingBot,
310
316
  callActive,
311
317
  isHost,
312
318
  hasUserJoinedRTM,
@@ -151,6 +151,7 @@ const VideoCall: React.FC = () => {
151
151
  const [waitingRoomAttendeeJoined, setWaitingRoomAttendeeJoined] =
152
152
  useState(false);
153
153
  const [sttAutoStarted, setSttAutoStarted] = useState(false);
154
+ const [recordingAutoStarted, setRecordingAutoStarted] = useState(false);
154
155
 
155
156
  const {phrase} = useParams<{phrase: string}>();
156
157
 
@@ -489,6 +490,8 @@ const VideoCall: React.FC = () => {
489
490
  setRecordingActive,
490
491
  isRecordingActive,
491
492
  callActive,
493
+ recordingAutoStarted,
494
+ setRecordingAutoStarted,
492
495
  }}>
493
496
  <NetworkQualityProvider>
494
497
  {!isMobileUA() && (
@@ -104,6 +104,8 @@ interface RecordingProviderProps {
104
104
  setRecordingActive: React.Dispatch<SetStateAction<boolean>>;
105
105
  isRecordingActive: boolean;
106
106
  callActive: boolean;
107
+ recordingAutoStarted: boolean;
108
+ setRecordingAutoStarted: React.Dispatch<React.SetStateAction<boolean>>;
107
109
  };
108
110
  }
109
111
 
@@ -141,8 +143,13 @@ const showErrorToast = (text1: string, text2?: string) => {
141
143
  };
142
144
 
143
145
  const RecordingProvider = (props: RecordingProviderProps) => {
144
- const {setRecordingActive, isRecordingActive, callActive} = props?.value;
145
- const [autoStartCompleted, setAutoStartCompleted] = useState(false);
146
+ const {
147
+ setRecordingActive,
148
+ isRecordingActive,
149
+ callActive,
150
+ recordingAutoStarted,
151
+ setRecordingAutoStarted,
152
+ } = props?.value;
146
153
  const {
147
154
  data: {isHost, roomId},
148
155
  } = useRoomInfo();
@@ -167,7 +174,8 @@ const RecordingProvider = (props: RecordingProviderProps) => {
167
174
 
168
175
  const userlabel = useString(videoRoomUserFallbackText)();
169
176
 
170
- const {localUid, hasUserJoinedRTM} = useContext(ChatContext);
177
+ const {localUid, hasUserJoinedRTM, isInitialQueueCompleted} =
178
+ useContext(ChatContext);
171
179
  const {store} = React.useContext(StorageContext);
172
180
 
173
181
  const {setChatType} = useChatUIControls();
@@ -841,33 +849,50 @@ const RecordingProvider = (props: RecordingProviderProps) => {
841
849
  _stopRecording,
842
850
  ]);
843
851
 
844
- //commented auto start for cloud recording
845
852
  // auto start recording
846
- // useEffect(() => {
847
- // if (
848
- // $config.CLOUD_RECORDING &&
849
- // $config.CLOUD_RECORDING_AUTO_START &&
850
- // callActive &&
851
- // !isRecordingActive &&
852
- // isHost &&
853
- // hasUserJoinedRTM &&
854
- // !autoStartCompleted
855
- // ) {
856
- // logger.log(
857
- // LogSource.Internals,
858
- // 'RECORDING',
859
- // 'CLOUD_RECORDING_AUTO_START triggered',
860
- // );
861
- // startRecording();
862
- // setAutoStartCompleted(true);
863
- // }
864
- // }, [
865
- // isRecordingActive,
866
- // isHost,
867
- // callActive,
868
- // hasUserJoinedRTM,
869
- // autoStartCompleted,
870
- // ]);
853
+ useEffect(() => {
854
+ if (
855
+ $config.CLOUD_RECORDING &&
856
+ $config.CLOUD_RECORDING_AUTO_START &&
857
+ callActive &&
858
+ hasUserJoinedRTM &&
859
+ isInitialQueueCompleted &&
860
+ isHost &&
861
+ roomId?.host &&
862
+ !isRecordingBot &&
863
+ !recordingAutoStarted
864
+ ) {
865
+ if (!isRecordingActive) {
866
+ logger.log(
867
+ LogSource.Internals,
868
+ 'RECORDING',
869
+ 'CLOUD_RECORDING_AUTO_START triggered',
870
+ {
871
+ uidWhoTriggered: localUid,
872
+ },
873
+ );
874
+ startRecording();
875
+ setRecordingAutoStarted(true);
876
+ } else {
877
+ logger.log(
878
+ LogSource.Internals,
879
+ 'RECORDING',
880
+ 'CLOUD_RECORDING_AUTO_START already triggered by some other host',
881
+ );
882
+ setRecordingAutoStarted(true);
883
+ }
884
+ }
885
+ }, [
886
+ callActive,
887
+ hasUserJoinedRTM,
888
+ isInitialQueueCompleted,
889
+ isHost,
890
+ isRecordingBot,
891
+ isRecordingActive,
892
+ recordingAutoStarted,
893
+ localUid,
894
+ roomId,
895
+ ]);
871
896
 
872
897
  // useEffect(() => { //
873
898
  // if (hasUserJoinedRTM && isRecordingBot) {