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
@@ -52,6 +52,7 @@ import {WhiteboardProvider} from '../components/contexts/WhiteboardContext';
52
52
  import {useWakeLock} from '../components/useWakeLock';
53
53
  import StorageContext from '../components/StorageContext';
54
54
  import SDKEvents from '../utils/SdkEvents';
55
+ import {UserPreferenceProvider} from '../components/useUserPreference';
55
56
 
56
57
  enum RnEncryptionEnum {
57
58
  /**
@@ -114,6 +115,7 @@ const VideoCall: React.FC = () => {
114
115
  : false,
115
116
  role: ClientRole.Broadcaster,
116
117
  geoFencing: $config.GEO_FENCING,
118
+ audioRoom: $config.AUDIO_ROOM,
117
119
  });
118
120
 
119
121
  const useJoin = useJoinMeeting();
@@ -128,11 +130,11 @@ const VideoCall: React.FC = () => {
128
130
  }, []);
129
131
 
130
132
  useEffect(() => {
131
- try {
132
- useJoin(phrase);
133
- } catch (error) {
134
- setGlobalErrorMessage(error);
135
- }
133
+ useJoin(phrase)
134
+ .then(() => {})
135
+ .catch((error) => {
136
+ setGlobalErrorMessage(error);
137
+ });
136
138
  }, []);
137
139
 
138
140
  const data = useMeetingInfo();
@@ -158,6 +160,7 @@ const VideoCall: React.FC = () => {
158
160
  screenShareToken: data.screenShareToken,
159
161
  role: data.isHost ? ClientRole.Broadcaster : ClientRole.Audience,
160
162
  geoFencing: $config.GEO_FENCING,
163
+ audioRoom: $config.AUDIO_ROOM,
161
164
  });
162
165
 
163
166
  // 1. Store the display name from API
@@ -200,65 +203,67 @@ const VideoCall: React.FC = () => {
200
203
  <DeviceConfigure>
201
204
  <ChatUIControlProvider>
202
205
  <ChatNotificationProvider>
203
- <ChatMessagesProvider>
204
- <SidePanelProvider
205
- value={{
206
- sidePanel,
207
- setSidePanel,
208
- }}>
206
+ <SidePanelProvider
207
+ value={{
208
+ sidePanel,
209
+ setSidePanel,
210
+ }}>
211
+ <ChatMessagesProvider>
209
212
  <ScreenShareProvider>
210
213
  <RtmConfigure
211
214
  setRecordingActive={setRecordingActive}
212
215
  callActive={callActive}>
213
- <WhiteboardProvider>
214
- <LayoutProvider
215
- value={{
216
- activeLayoutName,
217
- setActiveLayoutName,
218
- }}>
219
- <RecordingProvider
216
+ <UserPreferenceProvider>
217
+ <WhiteboardProvider>
218
+ <LayoutProvider
220
219
  value={{
221
- setRecordingActive,
222
- isRecordingActive,
220
+ activeLayoutName,
221
+ setActiveLayoutName,
223
222
  }}>
224
- <ScreenshareConfigure>
225
- <LiveStreamContextProvider
226
- value={{
227
- setRtcProps,
228
- rtcProps,
229
- callActive,
230
- }}>
231
- <LiveStreamDataProvider>
232
- <LocalUserContext
233
- localUid={rtcProps?.uid || 0}>
234
- <CustomUserContextHolder>
235
- <NetworkQualityProvider>
236
- {callActive ? (
237
- <VideoCallScreen />
238
- ) : $config.PRECALL ? (
239
- <PreCallProvider
240
- value={{
241
- callActive,
242
- setCallActive,
243
- }}>
244
- <Precall />
245
- </PreCallProvider>
246
- ) : (
247
- <></>
248
- )}
249
- </NetworkQualityProvider>
250
- </CustomUserContextHolder>
251
- </LocalUserContext>
252
- </LiveStreamDataProvider>
253
- </LiveStreamContextProvider>
254
- </ScreenshareConfigure>
255
- </RecordingProvider>
256
- </LayoutProvider>
257
- </WhiteboardProvider>
223
+ <RecordingProvider
224
+ value={{
225
+ setRecordingActive,
226
+ isRecordingActive,
227
+ }}>
228
+ <ScreenshareConfigure>
229
+ <LiveStreamContextProvider
230
+ value={{
231
+ setRtcProps,
232
+ rtcProps,
233
+ callActive,
234
+ }}>
235
+ <LiveStreamDataProvider>
236
+ <LocalUserContext
237
+ localUid={rtcProps?.uid || 0}>
238
+ <CustomUserContextHolder>
239
+ <NetworkQualityProvider>
240
+ {callActive ? (
241
+ <VideoCallScreen />
242
+ ) : $config.PRECALL ? (
243
+ <PreCallProvider
244
+ value={{
245
+ callActive,
246
+ setCallActive,
247
+ }}>
248
+ <Precall />
249
+ </PreCallProvider>
250
+ ) : (
251
+ <></>
252
+ )}
253
+ </NetworkQualityProvider>
254
+ </CustomUserContextHolder>
255
+ </LocalUserContext>
256
+ </LiveStreamDataProvider>
257
+ </LiveStreamContextProvider>
258
+ </ScreenshareConfigure>
259
+ </RecordingProvider>
260
+ </LayoutProvider>
261
+ </WhiteboardProvider>
262
+ </UserPreferenceProvider>
258
263
  </RtmConfigure>
259
264
  </ScreenShareProvider>
260
- </SidePanelProvider>
261
- </ChatMessagesProvider>
265
+ </ChatMessagesProvider>
266
+ </SidePanelProvider>
262
267
  </ChatNotificationProvider>
263
268
  </ChatUIControlProvider>
264
269
  </DeviceConfigure>
@@ -2,11 +2,19 @@ import React from 'react';
2
2
  import {useFpe} from 'fpe-api';
3
3
 
4
4
  const CustomUserContextHolder: React.FC<{children: any}> = (props) => {
5
- //commented for v1 release
6
- // const fpeCustomContext = useFpe((config) => config?.customUserContext);
7
- // if (fpeCustomContext) {
8
- // fpeCustomContext();
9
- // }
5
+ const useUserContext = useFpe((config) => {
6
+ if (
7
+ config?.components?.videoCall &&
8
+ typeof config?.components?.videoCall === 'object' &&
9
+ config?.components?.videoCall?.useUserContext &&
10
+ typeof config?.components?.videoCall?.useUserContext === 'function'
11
+ ) {
12
+ return config?.components?.videoCall?.useUserContext;
13
+ } else {
14
+ return () => {};
15
+ }
16
+ });
17
+ useUserContext();
10
18
  return props.children;
11
19
  };
12
20
  export default CustomUserContextHolder;
@@ -95,14 +95,13 @@ const VideoCallScreen = () => {
95
95
  components.BottombarComponent = data?.components?.videoCall.bottomBar;
96
96
  }
97
97
 
98
- // commented for v1 release
99
- // if (
100
- // data?.components?.videoCall.topBar &&
101
- // typeof data?.components?.videoCall.topBar !== 'object' &&
102
- // isValidReactComponent(data?.components?.videoCall.topBar)
103
- // ) {
104
- // components.TopbarComponent = data?.components?.videoCall.topBar;
105
- // }
98
+ if (
99
+ data?.components?.videoCall.topBar &&
100
+ typeof data?.components?.videoCall.topBar !== 'object' &&
101
+ isValidReactComponent(data?.components?.videoCall.topBar)
102
+ ) {
103
+ components.TopbarComponent = data?.components?.videoCall.topBar;
104
+ }
106
105
 
107
106
  if (
108
107
  data?.components?.videoCall.participantsPanel &&
@@ -128,13 +127,17 @@ const VideoCallScreen = () => {
128
127
  });
129
128
 
130
129
  useEffect(() => {
131
- new Promise((res) =>
132
- rtc.RtcEngine.getDevices(function (devices: MediaDeviceInfo[]) {
133
- res(devices);
134
- }),
135
- ).then((devices: MediaDeviceInfo[]) => {
136
- SDKEvents.emit('join', meetingTitle, devices, isHost);
137
- });
130
+ /**
131
+ * Commenting this code as getDevices API is web only
132
+ * The below code fails on native app
133
+ */
134
+ // new Promise((res) =>
135
+ // rtc.RtcEngine.getDevices(function (devices: MediaDeviceInfo[]) {
136
+ // res(devices);
137
+ // }),
138
+ // ).then((devices: MediaDeviceInfo[]) => {
139
+ // SDKEvents.emit('join', meetingTitle, devices, isHost);
140
+ // });
138
141
  }, []);
