agora-appbuilder-core 2.0.1 → 2.0.3-rc2

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 (79) hide show
  1. package/Readme.md +2 -1
  2. package/package.json +1 -1
  3. package/template/_package-lock.json +8853 -8806
  4. package/template/agora-rn-uikit/.git/index +0 -0
  5. package/template/agora-rn-uikit/.git/logs/HEAD +2 -2
  6. package/template/agora-rn-uikit/.git/logs/refs/heads/ab-dev-auto +1 -1
  7. package/template/agora-rn-uikit/.git/logs/refs/heads/master +1 -1
  8. package/template/agora-rn-uikit/.git/logs/refs/remotes/origin/HEAD +1 -1
  9. package/template/agora-rn-uikit/.git/objects/pack/pack-2a0122bf5a3199f941e5a52535f43881623f752c.idx +0 -0
  10. package/template/agora-rn-uikit/.git/objects/pack/{pack-f379286d0537eb68377220b4929979324b8d5d1c.pack → pack-2a0122bf5a3199f941e5a52535f43881623f752c.pack} +0 -0
  11. package/template/agora-rn-uikit/.git/packed-refs +4 -2
  12. package/template/agora-rn-uikit/.git/refs/heads/ab-dev-auto +1 -1
  13. package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +21 -0
  14. package/template/agora-rn-uikit/src/Controls/BtnTemplate.tsx +22 -14
  15. package/template/agora-rn-uikit/src/Controls/ImageIcon.tsx +17 -13
  16. package/template/agora-rn-uikit/src/Controls/types.ts +4 -0
  17. package/template/agora-rn-uikit/src/Rtc/Create.tsx +117 -19
  18. package/template/agora-rn-uikit/src/RtcConfigure.tsx +24 -13
  19. package/template/{src/utils/isSafariBrowser.tsx → agora-rn-uikit/src/Utils/isSafariBrowser.ts} +3 -0
  20. package/template/{src → agora-rn-uikit/src}/hooks/useImageDelay.tsx +5 -2
  21. package/template/agora-rn-uikit/src/index.ts +2 -0
  22. package/template/bridge/rtc/webNg/RtcEngine.ts +73 -70
  23. package/template/bridge/rtc/webNg/Types.ts +59 -5
  24. package/template/bridge/rtm/web/Types.ts +13 -0
  25. package/template/bridge/rtm/web/index.ts +78 -1
  26. package/template/global.d.ts +2 -0
  27. package/template/package-lock.json +8853 -8806
  28. package/template/package.json +3 -4
  29. package/template/react-native-toast-message/src/components/base/styles.js +4 -2
  30. package/template/src/assets/icons.ts +41 -28
  31. package/template/src/components/Chat.tsx +70 -184
  32. package/template/src/components/ChatContext.ts +13 -2
  33. package/template/src/components/Controls.native.tsx +37 -76
  34. package/template/src/components/Controls.tsx +50 -158
  35. package/template/src/components/DeviceConfigure.native.tsx +5 -1
  36. package/template/src/components/DeviceConfigure.tsx +38 -20
  37. package/template/src/components/Navbar.tsx +185 -226
  38. package/template/src/components/ParticipantsView.tsx +176 -184
  39. package/template/src/components/Precall.native.tsx +83 -69
  40. package/template/src/components/Precall.tsx +174 -191
  41. package/template/src/components/RTMConfigure.tsx +264 -78
  42. package/template/src/components/SettingsView.tsx +9 -19
  43. package/template/src/components/livestream/LiveStreamContext.tsx +411 -0
  44. package/template/src/components/livestream/Types.ts +69 -0
  45. package/template/src/components/livestream/index.ts +9 -0
  46. package/template/src/components/livestream/views/LiveStreamControls.tsx +27 -0
  47. package/template/src/components/participants/AllAudienceParticipants.tsx +53 -0
  48. package/template/src/components/participants/AllHostParticipants.tsx +65 -0
  49. package/template/src/components/participants/MeParticipant.tsx +37 -0
  50. package/template/src/components/participants/ParticipantName.tsx +47 -0
  51. package/template/src/components/participants/ParticipantSectionTitle.tsx +29 -0
  52. package/template/src/components/participants/RemoteParticipants.tsx +69 -0
  53. package/template/src/components/participants/ScreenshareParticipants.tsx +28 -0
  54. package/template/src/components/participants/context/ParticipantContext.tsx +97 -0
  55. package/template/src/components/styles.ts +13 -0
  56. package/template/src/pages/Create.tsx +25 -14
  57. package/template/src/pages/VideoCall.tsx +197 -159
  58. package/template/src/subComponents/ChatBubble.tsx +4 -1
  59. package/template/src/subComponents/ChatContainer.tsx +44 -20
  60. package/template/src/subComponents/ChatInput.tsx +4 -12
  61. package/template/src/subComponents/Checkbox.native.tsx +6 -5
  62. package/template/src/subComponents/Checkbox.tsx +1 -0
  63. package/template/src/subComponents/Recording.tsx +23 -9
  64. package/template/src/subComponents/RemoteVideoMute.tsx +2 -3
  65. package/template/src/subComponents/SelectDevice.tsx +70 -35
  66. package/template/src/subComponents/chat/ChatParticipants.tsx +121 -0
  67. package/template/src/subComponents/livestream/ApprovedLiveStreamControlsView.tsx +23 -0
  68. package/template/src/subComponents/livestream/CurrentLiveStreamRequestsView.tsx +70 -0
  69. package/template/src/subComponents/livestream/controls/LocalRaiseHand.tsx +57 -0
  70. package/template/src/subComponents/livestream/controls/RemoteLiveStreamApprovedRequestRecall.tsx +24 -0
  71. package/template/src/subComponents/livestream/controls/RemoteLiveStreamRequestApprove.tsx +38 -0
  72. package/template/src/subComponents/livestream/controls/RemoteLiveStreamRequestReject.tsx +37 -0
  73. package/template/src/subComponents/livestream/index.ts +18 -0
  74. package/template/src/subComponents/screenshare/ScreenshareButton.tsx +80 -0
  75. package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +24 -0
  76. package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +200 -0
  77. package/template/src/subComponents/screenshare/ScreenshareContext.tsx +21 -0
  78. package/template/src/utils/index.tsx +48 -0
  79. package/template/agora-rn-uikit/.git/objects/pack/pack-f379286d0537eb68377220b4929979324b8d5d1c.idx +0 -0
