agora-appbuilder-core 2.3.0-beta.2 → 2.3.0-beta.22

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.
Files changed (78) hide show
  1. package/Readme.md +11 -6
  2. package/package.json +2 -2
  3. package/template/Gulpfile.js +112 -13
  4. package/template/_package-lock.json +13011 -13288
  5. package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +2 -0
  6. package/template/agora-rn-uikit/src/Controls/BtnTemplate.tsx +4 -5
  7. package/template/agora-rn-uikit/src/Controls/ImageIcon.tsx +3 -1
  8. package/template/agora-rn-uikit/src/Reducer/UserJoined.ts +3 -1
  9. package/template/agora-rn-uikit/src/Rtc/Create.tsx +64 -33
  10. package/template/agora-rn-uikit/src/Rtc/Join.tsx +11 -2
  11. package/template/agora-rn-uikit/src/RtcConfigure.tsx +23 -4
  12. package/template/agora-rn-uikit/src/Utils/permission.ts +17 -6
  13. package/template/bridge/rtc/webNg/RtcEngine.ts +51 -26
  14. package/template/esbuild.rsdk.go +20 -6
  15. package/template/fpe-api/components.ts +15 -0
  16. package/template/fpe-api/context.ts +2 -3
  17. package/template/fpe-api/install.ts +19 -9
  18. package/template/fpe-api/typeDefinition.ts +7 -6
  19. package/template/fpe-api/utils.ts +32 -25
  20. package/template/global.d.ts +3 -2
  21. package/template/index.rsdk.tsx +15 -4
  22. package/template/index.wsdk.tsx +13 -3
  23. package/template/package.json +4 -2
  24. package/template/react-native-toast-message/src/index.js +3 -7
  25. package/template/react-native-toast-message/src/{index.wsdk.js → index.sdk.tsx} +1 -1
  26. package/template/react-native-toast-message/src/styles.sdk.ts +17 -0
  27. package/template/src/SDKAppWrapper.tsx +1 -1
  28. package/template/src/components/Chat.tsx +23 -5
  29. package/template/src/components/ChatContext.ts +15 -4
  30. package/template/src/components/Controls.native.tsx +10 -6
  31. package/template/src/components/Controls.tsx +6 -4
  32. package/template/src/components/HostControlView.tsx +5 -3
  33. package/template/src/components/Navbar.tsx +15 -13
  34. package/template/src/components/RTMConfigure.tsx +20 -50
  35. package/template/src/components/chat-messages/useChatMessages.tsx +369 -70
  36. package/template/src/components/contexts/LiveStreamDataContext.tsx +3 -3
  37. package/template/src/components/contexts/ScreenShareContext.tsx +2 -0
  38. package/template/src/components/livestream/LiveStreamContext.tsx +9 -6
  39. package/template/src/components/participants/MeParticipant.tsx +5 -3
  40. package/template/src/components/participants/RemoteParticipants.tsx +9 -7
  41. package/template/src/components/precall/LocalMute.native.tsx +12 -8
  42. package/template/src/components/precall/LocalMute.tsx +5 -3
  43. package/template/src/components/precall/textInput.tsx +1 -1
  44. package/template/src/components/useShareLink.tsx +37 -39
  45. package/template/src/components/useUserPreference.tsx +125 -0
  46. package/template/src/custom-events/CustomEvents.ts +39 -23
  47. package/template/src/custom-events/types.ts +3 -3
  48. package/template/src/language/default-labels/videoCallScreenLabels.ts +4 -2
  49. package/template/src/pages/Create.tsx +10 -3
  50. package/template/src/pages/Join.tsx +4 -1
  51. package/template/src/pages/VideoCall.tsx +61 -56
  52. package/template/src/pages/video-call/CustomUserContextHolder.tsx +13 -5
  53. package/template/src/pages/video-call/VideoCallScreen.tsx +18 -15
  54. package/template/src/rtm/RTMEngine.ts +13 -0
  55. package/template/src/rtm/utils.ts +1 -1
  56. package/template/src/rtm-events/EventUtils.ts +3 -0
  57. package/template/src/rtm-events/EventsQueue.ts +9 -3
  58. package/template/src/rtm-events/constants.ts +3 -1
  59. package/template/src/subComponents/ChatBubble.tsx +22 -4
  60. package/template/src/subComponents/ChatContainer.tsx +30 -19
  61. package/template/src/subComponents/ChatInput.tsx +38 -26
  62. package/template/src/subComponents/SelectDevice.tsx +1 -1
  63. package/template/src/subComponents/recording/useRecording.tsx +15 -4
  64. package/template/src/subComponents/recording/useRecordingLayoutQuery.tsx +11 -5
  65. package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +35 -26
  66. package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +83 -33
  67. package/template/src/utils/SdkEvents.ts +3 -3
  68. package/template/src/utils/getMeetingInvite.ts +38 -15
  69. package/template/src/utils/getUniqueID.ts +5 -0
  70. package/template/src/utils/useDeleteMessage.ts +36 -0
  71. package/template/src/utils/useEditMessage.ts +41 -0
  72. package/template/src/utils/useGetName.ts +2 -3
  73. package/template/src/utils/useJoinMeeting.ts +22 -14
  74. package/template/src/utils/useLocalShareScreenUid.ts +19 -0
  75. package/template/src/utils/useSendMessage.ts +4 -5
  76. package/template/src/utils/useSetName.ts +2 -4
  77. package/template/webpack.rsdk.config.js +3 -2
  78. package/template/webpack.wsdk.config.js +0 -1
