agora-appbuilder-core 4.1.22-beta.7 → 4.1.22-beta.9
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 +1 -1
- package/template/bridge/rtm/web/__tests__/storage.test.ts +15 -0
- package/template/bridge/rtm/web/index.ts +40 -31
- package/template/customization-api/index.ts +0 -1
- package/template/customization-api/typeDefinition.ts +7 -0
- package/template/defaultConfig.js +2 -2
- package/template/src/atoms/IconButton.tsx +3 -1
- package/template/src/atoms/Tooltip.tsx +1 -1
- package/template/src/auth/AuthProvider.tsx +10 -0
- package/template/src/components/Controls.tsx +8 -14
- package/template/src/components/EventsConfigure.tsx +1 -36
- package/template/src/components/RTMConfigure.tsx +44 -7
- package/template/src/components/whiteboard/WhiteboardButton.tsx +3 -3
- package/template/src/components/whiteboard/WhiteboardConfigure.tsx +2 -2
- package/template/src/pages/video-call/ActionSheetContent.tsx +6 -4
- package/template/src/subComponents/screenshare/ScreenshareButton.tsx +9 -2
- package/template/customization-api/ai-agent.ts +0 -4
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import {beforeEach, describe, expect, it, jest} from '@jest/globals';
|
|
|
3
3
|
const mockSetChannelMetadata = jest.fn<any>();
|
|
4
4
|
const mockGetChannelMetadata = jest.fn<any>();
|
|
5
5
|
const mockRemoveChannelMetadata = jest.fn<any>();
|
|
6
|
+
const mockRemoveUserMetadata = jest.fn<any>();
|
|
6
7
|
|
|
7
8
|
jest.mock('agora-rtm-sdk', () => ({
|
|
8
9
|
__esModule: true,
|
|
@@ -15,6 +16,7 @@ jest.mock('agora-rtm-sdk', () => ({
|
|
|
15
16
|
setChannelMetadata: mockSetChannelMetadata,
|
|
16
17
|
getChannelMetadata: mockGetChannelMetadata,
|
|
17
18
|
removeChannelMetadata: mockRemoveChannelMetadata,
|
|
19
|
+
removeUserMetadata: mockRemoveUserMetadata,
|
|
18
20
|
},
|
|
19
21
|
presence: {},
|
|
20
22
|
})),
|
|
@@ -30,9 +32,22 @@ describe('RTMWebClient channel metadata bridge', () => {
|
|
|
30
32
|
jest.clearAllMocks();
|
|
31
33
|
mockSetChannelMetadata.mockResolvedValue({});
|
|
32
34
|
mockRemoveChannelMetadata.mockResolvedValue({});
|
|
35
|
+
mockRemoveUserMetadata.mockResolvedValue({});
|
|
33
36
|
client = new RTMWebClient('app-id', 'user-id');
|
|
34
37
|
});
|
|
35
38
|
|
|
39
|
+
it('clears all metadata for the requested user when data is omitted', async () => {
|
|
40
|
+
await client.storage.removeUserMetadata({userId: 'agent-user'});
|
|
41
|
+
|
|
42
|
+
expect(mockRemoveUserMetadata).toHaveBeenCalledWith({
|
|
43
|
+
userId: 'agent-user',
|
|
44
|
+
majorRevision: undefined,
|
|
45
|
+
lockName: undefined,
|
|
46
|
+
addUserId: true,
|
|
47
|
+
addTimeStamp: true,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
36
51
|
it('preserves revision zero for create-only channel metadata', async () => {
|
|
37
52
|
await client.storage.setChannelMetadata(
|
|
38
53
|
'room',
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
type Metadata as NativeMetadata,
|
|
3
3
|
type MetadataItem as NativeMetadataItem,
|
|
4
4
|
type GetUserMetadataOptions as NativeGetUserMetadataOptions,
|
|
5
|
+
type RemoveUserMetadataOptions as NativeRemoveUserMetadataOptions,
|
|
5
6
|
type RtmChannelType as NativeRtmChannelType,
|
|
6
7
|
type SetUserMetadataResponse,
|
|
7
8
|
type LoginOptions as NativeLoginOptions,
|
|
@@ -72,24 +73,12 @@ export class RTMWebClient {
|
|
|
72
73
|
private client: RTMClient;
|
|
73
74
|
private appId: string;
|
|
74
75
|
private userId: string;
|
|
75
|
-
private eventsMap = new Map<keyof NativeRTMClientEventMap,
|
|
76
|
-
[
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
],
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
private emitEvent(event: keyof NativeRTMClientEventMap, data: any) {
|
|
85
|
-
const listeners = this.eventsMap.get(event);
|
|
86
|
-
|
|
87
|
-
if (!listeners) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
listeners.forEach(listener => listener(data));
|
|
92
|
-
}
|
|
76
|
+
private eventsMap = new Map<keyof NativeRTMClientEventMap, CallbackType>([
|
|
77
|
+
['linkState', () => null],
|
|
78
|
+
['storage', () => null],
|
|
79
|
+
['presence', () => null],
|
|
80
|
+
['message', () => null],
|
|
81
|
+
]);
|
|
93
82
|
|
|
94
83
|
constructor(appId: string, userId: string) {
|
|
95
84
|
this.appId = appId;
|
|
@@ -109,7 +98,7 @@ export class RTMWebClient {
|
|
|
109
98
|
nativeLinkStateMapping.IDLE,
|
|
110
99
|
reasonCode: linkStatusReasonCodeMapping[data.reasonCode] || 0,
|
|
111
100
|
};
|
|
112
|
-
this.
|
|
101
|
+
(this.eventsMap.get('linkState') ?? (() => {}))(nativeState);
|
|
113
102
|
});
|
|
114
103
|
|
|
115
104
|
this.client.addEventListener('storage', data => {
|
|
@@ -120,7 +109,7 @@ export class RTMWebClient {
|
|
|
120
109
|
data: convertWebToNativeMetadata(data.data),
|
|
121
110
|
timestamp: data.timestamp,
|
|
122
111
|
};
|
|
123
|
-
this.
|
|
112
|
+
(this.eventsMap.get('storage') ?? (() => {}))(nativeStorageEvent);
|
|
124
113
|
});
|
|
125
114
|
|
|
126
115
|
this.client.addEventListener('presence', data => {
|
|
@@ -131,7 +120,7 @@ export class RTMWebClient {
|
|
|
131
120
|
publisher: data.publisher,
|
|
132
121
|
timestamp: data.timestamp,
|
|
133
122
|
};
|
|
134
|
-
this.
|
|
123
|
+
(this.eventsMap.get('presence') ?? (() => {}))(nativePresenceEvent);
|
|
135
124
|
});
|
|
136
125
|
|
|
137
126
|
this.client.addEventListener('message', data => {
|
|
@@ -141,7 +130,7 @@ export class RTMWebClient {
|
|
|
141
130
|
messageType: nativeMessageEventTypeMapping[data.messageType],
|
|
142
131
|
message: `${data.message}`,
|
|
143
132
|
};
|
|
144
|
-
this.
|
|
133
|
+
(this.eventsMap.get('message') ?? (() => {}))(nativeMessageEvent);
|
|
145
134
|
});
|
|
146
135
|
} catch (error) {
|
|
147
136
|
const contextError = new Error(
|
|
@@ -241,6 +230,23 @@ export class RTMWebClient {
|
|
|
241
230
|
return nativeResponse;
|
|
242
231
|
},
|
|
243
232
|
|
|
233
|
+
removeUserMetadata: (options?: NativeRemoveUserMetadataOptions) => {
|
|
234
|
+
const data = options?.data?.items?.map(item => ({
|
|
235
|
+
key: item.key,
|
|
236
|
+
value: item.value ?? '',
|
|
237
|
+
revision: item.revision ?? -1,
|
|
238
|
+
}));
|
|
239
|
+
|
|
240
|
+
return this.client.storage.removeUserMetadata({
|
|
241
|
+
userId: options?.userId,
|
|
242
|
+
majorRevision: options?.majorRevision,
|
|
243
|
+
lockName: options?.lockName,
|
|
244
|
+
...(data ? {data} : {}),
|
|
245
|
+
addTimeStamp: options?.addTimeStamp ?? true,
|
|
246
|
+
addUserId: options?.addUserId ?? true,
|
|
247
|
+
});
|
|
248
|
+
},
|
|
249
|
+
|
|
244
250
|
setChannelMetadata: async (
|
|
245
251
|
channelName: string,
|
|
246
252
|
channelType: NativeRtmChannelType,
|
|
@@ -411,18 +417,21 @@ export class RTMWebClient {
|
|
|
411
417
|
listener: (event: any) => void,
|
|
412
418
|
) {
|
|
413
419
|
if (this.client) {
|
|
414
|
-
//
|
|
415
|
-
|
|
416
|
-
this.eventsMap.get(event)?.add(listener as CallbackType);
|
|
420
|
+
// Simply replace the handler in our map - web client listeners are fixed in constructor
|
|
421
|
+
this.eventsMap.set(event, listener as CallbackType);
|
|
417
422
|
}
|
|
418
423
|
}
|
|
419
424
|
|
|
420
425
|
removeEventListener(
|
|
421
426
|
event: keyof NativeRTMClientEventMap,
|
|
422
|
-
|
|
427
|
+
_listener: (event: any) => void,
|
|
423
428
|
) {
|
|
424
429
|
if (this.client && this.eventsMap.has(event)) {
|
|
425
|
-
this.eventsMap.get(event)
|
|
430
|
+
const prevListener = this.eventsMap.get(event);
|
|
431
|
+
if (prevListener) {
|
|
432
|
+
this.client.removeEventListener(event, prevListener);
|
|
433
|
+
}
|
|
434
|
+
this.eventsMap.set(event, () => null); // reset to no-op
|
|
426
435
|
}
|
|
427
436
|
}
|
|
428
437
|
|
|
@@ -485,10 +494,10 @@ export class RTMWebClient {
|
|
|
485
494
|
|
|
486
495
|
removeAllListeners() {
|
|
487
496
|
this.eventsMap = new Map([
|
|
488
|
-
['linkState',
|
|
489
|
-
['storage',
|
|
490
|
-
['presence',
|
|
491
|
-
['message',
|
|
497
|
+
['linkState', () => null],
|
|
498
|
+
['storage', () => null],
|
|
499
|
+
['presence', () => null],
|
|
500
|
+
['message', () => null],
|
|
492
501
|
]);
|
|
493
502
|
return this.client.removeAllListeners();
|
|
494
503
|
}
|
|
@@ -18,6 +18,7 @@ import {ToolbarPresetProps} from './sub-components';
|
|
|
18
18
|
import {TextDataInterface} from '../src/language/default-labels';
|
|
19
19
|
import {VBPanelProps} from '../src/components/virtual-background/VBPanel';
|
|
20
20
|
import {AIAgentState} from '../src/ai-agent/components/AgentControls/const';
|
|
21
|
+
import type {MessageEvent, PresenceEvent} from 'agora-react-native-rtm';
|
|
21
22
|
|
|
22
23
|
export const CUSTOM_ROUTES_PREFIX = '/r/';
|
|
23
24
|
|
|
@@ -136,6 +137,9 @@ export type EndCallHookType = () => (
|
|
|
136
137
|
isHost: boolean,
|
|
137
138
|
history: History,
|
|
138
139
|
) => Promise<void>;
|
|
140
|
+
export type DeepLinkHandlerType = (link: string) => boolean | void;
|
|
141
|
+
export type RtmMessageHandlerType = (message: MessageEvent) => boolean | void;
|
|
142
|
+
export type RtmPresenceHandlerType = (presence: PresenceEvent) => void;
|
|
139
143
|
|
|
140
144
|
export interface AppConfig {
|
|
141
145
|
defaultRootFallback?: React.ComponentType;
|
|
@@ -170,6 +174,9 @@ export interface CustomizationApiInterface {
|
|
|
170
174
|
lifecycle?: {
|
|
171
175
|
useAfterEndCall?: EndCallHookType;
|
|
172
176
|
useBeforeEndCall?: EndCallHookType;
|
|
177
|
+
onDeepLink?: DeepLinkHandlerType;
|
|
178
|
+
onRtmMessage?: RtmMessageHandlerType;
|
|
179
|
+
onRtmPresence?: RtmPresenceHandlerType;
|
|
173
180
|
// useBeforeJoin?: CustomHookType;
|
|
174
181
|
// useBeforeCreate?: CustomHookType;
|
|
175
182
|
};
|
|
@@ -77,8 +77,8 @@ const DefaultConfig = {
|
|
|
77
77
|
CHAT_ORG_NAME: "",
|
|
78
78
|
CHAT_APP_NAME: "",
|
|
79
79
|
CHAT_URL: "",
|
|
80
|
-
CLI_VERSION: "3.1.22-beta.
|
|
81
|
-
CORE_VERSION: "4.1.22-beta.
|
|
80
|
+
CLI_VERSION: "3.1.22-beta.9",
|
|
81
|
+
CORE_VERSION: "4.1.22-beta.9",
|
|
82
82
|
DISABLE_LANDSCAPE_MODE: false,
|
|
83
83
|
STT_AUTO_START: false,
|
|
84
84
|
CLOUD_RECORDING_AUTO_START: false,
|
|
@@ -25,6 +25,7 @@ export interface IconButtonProps {
|
|
|
25
25
|
setRef?: (ref: any) => void;
|
|
26
26
|
onPress?: PressableProps['onPress'];
|
|
27
27
|
disabled?: boolean;
|
|
28
|
+
showToolTipWhenDisabled?: boolean;
|
|
28
29
|
containerStyle?: ViewStyle;
|
|
29
30
|
rootContainerStyle?: ViewStyle;
|
|
30
31
|
iconContainerStyle?: ViewStyle;
|
|
@@ -156,13 +157,14 @@ const IconButtonWithToolTip = (props: IconButtonProps) => {
|
|
|
156
157
|
isClickable = false,
|
|
157
158
|
showTooltipArrow = true,
|
|
158
159
|
disabled = false,
|
|
160
|
+
showToolTipWhenDisabled = false,
|
|
159
161
|
} = props;
|
|
160
162
|
if (props?.toolTipMessage) {
|
|
161
163
|
return (
|
|
162
164
|
<ToolTip
|
|
163
165
|
isClickable={isClickable}
|
|
164
166
|
toolTipMessage={props.toolTipMessage}
|
|
165
|
-
disabled={disabled}
|
|
167
|
+
disabled={disabled && !showToolTipWhenDisabled}
|
|
166
168
|
//@ts-ignore
|
|
167
169
|
placement={placement}
|
|
168
170
|
showTooltipArrow={showTooltipArrow}
|
|
@@ -43,6 +43,7 @@ import SDKEvents from '../utils/SdkEvents';
|
|
|
43
43
|
import LocalEventEmitter, {
|
|
44
44
|
LocalEventsEnum,
|
|
45
45
|
} from '../rtm-events-api/LocalEvents';
|
|
46
|
+
import {useCustomization} from 'customization-implementation';
|
|
46
47
|
|
|
47
48
|
const GET_USER_URL = `${$config.BACKEND_ENDPOINT}/v1/user/details`;
|
|
48
49
|
|
|
@@ -64,6 +65,7 @@ const AuthContext = createContext<AuthContextInterface | null>(null);
|
|
|
64
65
|
const AuthProvider = (props: AuthProviderProps) => {
|
|
65
66
|
const loadingLabel = useString(loadingText)();
|
|
66
67
|
const timeoutHeading = useString(authSessionTimeoutToastHeading)();
|
|
68
|
+
const {lifecycle} = useCustomization();
|
|
67
69
|
const regEvent = useRef(true);
|
|
68
70
|
const refreshTimeoutWeb = useRef(null);
|
|
69
71
|
const [showNativePopup, setShowNativePopup] = useState(false);
|
|
@@ -137,6 +139,14 @@ const AuthProvider = (props: AuthProviderProps) => {
|
|
|
137
139
|
|
|
138
140
|
const deepLinkUrl = (link: string | null) => {
|
|
139
141
|
if (link !== null) {
|
|
142
|
+
if (lifecycle?.onDeepLink?.(link)) {
|
|
143
|
+
logger.log(
|
|
144
|
+
LogSource.Internals,
|
|
145
|
+
'AUTH',
|
|
146
|
+
'Deep link handled by customization',
|
|
147
|
+
);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
140
150
|
//deeplinking handling with authentication enabled
|
|
141
151
|
if ($config.ENABLE_IDP_AUTH) {
|
|
142
152
|
const url = processDeepLinkURI(link);
|
|
@@ -125,9 +125,6 @@ import {
|
|
|
125
125
|
import ViewTextTracksModal from './text-tracks/ViewTextTracksModal';
|
|
126
126
|
import LiveReactionButton from './reactions/LiveReactionButton';
|
|
127
127
|
|
|
128
|
-
const getWhiteboardActivePayload = (status: boolean, channel?: string) =>
|
|
129
|
-
JSON.stringify({status, channel});
|
|
130
|
-
|
|
131
128
|
export const useToggleWhiteboard = () => {
|
|
132
129
|
const {
|
|
133
130
|
whiteboardActive,
|
|
@@ -138,9 +135,6 @@ export const useToggleWhiteboard = () => {
|
|
|
138
135
|
const {setCustomContent} = useContent();
|
|
139
136
|
const {setLayout} = useLayout();
|
|
140
137
|
const {dispatch} = useContext(DispatchContext);
|
|
141
|
-
const {
|
|
142
|
-
data: {channel},
|
|
143
|
-
} = useRoomInfo();
|
|
144
138
|
return () => {
|
|
145
139
|
if ($config.ENABLE_WHITEBOARD) {
|
|
146
140
|
if (whiteboardActive) {
|
|
@@ -149,7 +143,7 @@ export const useToggleWhiteboard = () => {
|
|
|
149
143
|
setLayout('grid');
|
|
150
144
|
events.send(
|
|
151
145
|
EventNames.WHITEBOARD_ACTIVE,
|
|
152
|
-
|
|
146
|
+
JSON.stringify({status: false}),
|
|
153
147
|
PersistanceLevel.Session,
|
|
154
148
|
);
|
|
155
149
|
} else {
|
|
@@ -162,7 +156,7 @@ export const useToggleWhiteboard = () => {
|
|
|
162
156
|
setLayout('pinned');
|
|
163
157
|
events.send(
|
|
164
158
|
EventNames.WHITEBOARD_ACTIVE,
|
|
165
|
-
|
|
159
|
+
JSON.stringify({status: true}),
|
|
166
160
|
PersistanceLevel.Session,
|
|
167
161
|
);
|
|
168
162
|
}
|
|
@@ -175,7 +169,7 @@ export const WhiteboardListener = () => {
|
|
|
175
169
|
const {setCustomContent} = useContent();
|
|
176
170
|
const {currentLayout, setLayout} = useLayout();
|
|
177
171
|
const {
|
|
178
|
-
data: {
|
|
172
|
+
data: {isHost},
|
|
179
173
|
isWhiteBoardOn,
|
|
180
174
|
} = useRoomInfo();
|
|
181
175
|
|
|
@@ -254,7 +248,7 @@ export const WhiteboardListener = () => {
|
|
|
254
248
|
triggerEvent &&
|
|
255
249
|
events.send(
|
|
256
250
|
EventNames.WHITEBOARD_ACTIVE,
|
|
257
|
-
|
|
251
|
+
JSON.stringify({status: false}),
|
|
258
252
|
PersistanceLevel.Session,
|
|
259
253
|
);
|
|
260
254
|
} else {
|
|
@@ -268,7 +262,7 @@ export const WhiteboardListener = () => {
|
|
|
268
262
|
triggerEvent &&
|
|
269
263
|
events.send(
|
|
270
264
|
EventNames.WHITEBOARD_ACTIVE,
|
|
271
|
-
|
|
265
|
+
JSON.stringify({status: true}),
|
|
272
266
|
PersistanceLevel.Session,
|
|
273
267
|
);
|
|
274
268
|
}
|
|
@@ -346,7 +340,7 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
|
|
|
346
340
|
|
|
347
341
|
// const {start, restart} = useSTTAPI();
|
|
348
342
|
const {
|
|
349
|
-
data: {
|
|
343
|
+
data: {isHost},
|
|
350
344
|
} = useRoomInfo();
|
|
351
345
|
const {setShowInvitePopup, setShowStopRecordingPopup, setShowLayoutOption} =
|
|
352
346
|
useVideoCall();
|
|
@@ -477,7 +471,7 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
|
|
|
477
471
|
triggerEvent &&
|
|
478
472
|
events.send(
|
|
479
473
|
EventNames.WHITEBOARD_ACTIVE,
|
|
480
|
-
|
|
474
|
+
JSON.stringify({status: false}),
|
|
481
475
|
PersistanceLevel.Session,
|
|
482
476
|
);
|
|
483
477
|
} else {
|
|
@@ -491,7 +485,7 @@ const MoreButton = (props: {fields: ToolbarMoreButtonDefaultFields}) => {
|
|
|
491
485
|
triggerEvent &&
|
|
492
486
|
events.send(
|
|
493
487
|
EventNames.WHITEBOARD_ACTIVE,
|
|
494
|
-
|
|
488
|
+
JSON.stringify({status: true}),
|
|
495
489
|
PersistanceLevel.Session,
|
|
496
490
|
);
|
|
497
491
|
}
|
|
@@ -243,12 +243,11 @@ const EventsConfigure: React.FC<Props> = ({
|
|
|
243
243
|
defaultContentRef.current.defaultContent = defaultContent;
|
|
244
244
|
}, [defaultContent]);
|
|
245
245
|
const {
|
|
246
|
-
data: {
|
|
246
|
+
data: {isHost, roomId},
|
|
247
247
|
roomPreference: {userRemovalTimeout},
|
|
248
248
|
} = useRoomInfo();
|
|
249
249
|
const {setRoomInfo} = useSetRoomInfo();
|
|
250
250
|
const isHostRef = React.useRef(isHost);
|
|
251
|
-
const channelRef = React.useRef(channel);
|
|
252
251
|
const {permissionStatus} = useLocalUserInfo();
|
|
253
252
|
const permissionStatusRef = React.useRef(permissionStatus);
|
|
254
253
|
const {waitingRoomUids, waitingRoomRef} = useWaitingRoomContext();
|
|
@@ -264,13 +263,6 @@ const EventsConfigure: React.FC<Props> = ({
|
|
|
264
263
|
useEffect(() => {
|
|
265
264
|
isHostRef.current = isHost;
|
|
266
265
|
}, [isHost]);
|
|
267
|
-
useEffect(() => {
|
|
268
|
-
channelRef.current = channel;
|
|
269
|
-
}, [channel]);
|
|
270
|
-
const isDifferentWhiteboardChannel = (eventChannel?: string) => {
|
|
271
|
-
const currentChannel = channelRef.current;
|
|
272
|
-
return !!currentChannel && eventChannel !== currentChannel;
|
|
273
|
-
};
|
|
274
266
|
|
|
275
267
|
useEffect(() => {
|
|
276
268
|
permissionStatusRef.current = permissionStatus;
|
|
@@ -500,15 +492,6 @@ const EventsConfigure: React.FC<Props> = ({
|
|
|
500
492
|
|
|
501
493
|
events.on(EventNames.WHITEBOARD_ACTIVE, ({payload}) => {
|
|
502
494
|
const data = JSON.parse(payload);
|
|
503
|
-
if (isDifferentWhiteboardChannel(data?.channel)) {
|
|
504
|
-
logger.debug(
|
|
505
|
-
LogSource.Internals,
|
|
506
|
-
'WHITEBOARD',
|
|
507
|
-
'Ignoring whiteboard state for a different channel',
|
|
508
|
-
{eventChannel: data?.channel, currentChannel: channelRef.current},
|
|
509
|
-
);
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
495
|
if (data && data?.status) {
|
|
513
496
|
if (
|
|
514
497
|
($config.ENABLE_WAITING_ROOM && !isHostRef.current) ||
|
|
@@ -546,15 +529,6 @@ const EventsConfigure: React.FC<Props> = ({
|
|
|
546
529
|
|
|
547
530
|
events.on(EventNames.BOARD_COLOR_CHANGED, ({payload}) => {
|
|
548
531
|
const data = JSON.parse(payload);
|
|
549
|
-
if (isDifferentWhiteboardChannel(data?.channel)) {
|
|
550
|
-
logger.debug(
|
|
551
|
-
LogSource.Internals,
|
|
552
|
-
'WHITEBOARD',
|
|
553
|
-
'Ignoring whiteboard board color for a different channel',
|
|
554
|
-
{eventChannel: data?.channel, currentChannel: channelRef.current},
|
|
555
|
-
);
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
532
|
if (data?.boardColor) {
|
|
559
533
|
if (
|
|
560
534
|
($config.ENABLE_WAITING_ROOM && !isHostRef.current) ||
|
|
@@ -576,15 +550,6 @@ const EventsConfigure: React.FC<Props> = ({
|
|
|
576
550
|
|
|
577
551
|
events.on(EventNames.WHITEBOARD_LAST_IMAGE_UPLOAD_POSITION, ({payload}) => {
|
|
578
552
|
const data = JSON.parse(payload);
|
|
579
|
-
if (isDifferentWhiteboardChannel(data?.channel)) {
|
|
580
|
-
logger.debug(
|
|
581
|
-
LogSource.Internals,
|
|
582
|
-
'WHITEBOARD',
|
|
583
|
-
'Ignoring whiteboard upload position for a different channel',
|
|
584
|
-
{eventChannel: data?.channel, currentChannel: channelRef.current},
|
|
585
|
-
);
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
553
|
if (
|
|
589
554
|
($config.ENABLE_WAITING_ROOM && !isHostRef.current) ||
|
|
590
555
|
$config.AUTO_CONNECT_RTM
|
|
@@ -35,6 +35,7 @@ import {Platform} from 'react-native';
|
|
|
35
35
|
import {backOff} from 'exponential-backoff';
|
|
36
36
|
import {isAndroid, isIOS, isWeb, isWebInternal} from '../utils/common';
|
|
37
37
|
import {useContent} from 'customization-api';
|
|
38
|
+
import {useCustomization} from 'customization-implementation';
|
|
38
39
|
import {
|
|
39
40
|
safeJsonParse,
|
|
40
41
|
timeNow,
|
|
@@ -81,6 +82,7 @@ const RtmConfigure = (props: any) => {
|
|
|
81
82
|
const {rtcProps} = useContext(PropsContext);
|
|
82
83
|
const {dispatch} = useContext(DispatchContext);
|
|
83
84
|
const {defaultContent, activeUids} = useContent();
|
|
85
|
+
const {lifecycle} = useCustomization();
|
|
84
86
|
const {
|
|
85
87
|
waitingRoomStatus,
|
|
86
88
|
data: {isHost},
|
|
@@ -318,6 +320,16 @@ const RtmConfigure = (props: any) => {
|
|
|
318
320
|
if (`${localUid}` === presence.publisher) {
|
|
319
321
|
return;
|
|
320
322
|
}
|
|
323
|
+
try {
|
|
324
|
+
lifecycle?.onRtmPresence?.(presence);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
logger.error(
|
|
327
|
+
LogSource.Events,
|
|
328
|
+
'CUSTOM_EVENTS',
|
|
329
|
+
'Customization RTM presence handler failed',
|
|
330
|
+
{error, presence},
|
|
331
|
+
);
|
|
332
|
+
}
|
|
321
333
|
// remoteJoinChannel
|
|
322
334
|
if (presence.type === nativePresenceEventTypeMapping.REMOTE_JOIN) {
|
|
323
335
|
logger.log(
|
|
@@ -325,10 +337,22 @@ const RtmConfigure = (props: any) => {
|
|
|
325
337
|
'Event',
|
|
326
338
|
'RTM presenceEvent of type [3 - remoteJoin] (channelMemberJoined)',
|
|
327
339
|
);
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
340
|
+
try {
|
|
341
|
+
const backoffAttributes = await fetchUserAttributesWithBackoffRetry(
|
|
342
|
+
presence.publisher,
|
|
343
|
+
);
|
|
344
|
+
await processUserUidAttributes(
|
|
345
|
+
backoffAttributes,
|
|
346
|
+
presence.publisher,
|
|
347
|
+
);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
logger.warn(
|
|
350
|
+
LogSource.AgoraSDK,
|
|
351
|
+
'Event',
|
|
352
|
+
`RTM could not apply metadata for joined member ${presence.publisher}`,
|
|
353
|
+
{error},
|
|
354
|
+
);
|
|
355
|
+
}
|
|
332
356
|
}
|
|
333
357
|
// remoteLeaveChannel and, on web, remote connection timeout
|
|
334
358
|
if (isRemoteDeparture(presence.type, isWebInternal())) {
|
|
@@ -363,6 +387,20 @@ const RtmConfigure = (props: any) => {
|
|
|
363
387
|
if (`${localUid}` === message.publisher) {
|
|
364
388
|
return;
|
|
365
389
|
}
|
|
390
|
+
let handledByCustomization = false;
|
|
391
|
+
try {
|
|
392
|
+
handledByCustomization = !!lifecycle?.onRtmMessage?.(message);
|
|
393
|
+
} catch (error) {
|
|
394
|
+
logger.error(
|
|
395
|
+
LogSource.Events,
|
|
396
|
+
'CUSTOM_EVENTS',
|
|
397
|
+
'Customization RTM message handler failed',
|
|
398
|
+
{error, message},
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
if (handledByCustomization) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
366
404
|
// message - 1 (channel)
|
|
367
405
|
if (message.channelType === nativeChannelTypeMapping.MESSAGE) {
|
|
368
406
|
logger.debug(
|
|
@@ -501,6 +539,7 @@ const RtmConfigure = (props: any) => {
|
|
|
501
539
|
const options: SetOrUpdateUserMetadataOptions = {
|
|
502
540
|
userId: `${localUid}`,
|
|
503
541
|
};
|
|
542
|
+
await engine.current.storage.removeUserMetadata(options);
|
|
504
543
|
await engine.current.storage.setUserMetadata(data, options);
|
|
505
544
|
logger.log(
|
|
506
545
|
LogSource.AgoraSDK,
|
|
@@ -816,19 +855,17 @@ const RtmConfigure = (props: any) => {
|
|
|
816
855
|
const uid = parseInt(userId, 10);
|
|
817
856
|
const screenUidItem = attr?.items?.find(item => item.key === 'screenUid');
|
|
818
857
|
const isHostItem = attr?.items?.find(item => item.key === 'isHost');
|
|
819
|
-
const nameItem = attr?.items?.find(item => item.key === 'name');
|
|
820
858
|
const screenUid = screenUidItem?.value
|
|
821
859
|
? parseInt(screenUidItem.value, 10)
|
|
822
860
|
: undefined;
|
|
823
861
|
|
|
824
862
|
//start - updating user data in rtc
|
|
825
863
|
const userData = {
|
|
826
|
-
screenUid
|
|
864
|
+
screenUid,
|
|
827
865
|
//below thing for livestreaming
|
|
828
866
|
type: uid === parseInt(RECORDING_BOT_UID, 10) ? 'bot' : 'rtc',
|
|
829
867
|
uid,
|
|
830
868
|
offline: false,
|
|
831
|
-
...(nameItem?.value ? {name: nameItem.value} : {}),
|
|
832
869
|
isHost: isHostItem?.value || false,
|
|
833
870
|
lastMessageTimeStamp: 0,
|
|
834
871
|
};
|
|
@@ -19,7 +19,7 @@ const WhiteboardButton = () => {
|
|
|
19
19
|
leaveWhiteboardRoom,
|
|
20
20
|
} = useContext(whiteboardContext);
|
|
21
21
|
const {
|
|
22
|
-
data: {
|
|
22
|
+
data: {isHost},
|
|
23
23
|
} = useRoomInfo();
|
|
24
24
|
|
|
25
25
|
const {setLayout, currentLayout} = useLayout();
|
|
@@ -46,7 +46,7 @@ const WhiteboardButton = () => {
|
|
|
46
46
|
triggerEvent &&
|
|
47
47
|
customEvents.send(
|
|
48
48
|
EventNames.WHITEBOARD_ACTIVE,
|
|
49
|
-
JSON.stringify({status: false
|
|
49
|
+
JSON.stringify({status: false}),
|
|
50
50
|
PersistanceLevel.Session,
|
|
51
51
|
);
|
|
52
52
|
} else {
|
|
@@ -55,7 +55,7 @@ const WhiteboardButton = () => {
|
|
|
55
55
|
triggerEvent &&
|
|
56
56
|
customEvents.send(
|
|
57
57
|
EventNames.WHITEBOARD_ACTIVE,
|
|
58
|
-
JSON.stringify({status: true
|
|
58
|
+
JSON.stringify({status: true}),
|
|
59
59
|
PersistanceLevel.Session,
|
|
60
60
|
);
|
|
61
61
|
}
|
|
@@ -140,7 +140,7 @@ const WhiteboardConfigure: React.FC<WhiteboardPropsInterface> = props => {
|
|
|
140
140
|
|
|
141
141
|
const [name] = useUserName();
|
|
142
142
|
const {
|
|
143
|
-
data: {
|
|
143
|
+
data: {isHost, whiteboard: {room_token, room_uuid} = {}},
|
|
144
144
|
boardColor: boardColorRemote,
|
|
145
145
|
whiteboardLastImageUploadPosition: whiteboardLastImageUploadPositionRemote,
|
|
146
146
|
} = useRoomInfo();
|
|
@@ -335,7 +335,7 @@ const WhiteboardConfigure: React.FC<WhiteboardPropsInterface> = props => {
|
|
|
335
335
|
*/
|
|
336
336
|
events.send(
|
|
337
337
|
EventNames.WHITEBOARD_LAST_IMAGE_UPLOAD_POSITION,
|
|
338
|
-
JSON.stringify({height: height || 0
|
|
338
|
+
JSON.stringify({height: height || 0}),
|
|
339
339
|
PersistanceLevel.Session,
|
|
340
340
|
);
|
|
341
341
|
};
|
|
@@ -519,10 +519,12 @@ const ActionSheetContent = props => {
|
|
|
519
519
|
</View>
|
|
520
520
|
</ActionSheetProvider>
|
|
521
521
|
|
|
522
|
-
<
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
522
|
+
<ActionSheetProvider>
|
|
523
|
+
<CarouselWrapper
|
|
524
|
+
data={displayItemsOrdered?.slice(3, displayItemsOrdered?.length)}
|
|
525
|
+
dataObject={displayItems}
|
|
526
|
+
/>
|
|
527
|
+
</ActionSheetProvider>
|
|
526
528
|
</View>
|
|
527
529
|
);
|
|
528
530
|
};
|
|
@@ -20,6 +20,7 @@ import useIsHandRaised from '../../utils/useIsHandRaised';
|
|
|
20
20
|
import {isAndroid, isIOS} from '../../utils/common';
|
|
21
21
|
import {useVideoCall} from '../../components/useVideoCall';
|
|
22
22
|
import {useToolbarMenu} from '../../utils/useMenu';
|
|
23
|
+
import {useActionSheet} from '../../utils/useActionSheet';
|
|
23
24
|
import ToolbarMenuItem from '../../atoms/ToolbarMenuItem';
|
|
24
25
|
import {
|
|
25
26
|
livestreamingShareTooltipText,
|
|
@@ -41,9 +42,15 @@ export interface ScreenshareButtonProps {
|
|
|
41
42
|
const ScreenshareButton = (props: ScreenshareButtonProps) => {
|
|
42
43
|
const {label = null, onPress: onPressCustom = null} = useToolbarProps();
|
|
43
44
|
const {isToolbarMenuItem} = useToolbarMenu();
|
|
45
|
+
const {
|
|
46
|
+
isOnActionSheet: isOnActionSheetContext,
|
|
47
|
+
showLabel: showActionSheetLabel,
|
|
48
|
+
} = useActionSheet();
|
|
44
49
|
const {rtcProps} = useContext(PropsContext);
|
|
45
|
-
const
|
|
46
|
-
|
|
50
|
+
const isOnActionSheet = props.isOnActionSheet || isOnActionSheetContext;
|
|
51
|
+
const showLabel =
|
|
52
|
+
props.showLabel ??
|
|
53
|
+
(isOnActionSheet ? showActionSheetLabel : $config.ICON_TEXT || false);
|
|
47
54
|
const {
|
|
48
55
|
data: {isHost},
|
|
49
56
|
} = useRoomInfo();
|