@q9labsai/chalk-react-native 5.2.0 → 5.2.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/dist/{chunk-4L5GXJ36.js → chunk-BXDD5BE4.js} +23 -1
- package/dist/{chunk-MBZRE4US.js → chunk-PPQSOU35.js} +5 -5
- package/dist/client.js +5 -4
- package/dist/components/EmbeddedWhiteboard.d.ts +8 -4
- package/dist/frame/call-controls.d.ts +2 -0
- package/dist/frame/use-landscape-chrome.d.ts +8 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +365 -101
- package/dist/invites.d.ts +5 -0
- package/dist/invites.js +3 -1
- package/dist/primitives/IconButton.d.ts +1 -0
- package/dist/primitives/NameTag.d.ts +2 -1
- package/dist/primitives/TileShell.d.ts +2 -1
- package/dist/stage/ParticipantTile.d.ts +3 -1
- package/dist/stage/TileSheet.d.ts +1 -1
- package/dist/stage/stage-view.d.ts +4 -0
- package/dist/status/StatusPage.d.ts +3 -1
- package/dist/ui.js +1 -1
- package/dist/whiteboard/export-board-image.d.ts +6 -0
- package/dist/whiteboard/native-board-session.d.ts +15 -0
- package/embedded/chalk-whiteboard/Figtree-Regular.ttf +0 -0
- package/embedded/chalk-whiteboard/Figtree-SemiBold.ttf +0 -0
- package/embedded/chalk-whiteboard/asset-manifest.json +19 -4
- package/embedded/chalk-whiteboard/chalk.css +44 -0
- package/embedded/chalk-whiteboard/licenses/Figtree.txt +93 -0
- package/embedded/chalk-whiteboard/renderer.js +1669 -1418
- package/package.json +11 -6
- package/src/components/EmbeddedWhiteboard.tsx +90 -6
- package/src/dock/Dock.tsx +14 -3
- package/src/dock/MoreSheet.tsx +23 -0
- package/src/frame/CallFrame.tsx +20 -33
- package/src/frame/call-controls.ts +4 -0
- package/src/frame/use-landscape-chrome.ts +22 -0
- package/src/index.ts +2 -2
- package/src/invites.ts +32 -1
- package/src/primitives/IconButton.tsx +6 -5
- package/src/primitives/NameTag.tsx +7 -1
- package/src/primitives/TileShell.tsx +3 -1
- package/src/space-client/create-native-space-client.ts +5 -4
- package/src/stage/ContentTile.tsx +64 -19
- package/src/stage/ParticipantTile.tsx +6 -4
- package/src/stage/Stage.tsx +37 -6
- package/src/stage/TileSheet.tsx +17 -2
- package/src/stage/stage-view.tsx +11 -1
- package/src/status/CallOverlays.tsx +1 -1
- package/src/status/StatusPage.tsx +12 -4
- package/src/whiteboard/export-board-image.ts +21 -0
- package/src/whiteboard/native-board-session.ts +29 -0
package/dist/index.js
CHANGED
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
extractSpaceInviteFromLink,
|
|
6
6
|
getClipboardInviteSuggestion,
|
|
7
|
+
parseChalkInviteLink,
|
|
7
8
|
parseSpaceInviteLink
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BXDD5BE4.js";
|
|
9
10
|
import {
|
|
10
11
|
BottomSheet,
|
|
11
12
|
ChalkText,
|
|
@@ -53,13 +54,13 @@ import {
|
|
|
53
54
|
useTheme,
|
|
54
55
|
useToasts,
|
|
55
56
|
viewer
|
|
56
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-PPQSOU35.js";
|
|
57
58
|
import {
|
|
58
59
|
useMeasuredRef
|
|
59
60
|
} from "./chunk-GYVZSOGQ.js";
|
|
60
61
|
|
|
61
62
|
// src/frame/Chalk.tsx
|
|
62
|
-
import { useEffect as
|
|
63
|
+
import { useEffect as useEffect23 } from "react";
|
|
63
64
|
import { StyleSheet as StyleSheet24 } from "react-native";
|
|
64
65
|
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
65
66
|
import { SafeAreaProvider as SafeAreaProvider2 } from "react-native-safe-area-context";
|
|
@@ -114,6 +115,8 @@ var StageViewContext = createContext2(null);
|
|
|
114
115
|
function StageViewProvider({ children }) {
|
|
115
116
|
const [layout, setLayout] = useState("spotlight");
|
|
116
117
|
const [pinned, setPinned] = useState(null);
|
|
118
|
+
const [boardOpen, setBoardOpen] = useState(null);
|
|
119
|
+
const [following, setFollowing] = useState(null);
|
|
117
120
|
const [mirror, setMirror] = useState(true);
|
|
118
121
|
const dev = useDevScenario();
|
|
119
122
|
useEffect(() => {
|
|
@@ -124,6 +127,10 @@ function StageViewProvider({ children }) {
|
|
|
124
127
|
() => ({
|
|
125
128
|
layout,
|
|
126
129
|
pinned,
|
|
130
|
+
boardOpen,
|
|
131
|
+
setBoardOpen,
|
|
132
|
+
following,
|
|
133
|
+
setFollowing,
|
|
127
134
|
mirror,
|
|
128
135
|
setLayout: (next) => {
|
|
129
136
|
setLayout(next);
|
|
@@ -143,7 +150,7 @@ function StageViewProvider({ children }) {
|
|
|
143
150
|
},
|
|
144
151
|
setMirror
|
|
145
152
|
}),
|
|
146
|
-
[layout, mirror, pinned]
|
|
153
|
+
[layout, mirror, pinned, following, boardOpen]
|
|
147
154
|
);
|
|
148
155
|
return /* @__PURE__ */ jsx2(StageViewContext.Provider, { value, children });
|
|
149
156
|
}
|
|
@@ -154,7 +161,7 @@ function useStageView() {
|
|
|
154
161
|
}
|
|
155
162
|
|
|
156
163
|
// src/frame/CallFrame.tsx
|
|
157
|
-
import { useCallback as
|
|
164
|
+
import { useCallback as useCallback17, useEffect as useEffect22, useMemo as useMemo12, useRef as useRef13, useState as useState15 } from "react";
|
|
158
165
|
import { Pressable as Pressable15, StatusBar, StyleSheet as StyleSheet23, View as View22 } from "react-native";
|
|
159
166
|
import Animated12, { useAnimatedStyle as useAnimatedStyle7, useSharedValue as useSharedValue5, withTiming as withTiming7 } from "react-native-reanimated";
|
|
160
167
|
|
|
@@ -295,13 +302,27 @@ function RoutePicker({ open, onClose, onSelect, output, anchorRef }) {
|
|
|
295
302
|
import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
296
303
|
var Dock = memo(function Dock2({ arrangement, microphoneOn, cameraOn, onToggleMicrophone, onToggleCamera, onOpenMore, onLeave, moreOpen, leaveOpen, moreRef, leaveRef }) {
|
|
297
304
|
const live = useConnection().status === "live";
|
|
305
|
+
const { local } = useMedia();
|
|
298
306
|
const size = arrangement === "pad" ? 44 : 52;
|
|
299
307
|
const dockStyle = [styles.dock, arrangement === "pad" ? styles.pad : arrangement === "landscape" ? styles.landscape : styles.portrait];
|
|
300
308
|
const dockRef = useMeasuredRef("frame.dock", dockStyle);
|
|
301
309
|
const output = useAudioOutput();
|
|
302
310
|
return /* @__PURE__ */ jsxs(View, { accessibilityLabel: "Call controls", accessibilityRole: "toolbar", pointerEvents: "box-none", ref: dockRef, style: dockStyle, testID: "frame.dock", children: [
|
|
303
|
-
/* @__PURE__ */ jsx4(
|
|
304
|
-
|
|
311
|
+
/* @__PURE__ */ jsx4(
|
|
312
|
+
IconButton,
|
|
313
|
+
{
|
|
314
|
+
accessibilityLabel: microphoneOn ? "Mute microphone" : "Unmute microphone",
|
|
315
|
+
busy: local.microphone.state === "requesting",
|
|
316
|
+
icon: microphoneOn ? "mic" : "micOff",
|
|
317
|
+
off: !microphoneOn,
|
|
318
|
+
disabled: !live && !microphoneOn,
|
|
319
|
+
onCanvas: true,
|
|
320
|
+
onPress: onToggleMicrophone,
|
|
321
|
+
size,
|
|
322
|
+
testID: "dock.microphone"
|
|
323
|
+
}
|
|
324
|
+
),
|
|
325
|
+
/* @__PURE__ */ jsx4(IconButton, { accessibilityLabel: cameraOn ? "Turn off camera" : "Turn on camera", busy: local.camera.state === "requesting", icon: cameraOn ? "cam" : "camOff", off: !cameraOn, disabled: !live && !cameraOn, onCanvas: true, onPress: onToggleCamera, size, testID: "dock.camera" }),
|
|
305
326
|
output ? /* @__PURE__ */ jsx4(AudioOutputButton, { captioned: arrangement === "portrait", output, size }) : null,
|
|
306
327
|
/* @__PURE__ */ jsx4(IconButton, { accessibilityLabel: "More options", expanded: moreOpen, icon: "more", onCanvas: true, onPress: onOpenMore, ref: moreRef, size, testID: "dock.more" }),
|
|
307
328
|
arrangement === "pad" ? /* @__PURE__ */ jsx4(View, { style: styles.gap }) : null,
|
|
@@ -403,12 +424,14 @@ var REACTIONS = [
|
|
|
403
424
|
function MoreSheet({ open, onClose, onOpenPeople, onOpenChat, inviteLink, returnFocusRef }) {
|
|
404
425
|
const client = useSpaceClient();
|
|
405
426
|
const self = useSelf();
|
|
427
|
+
const stage = useStageView();
|
|
406
428
|
const people2 = useParticipants().roster.length;
|
|
407
429
|
const toasts = useToasts();
|
|
408
430
|
const { soundsEnabled } = usePreferences();
|
|
409
431
|
const canRaiseHand = useCan("raiseHand");
|
|
410
432
|
const live = useConnection().status === "live";
|
|
411
433
|
const canReact = useCan("sendReaction") && live;
|
|
434
|
+
const canManageBoard = useCan("manageWhiteboard");
|
|
412
435
|
const fail = useCallback5((message2) => () => toasts.show({ kind: "error", dismissible: true, message: message2 }), [toasts]);
|
|
413
436
|
const toggleHand = useCallback5(() => {
|
|
414
437
|
onClose();
|
|
@@ -436,6 +459,27 @@ function MoreSheet({ open, onClose, onOpenPeople, onOpenChat, inviteLink, return
|
|
|
436
459
|
/* @__PURE__ */ jsxs3(SheetGroup, { children: [
|
|
437
460
|
inviteLink ? /* @__PURE__ */ jsx7(CopyLinkRow, { link: inviteLink }) : null,
|
|
438
461
|
inviteLink ? /* @__PURE__ */ jsx7(SheetRow, { icon: "iosShare", label: "Share link", onPress: () => shareLink(inviteLink), testID: "more.share" }) : null,
|
|
462
|
+
/* @__PURE__ */ jsx7(
|
|
463
|
+
SheetRow,
|
|
464
|
+
{
|
|
465
|
+
icon: "pen",
|
|
466
|
+
label: "Board",
|
|
467
|
+
onPress: () => {
|
|
468
|
+
onClose();
|
|
469
|
+
const transport = client.whiteboard.transport();
|
|
470
|
+
if (!transport) {
|
|
471
|
+
fail("The board is unavailable in this call.")();
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
void transport.startSceneSubscription().then(async () => {
|
|
475
|
+
if (canManageBoard) await transport.setPresentation?.(true);
|
|
476
|
+
stage.setBoardOpen(true);
|
|
477
|
+
stage.showContent();
|
|
478
|
+
}).catch(fail("Couldn\u2019t open the board. Try again."));
|
|
479
|
+
},
|
|
480
|
+
testID: "more.board"
|
|
481
|
+
}
|
|
482
|
+
),
|
|
439
483
|
/* @__PURE__ */ jsx7(RecordingRow, { onDone: onClose }),
|
|
440
484
|
/* @__PURE__ */ jsx7(ChatRow, { onPress: onOpenChat }),
|
|
441
485
|
/* @__PURE__ */ jsx7(SheetRow, { end: /* @__PURE__ */ jsx7(PeopleCount, { count: people2 }), icon: "users", label: "People", onPress: onOpenPeople, testID: "more.people" }),
|
|
@@ -1606,10 +1650,33 @@ var styles11 = StyleSheet11.create({
|
|
|
1606
1650
|
});
|
|
1607
1651
|
|
|
1608
1652
|
// src/stage/Stage.tsx
|
|
1609
|
-
import { memo as memo11, useCallback as
|
|
1653
|
+
import { memo as memo11, useCallback as useCallback14, useEffect as useEffect16, useMemo as useMemo11, useState as useState13 } from "react";
|
|
1610
1654
|
import { Pressable as Pressable13, StyleSheet as StyleSheet18, View as View18 } from "react-native";
|
|
1611
1655
|
import Animated9 from "react-native-reanimated";
|
|
1612
1656
|
|
|
1657
|
+
// src/whiteboard/native-board-session.ts
|
|
1658
|
+
function ownNativeBoardSession(client, onError) {
|
|
1659
|
+
const transport = client.whiteboard.transport();
|
|
1660
|
+
if (!transport) return () => {
|
|
1661
|
+
};
|
|
1662
|
+
let started = false;
|
|
1663
|
+
let active = true;
|
|
1664
|
+
const observe = () => {
|
|
1665
|
+
if (started || client.getSnapshot().connection.status !== "live") return;
|
|
1666
|
+
started = true;
|
|
1667
|
+
void transport.startSceneSubscription().catch(() => {
|
|
1668
|
+
if (active) onError();
|
|
1669
|
+
});
|
|
1670
|
+
};
|
|
1671
|
+
const unsubscribe = client.subscribe(observe);
|
|
1672
|
+
observe();
|
|
1673
|
+
return () => {
|
|
1674
|
+
active = false;
|
|
1675
|
+
unsubscribe();
|
|
1676
|
+
if (started) void transport.stopSceneSubscription();
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1613
1680
|
// src/motion/MovingFrame.tsx
|
|
1614
1681
|
import { useEffect as useEffect11, useRef as useRef7 } from "react";
|
|
1615
1682
|
import { StyleSheet as StyleSheet12 } from "react-native";
|
|
@@ -1688,13 +1755,37 @@ var tileLeaving = () => {
|
|
|
1688
1755
|
};
|
|
1689
1756
|
|
|
1690
1757
|
// src/stage/ContentTile.tsx
|
|
1691
|
-
import {
|
|
1758
|
+
import { ChalkWhiteboardViewBounds } from "@q9labsai/chalk-client";
|
|
1759
|
+
import { memo as memo8, useCallback as useCallback11, useContext as useContext4, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef10, useState as useState12 } from "react";
|
|
1692
1760
|
import { Pressable as Pressable11, StyleSheet as StyleSheet14, View as View14 } from "react-native";
|
|
1693
1761
|
|
|
1694
1762
|
// src/components/EmbeddedWhiteboard.tsx
|
|
1695
1763
|
import { ChalkWhiteboardController } from "@q9labsai/chalk-whiteboard/embedded";
|
|
1696
1764
|
import { useCallback as useCallback9, useEffect as useEffect12, useMemo as useMemo7, useRef as useRef8, useState as useState11 } from "react";
|
|
1697
1765
|
import { ActivityIndicator as ActivityIndicator2, Pressable as Pressable10, Text as Text2, useWindowDimensions, View as View12 } from "react-native";
|
|
1766
|
+
|
|
1767
|
+
// src/whiteboard/export-board-image.ts
|
|
1768
|
+
import { setImageAsync } from "expo-clipboard";
|
|
1769
|
+
import { File as File2, Paths } from "expo-file-system";
|
|
1770
|
+
import { isAvailableAsync, shareAsync } from "expo-sharing";
|
|
1771
|
+
async function exportBoardImage(value) {
|
|
1772
|
+
if (value.format !== "png" || !value.dataURL.startsWith("data:image/png;base64,")) throw new Error("Board export is not a PNG image");
|
|
1773
|
+
const base64 = value.dataURL.slice("data:image/png;base64,".length);
|
|
1774
|
+
if (value.action === "copy") {
|
|
1775
|
+
await setImageAsync(base64);
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
if (!await isAvailableAsync()) throw new Error("Image sharing is unavailable on this device");
|
|
1779
|
+
const file = new File2(Paths.cache, `chalk-board-${Date.now()}.png`);
|
|
1780
|
+
try {
|
|
1781
|
+
file.write(base64, { encoding: "base64" });
|
|
1782
|
+
await shareAsync(file.uri, { mimeType: "image/png", UTI: "public.png", dialogTitle: "Save or share the board", anchor: { x: 16, y: 16, width: 1, height: 1 } });
|
|
1783
|
+
} finally {
|
|
1784
|
+
if (file.exists) file.delete();
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
// src/components/EmbeddedWhiteboard.tsx
|
|
1698
1789
|
import WebView from "react-native-webview";
|
|
1699
1790
|
|
|
1700
1791
|
// src/whiteboard/embedded-whiteboard-assets.ts
|
|
@@ -1743,7 +1834,7 @@ var embeddedWhiteboardWebViewSecurityPolicy = Object.freeze({
|
|
|
1743
1834
|
allowFileAccessFromFileURLs: false,
|
|
1744
1835
|
allowUniversalAccessFromFileURLs: false,
|
|
1745
1836
|
cacheEnabled: false,
|
|
1746
|
-
domStorageEnabled:
|
|
1837
|
+
domStorageEnabled: true,
|
|
1747
1838
|
javaScriptCanOpenWindowsAutomatically: false,
|
|
1748
1839
|
javaScriptEnabled: true,
|
|
1749
1840
|
mixedContentMode: "never",
|
|
@@ -1751,11 +1842,41 @@ var embeddedWhiteboardWebViewSecurityPolicy = Object.freeze({
|
|
|
1751
1842
|
sharedCookiesEnabled: false,
|
|
1752
1843
|
thirdPartyCookiesEnabled: false
|
|
1753
1844
|
});
|
|
1754
|
-
function EmbeddedWhiteboard({
|
|
1845
|
+
function EmbeddedWhiteboard({
|
|
1846
|
+
board,
|
|
1847
|
+
onFollow,
|
|
1848
|
+
onCloseBoard,
|
|
1849
|
+
transport,
|
|
1850
|
+
journeyId,
|
|
1851
|
+
traceparent,
|
|
1852
|
+
tracestate,
|
|
1853
|
+
canDraw,
|
|
1854
|
+
canClear,
|
|
1855
|
+
theme: themeOverride,
|
|
1856
|
+
localParticipantColor,
|
|
1857
|
+
rendererURL: rendererURLOverride,
|
|
1858
|
+
style,
|
|
1859
|
+
testID,
|
|
1860
|
+
onMetric,
|
|
1861
|
+
onError,
|
|
1862
|
+
onUserExport
|
|
1863
|
+
}) {
|
|
1864
|
+
const toasts = useToasts();
|
|
1865
|
+
const noticesRef = useRef8(/* @__PURE__ */ new Map());
|
|
1866
|
+
const clearNotices = useCallback9(() => {
|
|
1867
|
+
noticesRef.current.forEach((id) => toasts.dismiss(id));
|
|
1868
|
+
noticesRef.current.clear();
|
|
1869
|
+
}, [toasts]);
|
|
1755
1870
|
const theme = themeOverride ?? "light";
|
|
1756
1871
|
const webViewRef = useRef8(null);
|
|
1757
1872
|
const controllerRef = useRef8(null);
|
|
1758
1873
|
const listenersRef = useRef8(/* @__PURE__ */ new Set());
|
|
1874
|
+
const boardRef = useRef8(board);
|
|
1875
|
+
boardRef.current = board;
|
|
1876
|
+
const onFollowRef = useRef8(onFollow);
|
|
1877
|
+
onFollowRef.current = onFollow;
|
|
1878
|
+
const onCloseBoardRef = useRef8(onCloseBoard);
|
|
1879
|
+
onCloseBoardRef.current = onCloseBoard;
|
|
1759
1880
|
const onMetricRef = useRef8(onMetric);
|
|
1760
1881
|
const onErrorRef = useRef8(onError);
|
|
1761
1882
|
const onUserExportRef = useRef8(onUserExport);
|
|
@@ -1784,7 +1905,13 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
|
|
|
1784
1905
|
);
|
|
1785
1906
|
const handleControllerError = useCallback9((error2) => onErrorRef.current?.(error2), []);
|
|
1786
1907
|
const handleControllerMetric = useCallback9((metric) => onMetricRef.current?.(metric), []);
|
|
1787
|
-
const handleControllerUserExport = useCallback9((value) =>
|
|
1908
|
+
const handleControllerUserExport = useCallback9(async (value) => {
|
|
1909
|
+
if (onUserExportRef.current) {
|
|
1910
|
+
await onUserExportRef.current(value);
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1913
|
+
await exportBoardImage(value);
|
|
1914
|
+
}, []);
|
|
1788
1915
|
useEffect12(() => {
|
|
1789
1916
|
let active = true;
|
|
1790
1917
|
setLoadError(null);
|
|
@@ -1808,6 +1935,41 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
|
|
|
1808
1935
|
journeyId,
|
|
1809
1936
|
...traceparent ? { traceparent } : {},
|
|
1810
1937
|
...tracestate ? { tracestate } : {},
|
|
1938
|
+
board: boardRef.current,
|
|
1939
|
+
manageSceneSubscription: false,
|
|
1940
|
+
onNotice: (notice) => {
|
|
1941
|
+
if (!notice) {
|
|
1942
|
+
clearNotices();
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
const toastId = toasts.show({
|
|
1946
|
+
kind: notice.kind,
|
|
1947
|
+
message: notice.message,
|
|
1948
|
+
dismissible: notice.kind === "error",
|
|
1949
|
+
...notice.actionLabel ? {
|
|
1950
|
+
actions: [
|
|
1951
|
+
{
|
|
1952
|
+
label: notice.actionLabel,
|
|
1953
|
+
onPress: () => {
|
|
1954
|
+
controller.performNoticeAction(notice.id);
|
|
1955
|
+
const id = noticesRef.current.get(notice.id);
|
|
1956
|
+
if (id !== void 0) toasts.dismiss(id);
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
]
|
|
1960
|
+
} : {}
|
|
1961
|
+
});
|
|
1962
|
+
noticesRef.current.set(notice.id, toastId);
|
|
1963
|
+
if (noticesRef.current.size > 8) {
|
|
1964
|
+
const oldest = noticesRef.current.entries().next().value;
|
|
1965
|
+
if (oldest) {
|
|
1966
|
+
toasts.dismiss(oldest[1]);
|
|
1967
|
+
noticesRef.current.delete(oldest[0]);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
},
|
|
1971
|
+
onFollow: (id) => onFollowRef.current?.(id),
|
|
1972
|
+
onCloseBoard: () => onCloseBoardRef.current?.(),
|
|
1811
1973
|
canDraw,
|
|
1812
1974
|
canClear,
|
|
1813
1975
|
theme,
|
|
@@ -1823,8 +1985,12 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
|
|
|
1823
1985
|
return () => {
|
|
1824
1986
|
if (controllerRef.current === controller) controllerRef.current = null;
|
|
1825
1987
|
controller.stop();
|
|
1988
|
+
clearNotices();
|
|
1826
1989
|
};
|
|
1827
|
-
}, [handleControllerError, handleControllerMetric, handleControllerUserExport, journeyId, localParticipantColor, rendererPort, theme, traceparent, tracestate, transport]);
|
|
1990
|
+
}, [clearNotices, toasts, handleControllerError, handleControllerMetric, handleControllerUserExport, journeyId, localParticipantColor, rendererPort, theme, traceparent, tracestate, transport]);
|
|
1991
|
+
useEffect12(() => {
|
|
1992
|
+
controllerRef.current?.setBoard(board);
|
|
1993
|
+
}, [board]);
|
|
1828
1994
|
useEffect12(() => {
|
|
1829
1995
|
controllerRef.current?.setCapabilities({ canDraw, canClear });
|
|
1830
1996
|
}, [canClear, canDraw]);
|
|
@@ -1842,6 +2008,7 @@ function EmbeddedWhiteboard({ transport, journeyId, traceparent, tracestate, can
|
|
|
1842
2008
|
};
|
|
1843
2009
|
const allowNavigation = (request) => Boolean(rendererURL && isEmbeddedWhiteboardNavigationAllowed(request.url, rendererURL));
|
|
1844
2010
|
const reloadRenderer = () => {
|
|
2011
|
+
clearNotices();
|
|
1845
2012
|
controllerRef.current?.rendererReloaded();
|
|
1846
2013
|
setRendererGeneration(createRendererGeneration());
|
|
1847
2014
|
};
|
|
@@ -1928,16 +2095,21 @@ function RtcVideoView(props) {
|
|
|
1928
2095
|
return /* @__PURE__ */ jsx21(RtcView, { ...props });
|
|
1929
2096
|
}
|
|
1930
2097
|
|
|
2098
|
+
// src/frame/call-controls.ts
|
|
2099
|
+
import { createContext as createContext4 } from "react";
|
|
2100
|
+
var LandscapeControlsContext = createContext4(false);
|
|
2101
|
+
|
|
1931
2102
|
// src/primitives/NameTag.tsx
|
|
1932
2103
|
import { memo as memo7 } from "react";
|
|
1933
2104
|
import { StyleSheet as StyleSheet13, View as View13 } from "react-native";
|
|
1934
2105
|
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1935
|
-
var NameTag = memo7(function NameTag2({ name, muted = false, pinned = false, icon, you = false, handRaised = false, handOrder, testID }) {
|
|
2106
|
+
var NameTag = memo7(function NameTag2({ name, muted = false, pinned = false, following = false, icon, you = false, handRaised = false, handOrder, testID }) {
|
|
1936
2107
|
const tagRef = useMeasuredRef(testID, styles13.tag);
|
|
1937
2108
|
return /* @__PURE__ */ jsx22(View13, { pointerEvents: "none", style: styles13.slot, children: /* @__PURE__ */ jsxs14(View13, { ref: tagRef, style: styles13.tag, testID, children: [
|
|
1938
2109
|
pinned ? /* @__PURE__ */ jsx22(Icon, { color: fixed.overlayText, name: "pin", size: 14 }) : null,
|
|
1939
2110
|
icon ? /* @__PURE__ */ jsx22(Icon, { color: fixed.overlayText, name: icon, size: 14 }) : null,
|
|
1940
2111
|
/* @__PURE__ */ jsx22(ChalkText, { color: fixed.overlayText, numberOfLines: 1, style: styles13.name, variant: "label", children: name }),
|
|
2112
|
+
following ? /* @__PURE__ */ jsx22(ChalkText, { color: fixed.overlayText, variant: "label", children: "following" }) : null,
|
|
1941
2113
|
you ? /* @__PURE__ */ jsx22(ChalkText, { color: fixed.overlayText, style: styles13.you, variant: "label", children: "(You)" }) : null,
|
|
1942
2114
|
muted ? /* @__PURE__ */ jsx22(Icon, { color: fixed.overlayDanger, name: "micOff", size: 14 }) : null,
|
|
1943
2115
|
handRaised ? /* @__PURE__ */ jsxs14(View13, { style: styles13.hand, children: [
|
|
@@ -2006,30 +2178,72 @@ function ScreenShare({ sharerId, inner, mini, onShowInSpotlight }) {
|
|
|
2006
2178
|
] });
|
|
2007
2179
|
}
|
|
2008
2180
|
var selectBoard = (snapshot) => snapshot.whiteboard.engine.status;
|
|
2181
|
+
var selectRoster = (snapshot) => snapshot.participants.roster;
|
|
2182
|
+
var selectSelfId = (snapshot) => snapshot.self.participantId;
|
|
2183
|
+
var selectConnection = (snapshot) => snapshot.connection.status;
|
|
2184
|
+
var selectAccess = (snapshot) => snapshot.whiteboard.access;
|
|
2185
|
+
var selectCanManage = (snapshot) => snapshot.self.can("manageWhiteboard");
|
|
2186
|
+
var selectSceneId = (snapshot) => snapshot.whiteboard.engine.sceneId;
|
|
2009
2187
|
function Board({ mini, onShowInSpotlight }) {
|
|
2010
2188
|
const client = useSpaceClient();
|
|
2011
2189
|
const { colors, scheme } = useTheme();
|
|
2190
|
+
const view = useStageView();
|
|
2191
|
+
const { width, height } = useDeviceLayout();
|
|
2192
|
+
const landscapeControlsVisible = useContext4(LandscapeControlsContext);
|
|
2193
|
+
const phone = Math.min(width, height) < 600;
|
|
2012
2194
|
const status = useSpaceSelector(selectBoard);
|
|
2013
|
-
const
|
|
2014
|
-
const
|
|
2195
|
+
const roster = useSpaceSelector(selectRoster);
|
|
2196
|
+
const selfId = useSpaceSelector(selectSelfId);
|
|
2197
|
+
const connectionStatus = useSpaceSelector(selectConnection);
|
|
2198
|
+
const sceneId = useSpaceSelector(selectSceneId);
|
|
2199
|
+
const access = useSpaceSelector(selectAccess);
|
|
2200
|
+
const canManage = useSpaceSelector(selectCanManage);
|
|
2201
|
+
const toasts = useToasts();
|
|
2015
2202
|
const transport = useMemo8(() => client.whiteboard.transport(), [client, status]);
|
|
2203
|
+
const [capabilities, setCapabilities] = useState12({ canDraw: false, canClear: false, viewsAvailable: false });
|
|
2204
|
+
useEffect13(() => transport?.subscribeSummary?.((summary) => setCapabilities({ canDraw: summary.canDraw, canClear: summary.canClear, viewsAvailable: transport.supportsViews === true })), [transport]);
|
|
2205
|
+
const board = useMemo8(
|
|
2206
|
+
() => ({
|
|
2207
|
+
primary: !mini,
|
|
2208
|
+
phone,
|
|
2209
|
+
landscapeControlsVisible,
|
|
2210
|
+
following: view.following,
|
|
2211
|
+
ownParticipantId: selfId,
|
|
2212
|
+
people: roster.map((person) => ({ id: person.participantId, displayName: person.displayName })),
|
|
2213
|
+
viewBounds: ChalkWhiteboardViewBounds,
|
|
2214
|
+
sceneId,
|
|
2215
|
+
sceneStatus: status,
|
|
2216
|
+
connectionStatus,
|
|
2217
|
+
viewsAvailable: capabilities.viewsAvailable,
|
|
2218
|
+
...canManage && access.policy !== null && transport?.setDrawPolicy ? {
|
|
2219
|
+
whoCanDraw: {
|
|
2220
|
+
policy: access.policy,
|
|
2221
|
+
people: roster.filter((person) => person.participantId !== selfId && !person.capabilities.includes("manageWhiteboard")).map((person) => ({ id: person.participantId, name: person.displayName, picked: access.permissions.some((permission) => permission.participantId === person.participantId && permission.canDraw) }))
|
|
2222
|
+
}
|
|
2223
|
+
} : {},
|
|
2224
|
+
colors
|
|
2225
|
+
}),
|
|
2226
|
+
[mini, phone, landscapeControlsVisible, view.following, selfId, roster, sceneId, status, connectionStatus, capabilities.viewsAvailable, canManage, access, transport, colors]
|
|
2227
|
+
);
|
|
2228
|
+
const onClose = useCallback11(() => {
|
|
2229
|
+
void (async () => {
|
|
2230
|
+
if (canManage) await transport?.setPresentation?.(false);
|
|
2231
|
+
view.setBoardOpen(false);
|
|
2232
|
+
view.setFollowing(null);
|
|
2233
|
+
})().catch(() => toasts.show({ kind: "error", dismissible: true, message: "Couldn\u2019t close the board. Try again." }));
|
|
2234
|
+
}, [canManage, transport, toasts, view.setBoardOpen, view.setFollowing]);
|
|
2016
2235
|
const journeyId = useRef10(`board-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`).current;
|
|
2017
2236
|
return /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
2018
|
-
transport ? /* @__PURE__ */ jsx23(EmbeddedWhiteboard, { canClear:
|
|
2237
|
+
transport ? /* @__PURE__ */ jsx23(EmbeddedWhiteboard, { board, canClear: capabilities.canClear, canDraw: !mini && capabilities.canDraw, journeyId, onCloseBoard: onClose, onFollow: view.setFollowing, style: StyleSheet14.absoluteFill, testID: "tile.content.board", theme: scheme, transport }) : null,
|
|
2019
2238
|
mini ? /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
2020
2239
|
/* @__PURE__ */ jsx23(Pressable11, { accessibilityLabel: "Show the board in spotlight", accessibilityRole: "button", onPress: onShowInSpotlight, style: StyleSheet14.absoluteFill, testID: "tile.content.open" }),
|
|
2021
2240
|
/* @__PURE__ */ jsx23(NameTag, { icon: "pen", name: "Board", testID: "tile.content.name" })
|
|
2022
|
-
] }) :
|
|
2023
|
-
/* @__PURE__ */ jsx23(Icon, { color: colors.textMuted, name: "lock", size: 16 }),
|
|
2024
|
-
/* @__PURE__ */ jsx23(ChalkText, { tone: "textSoft", variant: "section", children: "View only" })
|
|
2025
|
-
] })
|
|
2241
|
+
] }) : null
|
|
2026
2242
|
] });
|
|
2027
2243
|
}
|
|
2028
2244
|
var styles14 = StyleSheet14.create({
|
|
2029
2245
|
tile: { flex: 1, overflow: "hidden", borderRadius: radii.tilePhone },
|
|
2030
|
-
box: { position: "absolute", overflow: "hidden" }
|
|
2031
|
-
// `.vchip`: a 30 pt pill 12 pt in from the board's top-left corner, with a one-pixel ring.
|
|
2032
|
-
viewOnly: { position: "absolute", left: 12, top: 12, height: 30, paddingHorizontal: 12, borderRadius: radii.round, borderWidth: 1, flexDirection: "row", alignItems: "center", gap: 6, zIndex: 3 }
|
|
2246
|
+
box: { position: "absolute", overflow: "hidden" }
|
|
2033
2247
|
});
|
|
2034
2248
|
|
|
2035
2249
|
// src/stage/layout.ts
|
|
@@ -2198,7 +2412,7 @@ function nextStageOrder(previous, present, selfId, speaker) {
|
|
|
2198
2412
|
}
|
|
2199
2413
|
|
|
2200
2414
|
// src/stage/ParticipantTile.tsx
|
|
2201
|
-
import { memo as memo10, useCallback as
|
|
2415
|
+
import { memo as memo10, useCallback as useCallback12, useEffect as useEffect15, useMemo as useMemo9 } from "react";
|
|
2202
2416
|
import { Pressable as Pressable12, StyleSheet as StyleSheet16, View as View16 } from "react-native";
|
|
2203
2417
|
import { useSharedValue as useSharedValue3, withTiming as withTiming5 } from "react-native-reanimated";
|
|
2204
2418
|
|
|
@@ -2208,17 +2422,17 @@ function tileAvatarSize(width, height) {
|
|
|
2208
2422
|
}
|
|
2209
2423
|
|
|
2210
2424
|
// src/primitives/TileShell.tsx
|
|
2211
|
-
import { memo as memo9, useEffect as
|
|
2425
|
+
import { memo as memo9, useEffect as useEffect14 } from "react";
|
|
2212
2426
|
import { StyleSheet as StyleSheet15, View as View15 } from "react-native";
|
|
2213
2427
|
import Animated8, { useAnimatedStyle as useAnimatedStyle4, useSharedValue as useSharedValue2, withTiming as withTiming4 } from "react-native-reanimated";
|
|
2214
2428
|
import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2215
|
-
var TileShell = memo9(function TileShell2({ children, speaking = false, cameraOn = false, level, testID }) {
|
|
2429
|
+
var TileShell = memo9(function TileShell2({ children, selected = false, speaking = false, cameraOn = false, level, testID }) {
|
|
2216
2430
|
const { colors } = useTheme();
|
|
2217
2431
|
const { phone } = useDeviceLayout();
|
|
2218
2432
|
const radius = phone ? radii.tilePhone : radii.tile;
|
|
2219
2433
|
const live = useSharedValue2(0);
|
|
2220
2434
|
const showRing = speaking && cameraOn;
|
|
2221
|
-
|
|
2435
|
+
useEffect14(() => {
|
|
2222
2436
|
live.value = withTiming4(showRing ? 1 : 0, timings.scrim);
|
|
2223
2437
|
}, [live, showRing]);
|
|
2224
2438
|
const ringStyle = useAnimatedStyle4(() => {
|
|
@@ -2227,6 +2441,7 @@ var TileShell = memo9(function TileShell2({ children, speaking = false, cameraOn
|
|
|
2227
2441
|
});
|
|
2228
2442
|
return /* @__PURE__ */ jsxs16(View15, { style: [styles15.tile, { borderRadius: radius, backgroundColor: colors.tile }], testID, children: [
|
|
2229
2443
|
children,
|
|
2444
|
+
selected ? /* @__PURE__ */ jsx24(View15, { pointerEvents: "none", style: [StyleSheet15.absoluteFill, { borderRadius: radius, borderWidth: 2, borderColor: colors.text, zIndex: 6 }] }) : null,
|
|
2230
2445
|
/* @__PURE__ */ jsx24(Animated8.View, { pointerEvents: "none", style: [styles15.ring, { borderRadius: radius }, ringStyle], testID: testID ? `${testID}.ring` : void 0, children: /* @__PURE__ */ jsx24(View15, { style: [styles15.ringShade, { borderRadius: radius - 3 }] }) })
|
|
2231
2446
|
] });
|
|
2232
2447
|
});
|
|
@@ -2270,12 +2485,12 @@ function selectTile(id) {
|
|
|
2270
2485
|
};
|
|
2271
2486
|
};
|
|
2272
2487
|
}
|
|
2273
|
-
var ParticipantTile = memo10(function ParticipantTile2({ id, width, height, float, pinned, mirror, onOpen }) {
|
|
2488
|
+
var ParticipantTile = memo10(function ParticipantTile2({ id, width, height, float, pinned, following = false, mirror, onOpen, onOptions }) {
|
|
2274
2489
|
const select = useMemo9(() => selectTile(id), [id]);
|
|
2275
2490
|
const tile = useSpaceSelector(select, shallowEqual);
|
|
2276
2491
|
const slot = useDevScenario().videoSlots?.[id];
|
|
2277
2492
|
const level = useSharedValue3(0);
|
|
2278
|
-
|
|
2493
|
+
useEffect15(() => {
|
|
2279
2494
|
level.value = withTiming5(tile.speaking ? 0.6 : 0, timings.level);
|
|
2280
2495
|
}, [level, tile.speaking]);
|
|
2281
2496
|
const streamURL = useMemo9(() => tile.track ? createNativeMediaStream(tile.track).toURL() : null, [tile.track]);
|
|
@@ -2286,10 +2501,10 @@ var ParticipantTile = memo10(function ParticipantTile2({ id, width, height, floa
|
|
|
2286
2501
|
const state = `${tile.muted ? ", microphone off" : ""}${tile.handRaised ? ", hand raised" : ""}`;
|
|
2287
2502
|
const hitRef = useMeasuredRef(`tile.${id}.open`, StyleSheet16.absoluteFill);
|
|
2288
2503
|
const label = `Options for ${tile.name}${tile.isSelf ? " (you)" : ""}${pinned ? ", pinned" : ""}${state}`;
|
|
2289
|
-
return /* @__PURE__ */ jsxs17(TileShell, { cameraOn: video !== null, level, speaking: tile.speaking, testID: `tile.${id}`, children: [
|
|
2504
|
+
return /* @__PURE__ */ jsxs17(TileShell, { selected: following, cameraOn: video !== null, level, speaking: tile.speaking, testID: `tile.${id}`, children: [
|
|
2290
2505
|
video ?? /* @__PURE__ */ jsx25(View16, { style: styles16.center, children: /* @__PURE__ */ jsx25(FaceAvatar, { level, lookAround: true, name: tile.name, size: tileAvatarSize(width, height - nameTagZone), style: "bold" }) }),
|
|
2291
|
-
/* @__PURE__ */ jsx25(Pressable12, { accessibilityHint: "Opens a sheet", accessibilityLabel: label, accessibilityRole: "button", onPress: () => onOpen(id), ref: hitRef, style: StyleSheet16.absoluteFill, testID: `tile.${id}.open` }),
|
|
2292
|
-
/* @__PURE__ */ jsx25(NameTag, { handRaised: tile.handRaised, muted: tile.muted, name, pinned, testID: `tile.${id}.name`, you }),
|
|
2506
|
+
/* @__PURE__ */ jsx25(Pressable12, { accessibilityHint: "Opens a sheet", accessibilityLabel: label, accessibilityRole: "button", onPress: () => onOpen(id), onLongPress: () => onOptions?.(id), ref: hitRef, style: StyleSheet16.absoluteFill, testID: `tile.${id}.open` }),
|
|
2507
|
+
/* @__PURE__ */ jsx25(NameTag, { following, handRaised: tile.handRaised, muted: tile.muted, name, pinned, testID: `tile.${id}.name`, you }),
|
|
2293
2508
|
tile.isSelf && video !== null ? /* @__PURE__ */ jsx25(FlipCameraButton, { back: tile.back, float, testID: `tile.${id}.flip` }) : null
|
|
2294
2509
|
] });
|
|
2295
2510
|
});
|
|
@@ -2303,7 +2518,7 @@ function FlipCameraButton({ back, float, testID }) {
|
|
|
2303
2518
|
const client = useSpaceClient();
|
|
2304
2519
|
const toasts = useToasts();
|
|
2305
2520
|
const other = useSpaceSelector(selectOtherCamera);
|
|
2306
|
-
const flip =
|
|
2521
|
+
const flip = useCallback12(() => {
|
|
2307
2522
|
if (other === null) return;
|
|
2308
2523
|
client.media.selectCamera(other).catch(() => toasts.show({ kind: "error", dismissible: true, message: "Couldn't switch the camera." }));
|
|
2309
2524
|
}, [client, other, toasts]);
|
|
@@ -2321,10 +2536,10 @@ var styles16 = StyleSheet16.create({
|
|
|
2321
2536
|
});
|
|
2322
2537
|
|
|
2323
2538
|
// src/stage/TileSheet.tsx
|
|
2324
|
-
import { useCallback as
|
|
2539
|
+
import { useCallback as useCallback13, useMemo as useMemo10 } from "react";
|
|
2325
2540
|
import { StyleSheet as StyleSheet17, View as View17 } from "react-native";
|
|
2326
2541
|
import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2327
|
-
var closed = { name: "", isSelf: false, cameraOn: false, back: false, otherCamera: null, muted: false, canMute: false, canRemove: false };
|
|
2542
|
+
var closed = { boardOpen: false, name: "", isSelf: false, cameraOn: false, back: false, otherCamera: null, muted: false, canMute: false, canRemove: false };
|
|
2328
2543
|
function TileSheet({ participantId, open, onClose }) {
|
|
2329
2544
|
const client = useSpaceClient();
|
|
2330
2545
|
const toasts = useToasts();
|
|
@@ -2335,6 +2550,7 @@ function TileSheet({ participantId, open, onClose }) {
|
|
|
2335
2550
|
const person2 = snapshot.participants.roster.find((participant) => participant.participantId === participantId);
|
|
2336
2551
|
const isSelf = snapshot.self.participantId === participantId;
|
|
2337
2552
|
return {
|
|
2553
|
+
boardOpen: snapshot.whiteboard.engine.presenting,
|
|
2338
2554
|
name: person2?.displayName ?? snapshot.self.displayName ?? "",
|
|
2339
2555
|
isSelf,
|
|
2340
2556
|
cameraOn: isSelf && snapshot.media.local.camera.state === "enabled",
|
|
@@ -2348,8 +2564,10 @@ function TileSheet({ participantId, open, onClose }) {
|
|
|
2348
2564
|
[participantId]
|
|
2349
2565
|
);
|
|
2350
2566
|
const person = useSpaceSelector(select, shallowEqual);
|
|
2567
|
+
const selectViewsAvailable = useCallback13(() => client.whiteboard.transport()?.supportsViews === true, [client]);
|
|
2568
|
+
const viewsAvailable = useSpaceSelector(selectViewsAvailable);
|
|
2351
2569
|
const id = participantId ?? "";
|
|
2352
|
-
const failed =
|
|
2570
|
+
const failed = useCallback13((message2) => () => toasts.show({ kind: "error", dismissible: true, message: message2 }), [toasts]);
|
|
2353
2571
|
const run = (action) => () => {
|
|
2354
2572
|
onClose();
|
|
2355
2573
|
action();
|
|
@@ -2360,6 +2578,18 @@ function TileSheet({ participantId, open, onClose }) {
|
|
|
2360
2578
|
/* @__PURE__ */ jsx26(ChalkText, { numberOfLines: 1, style: styles17.name, variant: "sheetTitle", children: `${person.name}${person.isSelf ? " (You)" : ""}` })
|
|
2361
2579
|
] }),
|
|
2362
2580
|
/* @__PURE__ */ jsxs18(SheetGroup, { children: [
|
|
2581
|
+
(view.boardOpen ?? person.boardOpen) && viewsAvailable && !person.isSelf ? /* @__PURE__ */ jsx26(
|
|
2582
|
+
SheetRow,
|
|
2583
|
+
{
|
|
2584
|
+
icon: "pin",
|
|
2585
|
+
label: view.following === participantId ? "Stop following" : "Follow",
|
|
2586
|
+
onPress: run(() => {
|
|
2587
|
+
view.showContent();
|
|
2588
|
+
view.setFollowing(view.following === participantId ? null : id);
|
|
2589
|
+
}),
|
|
2590
|
+
testID: "tile-sheet.follow"
|
|
2591
|
+
}
|
|
2592
|
+
) : null,
|
|
2363
2593
|
/* @__PURE__ */ jsx26(SheetRow, { icon: "pin", label: view.pinned === participantId ? "Unpin" : "Pin", onPress: run(() => view.togglePin(id)), testID: "tile-sheet.pin" }),
|
|
2364
2594
|
person.cameraOn && person.otherCamera !== null ? /* @__PURE__ */ jsx26(
|
|
2365
2595
|
SheetRow,
|
|
@@ -2411,20 +2641,33 @@ function selectStructure(snapshot) {
|
|
|
2411
2641
|
present: (hasSelf && selfId !== null ? [selfId, ...others] : others).join("\n"),
|
|
2412
2642
|
speaker: roster.find((person) => person.presence.activeSpeaker)?.participantId ?? null,
|
|
2413
2643
|
sharer: roster.find((person) => person.participantId !== selfId && person.media.screenShare === "active")?.participantId ?? null,
|
|
2414
|
-
board: snapshot.whiteboard.
|
|
2644
|
+
board: snapshot.whiteboard.engine.presenting
|
|
2415
2645
|
};
|
|
2416
2646
|
}
|
|
2417
2647
|
var Stage = memo11(function Stage2({ frame, onOpenPeople }) {
|
|
2648
|
+
const client = useSpaceClient();
|
|
2649
|
+
const toasts = useToasts();
|
|
2650
|
+
useEffect16(() => ownNativeBoardSession(client, () => toasts.show({ kind: "error", dismissible: true, message: "Couldn\u2019t open the board. Try again from More." })), [client, toasts]);
|
|
2418
2651
|
const structure = useSpaceSelector(selectStructure, shallowEqual);
|
|
2652
|
+
const selectViewsAvailable = useCallback14(() => client.whiteboard.transport()?.supportsViews === true, [client]);
|
|
2653
|
+
const viewsAvailable = useSpaceSelector(selectViewsAvailable);
|
|
2419
2654
|
const view = useStageView();
|
|
2420
2655
|
const { arrangement } = useDeviceLayout();
|
|
2421
2656
|
const { shareAspect } = useDevScenario();
|
|
2422
|
-
const [sheet, setSheet] =
|
|
2657
|
+
const [sheet, setSheet] = useState13({ id: null, open: false });
|
|
2658
|
+
useEffect16(() => {
|
|
2659
|
+
if (view.following && !structure.present.split("\n").includes(view.following)) view.setFollowing(null);
|
|
2660
|
+
}, [structure.present, view.following, view.setFollowing]);
|
|
2423
2661
|
const present = useMemo11(() => structure.present ? structure.present.split("\n") : [], [structure.present]);
|
|
2424
|
-
const [order, setOrder] =
|
|
2662
|
+
const [order, setOrder] = useState13({ order: [], spot: null });
|
|
2425
2663
|
const next = nextStageOrder(order, present, structure.selfId, structure.speaker);
|
|
2426
2664
|
if (next !== order) setOrder(next);
|
|
2427
|
-
|
|
2665
|
+
useEffect16(() => {
|
|
2666
|
+
view.setBoardOpen(null);
|
|
2667
|
+
view.setFollowing(null);
|
|
2668
|
+
}, [structure.board, view.setBoardOpen, view.setFollowing]);
|
|
2669
|
+
const boardVisible = view.boardOpen ?? structure.board;
|
|
2670
|
+
const content = useMemo11(() => boardVisible ? { kind: "board" } : structure.sharer !== null ? { kind: "screen", sharerId: structure.sharer } : null, [boardVisible, structure.sharer]);
|
|
2428
2671
|
const pinned = view.pinned !== null && present.includes(view.pinned) ? view.pinned : null;
|
|
2429
2672
|
const items = useMemo11(
|
|
2430
2673
|
() => stageLayout({
|
|
@@ -2439,21 +2682,32 @@ var Stage = memo11(function Stage2({ frame, onOpenPeople }) {
|
|
|
2439
2682
|
}),
|
|
2440
2683
|
[arrangement, content, frame, next, pinned, shareAspect, view.layout]
|
|
2441
2684
|
);
|
|
2442
|
-
const
|
|
2443
|
-
|
|
2685
|
+
const followTile = useCallback14(
|
|
2686
|
+
(id) => {
|
|
2687
|
+
if (!boardVisible || !viewsAvailable || id === structure.selfId) {
|
|
2688
|
+
setSheet({ id, open: true });
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2691
|
+
view.showContent();
|
|
2692
|
+
view.setFollowing(view.following === id ? null : id);
|
|
2693
|
+
},
|
|
2694
|
+
[boardVisible, viewsAvailable, structure.selfId, view]
|
|
2695
|
+
);
|
|
2696
|
+
const openTile = useCallback14((id) => setSheet({ id, open: true }), []);
|
|
2697
|
+
const closeTile = useCallback14(() => setSheet((current) => ({ ...current, open: false })), []);
|
|
2444
2698
|
const stageRef = useMeasuredRef("frame.stage", styles18.layer);
|
|
2445
2699
|
return /* @__PURE__ */ jsxs19(View18, { pointerEvents: "box-none", ref: stageRef, style: styles18.layer, testID: "frame.stage", children: [
|
|
2446
|
-
items.map((item) => /* @__PURE__ */ jsx27(StageTile, { content, item, mirror: view.mirror, onOpenPeople, onOpenTile: openTile, onShowContent: view.showContent, peopleCount: present.length, pinned }, itemKey(item))),
|
|
2700
|
+
items.map((item) => /* @__PURE__ */ jsx27(StageTile, { content, item, mirror: view.mirror, onOpenPeople, onOpenTile: followTile, onTileOptions: openTile, following: view.following, onShowContent: view.showContent, peopleCount: present.length, pinned }, itemKey(item))),
|
|
2447
2701
|
/* @__PURE__ */ jsx27(TileSheet, { onClose: closeTile, open: sheet.open, participantId: sheet.id })
|
|
2448
2702
|
] });
|
|
2449
2703
|
});
|
|
2450
2704
|
function itemKey(item) {
|
|
2451
2705
|
return item.kind === "person" ? `person:${item.id}` : item.kind;
|
|
2452
2706
|
}
|
|
2453
|
-
function StageTile({ item, content, pinned, mirror, peopleCount, onOpenTile, onOpenPeople, onShowContent }) {
|
|
2707
|
+
function StageTile({ item, content, pinned, mirror, peopleCount, onOpenTile, onOpenPeople, onShowContent, following, onTileOptions }) {
|
|
2454
2708
|
const { scheme } = useTheme();
|
|
2455
2709
|
const float = item.kind === "person" && item.float;
|
|
2456
|
-
return /* @__PURE__ */ jsx27(MovingFrame, { frame: item.frame, style: float ? [styles18.float, { boxShadow: elevations[scheme].floatTile }] : null, children: /* @__PURE__ */ jsx27(Animated9.View, { entering: tileEntering, exiting: tileLeaving, style: styles18.fill, children: item.kind === "person" ? /* @__PURE__ */ jsx27(ParticipantTile, { float, height: item.frame.height, id: item.id, mirror, onOpen: onOpenTile, pinned: pinned === item.id, width: item.frame.width }) : item.kind === "content" && content ? /* @__PURE__ */ jsx27(ContentTile, { content, inner: item.inner, mini: item.mini, onShowInSpotlight: onShowContent }) : item.kind === "more" ? /* @__PURE__ */ jsx27(MoreTile, { count: item.count, onPress: onOpenPeople, peopleCount }) : null }) });
|
|
2710
|
+
return /* @__PURE__ */ jsx27(MovingFrame, { frame: item.frame, style: float ? [styles18.float, { boxShadow: elevations[scheme].floatTile }] : null, children: /* @__PURE__ */ jsx27(Animated9.View, { entering: tileEntering, exiting: tileLeaving, style: styles18.fill, children: item.kind === "person" ? /* @__PURE__ */ jsx27(ParticipantTile, { float, height: item.frame.height, id: item.id, mirror, onOpen: onOpenTile, onOptions: onTileOptions, following: following === item.id, pinned: pinned === item.id, width: item.frame.width }) : item.kind === "content" && content ? /* @__PURE__ */ jsx27(ContentTile, { content, inner: item.inner, mini: item.mini, onShowInSpotlight: onShowContent }) : item.kind === "more" ? /* @__PURE__ */ jsx27(MoreTile, { count: item.count, onPress: onOpenPeople, peopleCount }) : null }) });
|
|
2457
2711
|
}
|
|
2458
2712
|
var MoreTile = memo11(function MoreTile2({ count, peopleCount, onPress }) {
|
|
2459
2713
|
const { colors } = useTheme();
|
|
@@ -2469,12 +2723,33 @@ var styles18 = StyleSheet18.create({
|
|
|
2469
2723
|
moreText: { fontFamily: fontFamilies[600], fontSize: 22, lineHeight: 22 * 1.4 }
|
|
2470
2724
|
});
|
|
2471
2725
|
|
|
2726
|
+
// src/frame/use-landscape-chrome.ts
|
|
2727
|
+
import { useCallback as useCallback15, useEffect as useEffect17, useState as useState14 } from "react";
|
|
2728
|
+
function useLandscapeChrome({ fades, boardVisible }) {
|
|
2729
|
+
const canHide = fades && !boardVisible;
|
|
2730
|
+
const [hidden, setHidden] = useState14(false);
|
|
2731
|
+
const [shownAt, setShownAt] = useState14(0);
|
|
2732
|
+
useEffect17(() => {
|
|
2733
|
+
if (!canHide) {
|
|
2734
|
+
setHidden(false);
|
|
2735
|
+
return;
|
|
2736
|
+
}
|
|
2737
|
+
const timer = setTimeout(() => setHidden(true), durations.landscapeHide);
|
|
2738
|
+
return () => clearTimeout(timer);
|
|
2739
|
+
}, [canHide, shownAt]);
|
|
2740
|
+
const show = useCallback15(() => {
|
|
2741
|
+
setHidden(false);
|
|
2742
|
+
setShownAt(Date.now());
|
|
2743
|
+
}, []);
|
|
2744
|
+
return { hidden: canHide && hidden, show };
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2472
2747
|
// src/status/CallOverlays.tsx
|
|
2473
|
-
import { useEffect as
|
|
2748
|
+
import { useEffect as useEffect20 } from "react";
|
|
2474
2749
|
import { StyleSheet as StyleSheet21, View as View20 } from "react-native";
|
|
2475
2750
|
|
|
2476
2751
|
// src/limbo/Veil.tsx
|
|
2477
|
-
import { useEffect as
|
|
2752
|
+
import { useEffect as useEffect18 } from "react";
|
|
2478
2753
|
import { StyleSheet as StyleSheet19 } from "react-native";
|
|
2479
2754
|
import Animated10, { ReduceMotion as ReduceMotion2, useAnimatedStyle as useAnimatedStyle5, useSharedValue as useSharedValue4, withTiming as withTiming6 } from "react-native-reanimated";
|
|
2480
2755
|
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
@@ -2483,7 +2758,7 @@ var LIFT_FROM = 0.6;
|
|
|
2483
2758
|
function Veil({ level }) {
|
|
2484
2759
|
const { colors } = useTheme();
|
|
2485
2760
|
const opacity = useSharedValue4(OPACITY[level]);
|
|
2486
|
-
|
|
2761
|
+
useEffect18(() => {
|
|
2487
2762
|
if (level !== "none") {
|
|
2488
2763
|
opacity.value = OPACITY[level];
|
|
2489
2764
|
return;
|
|
@@ -2500,7 +2775,8 @@ function Veil({ level }) {
|
|
|
2500
2775
|
}
|
|
2501
2776
|
|
|
2502
2777
|
// src/status/StatusPage.tsx
|
|
2503
|
-
import { forwardRef as forwardRef3, memo as memo12, useEffect as
|
|
2778
|
+
import { forwardRef as forwardRef3, memo as memo12, useEffect as useEffect19, useRef as useRef11 } from "react";
|
|
2779
|
+
import { formatSyncConnectDiagnostic, getConnectionFailureDetail } from "@q9labsai/chalk-client";
|
|
2504
2780
|
import { AccessibilityInfo as AccessibilityInfo2, findNodeHandle as findNodeHandle2, Pressable as Pressable14, StyleSheet as StyleSheet20, View as View19 } from "react-native";
|
|
2505
2781
|
import Animated11, { useAnimatedStyle as useAnimatedStyle6 } from "react-native-reanimated";
|
|
2506
2782
|
import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
@@ -2511,7 +2787,7 @@ function pageFor(outcome, callName) {
|
|
|
2511
2787
|
case "ended":
|
|
2512
2788
|
return { title: "The call ended", actions: ["rejoin", "home"] };
|
|
2513
2789
|
case "failed":
|
|
2514
|
-
return { title: `Couldn\u2019t connect to ${callName}`,
|
|
2790
|
+
return { title: `Couldn\u2019t connect to ${callName}`, actions: ["rejoin", "home"], rejoinLabel: "Try again" };
|
|
2515
2791
|
case "removed":
|
|
2516
2792
|
return { title: `You were removed from ${callName}`, detail: "The host removed you from this call.", actions: ["home"] };
|
|
2517
2793
|
case "exited":
|
|
@@ -2520,19 +2796,21 @@ function pageFor(outcome, callName) {
|
|
|
2520
2796
|
return { title: "This call is full", detail: `${callName} has reached 100 people. Ask the host to make room, then try again.`, actions: ["rejoin", "home"], rejoinLabel: "Try again" };
|
|
2521
2797
|
}
|
|
2522
2798
|
}
|
|
2523
|
-
function StatusPage({ outcome, callName, onRejoin, onHome }) {
|
|
2799
|
+
function StatusPage({ outcome, callName, failure, onRejoin, onHome }) {
|
|
2524
2800
|
const { colors } = useTheme();
|
|
2525
2801
|
const page = pageFor(outcome, callName);
|
|
2802
|
+
const detail = outcome === "failed" ? getConnectionFailureDetail({ code: failure?.code, sync: failure?.sync }) : page.detail;
|
|
2526
2803
|
const pageStyle = [styles19.page, { backgroundColor: colors.canvas }];
|
|
2527
2804
|
const ref = useMeasuredRef("status.page", pageStyle);
|
|
2528
2805
|
const firstAction = useRef11(null);
|
|
2529
|
-
|
|
2806
|
+
useEffect19(() => {
|
|
2530
2807
|
const node = firstAction.current && findNodeHandle2(firstAction.current);
|
|
2531
2808
|
if (node) AccessibilityInfo2.setAccessibilityFocus(node);
|
|
2532
2809
|
}, [outcome]);
|
|
2533
2810
|
return /* @__PURE__ */ jsxs20(View19, { accessibilityViewIsModal: true, ref, style: pageStyle, testID: "status.page", children: [
|
|
2534
2811
|
/* @__PURE__ */ jsx29(ChalkText, { accessibilityRole: "header", style: styles19.center, testID: "status.title", variant: "statusTitle", children: page.title }),
|
|
2535
|
-
|
|
2812
|
+
detail ? /* @__PURE__ */ jsx29(ChalkText, { style: styles19.center, testID: "status.detail", tone: "textMuted", children: detail }) : null,
|
|
2813
|
+
outcome === "failed" && failure ? /* @__PURE__ */ jsx29(ChalkText, { style: styles19.center, testID: "status.reference", tone: "textMuted", variant: "caption", children: `Reference: ${failure.code}${failure.sync ? ` ${formatSyncConnectDiagnostic(failure.sync)}` : ""}` }) : null,
|
|
2536
2814
|
/* @__PURE__ */ jsx29(View19, { style: styles19.actions, children: page.actions.map(
|
|
2537
2815
|
(action, index) => action === "rejoin" ? /* @__PURE__ */ jsx29(StatusAction, { icon: "retry", label: page.rejoinLabel ?? "Rejoin", onPress: onRejoin, ref: index === 0 ? firstAction : void 0, testID: "status.rejoin" }, action) : /* @__PURE__ */ jsx29(StatusAction, { icon: "home", label: "Home", onPress: onHome, ref: index === 0 ? firstAction : void 0, testID: "status.home" }, action)
|
|
2538
2816
|
) })
|
|
@@ -2579,7 +2857,7 @@ function CallOverlays({ screen, callName, rejoining, onHold, onRejoin, onHome })
|
|
|
2579
2857
|
useBackHandler(screen.kind === "status", onHome);
|
|
2580
2858
|
const { clear } = useToasts();
|
|
2581
2859
|
const clearsNotices = screen.kind === "status" || screen.kind === "joining";
|
|
2582
|
-
|
|
2860
|
+
useEffect20(() => {
|
|
2583
2861
|
if (clearsNotices) clear();
|
|
2584
2862
|
}, [clear, clearsNotices]);
|
|
2585
2863
|
const limbo = screen.kind === "joining" ? { kind: "joining", rejoining } : screen.kind === "call" && onHold ? { kind: "hold" } : null;
|
|
@@ -2588,7 +2866,7 @@ function CallOverlays({ screen, callName, rejoining, onHold, onRejoin, onHome })
|
|
|
2588
2866
|
/* @__PURE__ */ jsx30(Veil, { level: screen.kind === "status" ? "none" : veil }),
|
|
2589
2867
|
screen.kind === "reconnecting" || screen.kind === "call" && connection.syncHealth === "degraded" ? /* @__PURE__ */ jsx30(View20, { pointerEvents: "none", style: { position: "absolute", top: header.y + header.height + 4, left: layout.insets.left + 16, right: layout.insets.right + 16, alignItems: "center" }, testID: "connection.notice", children: /* @__PURE__ */ jsx30(ChalkText, { accessibilityLiveRegion: "polite", variant: "caption", style: { backgroundColor: colors.surface, borderRadius: 12, paddingHorizontal: 12, paddingVertical: 6 }, children: screen.kind === "reconnecting" ? `Reconnecting\u2026${queuedMessages ? ` ${queuedMessages} messages waiting to send.` : ""}` : "Connection is slow" }) }) : null,
|
|
2590
2868
|
limbo ? /* @__PURE__ */ jsx30(Limbo, { callName, recording: recording2, state: limbo }) : null,
|
|
2591
|
-
screen.kind === "status" ? /* @__PURE__ */ jsx30(StatusPage, { callName, onHome, onRejoin, outcome: screen.outcome }) : null
|
|
2869
|
+
screen.kind === "status" ? /* @__PURE__ */ jsx30(StatusPage, { callName, failure: connection.lastError, onHome, onRejoin, outcome: screen.outcome }) : null
|
|
2592
2870
|
] });
|
|
2593
2871
|
}
|
|
2594
2872
|
|
|
@@ -2630,7 +2908,7 @@ function callScreen(connection, leftByChoice) {
|
|
|
2630
2908
|
|
|
2631
2909
|
// src/toasts/CallEventToasts.tsx
|
|
2632
2910
|
import { SpaceClientError } from "@q9labsai/chalk-client";
|
|
2633
|
-
import { useCallback as
|
|
2911
|
+
import { useCallback as useCallback16, useEffect as useEffect21, useRef as useRef12 } from "react";
|
|
2634
2912
|
import { Linking as Linking2, Platform as Platform7 } from "react-native";
|
|
2635
2913
|
|
|
2636
2914
|
// src/toasts/media-failure-copy.ts
|
|
@@ -2688,7 +2966,7 @@ function useCallEventToasts({ onOpenSettings, resumedAfterSettings }) {
|
|
|
2688
2966
|
const ownMicrophoneChange = useRef12(false);
|
|
2689
2967
|
const latest = useRef12({ colors, soundsEnabled });
|
|
2690
2968
|
latest.current = { colors, soundsEnabled };
|
|
2691
|
-
|
|
2969
|
+
useEffect21(() => {
|
|
2692
2970
|
let previous = client.getSnapshot();
|
|
2693
2971
|
return client.subscribe(() => {
|
|
2694
2972
|
const next = client.getSnapshot();
|
|
@@ -2705,10 +2983,10 @@ function useCallEventToasts({ onOpenSettings, resumedAfterSettings }) {
|
|
|
2705
2983
|
});
|
|
2706
2984
|
}, [client, toasts]);
|
|
2707
2985
|
useResumedAfterSettings(resumedAfterSettings, toasts);
|
|
2708
|
-
const noteOwnMicrophoneChange =
|
|
2986
|
+
const noteOwnMicrophoneChange = useCallback16(() => {
|
|
2709
2987
|
ownMicrophoneChange.current = true;
|
|
2710
2988
|
}, []);
|
|
2711
|
-
const reportMediaFailure =
|
|
2989
|
+
const reportMediaFailure = useCallback16(
|
|
2712
2990
|
function reportMediaFailure2(permission, cause, retry) {
|
|
2713
2991
|
const code = cause instanceof SpaceClientError ? cause.code : null;
|
|
2714
2992
|
const icon = permission === "microphone" ? "micOff" : "camOff";
|
|
@@ -2773,7 +3051,7 @@ function useResumedAfterSettings(permission, toasts) {
|
|
|
2773
3051
|
const client = useSpaceClient();
|
|
2774
3052
|
const { colors } = useTheme();
|
|
2775
3053
|
const shown = useRef12(false);
|
|
2776
|
-
|
|
3054
|
+
useEffect21(() => {
|
|
2777
3055
|
if (!permission) return;
|
|
2778
3056
|
const check = () => {
|
|
2779
3057
|
if (shown.current || client.getSnapshot().connection.status !== "live") return;
|
|
@@ -2838,31 +3116,31 @@ function CallFrame({ displayName, callName = "Call", inviteLink, onLeave, onOpen
|
|
|
2838
3116
|
const { soundsEnabled } = usePreferences();
|
|
2839
3117
|
const toasts = useToasts();
|
|
2840
3118
|
const callEvents = useCallEventToasts({ onOpenSettings, resumedAfterSettings });
|
|
2841
|
-
const [leftByChoice, setLeftByChoice] =
|
|
2842
|
-
const [sheet, setSheet] =
|
|
3119
|
+
const [leftByChoice, setLeftByChoice] = useState15(false);
|
|
3120
|
+
const [sheet, setSheet] = useState15(null);
|
|
2843
3121
|
const moreRef = useRef13(null);
|
|
2844
3122
|
const leaveRef = useRef13(null);
|
|
2845
3123
|
const nameRef = useRef13(null);
|
|
2846
3124
|
const canEnd = useCan("endEpisode");
|
|
2847
|
-
const [leaveMenuOpen, setLeaveMenuOpen] =
|
|
3125
|
+
const [leaveMenuOpen, setLeaveMenuOpen] = useState15(false);
|
|
2848
3126
|
const sheetCount = usePortalCount("sheets");
|
|
2849
3127
|
const menuCount = usePortalCount("menus");
|
|
2850
3128
|
const layered = sheetCount > 0 || menuCount > 0;
|
|
2851
3129
|
const regions = useMemo12(() => frameRegions(layout.arrangement, layout.width, layout.height, layout.insets), [layout]);
|
|
2852
3130
|
const screenStyle = [styles21.root, { backgroundColor: colors.canvas }];
|
|
2853
3131
|
const screenRef = useMeasuredRef("frame.screen", screenStyle);
|
|
2854
|
-
const join2 =
|
|
3132
|
+
const join2 = useCallback17(() => {
|
|
2855
3133
|
setLeftByChoice(false);
|
|
2856
3134
|
client.join({ displayName, microphone: false, camera: false }).catch(() => void 0);
|
|
2857
3135
|
}, [client, displayName]);
|
|
2858
|
-
|
|
3136
|
+
useEffect22(() => {
|
|
2859
3137
|
if (client.getSnapshot().connection.status === "idle") join2();
|
|
2860
3138
|
}, [client, join2]);
|
|
2861
3139
|
useAndroidCallService();
|
|
2862
3140
|
const microphoneOn = media.local.microphone.state === "enabled";
|
|
2863
3141
|
const cameraOn = media.local.camera.state === "enabled";
|
|
2864
3142
|
const { noteOwnMicrophoneChange, reportMediaFailure } = callEvents;
|
|
2865
|
-
const toggleMicrophone =
|
|
3143
|
+
const toggleMicrophone = useCallback17(() => {
|
|
2866
3144
|
haptics.mute();
|
|
2867
3145
|
playSound(microphoneOn ? "mute" : "unmute", soundsEnabled);
|
|
2868
3146
|
if (microphoneOn) noteOwnMicrophoneChange();
|
|
@@ -2870,12 +3148,12 @@ function CallFrame({ displayName, callName = "Call", inviteLink, onLeave, onOpen
|
|
|
2870
3148
|
if (microphoneOn) client.media.setMicrophoneEnabled(false).catch(() => toasts.show({ kind: "error", dismissible: true, message: "Couldn\u2019t mute your microphone." }));
|
|
2871
3149
|
else void turnOn().catch((cause) => reportMediaFailure("microphone", cause, turnOn));
|
|
2872
3150
|
}, [client, microphoneOn, noteOwnMicrophoneChange, reportMediaFailure, soundsEnabled, toasts]);
|
|
2873
|
-
const toggleCamera =
|
|
3151
|
+
const toggleCamera = useCallback17(() => {
|
|
2874
3152
|
const turnOn = () => client.media.setCameraEnabled(true);
|
|
2875
3153
|
if (cameraOn) client.media.setCameraEnabled(false).catch(() => toasts.show({ kind: "error", dismissible: true, message: "Couldn\u2019t turn off your camera." }));
|
|
2876
3154
|
else void turnOn().catch((cause) => reportMediaFailure("camera", cause, turnOn));
|
|
2877
3155
|
}, [cameraOn, client, reportMediaFailure, toasts]);
|
|
2878
|
-
const exit =
|
|
3156
|
+
const exit = useCallback17(
|
|
2879
3157
|
(how) => {
|
|
2880
3158
|
setSheet(null);
|
|
2881
3159
|
setLeaveMenuOpen(false);
|
|
@@ -2886,26 +3164,36 @@ function CallFrame({ displayName, callName = "Call", inviteLink, onLeave, onOpen
|
|
|
2886
3164
|
},
|
|
2887
3165
|
[client, toasts]
|
|
2888
3166
|
);
|
|
2889
|
-
const pressLeave =
|
|
3167
|
+
const pressLeave = useCallback17(() => {
|
|
2890
3168
|
haptics.leave();
|
|
2891
3169
|
if (canEnd) setLeaveMenuOpen((open) => !open);
|
|
2892
3170
|
else exit("leave");
|
|
2893
3171
|
}, [canEnd, exit]);
|
|
2894
3172
|
const devScenario = useDevScenario();
|
|
2895
|
-
|
|
3173
|
+
useEffect22(() => {
|
|
2896
3174
|
if (devScenario.sheet && devScenario.sheet !== "route") setSheet(devScenario.sheet);
|
|
2897
3175
|
if (devScenario.menu === "leave") setLeaveMenuOpen(true);
|
|
2898
3176
|
}, [devScenario]);
|
|
2899
|
-
const
|
|
3177
|
+
const sharedBoard = useWhiteboard().engine.presenting;
|
|
3178
|
+
const boardVisible = useStageView().boardOpen ?? sharedBoard;
|
|
3179
|
+
const chrome = useLandscapeChrome({ fades: layout.arrangement === "landscape" && sheet === null && !layered, boardVisible });
|
|
3180
|
+
const chromeOpacity = useSharedValue5(1);
|
|
3181
|
+
useEffect22(() => {
|
|
3182
|
+
chromeOpacity.value = withTiming7(chrome.hidden ? 0 : 1, timings.fade);
|
|
3183
|
+
}, [chrome.hidden, chromeOpacity]);
|
|
3184
|
+
const chromeStyle = useAnimatedStyle7(() => {
|
|
3185
|
+
"worklet";
|
|
3186
|
+
return { opacity: chromeOpacity.value };
|
|
3187
|
+
});
|
|
2900
3188
|
const forced = devScenario.callState;
|
|
2901
3189
|
const screen = forced === "hold" ? { kind: "call" } : forced === "left" || forced === "ended" || forced === "failed" || forced === "removed" || forced === "exited" ? { kind: "status", outcome: forced } : callScreen(connection, leftByChoice);
|
|
2902
3190
|
return /* @__PURE__ */ jsxs22(View22, { ref: screenRef, style: screenStyle, testID: "frame.screen", children: [
|
|
2903
3191
|
/* @__PURE__ */ jsx33(StatusBar, { barStyle: scheme === "dark" ? "light-content" : "dark-content" }),
|
|
2904
3192
|
/* @__PURE__ */ jsxs22(View22, { accessibilityElementsHidden: layered, importantForAccessibility: layered ? "no-hide-descendants" : "auto", style: StyleSheet23.absoluteFill, children: [
|
|
2905
|
-
/* @__PURE__ */ jsx33(Stage, { frame: regions.stage, onOpenPeople: () => setSheet("people") }),
|
|
3193
|
+
/* @__PURE__ */ jsx33(LandscapeControlsContext.Provider, { value: layout.arrangement === "landscape" && !chrome.hidden, children: /* @__PURE__ */ jsx33(Stage, { frame: regions.stage, onOpenPeople: () => setSheet("people") }) }),
|
|
2906
3194
|
chrome.hidden ? /* @__PURE__ */ jsx33(Pressable15, { accessibilityLabel: "Show call controls", onPress: chrome.show, style: StyleSheet23.absoluteFill, testID: "frame.show-controls" }) : null,
|
|
2907
|
-
/* @__PURE__ */ jsx33(Animated12.View, { pointerEvents: chrome.hidden ? "none" : "box-none", style: [styles21.region, frameStyle(regions.header),
|
|
2908
|
-
/* @__PURE__ */ jsx33(Animated12.View, { pointerEvents: chrome.hidden ? "none" : "box-none", style: [styles21.region, frameStyle(regions.dock),
|
|
3195
|
+
/* @__PURE__ */ jsx33(Animated12.View, { pointerEvents: chrome.hidden ? "none" : "box-none", style: [styles21.region, frameStyle(regions.header), chromeStyle], children: /* @__PURE__ */ jsx33(Header, { arrangement: layout.arrangement, callName, detailsOpen: sheet === "details", onOpenDetails: () => setSheet("details"), ref: nameRef }) }),
|
|
3196
|
+
/* @__PURE__ */ jsx33(Animated12.View, { pointerEvents: chrome.hidden ? "none" : "box-none", style: [styles21.region, frameStyle(regions.dock), chromeStyle], children: /* @__PURE__ */ jsx33(
|
|
2909
3197
|
Dock,
|
|
2910
3198
|
{
|
|
2911
3199
|
arrangement: layout.arrangement,
|
|
@@ -2937,31 +3225,6 @@ function CallFrame({ displayName, callName = "Call", inviteLink, onLeave, onOpen
|
|
|
2937
3225
|
/* @__PURE__ */ jsx33(ChatNotices, { chatVisible: sheet === "chat", onOpenChat: () => setSheet("chat"), sheetOpen: sheet === "people" || sheet === "chat" })
|
|
2938
3226
|
] });
|
|
2939
3227
|
}
|
|
2940
|
-
function useLandscapeChrome(fades) {
|
|
2941
|
-
const [hidden, setHidden] = useState13(false);
|
|
2942
|
-
const [shownAt, setShownAt] = useState13(0);
|
|
2943
|
-
const opacity = useSharedValue5(1);
|
|
2944
|
-
useEffect19(() => {
|
|
2945
|
-
opacity.value = withTiming7(hidden ? 0 : 1, timings.fade);
|
|
2946
|
-
}, [hidden, opacity]);
|
|
2947
|
-
useEffect19(() => {
|
|
2948
|
-
if (!fades) {
|
|
2949
|
-
setHidden(false);
|
|
2950
|
-
return;
|
|
2951
|
-
}
|
|
2952
|
-
const timer = setTimeout(() => setHidden(true), durations.landscapeHide);
|
|
2953
|
-
return () => clearTimeout(timer);
|
|
2954
|
-
}, [fades, shownAt]);
|
|
2955
|
-
const show = useCallback15(() => {
|
|
2956
|
-
setHidden(false);
|
|
2957
|
-
setShownAt(Date.now());
|
|
2958
|
-
}, []);
|
|
2959
|
-
const style = useAnimatedStyle7(() => {
|
|
2960
|
-
"worklet";
|
|
2961
|
-
return { opacity: opacity.value };
|
|
2962
|
-
});
|
|
2963
|
-
return { hidden, show, style };
|
|
2964
|
-
}
|
|
2965
3228
|
function frameStyle(frame) {
|
|
2966
3229
|
return { left: frame.x, top: frame.y, width: frame.width, height: frame.height };
|
|
2967
3230
|
}
|
|
@@ -2973,7 +3236,7 @@ var styles21 = StyleSheet23.create({
|
|
|
2973
3236
|
// src/frame/Chalk.tsx
|
|
2974
3237
|
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
2975
3238
|
function Chalk({ client, colorScheme, onColorSchemeChange, soundsEnabled, onSoundsEnabledChange, ...frame }) {
|
|
2976
|
-
|
|
3239
|
+
useEffect23(() => releaseSounds, []);
|
|
2977
3240
|
return /* @__PURE__ */ jsx34(GestureHandlerRootView, { style: styles22.root, children: /* @__PURE__ */ jsx34(SafeAreaProvider2, { children: /* @__PURE__ */ jsx34(PreferencesProvider, { colorScheme, onColorSchemeChange, onSoundsEnabledChange, soundsEnabled, children: (preferences) => /* @__PURE__ */ jsx34(ThemeProvider, { colorScheme: preferences.colorScheme, children: /* @__PURE__ */ jsx34(DeviceLayoutProvider, { children: /* @__PURE__ */ jsx34(PortalProvider, { children: /* @__PURE__ */ jsx34(ToastProvider, { children: /* @__PURE__ */ jsx34(ChalkProvider, { client, children: /* @__PURE__ */ jsx34(StageViewProvider, { children: /* @__PURE__ */ jsx34(CallFrame, { ...frame }) }) }) }) }) }) }) }) }) });
|
|
2978
3241
|
}
|
|
2979
3242
|
var styles22 = StyleSheet24.create({
|
|
@@ -2994,6 +3257,7 @@ export {
|
|
|
2994
3257
|
buildChalkInviteLink,
|
|
2995
3258
|
extractSpaceInviteFromLink,
|
|
2996
3259
|
getClipboardInviteSuggestion,
|
|
3260
|
+
parseChalkInviteLink,
|
|
2997
3261
|
parseSpaceInviteLink,
|
|
2998
3262
|
useCan,
|
|
2999
3263
|
useChat,
|