@@ -106,6 +106,7 @@ export interface RtcPropsInterface {
106
106
  // useBeforeCreate?: () => () => Promise<void>;
107
107
  // };
108
108
  geoFencing?: boolean;
109
+ audioRoom?: boolean;
109
110
  }
110
111
 
111
112
  export interface CallbacksInterface {
@@ -142,6 +143,7 @@ const initialValue: PropsInterface = {
142
143
  appId: '',
143
144
  channel: '',
144
145
  geoFencing: true,
146
+ audioRoom: false,
145
147
  },
146
148
  };
147
149
 
@@ -62,11 +62,10 @@ const BtnTemplate: React.FC<BtnTemplateInterface> = (props) => {
62
62
  tintColor: disabled ? 'grey' : props.color || theme || '#fff',
63
63
  }}
64
64
  resizeMode={'contain'}
65
- source={
66
- props.name && icons[props.name]
67
- ? {uri: icons[props.name]}
68
- : props.icon
69
- }
65
+ source={{
66
+ uri:
67
+ props.name && icons[props.name] ? icons[props.name] : props.icon,
68
+ }}
70
69
  />
71
70
  </View>
72
71
  <Text
@@ -49,7 +49,9 @@ const ImageIcon: React.FC<ImageIconInterface> = (props) => {
49
49
  props.style as object,
50
50
  ]}
51
51
  resizeMode={'contain'}
52
- source={props.name && icons[props.name] ? {uri: icons[props.name] } : props.icon}
52
+ source={{
53
+ uri: props.name && icons[props.name] ? icons[props.name] : props.icon,
54
+ }}
53
55
  />
54
56
  );
55
57
  };
@@ -32,7 +32,9 @@ export default function UserJoined(
32
32
  ...typeData,
33
33
  },
34
34
  };
35
- let renderPosition = [...state.renderPosition, newUid];
35
+ let renderPosition = state.renderPosition.filter((i) => i === newUid).length
36
+ ? [...state.renderPosition]
37
+ : [...state.renderPosition, newUid];
36
38
  const [maxUid] = renderPosition;
