agora-appbuilder-core 4.1.16 → 4.1.17
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/defaultConfig.js +3 -2
- package/template/global.d.ts +1 -0
- package/template/package.json +1 -0
- package/template/src/assets/live-reactions/1f389.gif +0 -0
- package/template/src/assets/live-reactions/1f44d.gif +0 -0
- package/template/src/assets/live-reactions/1f44f.gif +0 -0
- package/template/src/assets/live-reactions/1f496.gif +0 -0
- package/template/src/assets/live-reactions/1f602.gif +0 -0
- package/template/src/assets/live-reactions/1f622.gif +0 -0
- package/template/src/assets/live-reactions/1f62e.gif +0 -0
- package/template/src/assets/live-reactions/1f914.gif +0 -0
- package/template/src/assets/live-reactions/animated/1f389.json +1 -0
- package/template/src/assets/live-reactions/animated/1f44d.json +1 -0
- package/template/src/assets/live-reactions/animated/1f44f.json +1 -0
- package/template/src/assets/live-reactions/animated/1f496.json +1 -0
- package/template/src/assets/live-reactions/animated/1f602.json +1 -0
- package/template/src/assets/live-reactions/animated/1f622.json +1 -0
- package/template/src/assets/live-reactions/animated/1f62e.json +1 -0
- package/template/src/assets/live-reactions/animated/1f914.json +1 -0
- package/template/src/components/Controls.tsx +21 -5
- package/template/src/components/reactions/LiveReactionBadge.tsx +57 -0
- package/template/src/components/reactions/LiveReactionButton.tsx +257 -0
- package/template/src/components/reactions/LiveReactionStageOverlay.native.tsx +256 -0
- package/template/src/components/reactions/LiveReactionStageOverlay.tsx +326 -0
- package/template/src/components/reactions/catalog.ts +79 -0
- package/template/src/components/useVideoCall.tsx +219 -1
- package/template/src/language/default-labels/videoCallScreenLabels.ts +3 -0
- package/template/src/pages/video-call/ActionSheetContent.tsx +14 -1
- package/template/src/pages/video-call/VideoComponent.tsx +9 -1
- package/template/src/pages/video-call/VideoRenderer.tsx +8 -0
- package/template/src/rtm-events/constants.ts +2 -0
- package/template/webpack.commons.js +1 -1
- package/template/webpack.ts.config.js +1 -1
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import React, {
|
|
14
14
|
SetStateAction,
|
|
15
15
|
useState,
|
|
16
|
+
useCallback,
|
|
16
17
|
useContext,
|
|
17
18
|
useEffect,
|
|
18
19
|
useRef,
|
|
@@ -23,11 +24,30 @@ import StopRecordingPopup from './popups/StopRecordingPopup';
|
|
|
23
24
|
import StartScreenSharePopup from './popups/StartScreenSharePopup';
|
|
24
25
|
import StopScreenSharePopup from './popups/StopScreenSharePopup';
|
|
25
26
|
import {SdkApiContext} from './SdkApiContext';
|
|
26
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
UidType,
|
|
29
|
+
useContent,
|
|
30
|
+
useLocalUserInfo,
|
|
31
|
+
useRoomInfo,
|
|
32
|
+
} from 'customization-api';
|
|
27
33
|
import SDKEvents from '../utils/SdkEvents';
|
|
28
34
|
import DeviceContext from './DeviceContext';
|
|
29
35
|
import useSetName from '../utils/useSetName';
|
|
30
36
|
import WhiteboardClearAllPopup from './popups/WhiteboardClearAllPopup';
|
|
37
|
+
import events from '../rtm-events-api';
|
|
38
|
+
import {PersistanceLevel} from '../rtm-events-api/types';
|
|
39
|
+
import {EventNames} from '../rtm-events';
|
|
40
|
+
import {nanoid} from 'nanoid/non-secure';
|
|
41
|
+
import {useUserPreference} from './useUserPreference';
|
|
42
|
+
import {
|
|
43
|
+
LIVE_REACTION_BADGE_DURATION,
|
|
44
|
+
LIVE_REACTION_FLOAT_DURATION,
|
|
45
|
+
LIVE_REACTION_MAX_FLOATING_ITEMS,
|
|
46
|
+
LiveReactionDefinition,
|
|
47
|
+
LiveReactionEvent,
|
|
48
|
+
} from './reactions/catalog';
|
|
49
|
+
import {useString} from '../utils/useString';
|
|
50
|
+
import {videoRoomUserFallbackText} from '../language/default-labels/videoCallScreenLabels';
|
|
31
51
|
|
|
32
52
|
interface InViewPortState {
|
|
33
53
|
[key: number]: boolean;
|
|
@@ -49,6 +69,9 @@ export interface VideoCallContextInterface {
|
|
|
49
69
|
setVideoTileInViewPortState: (uid: UidType, visible: boolean) => void;
|
|
50
70
|
showWhiteboardClearAllPopup: boolean;
|
|
51
71
|
setShowWhiteboardClearAllPopup: React.Dispatch<SetStateAction<boolean>>;
|
|
72
|
+
latestReactionByUid: Record<string, LiveReactionEvent>;
|
|
73
|
+
floatingReactions: LiveReactionEvent[];
|
|
74
|
+
emitLiveReaction: (reaction: LiveReactionDefinition) => void;
|
|
52
75
|
}
|
|
53
76
|
|
|
54
77
|
const VideoCallContext = React.createContext<VideoCallContextInterface>({
|
|
@@ -68,6 +91,9 @@ const VideoCallContext = React.createContext<VideoCallContextInterface>({
|
|
|
68
91
|
setVideoTileInViewPortState: () => {},
|
|
69
92
|
showWhiteboardClearAllPopup: false,
|
|
70
93
|
setShowWhiteboardClearAllPopup: () => {},
|
|
94
|
+
latestReactionByUid: {},
|
|
95
|
+
floatingReactions: [],
|
|
96
|
+
emitLiveReaction: () => {},
|
|
71
97
|
});
|
|
72
98
|
|
|
73
99
|
interface VideoCallProviderProps {
|
|
@@ -86,10 +112,50 @@ const VideoCallProvider = (props: VideoCallProviderProps) => {
|
|
|
86
112
|
useState(false);
|
|
87
113
|
const {join, enterRoom} = useContext(SdkApiContext);
|
|
88
114
|
const roomInfo = useRoomInfo();
|
|
115
|
+
const localUser = useLocalUserInfo();
|
|
116
|
+
const {defaultContent} = useContent();
|
|
117
|
+
const {uids} = useUserPreference();
|
|
118
|
+
const remoteUserFallbackName = useString(videoRoomUserFallbackText)();
|
|
89
119
|
const {deviceList} = useContext(DeviceContext);
|
|
90
120
|
const setUsername = useSetName();
|
|
91
121
|
//const videoTileInViewPortStateRef = useRef({});
|
|
92
122
|
const [videoTileInViewPortState, setVideoTileInViewPortStateL] = useState({});
|
|
123
|
+
const [latestReactionByUid, setLatestReactionByUid] = useState<
|
|
124
|
+
Record<string, LiveReactionEvent>
|
|
125
|
+
>({});
|
|
126
|
+
const [floatingReactions, setFloatingReactions] = useState<
|
|
127
|
+
LiveReactionEvent[]
|
|
128
|
+
>([]);
|
|
129
|
+
const reactionBadgeTimeoutsRef = useRef<
|
|
130
|
+
Record<string, ReturnType<typeof setTimeout>>
|
|
131
|
+
>({});
|
|
132
|
+
const floatingReactionTimeoutsRef = useRef<
|
|
133
|
+
Record<string, ReturnType<typeof setTimeout>>
|
|
134
|
+
>({});
|
|
135
|
+
const processedReactionIdsRef = useRef<Set<string>>(new Set());
|
|
136
|
+
|
|
137
|
+
const assignReactionLane = useCallback((reaction: LiveReactionEvent) => {
|
|
138
|
+
if (typeof reaction.lane === 'number') {
|
|
139
|
+
return reaction;
|
|
140
|
+
}
|
|
141
|
+
const lane = Math.floor(Math.random() * 5);
|
|
142
|
+
return {...reaction, lane};
|
|
143
|
+
}, []);
|
|
144
|
+
|
|
145
|
+
const getReactionSenderName = useCallback(
|
|
146
|
+
(senderUid: string) => {
|
|
147
|
+
if (String(localUser.uid) === String(senderUid)) {
|
|
148
|
+
return 'You';
|
|
149
|
+
}
|
|
150
|
+
return (
|
|
151
|
+
uids[String(senderUid)]?.name ||
|
|
152
|
+
defaultContent[Number(senderUid)]?.name ||
|
|
153
|
+
defaultContent[String(senderUid)]?.name ||
|
|
154
|
+
remoteUserFallbackName
|
|
155
|
+
);
|
|
156
|
+
},
|
|
157
|
+
[defaultContent, localUser.uid, remoteUserFallbackName, uids],
|
|
158
|
+
);
|
|
93
159
|
|
|
94
160
|
const setVideoTileInViewPortState = (uid: UidType, visible: boolean) => {
|
|
95
161
|
//videoTileInViewPortStateRef.current[uid] = visible;
|
|
@@ -101,6 +167,117 @@ const VideoCallProvider = (props: VideoCallProviderProps) => {
|
|
|
101
167
|
});
|
|
102
168
|
};
|
|
103
169
|
|
|
170
|
+
const cleanupReactionBadgeTimeout = useCallback((uid: string) => {
|
|
171
|
+
if (reactionBadgeTimeoutsRef.current[uid]) {
|
|
172
|
+
clearTimeout(reactionBadgeTimeoutsRef.current[uid]);
|
|
173
|
+
delete reactionBadgeTimeoutsRef.current[uid];
|
|
174
|
+
}
|
|
175
|
+
}, []);
|
|
176
|
+
|
|
177
|
+
const cleanupFloatingReactionTimeout = useCallback((reactionId: string) => {
|
|
178
|
+
if (floatingReactionTimeoutsRef.current[reactionId]) {
|
|
179
|
+
clearTimeout(floatingReactionTimeoutsRef.current[reactionId]);
|
|
180
|
+
delete floatingReactionTimeoutsRef.current[reactionId];
|
|
181
|
+
}
|
|
182
|
+
}, []);
|
|
183
|
+
|
|
184
|
+
const ingestReaction = useCallback(
|
|
185
|
+
(reaction: LiveReactionEvent) => {
|
|
186
|
+
if (!$config.ENABLE_LIVE_REACTIONS) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (processedReactionIdsRef.current.has(reaction.reactionId)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const nextReaction = assignReactionLane({
|
|
193
|
+
...reaction,
|
|
194
|
+
senderDisplayName: getReactionSenderName(reaction.senderUid),
|
|
195
|
+
});
|
|
196
|
+
processedReactionIdsRef.current.add(nextReaction.reactionId);
|
|
197
|
+
if (processedReactionIdsRef.current.size > 200) {
|
|
198
|
+
processedReactionIdsRef.current = new Set(
|
|
199
|
+
Array.from(processedReactionIdsRef.current).slice(-100),
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
setLatestReactionByUid(prev => ({
|
|
204
|
+
...prev,
|
|
205
|
+
[nextReaction.senderUid]: nextReaction,
|
|
206
|
+
}));
|
|
207
|
+
cleanupReactionBadgeTimeout(nextReaction.senderUid);
|
|
208
|
+
reactionBadgeTimeoutsRef.current[nextReaction.senderUid] = setTimeout(
|
|
209
|
+
() => {
|
|
210
|
+
setLatestReactionByUid(prev => {
|
|
211
|
+
if (
|
|
212
|
+
prev[nextReaction.senderUid]?.reactionId !==
|
|
213
|
+
nextReaction.reactionId
|
|
214
|
+
) {
|
|
215
|
+
return prev;
|
|
216
|
+
}
|
|
217
|
+
const next = {...prev};
|
|
218
|
+
delete next[nextReaction.senderUid];
|
|
219
|
+
return next;
|
|
220
|
+
});
|
|
221
|
+
cleanupReactionBadgeTimeout(nextReaction.senderUid);
|
|
222
|
+
},
|
|
223
|
+
LIVE_REACTION_BADGE_DURATION,
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
setFloatingReactions(prev => {
|
|
227
|
+
const next = [...prev, nextReaction];
|
|
228
|
+
return next.length > LIVE_REACTION_MAX_FLOATING_ITEMS
|
|
229
|
+
? next.slice(next.length - LIVE_REACTION_MAX_FLOATING_ITEMS)
|
|
230
|
+
: next;
|
|
231
|
+
});
|
|
232
|
+
cleanupFloatingReactionTimeout(nextReaction.reactionId);
|
|
233
|
+
floatingReactionTimeoutsRef.current[nextReaction.reactionId] = setTimeout(
|
|
234
|
+
() => {
|
|
235
|
+
setFloatingReactions(prev =>
|
|
236
|
+
prev.filter(item => item.reactionId !== nextReaction.reactionId),
|
|
237
|
+
);
|
|
238
|
+
cleanupFloatingReactionTimeout(nextReaction.reactionId);
|
|
239
|
+
},
|
|
240
|
+
LIVE_REACTION_FLOAT_DURATION,
|
|
241
|
+
);
|
|
242
|
+
},
|
|
243
|
+
[
|
|
244
|
+
assignReactionLane,
|
|
245
|
+
cleanupFloatingReactionTimeout,
|
|
246
|
+
cleanupReactionBadgeTimeout,
|
|
247
|
+
getReactionSenderName,
|
|
248
|
+
],
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const emitLiveReaction = useCallback(
|
|
252
|
+
(reaction: LiveReactionDefinition) => {
|
|
253
|
+
const reactionId = `${localUser.uid}-${
|
|
254
|
+
reaction.key
|
|
255
|
+
}-${Date.now()}-${nanoid(4)}`;
|
|
256
|
+
const senderDisplayName = getReactionSenderName(String(localUser.uid));
|
|
257
|
+
const nextReaction: LiveReactionEvent = {
|
|
258
|
+
reactionId,
|
|
259
|
+
assetKey: reaction.key,
|
|
260
|
+
emoji: reaction.emoji,
|
|
261
|
+
senderUid: String(localUser.uid),
|
|
262
|
+
senderDisplayName,
|
|
263
|
+
timestamp: Date.now(),
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
ingestReaction(nextReaction);
|
|
267
|
+
events.send(
|
|
268
|
+
EventNames.LIVE_REACTION,
|
|
269
|
+
JSON.stringify({
|
|
270
|
+
reactionId: nextReaction.reactionId,
|
|
271
|
+
assetKey: nextReaction.assetKey,
|
|
272
|
+
emoji: nextReaction.emoji,
|
|
273
|
+
timestamp: nextReaction.timestamp,
|
|
274
|
+
}),
|
|
275
|
+
PersistanceLevel.None,
|
|
276
|
+
);
|
|
277
|
+
},
|
|
278
|
+
[getReactionSenderName, ingestReaction, localUser.uid],
|
|
279
|
+
);
|
|
280
|
+
|
|
104
281
|
useEffect(() => {
|
|
105
282
|
if (join.initialized && join.phrase) {
|
|
106
283
|
if (join.userName && join.skipPrecall) {
|
|
@@ -118,6 +295,44 @@ const VideoCallProvider = (props: VideoCallProviderProps) => {
|
|
|
118
295
|
roomInfo.data.isHost,
|
|
119
296
|
);
|
|
120
297
|
}, []);
|
|
298
|
+
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
if (!$config.ENABLE_LIVE_REACTIONS) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const unsubscribe = events.on(EventNames.LIVE_REACTION, data => {
|
|
304
|
+
try {
|
|
305
|
+
const payload =
|
|
306
|
+
typeof data.payload === 'string'
|
|
307
|
+
? JSON.parse(data.payload)
|
|
308
|
+
: data.payload;
|
|
309
|
+
ingestReaction({
|
|
310
|
+
reactionId: payload.reactionId,
|
|
311
|
+
assetKey: payload.assetKey,
|
|
312
|
+
emoji: payload.emoji,
|
|
313
|
+
senderUid: String(data.sender),
|
|
314
|
+
timestamp: payload.timestamp || data.ts || Date.now(),
|
|
315
|
+
});
|
|
316
|
+
} catch (error) {
|
|
317
|
+
console.warn('Failed to parse live reaction payload', error);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
return () => {
|
|
322
|
+
unsubscribe();
|
|
323
|
+
};
|
|
324
|
+
}, [ingestReaction]);
|
|
325
|
+
|
|
326
|
+
useEffect(() => {
|
|
327
|
+
return () => {
|
|
328
|
+
Object.keys(reactionBadgeTimeoutsRef.current).forEach(uid => {
|
|
329
|
+
cleanupReactionBadgeTimeout(uid);
|
|
330
|
+
});
|
|
331
|
+
Object.keys(floatingReactionTimeoutsRef.current).forEach(reactionId => {
|
|
332
|
+
cleanupFloatingReactionTimeout(reactionId);
|
|
333
|
+
});
|
|
334
|
+
};
|
|
335
|
+
}, [cleanupFloatingReactionTimeout, cleanupReactionBadgeTimeout]);
|
|
121
336
|
return (
|
|
122
337
|
<VideoCallContext.Provider
|
|
123
338
|
value={{
|
|
@@ -138,6 +353,9 @@ const VideoCallProvider = (props: VideoCallProviderProps) => {
|
|
|
138
353
|
videoTileInViewPortState,
|
|
139
354
|
showWhiteboardClearAllPopup,
|
|
140
355
|
setShowWhiteboardClearAllPopup,
|
|
356
|
+
latestReactionByUid,
|
|
357
|
+
floatingReactions,
|
|
358
|
+
emitLiveReaction,
|
|
141
359
|
}}>
|
|
142
360
|
<StartScreenSharePopup />
|
|
143
361
|
<StopScreenSharePopup />
|
|
@@ -114,6 +114,7 @@ export const toolbarItemManageTextTracksText =
|
|
|
114
114
|
export const toolbarItemVirtualBackgroundText =
|
|
115
115
|
'toolbarItemVirtualBackgroundText';
|
|
116
116
|
export const toolbarItemViewRecordingText = 'toolbarItemViewRecordingText';
|
|
117
|
+
export const toolbarItemReactionText = 'toolbarItemReactionText';
|
|
117
118
|
|
|
118
119
|
export const toolbarItemRaiseHandText = 'toolbarItemRaiseHandText';
|
|
119
120
|
|
|
@@ -585,6 +586,7 @@ export interface I18nVideoCallScreenLabelsInterface {
|
|
|
585
586
|
[toolbarItemManageTextTracksText]?: I18nConditionalType;
|
|
586
587
|
[toolbarItemVirtualBackgroundText]?: I18nBaseType;
|
|
587
588
|
[toolbarItemViewRecordingText]?: I18nConditionalType;
|
|
589
|
+
[toolbarItemReactionText]?: I18nBaseType;
|
|
588
590
|
|
|
589
591
|
[toolbarItemRaiseHandText]?: I18nConditionalType;
|
|
590
592
|
|
|
@@ -957,6 +959,7 @@ export const VideoCallScreenLabels: I18nVideoCallScreenLabelsInterface = {
|
|
|
957
959
|
[toolbarItemTranscriptText]: active =>
|
|
958
960
|
active ? 'Hide Meeting Transcript' : 'Show Meeting Transcript',
|
|
959
961
|
[toolbarItemViewRecordingText]: 'View Recordings',
|
|
962
|
+
[toolbarItemReactionText]: 'React',
|
|
960
963
|
[toolbarItemManageTextTracksText]: 'View Text-tracks',
|
|
961
964
|
|
|
962
965
|
[toolbarItemRaiseHandText]: active => (active ? 'Lower Hand' : 'Raise Hand'),
|
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
ScreenshareToolbarItem,
|
|
66
66
|
} from '../../components/controls/toolbar-items';
|
|
67
67
|
import {useControlPermissionMatrix} from '../../components/controls/useControlPermissionMatrix';
|
|
68
|
+
import LiveReactionButton from '../../components/reactions/LiveReactionButton';
|
|
68
69
|
//Icon for expanding Action Sheet
|
|
69
70
|
interface ShowMoreIconProps {
|
|
70
71
|
isExpanded: boolean;
|
|
@@ -157,6 +158,14 @@ const LayoutIcon = props => {
|
|
|
157
158
|
);
|
|
158
159
|
};
|
|
159
160
|
|
|
161
|
+
const LiveReactionIcon = props => {
|
|
162
|
+
return (
|
|
163
|
+
<ToolbarItem toolbarProps={props}>
|
|
164
|
+
<LiveReactionButton />
|
|
165
|
+
</ToolbarItem>
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
|
|
160
169
|
interface CaptionIconBtnProps {
|
|
161
170
|
showLabel?: boolean;
|
|
162
171
|
onPressCallback?: () => void;
|
|
@@ -341,8 +350,12 @@ const ActionSheetContent = props => {
|
|
|
341
350
|
component:
|
|
342
351
|
!isAudioRoom && (isAudioVideoControlsDisabled ? null : CamIcon),
|
|
343
352
|
},
|
|
344
|
-
|
|
353
|
+
reactions: {
|
|
345
354
|
order: 2,
|
|
355
|
+
component: $config.ENABLE_LIVE_REACTIONS ? LiveReactionIcon : null,
|
|
356
|
+
},
|
|
357
|
+
'end-call': {
|
|
358
|
+
order: 3,
|
|
346
359
|
component: EndCallIcon,
|
|
347
360
|
},
|
|
348
361
|
chat: {
|
|
@@ -13,6 +13,7 @@ import {useLiveStreamDataContext} from '../../components/contexts/LiveStreamData
|
|
|
13
13
|
import {useCustomization} from 'customization-implementation';
|
|
14
14
|
import useMount from '../../components/useMount';
|
|
15
15
|
import {whiteboardContext} from '../../components/whiteboard/WhiteboardConfigure';
|
|
16
|
+
import LiveReactionStageOverlay from '../../components/reactions/LiveReactionStageOverlay';
|
|
16
17
|
|
|
17
18
|
const VideoComponent = () => {
|
|
18
19
|
const {dispatch} = useContext(DispatchContext);
|
|
@@ -108,10 +109,12 @@ const VideoComponent = () => {
|
|
|
108
109
|
<View
|
|
109
110
|
style={{
|
|
110
111
|
flex: 1,
|
|
112
|
+
position: 'relative',
|
|
111
113
|
flexDirection: isDesktop() ? 'row' : 'column',
|
|
112
114
|
justifyContent: 'space-between',
|
|
113
115
|
}}>
|
|
114
116
|
<CurrentLayout renderData={activeUids} />
|
|
117
|
+
<LiveReactionStageOverlay />
|
|
115
118
|
{((!$config.EVENT_MODE && activeUids.length === 1) ||
|
|
116
119
|
($config.EVENT_MODE &&
|
|
117
120
|
hostUids.concat(audienceUids)?.length === 1)) &&
|
|
@@ -127,7 +130,12 @@ const VideoComponent = () => {
|
|
|
127
130
|
</View>
|
|
128
131
|
);
|
|
129
132
|
}
|
|
130
|
-
return
|
|
133
|
+
return (
|
|
134
|
+
<View style={{flex: 1, position: 'relative'}}>
|
|
135
|
+
<CurrentLayout renderData={activeUids} />
|
|
136
|
+
<LiveReactionStageOverlay />
|
|
137
|
+
</View>
|
|
138
|
+
);
|
|
131
139
|
} else {
|
|
132
140
|
return <></>;
|
|
133
141
|
}
|
|
@@ -52,6 +52,7 @@ import {LogSource, logger} from '../../logger/AppBuilderLogger';
|
|
|
52
52
|
import {useFullScreen} from '../../utils/useFullScreen';
|
|
53
53
|
import SpotlightHighligher from './SpotlightHighlighter';
|
|
54
54
|
import {AgentContext} from '../../ai-agent/components/AgentControls/AgentContext';
|
|
55
|
+
import LiveReactionBadge from '../../components/reactions/LiveReactionBadge';
|
|
55
56
|
|
|
56
57
|
export interface VideoRendererProps {
|
|
57
58
|
user: ContentInterface;
|
|
@@ -238,6 +239,13 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
|
|
|
238
239
|
{!showReplacePin && !showPinForMe && (
|
|
239
240
|
<ScreenShareNotice uid={user.uid} isMax={isMax} />
|
|
240
241
|
)}
|
|
242
|
+
<LiveReactionBadge
|
|
243
|
+
uid={user.uid}
|
|
244
|
+
hasLeadingIcon={
|
|
245
|
+
currentLayout === DefaultLayouts[1].name &&
|
|
246
|
+
user.uid === secondaryPinnedUid
|
|
247
|
+
}
|
|
248
|
+
/>
|
|
241
249
|
{currentLayout === DefaultLayouts[1].name &&
|
|
242
250
|
user.uid === secondaryPinnedUid ? (
|
|
243
251
|
<View
|
|
@@ -47,6 +47,7 @@ const BOARD_COLOR_CHANGED = 'BOARD_COLOR_CHANGED';
|
|
|
47
47
|
const WHITEBOARD_LAST_IMAGE_UPLOAD_POSITION = 'WHITEBOARD_L_I_U_P';
|
|
48
48
|
const RECORDING_DELETED = 'RECORDING_DELETED';
|
|
49
49
|
const SPOTLIGHT_USER_CHANGED = 'SPOTLIGHT_USER_CHANGED';
|
|
50
|
+
const LIVE_REACTION = 'LIVE_REACTION';
|
|
50
51
|
const EventNames = {
|
|
51
52
|
RECORDING_STATE_ATTRIBUTE,
|
|
52
53
|
RECORDING_STARTED_BY_ATTRIBUTE,
|
|
@@ -76,6 +77,7 @@ const EventNames = {
|
|
|
76
77
|
WHITEBOARD_LAST_IMAGE_UPLOAD_POSITION,
|
|
77
78
|
RECORDING_DELETED,
|
|
78
79
|
SPOTLIGHT_USER_CHANGED,
|
|
80
|
+
LIVE_REACTION,
|
|
79
81
|
};
|
|
80
82
|
/** ***** EVENT NAMES ENDS ***** */
|
|
81
83
|
|