agora-appbuilder-core 4.1.4-beta.7 → 4.1.4

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": "4.1.4-beta.7",
3
+ "version": "4.1.4",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -94,6 +94,10 @@ export interface VideoCallInterface extends BeforeAndAfterInterface {
94
94
  title: string;
95
95
  renderComponent?: React.ComponentType;
96
96
  };
97
+ hostControls?: {
98
+ audioControl?: React.ComponentType;
99
+ videoControl?: React.ComponentType;
100
+ };
97
101
  }
98
102
 
99
103
  export type ComponentsInterface = {
@@ -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.4-beta.7',
81
- CORE_VERSION: '4.1.4-beta.7',
80
+ CLI_VERSION: '3.1.4',
81
+ CORE_VERSION: '4.1.4',
82
82
  DISABLE_LANDSCAPE_MODE: false,
83
83
  STT_AUTO_START: false,
84
84
  CLOUD_RECORDING_AUTO_START: false,
@@ -49,6 +49,7 @@ export interface ActionMenuItem {
49
49
  disabled?: boolean;
50
50
  iconSize?: number;
51
51
  hide?: ToolbarItemHide;
52
+ type?: string;
52
53
  }
53
54
  export interface ActionMenuProps {
54
55
  from: string;
@@ -200,6 +201,7 @@ const ActionMenu = (props: ActionMenuProps) => {
200
201
  onHoverContent = undefined,
201
202
  iconSize = 20,
202
203
  titleStyle = {},
204
+ type = '',
203
205
  } = item;
204
206
  return (
205
207
  <PlatformWrapper key={props.from + '_' + title + index}>
@@ -232,6 +234,7 @@ const ActionMenu = (props: ActionMenuProps) => {
232
234
  closeActionMenu={closeActionMenu}
233
235
  targetUid={uid}
234
236
  hostMeetingId={roomId?.host}
237
+ targetUidType={type}
235
238
  />
236
239
  </TouchableOpacity>
237
240
  ) : (
@@ -57,6 +57,7 @@ export type AttendeeRemoteActionKeys = 'view-in-large' | 'message-privately';
57
57
  export interface UserActionMenuDefaultItem {
58
58
  hide?: boolean;
59
59
  order?: number;
60
+ disabled?: boolean;
60
61
  onPress?: () => void; // replace existing logic
61
62
  onAction?: (uid?: UidType, hostMeetingId?: string) => void; // add additional logic
62
63
  visibility?: ActionVisibility[]; // to whom custom action item should be visible , build in actions menu is already handled
@@ -64,6 +65,7 @@ export interface UserActionMenuDefaultItem {
64
65
  closeActionMenu: () => void;
65
66
  targetUid: UidType;
66
67
  hostMeetingId?: string;
68
+ targetUidType: string;
67
69
  }>; // to override default component or add new
68
70
  }
69
71
  export type UserActionDefaultItemsConfig = {
@@ -16,12 +16,13 @@ import useRemoteMute, {MUTE_REMOTE_TYPE} from '../utils/useRemoteMute';
16
16
  import TertiaryButton from '../atoms/TertiaryButton';
17
17
  import Spacer from '../atoms/Spacer';
18
18
  import RemoteMutePopup from '../subComponents/RemoteMutePopup';
19
- import {calculatePosition} from '../utils/common';
19
+ import {calculatePosition, isValidReactComponent} from '../utils/common';
20
20
  import {
21
21
  I18nMuteType,
22
22
  peoplePanelMuteAllMicBtnText,
23
23
  peoplePanelTurnoffAllCameraBtnText,
24
24
  } from '../language/default-labels/videoCallScreenLabels';
25
+ import {useCustomization} from 'customization-implementation';
25
26
 
26
27
  export interface MuteAllAudioButtonProps {
27
28
  render?: (onPress: () => void) => JSX.Element;
@@ -145,17 +146,52 @@ export const MuteAllVideoButton = (props: MuteAllVideoButtonProps) => {
145
146
  };
146
147
 
147
148
  const HostControlView = () => {
149
+ const {AudioControlComponent, VideoControlComponent} = useCustomization(
150
+ data => {
151
+ let components: {
152
+ AudioControlComponent: React.ComponentType;
153
+ VideoControlComponent: React.ComponentType;
154
+ } = {
155
+ AudioControlComponent:
156
+ MuteAllAudioButton as React.ComponentType<MuteAllAudioButtonProps>,
157
+ VideoControlComponent:
158
+ MuteAllVideoButton as React.ComponentType<MuteAllVideoButtonProps>,
159
+ };
160
+
161
+ if (
162
+ data?.components?.videoCall?.hostControls?.audioControl &&
163
+ isValidReactComponent(
164
+ data?.components?.videoCall?.hostControls?.audioControl,
165
+ )
166
+ ) {
167
+ components.AudioControlComponent =
168
+ data?.components?.videoCall?.hostControls?.audioControl;
169
+ }
170
+
171
+ if (
172
+ data?.components?.videoCall?.hostControls?.videoControl &&
173
+ isValidReactComponent(
174
+ data?.components?.videoCall?.hostControls?.videoControl,
175
+ )
176
+ ) {
177
+ components.VideoControlComponent =
178
+ data?.components?.videoCall?.hostControls?.videoControl;
179
+ }
180
+
181
+ return components;
182
+ },
183
+ );
148
184
  return (
149
185
  // <View style={style.container}>
150
186
  <>
151
187
  {!$config.AUDIO_ROOM && (
152
188
  <View style={{display: 'flex', flex: 1}}>
153
- <MuteAllVideoButton />
189
+ <VideoControlComponent />
154
190
  </View>
155
191
  )}
156
192
  <Spacer horizontal size={16} />
157
193
  <View style={{display: 'flex', flex: 1}}>
158
- <MuteAllAudioButton />
194
+ <AudioControlComponent />
159
195
  </View>
160
196
  </>
161
197
  // </View>
@@ -206,8 +206,8 @@ export default function UserActionMenuOptionsOptions(
206
206
  if (!viewInLargeConfig.hide && !isPinned) {
207
207
  items.push({
208
208
  key: viewInLargeKey,
209
- disabled: isOnlyOneActive,
210
- order: viewInLargeConfig.order ?? 4,
209
+ disabled: viewInLargeConfig.disabled ?? isOnlyOneActive,
210
+ order: viewInLargeConfig.order ?? 0,
211
211
  icon: isPinned ? 'unpin-outlined' : 'pin-outlined',
212
212
  onHoverIcon: isPinned ? 'unpin-filled' : 'pin-filled',
213
213
  iconColor: $config.SECONDARY_ACTION_COLOR,
@@ -268,8 +268,8 @@ export default function UserActionMenuOptionsOptions(
268
268
  if (!pinToTopConfig.hide) {
269
269
  items.push({
270
270
  key: pinToTopKey,
271
- disabled: isOnlyOneActive,
272
- order: pinToTopConfig.order ?? 0,
271
+ disabled: pinToTopConfig.disabled ?? isOnlyOneActive,
272
+ order: pinToTopConfig.order ?? 1,
273
273
  icon: isPinnedToTop ? 'unpin-outlined' : 'pin-outlined',
274
274
  onHoverIcon: isPinnedToTop ? 'unpin-filled' : 'pin-filled',
275
275
  iconColor: $config.SECONDARY_ACTION_COLOR,
@@ -359,6 +359,7 @@ export default function UserActionMenuOptionsOptions(
359
359
  if (!messageConfig.hide && $config.CHAT) {
360
360
  items.push({
361
361
  key: messageKey,
362
+ disabled: messageConfig.disable ?? false,
362
363
  order: messageConfig.order ?? 2,
363
364
  icon: 'chat-outlined',
364
365
  onHoverIcon: 'chat-filled',
@@ -430,6 +431,7 @@ export default function UserActionMenuOptionsOptions(
430
431
  if (!muteAudioConfig.hide) {
431
432
  items.push({
432
433
  key: muteAudioKey,
434
+ disabled: muteAudioConfig.disabled ?? false,
433
435
  order: muteAudioConfig.order ?? 3,
434
436
  icon: isMuted ? 'mic-off-outlined' : 'mic-on-outlined',
435
437
  onHoverIcon: isMuted ? 'mic-off-filled' : 'mic-on-filled',
@@ -456,6 +458,7 @@ export default function UserActionMenuOptionsOptions(
456
458
  if (!$config.AUDIO_ROOM && !muteVideoConfig.hide) {
457
459
  items.push({
458
460
  key: muteVideoKey,
461
+ disabled: muteVideoConfig.disabled ?? false,
459
462
  order: muteVideoConfig.order ?? 4,
460
463
  icon: isVideoMuted ? 'video-off-outlined' : 'video-on-outlined',
461
464
  onHoverIcon: isVideoMuted
@@ -544,7 +547,8 @@ export default function UserActionMenuOptionsOptions(
544
547
  if (!removeConfig.hide) {
545
548
  items.push({
546
549
  key: removeKey,
547
- order: removeConfig.order ?? 10,
550
+ disabled: removeConfig.disabled ?? false,
551
+ order: removeConfig.order ?? 5,
548
552
  icon: 'remove-meeting',
549
553
  iconColor: $config.SEMANTIC_ERROR,
550
554
  textColor: $config.SEMANTIC_ERROR,
@@ -586,7 +590,8 @@ export default function UserActionMenuOptionsOptions(
586
590
  ) {
587
591
  items.push({
588
592
  key: changeNameKey,
589
- order: changeNameConfig.order ?? 5,
593
+ disabled: changeNameConfig.disabled ?? false,
594
+ order: changeNameConfig.order ?? 6,
590
595
  icon: 'pencil-outlined',
591
596
  onHoverIcon: 'pencil-filled',
592
597
  iconColor: $config.SECONDARY_ACTION_COLOR,
@@ -635,7 +640,8 @@ export default function UserActionMenuOptionsOptions(
635
640
  ) {
636
641
  items.push({
637
642
  key: removeScreenshareKey,
638
- order: removeScreenshareConfig.order ?? 10,
643
+ disabled: removeScreenshareConfig.disabled ?? false,
644
+ order: removeScreenshareConfig.order ?? 7,
639
645
  icon: 'remove-meeting',
640
646
  iconColor: $config.SEMANTIC_ERROR,
641
647
  textColor: $config.SEMANTIC_ERROR,
@@ -679,12 +685,14 @@ export default function UserActionMenuOptionsOptions(
679
685
  }
680
686
  return {
681
687
  key,
682
- order: config.order ?? 99,
688
+ order: config.order ?? 8,
683
689
  component: config.component,
684
690
  closeActionMenu: () => {
685
691
  setActionMenuVisible(false);
686
692
  },
687
693
  uid: user.uid,
694
+ disabled: config.disabled ?? false,
695
+ type: user.type,
688
696
  };
689
697
  });
690
698
 
@@ -1,16 +1,29 @@
1
1
  import React, {createContext, useContext, useState, useEffect} from 'react';
2
- import {UserActionMenuItemsConfig} from 'customization-api';
2
+ import {
3
+ UidType,
4
+ UserActionMenuItemsConfig,
5
+ DispatchContext,
6
+ useLayout,
7
+ } from 'customization-api';
8
+ import {
9
+ getGridLayoutName,
10
+ getPinnedLayoutName,
11
+ } from '../pages/video-call/DefaultLayouts';
3
12
 
4
13
  interface UserActionMenuContextType {
5
14
  userActionMenuItems: UserActionMenuItemsConfig;
6
15
  updateUserActionMenuItems: React.Dispatch<
7
16
  React.SetStateAction<UserActionMenuItemsConfig>
8
17
  >;
18
+ pinForEveryone: (uid: UidType) => void;
19
+ unPinForEveryone: () => void;
9
20
  }
10
21
 
11
22
  const UserActionMenuContext = createContext<UserActionMenuContextType>({
12
23
  userActionMenuItems: {},
13
24
  updateUserActionMenuItems: () => {},
25
+ pinForEveryone: () => {},
26
+ unPinForEveryone: () => {},
14
27
  });
15
28
 
16
29
  export const UserActionMenuProvider: React.FC<{children: React.ReactNode}> = ({
@@ -18,10 +31,33 @@ export const UserActionMenuProvider: React.FC<{children: React.ReactNode}> = ({
18
31
  }) => {
19
32
  const [userActionMenuItems, updateUserActionMenuItems] =
20
33
  useState<UserActionMenuItemsConfig>({});
34
+ const {dispatch} = useContext(DispatchContext);
35
+ const {setLayout} = useLayout();
36
+
37
+ const pinForEveryone = (uid: UidType) => {
38
+ dispatch({
39
+ type: 'UserPin',
40
+ value: [uid],
41
+ });
42
+ setLayout(getPinnedLayoutName());
43
+ };
44
+
45
+ const unPinForEveryone = () => {
46
+ dispatch({
47
+ type: 'UserPin',
48
+ value: [0],
49
+ });
50
+ setLayout(getGridLayoutName());
51
+ };
21
52
 
22
53
  return (
23
54
  <UserActionMenuContext.Provider
24
- value={{userActionMenuItems, updateUserActionMenuItems}}>
55
+ value={{
56
+ userActionMenuItems,
57
+ updateUserActionMenuItems,
58
+ pinForEveryone,
59
+ unPinForEveryone,
60
+ }}>
25
61
  {children}
26
62
  </UserActionMenuContext.Provider>
27
63
  );
@@ -80,6 +80,11 @@ const ChatParticipants = (props: any) => {
80
80
  } else {
81
81
  const userId = i;
82
82
  const userInfo = defaultContent[userId];
83
+
84
+ // if user is not in active uids, then skip it
85
+ if (!activeUids.includes(userId)) {
86
+ return false;
87
+ }
83
88
  //video meeting with waiting room
84
89
  if (
85
90
  $config.ENABLE_WAITING_ROOM &&