agora-appbuilder-core 4.1.9 → 4.1.10-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.
Files changed (107) hide show
  1. package/package.json +2 -2
  2. package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +1 -3
  3. package/template/agora-rn-uikit/src/Contexts/RtcContext.tsx +1 -2
  4. package/template/agora-rn-uikit/src/Reducer/index.ts +0 -2
  5. package/template/agora-rn-uikit/src/Rtc/Join.tsx +11 -25
  6. package/template/agora-rn-uikit/src/RtcConfigure.tsx +1 -14
  7. package/template/bridge/rtc/webNg/RtcEngine.ts +2 -2
  8. package/template/bridge/rtm/web/index.ts +30 -0
  9. package/template/customization-api/typeDefinition.ts +1 -0
  10. package/template/defaultConfig.js +3 -2
  11. package/template/global.d.ts +1 -0
  12. package/template/src/AppRoutes.tsx +3 -3
  13. package/template/src/ai-agent/components/ControlButtons.tsx +1 -1
  14. package/template/src/assets/font-styles.css +36 -0
  15. package/template/src/assets/fonts/icomoon.ttf +0 -0
  16. package/template/src/assets/selection.json +1 -1
  17. package/template/src/atoms/CustomIcon.tsx +8 -0
  18. package/template/src/atoms/Dropdown.tsx +5 -0
  19. package/template/src/atoms/TertiaryButton.tsx +1 -1
  20. package/template/src/atoms/UserAvatar.tsx +1 -1
  21. package/template/src/components/ChatContext.ts +5 -3
  22. package/template/src/components/Controls.tsx +68 -22
  23. package/template/src/components/DeviceConfigure.tsx +1 -1
  24. package/template/src/components/EventsConfigure.tsx +22 -17
  25. package/template/src/components/Navbar.tsx +14 -11
  26. package/template/src/components/RTMConfigure.tsx +31 -1036
  27. package/template/src/components/UserGlobalPreferenceProvider.tsx +227 -0
  28. package/template/src/components/beauty-effect/useBeautyEffects.tsx +50 -13
  29. package/template/src/components/breakout-room/BreakoutRoomPanel.tsx +58 -0
  30. package/template/src/components/breakout-room/context/BreakoutRoomContext.tsx +2508 -0
  31. package/template/src/components/breakout-room/events/BreakoutRoomEventsConfigure.tsx +272 -0
  32. package/template/src/components/breakout-room/events/constants.ts +17 -0
  33. package/template/src/components/breakout-room/hoc/BreakoutRoomNameRenderer.tsx +68 -0
  34. package/template/src/components/breakout-room/hooks/useBreakoutRoomExit.ts +49 -0
  35. package/template/src/components/breakout-room/state/reducer.ts +522 -0
  36. package/template/src/components/breakout-room/state/types.ts +54 -0
  37. package/template/src/components/breakout-room/ui/BreakoutMeetingTitle.tsx +60 -0
  38. package/template/src/components/breakout-room/ui/BreakoutRoomActionMenu.tsx +136 -0
  39. package/template/src/components/breakout-room/ui/BreakoutRoomAnnouncementModal.tsx +135 -0
  40. package/template/src/components/breakout-room/ui/BreakoutRoomGroupSettings.tsx +588 -0
  41. package/template/src/components/breakout-room/ui/BreakoutRoomMainRoomUsers.tsx +142 -0
  42. package/template/src/components/breakout-room/ui/BreakoutRoomMemberActionMenu.tsx +122 -0
  43. package/template/src/components/breakout-room/ui/BreakoutRoomParticipants.tsx +124 -0
  44. package/template/src/components/breakout-room/ui/BreakoutRoomRaiseHand.tsx +65 -0
  45. package/template/src/components/breakout-room/ui/BreakoutRoomRenameModal.tsx +227 -0
  46. package/template/src/components/breakout-room/ui/BreakoutRoomSettings.tsx +140 -0
  47. package/template/src/components/breakout-room/ui/BreakoutRoomTransition.tsx +52 -0
  48. package/template/src/components/breakout-room/ui/BreakoutRoomView.tsx +193 -0
  49. package/template/src/components/breakout-room/ui/ExitBreakoutRoomIconButton.tsx +79 -0
  50. package/template/src/components/breakout-room/ui/ParticipantManualAssignmentModal.tsx +638 -0
  51. package/template/src/components/breakout-room/ui/SelectParticipantAssignmentStrategy.tsx +57 -0
  52. package/template/src/components/chat/chatConfigure.tsx +7 -1
  53. package/template/src/components/chat-messages/useChatMessages.tsx +43 -11
  54. package/template/src/components/common/Dividers.tsx +53 -0
  55. package/template/src/components/controls/toolbar-items/ExitBreakoutRoomToolbarItem.tsx +13 -0
  56. package/template/src/components/controls/useControlPermissionMatrix.tsx +32 -4
  57. package/template/src/components/participants/AllHostParticipants.tsx +10 -2
  58. package/template/src/components/participants/Participant.tsx +7 -1
  59. package/template/src/components/participants/UserActionMenuOptions.tsx +12 -2
  60. package/template/src/components/precall/joinWaitingRoomBtn.native.tsx +12 -8
  61. package/template/src/components/precall/joinWaitingRoomBtn.tsx +14 -10
  62. package/template/src/components/raise-hand/RaiseHandButton.tsx +50 -0
  63. package/template/src/components/raise-hand/RaiseHandProvider.tsx +308 -0
  64. package/template/src/components/raise-hand/index.ts +14 -0
  65. package/template/src/components/recordings/RecordingsDateTable.tsx +3 -2
  66. package/template/src/components/room-info/useCurrentRoomInfo.tsx +42 -0
  67. package/template/src/components/room-info/useSetBreakoutRoomInfo.tsx +64 -0
  68. package/template/src/components/useUserPreference.tsx +39 -12
  69. package/template/src/components/virtual-background/useVB.tsx +18 -0
  70. package/template/src/components/whiteboard/WhiteboardConfigure.tsx +27 -0
  71. package/template/src/language/default-labels/videoCallScreenLabels.ts +7 -0
  72. package/template/src/logger/AppBuilderLogger.tsx +11 -3
  73. package/template/src/pages/VideoCall.tsx +171 -518
  74. package/template/src/pages/video-call/BreakoutVideoCall.tsx +213 -0
  75. package/template/src/pages/video-call/SidePanelHeader.tsx +17 -0
  76. package/template/src/pages/video-call/VideoCallContent.tsx +211 -0
  77. package/template/src/pages/video-call/VideoCallScreen.tsx +18 -0
  78. package/template/src/pages/video-call/VideoCallScreenWrapper.tsx +0 -1
  79. package/template/src/pages/video-call/VideoCallStateWrapper.tsx +495 -0
  80. package/template/src/rtm/RTMConfigureBreakoutRoomProvider.tsx +882 -0
  81. package/template/src/rtm/RTMConfigureMainRoomProvider.tsx +757 -0
  82. package/template/src/rtm/RTMCoreProvider.tsx +419 -0
  83. package/template/src/rtm/RTMEngine.ts +188 -60
  84. package/template/src/rtm/RTMGlobalStateProvider.tsx +706 -0
  85. package/template/src/rtm/RTMStatusBanner.tsx +99 -0
  86. package/template/src/rtm/constants.ts +12 -0
  87. package/template/src/rtm/hooks/useMainRoomUserDisplayName.ts +45 -0
  88. package/template/src/rtm/rtm-presence-utils.ts +344 -0
  89. package/template/src/rtm/utils.ts +68 -1
  90. package/template/src/rtm-events/constants.ts +40 -1
  91. package/template/src/rtm-events-api/Events.ts +62 -19
  92. package/template/src/subComponents/ChatBubble.tsx +3 -3
  93. package/template/src/subComponents/ChatContainer.tsx +19 -9
  94. package/template/src/subComponents/LocalAudioMute.tsx +2 -2
  95. package/template/src/subComponents/LocalVideoMute.tsx +2 -2
  96. package/template/src/subComponents/SidePanelEnum.tsx +1 -0
  97. package/template/src/subComponents/caption/useCaption.tsx +1 -1
  98. package/template/src/subComponents/chat/ChatAnnouncementView.tsx +65 -0
  99. package/template/src/subComponents/chat/ChatSendButton.tsx +1 -0
  100. package/template/src/subComponents/screenshare/ScreenshareButton.tsx +16 -0
  101. package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +1 -1
  102. package/template/src/subComponents/waiting-rooms/WaitingRoomControls.tsx +7 -4
  103. package/template/src/utils/useDebouncedCallback.tsx +20 -0
  104. package/template/src/utils/useEndCall.ts +0 -2
  105. package/template/src/utils/useMuteToggleLocal.ts +14 -10
  106. package/template/agora-rn-uikit/src/Reducer/Spotlight.ts +0 -11
  107. package/template/agora-rn-uikit/src/Reducer/UserBanned.ts +0 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agora-appbuilder-core",
