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

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": "2.3.0-beta.1",
3
+ "version": "2.3.0-beta.2",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -6,4 +6,4 @@ import {EventSourceEnum} from '../src/custom-events';
6
6
  const fpeEvents = new CustomEvents(EventSourceEnum.fpe);
7
7
 
8
8
  // 3. export
9
- export {fpeEvents};
9
+ export {fpeEvents as CustomEvents};
@@ -53,63 +53,43 @@ const ParticipantView = () => {
53
53
  <View style={style.lineUnderHeading}>
54
54
  <Text style={style.mainHeading}>{participantsLabel}</Text>
55
55
  </View>
56
- <ScrollView style={[style.bodyContainer, style.padding10]}>
57
- {$config.EVENT_MODE ? (
58
- <>
59
- {
60
- /*Live streaming is true
56
+ </View>
57
+ <ScrollView style={[style.bodyContainer, style.padding10]}>
58
+ {$config.EVENT_MODE ? (
59
+ <>
60
+ {
61
+ /*Live streaming is true
61
62
  Host and New host view */
62
- rtcProps?.role == ClientRole.Broadcaster &&
63
- (isHost ? (
64
- /**
65
- * Original Host
66
- * a) Can view streaming requests
67
- * b) Can view all hosts with remote controls
68
- */
69
- <>
70
- {/* a) Live streaming view */}
71
- <View style={style.participantsection}>
72
- <CurrentLiveStreamRequestsView
73
- p_style={style}
74
- userList={liveStreamData}
75
- />
76
- </View>
77
- {/* b) Host view with remote controls*/}
78
- <View style={style.participantsection}>
79
- <ParticipantSectionTitle
80
- title={hostLabel}
81
- count={hostUids.length}
82
- />
83
- <View style={style.participantContainer}>
84
- <AllHostParticipants
85
- p_style={style}
86
- isHost={isHost}
87
- />
88
- </View>
89
- </View>
90
- </>
91
- ) : (
92
- /** New Host ( earlier was 'audience' and now is host )
93
- * a) Can view all hosts without remote controls
94
- */
63
+ rtcProps?.role == ClientRole.Broadcaster &&
64
+ (isHost ? (
65
+ /**
66
+ * Original Host
67
+ * a) Can view streaming requests
68
+ * b) Can view all hosts with remote controls
69
+ */
70
+ <>
71
+ {/* a) Live streaming view */}
72
+ <View style={style.participantsection}>
73
+ <CurrentLiveStreamRequestsView
74
+ p_style={style}
75
+ userList={liveStreamData}
76
+ />
77
+ </View>
78
+ {/* b) Host view with remote controls*/}
95
79
  <View style={style.participantsection}>
96
80
  <ParticipantSectionTitle
97
81
  title={hostLabel}
98
82
  count={hostUids.length}
99
83
  />
100
- <AllAudienceParticipants
101
- uids={hostUids}
102
- p_style={style}
103
- isHost={isHost}
104
- />
84
+ <View style={style.participantContainer}>
85
+ <AllHostParticipants p_style={style} isHost={isHost} />
86
+ </View>
105
87
  </View>
106
- ))
107
- }
108
- {
109
- /**
110
- * Audience views all hosts without remote controls
111
- */
112
- rtcProps?.role == ClientRole.Audience && (
88
+ </>
89
+ ) : (
90
+ /** New Host ( earlier was 'audience' and now is host )
91
+ * a) Can view all hosts without remote controls
92
+ */
113
93
  <View style={style.participantsection}>
114
94
  <ParticipantSectionTitle
115
95
  title={hostLabel}
@@ -121,32 +101,50 @@ const ParticipantView = () => {
121
101
  isHost={isHost}
122
102
  />
123
103
  </View>
124
- )
125
- }
126
- {
127
- /* Everyone can see audience */
104
+ ))
105
+ }
106
+ {
107
+ /**
108
+ * Audience views all hosts without remote controls
109
+ */
110
+ rtcProps?.role == ClientRole.Audience && (
128
111
  <View style={style.participantsection}>
129
112
  <ParticipantSectionTitle
130
- title={audienceLabel}
131
- count={audienceUids.length}
113
+ title={hostLabel}
114
+ count={hostUids.length}
132
115
  />
133
116
  <AllAudienceParticipants
134
- uids={audienceUids}
117
+ uids={hostUids}
135
118
  p_style={style}
136
119
  isHost={isHost}
137
120
  />
138
121
  </View>
139
- }
140
- </>
141
- ) : (
142
- <View style={style.participantsection}>
143
- <View style={style.participantContainer}>
144
- <AllHostParticipants p_style={style} isHost={isHost} />
122
+ )
123
+ }
124
+ {
125
+ /* Everyone can see audience */
126
+ <View style={style.participantsection}>
127
+ <ParticipantSectionTitle
128
+ title={audienceLabel}
129
+ count={audienceUids.length}
130
+ />
131
+ <AllAudienceParticipants
132
+ uids={audienceUids}
133
+ p_style={style}
134
+ isHost={isHost}
135
+ />
145
136
  </View>
137
+ }
138
+ </>
139
+ ) : (
140
+ <View style={style.participantsection}>
141
+ <View style={style.participantContainer}>
142
+ <AllHostParticipants p_style={style} isHost={isHost} />
146
143
  </View>
147
- )}
148
- </ScrollView>
149
- </View>
144
+ </View>
145
+ )}
146
+ </ScrollView>
147
+
150
148
  <View
