agora-appbuilder-core 4.1.24-beta.1 → 4.1.24-beta.2
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 +2 -2
- package/template/src/components/PinnedVideo.tsx +43 -23
- package/template/src/components/__tests__/pinnedLayoutState.test.ts +47 -0
- package/template/src/components/participants/UserActionMenuOptions.tsx +15 -2
- package/template/src/components/pinnedLayoutState.ts +43 -0
- package/template/src/pages/video-call/VideoRenderer.tsx +2 -0
package/package.json
CHANGED
|
@@ -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.24-beta.
|
|
81
|
-
CORE_VERSION: "4.1.24-beta.
|
|
80
|
+
CLI_VERSION: "3.1.24-beta.2",
|
|
81
|
+
CORE_VERSION: "4.1.24-beta.2",
|
|
82
82
|
DISABLE_LANDSCAPE_MODE: false,
|
|
83
83
|
STT_AUTO_START: false,
|
|
84
84
|
CLOUD_RECORDING_AUTO_START: false,
|
|
@@ -37,6 +37,8 @@ import {
|
|
|
37
37
|
videoRoomGoToActiveSpeakerText,
|
|
38
38
|
} from '../language/default-labels/videoCallScreenLabels';
|
|
39
39
|
import {useFullScreen} from '..//utils/useFullScreen';
|
|
40
|
+
import {LogSource, logger} from '../logger/AppBuilderLogger';
|
|
41
|
+
import {getPinnedLayoutState} from './pinnedLayoutState';
|
|
40
42
|
const {topPinned} = layoutProps;
|
|
41
43
|
|
|
42
44
|
const PinnedVideo = ({renderData}) => {
|
|
@@ -50,12 +52,38 @@ const PinnedVideo = ({renderData}) => {
|
|
|
50
52
|
const {width} = useWindowDimensions();
|
|
51
53
|
const isDesktop = width > BREAKPOINTS.lg;
|
|
52
54
|
const isSidePinnedlayout = topPinned === true ? false : isDesktop; // if either explicity set to false or auto evaluation
|
|
53
|
-
const
|
|
55
|
+
const {maximizedUid, sidebarUids} = getPinnedLayoutState(
|
|
56
|
+
renderData,
|
|
57
|
+
pinnedUid,
|
|
58
|
+
secondaryPinnedUid,
|
|
59
|
+
);
|
|
60
|
+
const renderDataSnapshot = JSON.stringify(renderData);
|
|
61
|
+
const sidebarUidsSnapshot = JSON.stringify(sidebarUids);
|
|
54
62
|
const activeSpeaker = useActiveSpeaker();
|
|
55
63
|
const {dispatch} = useContext(DispatchContext);
|
|
56
64
|
const {videoTileInViewPortState} = useVideoCall();
|
|
57
65
|
const {getWhiteboardUid = () => 0} = useWhiteboard();
|
|
58
66
|
const {defaultContent, customContent} = useContent();
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
logger.log(
|
|
69
|
+
LogSource.Internals,
|
|
70
|
+
'LAYOUT',
|
|
71
|
+
'[PINNED_LAYOUT] pinned layout UIDs resolved',
|
|
72
|
+
{
|
|
73
|
+
renderData: JSON.parse(renderDataSnapshot),
|
|
74
|
+
pinnedUid: pinnedUid || null,
|
|
75
|
+
secondaryPinnedUid: secondaryPinnedUid || null,
|
|
76
|
+
maximizedUid,
|
|
77
|
+
sidebarUids: JSON.parse(sidebarUidsSnapshot),
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
}, [
|
|
81
|
+
renderDataSnapshot,
|
|
82
|
+
pinnedUid,
|
|
83
|
+
secondaryPinnedUid,
|
|
84
|
+
maximizedUid,
|
|
85
|
+
sidebarUidsSnapshot,
|
|
86
|
+
]);
|
|
59
87
|
useEffect(() => {
|
|
60
88
|
if (activeSpeaker && !videoTileInViewPortState[activeSpeaker] && isOnTop) {
|
|
61
89
|
dispatch({
|
|
@@ -85,21 +113,20 @@ const PinnedVideo = ({renderData}) => {
|
|
|
85
113
|
}
|
|
86
114
|
};
|
|
87
115
|
|
|
88
|
-
const isWhiteboard = customContent && customContent[
|
|
116
|
+
const isWhiteboard = customContent && customContent[maximizedUid];
|
|
89
117
|
const isRemoteScreenshare =
|
|
90
|
-
|
|
118
|
+
maximizedUid != screenUid &&
|
|
91
119
|
defaultContent &&
|
|
92
|
-
defaultContent[
|
|
93
|
-
defaultContent[
|
|
120
|
+
defaultContent[maximizedUid]?.video &&
|
|
121
|
+
defaultContent[maximizedUid]?.type === 'screenshare';
|
|
94
122
|
|
|
95
123
|
//fixed issue on expand/collapse for screenshare
|
|
96
124
|
//screen will have the fullscreen functionality
|
|
97
125
|
useEffect(() => {
|
|
98
|
-
const maximizedUid = pinnedUid || maxUid;
|
|
99
126
|
if (getWhiteboardUid() != maximizedUid && collapse) {
|
|
100
127
|
setCollapse(false);
|
|
101
128
|
}
|
|
102
|
-
}, [isWhiteboard, collapse,
|
|
129
|
+
}, [isWhiteboard, collapse, maximizedUid, getWhiteboardUid]);
|
|
103
130
|
|
|
104
131
|
return (
|
|
105
132
|
<View
|
|
@@ -129,9 +156,7 @@ const PinnedVideo = ({renderData}) => {
|
|
|
129
156
|
marginBottom: 8,
|
|
130
157
|
}
|
|
131
158
|
}>
|
|
132
|
-
{secondaryPinnedUid &&
|
|
133
|
-
secondaryPinnedUid !== pinnedUid &&
|
|
134
|
-
secondaryPinnedUid !== maxUid ? (
|
|
159
|
+
{secondaryPinnedUid && sidebarUids.includes(secondaryPinnedUid) ? (
|
|
135
160
|
<Pressable
|
|
136
161
|
disabled={true}
|
|
137
162
|
style={
|
|
@@ -158,10 +183,8 @@ const PinnedVideo = ({renderData}) => {
|
|
|
158
183
|
<></>
|
|
159
184
|
)}
|
|
160
185
|
{/* Pinned Video Top View(Desktop minimized and Mobile native and Mobile web) / Side View(Desktop maximized)*/}
|
|
161
|
-
{
|
|
186
|
+
{sidebarUids?.map(minUid => {
|
|
162
187
|
if (minUid === secondaryPinnedUid) return null;
|
|
163
|
-
if (minUid === pinnedUid) return null;
|
|
164
|
-
if (minUid === maxUid) return null;
|
|
165
188
|
//rendering minimized view
|
|
166
189
|
return (
|
|
167
190
|
<Pressable
|
|
@@ -194,7 +217,7 @@ const PinnedVideo = ({renderData}) => {
|
|
|
194
217
|
marginRight: 8,
|
|
195
218
|
}
|
|
196
219
|
}
|
|
197
|
-
key={'minVideo' +
|
|
220
|
+
key={'minVideo' + minUid}
|
|
198
221
|
onPress={() => {}}>
|
|
199
222
|
<RenderComponent uid={minUid} />
|
|
200
223
|
</Pressable>
|
|
@@ -259,7 +282,7 @@ const PinnedVideo = ({renderData}) => {
|
|
|
259
282
|
)}
|
|
260
283
|
</>
|
|
261
284
|
)}
|
|
262
|
-
{
|
|
285
|
+
{maximizedUid && (
|
|
263
286
|
<View
|
|
264
287
|
style={
|
|
265
288
|
isSidePinnedlayout
|
|
@@ -268,7 +291,7 @@ const PinnedVideo = ({renderData}) => {
|
|
|
268
291
|
: style.width80
|
|
269
292
|
: style.flex8
|
|
270
293
|
}>
|
|
271
|
-
<View style={style.flex1} key={'maxVideo' +
|
|
294
|
+
<View style={style.flex1} key={'maxVideo' + maximizedUid}>
|
|
272
295
|
{isSidePinnedlayout && (isWhiteboard || isRemoteScreenshare) ? (
|
|
273
296
|
<IconButton
|
|
274
297
|
containerStyle={{
|
|
@@ -279,12 +302,9 @@ const PinnedVideo = ({renderData}) => {
|
|
|
279
302
|
elevation: 999,
|
|
280
303
|
}}
|
|
281
304
|
onPress={() => {
|
|
282
|
-
if (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
) {
|
|
286
|
-
requestFullscreen(pinnedUid || maxUid);
|
|
287
|
-
} else if (customContent[pinnedUid || maxUid]) {
|
|
305
|
+
if (defaultContent && defaultContent[maximizedUid]?.video) {
|
|
306
|
+
requestFullscreen(maximizedUid);
|
|
307
|
+
} else if (customContent[maximizedUid]) {
|
|
288
308
|
setCollapse(!collapse);
|
|
289
309
|
}
|
|
290
310
|
}}
|
|
@@ -348,7 +368,7 @@ const PinnedVideo = ({renderData}) => {
|
|
|
348
368
|
<></>
|
|
349
369
|
)} */}
|
|
350
370
|
{/** Render the maximized view */}
|
|
351
|
-
<RenderComponent uid={
|
|
371
|
+
<RenderComponent uid={maximizedUid} isMax={true} />
|
|
352
372
|
</View>
|
|
353
373
|
</View>
|
|
354
374
|
)}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canViewInLarge,
|
|
3
|
+
getPinnedLayoutState,
|
|
4
|
+
isUidMaximized,
|
|
5
|
+
} from '../pinnedLayoutState';
|
|
6
|
+
|
|
7
|
+
describe('pinned layout state', () => {
|
|
8
|
+
it('keeps every non-maximized UID visible when active-speaker ordering moves another UID to index zero', () => {
|
|
9
|
+
expect(getPinnedLayoutState([200, 101, 100, 201], 101)).toEqual({
|
|
10
|
+
maximizedUid: 101,
|
|
11
|
+
sidebarUids: [200, 100, 201],
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('keeps the secondary pin first without removing any other sidebar UID', () => {
|
|
16
|
+
expect(getPinnedLayoutState([200, 100, 101, 201], 101, 100)).toEqual({
|
|
17
|
+
maximizedUid: 101,
|
|
18
|
+
sidebarUids: [100, 200, 201],
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('falls back to the first render UID when there is no valid primary pin', () => {
|
|
23
|
+
expect(getPinnedLayoutState([200, 100, 101], 999)).toEqual({
|
|
24
|
+
maximizedUid: 200,
|
|
25
|
+
sidebarUids: [100, 101],
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('does not offer View in large for either pinned position', () => {
|
|
30
|
+
expect(canViewInLarge(101, 101, 100)).toBe(false);
|
|
31
|
+
expect(canViewInLarge(100, 101, 100)).toBe(false);
|
|
32
|
+
expect(canViewInLarge(200, 101, 100)).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('does not offer View in large for the fallback maximized UID', () => {
|
|
36
|
+
expect(canViewInLarge(101, undefined, 100, 101)).toBe(false);
|
|
37
|
+
expect(canViewInLarge(100, undefined, 100, 101)).toBe(false);
|
|
38
|
+
expect(canViewInLarge(200, undefined, 100, 101)).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('identifies explicit and fallback maximized UIDs for tile actions', () => {
|
|
42
|
+
expect(isUidMaximized(101, 101, 200)).toBe(true);
|
|
43
|
+
expect(isUidMaximized(200, 101, 200)).toBe(false);
|
|
44
|
+
expect(isUidMaximized(200, undefined, 200)).toBe(true);
|
|
45
|
+
expect(isUidMaximized(100, undefined, 200)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -77,6 +77,7 @@ import {
|
|
|
77
77
|
DEFAULT_ACTION_KEYS,
|
|
78
78
|
UserActionMenuItemsConfig,
|
|
79
79
|
} from '../../atoms/UserActionMenuPreset';
|
|
80
|
+
import {canViewInLarge, isUidMaximized} from '../pinnedLayoutState';
|
|
80
81
|
|
|
81
82
|
interface UserActionMenuOptionsOptionsProps {
|
|
82
83
|
user: ContentInterface;
|
|
@@ -207,7 +208,14 @@ export default function UserActionMenuOptionsOptions(
|
|
|
207
208
|
)
|
|
208
209
|
) {
|
|
209
210
|
if (enablePinForMe) {
|
|
210
|
-
if (
|
|
211
|
+
if (
|
|
212
|
+
canViewInLarge(
|
|
213
|
+
user.uid,
|
|
214
|
+
pinnedUid,
|
|
215
|
+
secondaryPinnedUid,
|
|
216
|
+
activeUids?.[0],
|
|
217
|
+
)
|
|
218
|
+
) {
|
|
211
219
|
const viewInLargeKey = ActionMenuKeys.VIEW_IN_LARGE;
|
|
212
220
|
const viewInLargeConfig = userActionMenuItems?.[viewInLargeKey] ?? {};
|
|
213
221
|
const isPinned = pinnedUid === user.uid;
|
|
@@ -274,9 +282,14 @@ export default function UserActionMenuOptionsOptions(
|
|
|
274
282
|
const pinToTopKey = ActionMenuKeys.PIN_TO_TOP;
|
|
275
283
|
const pinToTopConfig = userActionMenuItems?.[pinToTopKey] ?? {};
|
|
276
284
|
const isPinnedToTop = user.uid === secondaryPinnedUid;
|
|
285
|
+
const isMaximized = isUidMaximized(
|
|
286
|
+
user.uid,
|
|
287
|
+
pinnedUid,
|
|
288
|
+
activeUids?.[0],
|
|
289
|
+
);
|
|
277
290
|
const isOnlyOneActive = activeUids?.length === 1;
|
|
278
291
|
|
|
279
|
-
if (!pinToTopConfig.hide) {
|
|
292
|
+
if (!pinToTopConfig.hide && !isMaximized) {
|
|
280
293
|
items.push({
|
|
281
294
|
key: pinToTopKey,
|
|
282
295
|
disabled: pinToTopConfig.disabled ?? isOnlyOneActive,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {UidType} from '../../agora-rn-uikit';
|
|
2
|
+
|
|
3
|
+
export const getPinnedLayoutState = (
|
|
4
|
+
renderData: UidType[],
|
|
5
|
+
pinnedUid?: UidType,
|
|
6
|
+
secondaryPinnedUid?: UidType,
|
|
7
|
+
) => {
|
|
8
|
+
const maximizedUid: UidType =
|
|
9
|
+
(pinnedUid && renderData.includes(pinnedUid) ? pinnedUid : renderData[0]) ||
|
|
10
|
+
0;
|
|
11
|
+
const sidebarUids = renderData.filter(uid => uid !== maximizedUid);
|
|
12
|
+
|
|
13
|
+
if (
|
|
14
|
+
secondaryPinnedUid &&
|
|
15
|
+
sidebarUids.includes(secondaryPinnedUid) &&
|
|
16
|
+
sidebarUids[0] !== secondaryPinnedUid
|
|
17
|
+
) {
|
|
18
|
+
return {
|
|
19
|
+
maximizedUid,
|
|
20
|
+
sidebarUids: [
|
|
21
|
+
secondaryPinnedUid,
|
|
22
|
+
...sidebarUids.filter(uid => uid !== secondaryPinnedUid),
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {maximizedUid, sidebarUids};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const isUidMaximized = (
|
|
31
|
+
uid: UidType,
|
|
32
|
+
pinnedUid?: UidType,
|
|
33
|
+
fallbackMaximizedUid?: UidType,
|
|
34
|
+
) => uid === (pinnedUid || fallbackMaximizedUid);
|
|
35
|
+
|
|
36
|
+
export const canViewInLarge = (
|
|
37
|
+
uid: UidType,
|
|
38
|
+
pinnedUid?: UidType,
|
|
39
|
+
secondaryPinnedUid?: UidType,
|
|
40
|
+
fallbackMaximizedUid?: UidType,
|
|
41
|
+
) =>
|
|
42
|
+
!isUidMaximized(uid, pinnedUid, fallbackMaximizedUid) &&
|
|
43
|
+
uid !== secondaryPinnedUid;
|
|
@@ -247,10 +247,12 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
|
|
|
247
247
|
uid={user.uid}
|
|
248
248
|
hasLeadingIcon={
|
|
249
249
|
currentLayout === DefaultLayouts[1].name &&
|
|
250
|
+
!isMax &&
|
|
250
251
|
user.uid === secondaryPinnedUid
|
|
251
252
|
}
|
|
252
253
|
/>
|
|
253
254
|
{currentLayout === DefaultLayouts[1].name &&
|
|
255
|
+
!isMax &&
|
|
254
256
|
user.uid === secondaryPinnedUid ? (
|
|
255
257
|
<View
|
|
256
258
|
style={{
|