@q9labsai/chalk-react-native 5.0.0 → 5.1.0
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/CHANGELOG.md +25 -0
- package/android/build.gradle +38 -0
- package/android/compatibility/ModuleApiCompatibility.java +215 -0
- package/android/src/main/kotlin/ai/q9labs/chalk/reactnative/ChalkAudioRouteModule.kt +5 -6
- package/android/src/main/kotlin/ai/q9labs/chalk/reactnative/CommunicationDeviceListener.kt +23 -0
- package/dist/android/call-service.d.ts +0 -1
- package/dist/android/connection-service.d.ts +0 -1
- package/dist/avatar/FaceAvatar.d.ts +0 -1
- package/dist/avatar/tile-avatar-size.d.ts +0 -1
- package/dist/callkit/callkit.d.ts +0 -1
- package/dist/callkit/resolve-space-callkit-options.d.ts +0 -1
- package/dist/{chunk-OIBT2FNM.js → chunk-MBZRE4US.js} +2 -3
- package/dist/client.d.ts +0 -1
- package/dist/client.js +8 -5
- package/dist/clipboard-store.d.ts +0 -1
- package/dist/clipboard.d.ts +0 -1
- package/dist/components/EmbeddedWhiteboard.d.ts +0 -1
- package/dist/components/RtcVideoView.d.ts +0 -1
- package/dist/components/android-connection-service-controller.d.ts +0 -1
- package/dist/components/native-media-visibility.d.ts +0 -1
- package/dist/components/native-space-callkit-controller.d.ts +0 -1
- package/dist/components/native-space-view/screen-share-availability.d.ts +0 -1
- package/dist/components/rtc-video-view-availability.d.ts +0 -1
- package/dist/components/space-lifecycle.d.ts +0 -1
- package/dist/components/useAndroidCallService.d.ts +0 -1
- package/dist/components/useAndroidConnectionService.d.ts +0 -1
- package/dist/context/space-client-context.d.ts +0 -1
- package/dist/dev.d.ts +0 -1
- package/dist/diagnostics.d.ts +0 -1
- package/dist/dock/Dock.d.ts +0 -1
- package/dist/dock/LeaveMenu.d.ts +0 -1
- package/dist/dock/MoreSheet.d.ts +0 -1
- package/dist/dock/ReactionBurst.d.ts +0 -1
- package/dist/dock/RoutePicker.d.ts +0 -1
- package/dist/dock/audio-route.d.ts +0 -1
- package/dist/frame/CallFrame.d.ts +0 -1
- package/dist/frame/Chalk.d.ts +0 -1
- package/dist/frame/back-handler.d.ts +0 -1
- package/dist/frame/dev-scenario.d.ts +0 -1
- package/dist/frame/device-layout.d.ts +0 -1
- package/dist/frame/measurement.d.ts +0 -1
- package/dist/frame/portal.d.ts +0 -1
- package/dist/frame/preferences.d.ts +0 -1
- package/dist/frame/regions.d.ts +0 -1
- package/dist/haptics/haptics.d.ts +0 -1
- package/dist/header/CallDetailsSheet.d.ts +0 -1
- package/dist/header/Header.d.ts +0 -1
- package/dist/header/QrCode.d.ts +0 -1
- package/dist/hooks/external-store.d.ts +0 -1
- package/dist/hooks/space-hooks.d.ts +0 -1
- package/dist/icons/Icon.d.ts +0 -1
- package/dist/icons/icon-element.d.ts +0 -1
- package/dist/icons/icon-paths.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +45 -17
- package/dist/invites.d.ts +0 -1
- package/dist/limbo/Limbo.d.ts +0 -1
- package/dist/limbo/Veil.d.ts +0 -1
- package/dist/media/native-capture-error.d.ts +0 -1
- package/dist/media/native-webrtc.d.ts +0 -1
- package/dist/motion/MovingFrame.d.ts +0 -1
- package/dist/motion/motion.d.ts +0 -1
- package/dist/motion/presence.d.ts +0 -1
- package/dist/motion/press.d.ts +0 -1
- package/dist/platform/platform.d.ts +0 -1
- package/dist/primitives/BottomSheet.d.ts +0 -1
- package/dist/primitives/ChalkText.d.ts +0 -1
- package/dist/primitives/CopyButton.d.ts +0 -1
- package/dist/primitives/IconButton.d.ts +0 -1
- package/dist/primitives/Menu.d.ts +0 -1
- package/dist/primitives/NameTag.d.ts +0 -1
- package/dist/primitives/PillButton.d.ts +0 -1
- package/dist/primitives/SegmentedControl.d.ts +0 -1
- package/dist/primitives/SheetGroup.d.ts +0 -1
- package/dist/primitives/Switch.d.ts +0 -1
- package/dist/primitives/TileShell.d.ts +0 -1
- package/dist/primitives/announce.d.ts +0 -1
- package/dist/primitives/menu-placement.d.ts +0 -1
- package/dist/primitives/toast/Toast.d.ts +0 -1
- package/dist/primitives/toast/ToastStack.d.ts +0 -1
- package/dist/primitives/toast/toast-store.d.ts +0 -1
- package/dist/runtime.d.ts +0 -1
- package/dist/sheets/people-chat/ChatNotices.d.ts +0 -1
- package/dist/sheets/people-chat/ChatTab.d.ts +0 -1
- package/dist/sheets/people-chat/Composer.d.ts +0 -1
- package/dist/sheets/people-chat/PeopleChatSheet.d.ts +0 -1
- package/dist/sheets/people-chat/PeopleTab.d.ts +0 -1
- package/dist/sheets/people-chat/PhotoViewer.d.ts +0 -1
- package/dist/sheets/people-chat/TextField.d.ts +0 -1
- package/dist/sheets/people-chat/attachments.d.ts +0 -1
- package/dist/sheets/people-chat/chat-model.d.ts +0 -1
- package/dist/sheets/people-chat/people-model.d.ts +0 -1
- package/dist/sounds/sounds.d.ts +0 -1
- package/dist/space-client/create-native-space-client.d.ts +0 -1
- package/dist/space-client/random-uuid.d.ts +0 -1
- package/dist/stage/ContentTile.d.ts +0 -1
- package/dist/stage/ParticipantTile.d.ts +0 -1
- package/dist/stage/Stage.d.ts +0 -1
- package/dist/stage/TileSheet.d.ts +0 -1
- package/dist/stage/camera.d.ts +0 -1
- package/dist/stage/layout.d.ts +0 -1
- package/dist/stage/space-selector.d.ts +0 -1
- package/dist/stage/stage-view.d.ts +0 -1
- package/dist/status/CallOverlays.d.ts +1 -2
- package/dist/status/ChalkArrival.d.ts +0 -1
- package/dist/status/StatusPage.d.ts +0 -1
- package/dist/status/call-screen.d.ts +0 -1
- package/dist/theme/theme.d.ts +0 -1
- package/dist/theme/tokens.d.ts +0 -1
- package/dist/toasts/CallEventToasts.d.ts +1 -2
- package/dist/toasts/media-failure-copy.d.ts +2 -0
- package/dist/toasts/notices.d.ts +0 -1
- package/dist/ui/ChalkUI.d.ts +0 -1
- package/dist/ui.d.ts +0 -1
- package/dist/ui.js +1 -1
- package/dist/utils/build-chalk-invite-link.d.ts +0 -1
- package/dist/utils/ios-simulator.d.ts +0 -1
- package/dist/whiteboard/embedded-whiteboard-assets.d.ts +0 -1
- package/dist/whiteboard/embedded-whiteboard-viewport.d.ts +0 -1
- package/embedded/chalk-whiteboard/asset-manifest.json +2 -2
- package/embedded/chalk-whiteboard/renderer.js +579 -579
- package/package.json +8 -4
- package/src/components/rtc-video-view-availability.ts +1 -1
- package/src/dock/Dock.tsx +4 -2
- package/src/dock/MoreSheet.tsx +3 -2
- package/src/frame/CallFrame.tsx +4 -4
- package/src/frame/device-layout.tsx +2 -3
- package/src/space-client/create-native-space-client.ts +8 -5
- package/src/stage/TileSheet.tsx +5 -1
- package/src/status/CallOverlays.tsx +18 -3
- package/src/toasts/CallEventToasts.tsx +16 -7
- package/src/toasts/media-failure-copy.ts +10 -0
- package/dist/android/call-service.d.ts.map +0 -1
- package/dist/android/connection-service.d.ts.map +0 -1
- package/dist/avatar/FaceAvatar.d.ts.map +0 -1
- package/dist/avatar/tile-avatar-size.d.ts.map +0 -1
- package/dist/callkit/callkit.d.ts.map +0 -1
- package/dist/callkit/resolve-space-callkit-options.d.ts.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/clipboard-store.d.ts.map +0 -1
- package/dist/clipboard.d.ts.map +0 -1
- package/dist/components/EmbeddedWhiteboard.d.ts.map +0 -1
- package/dist/components/RtcVideoView.d.ts.map +0 -1
- package/dist/components/android-connection-service-controller.d.ts.map +0 -1
- package/dist/components/native-media-visibility.d.ts.map +0 -1
- package/dist/components/native-space-callkit-controller.d.ts.map +0 -1
- package/dist/components/native-space-view/screen-share-availability.d.ts.map +0 -1
- package/dist/components/rtc-video-view-availability.d.ts.map +0 -1
- package/dist/components/space-lifecycle.d.ts.map +0 -1
- package/dist/components/useAndroidCallService.d.ts.map +0 -1
- package/dist/components/useAndroidConnectionService.d.ts.map +0 -1
- package/dist/context/space-client-context.d.ts.map +0 -1
- package/dist/dev.d.ts.map +0 -1
- package/dist/diagnostics.d.ts.map +0 -1
- package/dist/dock/Dock.d.ts.map +0 -1
- package/dist/dock/LeaveMenu.d.ts.map +0 -1
- package/dist/dock/MoreSheet.d.ts.map +0 -1
- package/dist/dock/ReactionBurst.d.ts.map +0 -1
- package/dist/dock/RoutePicker.d.ts.map +0 -1
- package/dist/dock/audio-route.d.ts.map +0 -1
- package/dist/frame/CallFrame.d.ts.map +0 -1
- package/dist/frame/Chalk.d.ts.map +0 -1
- package/dist/frame/back-handler.d.ts.map +0 -1
- package/dist/frame/dev-scenario.d.ts.map +0 -1
- package/dist/frame/device-layout.d.ts.map +0 -1
- package/dist/frame/measurement.d.ts.map +0 -1
- package/dist/frame/portal.d.ts.map +0 -1
- package/dist/frame/preferences.d.ts.map +0 -1
- package/dist/frame/regions.d.ts.map +0 -1
- package/dist/haptics/haptics.d.ts.map +0 -1
- package/dist/header/CallDetailsSheet.d.ts.map +0 -1
- package/dist/header/Header.d.ts.map +0 -1
- package/dist/header/QrCode.d.ts.map +0 -1
- package/dist/hooks/external-store.d.ts.map +0 -1
- package/dist/hooks/space-hooks.d.ts.map +0 -1
- package/dist/icons/Icon.d.ts.map +0 -1
- package/dist/icons/icon-element.d.ts.map +0 -1
- package/dist/icons/icon-paths.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/invites.d.ts.map +0 -1
- package/dist/limbo/Limbo.d.ts.map +0 -1
- package/dist/limbo/Veil.d.ts.map +0 -1
- package/dist/media/native-capture-error.d.ts.map +0 -1
- package/dist/media/native-webrtc.d.ts.map +0 -1
- package/dist/motion/MovingFrame.d.ts.map +0 -1
- package/dist/motion/motion.d.ts.map +0 -1
- package/dist/motion/presence.d.ts.map +0 -1
- package/dist/motion/press.d.ts.map +0 -1
- package/dist/platform/platform.d.ts.map +0 -1
- package/dist/primitives/BottomSheet.d.ts.map +0 -1
- package/dist/primitives/ChalkText.d.ts.map +0 -1
- package/dist/primitives/CopyButton.d.ts.map +0 -1
- package/dist/primitives/IconButton.d.ts.map +0 -1
- package/dist/primitives/Menu.d.ts.map +0 -1
- package/dist/primitives/NameTag.d.ts.map +0 -1
- package/dist/primitives/PillButton.d.ts.map +0 -1
- package/dist/primitives/SegmentedControl.d.ts.map +0 -1
- package/dist/primitives/SheetGroup.d.ts.map +0 -1
- package/dist/primitives/Switch.d.ts.map +0 -1
- package/dist/primitives/TileShell.d.ts.map +0 -1
- package/dist/primitives/announce.d.ts.map +0 -1
- package/dist/primitives/menu-placement.d.ts.map +0 -1
- package/dist/primitives/toast/Toast.d.ts.map +0 -1
- package/dist/primitives/toast/ToastStack.d.ts.map +0 -1
- package/dist/primitives/toast/toast-store.d.ts.map +0 -1
- package/dist/runtime.d.ts.map +0 -1
- package/dist/sheets/people-chat/ChatNotices.d.ts.map +0 -1
- package/dist/sheets/people-chat/ChatTab.d.ts.map +0 -1
- package/dist/sheets/people-chat/Composer.d.ts.map +0 -1
- package/dist/sheets/people-chat/PeopleChatSheet.d.ts.map +0 -1
- package/dist/sheets/people-chat/PeopleTab.d.ts.map +0 -1
- package/dist/sheets/people-chat/PhotoViewer.d.ts.map +0 -1
- package/dist/sheets/people-chat/TextField.d.ts.map +0 -1
- package/dist/sheets/people-chat/attachments.d.ts.map +0 -1
- package/dist/sheets/people-chat/chat-model.d.ts.map +0 -1
- package/dist/sheets/people-chat/people-model.d.ts.map +0 -1
- package/dist/sounds/sounds.d.ts.map +0 -1
- package/dist/space-client/create-native-space-client.d.ts.map +0 -1
- package/dist/space-client/random-uuid.d.ts.map +0 -1
- package/dist/stage/ContentTile.d.ts.map +0 -1
- package/dist/stage/ParticipantTile.d.ts.map +0 -1
- package/dist/stage/Stage.d.ts.map +0 -1
- package/dist/stage/TileSheet.d.ts.map +0 -1
- package/dist/stage/camera.d.ts.map +0 -1
- package/dist/stage/layout.d.ts.map +0 -1
- package/dist/stage/space-selector.d.ts.map +0 -1
- package/dist/stage/stage-view.d.ts.map +0 -1
- package/dist/status/CallOverlays.d.ts.map +0 -1
- package/dist/status/ChalkArrival.d.ts.map +0 -1
- package/dist/status/StatusPage.d.ts.map +0 -1
- package/dist/status/call-screen.d.ts.map +0 -1
- package/dist/theme/theme.d.ts.map +0 -1
- package/dist/theme/tokens.d.ts.map +0 -1
- package/dist/toasts/CallEventToasts.d.ts.map +0 -1
- package/dist/toasts/notices.d.ts.map +0 -1
- package/dist/ui/ChalkUI.d.ts.map +0 -1
- package/dist/ui.d.ts.map +0 -1
- package/dist/utils/build-chalk-invite-link.d.ts.map +0 -1
- package/dist/utils/ios-simulator.d.ts.map +0 -1
- package/dist/whiteboard/embedded-whiteboard-assets.d.ts.map +0 -1
- package/dist/whiteboard/embedded-whiteboard-viewport.d.ts.map +0 -1
- package/src/callkit/callkit.test.ts +0 -97
- package/src/components/native-space-view/screen-share-availability.test.ts +0 -16
- package/src/frame/regions.test.ts +0 -38
- package/src/media/native-capture-error.test.ts +0 -19
- package/src/primitives/menu-placement.test.ts +0 -50
- package/src/sheets/people-chat/people-chat-model.test.ts +0 -98
- package/src/space-client/whiteboard-watchdog.test.ts +0 -23
- package/src/stage/layout.test.ts +0 -77
- package/src/status/call-screen.test.ts +0 -42
- package/src/toasts/notices.test.ts +0 -92
- package/src/whiteboard/embedded-whiteboard-viewport.test.ts +0 -13
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import type { SpaceClientPlatform } from "@q9labsai/chalk-client/effect";
|
|
3
|
-
const mocks = vi.hoisted(() => ({ platform: vi.fn(), whiteboard: vi.fn() }));
|
|
4
|
-
vi.mock("react-native", () => ({ AppState: { currentState: "active", addEventListener: vi.fn(() => ({ remove: vi.fn() })) } }));
|
|
5
|
-
vi.mock("@cloudflare/react-native-webrtc", () => ({ RTCPeerConnection: vi.fn(), mediaDevices: {} }));
|
|
6
|
-
vi.mock("@q9labsai/chalk-client/effect", () => ({ createSpaceClientForPlatform: mocks.platform }));
|
|
7
|
-
vi.mock("@q9labsai/chalk-client", async (original) => ({ ...(await original<typeof import("@q9labsai/chalk-client")>()), createChalkWhiteboardV1Client: mocks.whiteboard }));
|
|
8
|
-
import { createNativeSpaceClient } from "./create-native-space-client";
|
|
9
|
-
describe("native whiteboard watchdog adapter", () => {
|
|
10
|
-
it("passes the shared core's replacement recorder without a journey option", () => {
|
|
11
|
-
createNativeSpaceClient({
|
|
12
|
-
space: "test",
|
|
13
|
-
getAccess: async () => {
|
|
14
|
-
throw new Error("unused");
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
const platform: SpaceClientPlatform | undefined = mocks.platform.mock.calls[0]?.[1];
|
|
18
|
-
const onWatchdogReplacement = vi.fn();
|
|
19
|
-
platform?.dependencies?.createWhiteboardClient?.({ token: async () => "unused", onSummary: vi.fn(), onWatchdogReplacement });
|
|
20
|
-
expect(mocks.whiteboard).toHaveBeenCalledOnce();
|
|
21
|
-
expect(mocks.whiteboard.mock.calls[0]?.[0].onWatchdogReplacement).toBe(onWatchdogReplacement);
|
|
22
|
-
});
|
|
23
|
-
});
|
package/src/stage/layout.test.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { nextStageOrder, stageLayout, type StageInput, type StageItem } from "./layout";
|
|
3
|
-
|
|
4
|
-
// The D1 portrait stage from `frameRegions`. Expected frames come from the mockup's own `layout()`.
|
|
5
|
-
const stage = { x: 8, y: 111, width: 377, height: 625 };
|
|
6
|
-
const ids = (count: number) => Array.from({ length: count }, (_, index) => String(index));
|
|
7
|
-
const input = (overrides: Partial<StageInput>): StageInput => ({ stage, portrait: true, layout: "spotlight", order: ids(6), spot: "1", pinned: null, content: null, ...overrides });
|
|
8
|
-
const rounded = (item: StageItem) => [item.frame.x, item.frame.y, item.frame.width, item.frame.height].map((value) => Math.round(value * 10) / 10);
|
|
9
|
-
|
|
10
|
-
describe("stageLayout", () => {
|
|
11
|
-
it("floats you over the other person when two are in the call (P2)", () => {
|
|
12
|
-
const [main, you] = stageLayout(input({ order: ids(2) }));
|
|
13
|
-
expect(main).toMatchObject({ kind: "person", id: "1", frame: stage });
|
|
14
|
-
expect(you).toMatchObject({ kind: "person", id: "0", float: true });
|
|
15
|
-
if (you) expect(rounded(you)).toEqual([277, 123, 96, 128]);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("puts the speaker big and everyone else in justified rows below (P3, G1)", () => {
|
|
19
|
-
const items = stageLayout(input({}));
|
|
20
|
-
expect(items.map((item) => (item.kind === "person" ? item.id : item.kind))).toEqual(["1", "0", "2", "3", "4", "5"]);
|
|
21
|
-
expect(items[0]).toMatchObject({ big: true });
|
|
22
|
-
expect(items.map(rounded)).toEqual([
|
|
23
|
-
[8, 111, 377, 429],
|
|
24
|
-
[8, 548, 120.3, 90],
|
|
25
|
-
[136.3, 548, 120.3, 90],
|
|
26
|
-
[264.7, 548, 120.3, 90],
|
|
27
|
-
[8, 646, 184.5, 90],
|
|
28
|
-
[200.5, 646, 184.5, 90],
|
|
29
|
-
]);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("keeps a pinned person big over the speaker", () => {
|
|
33
|
-
expect(stageLayout(input({ pinned: "4" }))[0]).toMatchObject({ kind: "person", id: "4", big: true });
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("fills the stage with 24 tiles in Grid (P4, G2)", () => {
|
|
37
|
-
const items = stageLayout(input({ layout: "grid", order: ids(24) }));
|
|
38
|
-
expect(items).toHaveLength(24);
|
|
39
|
-
expect(items.every((item) => item.kind === "person" && Math.round(item.frame.width * 10) / 10 === 88.3)).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("stands a phone share at full height with people beside it (C2, S4)", () => {
|
|
43
|
-
const [share, ...rest] = stageLayout(input({ content: { kind: "screen", aspect: 9 / 16 } }));
|
|
44
|
-
expect(share).toMatchObject({ kind: "content", mini: false });
|
|
45
|
-
if (share) expect(rounded(share)).toEqual([8, 111, 249, 625]);
|
|
46
|
-
expect(rest.every((item) => item.frame.x === 265 && item.frame.width === 120)).toBe(true);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("gives a shared board the stage with one row of people and a +N tile (C3)", () => {
|
|
50
|
-
const items = stageLayout(input({ content: { kind: "board", aspect: null } }));
|
|
51
|
-
expect(items[0] && rounded(items[0])).toEqual([8, 111, 377, 511]);
|
|
52
|
-
expect(items.at(-1)).toMatchObject({ kind: "more", count: 3 });
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("shows the share as a double tile in Grid", () => {
|
|
56
|
-
const [share] = stageLayout(input({ layout: "grid", content: { kind: "screen", aspect: 16 / 9 } }));
|
|
57
|
-
expect(share).toMatchObject({ kind: "content", mini: true });
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe("nextStageOrder", () => {
|
|
62
|
-
it("swaps a new speaker with the person in the spotlight, so only those two tiles move", () => {
|
|
63
|
-
const start = nextStageOrder({ order: [], spot: null }, ["you", "a", "b", "c"], "you", null);
|
|
64
|
-
expect(start).toEqual({ order: ["you", "a", "b", "c"], spot: "a" });
|
|
65
|
-
expect(nextStageOrder(start, ["you", "a", "b", "c"], "you", "c")).toEqual({ order: ["you", "c", "b", "a"], spot: "c" });
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("ignores your own speech and keeps the same object when nothing changes", () => {
|
|
69
|
-
const start = nextStageOrder({ order: [], spot: null }, ["you", "a", "b"], "you", null);
|
|
70
|
-
expect(nextStageOrder(start, ["you", "a", "b"], "you", "you")).toBe(start);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("drops leavers, appends newcomers and moves the spotlight off someone who left", () => {
|
|
74
|
-
const start = { order: ["you", "a", "b"], spot: "a" };
|
|
75
|
-
expect(nextStageOrder(start, ["you", "b", "d"], "you", null)).toEqual({ order: ["you", "b", "d"], spot: "b" });
|
|
76
|
-
});
|
|
77
|
-
});
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { callScreen } from "./call-screen";
|
|
3
|
-
|
|
4
|
-
type ConnectionOptions = { readonly code?: "episode.ended" | "access.invalid"; readonly episodeEnded?: boolean; readonly removedByHost?: boolean };
|
|
5
|
-
|
|
6
|
-
const connection = (status: Parameters<typeof callScreen>[0]["status"], { code, episodeEnded = false, removedByHost = false }: ConnectionOptions = {}) => ({
|
|
7
|
-
status,
|
|
8
|
-
episode: null,
|
|
9
|
-
lastError: code ? { code, recoverable: false, message: "" } : null,
|
|
10
|
-
episodeEnded,
|
|
11
|
-
removedByHost,
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
describe("callScreen", () => {
|
|
15
|
-
it("covers the call while it joins or reconnects", () => {
|
|
16
|
-
expect(callScreen(connection("joining"), false)).toEqual({ kind: "joining" });
|
|
17
|
-
expect(callScreen(connection("reconnecting"), false)).toEqual({ kind: "reconnecting" });
|
|
18
|
-
expect(callScreen(connection("live"), false)).toEqual({ kind: "call" });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("shows the person's own leave as left, even when the leave call failed", () => {
|
|
22
|
-
expect(callScreen(connection("left"), true)).toEqual({ kind: "status", outcome: "left" });
|
|
23
|
-
expect(callScreen(connection("left", { removedByHost: true }), true)).toEqual({ kind: "status", outcome: "left" });
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("shows removed only when the server reported a host removal", () => {
|
|
27
|
-
expect(callScreen(connection("left", { removedByHost: true }), false)).toEqual({ kind: "status", outcome: "removed" });
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("shows a neutral exit for any other exit nobody asked for", () => {
|
|
31
|
-
expect(callScreen(connection("left"), false)).toEqual({ kind: "status", outcome: "exited" });
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("shows the call ended when the Episode ends while the person is in it", () => {
|
|
35
|
-
expect(callScreen(connection("left", { episodeEnded: true }), false)).toEqual({ kind: "status", outcome: "ended" });
|
|
36
|
-
expect(callScreen(connection("left", { code: "episode.ended" }), false)).toEqual({ kind: "status", outcome: "ended" });
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("shows a failure as failed", () => {
|
|
40
|
-
expect(callScreen(connection("failed", { code: "access.invalid" }), false)).toEqual({ kind: "status", outcome: "failed" });
|
|
41
|
-
});
|
|
42
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import type { Capability, Participant, SpaceSnapshot } from "@q9labsai/chalk-client";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
import { callNotices } from "./notices";
|
|
4
|
-
|
|
5
|
-
const HOST: readonly Capability[] = ["endEpisode", "muteOthers"];
|
|
6
|
-
|
|
7
|
-
function person(participantId: string, displayName: string, capabilities: readonly Capability[] = [], screenShare: "active" | "inactive" = "inactive"): Participant {
|
|
8
|
-
return {
|
|
9
|
-
participantId,
|
|
10
|
-
displayName,
|
|
11
|
-
role: capabilities.length ? "host" : "guest",
|
|
12
|
-
eligibleRoles: [],
|
|
13
|
-
capabilities,
|
|
14
|
-
handRaised: false,
|
|
15
|
-
media: { microphone: "inactive", camera: "inactive", screenShare },
|
|
16
|
-
presence: { state: "connected", speaking: false, activeSpeaker: false },
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type Shape = {
|
|
21
|
-
readonly status?: SpaceSnapshot["connection"]["status"];
|
|
22
|
-
readonly roster?: readonly Participant[];
|
|
23
|
-
readonly selfCapabilities?: readonly Capability[];
|
|
24
|
-
readonly microphone?: "enabled" | "disabled";
|
|
25
|
-
readonly requests?: SpaceSnapshot["media"]["incomingRequests"];
|
|
26
|
-
readonly recording?: "recording" | "stopped";
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
function snapshot({ status = "live", roster = [], selfCapabilities = [], microphone = "disabled", requests = [], recording }: Shape): SpaceSnapshot {
|
|
30
|
-
const local = (state: "enabled" | "disabled") => ({ source: "microphone" as const, state, track: null });
|
|
31
|
-
return {
|
|
32
|
-
connection: { status, episode: null, lastError: null },
|
|
33
|
-
self: { participantId: "me", displayName: "Hasan", role: null, capabilities: selfCapabilities, handRaised: false, can: (capability) => selfCapabilities.includes(capability) },
|
|
34
|
-
participants: { roster: [person("me", "Hasan", selfCapabilities), ...roster], admissionQueue: [] },
|
|
35
|
-
media: {
|
|
36
|
-
devices: { microphones: [], cameras: [], speakers: [] },
|
|
37
|
-
selection: { microphone: null, camera: null, speaker: null },
|
|
38
|
-
local: { microphone: local(microphone), camera: { ...local("disabled"), source: "camera" }, screen: { ...local("disabled"), source: "screen" } },
|
|
39
|
-
remote: [],
|
|
40
|
-
screenShare: { ...local("disabled"), source: "screen" },
|
|
41
|
-
incomingRequests: requests,
|
|
42
|
-
},
|
|
43
|
-
chat: { status: "ready", messages: [], pendingSends: [], readReceipts: [], unreadCount: 0, pagination: { cursor: null, hasOlder: false, historyTruncated: false }, lastError: null },
|
|
44
|
-
reactions: { active: [] },
|
|
45
|
-
recording: { current: recording ? { recordingId: "r1", status: recording, failureCode: null } : null },
|
|
46
|
-
whiteboard: { open: false, engine: { status: "unsubscribed", sceneId: null, revision: null, presenting: false, error: null } },
|
|
47
|
-
offline: { pending: [], decisionNeeded: false, policy: "ask" },
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const nora = person("nora", "Nora Lindqvist", HOST);
|
|
52
|
-
const sam = person("sam", "Sam Okafor");
|
|
53
|
-
|
|
54
|
-
describe("callNotices", () => {
|
|
55
|
-
it("says nothing while the roster arrives on join or empties on leave", () => {
|
|
56
|
-
expect(callNotices(snapshot({ status: "joining" }), snapshot({ roster: [nora, sam] }), false)).toEqual([]);
|
|
57
|
-
expect(callNotices(snapshot({ roster: [nora, sam] }), snapshot({ status: "left" }), false)).toEqual([]);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("names people who join and leave, but never you", () => {
|
|
61
|
-
expect(callNotices(snapshot({ roster: [nora] }), snapshot({ roster: [nora, sam] }), false)).toEqual([{ kind: "joined", name: "Sam Okafor" }]);
|
|
62
|
-
expect(callNotices(snapshot({ roster: [nora, sam] }), snapshot({ roster: [nora] }), false)).toEqual([{ kind: "left", name: "Sam Okafor" }]);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("tells you the host left and you're the host now, instead of a plain leave", () => {
|
|
66
|
-
const notices = callNotices(snapshot({ roster: [nora, sam] }), snapshot({ roster: [sam], selfCapabilities: HOST }), false);
|
|
67
|
-
expect(notices).toEqual([{ kind: "newHost", previousHost: "Nora" }]);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("reports a host mute only when you didn't mute yourself", () => {
|
|
71
|
-
const before = snapshot({ roster: [nora, sam], microphone: "enabled" });
|
|
72
|
-
const after = snapshot({ roster: [nora, sam], microphone: "disabled" });
|
|
73
|
-
expect(callNotices(before, after, false)).toEqual([{ kind: "mutedByHost", by: "Nora" }]);
|
|
74
|
-
expect(callNotices(before, after, true)).toEqual([]);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("reports each new request to unmute once", () => {
|
|
78
|
-
const request = { requestId: "q1", kind: "unmute" as const, actorParticipantId: "nora", actorDisplayName: "Nora Lindqvist", expiresAt: "2026-10-18T12:00:00Z" };
|
|
79
|
-
expect(callNotices(snapshot({ roster: [nora] }), snapshot({ roster: [nora], requests: [request] }), false)).toEqual([{ kind: "mediaRequest", request }]);
|
|
80
|
-
expect(callNotices(snapshot({ roster: [nora], requests: [request] }), snapshot({ roster: [nora], requests: [request] }), false)).toEqual([]);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it("reports when someone else stops sharing", () => {
|
|
84
|
-
const sharing = person("sam", "Sam Okafor", [], "active");
|
|
85
|
-
expect(callNotices(snapshot({ roster: [sharing] }), snapshot({ roster: [sam] }), false)).toEqual([{ kind: "shareStopped", name: "Sam" }]);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("reports recording starting and stopping", () => {
|
|
89
|
-
expect(callNotices(snapshot({}), snapshot({ recording: "recording" }), false)).toEqual([{ kind: "recordingStarted" }]);
|
|
90
|
-
expect(callNotices(snapshot({ recording: "recording" }), snapshot({ recording: "stopped" }), false)).toEqual([{ kind: "recordingStopped" }]);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { createEmbeddedWhiteboardViewport } from "./embedded-whiteboard-viewport";
|
|
4
|
-
|
|
5
|
-
describe("native embedded whiteboard viewport", () => {
|
|
6
|
-
it("uses the measured Board rectangle rather than the device window", () => {
|
|
7
|
-
expect(createEmbeddedWhiteboardViewport(640, 420, 2)).toEqual({ width: 640, height: 420, scale: 2 });
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it("waits for a usable layout", () => {
|
|
11
|
-
expect(createEmbeddedWhiteboardViewport(0, 420, 2)).toBeNull();
|
|
12
|
-
});
|
|
13
|
-
});
|