151
149
  style={{
152
150
  width: '100%',
@@ -22,9 +22,15 @@ import {useString} from '../utils/useString';
22
22
  import {isAndroid, isWeb} from '../utils/common';
23
23
  import StorageContext from './StorageContext';
24
24
  import {useRenderContext} from 'fpe-api';
25
- import {safeJsonParse, timeNow, hasJsonStructure} from '../rtm/utils';
25
+ import {
26
+ safeJsonParse,
27
+ timeNow,
28
+ hasJsonStructure,
29
+ getMessageTime,
30
+ get32BitUid,
31
+ adjustUID,
32
+ } from '../rtm/utils';
26
33
  import {EventUtils, EventsQueue, eventMessageType} from '../rtm-events';
27
-
28
34
  import RTMEngine from '../rtm/RTMEngine';
29
35
  import {filterObject} from '../utils';
30
36
 
@@ -32,18 +38,6 @@ export enum UserType {
32
38
  ScreenShare = 'screenshare',
33
39
  }
34
40
 
35
- const adjustUID = (uid: number | string) => {
36
- let number: number | string;
37
- if (typeof uid === 'string') number = uid;
38
- else {
39
- number = uid;
40
- if (number < 0) {
41
- number = 0xffffffff + number + 1;
42
- }
43
- }
44
- return number;
45
- };
46
-
47
41
  const stringifyPayload = (
48
42
  source: messageSourceType,
49
43
  type: messageActionType,
@@ -370,12 +364,9 @@ const RtmConfigure = (props: any) => {
370
364
  const textObj = parsePayload(text);
371
365
  const {type, msg} = textObj;
372
366
 
373
- let arr = new Int32Array(1);
374
- arr[0] = parseInt(peerId);
367
+ const timestamp = getMessageTime(ts);
375
368
 
376
- const timestamp = timeNow();
377
-
378
- const sender = isAndroid ? arr[0] : peerId;
369
+ const sender = isAndroid ? get32BitUid(peerId) : peerId;
379
370
 
380
371
  if (type === messageActionType.Control) {
381
372
  switch (msg) {
@@ -417,11 +408,10 @@ const RtmConfigure = (props: any) => {
417
408
  const textObj = parsePayload(text);
418
409
  const [err, result] = safeJsonParse(text);
419
410
  const {type, msg} = textObj;
420
- let arr = new Int32Array(1);
421
- arr[0] = parseInt(uid);
422
411
 
423
- const sender = Platform.OS ? arr[0] : uid;
424
- const timestamp = ts ? (parseInt(ts) === 0 ? timeNow() : ts) : timeNow();
412
+ const timestamp = getMessageTime(ts);
413
+
414
+ const sender = Platform.OS ? get32BitUid(uid) : uid;
425
415
 
426
416
  if (channelId === rtcProps.channel) {
427
417
  if (
@@ -534,10 +524,9 @@ const RtmConfigure = (props: any) => {
534
524
 
535
525
  const sendMessageToUid = async (msg: string, uid: UidType) => {
536
526
  if (msg.trim() === '') return;
537
- let adjustedUID = uid;
538
- if (adjustedUID < 0) {
539
- adjustedUID = adjustUID(uid);
540
- }
527
+
528
+ const adjustedUID = adjustUID(uid);
529
+
541
530
  const text = stringifyPayload(
542
531
  messageSourceType.Core,
543
532
  messageActionType.Normal,
@@ -563,16 +552,17 @@ const RtmConfigure = (props: any) => {
563
552
  };
564
553
 
565
554
  const sendControlMessageToUid = async (msg: string, uid: UidType) => {
566
- if (uid < 0) {
567
- uid = adjustUID(uid);
568
- }
555
+ if (msg.trim() === '') return;
556
+
557
+ const adjustedUID = adjustUID(uid);
558
+
569
559
  const text = stringifyPayload(
570
560
  messageSourceType.Core,
571
561
  messageActionType.Control,
572
562
  msg,
573
563
  );
574
564
  await (engine.current as RtmEngine).sendMessageToPeer({
575
- peerId: uid.toString(),
565
+ peerId: adjustedUID.toString(),
576
566
  offline: false,
577
567
  text,
578
568
  });
@@ -13,16 +13,14 @@ import {createHook} from 'fpe-implementation';
13
13
  import React, {useState, useEffect, useRef} from 'react';
14
14
  import {useRenderContext} from 'fpe-api';
15
15
  import {SidePanelType} from '../../subComponents/SidePanelEnum';
16
- import {useLocalUid} from '../../../agora-rn-uikit';
16
+ import {useLocalUid, UidType} from '../../../agora-rn-uikit';
17
17
  import CustomEvents from '../../custom-events';
18
18
  import {EventNames} from '../../rtm-events';
19
19
  import {useChatUIControl} from '../chat-ui/useChatUIControl';
20
20
  import {useChatNotification} from '../chat-notification/useChatNotification';
21
- import {useString} from '../../utils/useString';
22
21
  import Toast from '../../../react-native-toast-message';
23
22
  import {timeNow} from '../../rtm/utils';
24
23
  import {useSidePanel} from '../../utils/useSidePanel';
25
- import {UidType} from '../../../agora-rn-uikit';
26
24
 
27
25
  interface ChatMessagesProviderProps {
28
26
  children: React.ReactNode;
@@ -32,13 +30,13 @@ interface messageInterface {
32
30
  msg: string;
33
31
  }
34
32
  interface messageStoreInterface extends messageInterface {
35
- uid: string;
33
+ uid: UidType;
36
34
  }
37
35
 
38
36
  interface ChatMessagesInterface {
39
37
  messageStore: messageStoreInterface | any;
40
38
  privateMessageStore: any;
41
- sendChatMessage: (msg: string, toUid?: number) => void;
39
+ sendChatMessage: (msg: string, toUid?: UidType) => void;
42
40
  }
43
41
 
44
42
  const ChatMessagesContext = React.createContext<ChatMessagesInterface>({
@@ -94,7 +92,7 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
94
92
  };
95
93
  CustomEvents.on(EventNames.PUBLIC_CHAT_MESSAGE, (data) => {
96
94
  showMessageNotification(data.payload.value, data.sender);
97
- addMessageToStore(data.sender, {
95
+ addMessageToStore(parseInt(data.sender), {
98
96
  msg: data.payload.value,
99
97
  ts: data.ts,
100
98
  });
@@ -111,34 +109,41 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
111
109
  CustomEvents.on(EventNames.PRIVATE_CHAT_MESSAGE, (data) => {
112
110
  showMessageNotification(data.payload.value, data.sender);
113
111
  addMessageToPrivateStore(
114
- data.sender,
112
+ parseInt(data.sender),
115
113
  {
116
114
  msg: data.payload.value,
117
115
  ts: data.ts,
118
116
  },
119
117
  false,
120
118
  );
121
- if (!(individualActiveRef.current === data.sender)) {
119
+ /**
120
+ * if user's private window is active.
121
+ * then we will not increment the unread count
122
+ */
123
+
124
+ if (!(individualActiveRef.current === parseInt(data.sender))) {
122
125
  setUnreadIndividualMessageCount((prevState) => {
123
126
  const prevCount =
124
- prevState && prevState[data.sender] ? prevState[data.sender] : 0;
127
+ prevState && prevState[parseInt(data.sender)]
128
+ ? prevState[parseInt(data.sender)]
129
+ : 0;
125
130
  return {
126
131
  ...prevState,
127
- [data.sender]: prevCount + 1,
132
+ [parseInt(data.sender)]: prevCount + 1,
128
133
  };
129
134
  });
130
135
  }
131
136
  });
132
137
  }, []);
133
138
 
134
- const addMessageToStore = (uid: string, body: messageInterface) => {
139
+ const addMessageToStore = (uid: UidType, body: messageInterface) => {
135
140
  setMessageStore((m: messageStoreInterface[]) => {
136
141
  return [...m, {ts: body.ts, uid, msg: body.msg}];
137
142
  });
138
143
  };
139
144
 
140
145
  const addMessageToPrivateStore = (
141
- uid: string,
146
+ uid: UidType,
142
147
  body: messageInterface,
143
148
  local: boolean,
144
149
  ) => {
@@ -158,6 +163,7 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
158
163
  };
159
164
 
160
165
  const sendChatMessage = (msg: string, toUid?: UidType) => {
166
+ if (typeof msg == 'string' && msg.trim() === '') return;
161
167
  if (toUid) {
162
168
  CustomEvents.send(
163
169
  EventNames.PRIVATE_CHAT_MESSAGE,
@@ -167,7 +173,7 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
167
173
  toUid,
168
174
  );
169
175
  addMessageToPrivateStore(
170
- toUid.toString(),
176
+ toUid,
171
177
  {
172
178
  msg: msg,
173
179
  ts: timeNow(),
@@ -178,7 +184,7 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
178
184
  CustomEvents.send(EventNames.PUBLIC_CHAT_MESSAGE, {
179
185
  value: msg,
180
186
  });
181
- addMessageToStore(localUid.toString(), {
187
+ addMessageToStore(localUid, {
182
188
  msg: msg,
183
189
  ts: timeNow(),
184
190
  });
@@ -19,30 +19,35 @@ export default function AllHostParticipants(props: any) {
19
19
 
20
20
  return (
21
21
  <>
22
- {renderPosition.map((uid) =>
23
- uid === localUid ? (
24
- <MeParticipant
25
- name={getParticipantName(uid)}
26
- p_style={p_style}
27
- key={uid}
28
- />
29
- ) : renderList[uid]?.type === 'screenshare' ? (
30
- <ScreenshareParticipants
31
- name={getParticipantName(uid)}
32
- p_styles={p_style}
33
- key={uid}
34
- />
35
- ) : (
36
- <RemoteParticipants
37
- name={getParticipantName(uid)}
38
- p_styles={p_style}
39
- user={renderList[uid]}
40
- showControls={renderList[uid]?.type === 'rtc'}
41
- isHost={isHost}
42
- key={uid}
43
- />
44
- ),
22
+ {/* User should see his name first */}
23
+ {renderPosition.filter((uid) => uid === localUid).length > 0 && (
24
+ <MeParticipant
25
+ name={getParticipantName(localUid)}
26
+ p_style={p_style}
27
+ key={localUid}
28
+ />
45
29
  )}
30
+ {/* Others Users in the call */}
31
+ {renderPosition
32
+ .filter((uid) => uid !== localUid)
33
+ .map((uid) =>
34
+ renderList[uid]?.type === 'screenshare' ? (
35
+ <ScreenshareParticipants
36
+ name={getParticipantName(uid)}
37
+ p_styles={p_style}
38
+ key={uid}
39
+ />
40
+ ) : (
41
+ <RemoteParticipants
42
+ name={getParticipantName(uid)}
43
+ p_styles={p_style}
44
+ user={renderList[uid]}
45
+ showControls={renderList[uid]?.type === 'rtc'}
46
+ isHost={isHost}
47
+ key={uid}
48
+ />
49
+ ),
50
+ )}
46
51
  </>
47
52
  );
48
53
  }
@@ -45,8 +45,12 @@ interface ShareLinkProvideProps {
45
45
  }
46
46
 
47
47
  const ShareLinkProvider = (props: ShareLinkProvideProps) => {
48
- const {meetingTitle, meetingPassphrase, isSeparateHostLink} =
49
- useMeetingInfo();
48
+ const {
49
+ meetingTitle,
50
+ meetingPassphrase,
51
+ isSeparateHostLink,
52
+ isJoinDataFetched,
53
+ } = useMeetingInfo();
50
54
 
51
55
  //commmented for v1 release
52
56
  // const copiedToClipboardText = useString(
@@ -61,7 +65,7 @@ const ShareLinkProvider = (props: ShareLinkProvideProps) => {
61
65
  const meetingIdText = 'Meeting ID';
62
66
  const PSTNNumberText = 'PSTN Number';
63
67
  const PSTNPinText = 'PSTN Pin';
64
- const meetingInviteText = ({meetingName, id, url, pstn}) => {
68
+ const meetingInviteText = ({meetingName, id, url, pstn, isCallActive}) => {
65
69
  let inviteContent = '';
66
70
  if (url) {
67
71
  // if host data is present generate links for both host and attendee
@@ -70,7 +74,13 @@ const ShareLinkProvider = (props: ShareLinkProvideProps) => {
70
74
  }
71
75
  // if host data is not present then generate link for attendee alone
72
76
  else {
73
- inviteContent += `Meeting - ${meetingName}\nMeeting URL: ${url?.attendee}`;
77
+ if (isCallActive) {
78
+ //copy this label on videocall screen
79
+ inviteContent += `Meeting - ${meetingName}\nURL for Attendee: ${url?.attendee}`;
80
+ } else {
81
+ //copy this label on share link screen
82
+ inviteContent += `Meeting - ${meetingName}\nMeeting URL: ${url?.attendee}`;
83
+ }
74
84
  }
75
85
  } else {
76
86
  // if host data is present generate meeting ID for both host and attendee
@@ -79,7 +89,13 @@ const ShareLinkProvider = (props: ShareLinkProvideProps) => {
79
89
  }
80
90
  // if host data is not present then generate meeting ID for attendee alone
81
91
  else {
82
- inviteContent += `Meeting - ${meetingName}\nMeeting ID: ${id?.attendee}`;
92
+ if (isCallActive) {
93
+ //copy this label on videocall screen
94
+ inviteContent += `Meeting - ${meetingName}\nAttendee Meeting ID: ${id?.attendee}`;
95
+ } else {
96
+ //copy this label on share link screen
97
+ inviteContent += `Meeting - ${meetingName}\nMeeting ID: ${id?.attendee}`;
98
+ }
83
99
  }
84
100
  }
85
101
  // Adding pstn data into meeting data if present
@@ -114,6 +130,7 @@ const ShareLinkProvider = (props: ShareLinkProvideProps) => {
114
130
  pin: meetingPassphrase.pstn.pin,
115
131
  }
116
132
  : undefined,
133
+ isCallActive: isJoinDataFetched,
117
134
  });
118
135
  return stringToCopy;
119
136
  };
@@ -16,10 +16,11 @@ import RTMEngine from '../rtm/RTMEngine';
16
16
  import {ToOptions, EventPayload} from './types';
17
17
  import {EventUtils, eventMessageType} from '../rtm-events';
18
18
  import {TEventCallback, EventSourceEnum} from './types';
19
+ import {adjustUID} from '../rtm/utils';
19
20
 
20
21
  class CustomEvents {
21
- engine!: RtmEngine;
22
- source: EventSourceEnum = EventSourceEnum.core;
22
+ private engine!: RtmEngine;
23
+ private source: EventSourceEnum = EventSourceEnum.core;
23
24
 
24
25
  constructor(source?: EventSourceEnum) {
25
26
  this.engine = RTMEngine.getInstance().engine;
@@ -63,6 +64,7 @@ class CustomEvents {
63
64
  }
64
65
  return true;
65
66
  };
67
+
66
68
  private _validateListener = (listener: TEventCallback): boolean => {
67
69
  if (typeof listener !== 'function') {
68
70
  throw Error(
@@ -73,10 +75,13 @@ class CustomEvents {
73
75
  };
74
76
 
75
77
  /**
76
- * Sends the data across to client using transport layer RTM API's
78
+ * Sets the local attribute of user if persist level is 2 or 3.
79
+ * If param 'to' is not provided, message is sent in the channel.
80
+ * If param 'to' is provided message is sent to that individual.
81
+ * If param 'to' is an array of uids is provided then message is sent to all the individual uids in loop.
77
82
  *
78
83
  * @param {any} rtmPayload payload to be sent across
79
- * @param {ToOptions} to If defined then sent to individual peer in the channle. If not defined then sent to everyone
84
+ * @param {ToOptions} to uid or uids[] of user
80
85
  * @api private
81
86
  */
82
87
  private _send = async (rtmPayload: any, to?: ToOptions) => {
@@ -87,7 +92,7 @@ class CustomEvents {
87
92
  // Case 1: send to channel
88
93
  if (
89
94
  typeof to === 'undefined' ||
90
- (typeof to === 'number' && !to) ||
95
+ (typeof to === 'number' && to <= 0) ||
91
96
  (Array.isArray(to) && to?.length === 0)
92
97
  ) {
93
98
  console.log('CUSTOM_EVENT_API: case 1 executed');
@@ -100,12 +105,12 @@ class CustomEvents {
100
105
  }
101
106
  }
102
107
  // Case 2: send to indivdual
103
- if (typeof to === 'number' && !to) {
108
+ if (typeof to === 'number' && to > 0) {
104
109
  console.log('CUSTOM_EVENT_API: case 2 executed', to);
105
-
110
+ const adjustedUID = adjustUID(to);
106
111
  try {
107
112
  await this.engine.sendMessageToPeer({
108
- peerId: `${to}`,
113
+ peerId: `${adjustedUID}`,
109
114
  offline: false,
110
115
  text,
111
116
  });
@@ -120,9 +125,9 @@ class CustomEvents {
120
125
 
121
126
  try {
122
127
  for (const uid of to) {
123
- // TODO adjust uids
128
+ const adjustedUID = adjustUID(uid);
124
129
  await this.engine.sendMessageToPeer({
125
- peerId: `${uid}`,
130
+ peerId: `${adjustedUID}`,
126
131
  offline: false,
127
132
  text,
128
133
  });
@@ -134,15 +139,35 @@ class CustomEvents {
134
139
  }
135
140
  };
136
141
 
142
+ /**
143
+ * Listens for a specified event.
144
+ * Adds a listener function to the specified event.
145
+ * When the specified event happens, the Events API triggers the callback that you pass.
146
+ * The listener will not be added if it is a duplicate.
147
+ *
148
+ * @param {String} evt Name of the event to attach the listener to.
149
+ * @param {Function} listener Method to be called when the event is emitted.
150
+ * @api public
151
+ */
137
152
  on = (evt: string, listener: TEventCallback) => {
138
153
  if (!this._validateEvt(evt) || !this._validateListener(listener)) return;
139
154
  EventUtils.addListener(evt, listener, this.source);
140
155
  };
141
156
 
142
- off = (evt?: string, listener?: TEventCallback) => {
143
- if (listener) {
144
- if (this._validateListener(listener) && this._validateEvt(evt)) {
145
- EventUtils.removeListener(evt, listener, this.source);
157
+ /**
158
+ * Removes a listener function from the specified event if evt and listener function both are provided.
159
+ * Removes all listeners from a specified event if listener function is not provided.
160
+ * If you do not specify an event then all listeners will be removed.
161
+ * That means every event will be emptied.
162
+ *
163
+ * @param {String} evt Name of the event to remove the listener from.
164
+ * @param {Function} listenerToRemove Method to remove from the event.
165
+ * @api public
166
+ */
167
+ off = (evt?: string, listenerToRemove?: TEventCallback) => {
168
+ if (listenerToRemove) {
169
+ if (this._validateListener(listenerToRemove) && this._validateEvt(evt)) {
170
+ EventUtils.removeListener(evt, listenerToRemove, this.source);
146
171
  }
147
172
  } else if (evt) {
148
173
  if (this._validateEvt(evt)) {
@@ -153,6 +178,20 @@ class CustomEvents {
153
178
  }
154
179
  };
155
180
 
181
+ /**
182
+ * This method sends p2p or channel message depending upon the 'to' value.
183
+ * - If 'to' is provided this method sends p2p message.
184
+ * - If 'to' is empty this method sends channel message.
185
+ *
186
+ *
187
+ * @param {String} evt Name of the event to remove the listener from.
188
+ * @param {EventPayload} payload contains action, level, value metrics.
189
+ * - action: {string}
190
+ * - level: 1 | 2 | 3
191
+ * - value: {string}. NOTICE: value bytelength has MAX_SIZE 32kb limit.
192
+ * @param {ToOptions} to uid or uid array. The default mode is to send a message in channel.
193
+ * @api public
194
+ * */
156
195
  send = async (evt: string, payload: EventPayload, to?: ToOptions) => {
157
196
  if (!this._validateEvt(evt)) return;
158
197
  const {action = '', value = '', level = 1} = payload;
@@ -177,21 +216,6 @@ class CustomEvents {
177
216
  console.log('CUSTOM_EVENT_API: sendPersist sending failed. ', error);
178
217
  }
179
218
  };
180
-
181
- printEvents = () => {
182
- console.log(
183
- 'CUSTOM_EVENT_API: EVENTS source',
184
- EventUtils.getEvents(EventSourceEnum.core),
185
- );
186
- console.log(
187
- 'CUSTOM_EVENT_API: EVENTS fpe',
188
- EventUtils.getEvents(EventSourceEnum.fpe),
189
- );
190
- };
191
- // once = (name: string, listener: any) => {
192
- // console.log('CUSTOM_EVENT_API: Event lifecycle: ONCE');
193
- // const response = EventUtils.addOnceListener(name, listener);
194
- // };
195
219
  }
196
220
 
197
221
  export default CustomEvents;
@@ -26,3 +26,19 @@ export const adjustUID = (uid: number): number => {
26
26
  };
27
27
 
28
28
  export const timeNow = () => new Date().getTime();
29
+
30
+ export const getMessageTime = (ts?: number): number => {
31
+ if (!ts) return timeNow();
32
+ try {
33
+ const timestamp = new Date(ts).getHours();
34
+ return isNaN(timestamp) ? timeNow() : timestamp;
35
+ } catch (error) {
36
+ return timeNow();
37
+ }
38
+ };
39
+
40
+ export const get32BitUid = (peerId: string) => {
41
+ let arr = new Int32Array(1);
42
+ arr[0] = parseInt(peerId);
43
+ return arr[0];
44
+ };
@@ -120,10 +120,9 @@ const EventUtils = (function () {
120
120
  /**
121
121
  * Adds a listener function to the specified event.
122
122
  * The listener will not be added if it is a duplicate.
123
- * If the listener returns true then it will be removed after it is called.
124
123
  *
125
124
  * @param {String} evt Name of the event to attach the listener to.
126
- * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
125
+ * @param {Function} listener Method to be called when the event is emitted.
127
126
  * @param {EventSourceEnum} source Name of the bucket to search events from
128
127
  * @return {Object} Current instance of EventUtils
129
128
  */
@@ -9,7 +9,7 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React, {useContext, useRef} from 'react';
12
+ import React, {useRef} from 'react';
13
13
  import {
14
14
  View,
15
15
  ScrollView,
@@ -21,12 +21,12 @@ import {
21
21
  } from 'react-native';
22
22
  import {RFValue} from 'react-native-responsive-fontsize';
23
23
  import ChatBubble from './ChatBubble';
24
- import ChatContext, {ChatBubbleProps} from '../components/ChatContext';
25
- import {BtnTemplate} from '../../agora-rn-uikit';
24
+ import {ChatBubbleProps} from '../components/ChatContext';
25
+ 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 {isValidReactComponent, isWeb} from '../utils/common';
29
+ import {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';
@@ -50,7 +50,7 @@ const ChatContainer = (props: any) => {
50
50
  selectedChatUserId: selectedUserID,
51
51
  setPrivateActive,
52
52
  } = useChatUIControl();
53
- const {localUid} = useContext(ChatContext);
53
+ const localUid = useLocalUid();
54
54
  //commented for v1 release
55
55
  //const remoteUserDefaultLabel = useString('remoteUserDefaultLabel')();
56
56
  const remoteUserDefaultLabel = 'User';
@@ -34,13 +34,15 @@ export interface ScreenshareButtonProps {
34
34
  }
35
35
 
36
36
  const ScreenshareButton = (props: ScreenshareButtonProps) => {
37
- const {isScreenshareActive, startUserScreenshare} = useScreenshare();
37
+ const {isScreenshareActive, startUserScreenshare, stopUserScreenShare} =
38
+ useScreenshare();
38
39
  //commented for v1 release
39
40
  //const screenShareButton = useString('screenShareButton')();
40
41
  const screenShareButton = 'Share';
41
42
  const defaultTemplateValue = useButtonTemplate().buttonTemplateName;
42
43
  const {buttonTemplateName = defaultTemplateValue} = props;
43
- const onPress = () => startUserScreenshare();
44
+ const onPress = () =>
45
+ isScreenshareActive ? stopUserScreenShare() : startUserScreenshare();
44
46
  let btnTemplateProps: BtnTemplateInterface = {
45
47
  name: isScreenshareActive ? 'screenshareOffIcon' : 'screenshareIcon',
46
48
  onPress,
@@ -40,9 +40,6 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
40
40
  const setPinnedLayout = useSetPinnedLayout();
41
41
  const changeLayout = useChangeDefaultLayout();
42
42
 
43
- const prevRenderPosition = usePrevious<{renderPosition: UidType[]}>({
44
- renderPosition,
45
- });
46
43
  const {channel, appId, screenShareUid, screenShareToken, encryption} =
47
44
  useContext(PropsContext).rtcProps;
48
45
 
@@ -60,9 +57,8 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
60
57
  value: [screenShareUid],
61
58
  });
62
59
  setPinnedLayout();
63
- }
64
- //screenshare is stopped set the layout Grid View
65
- else {
60
+ } else {
61
+ //screenshare is stopped set the layout Grid View
66
62
  changeLayout();
67
63
  }
68
64
  };
@@ -113,15 +109,17 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
113
109
  };
114
110
 
115
111
  const stopUserScreenShare = () => {
116
- if (isScreenshareActive) {
117
- startUserScreenshare();
118
- }
112
+ if (!isScreenshareActive) return;
113
+ userScreenshare(false);
114
+ };
115
+ const startUserScreenshare = () => {
116
+ if (isScreenshareActive) return;
117
+ userScreenshare(true);
119
118
  };
120
119
 
121
- const startUserScreenshare = async () => {
122
- const isScreenActive = isScreenshareActive;
120
+ const userScreenshare = async (isActive: boolean) => {
123
121
  if (isRecordingActive) {
124
- executeRecordingQuery(isScreenActive);
122
+ executeRecordingQuery(isActive);
125
123
  }
126
124
  try {
127
125
  // @ts-ignore
@@ -134,17 +132,19 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
134
132
  rtc.RtcEngine as unknown as IAgoraRTC,
135
133
  encryption as unknown as any,
136
134
  );
137
- !isScreenActive && setScreenshareActive(true);
135
+ isActive && setScreenshareActive(true);
138
136
  } catch (e) {
139
137
  console.error("can't start the screen share", e);
140
138
  executeNormalQuery();
141
139
  }
142
- CustomEvents.send(EventNames.SCREENSHARE_ATTRIBUTE, {
143
- value: `${true}`,
144
- level: EventLevel.LEVEL2,
145
- });
146
- //if local user started the screenshare then change layout to pinned
147
- triggerChangeLayout(true, screenShareUid);
140
+ if (isActive) {
141
+ CustomEvents.send(EventNames.SCREENSHARE_ATTRIBUTE, {
142
+ value: `${true}`,
143
+ level: EventLevel.LEVEL2,
144
+ });
145
+ //if local user started the screenshare then change layout to pinned
146
+ triggerChangeLayout(true, screenShareUid);
147
+ }
148
148
  };
149
149
 
150
150
  return (