3
- "version": "4.1.9",
3
+ "version": "4.1.10-beta.1",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -9,7 +9,7 @@
9
9
  ],
10
10
  "scripts": {
11
11
  "vercel-build": "npm run dev-setup && cd template && npm run web:build && cd .. && npm run copy-vercel",
12
- "uikit": "rm -rf template/agora-rn-uikit && git clone https://github.com/AgoraIO-Community/appbuilder-ui-kit.git template/agora-rn-uikit && cd template/agora-rn-uikit && git checkout appbuilder-uikit-3.1.8",
12
+ "uikit": "rm -rf template/agora-rn-uikit && git clone https://github.com/AgoraIO-Community/appbuilder-ui-kit.git template/agora-rn-uikit && cd template/agora-rn-uikit && git checkout appbuilder-uikit-3.1.10",
13
13
  "deps": "cd template && npm i --force",
14
14
  "dev-setup": "npm run uikit && npm run deps && node devSetup.js",
15
15
  "web-build": "cd template && npm run web:build && cd .. && npm run copy-vercel",
@@ -142,7 +142,7 @@ export interface RtcPropsInterface {
142
142
  callActive?: boolean;
143
143
  encryption?: {
144
144
  key: string;
145
- mode: EncryptionMode.Aes128Xts | EncryptionMode.Aes256Gcm2;
145
+ mode: EncryptionMode.Aes128Gcm2 | EncryptionMode.Aes256Gcm2;
146
146
  salt: number[];
147
147
  };
148
148
  // commented for v1 release
@@ -185,10 +185,8 @@ export interface CallbacksInterface {
185
185
  AddCustomContent(uid: UidType, data: any): void;
186
186
  RemoveCustomContent(uid: UidType): void;
187
187
  UserPin(Uid: UidType): void;
188
- Spotlight(Uid: UidType): void;
189
188
  UserSecondaryPin(Uid: UidType): void;
190
189
  ActiveSpeaker(Uid: UidType): void;
191
- UserBanned(isBanned: boolean): void;
192
190
  }
193
191
 
194
192
  export type CustomCallbacksInterface = CallbacksInterface;
@@ -33,8 +33,6 @@ export interface ContentStateInterface {
33
33
  pinnedUid?: UidType;
34
34
  secondaryPinnedUid?: UidType;
35
35
  lastJoinedUid?: UidType;
36
- spotlightUid?: UidType;
37
- isUserBaned?: boolean;
38
36
  }
39
37
 
40
38
  export interface ActionInterface<T extends keyof CallbacksInterface> {
@@ -47,6 +45,7 @@ export type ActionType<T extends keyof CallbacksInterface> = ActionInterface<T>;
47
45
  export interface RtcContextInterface {
48
46
  RtcEngineUnsafe: IRtcEngine;
49
47
  setDualStreamMode: React.Dispatch<React.SetStateAction<DualStreamMode>>;
48
+ rtcTracksReady: boolean;
50
49
  }
51
50
 
52
51
  const RtcContext = React.createContext<RtcContextInterface>(
@@ -11,5 +11,3 @@ export {default as RemoteVideoStateChanged} from './RemoteVideoStateChanged';
11
11
  export {default as UserPin} from './UserPin';
12
12
  export {default as UserSecondaryPin} from './UserSecondaryPin';
13
13
  export {default as ActiveSpeaker} from './ActiveSpeaker';
14
- export {default as Spotlight} from './Spotlight';
15
- export {default as UserBanned} from './UserBanned';
@@ -51,27 +51,18 @@ const Join: React.FC<{
51
51
  const videoState = defaultContent[maxUid]?.video;
52
52
  async function join() {
53
53
  if (
54
- // rtcProps?.encryption &&
55
- // rtcProps?.encryption.key &&
56
- rtcProps?.encryption?.mode
57
- // rtcProps.encryption.salt
54
+ rtcProps?.encryption &&
55
+ rtcProps?.encryption.key &&
56
+ rtcProps.encryption.mode &&
57
+ rtcProps.encryption.salt
58
58
  ) {
59
59
  try {
60
- console.log(
61
- 'ui kit setting encryption mode to ',
62
- rtcProps?.encryption?.mode,
63
- );
64
- const encryptionConfig = {
65
- encryptionKey: rtcProps?.encryption?.key,
66
- encryptionMode: rtcProps?.encryption?.mode,
60
+ await engine.enableEncryption(true, {
61
+ encryptionKey: rtcProps?.encryption.key,
62
+ encryptionMode: rtcProps?.encryption.mode,
63
+ encryptionKdfSalt: rtcProps?.encryption.salt,
67
64
  datastreamEncryptionEnabled: true,
68
- ...(rtcProps?.encryption?.mode == 1
69
- ? {}
70
- : {
71
- encryptionKdfSalt: rtcProps?.encryption?.salt,
72
- }),
73
- };
74
- await engine.enableEncryption(true, encryptionConfig);
65
+ });
75
66
  } catch (error) {
76
67
  console.warn('encryption error', error);
77
68
  }
@@ -106,13 +97,8 @@ const Join: React.FC<{
106
97
  rtcProps?.uid || 0,
107
98
  {},
108
99
  );
109
- } catch (error: any) {
110
- console.error('RTC joinChannel error ', error);
111
- if (
112
- error?.code === 'UID_BANNED' ||
113
- error?.message?.includes('UID_BANNED')
114
- )
115
- dispatch({type: 'UserBanned', value: [true]});
100
+ } catch (error) {
101
+ console.error('RTC joinChannel error', error);
116
102
  }
117
103
  if (
118
104
  !audioRoom &&
@@ -32,8 +32,6 @@ import {
32
32
  UserPin,
33
33
  UserSecondaryPin,
34
34
  ActiveSpeaker,
35
- Spotlight,
36
- UserBanned,
37
35
  } from './Reducer';
38
36
  import Create from './Rtc/Create';
39
37
  import Join from './Rtc/Join';
@@ -262,16 +260,6 @@ const RtcConfigure = (outerProps: {children: React.ReactNode}) => {
262
260
  stateUpdate = ActiveSpeaker(state, action);
263
261
  }
264
262
  break;
265
- case 'Spotlight':
266
- if (actionTypeGuard(action, action.type)) {
267
- stateUpdate = Spotlight(state, action);
268
- }
269
- break;
270
- case 'UserBanned':
271
- if (actionTypeGuard(action, action.type)) {
272
- stateUpdate = UserBanned(state, action);
273
- }
274
- break;
275
263
  }
276
264
 
277
265
  // TODO: remove Handle event listeners
@@ -437,6 +425,7 @@ const RtcConfigure = (outerProps: {children: React.ReactNode}) => {
437
425
  value={{
438
426
  RtcEngineUnsafe: engineRef.current,
439
427
  setDualStreamMode,
428
+ rtcTracksReady: tracksReady,
440
429
  }}>
441
430
  <ContentProvider
442
431
  value={{
@@ -471,8 +460,6 @@ const RtcConfigure = (outerProps: {children: React.ReactNode}) => {
471
460
  ? uidState.secondaryPinnedUid
472
461
  : undefined,
473
462
  lastJoinedUid: uidState.lastJoinedUid,
474
- spotlightUid: uidState.spotlightUid,
475
- isUserBaned: uidState.isUserBaned,
476
463
  }}>
477
464
  {outerProps.children}
478
465
  </ContentProvider>
@@ -1466,13 +1466,13 @@ export default class RtcEngine {
1466
1466
  this.client.setEncryptionConfig(
1467
1467
  mode,
1468
1468
  config.encryptionKey,
1469
- config.encryptionMode === 1? null:config.encryptionKdfSalt,
1469
+ config.encryptionMode === 1 ? null : config.encryptionKdfSalt,
1470
1470
  true, // encryptDataStream
1471
1471
  ),
1472
1472
  this.screenClient.setEncryptionConfig(
1473
1473
  mode,
1474
1474
  config.encryptionKey,
1475
- config.encryptionMode === 1? null:config.encryptionKdfSalt,
1475
+ config.encryptionMode === 1 ? null : config.encryptionKdfSalt,
1476
1476
  true, // encryptDataStream
1477
1477
  ),
1478
1478
  ]);
@@ -9,6 +9,8 @@ import {
9
9
  type GetUserMetadataResponse as NativeGetUserMetadataResponse,
10
10
  type GetChannelMetadataResponse as NativeGetChannelMetadataResponse,
11
11
  type SetOrUpdateUserMetadataOptions as NativeSetOrUpdateUserMetadataOptions,
12
+ type RemoveUserMetadataOptions as NativeRemoveUserMetadataOptions,
13
+ type RemoveUserMetadataResponse as NativeRemoveUserMetadataResponse,
12
14
  type IMetadataOptions as NativeIMetadataOptions,
13
15
  type StorageEvent as NativeStorageEvent,
14
16
  type PresenceEvent as NativePresenceEvent,
@@ -23,6 +25,7 @@ import AgoraRTM, {
23
25
  PublishOptions,
24
26
  ChannelType,
25
27
  MetaDataDetail,
28
+ RemoveUserMetadataOptions,
26
29
  } from 'agora-rtm-sdk';
27
30
  import {
28
31
  linkStatusReasonCodeMapping,
@@ -221,6 +224,33 @@ export class RTMWebClient {
221
224
  return nativeResponse;
222
225
  },
223
226
 
227
+ removeUserMetadata: async (
228
+ options?: NativeRemoveUserMetadataOptions,
229
+ ): Promise<NativeRemoveUserMetadataResponse> => {
230
+ // Build the options object for the web SDK call
231
+ const webOptions: RemoveUserMetadataOptions = {};
232
+
233
+ // Add userId if provided (for removing another user's metadata, defaults to self if not provided)
234
+ if (options?.userId && typeof options.userId === 'string') {
235
+ webOptions.userId = options.userId;
236
+ }
237
+
238
+ // Convert native Metadata to web MetadataItem[] format if provided
239
+ if (
240
+ options?.data &&
241
+ options.data.items &&
242
+ Array.isArray(options.data.items) &&
243
+ options.data.items.length > 0
244
+ ) {
245
+ webOptions.data = options.data.items.map(item => ({
246
+ key: item.key,
247
+ value: item.value || '', // Require not used for remove.we use keys
248
+ }));
249
+ }
250
+
251
+ return await this.client.storage.removeUserMetadata(webOptions);
252
+ },
253
+
224
254
  setChannelMetadata: async (
225
255
  channelName: string,
226
256
  channelType: NativeRtmChannelType,
@@ -86,6 +86,7 @@ export interface VideoCallInterface extends BeforeAndAfterInterface {
86
86
  captionPanel?: React.ComponentType;
87
87
  transcriptPanel?: React.ComponentType;
88
88
  virtualBackgroundPanel?: React.ComponentType<VBPanelProps>;
89
+ breakoutRoomPanel?: React.ComponentType;
89
90
  customLayout?: (layouts: LayoutItem[]) => LayoutItem[];
90
91
  wrapper?: React.ComponentType;
91
92
  customAgentInterface?: React.ComponentType<CustomAgentInterfaceProps>;
@@ -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.9',
81
- CORE_VERSION: '4.1.9',
80
+ CLI_VERSION: '3.1.10-beta.1',
81
+ CORE_VERSION: '4.1.10-beta.1',
82
82
  DISABLE_LANDSCAPE_MODE: false,
83
83
  STT_AUTO_START: false,
84
84
  CLOUD_RECORDING_AUTO_START: false,
@@ -91,6 +91,7 @@ const DefaultConfig = {
91
91
  ENABLE_WAITING_ROOM_AUTO_APPROVAL: false,
92
92
  ENABLE_WAITING_ROOM_AUTO_REQUEST: false,
93
93
  ENABLE_TEXT_TRACKS: false,
94
+ ENABLE_BREAKOUT_ROOM: false,
94
95
  };
95
96
 
96
97
  module.exports = DefaultConfig;
@@ -178,6 +178,7 @@ interface ConfigInterface {
178
178
  ENABLE_WAITING_ROOM_AUTO_APPROVAL: boolean;
179
179
  ENABLE_WAITING_ROOM_AUTO_REQUEST: boolean;
180
180
  ENABLE_TEXT_TRACKS: boolean;
181
+ ENABLE_BREAKOUT_ROOM: boolean;
181
182
  }
182
183
  declare var $config: ConfigInterface;
183
184
  declare module 'customization' {
@@ -11,7 +11,6 @@
11
11
  */
12
12
  import React from 'react';
13
13
  import Join from './pages/Join';
14
- import VideoCall from './pages/VideoCall';
15
14
  import Create from './pages/Create';
16
15
  import {Route, Switch, Redirect} from './components/Router';
17
16
  import AuthRoute from './auth/AuthRoute';
@@ -25,6 +24,7 @@ import {useIsRecordingBot} from './subComponents/recording/useIsRecordingBot';
25
24
  import {isValidReactComponent} from './utils/common';
26
25
  import ErrorBoundary from './components/ErrorBoundary';
27
26
  import {ErrorBoundaryFallback} from './components/ErrorBoundaryFallback';
27
+ import VideoCallStateWrapper from './pages/video-call/VideoCallStateWrapper';
28
28
 
29
29
  function VideoCallWrapper(props) {
30
30
  const {isRecordingBot} = useIsRecordingBot();
@@ -32,13 +32,13 @@ function VideoCallWrapper(props) {
32
32
  return isRecordingBot ? (
33
33
  <RecordingBotRoute history={props.history}>
34
34
  <ErrorBoundary fallback={ErrorBoundaryFallbackComponent}>
35
- <VideoCall />
35
+ <VideoCallStateWrapper />
36
36
  </ErrorBoundary>
37
37
  </RecordingBotRoute>
38
38
  ) : (
39
39
  <AuthRoute>
40
40
  <ErrorBoundary fallback={ErrorBoundaryFallbackComponent}>
41
- <VideoCall />
41
+ <VideoCallStateWrapper />
42
42
  </ErrorBoundary>
43
43
  </AuthRoute>
44
44
  );
@@ -31,7 +31,7 @@ export const MicButton = () => {
31
31
  borderRadius: 50,
32
32
  marginHorizontal: 8,
33
33
  }}
34
- onPress={() => muteToggle(MUTE_LOCAL_TYPE.audio)}>
34
+ onPress={async () => await muteToggle(MUTE_LOCAL_TYPE.audio)}>
35
35
  <Image
36
36
  style={[styles.iconStyle, {tintColor: $config.FONT_COLOR}]}
37
37
  source={audio ? MicOnIcon : MicOffIcon}
@@ -24,6 +24,42 @@
24
24
  -moz-osx-font-smoothing: grayscale;
25
25
  }
26
26
 
27
+ .icon-raise-hand-fill:before {
28
+ content: '\e9ac';
29
+ color: #ffab00;
30
+ }
31
+ .icon-open-room:before {
32
+ content: '\e9ab';
33
+ color: #fff;
34
+ }
35
+ .icon-people-assigned:before {
36
+ content: '\e9a4';
37
+ color: #e8eaed;
38
+ }
39
+ .icon-double-up-arrow:before {
40
+ content: '\e9a5';
41
+ color: #fff;
42
+ }
43
+ .icon-move-up:before {
44
+ content: '\e9a6';
45
+ color: #fff;
46
+ }
47
+ .icon-close-room:before {
48
+ content: '\e9a7';
49
+ color: #fff;
50
+ }
51
+ .icon-announcement:before {
52
+ content: '\e9a8';
53
+ color: #fff;
54
+ }
55
+ .icon-settings-outlined:before {
56
+ content: '\e9a9';
57
+ color: #fff;
58
+ }
59
+ .icon-breakout-room:before {
60
+ content: '\e9aa';
61
+ color: #d9d9d9;
62
+ }
27
63
  .icon-spotlight:before {
28
64
  content: '\e9a3';
29
65
  color: #fff;