agora-appbuilder-core 4.1.22 → 4.1.23-beta.1
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/-clean/_logs/2024-11-08T10_59_57_653Z-debug-0.log +45 -0
- package/template/.buckconfig +6 -0
- package/template/.eslintrc.js +20 -0
- package/template/.gitattributes +1 -0
- package/template/.prettierrc.js +18 -0
- package/template/.watchmanconfig +1 -0
- package/template/android/.idea/.name +1 -0
- package/template/android/.idea/compiler.xml +6 -0
- package/template/android/.idea/deploymentTargetDropDown.xml +34 -0
- package/template/android/.idea/gradle.xml +53 -0
- package/template/android/.idea/jarRepositories.xml +50 -0
- package/template/android/.idea/kotlinc.xml +6 -0
- package/template/android/.idea/migrations.xml +10 -0
- package/template/android/.idea/misc.xml +12 -0
- package/template/android/.idea/modules/-1014912928/HelloWorld.react-native-agora-chat.main.iml +11 -0
- package/template/android/.idea/modules/-1705378519/HelloWorld.react-native-reanimated.main.iml +42 -0
- package/template/android/.idea/modules.xml +9 -0
- package/template/android/.idea/vcs.xml +6 -0
- package/template/android/local.properties +9 -0
- package/template/config.json +101 -0
- package/template/customization/CustomEndCallPage.tsx +122 -0
- package/template/customization/CustomWrapper.tsx +121 -0
- package/template/customization/NewBottomBar.tsx +86 -0
- package/template/customization/NewUserActionsMenu.tsx +137 -0
- package/template/customization/PinContext.tsx +142 -0
- package/template/customization/PreferenceWraper.tsx +212 -0
- package/template/customization/Reactions.tsx +228 -0
- package/template/customization/host-controls/AudioControlOverride.tsx +49 -0
- package/template/customization/host-controls/VideoControlOverride.tsx +53 -0
- package/template/customization/index.tsx +72 -0
- package/template/customization/package.json +13 -0
- package/template/defaultConfig.js +2 -2
- package/template/package-lock.json +57454 -0
- package/template/src/pages/video-call/SidePanelHeader.tsx +7 -4
- package/template/src/subComponents/caption/CLAUDE.md +252 -0
- package/template/src/subComponents/caption/Caption.tsx +1 -38
- package/template/src/subComponents/caption/CaptionIcon.tsx +11 -10
- package/template/src/subComponents/caption/DownloadTranscriptBtn.tsx +5 -4
- package/template/src/subComponents/caption/Transcript.tsx +1 -32
- package/template/src/subComponents/caption/TranscriptIcon.tsx +10 -18
- package/template/src/subComponents/caption/useCaption.tsx +101 -7
- package/template/src/subComponents/caption/useSTTAPI.tsx +99 -14
- package/template/src/subComponents/caption/useStreamMessageUtils.native.ts +35 -20
- package/template/src/subComponents/caption/useStreamMessageUtils.ts +42 -25
- package/template/src/subComponents/caption/useTranscriptDownload.native.ts +59 -69
- package/template/src/subComponents/caption/useTranscriptDownload.ts +54 -43
- package/template/src/utils/useSpeechToText.ts +3 -29
- package/template/theme.json +91 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {
|
|
2
|
+
customEvents,
|
|
3
|
+
useLocalAudio,
|
|
4
|
+
useLocalVideo,
|
|
5
|
+
useRoomInfo,
|
|
6
|
+
UidType,
|
|
7
|
+
useUserActionMenu,
|
|
8
|
+
useContent,
|
|
9
|
+
useWhiteboard,
|
|
10
|
+
} from 'customization-api';
|
|
11
|
+
import React, {useEffect, useRef, useState} from 'react';
|
|
12
|
+
import {PinProvider} from './PinContext';
|
|
13
|
+
|
|
14
|
+
export interface CustomWrapperContextInterface {
|
|
15
|
+
pinnedForAllUid: UidType | null;
|
|
16
|
+
setPinnedForAllUid: React.Dispatch<React.SetStateAction<UidType | null>>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const CustomWrapperContext = React.createContext<CustomWrapperContextInterface>(
|
|
20
|
+
{
|
|
21
|
+
pinnedForAllUid: null,
|
|
22
|
+
setPinnedForAllUid: () => {},
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
interface CustomWrapperProviderProps {
|
|
27
|
+
children: React.ReactNode;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const CustomWrapperProvider = (props: CustomWrapperProviderProps) => {
|
|
31
|
+
const {enableAudioButton, disableAudioButton} = useLocalAudio();
|
|
32
|
+
const {enableVideoButton, disableVideoButton} = useLocalVideo();
|
|
33
|
+
const {
|
|
34
|
+
data: {isHost},
|
|
35
|
+
} = useRoomInfo();
|
|
36
|
+
|
|
37
|
+
const [pinnedForAllUid, setPinnedForAllUid] = useState<UidType | null>(null);
|
|
38
|
+
const {pinForEveryone, unPinForEveryone} = useUserActionMenu();
|
|
39
|
+
const {pinnedUid} = useContent();
|
|
40
|
+
const {getWhiteboardUid} = useWhiteboard();
|
|
41
|
+
|
|
42
|
+
// override default host controls
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
/**
|
|
45
|
+
* custom event listener for disable attendee mic
|
|
46
|
+
* Here we can call disableAudioButton/enableAudioButton function to update participant mic button state
|
|
47
|
+
*/
|
|
48
|
+
customEvents.on('DISABLE_ATTENDEE_MIC', ({payload}) => {
|
|
49
|
+
try {
|
|
50
|
+
//host side we don't disable the button so ignoring it
|
|
51
|
+
if (isHost) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
//attendee only disable the mic button
|
|
55
|
+
const data = JSON.parse(payload);
|
|
56
|
+
if (data && data === true) {
|
|
57
|
+
disableAudioButton();
|
|
58
|
+
} else {
|
|
59
|
+
enableAudioButton();
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.log('debugging error on DISABLE_ATTENDEE_MIC listener ');
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
customEvents.on('DISABLE_ATTENDEE_VIDEO', ({payload}) => {
|
|
66
|
+
try {
|
|
67
|
+
//host side we don't disable the button so ignoring it
|
|
68
|
+
if (isHost) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
//attendee only disable the mic button
|
|
72
|
+
const data = JSON.parse(payload);
|
|
73
|
+
if (data && data === true) {
|
|
74
|
+
disableVideoButton();
|
|
75
|
+
} else {
|
|
76
|
+
enableVideoButton();
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.log('debugging error on DISABLE_ATTENDEE_VIDEO listener ');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Custom event listener for PIN_FOR_EVERYONE
|
|
85
|
+
* @param {Object} payload - The payload data sent with the event.
|
|
86
|
+
*/
|
|
87
|
+
customEvents.on('PIN_FOR_EVERYONE', ({payload}) => {
|
|
88
|
+
try {
|
|
89
|
+
const data = JSON.parse(payload);
|
|
90
|
+
const pinUID =
|
|
91
|
+
data.uidType === 'whiteboard' && data.pinForAllUid
|
|
92
|
+
? getWhiteboardUid()
|
|
93
|
+
: data.pinForAllUid;
|
|
94
|
+
|
|
95
|
+
setPinnedForAllUid(pinUID);
|
|
96
|
+
if (data.pinForAllUid) {
|
|
97
|
+
pinForEveryone(pinUID);
|
|
98
|
+
} else {
|
|
99
|
+
unPinForEveryone();
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.log('debugging error on PIN_FOR_EVERYONE listener ');
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return () => {
|
|
107
|
+
customEvents.off('DISABLE_ATTENDEE_MIC', () => {});
|
|
108
|
+
customEvents.off('DISABLE_ATTENDEE_VIDEO', () => {});
|
|
109
|
+
customEvents.off('PIN_FOR_EVERYONE', () => {});
|
|
110
|
+
};
|
|
111
|
+
}, []);
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<CustomWrapperContext.Provider
|
|
115
|
+
value={{pinnedForAllUid, setPinnedForAllUid}}>
|
|
116
|
+
<PinProvider>{props.children}</PinProvider>
|
|
117
|
+
</CustomWrapperContext.Provider>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export {CustomWrapperProvider, CustomWrapperContext};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ToolbarPreset,
|
|
3
|
+
ToolbarComponents,
|
|
4
|
+
ToolbarItem,
|
|
5
|
+
useRoomInfo,
|
|
6
|
+
useLocalAudio,
|
|
7
|
+
TertiaryButton,
|
|
8
|
+
customEvents,
|
|
9
|
+
PersistanceLevel,
|
|
10
|
+
useEndCall,
|
|
11
|
+
useHistory,
|
|
12
|
+
getCustomRoute,
|
|
13
|
+
useIsHost,
|
|
14
|
+
useLocalUid,
|
|
15
|
+
useIsAttendee,
|
|
16
|
+
} from 'customization-api';
|
|
17
|
+
import React, {useContext, useEffect, useRef, useState} from 'react';
|
|
18
|
+
import Reactions from './Reactions';
|
|
19
|
+
|
|
20
|
+
const NewEndCall = () => {
|
|
21
|
+
const {LocalEndcallToolbarItem} = ToolbarComponents;
|
|
22
|
+
const endCall = useEndCall();
|
|
23
|
+
const localUid = useLocalUid();
|
|
24
|
+
const isHost = useIsHost();
|
|
25
|
+
const history = useHistory();
|
|
26
|
+
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
customEvents.on('Host_Disconnects_Call', handleEndCallback);
|
|
29
|
+
return () => {
|
|
30
|
+
customEvents.off('Host_Disconnects_Call', handleEndCallback);
|
|
31
|
+
};
|
|
32
|
+
}, []);
|
|
33
|
+
const handleEndCallback = data => {
|
|
34
|
+
const payload = JSON.parse(data?.payload);
|
|
35
|
+
if (payload.callEnded) {
|
|
36
|
+
// other attendees leave call
|
|
37
|
+
endCall();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return (
|
|
41
|
+
<LocalEndcallToolbarItem
|
|
42
|
+
customExit={() => {
|
|
43
|
+
// only host can make other participants exist when host ends the call
|
|
44
|
+
if (isHost(localUid)) {
|
|
45
|
+
customEvents.send(
|
|
46
|
+
'Host_Disconnects_Call',
|
|
47
|
+
JSON.stringify({callEnded: true}),
|
|
48
|
+
PersistanceLevel.Session,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
// Delay the call end and navigation slightly to ensure the event is sent before the page unloads
|
|
52
|
+
window.setTimeout(() => {
|
|
53
|
+
endCall();
|
|
54
|
+
history.push(getCustomRoute('call-ended')); // optional : if user wants to navigate to a custom page after call ends
|
|
55
|
+
}, 50);
|
|
56
|
+
}}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const NewBottomBar = () => {
|
|
62
|
+
const {ChatToolbarItem, ParticipantToolbarItem} = ToolbarComponents;
|
|
63
|
+
|
|
64
|
+
const localUid = useLocalUid();
|
|
65
|
+
const isAttendee = useIsAttendee();
|
|
66
|
+
const isAttendeeUser = isAttendee(localUid);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<ToolbarPreset
|
|
70
|
+
align="bottom"
|
|
71
|
+
items={{
|
|
72
|
+
reactions: {
|
|
73
|
+
component: Reactions,
|
|
74
|
+
order: 5, // position at which item should appear in bottom list
|
|
75
|
+
align: 'center', // can be start,center,end
|
|
76
|
+
hide: false, // show icon or not
|
|
77
|
+
label: 'haha',
|
|
78
|
+
},
|
|
79
|
+
'end-call': {
|
|
80
|
+
component: NewEndCall,
|
|
81
|
+
},
|
|
82
|
+
}}
|
|
83
|
+
snapPointsMinMax={[100, 300]}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import React, {useState} from 'react';
|
|
2
|
+
import {
|
|
3
|
+
UidType,
|
|
4
|
+
UserActionMenuItem,
|
|
5
|
+
UserActionMenuItemsConfig,
|
|
6
|
+
} from 'customization-api';
|
|
7
|
+
|
|
8
|
+
const BanUserAction = ({
|
|
9
|
+
closeActionMenu,
|
|
10
|
+
targetUid,
|
|
11
|
+
}: {
|
|
12
|
+
closeActionMenu?: () => void;
|
|
13
|
+
targetUid: UidType;
|
|
14
|
+
}) => (
|
|
15
|
+
<UserActionMenuItem
|
|
16
|
+
icon="remove-meeting"
|
|
17
|
+
iconColor="orange"
|
|
18
|
+
textColor="orange"
|
|
19
|
+
label="Ban from room this person"
|
|
20
|
+
onPress={() => {
|
|
21
|
+
console.log('Ban logic triggered for', targetUid);
|
|
22
|
+
closeActionMenu?.();
|
|
23
|
+
}}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const PinForEveryone = ({
|
|
28
|
+
closeActionMenu,
|
|
29
|
+
targetUid,
|
|
30
|
+
}: {
|
|
31
|
+
closeActionMenu?: () => void;
|
|
32
|
+
targetUid: UidType;
|
|
33
|
+
}) => {
|
|
34
|
+
const [isPinned, setIsPinned] = useState(false);
|
|
35
|
+
return (
|
|
36
|
+
<UserActionMenuItem
|
|
37
|
+
label={isPinned ? 'Unpin for everyone' : 'Pin for everyone'}
|
|
38
|
+
icon={isPinned ? 'unpin-outlined' : 'pin-outlined'}
|
|
39
|
+
iconColor="orange"
|
|
40
|
+
textColor="orange"
|
|
41
|
+
onPress={() => {
|
|
42
|
+
setIsPinned(!isPinned);
|
|
43
|
+
console.log('Pin toggled:', !isPinned, targetUid);
|
|
44
|
+
closeActionMenu?.();
|
|
45
|
+
}}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const PinForEveryoneT = () => {
|
|
51
|
+
const [isPinned, setIsPinned] = useState(false);
|
|
52
|
+
return (
|
|
53
|
+
<UserActionMenuItem
|
|
54
|
+
label={isPinned ? 'Unpin T' : 'Pin T'}
|
|
55
|
+
icon={isPinned ? 'unpin-outlined' : 'pin-outlined'}
|
|
56
|
+
toggleStatus={isPinned}
|
|
57
|
+
iconColor="orange"
|
|
58
|
+
textColor="orange"
|
|
59
|
+
onPress={() => {
|
|
60
|
+
setIsPinned(!isPinned);
|
|
61
|
+
console.log('Pin T toggled:', !isPinned);
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const NewUserActionsMenu = () => null;
|
|
68
|
+
|
|
69
|
+
(NewUserActionsMenu as any).items = {
|
|
70
|
+
'remove-from-room': {
|
|
71
|
+
order: 0,
|
|
72
|
+
hide: false,
|
|
73
|
+
onAction: uid => {
|
|
74
|
+
console.log('Remove from room for uid:', uid);
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
'pin-to-top': {
|
|
78
|
+
order: 1,
|
|
79
|
+
hide: false,
|
|
80
|
+
onAction: () => {
|
|
81
|
+
console.log('Pin to top logic');
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
'change-name': {
|
|
85
|
+
order: 3,
|
|
86
|
+
hide: false,
|
|
87
|
+
onAction: () => {
|
|
88
|
+
console.log('Change name logic');
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
'view-in-large': {
|
|
92
|
+
order: 2,
|
|
93
|
+
hide: false,
|
|
94
|
+
onAction: () => {
|
|
95
|
+
console.log('View in large logic');
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
'mute-audio': {
|
|
99
|
+
order: 0,
|
|
100
|
+
hide: false,
|
|
101
|
+
onAction: () => {
|
|
102
|
+
console.log('Mute audio logic');
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
'mute-video': {
|
|
106
|
+
order: 5,
|
|
107
|
+
hide: false,
|
|
108
|
+
onAction: () => {
|
|
109
|
+
console.log('Mute video logic');
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
'message-privately': {
|
|
113
|
+
order: 1,
|
|
114
|
+
hide: false,
|
|
115
|
+
onAction: () => {
|
|
116
|
+
console.log('Message privately logic');
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
'ban-user': {
|
|
120
|
+
component: BanUserAction,
|
|
121
|
+
order: 99,
|
|
122
|
+
visibility: ['host-remote', 'event-host-remote'],
|
|
123
|
+
},
|
|
124
|
+
'pin-for-everyone': {
|
|
125
|
+
component: PinForEveryone,
|
|
126
|
+
order: 0,
|
|
127
|
+
visibility: ['host-remote', 'host-self'],
|
|
128
|
+
},
|
|
129
|
+
'pin-for-everyone-T': {
|
|
130
|
+
component: PinForEveryoneT,
|
|
131
|
+
hide: true,
|
|
132
|
+
order: 0,
|
|
133
|
+
visibility: ['host-remote', 'host-self'],
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export default NewUserActionsMenu;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useRoomInfo,
|
|
3
|
+
useUserActionMenu,
|
|
4
|
+
UidType,
|
|
5
|
+
UserActionMenuItem,
|
|
6
|
+
useUserBan,
|
|
7
|
+
useLocalUid,
|
|
8
|
+
customEvents,
|
|
9
|
+
PersistanceLevel,
|
|
10
|
+
useContent,
|
|
11
|
+
} from 'customization-api';
|
|
12
|
+
import React, {useContext, useEffect, useRef, useState} from 'react';
|
|
13
|
+
import {CustomWrapperContext} from './CustomWrapper';
|
|
14
|
+
|
|
15
|
+
export interface PinContextInterface {}
|
|
16
|
+
|
|
17
|
+
const PinContext = React.createContext<PinContextInterface>({});
|
|
18
|
+
|
|
19
|
+
interface PinProviderProps {
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const PinForEveryone = ({
|
|
24
|
+
closeActionMenu,
|
|
25
|
+
targetUid,
|
|
26
|
+
targetUidType,
|
|
27
|
+
}: {
|
|
28
|
+
closeActionMenu?: () => void;
|
|
29
|
+
targetUid: UidType;
|
|
30
|
+
targetUidType: string;
|
|
31
|
+
}) => {
|
|
32
|
+
const {pinnedForAllUid, setPinnedForAllUid} =
|
|
33
|
+
useContext(CustomWrapperContext);
|
|
34
|
+
const {pinForEveryone, unPinForEveryone} = useUserActionMenu();
|
|
35
|
+
const {activeUids, pinnedUid} = useContent();
|
|
36
|
+
|
|
37
|
+
const isPinned = pinnedForAllUid === targetUid;
|
|
38
|
+
return (
|
|
39
|
+
<UserActionMenuItem
|
|
40
|
+
label={isPinned ? 'Unpin for everyone' : 'Pin for everyone'}
|
|
41
|
+
icon={isPinned ? 'unpin-outlined' : 'pin-outlined'}
|
|
42
|
+
iconColor={'yellow'}
|
|
43
|
+
textColor={'yellow'}
|
|
44
|
+
disabled={activeUids.length === 1}
|
|
45
|
+
onPress={() => {
|
|
46
|
+
const newPinnedUid = pinnedForAllUid === targetUid ? null : targetUid;
|
|
47
|
+
|
|
48
|
+
customEvents.send(
|
|
49
|
+
'PIN_FOR_EVERYONE',
|
|
50
|
+
JSON.stringify({pinForAllUid: newPinnedUid, uidType: targetUidType}),
|
|
51
|
+
PersistanceLevel.Session,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Update local state
|
|
55
|
+
setPinnedForAllUid(newPinnedUid);
|
|
56
|
+
|
|
57
|
+
// pinned for local user
|
|
58
|
+
if (newPinnedUid) {
|
|
59
|
+
pinForEveryone(newPinnedUid);
|
|
60
|
+
} else {
|
|
61
|
+
unPinForEveryone();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
closeActionMenu?.();
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const PinForEveryoneT = () => {
|
|
71
|
+
const [isPinned, setIsPinned] = useState(false);
|
|
72
|
+
const {activeUids} = useContent();
|
|
73
|
+
return (
|
|
74
|
+
<UserActionMenuItem
|
|
75
|
+
label={isPinned ? 'Unpin T' : 'Pin T'}
|
|
76
|
+
icon={isPinned ? 'unpin-outlined' : 'pin-outlined'}
|
|
77
|
+
toggleStatus={isPinned}
|
|
78
|
+
iconColor="orange"
|
|
79
|
+
textColor="orange"
|
|
80
|
+
disabled={activeUids.length === 1}
|
|
81
|
+
onPress={() => {
|
|
82
|
+
setIsPinned(!isPinned);
|
|
83
|
+
console.log('Pin T toggled:', !isPinned);
|
|
84
|
+
}}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const PinProvider = (props: PinProviderProps) => {
|
|
90
|
+
const {
|
|
91
|
+
data: {isHost},
|
|
92
|
+
} = useRoomInfo();
|
|
93
|
+
const localUid = useLocalUid();
|
|
94
|
+
const {updateUserActionMenuItems} = useUserActionMenu();
|
|
95
|
+
const banUser = useUserBan();
|
|
96
|
+
const {activeUids} = useContent();
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
const updateActions = async () => {
|
|
100
|
+
// updated user action menu items
|
|
101
|
+
updateUserActionMenuItems({
|
|
102
|
+
'remove-from-room': {
|
|
103
|
+
order: 1,
|
|
104
|
+
hide: false,
|
|
105
|
+
onAction: (uid, hostMeetingId) => {
|
|
106
|
+
console.log('Remove from room for uid:', uid);
|
|
107
|
+
banUser({uid: uid, duration: 1440, hostMeetingId});
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
'view-in-large': {
|
|
111
|
+
order: 2,
|
|
112
|
+
hide: true,
|
|
113
|
+
onAction: () => {
|
|
114
|
+
console.log('View in large logic');
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
'pin-for-everyone': {
|
|
118
|
+
component: PinForEveryone,
|
|
119
|
+
order: 0,
|
|
120
|
+
disabled: activeUids.length === 1,
|
|
121
|
+
visibility: [
|
|
122
|
+
'host-remote',
|
|
123
|
+
'host-self',
|
|
124
|
+
'event-host-remote',
|
|
125
|
+
'event-host-self',
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
'pin-for-everyone-T': {
|
|
129
|
+
component: PinForEveryoneT,
|
|
130
|
+
hide: false,
|
|
131
|
+
order: 0,
|
|
132
|
+
visibility: ['host-remote', 'host-self'],
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
updateActions();
|
|
137
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
138
|
+
}, [activeUids]);
|
|
139
|
+
return <PinContext.Provider value={{}}>{props.children}</PinContext.Provider>;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export {PinProvider, PinContext};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useVirtualBackground,
|
|
3
|
+
type VBOption,
|
|
4
|
+
useUserActionMenu,
|
|
5
|
+
UidType,
|
|
6
|
+
UserActionMenuItem,
|
|
7
|
+
useUserBan,
|
|
8
|
+
} from 'customization-api';
|
|
9
|
+
import React, {useEffect, useState} from 'react';
|
|
10
|
+
|
|
11
|
+
const PreferenceWrapperContext = React.createContext({});
|
|
12
|
+
|
|
13
|
+
interface PreferenceWrapperProviderProps {
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
const BanUserAction = ({
|
|
17
|
+
closeActionMenu,
|
|
18
|
+
targetUid,
|
|
19
|
+
hostMeetingId,
|
|
20
|
+
}: {
|
|
21
|
+
closeActionMenu: () => void;
|
|
22
|
+
targetUid: UidType;
|
|
23
|
+
hostMeetingId: string;
|
|
24
|
+
}) => {
|
|
25
|
+
const banUser = useUserBan();
|
|
26
|
+
return (
|
|
27
|
+
<UserActionMenuItem
|
|
28
|
+
icon="remove-meeting"
|
|
29
|
+
iconColor="yellow"
|
|
30
|
+
textColor="yellow"
|
|
31
|
+
label="Ban from room this person now"
|
|
32
|
+
onPress={() => {
|
|
33
|
+
console.log('Ban logic triggered for', targetUid);
|
|
34
|
+
banUser({uid: targetUid, duration: 1440, hostMeetingId});
|
|
35
|
+
closeActionMenu?.();
|
|
36
|
+
}}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const PreferenceWrapperProvider = (props: PreferenceWrapperProviderProps) => {
|
|
42
|
+
const {virtualBackgrounds, addVirtualBackgrounds} = useVirtualBackground();
|
|
43
|
+
const {updateUserActionMenuItems} = useUserActionMenu();
|
|
44
|
+
const banUser = useUserBan();
|
|
45
|
+
|
|
46
|
+
const [isPinned, setIsPinned] = useState(false); // pin for rvyrone
|
|
47
|
+
|
|
48
|
+
const PinForEveryone = ({
|
|
49
|
+
closeActionMenu,
|
|
50
|
+
targetUid,
|
|
51
|
+
}: {
|
|
52
|
+
closeActionMenu?: () => void;
|
|
53
|
+
targetUid: UidType;
|
|
54
|
+
}) => {
|
|
55
|
+
return (
|
|
56
|
+
<UserActionMenuItem
|
|
57
|
+
label={isPinned ? 'Unpin for everyone' : 'Pin for everyone'}
|
|
58
|
+
icon={isPinned ? 'unpin-outlined' : 'pin-outlined'}
|
|
59
|
+
iconColor="yellow"
|
|
60
|
+
textColor="yellow"
|
|
61
|
+
onPress={() => {
|
|
62
|
+
setIsPinned(!isPinned);
|
|
63
|
+
console.log('Pin toggled:', !isPinned, targetUid);
|
|
64
|
+
// closeActionMenu?.();
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const PinForEveryoneT = () => {
|
|
71
|
+
const [isPinned, setIsPinned] = useState(false);
|
|
72
|
+
return (
|
|
73
|
+
<UserActionMenuItem
|
|
74
|
+
label={isPinned ? 'Unpin T' : 'Pin T'}
|
|
75
|
+
icon={isPinned ? 'unpin-outlined' : 'pin-outlined'}
|
|
76
|
+
toggleStatus={isPinned}
|
|
77
|
+
iconColor="orange"
|
|
78
|
+
textColor="orange"
|
|
79
|
+
onPress={() => {
|
|
80
|
+
setIsPinned(!isPinned);
|
|
81
|
+
console.log('Pin T toggled:', !isPinned);
|
|
82
|
+
}}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
React.useEffect(() => {
|
|
88
|
+
const update = async () => {
|
|
89
|
+
const initialOptions = virtualBackgrounds.slice(0, 3);
|
|
90
|
+
const options = [
|
|
91
|
+
...initialOptions,
|
|
92
|
+
|
|
93
|
+
{
|
|
94
|
+
type: 'image',
|
|
95
|
+
path: 'https://images.unsplash.com/photo-1581360742512-021d5b2157d8?q=80&w=2079&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
96
|
+
isSelected: true,
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
{
|
|
100
|
+
type: 'image',
|
|
101
|
+
path: 'https://images.unsplash.com/photo-1533090161767-e6ffed986c88?q=80&w=2069&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
102
|
+
isSelected: false,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
type: 'image',
|
|
106
|
+
path: 'https://images.unsplash.com/photo-1549890762-0a3f8933bc76?q=80&w=1936&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
107
|
+
isSelected: false,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'image',
|
|
111
|
+
path: 'https://images.unsplash.com/photo-1517093728432-a0440f8d45af?q=80&w=2028&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
112
|
+
isSelected: false,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: 'image',
|
|
116
|
+
path: 'https://images.unsplash.com/photo-1590523741831-ab7e8b8f9c7f?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
117
|
+
isSelected: false,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
type: 'image',
|
|
121
|
+
path: 'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
122
|
+
isSelected: false,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
type: 'image',
|
|
126
|
+
path: 'https://images.unsplash.com/photo-1419242902214-272b3f66ee7a?q=80&w=2113&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
127
|
+
isSelected: false,
|
|
128
|
+
},
|
|
129
|
+
] as VBOption[];
|
|
130
|
+
await addVirtualBackgrounds(options);
|
|
131
|
+
|
|
132
|
+
// // updated user action menu items
|
|
133
|
+
// updateUserActionMenuItems({
|
|
134
|
+
// 'remove-from-room': {
|
|
135
|
+
// order: 0,
|
|
136
|
+
// hide: false,
|
|
137
|
+
// onAction: (uid, hostMeetingId) => {
|
|
138
|
+
// console.log('Remove from room for uid:', uid);
|
|
139
|
+
// banUser({uid: uid, duration: 1440, hostMeetingId});
|
|
140
|
+
// },
|
|
141
|
+
// },
|
|
142
|
+
// 'pin-to-top': {
|
|
143
|
+
// order: 1,
|
|
144
|
+
// hide: false,
|
|
145
|
+
// onAction: () => {
|
|
146
|
+
// console.log('Pin to top logic');
|
|
147
|
+
// },
|
|
148
|
+
// },
|
|
149
|
+
// 'change-name': {
|
|
150
|
+
// order: 3,
|
|
151
|
+
// hide: false,
|
|
152
|
+
// onAction: () => {
|
|
153
|
+
// console.log('Change name logic');
|
|
154
|
+
// },
|
|
155
|
+
// },
|
|
156
|
+
// 'view-in-large': {
|
|
157
|
+
// order: 2,
|
|
158
|
+
// hide: false,
|
|
159
|
+
// onAction: () => {
|
|
160
|
+
// console.log('View in large logic');
|
|
161
|
+
// },
|
|
162
|
+
// },
|
|
163
|
+
// 'mute-audio': {
|
|
164
|
+
// order: 0,
|
|
165
|
+
// hide: false,
|
|
166
|
+
// onAction: () => {
|
|
167
|
+
// console.log('Mute audio logic');
|
|
168
|
+
// },
|
|
169
|
+
// },
|
|
170
|
+
// 'mute-video': {
|
|
171
|
+
// order: 5,
|
|
172
|
+
// hide: false,
|
|
173
|
+
// onAction: () => {
|
|
174
|
+
// console.log('Mute video logic');
|
|
175
|
+
// },
|
|
176
|
+
// },
|
|
177
|
+
// 'message-privately': {
|
|
178
|
+
// order: 1,
|
|
179
|
+
// hide: false,
|
|
180
|
+
// onAction: () => {
|
|
181
|
+
// console.log('Message privately logic');
|
|
182
|
+
// },
|
|
183
|
+
// },
|
|
184
|
+
// 'ban-user': {
|
|
185
|
+
// component: BanUserAction,
|
|
186
|
+
// order: 99,
|
|
187
|
+
// visibility: ['host-remote', 'event-host-remote'],
|
|
188
|
+
// },
|
|
189
|
+
// 'pin-for-everyone': {
|
|
190
|
+
// component: PinForEveryone,
|
|
191
|
+
// order: 0,
|
|
192
|
+
// visibility: ['host-remote', 'host-self'],
|
|
193
|
+
// },
|
|
194
|
+
// 'pin-for-everyone-T': {
|
|
195
|
+
// component: PinForEveryoneT,
|
|
196
|
+
// hide: false,
|
|
197
|
+
// order: 0,
|
|
198
|
+
// visibility: ['host-remote', 'host-self'],
|
|
199
|
+
// },
|
|
200
|
+
// });
|
|
201
|
+
};
|
|
202
|
+
update();
|
|
203
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
204
|
+
}, []);
|
|
205
|
+
return (
|
|
206
|
+
<PreferenceWrapperContext.Provider value={{}}>
|
|
207
|
+
{props.children}
|
|
208
|
+
</PreferenceWrapperContext.Provider>
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
export {PreferenceWrapperProvider, PreferenceWrapperContext};
|