139
142
 
140
143
  return VideocallComponent ? (
@@ -30,6 +30,11 @@ class RTMEngine {
30
30
  await this.engine.createClient($config.APP_ID);
31
31
  }
32
32
 
33
+ private async destroyClientInstance() {
34
+ await this.engine.logout();
35
+ await this.engine.destroyClient();
36
+ }
37
+
33
38
  private constructor() {
34
39
  if (RTMEngine._instance) {
35
40
  return RTMEngine._instance;
@@ -53,6 +58,14 @@ class RTMEngine {
53
58
  get channelUid() {
54
59
  return this.channelId;
55
60
  }
61
+ destroy() {
62
+ try {
63
+ this.destroyClientInstance();
64
+ RTMEngine._instance = null;
65
+ } catch (error) {
66
+ console.log('Error destroying instance error: ', error);
67
+ }
68
+ }
56
69
  }
57
70
 
58
71
  export default RTMEngine;
@@ -30,7 +30,7 @@ export const timeNow = () => new Date().getTime();
30
30
  export const getMessageTime = (ts?: number): number => {
31
31
  if (!ts) return timeNow();
32
32
  try {
33
- const timestamp = new Date(ts).getHours();
33
+ const timestamp = new Date(ts).getTime();
34
34
  return isNaN(timestamp) ? timeNow() : timestamp;
35
35
  } catch (error) {
36
36
  return timeNow();
@@ -245,6 +245,9 @@ const EventUtils = (function () {
245
245
  }
246
246
  return this;
247
247
  },
248
+ clear() {
249
+ _events = {};
250
+ },
248
251
  // 1. To add multiple listeners
249
252
  // addListeners(evt: string, listeners: any) {
250
253
  // if (Array.isArray(listeners)) {
@@ -27,10 +27,16 @@ const EventsQueue = (function () {
27
27
  },
28
28
  dequeue() {
29
29
  if (_eventsQueue.length == 0) return;
30
- _eventsQueue.shift();
30
+ return _eventsQueue.pop();
31
31
  },
32
- printQueue() {
33
- return _eventsQueue;
32
+ isEmpty() {
33
+ return _eventsQueue.length === 0;
34
+ },
35
+ size() {
36
+ return _eventsQueue.length;
37
+ },
38
+ clear() {
39
+ _eventsQueue = [];
34
40
  },
35
41
  };
36
42
  })();
@@ -26,7 +26,8 @@ const ROLE_ATTRIBUTE = 'role';
26
26
  // 3. CHAT MESSAGES
27
27
  const PUBLIC_CHAT_MESSAGE = 'PUBLIC_CHAT_MESSAGE';
28
28
  const PRIVATE_CHAT_MESSAGE = 'PRIVATE_CHAT_MESSAGE';
29
-
29
+ // 4. NAME ATTRIBUTE
30
+ const NAME_ATTRIBUTE = 'name';
30
31
  const EventNames = {
31
32
  RECORDING_ATTRIBUTE,
32
33
  RAISED_ATTRIBUTE,
@@ -34,6 +35,7 @@ const EventNames = {
34
35
  PUBLIC_CHAT_MESSAGE,
35
36
  PRIVATE_CHAT_MESSAGE,
36
37
  SCREENSHARE_ATTRIBUTE,
38
+ NAME_ATTRIBUTE,
37
39
  };
38
40
  /** ***** EVENT NAMES ENDS ***** */
39
41
 
@@ -21,11 +21,19 @@ import useUserList from '../utils/useUserList';
21
21
  const ChatBubble = (props: ChatBubbleProps) => {
22
22
  const {renderList} = useUserList();
23
23
  const {primaryColor} = useContext(ColorContext);
24
- let {isLocal, message, timestamp, uid} = props;
24
+ let {
25
+ isLocal,
26
+ message,
27
+ createdTimestamp,
28
+ uid,
29
+ isDeleted,
30
+ msgId,
31
+ updatedTimestamp,
32
+ } = props;
25
33
  let time =
26
- new Date(parseInt(timestamp)).getHours() +
34
+ new Date(parseInt(createdTimestamp)).getHours() +
27
35
  ':' +
28
- new Date(parseInt(timestamp)).getMinutes();
36
+ new Date(parseInt(createdTimestamp)).getMinutes();
29
37
  const handleUrl = (url: string) => {
30
38
  if (isWeb) {
31
39
  window.open(url, '_blank');
@@ -36,7 +44,17 @@ const ChatBubble = (props: ChatBubbleProps) => {
36
44
  //commented for v1 release
37
45
  //const remoteUserDefaultLabel = useString('remoteUserDefaultLabel')();
38
46
  const remoteUserDefaultLabel = 'User';
39
- return (
47
+ return props?.render ? (
48
+ props.render(
49
+ isLocal,
50
+ message,
51
+ createdTimestamp,
52
+ uid,
53
+ msgId,
54
+ isDeleted,
55
+ updatedTimestamp,
56
+ )
57
+ ) : (
40
58
  <View>
41
59
  <View style={isLocal ? style.chatSenderViewLocal : style.chatSenderView}>
42
60
  <Text style={isLocal ? style.timestampTextLocal : style.timestampText}>
@@ -26,7 +26,7 @@ import {useLocalUid} from '../../agora-rn-uikit';
26
26
  import {ImageIcon} from '../../agora-rn-uikit';
27
27
  import TextWithTooltip from './TextWithTooltip';
28
28
  import {useFpe} from 'fpe-api';
29
- import {isWeb} from '../utils/common';
29
+ import {isValidReactComponent, isWeb} from '../utils/common';
30
30
  import {useString} from '../utils/useString';
31
31
  import {useChatUIControl} from '../components/chat-ui/useChatUIControl';
32
32
  import useUserList from '../utils/useUserList';
@@ -38,13 +38,14 @@ import usePrivateMessages from '../utils/usePrivateMessages';
38
38
  * It retrieves all the messages from the appropriate stores (Message store an provate message store)
39
39
  * and maps it to a ChatBubble
40
40
  */
41
- const ChatContainer = (props: any) => {
41
+ const ChatContainer = (props?: {
42
+ chatBubble?: React.ComponentType<ChatBubbleProps>;
43
+ }) => {
42
44
  const {renderList} = useUserList();
43
45
  const messageStore = useGroupMessages();
44
46
  const getPrivateMessage = usePrivateMessages();
45
47
  const privateMessageStore = getPrivateMessage();
46
48
  const {height, width} = useWindowDimensions();
47
- const {selectPrivate} = props;
48
49
  const {
49
50
  privateActive,
50
51
  selectedChatUserId: selectedUserID,
@@ -66,20 +67,24 @@ const ChatContainer = (props: any) => {
66
67
  data?.components?.videoCall &&
67
68
  typeof data?.components?.videoCall === 'object'
68
69
  ) {
69
- // commented for v1 release
70
- // if (
71
- // data?.components?.videoCall?.chat &&
72
- // typeof data?.components?.videoCall?.chat === 'object'
73
- // ) {
74
- // if (
75
- // data?.components?.videoCall?.chat?.chatBubble &&
76
- // typeof data?.components?.videoCall?.chat?.chatBubble !== 'object' &&
77
- // isValidReactComponent(data?.components?.videoCall?.chat?.chatBubble)
78
- // ) {
79
- // components.ChatBubbleComponent =
80
- // data?.components?.videoCall?.chat?.chatBubble;
81
- // }
82
- // }
70
+ //commented for v1 release
71
+ if (
72
+ data?.components?.videoCall?.chat &&
73
+ typeof data?.components?.videoCall?.chat === 'object'
74
+ ) {
75
+ if (
76
+ data?.components?.videoCall?.chat?.chatBubble &&
77
+ typeof data?.components?.videoCall?.chat?.chatBubble !== 'object' &&
78
+ isValidReactComponent(data?.components?.videoCall?.chat?.chatBubble)
79
+ ) {
80
+ components.ChatBubbleComponent =
81
+ data?.components?.videoCall?.chat?.chatBubble;
82
+ }
83
+ }
84
+ } else {
85
+ if (props?.chatBubble && isValidReactComponent(props?.chatBubble)) {
86
+ components.ChatBubbleComponent = props?.chatBubble;
87
+ }
83
88
  }
84
89
  return components;
85
90
  });
@@ -124,9 +129,12 @@ const ChatContainer = (props: any) => {
124
129
  <ChatBubbleComponent
125
130
  isLocal={localUid === message.uid}
126
131
  message={message.msg}
127
- timestamp={message.ts}
132
+ createdTimestamp={message.createdTimestamp}
133
+ updatedTimestamp={message.updatedTimestamp}
128
134
  uid={message.uid}
129
135
  key={message.ts}
136
+ msgId={message.msgId}
137
+ isDeleted={message.isDeleted}
130
138
  />
131
139
  </>
132
140
  ))
@@ -135,9 +143,12 @@ const ChatContainer = (props: any) => {
135
143
  <ChatBubbleComponent
136
144
  isLocal={localUid === message.uid}
137
145
  message={message.msg}
138
- timestamp={message.ts}
146
+ createdTimestamp={message.createdTimestamp}
147
+ updatedTimestamp={message.updatedTimestamp}
139
148
  uid={message.uid}
140
149
  key={message.ts}
150
+ msgId={message.msgId}
151
+ isDeleted={message.isDeleted}
141
152
  />
142
153
  ))
143
154
  ) : (
@@ -119,7 +119,10 @@ export const ChatTextInput = (props: ChatTextInputProps) => {
119
119
  /**
120
120
  * Input component for the Chat interface
121
121
  */
122
- const ChatInput = () => {
122
+ const ChatInput = (props: {
123
+ chatInput?: React.ComponentType<ChatTextInputProps>;
124
+ chatSendButton?: React.ComponentType<ChatSendButtonProps>;
125
+ }) => {
123
126
  const {primaryColor} = useContext(ColorContext);
124
127
  const {ChatInputComponent, ChatSendButtonComponent} = useFpe((data) => {
125
128
  let components: {
@@ -133,31 +136,40 @@ const ChatInput = () => {
133
136
  data?.components?.videoCall &&
134
137
  typeof data?.components?.videoCall === 'object'
135
138
  ) {
136
- // commented for v1 release
137
- // if (
138
- // data?.components?.videoCall?.chat &&
139
- // typeof data?.components?.videoCall?.chat === 'object'
140
- // ) {
141
- // if (
142
- // data?.components?.videoCall?.chat?.chatInput &&
143
- // typeof data?.components?.videoCall?.chat?.chatInput !== 'object' &&
144
- // isValidReactComponent(data?.components?.videoCall?.chat?.chatInput)
145
- // ) {
146
- // components.ChatInputComponent =
147
- // data?.components?.videoCall?.chat?.chatInput;
148
- // }
149
- // if (
150
- // data?.components?.videoCall?.chat?.chatSentButton &&
151
- // typeof data?.components?.videoCall?.chat?.chatSentButton !==
152
- // 'object' &&
153
- // isValidReactComponent(
154
- // data?.components?.videoCall?.chat?.chatSentButton,
155
- // )
156
- // ) {
157
- // components.ChatSendButtonComponent =
158
- // data?.components?.videoCall?.chat?.chatSentButton;
159
- // }
160
- // }
139
+ if (
140
+ data?.components?.videoCall?.chat &&
141
+ typeof data?.components?.videoCall?.chat === 'object'
142
+ ) {
143
+ if (
144
+ data?.components?.videoCall?.chat?.chatInput &&
145
+ typeof data?.components?.videoCall?.chat?.chatInput !== 'object' &&
146
+ isValidReactComponent(data?.components?.videoCall?.chat?.chatInput)
147
+ ) {
148
+ components.ChatInputComponent =
149
+ data?.components?.videoCall?.chat?.chatInput;
150
+ }
151
+ if (
152
+ data?.components?.videoCall?.chat?.chatSentButton &&
153
+ typeof data?.components?.videoCall?.chat?.chatSentButton !==
154
+ 'object' &&
155
+ isValidReactComponent(
156
+ data?.components?.videoCall?.chat?.chatSentButton,
157
+ )
158
+ ) {
159
+ components.ChatSendButtonComponent =
160
+ data?.components?.videoCall?.chat?.chatSentButton;
161
+ }
162
+ }
163
+ } else {
164
+ if (props?.chatInput && isValidReactComponent(props.chatInput)) {
165
+ components.ChatInputComponent = props.chatInput;
166
+ }
167
+ if (
168
+ props?.chatSendButton &&
169
+ isValidReactComponent(props.chatSendButton)
170
+ ) {
171
+ components.ChatSendButtonComponent = props.chatSendButton;
172
+ }
161
173
  }
162
174
  return components;
163
175
  });
@@ -117,7 +117,7 @@ const SelectDevice = () => {
117
117
  <View>
118
118
  <View style={{marginTop: 15}}></View>
119
119
  <View>
120
- <SelectVideoDevice />
120
+ {!$config.AUDIO_ROOM && <SelectVideoDevice />}
121
121
  <SelectAudioDevice />
122
122
  </View>
123
123
  <View style={{marginTop: 15}}></View>
@@ -91,7 +91,7 @@ const RecordingProvider = (props: RecordingProviderProps) => {
91
91
  //const recordingStartedText = useString<boolean>('recordingNotificationLabel');
92
92
  const recordingStartedText = (active: boolean) =>
93
93
  active ? 'Recording Started' : 'Recording Stopped';
94
- const {executePresenterQuery} = useRecordingLayoutQuery();
94
+ const {executePresenterQuery, executeNormalQuery} = useRecordingLayoutQuery();
95
95
  const {localUid} = useContext(ChatContext);
96
96
  const {screenShareData} = useScreenContext();
97
97
 
@@ -156,9 +156,20 @@ const RecordingProvider = (props: RecordingProviderProps) => {
156
156
  // 2. set the local recording state to true to update the UI
157
157
  setRecordingActive(true);
158
158
  // 3. set the presenter mode if screen share is active
159
- if (Object.values(screenShareData).some((item) => item.isActive)) {
160
- console.log('Executing presenter query');
161
- executePresenterQuery();
159
+ // 3.a Get the most recent screenshare uid
160
+ const sorted = Object.entries(screenShareData)
161
+ .filter((el) => el[1]?.ts && el[1].ts > 0 && el[1]?.isActive)
162
+ .sort((a, b) => b[1].ts - a[1].ts);
163
+
164
+ const activeScreenshareUid = sorted.length > 0 ? sorted[0][0] : 0;
165
+ if (activeScreenshareUid) {
166
+ console.log(
167
+ 'screenshare: Executing presenter query for screenuid',
168
+ activeScreenshareUid,
169
+ );
170
+ executePresenterQuery(parseInt(activeScreenshareUid));
171
+ } else {
172
+ executeNormalQuery();
162
173
  }
163
174
  }
164
175
  })
@@ -1,8 +1,8 @@
1
- import React, {useContext} from 'react';
1
+ import React from 'react';
2
2
  import {useParams} from '../../components/Router';
3
3
 
4
4
  import {gql, useMutation} from '@apollo/client';
5
- import {PropsContext} from '../../../agora-rn-uikit';
5
+ import {UidType} from '../../../agora-rn-uikit';
6
6
 
7
7
  const SET_PRESENTER = gql`
8
8
  mutation setPresenter($uid: Int!, $passphrase: String!) {
@@ -19,10 +19,16 @@ const SET_NORMAL = gql`
19
19
  function useRecordingLayoutQuery() {
20
20
  const [setPresenterQuery] = useMutation(SET_PRESENTER);
21
21
  const [setNormalQuery] = useMutation(SET_NORMAL);
22
- const {screenShareUid} = useContext(PropsContext).rtcProps;
23
22
  const {phrase} = useParams<any>();
24
-
25
- const executePresenterQuery = () => {
23
+ /**
24
+ * @param screenShareUid
25
+ * Default : Grid
26
+ * Below query changes the layout to vertical and passed UID is maxed view
27
+ * This should be called only when screenshare is actively going on
28
+ * and we want that as the main view
29
+ * https://docs.agora.io/en/cloud-recording/cloud_recording_layout?platform=RESTful
30
+ */
31
+ const executePresenterQuery = (screenShareUid: UidType) => {
26
32
  setPresenterQuery({
27
33
  variables: {
28
34
  uid: screenShareUid,