agora-appbuilder-core 4.1.10-beta.1 → 4.1.11
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 +2 -2
- package/template/agora-rn-uikit/src/Utils/isBotUser.ts +1 -1
- package/template/android/app/build.gradle +0 -7
- package/template/bridge/rtc/webNg/RtcEngine.ts +2 -2
- package/template/bridge/rtm/web/Types.ts +0 -183
- package/template/bridge/rtm/web/index.ts +488 -450
- package/template/customization-api/typeDefinition.ts +0 -1
- package/template/defaultConfig.js +3 -4
- package/template/global.d.ts +0 -1
- package/template/ios/Podfile +0 -41
- package/template/package.json +5 -5
- package/template/src/AppRoutes.tsx +3 -3
- package/template/src/ai-agent/components/ControlButtons.tsx +1 -1
- package/template/src/assets/font-styles.css +1 -33
- package/template/src/assets/fonts/icomoon.ttf +0 -0
- package/template/src/assets/selection.json +1 -1
- package/template/src/atoms/ActionMenu.tsx +93 -13
- package/template/src/atoms/CustomIcon.tsx +1 -8
- package/template/src/atoms/DropDownMulti.tsx +80 -29
- package/template/src/atoms/Dropdown.tsx +0 -5
- package/template/src/atoms/Input.tsx +2 -1
- package/template/src/atoms/TertiaryButton.tsx +1 -1
- package/template/src/atoms/UserAvatar.tsx +1 -1
- package/template/src/components/ChatContext.ts +3 -5
- package/template/src/components/Controls.tsx +167 -208
- package/template/src/components/DeviceConfigure.tsx +1 -1
- package/template/src/components/EventsConfigure.tsx +168 -118
- package/template/src/components/Navbar.tsx +11 -14
- package/template/src/components/RTMConfigure.tsx +819 -32
- package/template/src/components/beauty-effect/useBeautyEffects.tsx +13 -50
- package/template/src/components/chat/chatConfigure.tsx +1 -7
- package/template/src/components/chat-messages/useChatMessages.tsx +11 -43
- package/template/src/components/controls/useControlPermissionMatrix.tsx +4 -32
- package/template/src/components/participants/AllHostParticipants.tsx +2 -10
- package/template/src/components/participants/Participant.tsx +1 -7
- package/template/src/components/participants/UserActionMenuOptions.tsx +2 -12
- package/template/src/components/precall/joinCallBtn.native.tsx +7 -2
- package/template/src/components/precall/joinCallBtn.tsx +7 -2
- package/template/src/components/precall/joinWaitingRoomBtn.native.tsx +16 -15
- package/template/src/components/precall/joinWaitingRoomBtn.tsx +31 -17
- package/template/src/components/precall/textInput.tsx +45 -22
- package/template/src/components/precall/usePreCall.tsx +7 -0
- package/template/src/components/recordings/RecordingsDateTable.tsx +2 -3
- package/template/src/components/room-info/useRoomInfo.tsx +5 -0
- package/template/src/components/useUserPreference.tsx +12 -39
- package/template/src/components/virtual-background/useVB.tsx +0 -18
- package/template/src/components/whiteboard/WhiteboardConfigure.tsx +0 -27
- package/template/src/language/default-labels/videoCallScreenLabels.ts +27 -11
- package/template/src/logger/AppBuilderLogger.tsx +3 -11
- package/template/src/pages/VideoCall.tsx +518 -171
- package/template/src/pages/video-call/ActionSheetContent.tsx +77 -77
- package/template/src/pages/video-call/SidePanelHeader.tsx +81 -53
- package/template/src/pages/video-call/VideoCallScreen.tsx +0 -18
- package/template/src/pages/video-call/VideoCallScreenWrapper.tsx +1 -0
- package/template/src/rtm/RTMEngine.ts +37 -262
- package/template/src/rtm/utils.ts +1 -68
- package/template/src/rtm-events/constants.ts +7 -40
- package/template/src/rtm-events-api/Events.ts +39 -158
- package/template/src/subComponents/ChatBubble.tsx +3 -3
- package/template/src/subComponents/ChatContainer.tsx +9 -19
- package/template/src/subComponents/LocalAudioMute.tsx +2 -2
- package/template/src/subComponents/LocalVideoMute.tsx +2 -2
- package/template/src/subComponents/SidePanelEnum.tsx +0 -1
- package/template/src/subComponents/caption/Caption.tsx +48 -7
- package/template/src/subComponents/caption/CaptionContainer.tsx +324 -51
- package/template/src/subComponents/caption/CaptionIcon.tsx +35 -34
- package/template/src/subComponents/caption/CaptionText.tsx +103 -2
- package/template/src/subComponents/caption/LanguageSelectorPopup.tsx +179 -69
- package/template/src/subComponents/caption/Transcript.tsx +46 -11
- package/template/src/subComponents/caption/TranscriptIcon.tsx +27 -35
- package/template/src/subComponents/caption/TranscriptText.tsx +78 -3
- package/template/src/subComponents/caption/proto/ptoto.js +38 -4
- package/template/src/subComponents/caption/proto/test.proto +34 -19
- package/template/src/subComponents/caption/useCaption.tsx +754 -11
- package/template/src/subComponents/caption/useSTTAPI.tsx +118 -205
- package/template/src/subComponents/caption/useStreamMessageUtils.native.ts +152 -33
- package/template/src/subComponents/caption/useStreamMessageUtils.ts +165 -34
- package/template/src/subComponents/caption/utils.ts +171 -3
- package/template/src/subComponents/chat/ChatSendButton.tsx +0 -1
- package/template/src/subComponents/screenshare/ScreenshareButton.tsx +0 -16
- package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +1 -1
- package/template/src/subComponents/waiting-rooms/WaitingRoomControls.tsx +4 -7
- package/template/src/utils/SdkEvents.ts +3 -0
- package/template/src/utils/useEndCall.ts +4 -4
- package/template/src/utils/useMuteToggleLocal.ts +10 -14
- package/template/src/utils/useSpeechToText.ts +31 -20
- package/template/bridge/rtm/web/index-legacy.ts +0 -540
- package/template/src/components/RTMConfigure-legacy.tsx +0 -848
- package/template/src/components/UserGlobalPreferenceProvider.tsx +0 -227
- package/template/src/components/breakout-room/BreakoutRoomPanel.tsx +0 -58
- package/template/src/components/breakout-room/context/BreakoutRoomContext.tsx +0 -2508
- package/template/src/components/breakout-room/events/BreakoutRoomEventsConfigure.tsx +0 -272
- package/template/src/components/breakout-room/events/constants.ts +0 -17
- package/template/src/components/breakout-room/hoc/BreakoutRoomNameRenderer.tsx +0 -68
- package/template/src/components/breakout-room/hooks/useBreakoutRoomExit.ts +0 -49
- package/template/src/components/breakout-room/state/reducer.ts +0 -522
- package/template/src/components/breakout-room/state/types.ts +0 -54
- package/template/src/components/breakout-room/ui/BreakoutMeetingTitle.tsx +0 -60
- package/template/src/components/breakout-room/ui/BreakoutRoomActionMenu.tsx +0 -136
- package/template/src/components/breakout-room/ui/BreakoutRoomAnnouncementModal.tsx +0 -135
- package/template/src/components/breakout-room/ui/BreakoutRoomGroupSettings.tsx +0 -588
- package/template/src/components/breakout-room/ui/BreakoutRoomMainRoomUsers.tsx +0 -142
- package/template/src/components/breakout-room/ui/BreakoutRoomMemberActionMenu.tsx +0 -122
- package/template/src/components/breakout-room/ui/BreakoutRoomParticipants.tsx +0 -124
- package/template/src/components/breakout-room/ui/BreakoutRoomRaiseHand.tsx +0 -65
- package/template/src/components/breakout-room/ui/BreakoutRoomRenameModal.tsx +0 -227
- package/template/src/components/breakout-room/ui/BreakoutRoomSettings.tsx +0 -140
- package/template/src/components/breakout-room/ui/BreakoutRoomTransition.tsx +0 -52
- package/template/src/components/breakout-room/ui/BreakoutRoomView.tsx +0 -193
- package/template/src/components/breakout-room/ui/ExitBreakoutRoomIconButton.tsx +0 -79
- package/template/src/components/breakout-room/ui/ParticipantManualAssignmentModal.tsx +0 -638
- package/template/src/components/breakout-room/ui/SelectParticipantAssignmentStrategy.tsx +0 -57
- package/template/src/components/common/Dividers.tsx +0 -53
- package/template/src/components/controls/toolbar-items/ExitBreakoutRoomToolbarItem.tsx +0 -13
- package/template/src/components/raise-hand/RaiseHandButton.tsx +0 -50
- package/template/src/components/raise-hand/RaiseHandProvider.tsx +0 -308
- package/template/src/components/raise-hand/index.ts +0 -14
- package/template/src/components/room-info/useCurrentRoomInfo.tsx +0 -42
- package/template/src/components/room-info/useSetBreakoutRoomInfo.tsx +0 -64
- package/template/src/pages/video-call/BreakoutVideoCall.tsx +0 -213
- package/template/src/pages/video-call/VideoCallContent.tsx +0 -211
- package/template/src/pages/video-call/VideoCallStateWrapper.tsx +0 -495
- package/template/src/rtm/RTMConfigureBreakoutRoomProvider.tsx +0 -882
- package/template/src/rtm/RTMConfigureMainRoomProvider.tsx +0 -757
- package/template/src/rtm/RTMCoreProvider.tsx +0 -419
- package/template/src/rtm/RTMGlobalStateProvider.tsx +0 -706
- package/template/src/rtm/RTMStatusBanner.tsx +0 -99
- package/template/src/rtm/constants.ts +0 -12
- package/template/src/rtm/hooks/useMainRoomUserDisplayName.ts +0 -45
- package/template/src/rtm/rtm-presence-utils.ts +0 -344
- package/template/src/subComponents/chat/ChatAnnouncementView.tsx +0 -65
- package/template/src/utils/useDebouncedCallback.tsx +0 -20
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import React, {useState, useEffect} from 'react';
|
|
2
|
-
import {View, Text, StyleSheet} from 'react-native';
|
|
3
|
-
import {useRTMCore} from './RTMCoreProvider';
|
|
4
|
-
import {nativeLinkStateMapping} from '../../bridge/rtm/web/Types';
|
|
5
|
-
|
|
6
|
-
export const RTMStatusBanner = () => {
|
|
7
|
-
const {connectionState, error, isLoggedIn} = useRTMCore();
|
|
8
|
-
|
|
9
|
-
// internal debounced copy of the state to prevent flicker
|
|
10
|
-
const [visibleState, setVisibleState] = useState(connectionState);
|
|
11
|
-
const [visibleError, setVisibleError] = useState(error);
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
const timeout = setTimeout(() => {
|
|
15
|
-
setVisibleState(connectionState);
|
|
16
|
-
setVisibleError(error);
|
|
17
|
-
}, 700); // debounce 700 ms
|
|
18
|
-
return () => clearTimeout(timeout);
|
|
19
|
-
}, [connectionState, error]);
|
|
20
|
-
|
|
21
|
-
// Don't show banner if connected and logged in with no errors
|
|
22
|
-
if (
|
|
23
|
-
visibleState === nativeLinkStateMapping.CONNECTED &&
|
|
24
|
-
isLoggedIn &&
|
|
25
|
-
!visibleError
|
|
26
|
-
) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let message = '';
|
|
31
|
-
let isError = false;
|
|
32
|
-
|
|
33
|
-
if (visibleError || visibleState === nativeLinkStateMapping.FAILED) {
|
|
34
|
-
// Login failed - critical error
|
|
35
|
-
message =
|
|
36
|
-
'RTM connection failed. App might not work correctly. Retrying...';
|
|
37
|
-
isError = true;
|
|
38
|
-
} else if (visibleState === nativeLinkStateMapping.DISCONNECTED) {
|
|
39
|
-
// RTM disconnected in the middle of the call - retrying
|
|
40
|
-
message = 'RTM disconnected — retrying connection...';
|
|
41
|
-
isError = false;
|
|
42
|
-
} else if (
|
|
43
|
-
visibleState === nativeLinkStateMapping.IDLE ||
|
|
44
|
-
visibleState === nativeLinkStateMapping.CONNECTING
|
|
45
|
-
) {
|
|
46
|
-
// RTM is idle or connecting
|
|
47
|
-
message = 'RTM connecting...';
|
|
48
|
-
isError = false;
|
|
49
|
-
} else if (!isLoggedIn) {
|
|
50
|
-
// Not logged in but no explicit error yet
|
|
51
|
-
message = 'RTM connecting...';
|
|
52
|
-
isError = false;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Don't render banner if there's no message to show
|
|
56
|
-
if (!message) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<View style={[styles.banner, isError ? styles.error : styles.warning]}>
|
|
62
|
-
<Text
|
|
63
|
-
style={[styles.text, isError ? styles.errorText : styles.warningText]}>
|
|
64
|
-
{message}
|
|
65
|
-
</Text>
|
|
66
|
-
</View>
|
|
67
|
-
);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const styles = StyleSheet.create({
|
|
71
|
-
banner: {
|
|
72
|
-
position: 'absolute',
|
|
73
|
-
top: 0,
|
|
74
|
-
left: 0,
|
|
75
|
-
right: 0,
|
|
76
|
-
paddingVertical: 8,
|
|
77
|
-
paddingHorizontal: 16,
|
|
78
|
-
zIndex: 9999,
|
|
79
|
-
alignItems: 'center',
|
|
80
|
-
justifyContent: 'center',
|
|
81
|
-
},
|
|
82
|
-
error: {
|
|
83
|
-
backgroundColor: '#f8d7da',
|
|
84
|
-
},
|
|
85
|
-
warning: {
|
|
86
|
-
backgroundColor: '#fff3cd',
|
|
87
|
-
},
|
|
88
|
-
text: {
|
|
89
|
-
fontSize: 14,
|
|
90
|
-
fontWeight: '500',
|
|
91
|
-
textAlign: 'center',
|
|
92
|
-
},
|
|
93
|
-
errorText: {
|
|
94
|
-
color: '#721c24',
|
|
95
|
-
},
|
|
96
|
-
warningText: {
|
|
97
|
-
color: '#856404',
|
|
98
|
-
},
|
|
99
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import {EventNames} from '../rtm-events';
|
|
2
|
-
|
|
3
|
-
export enum RTM_ROOMS {
|
|
4
|
-
BREAKOUT = 'BREAKOUT',
|
|
5
|
-
MAIN = 'MAIN',
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// RTM attributes to reset when room changes
|
|
9
|
-
export const RTM_EVENTS_ATTRIBUTES_TO_RESET_WHEN_ROOM_CHANGES = [
|
|
10
|
-
EventNames.RAISED_ATTRIBUTE, // (livestream)
|
|
11
|
-
EventNames.BREAKOUT_RAISE_HAND_ATTRIBUTE, // Breakout room raise hand ( will be made into independent)
|
|
12
|
-
] as const;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
********************************************
|
|
3
|
-
Copyright © 2021 Agora Lab, Inc., all rights reserved.
|
|
4
|
-
AppBuilder and all associated components, source code, APIs, services, and documentation
|
|
5
|
-
(the "Materials") are owned by Agora Lab, Inc. and its licensors. The Materials may not be
|
|
6
|
-
accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
|
|
7
|
-
Use without a license or in violation of any license terms and conditions (including use for
|
|
8
|
-
any purpose competitive to Agora Lab, Inc.'s business) is strictly prohibited. For more
|
|
9
|
-
information visit https://appbuilder.agora.io.
|
|
10
|
-
*********************************************
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import {useCallback} from 'react';
|
|
14
|
-
import {videoRoomUserFallbackText} from '../../language/default-labels/videoCallScreenLabels';
|
|
15
|
-
import {useString} from '../../utils/useString';
|
|
16
|
-
import {UidType} from '../../../agora-rn-uikit';
|
|
17
|
-
import {useRTMGlobalState} from '../RTMGlobalStateProvider';
|
|
18
|
-
import {useContent} from 'customization-api';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Hook to get user display names with fallback to main room RTM users
|
|
22
|
-
* This ensures users in breakout rooms can see names of users in other rooms
|
|
23
|
-
*/
|
|
24
|
-
export const useMainRoomUserDisplayName = () => {
|
|
25
|
-
const {mainRoomRTMUsers} = useRTMGlobalState();
|
|
26
|
-
const {defaultContent} = useContent();
|
|
27
|
-
const remoteUserDefaultLabel = useString(videoRoomUserFallbackText)();
|
|
28
|
-
|
|
29
|
-
const sanitize = (name?: string) => name?.trim() || undefined;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* useCallback ensures the returned function updates whenever
|
|
33
|
-
* defaultContent or mainRoomRTMUsers change
|
|
34
|
-
*/
|
|
35
|
-
return useCallback(
|
|
36
|
-
(uid: UidType): string => {
|
|
37
|
-
return (
|
|
38
|
-
sanitize(defaultContent?.[uid]?.name) ||
|
|
39
|
-
sanitize(mainRoomRTMUsers?.[uid]?.name) ||
|
|
40
|
-
remoteUserDefaultLabel
|
|
41
|
-
);
|
|
42
|
-
},
|
|
43
|
-
[defaultContent, mainRoomRTMUsers, remoteUserDefaultLabel],
|
|
44
|
-
);
|
|
45
|
-
};
|
|
@@ -1,344 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import {backOff} from 'exponential-backoff';
|
|
3
|
-
import {LogSource, logger} from '../logger/AppBuilderLogger';
|
|
4
|
-
import {
|
|
5
|
-
type GetUserMetadataResponse as NativeGetUserMetadataResponse,
|
|
6
|
-
type GetOnlineUsersResponse as NativeGetOnlineUsersResponse,
|
|
7
|
-
type GetChannelMetadataResponse,
|
|
8
|
-
type RTMClient,
|
|
9
|
-
type UserState,
|
|
10
|
-
type MetadataItem,
|
|
11
|
-
} from 'agora-react-native-rtm';
|
|
12
|
-
import {RTMUserData} from './RTMGlobalStateProvider';
|
|
13
|
-
import {RECORDING_BOT_UID} from '../utils/constants';
|
|
14
|
-
import {hasJsonStructure} from '../rtm/utils';
|
|
15
|
-
import {nativeChannelTypeMapping} from '../../bridge/rtm/web/Types';
|
|
16
|
-
|
|
17
|
-
export const fetchOnlineMembersWithRetries = async (
|
|
18
|
-
client: RTMClient,
|
|
19
|
-
channelName: string,
|
|
20
|
-
{
|
|
21
|
-
onPage, // 👈 callback so caller can process each page as soon as it's ready
|
|
22
|
-
}: {
|
|
23
|
-
onPage?: (page: {
|
|
24
|
-
occupants: UserState[];
|
|
25
|
-
total: number;
|
|
26
|
-
pageToken?: string;
|
|
27
|
-
}) => void | Promise<void>;
|
|
28
|
-
} = {},
|
|
29
|
-
) => {
|
|
30
|
-
let allMembers: any[] = [];
|
|
31
|
-
let nextPage: string | undefined;
|
|
32
|
-
let totalOccupancy = 0;
|
|
33
|
-
|
|
34
|
-
const fetchPage = async (pageNumber?: string) => {
|
|
35
|
-
return backOff(
|
|
36
|
-
async () => {
|
|
37
|
-
const result: NativeGetOnlineUsersResponse =
|
|
38
|
-
await client.presence.getOnlineUsers(
|
|
39
|
-
channelName,
|
|
40
|
-
nativeChannelTypeMapping.MESSAGE,
|
|
41
|
-
{page: pageNumber}, // cursor for pagination
|
|
42
|
-
);
|
|
43
|
-
return result;
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
numOfAttempts: 3,
|
|
47
|
-
retry: (e, attempt) => {
|
|
48
|
-
console.warn(
|
|
49
|
-
`[RTM] Page fetch failed (attempt ${attempt}/3). Retrying…`,
|
|
50
|
-
e,
|
|
51
|
-
);
|
|
52
|
-
return attempt < 3; // 👈 stop retrying after 3rd attempt
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
do {
|
|
59
|
-
try {
|
|
60
|
-
const result = await fetchPage(nextPage);
|
|
61
|
-
const {totalOccupancy: total, occupants, nextPage: next} = result;
|
|
62
|
-
if (occupants) {
|
|
63
|
-
allMembers = allMembers.concat(occupants);
|
|
64
|
-
// process this page immediately
|
|
65
|
-
await onPage?.({occupants, total, pageToken: nextPage});
|
|
66
|
-
}
|
|
67
|
-
totalOccupancy = total;
|
|
68
|
-
nextPage = next;
|
|
69
|
-
console.log(
|
|
70
|
-
`[RTM] Fetched ${allMembers.length}/${totalOccupancy} users, nextPage=${nextPage}`,
|
|
71
|
-
);
|
|
72
|
-
} catch (fetchPageError) {
|
|
73
|
-
console.error(`[RTM] Page ${nextPage || 'first'} failed`, fetchPageError);
|
|
74
|
-
// 👉 Skip to next page if this one keeps failing
|
|
75
|
-
nextPage = undefined;
|
|
76
|
-
}
|
|
77
|
-
} while (nextPage && nextPage.trim() !== '');
|
|
78
|
-
|
|
79
|
-
return {allMembers, totalOccupancy};
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export const fetchUserAttributesWithRetries = async (
|
|
83
|
-
client: RTMClient,
|
|
84
|
-
userId: string,
|
|
85
|
-
opts?: {
|
|
86
|
-
isMounted?: () => boolean; // <-- injected check
|
|
87
|
-
onNameFound?: (attr: NativeGetUserMetadataResponse) => void;
|
|
88
|
-
},
|
|
89
|
-
): Promise<NativeGetUserMetadataResponse> => {
|
|
90
|
-
return backOff(
|
|
91
|
-
async () => {
|
|
92
|
-
console.log(
|
|
93
|
-
'rudra-core-client: RTM fetching getUserMetadata for member',
|
|
94
|
-
userId,
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
// Fetch attributes
|
|
98
|
-
const attr: NativeGetUserMetadataResponse =
|
|
99
|
-
await client.storage.getUserMetadata({userId});
|
|
100
|
-
console.log('[user attributes', attr);
|
|
101
|
-
|
|
102
|
-
// 1. Check if attributes exist
|
|
103
|
-
if (!attr || !attr.items || attr.items.length === 0) {
|
|
104
|
-
console.log('rudra-core-client: RTM attributes for member not found');
|
|
105
|
-
throw new Error('No attribute items found');
|
|
106
|
-
}
|
|
107
|
-
console.log('sup-attribute-check user-attributes', attr);
|
|
108
|
-
|
|
109
|
-
// 2. Partial update allowed (screenUid, isHost, etc.)
|
|
110
|
-
const hasAny = attr.items.some(i => i.value);
|
|
111
|
-
if (!hasAny) {
|
|
112
|
-
throw new Error('No usable user-attributes yet');
|
|
113
|
-
}
|
|
114
|
-
console.log('sup-attribute-check user-attributes hasAny', hasAny);
|
|
115
|
-
|
|
116
|
-
// 3. If name exists, return immediately
|
|
117
|
-
const hasNameAttribute = attr.items.find(
|
|
118
|
-
i => i.key === 'name' && i.value,
|
|
119
|
-
);
|
|
120
|
-
console.log('sup-attribute-check user-attributes name', hasNameAttribute);
|
|
121
|
-
if (hasNameAttribute) {
|
|
122
|
-
return attr;
|
|
123
|
-
}
|
|
124
|
-
// 4. Background retry for name only
|
|
125
|
-
(async () => {
|
|
126
|
-
await backOff(
|
|
127
|
-
async () => {
|
|
128
|
-
// 🔒 Stop if unmounted
|
|
129
|
-
if (opts?.isMounted && !opts?.isMounted) {
|
|
130
|
-
throw new Error(`Component unmounted while retrying ${userId}`);
|
|
131
|
-
}
|
|
132
|
-
console.log(
|
|
133
|
-
'sup-attribute-check user-attributes inside name backoff',
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
const retriedAttributes: NativeGetUserMetadataResponse =
|
|
137
|
-
await client.storage.getUserMetadata({userId});
|
|
138
|
-
console.log(
|
|
139
|
-
'sup-attribute-check user-attributes retriedAttributes',
|
|
140
|
-
retriedAttributes,
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
const hasNameAttributeRetry = retriedAttributes.items.find(
|
|
144
|
-
i => i.key === 'name' && i.value,
|
|
145
|
-
);
|
|
146
|
-
console.log(
|
|
147
|
-
'sup-attribute-check user-attributes hasNameAttributeRetry',
|
|
148
|
-
hasNameAttributeRetry,
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
if (!hasNameAttributeRetry) {
|
|
152
|
-
throw new Error('user-attributes Name still not found');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (opts?.isMounted) {
|
|
156
|
-
console.log(
|
|
157
|
-
'sup-attribute-check user-attributes onNameFound',
|
|
158
|
-
retriedAttributes,
|
|
159
|
-
);
|
|
160
|
-
opts?.onNameFound?.(retriedAttributes);
|
|
161
|
-
}
|
|
162
|
-
return retriedAttributes;
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
retry: () => true,
|
|
166
|
-
maxDelay: Infinity, // No maximum delay limit for name
|
|
167
|
-
numOfAttempts: Infinity, // Infinite attempts for name
|
|
168
|
-
},
|
|
169
|
-
).catch(() => {
|
|
170
|
-
console.log(
|
|
171
|
-
`Name not found for ${userId} within 30s, giving up further retries`,
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
})();
|
|
175
|
-
|
|
176
|
-
return attr;
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
retry: (e, idx) => {
|
|
180
|
-
logger.debug(
|
|
181
|
-
LogSource.AgoraSDK,
|
|
182
|
-
'Log',
|
|
183
|
-
`[retrying] Attempt ${idx}. Fetching ${userId}'s name`,
|
|
184
|
-
e,
|
|
185
|
-
);
|
|
186
|
-
return true;
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
);
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
export const mapUserAttributesToState = (
|
|
193
|
-
attr: NativeGetUserMetadataResponse,
|
|
194
|
-
userId: string,
|
|
195
|
-
updateFn: (uid: number, userData: Partial<RTMUserData>) => void,
|
|
196
|
-
) => {
|
|
197
|
-
try {
|
|
198
|
-
const uid = parseInt(userId, 10);
|
|
199
|
-
const screenUidItem = attr?.items?.find(item => item.key === 'screenUid');
|
|
200
|
-
const isHostItem = attr?.items?.find(item => item.key === 'isHost');
|
|
201
|
-
const nameItem = attr?.items?.find(item => item.key === 'name');
|
|
202
|
-
const screenUid = screenUidItem?.value
|
|
203
|
-
? parseInt(screenUidItem.value, 10)
|
|
204
|
-
: undefined;
|
|
205
|
-
|
|
206
|
-
let userName = '';
|
|
207
|
-
if (nameItem?.value) {
|
|
208
|
-
try {
|
|
209
|
-
const parsedValue = JSON.parse(nameItem.value);
|
|
210
|
-
const payloadString = parsedValue.payload;
|
|
211
|
-
if (payloadString) {
|
|
212
|
-
const payload = JSON.parse(payloadString);
|
|
213
|
-
userName = payload.name;
|
|
214
|
-
}
|
|
215
|
-
} catch {
|
|
216
|
-
// ignore parse errors
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// --- Update main user RTM data
|
|
221
|
-
const userData: RTMUserData = {
|
|
222
|
-
uid,
|
|
223
|
-
type: uid === parseInt(RECORDING_BOT_UID, 10) ? 'bot' : 'rtc',
|
|
224
|
-
screenUid,
|
|
225
|
-
name: userName,
|
|
226
|
-
offline: false,
|
|
227
|
-
isHost: isHostItem?.value || 'false',
|
|
228
|
-
lastMessageTimeStamp: 0,
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
updateFn(uid, userData);
|
|
232
|
-
|
|
233
|
-
// --- Update screenshare RTM data if present
|
|
234
|
-
if (screenUid) {
|
|
235
|
-
const screenShareData: RTMUserData = {
|
|
236
|
-
type: 'screenshare',
|
|
237
|
-
parentUid: uid,
|
|
238
|
-
};
|
|
239
|
-
updateFn(screenUid, screenShareData);
|
|
240
|
-
}
|
|
241
|
-
} catch (e) {
|
|
242
|
-
console.log('RTM Failed to process user data for', userId, e);
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
export const fetchChannelAttributesWithRetries = async (
|
|
247
|
-
client: RTMClient,
|
|
248
|
-
channelName: string,
|
|
249
|
-
updateFn?: (eventData: {data: any; uid: string; ts: number}) => void,
|
|
250
|
-
) => {
|
|
251
|
-
try {
|
|
252
|
-
await client.storage
|
|
253
|
-
.getChannelMetadata(channelName, nativeChannelTypeMapping.MESSAGE)
|
|
254
|
-
.then(async (data: GetChannelMetadataResponse) => {
|
|
255
|
-
for (const item of data.items) {
|
|
256
|
-
try {
|
|
257
|
-
const {key, value, authorUserId, updateTs} = item;
|
|
258
|
-
if (hasJsonStructure(value as string)) {
|
|
259
|
-
const evtData = {
|
|
260
|
-
evt: key,
|
|
261
|
-
value,
|
|
262
|
-
};
|
|
263
|
-
updateFn?.({
|
|
264
|
-
data: evtData,
|
|
265
|
-
uid: authorUserId,
|
|
266
|
-
ts: updateTs,
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
} catch (error) {
|
|
270
|
-
logger.error(
|
|
271
|
-
LogSource.AgoraSDK,
|
|
272
|
-
'Log',
|
|
273
|
-
`RTM Failed to process channel attribute item: ${JSON.stringify(
|
|
274
|
-
item,
|
|
275
|
-
)}`,
|
|
276
|
-
{error},
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
} catch (error) {}
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
export const clearRoomScopedUserAttributes = async (
|
|
285
|
-
client: RTMClient,
|
|
286
|
-
attributeKeys: readonly string[],
|
|
287
|
-
) => {
|
|
288
|
-
try {
|
|
289
|
-
await client?.storage.removeUserMetadata({
|
|
290
|
-
data: {
|
|
291
|
-
items: attributeKeys.map(key => ({
|
|
292
|
-
key,
|
|
293
|
-
value: '',
|
|
294
|
-
})),
|
|
295
|
-
},
|
|
296
|
-
});
|
|
297
|
-
} catch (error) {
|
|
298
|
-
logger.error(
|
|
299
|
-
LogSource.AgoraSDK,
|
|
300
|
-
'RTMConfigure',
|
|
301
|
-
'Failed to clear room-scoped attributes',
|
|
302
|
-
{error},
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
export const processUserAttributeForQueue = (
|
|
308
|
-
item: MetadataItem,
|
|
309
|
-
userId: string,
|
|
310
|
-
currentRoomKey: string,
|
|
311
|
-
onProcessedEvent: (eventKey: string, value: string, userId: string) => void,
|
|
312
|
-
) => {
|
|
313
|
-
try {
|
|
314
|
-
if (hasJsonStructure(item.value as string)) {
|
|
315
|
-
let eventKey = item.key;
|
|
316
|
-
try {
|
|
317
|
-
// const parsedValue = JSON.parse(item.value);
|
|
318
|
-
// if (parsedValue.persistLevel === PersistanceLevel.Session) {
|
|
319
|
-
// const strippedKey = stripRoomPrefixFromEventKey(
|
|
320
|
-
// item.key,
|
|
321
|
-
// currentRoomKey,
|
|
322
|
-
// );
|
|
323
|
-
// if (strippedKey === null) {
|
|
324
|
-
// console.log(
|
|
325
|
-
// 'Skipping SESSION attribute for different room:',
|
|
326
|
-
// item.key,
|
|
327
|
-
// );
|
|
328
|
-
// return;
|
|
329
|
-
// }
|
|
330
|
-
// eventKey = strippedKey;
|
|
331
|
-
// }
|
|
332
|
-
|
|
333
|
-
onProcessedEvent(eventKey, item.value, userId);
|
|
334
|
-
} catch (e) {}
|
|
335
|
-
}
|
|
336
|
-
} catch (error) {
|
|
337
|
-
logger.error(
|
|
338
|
-
LogSource.AgoraSDK,
|
|
339
|
-
'Log',
|
|
340
|
-
'RTM Failed to process user attribute item',
|
|
341
|
-
{error},
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import {View, StyleSheet, Text} from 'react-native';
|
|
3
|
-
import ImageIcon from '../../atoms/ImageIcon';
|
|
4
|
-
import ThemeConfig from '../../theme';
|
|
5
|
-
import {AnnouncementMessage} from '../../components/chat-messages/useChatMessages';
|
|
6
|
-
|
|
7
|
-
export default function ChatAnnouncementView({
|
|
8
|
-
message,
|
|
9
|
-
announcement,
|
|
10
|
-
}: {
|
|
11
|
-
message: string;
|
|
12
|
-
announcement: AnnouncementMessage;
|
|
13
|
-
}) {
|
|
14
|
-
return (
|
|
15
|
-
<View style={style.announcementView}>
|
|
16
|
-
<ImageIcon
|
|
17
|
-
iconSize={20}
|
|
18
|
-
iconType="plain"
|
|
19
|
-
name="announcement"
|
|
20
|
-
tintColor={'#099DFD'}
|
|
21
|
-
/>
|
|
22
|
-
<View style={style.announcementMessage}>
|
|
23
|
-
<Text style={style.announcementMessageHeader}>
|
|
24
|
-
Message from host: {announcement.sender}
|
|
25
|
-
</Text>
|
|
26
|
-
<Text style={style.announcementMessageBody}>{message}</Text>
|
|
27
|
-
</View>
|
|
28
|
-
</View>
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const style = StyleSheet.create({
|
|
33
|
-
announcementView: {
|
|
34
|
-
display: 'flex',
|
|
35
|
-
flexDirection: 'row',
|
|
36
|
-
alignItems: 'flex-start',
|
|
37
|
-
justifyContent: 'flex-start',
|
|
38
|
-
marginRight: 12,
|
|
39
|
-
marginLeft: 12,
|
|
40
|
-
marginBottom: 4,
|
|
41
|
-
marginTop: 16,
|
|
42
|
-
gap: 6,
|
|
43
|
-
},
|
|
44
|
-
announcementMessage: {
|
|
45
|
-
display: 'flex',
|
|
46
|
-
flexDirection: 'column',
|
|
47
|
-
gap: 2,
|
|
48
|
-
},
|
|
49
|
-
announcementMessageHeader: {
|
|
50
|
-
fontSize: ThemeConfig.FontSize.tiny,
|
|
51
|
-
fontStyle: 'normal',
|
|
52
|
-
fontFamily: ThemeConfig.FontFamily.sansPro,
|
|
53
|
-
color: '#099DFD',
|
|
54
|
-
fontWeight: '700',
|
|
55
|
-
lineHeight: 14,
|
|
56
|
-
},
|
|
57
|
-
announcementMessageBody: {
|
|
58
|
-
fontSize: ThemeConfig.FontSize.tiny,
|
|
59
|
-
fontStyle: 'italic',
|
|
60
|
-
fontFamily: ThemeConfig.FontFamily.sansPro,
|
|
61
|
-
color: '#099DFD',
|
|
62
|
-
fontWeight: '400',
|
|
63
|
-
lineHeight: 14,
|
|
64
|
-
},
|
|
65
|
-
});
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import {useRef, useCallback} from 'react';
|
|
2
|
-
|
|
3
|
-
export function useDebouncedCallback<T extends (...args: any[]) => void>(
|
|
4
|
-
fn: T,
|
|
5
|
-
delay: number,
|
|
6
|
-
): (...args: Parameters<T>) => void {
|
|
7
|
-
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
8
|
-
|
|
9
|
-
const debounced = useCallback(
|
|
10
|
-
(...args: Parameters<T>) => {
|
|
11
|
-
if (timeoutRef.current) {
|
|
12
|
-
clearTimeout(timeoutRef.current);
|
|
13
|
-
}
|
|
14
|
-
timeoutRef.current = setTimeout(() => fn(...args), delay);
|
|
15
|
-
},
|
|
16
|
-
[fn, delay],
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
return debounced;
|
|
20
|
-
}
|