@@ -10,8 +10,11 @@
10
10
  *********************************************
11
11
  */
12
12
  import React, {useState, useContext, useEffect, useRef} from 'react';
13
- import RtmEngine from 'agora-react-native-rtm';
14
- import {PropsContext} from '../../agora-rn-uikit';
13
+ import RtmEngine, {
14
+ RtmChannelAttribute,
15
+ RtmAttribute,
16
+ } from 'agora-react-native-rtm';
17
+ import {ClientRole, PropsContext} from '../../agora-rn-uikit';
15
18
  import ChatContext, {controlMessageEnum} from './ChatContext';
16
19
  import {RtcContext} from '../../agora-rn-uikit';
17
20
  import {
@@ -19,10 +22,12 @@ import {
19
22
  messageChannelType,
20
23
  messageSourceType,
21
24
  messageActionType,
25
+ attrRequestTypes,
22
26
  } from './ChatContext';
23
27
  import {Platform} from 'react-native';
24
28
  import {backOff} from 'exponential-backoff';
25
29
  import events from './RTMEvents';
30
+ import {filterObject} from '../utils';
26
31
 
27
32
  export enum UserType {
28
33
  Normal,
@@ -52,6 +57,23 @@ const parsePayload = (data: string) => {
52
57
  return JSON.parse(data);
53
58
  };
54
59
 
60
+ function hasJsonStructure(str: string) {
61
+ if (typeof str !== 'string') return false;
62
+ try {
63
+ const result = JSON.parse(str);
64
+ const type = Object.prototype.toString.call(result);
65
+ return type === '[object Object]' || type === '[object Array]';
66
+ } catch (err) {
67
+ return false;
68
+ }
69
+ }
70
+ function safeJsonParse(str: string) {
71
+ try {
72
+ return [null, JSON.parse(str)];
73
+ } catch (err) {
74
+ return [err];
75
+ }
76
+ }
55
77
  const timeNow = () => new Date().getTime();
56
78
 
57
79
  const RtmConfigure = (props: any) => {
@@ -62,10 +84,36 @@ const RtmConfigure = (props: any) => {
62
84
  const [privateMessageStore, setPrivateMessageStore] = useState({});
63
85
  const [login, setLogin] = useState<boolean>(false);
64
86
  const [userList, setUserList] = useState<{[key: string]: any}>({});
87
+ const [onlineUsersCount, setTotalOnlineUsers] = useState<number>(0);
88
+
65
89
  let engine = useRef<RtmEngine>(null!);
66
90
  let localUid = useRef<string>('');
67
91
  const timerValueRef: any = useRef(5);
68
92
 
93
+ React.useEffect(() => {
94
+ const handBrowserClose = () => {
95
+ engine.current.leaveChannel(rtcProps.channel);
96
+ };
97
+
98
+ if (Platform.OS !== 'web') return;
99
+ window.addEventListener('beforeunload', handBrowserClose);
100
+ // cleanup this component
101
+ return () => {
102
+ window.removeEventListener('beforeunload', handBrowserClose);
103
+ };
104
+ }, []);
105
+
106
+ React.useEffect(() => {
107
+ setTotalOnlineUsers(
108
+ Object.keys(
109
+ filterObject(
110
+ userList,
111
+ ([k, v]) => v?.type === UserType.Normal && !v.offline,
112
+ ),
113
+ ).length,
114
+ );
115
+ }, [userList]);
116
+
69
117
  const addMessageToStore = (uid: string, msg: {body: string; ts: string}) => {
70
118
  setMessageStore((m: messageStoreInterface[]) => {
71
119
  return [...m, {ts: msg.ts, uid: uid, msg: msg.body}];
@@ -96,118 +144,136 @@ const RtmConfigure = (props: any) => {
96
144
  return {...newState};
97
145
  });
98
146
  };
99
-
147
+
100
148
  const doLoginAndSetupRTM = async () => {
101
149
  try {
102
150
  await engine.current.login({
103
151
  uid: localUid.current,
104
152
  token: rtcProps.rtm,
105
153
  });
106
- timerValueRef.current = 5
107
- setAttribute();
154
+ timerValueRef.current = 5;
155
+ setAttribute();
108
156
  } catch (error) {
109
- setTimeout( async () => {
157
+ setTimeout(async () => {
110
158
  timerValueRef.current = timerValueRef.current + timerValueRef.current;
111
159
  doLoginAndSetupRTM();
112
- }, timerValueRef.current * 1000 );
160
+ }, timerValueRef.current * 1000);
113
161
  }
114
- }
162
+ };
115
163
 
116
- const setAttribute = async () => {
164
+ const setAttribute = async () => {
117
165
  try {
118
166
  await engine.current.setLocalUserAttributes([
119
167
  {key: 'name', value: name || 'User'},
120
168
  {key: 'screenUid', value: String(rtcProps.screenShareUid)},
169
+ {key: 'role', value: String(rtcProps?.role)},
170
+ {key: 'requests', value: attrRequestTypes.none}, // stores Uid who have raised a request
121
171
  ]);
122
- timerValueRef.current = 5
123
- joinChannel()
172
+ timerValueRef.current = 5;
173
+ joinChannel();
124
174
  } catch (error) {
125
- setTimeout( async () => {
175
+ setTimeout(async () => {
126
176
  timerValueRef.current = timerValueRef.current + timerValueRef.current;
127
177
  setAttribute();
128
- }, timerValueRef.current * 1000 );
178
+ }, timerValueRef.current * 1000);
129
179
  }
130
- }
180
+ };
181
+
182
+ const addOrUpdateLocalUserAttributes = async (attributes: RtmAttribute[]) => {
183
+ try {
184
+ await engine.current.addOrUpdateLocalUserAttributes(attributes);
185
+ } catch (error) {
186
+ console.log('error while local user addOrUpdateAttributes: ', error);
187
+ }
188
+ };
131
189
 
132
190
  const joinChannel = async () => {
133
191
  try {
134
- await engine.current.joinChannel(rtcProps.channel);
135
- timerValueRef.current = 5
136
- getMembers()
192
+ await engine.current.joinChannel(rtcProps.channel);
193
+ timerValueRef.current = 5;
194
+ getMembers();
137
195
  } catch (error) {
138
- setTimeout( async () => {
196
+ setTimeout(async () => {
139
197
  timerValueRef.current = timerValueRef.current + timerValueRef.current;
140
198
  joinChannel();
141
- }, timerValueRef.current * 1000 );
142
- }
143
- }
199
+ }, timerValueRef.current * 1000);
200
+ }
201
+ };
144
202
 
145
203
  const getMembers = async () => {
146
204
  try {
147
205
  await engine.current
148
- .getChannelMembersBychannelId(rtcProps.channel)
149
- .then((data) => {
150
- data.members.map(async (member: any) => {
151
- const backoffAttributes = backOff(
152
- async () => {
153
- const attr = await engine.current.getUserAttributesByUid(
154
- member.uid,
155
- );
156
- if (attr?.attributes?.name && attr?.attributes?.screenUid) {
157
- return attr;
158
- } else {
159
- throw attr;
160
- }
161
- },
162
- {
163
- retry: (e, idx) => {
164
- console.log(
165
- `[retrying] Attempt ${idx}. Fetching ${member.uid}'s name`,
166
- e,
206
+ .getChannelMembersBychannelId(rtcProps.channel)
207
+ .then((data) => {
208
+ data.members.map(async (member: any) => {
209
+ const backoffAttributes = backOff(
210
+ async () => {
211
+ const attr = await engine.current.getUserAttributesByUid(
212
+ member.uid,
167
213
  );
168
- return true;
214
+ if (
215
+ attr?.attributes?.name &&
216
+ attr?.attributes?.screenUid &&
217
+ attr?.attributes?.role &&
218
+ attr?.attributes?.requests
219
+ ) {
220
+ return attr;
221
+ } else {
222
+ throw attr;
223
+ }
169
224
  },
170
- },
171
- );
172
- try {
173
- const attr = await backoffAttributes;
174
- console.log('[user attributes]:', {attr});
175
- setUserList((prevState) => {
176
- return {
177
- ...prevState,
178
- [member.uid]: {
179
- name: attr?.attributes?.name || 'User',
180
- type: UserType.Normal,
181
- screenUid: parseInt(attr?.attributes?.screenUid),
182
- },
183
- [parseInt(attr?.attributes?.screenUid)]: {
184
- name: `${attr?.attributes?.name || 'User'}'s screenshare`,
185
- type: UserType.ScreenShare,
225
+ {
226
+ retry: (e, idx) => {
227
+ console.log(
228
+ `[retrying] Attempt ${idx}. Fetching ${member.uid}'s name`,
229
+ e,
230
+ );
231
+ return true;
186
232
  },
187
- };
188
- });
189
- } catch (e) {
190
- console.error(`Could not retrieve name of ${member.uid}`, e);
191
- }
233
+ },
234
+ );
235
+ try {
236
+ const attr = await backoffAttributes;
237
+ console.log('[user attributes]:', {attr});
238
+ setUserList((prevState) => {
239
+ return {
240
+ ...prevState,
241
+ [member.uid]: {
242
+ name: attr?.attributes?.name || 'User',
243
+ type: UserType.Normal,
244
+ role: parseInt(attr?.attributes?.role),
245
+ screenUid: parseInt(attr?.attributes?.screenUid),
246
+ offline: false,
247
+ requests: attr?.attributes?.requests,
248
+ },
249
+ [parseInt(attr?.attributes?.screenUid)]: {
250
+ name: `${attr?.attributes?.name || 'User'}'s screenshare`,
251
+ type: UserType.ScreenShare,
252
+ },
253
+ };
254
+ });
255
+ } catch (e) {
256
+ console.error(`Could not retrieve name of ${member.uid}`, e);
257
+ }
258
+ });
259
+ setLogin(true);
260
+ console.log('RTM init done');
192
261
  });
193
- setLogin(true);
194
- console.log('RTM init done');
195
- });
196
- timerValueRef.current = 5
262
+ timerValueRef.current = 5;
197
263
  } catch (error) {
198
- setTimeout( async () => {
264
+ setTimeout(async () => {
199
265
  timerValueRef.current = timerValueRef.current + timerValueRef.current;
200
266
  getMembers();
201
- }, timerValueRef.current * 1000 );
202
- }
203
- }
267
+ }, timerValueRef.current * 1000);
268
+ }
269
+ };
204
270
  const init = async () => {
205
271
  engine.current = new RtmEngine();
206
272
  rtcProps.uid
207
273
  ? (localUid.current = rtcProps.uid + '')
208
274
  : (localUid.current = '' + timeNow());
209
275
  engine.current.on('connectionStateChanged', (evt: any) => {
210
- //console.log(evt);
276
+ //console.log(evt);
211
277
  });
212
278
  engine.current.on('error', (evt: any) => {
213
279
  // console.log(evt);
@@ -216,7 +282,12 @@ const RtmConfigure = (props: any) => {
216
282
  const backoffAttributes = backOff(
217
283
  async () => {
218
284
  const attr = await engine.current.getUserAttributesByUid(data.uid);
219
- if (attr?.attributes?.name && attr?.attributes?.screenUid) {
285
+ if (
286
+ attr?.attributes?.name &&
287
+ attr?.attributes?.screenUid &&
288
+ attr?.attributes?.role &&
289
+ attr?.attributes?.requests
290
+ ) {
220
291
  return attr;
221
292
  } else {
222
293
  throw attr;
@@ -242,7 +313,10 @@ const RtmConfigure = (props: any) => {
242
313
  [data.uid]: {
243
314
  name: attr?.attributes?.name || 'User',
244
315
  type: UserType.Normal,
316
+ role: parseInt(attr?.attributes?.role),
245
317
  screenUid: parseInt(attr?.attributes?.screenUid),
318
+ offline: false,
319
+ requests: attr?.attributes?.requests,
246
320
  },
247
321
  [parseInt(attr?.attributes?.screenUid)]: {
248
322
  name: `${attr?.attributes?.name || 'User'}'s screenshare`,
@@ -256,10 +330,24 @@ const RtmConfigure = (props: any) => {
256
330
  }
257
331
  getname();
258
332
  });
333
+
259
334
  engine.current.on('channelMemberLeft', (data: any) => {
260
335
  console.log('user left', data);
261
336
  // Chat of left user becomes undefined. So don't cleanup
337
+ const {uid} = data;
338
+ if (!uid) return;
339
+ setUserList((prevState) => {
340
+ return {
341
+ ...prevState,
342
+ [uid]: {
343
+ ...prevState[uid],
344
+ requests: attrRequestTypes.none,
345
+ offline: true,
346
+ },
347
+ };
348
+ });
262
349
  });
350
+
263
351
  engine.current.on('messageReceived', (evt: any) => {
264
352
  const {peerId, ts, text} = evt;
265
353
  const textObj = parsePayload(text);
@@ -296,7 +384,8 @@ const RtmConfigure = (props: any) => {
296
384
  });
297
385
  break;
298
386
  default:
299
- throw new Error('Unsupported message type');
387
+ break;
388
+ // throw new Error('Unsupported message type');
300
389
  }
301
390
  } catch (e) {
302
391
  events.emit(messageChannelType.Private, null, {
@@ -334,18 +423,26 @@ const RtmConfigure = (props: any) => {
334
423
  const {uid, channelId, text, ts} = evt;
335
424
  const textObj = parsePayload(text);
336
425
  const {type, msg} = textObj;
337
-
338
426
  let arr = new Int32Array(1);
339
427
  arr[0] = parseInt(uid);
340
428
 
341
429
  const userUID = Platform.OS ? arr[0] : uid;
342
- console.log('userId', userUID);
343
430
  const timestamp = ts === 0 ? timeNow() : ts;
344
431
 
345
432
  if (channelId === rtcProps.channel) {
346
433
  if (type === messageActionType.Control) {
434
+ let actionMsg = '';
435
+ if (hasJsonStructure(msg)) {
436
+ const [err, result] = safeJsonParse(msg);
437
+ if (!err) {
438
+ const {action} = result;
439
+ actionMsg = action;
440
+ }
441
+ } else {
442
+ actionMsg = msg;
443
+ }
347
444
  try {
348
- switch (msg) {
445
+ switch (actionMsg) {
349
446
  case controlMessageEnum.muteVideo:
350
447
  RtcEngine.muteLocalVideoStream(true);
351
448
  dispatch({
@@ -366,8 +463,28 @@ const RtmConfigure = (props: any) => {
366
463
  case controlMessageEnum.cloudRecordingUnactive:
367
464
  setRecordingActive(false);
368
465
  break;
466
+ case controlMessageEnum.clientRoleChanged:
467
+ const {payload} = JSON.parse(msg);
468
+ if (payload && payload?.role) {
469
+ if (
470
+ payload.role.trim() !== '' &&
471
+ payload.role in ClientRole
472
+ ) {
473
+ setUserList((prevState) => {
474
+ return {
475
+ ...prevState,
476
+ [uid]: {
477
+ ...prevState[uid],
478
+ role: parseInt(payload.role),
479
+ },
480
+ };
481
+ });
482
+ }
483
+ }
484
+ break;
369
485
  default:
370
- throw new Error('Unsupported message type');
486
+ break;
487
+ // throw new Error('Unsupported message type');
371
488
  }
372
489
  } catch (e) {
373
490
  events.emit(messageChannelType.Public, null, {
@@ -395,9 +512,20 @@ const RtmConfigure = (props: any) => {
395
512
  });
396
513
  });
397
514
 
515
+ engine.current.addListener(
516
+ 'ChannelAttributesUpdated',
517
+ (attributes: RtmChannelAttribute[]) => {
518
+ /**
519
+ * a) The following piece of code is commented for future reference.
520
+ * b) To be used in future implementations of channel attributes
521
+ * c) Kindly note the agora-react-native-rtm does not return the attributes with
522
+ * additional lastUpdateUserId and lastUpdateTs as mentioned in RtmChannelAttribute type
523
+ */
524
+ },
525
+ );
526
+
398
527
  await engine.current.createClient(rtcProps.appId);
399
528
  doLoginAndSetupRTM();
400
-
401
529
  };
402
530
 
403
531
  const sendMessage = async (msg: string) => {
@@ -416,6 +544,7 @@ const RtmConfigure = (props: any) => {
416
544
  ts: timeNow(),
417
545
  });
418
546
  };
547
+
419
548
  const sendMessageToUid = async (msg: string, uid: number) => {
420
549
  if (msg.trim() === '') return;
421
550
  let adjustedUID = uid;
@@ -479,6 +608,24 @@ const RtmConfigure = (props: any) => {
479
608
  : {};
480
609
  };
481
610
 
611
+ const updateChannelAttributes = async (attributes: RtmChannelAttribute[]) => {
612
+ /**
613
+ * a) The following piece of code is commented for future reference.
614
+ * b) To be used in future implementations of channel attributes
615
+ * c) attributes should be an array of key value [{key:"keyTobeUsed", value; 'valueToBeUsed}]
616
+ * following the type RtmChannelAttribute
617
+ */
618
+ // try {
619
+ // await (engine.current as RtmEngine).addOrUpdateChannelAttributes(
620
+ // rtcProps.channel,
621
+ // [...attributes],
622
+ // {enableNotificationToChannelMembers: true},
623
+ // );
624
+ // } catch (error) {
625
+ // console.log('AttributesUpdated error', error);
626
+ // }
627
+ };
628
+
482
629
  useEffect(() => {
483
630
  callActive ? init() : (console.log('waiting to init RTM'), setLogin(true));
484
631
  return () => {
@@ -487,6 +634,42 @@ const RtmConfigure = (props: any) => {
487
634
  // eslint-disable-next-line react-hooks/exhaustive-deps
488
635
  }, [rtcProps.channel, rtcProps.appId, callActive]);
489
636
 
637
+ const broadcastUserAttributes = async (
638
+ attributes: RtmAttribute[],
639
+ ctrlMsg: controlMessageEnum,
640
+ ) => {
641
+ // 1. Update my attributes in attribute-list
642
+ await addOrUpdateLocalUserAttributes(attributes);
643
+
644
+ let formattedAttributes: any = {};
645
+ // Transform the array into object of key value pair
646
+ attributes.map((attribute) => {
647
+ let key = Object.values(attribute)[0];
648
+ let value = Object.values(attribute)[1];
649
+ formattedAttributes[key] = value;
650
+ });
651
+ // 2. Update my attributes in user-list
652
+ setUserList((prevState) => {
653
+ return {
654
+ ...prevState,
655
+ [localUid.current]: {
656
+ ...prevState[localUid.current],
657
+ ...formattedAttributes,
658
+ },
659
+ };
660
+ });
661
+
662
+ /**
663
+ * 3. Broadcast my updated attributes to everyone
664
+ * send payload and control message as string
665
+ */
666
+ const msgAsString = JSON.stringify({
667
+ action: ctrlMsg,
668
+ payload: {...formattedAttributes},
669
+ });
670
+ sendControlMessage(msgAsString);
671
+ };
672
+
490
673
  return (
491
674
  <ChatContext.Provider
492
675
  value={{
@@ -496,9 +679,12 @@ const RtmConfigure = (props: any) => {
496
679
  sendControlMessageToUid,
497
680
  sendMessage,
498
681
  sendMessageToUid,
682
+ broadcastUserAttributes,
683
+ addOrUpdateLocalUserAttributes,
499
684
  engine: engine.current,
500
685
  localUid: localUid.current,
501
686
  userList: userList,
687
+ onlineUsersCount,
502
688
  events,
503
689
  }}>
504
690
  {login ? props.children : <></>}
@@ -9,19 +9,10 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React, {useContext} from 'react';
13
- import {
14
- View,
15
- Text,
16
- StyleSheet,
17
- Platform,
18
- TouchableOpacity,
19
- Image,
20
- } from 'react-native';
12
+ import React from 'react';
13
+ import {View, Text, StyleSheet, Platform} from 'react-native';
21
14
  import SelectDevice from '../subComponents/SelectDevice';
22
15
  import HostControlView from './HostControlView';
23
- import ColorContext from './ColorContext';
24
- import {SidePanelType} from '../subComponents/SidePanelEnum';
25
16
 
26
17
  const SettingsView = (props: any) => {
27
18
  const {isHost} = props;
@@ -31,9 +22,11 @@ const SettingsView = (props: any) => {
31
22
  Platform.OS === 'web' ? style.settingsView : style.settingsViewNative
32
23
  }>
33
24
  <View style={style.main}>
34
- <Text style={style.heading}>Select Input Device</Text>
35
- <View style={style.popupPickerHolder}>
36
- <SelectDevice />
25
+ <View>
26
+ <Text style={style.heading}>Select Input Device</Text>
27
+ <View style={style.popupPickerHolder}>
28
+ <SelectDevice />
29
+ </View>
37
30
  </View>
38
31
  {isHost ? <HostControlView /> : <></>}
39
32
  </View>
@@ -49,21 +42,18 @@ const style = StyleSheet.create({
49
42
  paddingVertical: 5,
50
43
  flexGrow: 1,
51
44
  shadowColor: $config.PRIMARY_FONT_COLOR + '80',
52
- shadowOpacity: .5,
53
- shadowOffset: {width:-2, height: 0},
45
+ shadowOpacity: 0.5,
46
+ shadowOffset: {width: -2, height: 0},
54
47
  shadowRadius: 3,
55
48
  paddingHorizontal: 20,
56
49
  },
57
50
  popupPickerHolder: {
58
- // height: '40%',
59
51
  justifyContent: 'space-around',
60
- // paddingHorizontal: '8%',
61
52
  },
62
53
  heading: {
63
54
  fontSize: 20,
64
55
  fontWeight: '700',
65
56
  color: $config.PRIMARY_FONT_COLOR,
66
- // marginBottom: 20,
67
57
  alignSelf: 'center',
68
58
  },
69
59
  settingsView: {