37
39
  if (renderPosition.length === 2 && maxUid === localUid) {
38
40
  //Only one remote and local is maximized
@@ -22,7 +22,7 @@ const Create = ({
22
22
  }) => {
23
23
  const [ready, setReady] = useState(false);
24
24
  const {callbacks, rtcProps, mode} = useContext(PropsContext);
25
- const {geoFencing = true} = rtcProps || {};
25
+ const {geoFencing = true, audioRoom = false} = rtcProps || {};
26
26
  let engine = useRef<RtcEngine>({} as RtcEngine);
27
27
  // commented for v1 release
28
28
  // const beforeCreate = rtcProps?.lifecycle?.useBeforeCreate
@@ -33,15 +33,23 @@ const Create = ({
33
33
 
34
34
  const enableVideoAndAudioWithDisabledState = async () => {
35
35
  try {
36
- await engine.current.enableVideo();
37
- dispatch({
38
- type: 'LocalMuteAudio',
39
- value: [ToggleState.disabled],
40
- });
41
- dispatch({
42
- type: 'LocalMuteVideo',
43
- value: [ToggleState.disabled],
44
- });
36
+ if (audioRoom === true) {
37
+ await engine.current.enableAudio();
38
+ dispatch({
39
+ type: 'LocalMuteAudio',
40
+ value: [ToggleState.disabled],
41
+ });
42
+ } else {
43
+ await engine.current.enableVideo();
44
+ dispatch({
45
+ type: 'LocalMuteAudio',
46
+ value: [ToggleState.disabled],
47
+ });
48
+ dispatch({
49
+ type: 'LocalMuteVideo',
50
+ value: [ToggleState.disabled],
51
+ });
52
+ }
45
53
  } catch (error) {
46
54
  const {status} = error as any;
47
55
  // App Builder web only
@@ -57,7 +65,7 @@ const Create = ({
57
65
  console.error('No audio device', audioError);
58
66
  }
59
67
 
60
- if (!videoError) {
68
+ if (!videoError && !audioRoom) {
61
69
  dispatch({
62
70
  type: 'LocalMuteVideo',
63
71
  value: [ToggleState.disabled],
@@ -71,15 +79,23 @@ const Create = ({
71
79
  };
72
80
  const enableVideoAndAudioWithEnabledState = async () => {
73
81
  try {
74
- await engine.current.enableVideo();
75
- dispatch({
76
- type: 'LocalMuteAudio',
77
- value: [ToggleState.enabled],
78
- });
79
- dispatch({
80
- type: 'LocalMuteVideo',
81
- value: [ToggleState.enabled],
82
- });
82
+ if (audioRoom === true) {
83
+ await engine.current.enableAudio();
84
+ dispatch({
85
+ type: 'LocalMuteAudio',
86
+ value: [ToggleState.enabled],
87
+ });
88
+ } else {
89
+ await engine.current.enableVideo();
90
+ dispatch({
91
+ type: 'LocalMuteAudio',
92
+ value: [ToggleState.enabled],
93
+ });
94
+ dispatch({
95
+ type: 'LocalMuteVideo',
96
+ value: [ToggleState.enabled],
97
+ });
98
+ }
83
99
  } catch (e) {
84
100
  const {status} = e as any;
85
101
 
@@ -96,7 +112,7 @@ const Create = ({
96
112
  console.error('No audio device', audioError);
97
113
  }
98
114
 
99
- if (!videoError) {
115
+ if (!videoError && !audioRoom) {
100
116
  dispatch({
101
117
  type: 'LocalMuteVideo',
102
118
  value: [ToggleState.enabled],
@@ -123,7 +139,7 @@ const Create = ({
123
139
  async function init() {
124
140
  if (Platform.OS === 'android') {
125
141
  //Request required permissions from Android
126
- await requestCameraAndAudioPermission();
142
+ await requestCameraAndAudioPermission(audioRoom);
127
143
  }
128
144
  // commented for v1 release
129
145
  // try {
@@ -247,7 +263,14 @@ const Create = ({
247
263
  }
248
264
  init();
249
265
  return () => {
250
- engine.current!.destroy();
266
+ /**
267
+ * if condition add for websdk issue
268
+ * For some reason even if engine.current is defined somehow destroy gets undefined and
269
+ * causes a crash so thats why this check is needed before we call the method
270
+ */
271
+ if (engine.current.destroy) {
272
+ engine.current!.destroy();
273
+ }
251
274
  };
252
275
  }, [rtcProps.appId]);
253
276
 
@@ -264,16 +287,20 @@ const Create = ({
264
287
  if (isVideoEnabledRef.current) {
265
288
  // This unpublishes the current track
266
289
  await engine.current?.muteLocalAudioStream(true);
267
- await engine.current?.muteLocalVideoStream(true);
290
+ if (!audioRoom) {
291
+ await engine.current?.muteLocalVideoStream(true);
292
+ }
268
293
  // This updates the uid interface
269
294
  dispatch({
270
295
  type: 'LocalMuteAudio',
271
296
  value: [ToggleState.disabled],
272
297
  });
273
- dispatch({
274
- type: 'LocalMuteVideo',
275
- value: [ToggleState.disabled],
276
- });
298
+ if (!audioRoom) {
299
+ dispatch({
300
+ type: 'LocalMuteVideo',
301
+ value: [ToggleState.disabled],
302
+ });
303
+ }
277
304
  }
278
305
  }
279
306
  if (rtcProps.role == ClientRole.Audience) {
@@ -282,15 +309,19 @@ const Create = ({
282
309
  * Otherwise the setClientRole method call fails and throws an exception.
283
310
  */
284
311
  await engine.current?.muteLocalAudioStream(true);
285
- await engine.current?.muteLocalVideoStream(true);
312
+ if (!audioRoom) {
313
+ await engine.current?.muteLocalVideoStream(true);
314
+ }
286
315
  dispatch({
287
316
  type: 'LocalMuteAudio',
288
317
  value: [ToggleState.disabled],
289
318
  });
290
- dispatch({
291
- type: 'LocalMuteVideo',
292
- value: [ToggleState.disabled],
293
- });
319
+ if (!audioRoom) {
320
+ dispatch({
321
+ type: 'LocalMuteVideo',
322
+ value: [ToggleState.disabled],
323
+ });
324
+ }
294
325
  await engine.current?.setClientRole(ClientRole.Audience);
295
326
  }
296
327
  }
@@ -13,6 +13,7 @@ const Join: React.FC<{
13
13
  }> = ({children, precall, engineRef, uidState, dispatch}) => {
14
14
  let joinState = useRef(false);
15
15
  const {rtcProps} = useContext(PropsContext);
16
+ const {audioRoom = false} = rtcProps;
16
17
  //commented for v1 release
17
18
  // const beforeJoin = rtcProps?.lifecycle?.useBeforeJoin
18
19
  // ? rtcProps.lifecycle.useBeforeJoin()
@@ -44,7 +45,11 @@ const Join: React.FC<{
44
45
  encryptionMode: rtcProps.encryption.mode,
45
46
  });
46
47
  }
47
- if (videoState === ToggleState.enabled && Platform.OS === 'ios') {
48
+ if (
49
+ !audioRoom &&
50
+ videoState === ToggleState.enabled &&
51
+ Platform.OS === 'ios'
52
+ ) {
48
53
  dispatch({
49
54
  type: 'LocalMuteVideo',
50
55
  value: [ToggleState.disabling],
@@ -70,7 +75,11 @@ const Join: React.FC<{
70
75
  null,
71
76
  rtcProps.uid || 0,
72
77
  );
73
- if (videoState === ToggleState.enabled && Platform.OS === 'ios') {
78
+ if (
79
+ !audioRoom &&
80
+ videoState === ToggleState.enabled &&
81
+ Platform.OS === 'ios'
82
+ ) {
74
83
  dispatch({
75
84
  type: 'LocalMuteVideo',
76
85
  value: [ToggleState.enabling],
@@ -203,16 +203,30 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
203
203
 
204
204
  const swapVideo = useCallback(
205
205
  (state: RenderStateInterface, newMaxUid: UidType) => {
206
+ if (state?.renderPosition?.indexOf(newMaxUid) === -1) {
207
+ //skip the update if new max uid is not joined yet.
208
+ return {};
209
+ }
206
210
  let renderPosition: RenderStateInterface['renderPosition'] = [
207
211
  ...state.renderPosition,
208
212
  ];
209
213
  let renderList: RenderStateInterface['renderList'] = {
210
214
  ...state.renderList,
211
215
  };
216
+
212
217
  // Element which is currently maximized
213
218
  const [currentMaxUid] = renderPosition;
214
219
 
215
220
  if (currentMaxUid === newMaxUid) {
221
+ //skip the update if new max uid is already maximized
222
+ return {};
223
+ }
224
+
225
+ const newMaxUidOldPosition = renderPosition.findIndex(
226
+ (i) => i === newMaxUid,
227
+ );
228
+
229
+ if (!newMaxUidOldPosition) {
216
230
  return {};
217
231
  }
218
232
 
@@ -228,10 +242,6 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
228
242
  * else push newMaxUid at last position
229
243
  */
230
244
 
231
- const newMaxUidOldPosition = renderPosition.findIndex(
232
- (i) => i === newMaxUid,
233
- );
234
-
235
245
  renderPosition[0] = newMaxUid;
236
246
  renderPosition[newMaxUidOldPosition] = currentMaxUid;
237
247
 
@@ -248,16 +258,25 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
248
258
  */
249
259
  const dequeVideo = useCallback(
250
260
  (state: RenderStateInterface, newMaxUid: UidType) => {
261
+ if (state?.renderPosition?.indexOf(newMaxUid) === -1) {
262
+ //skip the update if new max uid is not joined yet.
263
+ return {};
264
+ }
251
265
  let renderPosition: RenderStateInterface['renderPosition'] = [
252
266
  ...state.renderPosition,
253
267
  ];
254
268
  let renderList: RenderStateInterface['renderList'] = {
255
269
  ...state.renderList,
256
270
  };
271
+ if (!(newMaxUid in renderList)) {
272
+ //skip the update if new max uid is not joined yet.
273
+ return {};
274
+ }
257
275
  // Element which is currently maximized
258
276
  const [currentMaxUid] = renderPosition;
259
277
 
260
278
  if (currentMaxUid === newMaxUid) {
279
+ //skip the update if new max uid is already maximized
261
280
  return {};
262
281
  }
263
282
 
@@ -1,14 +1,20 @@
1
- import {PermissionsAndroid} from 'react-native';
1
+ import {Permission, PermissionsAndroid} from 'react-native';
2
2
  /**
3
3
  * @name requestCameraAndAudioPermission
4
4
  * @description Function to request permission for Audio and Camera
5
5
  */
6
- export default async function requestCameraAndAudioPermission() {
6
+ export default async function requestCameraAndAudioPermission(
7
+ audioRoom: boolean,
8
+ ) {
7
9
  try {
8
- const granted = await PermissionsAndroid.requestMultiple([
9
- PermissionsAndroid.PERMISSIONS.CAMERA,
10
- PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
11
- ]);
10
+ const permissionsToRequest: Permission[] = [];
11
+ permissionsToRequest.push(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO);
12
+ if (!audioRoom) {
13
+ permissionsToRequest.push(PermissionsAndroid.PERMISSIONS.CAMERA);
14
+ }
15
+ const granted = await PermissionsAndroid.requestMultiple(
16
+ permissionsToRequest,
17
+ );
12
18
  if (
13
19
  granted['android.permission.RECORD_AUDIO'] ===
14
20
  PermissionsAndroid.RESULTS.GRANTED &&
@@ -16,6 +22,11 @@ export default async function requestCameraAndAudioPermission() {
16
22
  PermissionsAndroid.RESULTS.GRANTED
17
23
  ) {
18
24
  console.log('You can use the cameras & mic');
25
+ } else if (
26
+ granted['android.permission.RECORD_AUDIO'] ===
27
+ PermissionsAndroid.RESULTS.GRANTED
28
+ ) {
29
+ console.log('You can use mic');
19
30
  } else {
20
31
  console.log('Permission denied');
21
32
  }
@@ -31,6 +31,10 @@ import type {
31
31
  import {VideoProfile} from '../quality';
32
32
  import {ChannelProfile, ClientRole} from '../../../agora-rn-uikit';
33
33
  import {role, mode} from './Types';
34
+ import {LOG_ENABLED, GEO_FENCING} from '../../../config.json';
35
+ import {Platform} from 'react-native';
36
+ import isMobileOrTablet from '../../../src/utils/isMobileOrTablet';
37
+
34
38
  interface MediaDeviceInfo {
35
39
  readonly deviceId: string;
36
40
  readonly label: string;
@@ -127,7 +131,7 @@ export enum RnEncryptionEnum {
127
131
  *
128
132
  * @since v3.3.1
129
133
  */
130
- AES256GCM = 6
134
+ AES256GCM = 6,
131
135
  }
132
136
 
133
137
  export enum VideoStreamType {
@@ -161,11 +165,6 @@ if ($config.LOG_ENABLED) {
161
165
  AgoraRTC.disableLogUpload();
162
166
  }
163
167
 
164
- interface CustomEvents {
165
- ScreenshareStopped: callbackType
166
- }
167
-
168
-
169
168
  export default class RtcEngine {
170
169
  public appId: string;
171
170
  // public AgoraRTC: any;
@@ -214,20 +213,42 @@ export default class RtcEngine {
214
213
  this.videoProfile = profile;
215
214
  }
216
215
 
216
+ async enableAudio(): Promise<void> {
217
+ try {
218
+ let localAudio = await AgoraRTC.createMicrophoneAudioTrack({});
219
+ this.localStream.audio = localAudio;
220
+ } catch (e) {
221
+ let audioError = e;
222
+ e.status = {audioError};
223
+ throw e;
224
+ }
225
+ }
226
+
217
227
  async enableVideo(): Promise<void> {
228
+ /**
229
+ * Issue: Backgrounding the browser or app causes the audio streaming to be cut off.
230
+ * Impact: All browsers and apps that use WKWebView on iOS 15.x, such as Safari and Chrome.
231
+ * Solution:
232
+ * Upgrade to the Web SDK v4.7.3 or later versions.
233
+ * When calling createMicrophoneAudioTrack, set bypassWebAudio as true.
234
+ * The Web SDK directly publishes the local audio stream without processing it through WebAudio.
235
+ */
236
+
237
+ const audioConfig =
238
+ Platform.OS == 'web' && isMobileOrTablet() ? {bypassWebAudio: true} : {};
218
239
  try {
219
240
  let [localAudio, localVideo] =
220
- await AgoraRTC.createMicrophoneAndCameraTracks(
221
- {},
222
- {encoderConfig: this.videoProfile},
223
- );
241
+ await AgoraRTC.createMicrophoneAndCameraTracks(audioConfig, {
242
+ encoderConfig: this.videoProfile,
243
+ });
224
244
  this.localStream.audio = localAudio;
225
245
  this.localStream.video = localVideo;
226
246
  } catch (e) {
227
247
  let audioError = false;
228
248
  let videoError = false;
229
249
  try {
230
- let localAudio = await AgoraRTC.createMicrophoneAudioTrack({});
250
+ let localAudio = await AgoraRTC.createMicrophoneAudioTrack(audioConfig);
251
+
231
252
  this.localStream.audio = localAudio;
232
253
  } catch (error) {
233
254
  audioError = error;
@@ -673,6 +694,8 @@ export default class RtcEngine {
673
694
  break;
674
695
  case RnEncryptionEnum.SM4128ECB:
675
696
  mode = 'sm4-128-ecb';
697
+ default:
698
+ mode = 'none';
676
699
  }
677
700
  } else {
678
701
  mode = 'none';
@@ -688,7 +711,7 @@ export default class RtcEngine {
688
711
  },
689
712
  ): Promise<void> {
690
713
  let mode: EncryptionMode;
691
- mode = this.getEncryptionMode(enabled, config.encryptionMode);
714
+ mode = this.getEncryptionMode(enabled, config?.encryptionMode);
692
715
  try {
693
716
  await Promise.all([
694
717
  this.client.setEncryptionConfig(mode, config.encryptionKey),
@@ -784,20 +807,22 @@ export default class RtcEngine {
784
807
  try {
785
808
  console.log('[screenshare]: creating stream');
786
809
 
787
- let mode: EncryptionMode;
788
- mode = this.getEncryptionMode(true, encryption.mode);
789
- try {
790
- /**
791
- * Since version 4.7.0, if client leaves a call
792
- * and joins again the encryption needs to be
793
- * set again
794
- */
795
- await this.screenClient.setEncryptionConfig(
796
- mode,
797
- encryption.screenKey,
798
- );
799
- } catch (e) {
800
- console.log('e: Encryption for screenshare failed', e);
810
+ if (encryption && encryption.screenKey && encryption.mode) {
811
+ let mode: EncryptionMode;
812
+ mode = this.getEncryptionMode(true, encryption?.mode);
813
+ try {
814
+ /**
815
+ * Since version 4.7.0, if client leaves a call
816
+ * and joins again the encryption needs to be
817
+ * set again
818
+ */
819
+ await this.screenClient.setEncryptionConfig(
820
+ mode,
821
+ encryption.screenKey,
822
+ );
823
+ } catch (e) {
824
+ console.log('e: Encryption for screenshare failed', e);
825
+ }
801
826
  }
802
827
 
803
828
  const screenTracks = await AgoraRTC.createScreenVideoTrack(
@@ -1,6 +1,7 @@
1
1
  package main
2
2
 
3
3
  import (
4
+ "flag"
4
5
  "log"
5
6
  "os"
6
7
  "path/filepath"
@@ -9,6 +10,11 @@ import (
9
10
  "github.com/evanw/esbuild/pkg/api"
10
11
  )
11
12
 
13
+ type ioPaths struct {
14
+ outPath string
15
+ configTransformerPath string
16
+ }
17
+
12
18
  func commonAliasResolver() api.Plugin {
13
19
  aliasResolvers := api.Plugin{
14
20
  Name: "importAliases",
@@ -152,7 +158,7 @@ func commonLoader() map[string]api.Loader {
152
158
  return loader
153
159
  }
154
160
 
155
- func common() api.BuildOptions {
161
+ func common(iopath *ioPaths) api.BuildOptions {
156
162
  commonBuildOpts := api.BuildOptions{
157
163
  // we can safely ignore (webpack) plugins for now because they seem to be used only for not reactsdk
158
164
 
@@ -164,14 +170,14 @@ func common() api.BuildOptions {
164
170
  Define: map[string]string{
165
171
  "$config": "config",
166
172
  },
167
- Inject: []string{"./esbuildConfigTransform.js"},
173
+ Inject: []string{iopath.configTransformerPath},
168
174
  }
169
175
 
170
176
  return commonBuildOpts
171
177
  }
172
178
 
173
- func rsdk() api.BuildResult {
174
- commonBuildOpts := common()
179
+ func rsdk(iopath *ioPaths) api.BuildResult {
180
+ commonBuildOpts := common(iopath)
175
181
  rsdkBuildOpts := api.BuildOptions{
176
182
  // build options common to rsdk and other components
177
183
  Plugins: commonBuildOpts.Plugins,
@@ -197,7 +203,7 @@ func rsdk() api.BuildResult {
197
203
  // bundle in cjs format because this index.js is meant to be used by other host applications
198
204
  // like webpack which runs on node
199
205
  Format: api.FormatCommonJS,
200
- Outfile: "../Builds/react-sdk/index.js",
206
+ Outfile: iopath.outPath,
201
207
 
202
208
  // other esbuild options
203
209
  Write: true,
@@ -215,7 +221,15 @@ func rsdk() api.BuildResult {
215
221
  }
216
222
 
217
223
  func main() {
218
- rsdkRes := rsdk()
224
+ outPath := flag.String("outpath", "../Builds/react-sdk/index.js", "path to write bundled js file")
225
+ configTransformerPath := flag.String("configtransformerpath", "./esbuildConfigTransform.js", "path to inject file")
226
+ flag.Parse()
227
+ iopath := &ioPaths{
228
+ outPath: *outPath,
229
+ configTransformerPath: *configTransformerPath,
230
+ }
231
+ log.Println("esbuild args = ", iopath)
232
+ rsdkRes := rsdk(iopath)
219
233
  if len(rsdkRes.Errors) > 0 {
220
234
  spew.Dump(rsdkRes)
221
235
  log.Fatalln("build failed")
@@ -1,3 +1,8 @@
1
+ //Common components
2
+ export {default as HorizontalRule} from '../src/atoms/HorizontalRule';
3
+ export {default as PrimaryButton} from '../src/atoms/PrimaryButton';
4
+ export {default as SecondaryButton} from '../src/atoms/SecondaryButton';
5
+ export {default as TextInput} from '../src/atoms/TextInput';
1
6
  //Icons
2
7
  export {default as icons} from '../src/assets/icons';
3
8
 
@@ -18,6 +23,12 @@ export {
18
23
  ParticipantsView,
19
24
  Controls,
20
25
  ControlsComponentsArray,
26
+ Navbar,
27
+ NavBarComponentsArray,
28
+ ChatBubble,
29
+ ChatSendButton,
30
+ ChatTextInput,
31
+ Chat,
21
32
  } from '../src/pages/video-call/index';
22
33
  export {default as GridLayout} from '../src/components/GridVideo';
23
34
  export {default as PinnedLayout} from '../src/components/PinnedVideo';
@@ -40,3 +51,7 @@ export {default as VideocallScreen} from '../src/pages/video-call/VideoCallScree
40
51
 
41
52
  //Sidepanel buttons
42
53
  export {SidePanelButtonsArray} from '../src/subComponents/SidePanelButtons';
54
+ export {
55
+ ImageIcon as UiKitImageIcon,
56
+ MaxVideoView as UiKitMaxVideoView,
57
+ } from '../agora-rn-uikit';
@@ -40,6 +40,5 @@ export {useRecording} from '../src/subComponents/recording/useRecording';
40
40
  export type {RecordingContextInterface} from '../src/subComponents/recording/useRecording';
41
41
  export {useMeetingInfo} from '../src/components/meeting-info/useMeetingInfo';
42
42
  export type {MeetingInfoContextInterface} from '../src/components/meeting-info/useMeetingInfo';
43
- // commented for v1 release
44
- // export {useChatUIControl} from '../src/components/chat-ui/useChatUIControl';
45
- // export type {ChatUIControlInterface} from '../src/components/chat-ui/useChatUIControl';
43
+ export {useChatUIControl} from '../src/components/chat-ui/useChatUIControl';
44
+ export type {ChatUIControlInterface} from '../src/components/chat-ui/useChatUIControl';
@@ -45,18 +45,28 @@ function isComponent(data: any) {
45
45
  return false;
46
46
  }
47
47
 
48
+ //These keys value are not react component. so doing indexOf and checking whether its function or not
49
+ const ignoreTheseKeys = ['customLayout', 'useUserContext'];
50
+
48
51
  function validateComponents(components: any) {
49
52
  for (const key in components) {
50
- let comp = components[key];
51
- if (comp) {
52
- if (isComponent(comp) || isObject(comp)) {
53
- if (isObject(comp)) {
54
- validateComponents(comp);
53
+ if (ignoreTheseKeys.indexOf(key) === -1) {
54
+ let comp = components[key];
55
+ if (comp) {
56
+ if (isComponent(comp) || isObject(comp)) {
57
+ if (isObject(comp)) {
58
+ validateComponents(comp);
59
+ }
60
+ } else {
61
+ console.error(
62
+ `InstallFPE:Error ${key} should be a react component or object`,
63
+ );
55
64
  }
56
- } else {
57
- console.error(
58
- `InstallFPE:Error ${key} should be a react component or object`,
59
- );
65
+ }
66
+ } else {
67
+ let comp = components[key];
68
+ if (comp && !isFunction(comp)) {
69
+ console.error(`InstallFPE:Error ${key} should be an function`);
60
70
  }
61
71
  }
62
72
  }