Automatisation des screenshots
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 223 KiB |
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 221 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 246 KiB |
|
Before Width: | Height: | Size: 271 KiB After Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 328 KiB After Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 274 KiB |
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import { execFileSync } from "node:child_process";
|
import { execFileSync } from "node:child_process";
|
||||||
import { existsSync, mkdirSync } from "node:fs";
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
||||||
import { dirname, join, resolve } from "node:path";
|
import { dirname, join, resolve } from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
|
@ -16,8 +16,10 @@ const appPath = resolve(
|
||||||
"Release-iphonesimulator",
|
"Release-iphonesimulator",
|
||||||
"mobile.app",
|
"mobile.app",
|
||||||
);
|
);
|
||||||
|
const productsPath = resolve(derivedDataPath, "Build", "Products", "Release-iphonesimulator");
|
||||||
const defaultOutputRoot = resolve(mobileRoot, "..", "ScreenShots");
|
const defaultOutputRoot = resolve(mobileRoot, "..", "ScreenShots");
|
||||||
const bundleId = "fr.negopoly.app";
|
const bundleId = "fr.negopoly.app";
|
||||||
|
const screenshotStorageKey = "negopoly:screenshot-scene";
|
||||||
const launchWaitMs = 4500;
|
const launchWaitMs = 4500;
|
||||||
const sceneWaitMs = 2200;
|
const sceneWaitMs = 2200;
|
||||||
|
|
||||||
|
|
@ -159,19 +161,78 @@ function buildReleaseApp(buildDestinationUdid) {
|
||||||
{ stdio: "inherit" },
|
{ stdio: "inherit" },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!existsSync(appPath)) {
|
return resolveBuiltAppPath();
|
||||||
throw new Error(`Built app not found at ${appPath}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function installApp(udid) {
|
function resolveBuiltAppPath() {
|
||||||
|
if (existsSync(appPath)) {
|
||||||
|
return appPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existsSync(productsPath)) {
|
||||||
|
throw new Error(`Build products directory not found at ${productsPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const candidates = readdirSync(productsPath)
|
||||||
|
.filter((entry) => entry.endsWith(".app"))
|
||||||
|
.filter((entry) => !entry.endsWith(".app.dSYM"))
|
||||||
|
.sort((left, right) => left.localeCompare(right));
|
||||||
|
|
||||||
|
if (candidates.length === 0) {
|
||||||
|
throw new Error(`Built app not found under ${productsPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return join(productsPath, candidates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function installApp(udid, builtAppPath) {
|
||||||
runQuiet("xcrun", ["simctl", "terminate", udid, bundleId]);
|
runQuiet("xcrun", ["simctl", "terminate", udid, bundleId]);
|
||||||
runQuiet("xcrun", ["simctl", "uninstall", udid, bundleId]);
|
runQuiet("xcrun", ["simctl", "uninstall", udid, bundleId]);
|
||||||
run("xcrun", ["simctl", "install", udid, appPath]);
|
run("xcrun", ["simctl", "install", udid, builtAppPath]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function grantAppPermissions(udid) {
|
||||||
|
runQuiet("xcrun", ["simctl", "privacy", udid, "grant", "notifications", bundleId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDataContainerPath(udid) {
|
||||||
|
return run("xcrun", ["simctl", "get_app_container", udid, bundleId, "data"]).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeScreenshotScene(udid, scene) {
|
||||||
|
const containerPath = getDataContainerPath(udid);
|
||||||
|
const storageDir = join(
|
||||||
|
containerPath,
|
||||||
|
"Library",
|
||||||
|
"Application Support",
|
||||||
|
bundleId,
|
||||||
|
"RCTAsyncLocalStorage_V1",
|
||||||
|
);
|
||||||
|
const manifestPath = join(storageDir, "manifest.json");
|
||||||
|
|
||||||
|
mkdirSync(storageDir, { recursive: true });
|
||||||
|
|
||||||
|
let manifest = {};
|
||||||
|
if (existsSync(manifestPath)) {
|
||||||
|
try {
|
||||||
|
manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
||||||
|
} catch {
|
||||||
|
manifest = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest[screenshotStorageKey] = scene;
|
||||||
|
writeFileSync(manifestPath, JSON.stringify(manifest), "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
function launchApp(udid) {
|
||||||
|
run("xcrun", ["simctl", "launch", udid, bundleId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openScene(udid, scene, waitMs) {
|
function openScene(udid, scene, waitMs) {
|
||||||
run("xcrun", ["simctl", "openurl", udid, `negopoly://screenshot/${scene}`]);
|
runQuiet("xcrun", ["simctl", "terminate", udid, bundleId]);
|
||||||
|
writeScreenshotScene(udid, scene);
|
||||||
|
launchApp(udid);
|
||||||
sleep(waitMs);
|
sleep(waitMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,14 +247,16 @@ function main() {
|
||||||
...target,
|
...target,
|
||||||
simulator: resolveDevice(target.matchName, devices),
|
simulator: resolveDevice(target.matchName, devices),
|
||||||
}));
|
}));
|
||||||
|
const builtAppPath = !options.skipBuild
|
||||||
|
? buildReleaseApp(resolvedTargets[0].simulator.udid)
|
||||||
|
: resolveBuiltAppPath();
|
||||||
|
|
||||||
if (!options.skipBuild) {
|
if (options.skipBuild && !existsSync(builtAppPath)) {
|
||||||
buildReleaseApp(resolvedTargets[0].simulator.udid);
|
throw new Error(`Cannot use --skip-build because ${builtAppPath} does not exist`);
|
||||||
} else if (!existsSync(appPath)) {
|
|
||||||
throw new Error(`Cannot use --skip-build because ${appPath} does not exist`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdirSync(options.outputRoot, { recursive: true });
|
mkdirSync(options.outputRoot, { recursive: true });
|
||||||
|
console.log(`Using built app: ${builtAppPath}`);
|
||||||
|
|
||||||
for (const target of resolvedTargets) {
|
for (const target of resolvedTargets) {
|
||||||
const { simulator } = target;
|
const { simulator } = target;
|
||||||
|
|
@ -203,7 +266,8 @@ function main() {
|
||||||
mkdirSync(deviceOutputDir, { recursive: true });
|
mkdirSync(deviceOutputDir, { recursive: true });
|
||||||
ensureBooted(simulator.udid);
|
ensureBooted(simulator.udid);
|
||||||
setSimulatorAppearance(simulator.udid);
|
setSimulatorAppearance(simulator.udid);
|
||||||
installApp(simulator.udid);
|
installApp(simulator.udid, builtAppPath);
|
||||||
|
grantAppPermissions(simulator.udid);
|
||||||
|
|
||||||
for (const [index, scene] of scenes.entries()) {
|
for (const [index, scene] of scenes.entries()) {
|
||||||
const targetPath = join(deviceOutputDir, scene.fileName);
|
const targetPath = join(deviceOutputDir, scene.fileName);
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ function RootNavigationGate() {
|
||||||
const lastTargetRef = useRef<keyof RootStackParamList | null>(null);
|
const lastTargetRef = useRef<keyof RootStackParamList | null>(null);
|
||||||
const lastLinkRef = useRef<string | null>(null);
|
const lastLinkRef = useRef<string | null>(null);
|
||||||
const pendingNotificationRef = useRef<NotificationTarget | null>(null);
|
const pendingNotificationRef = useRef<NotificationTarget | null>(null);
|
||||||
const pendingScreenshotRef = useRef(false);
|
const lastScreenshotSceneRef = useRef<string | null>(null);
|
||||||
const lastNotificationIdRef = useRef<string | null>(null);
|
const lastNotificationIdRef = useRef<string | null>(null);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const navigationTheme = getNavigationTheme(theme);
|
const navigationTheme = getNavigationTheme(theme);
|
||||||
|
|
@ -72,7 +72,6 @@ function RootNavigationGate() {
|
||||||
(url: string) => {
|
(url: string) => {
|
||||||
const scene = extractScreenshotScene(url);
|
const scene = extractScreenshotScene(url);
|
||||||
if (!scene) return false;
|
if (!scene) return false;
|
||||||
pendingScreenshotRef.current = true;
|
|
||||||
manager.activateScreenshotScene(scene);
|
manager.activateScreenshotScene(scene);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
@ -150,12 +149,15 @@ function RootNavigationGate() {
|
||||||
}, [manager.isBanker, manager.session, manager.sessionId, navReady, navigationRef]);
|
}, [manager.isBanker, manager.session, manager.sessionId, navReady, navigationRef]);
|
||||||
|
|
||||||
const processPendingScreenshot = useCallback(() => {
|
const processPendingScreenshot = useCallback(() => {
|
||||||
if (!pendingScreenshotRef.current) return;
|
const screenshot = manager.screenshot;
|
||||||
|
if (!screenshot) {
|
||||||
|
lastScreenshotSceneRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lastScreenshotSceneRef.current === screenshot.scene) return;
|
||||||
if (!navReady || !navigationRef.isReady()) return;
|
if (!navReady || !navigationRef.isReady()) return;
|
||||||
const target = manager.screenshot?.navigationTarget;
|
const target = screenshot.navigationTarget;
|
||||||
if (!target) return;
|
|
||||||
|
|
||||||
pendingScreenshotRef.current = false;
|
|
||||||
navigationRef.dispatch(
|
navigationRef.dispatch(
|
||||||
CommonActions.reset({
|
CommonActions.reset({
|
||||||
index: 0,
|
index: 0,
|
||||||
|
|
@ -163,10 +165,24 @@ function RootNavigationGate() {
|
||||||
{
|
{
|
||||||
name: target.root,
|
name: target.root,
|
||||||
params: target.params,
|
params: target.params,
|
||||||
|
state: target.state,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const followUp = target.followUp;
|
||||||
|
if (followUp) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!navigationRef.isReady()) return;
|
||||||
|
navigationRef.dispatch(
|
||||||
|
CommonActions.navigate({
|
||||||
|
name: followUp.name,
|
||||||
|
params: followUp.params,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
lastScreenshotSceneRef.current = screenshot.scene;
|
||||||
lastTargetRef.current = target.root;
|
lastTargetRef.current = target.root;
|
||||||
}, [manager.screenshot, navReady, navigationRef]);
|
}, [manager.screenshot, navReady, navigationRef]);
|
||||||
|
|
||||||
|
|
@ -195,9 +211,7 @@ function RootNavigationGate() {
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pendingScreenshotRef.current) {
|
if (manager.screenshot) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!navReady || !navigationRef.isReady()) return;
|
if (!navReady || !navigationRef.isReady()) return;
|
||||||
|
|
||||||
const currentRoute = navigationRef.getCurrentRoute();
|
const currentRoute = navigationRef.getCurrentRoute();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@ import type { SessionSnapshot } from "../shared/types";
|
||||||
|
|
||||||
export type ScreenshotScene = "start" | "lobby" | "home" | "transfers" | "chat";
|
export type ScreenshotScene = "start" | "lobby" | "home" | "transfers" | "chat";
|
||||||
|
|
||||||
|
export type ScreenshotNavigationState = {
|
||||||
|
index: number;
|
||||||
|
routes: Array<{
|
||||||
|
name: string;
|
||||||
|
params?: Record<string, unknown>;
|
||||||
|
state?: ScreenshotNavigationState;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ScreenshotFixture = {
|
export type ScreenshotFixture = {
|
||||||
scene: ScreenshotScene;
|
scene: ScreenshotScene;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
|
|
@ -11,6 +20,11 @@ export type ScreenshotFixture = {
|
||||||
navigationTarget: {
|
navigationTarget: {
|
||||||
root: "EntryLanding" | "Lobby" | "PlayerTabs";
|
root: "EntryLanding" | "Lobby" | "PlayerTabs";
|
||||||
params?: Record<string, unknown>;
|
params?: Record<string, unknown>;
|
||||||
|
state?: ScreenshotNavigationState;
|
||||||
|
followUp?: {
|
||||||
|
name: "PlayerTabs";
|
||||||
|
params: Record<string, unknown>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
transferDraft?: {
|
transferDraft?: {
|
||||||
targetId: string;
|
targetId: string;
|
||||||
|
|
@ -300,7 +314,14 @@ export function buildScreenshotFixture(scene: ScreenshotScene): ScreenshotFixtur
|
||||||
session: createActiveSession(),
|
session: createActiveSession(),
|
||||||
navigationTarget: {
|
navigationTarget: {
|
||||||
root: "PlayerTabs",
|
root: "PlayerTabs",
|
||||||
params: { screen: "PlayerHome" },
|
state: {
|
||||||
|
index: 0,
|
||||||
|
routes: [{ name: "PlayerHome" }],
|
||||||
|
},
|
||||||
|
followUp: {
|
||||||
|
name: "PlayerTabs",
|
||||||
|
params: { screen: "PlayerHome" },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +335,14 @@ export function buildScreenshotFixture(scene: ScreenshotScene): ScreenshotFixtur
|
||||||
session: createActiveSession(),
|
session: createActiveSession(),
|
||||||
navigationTarget: {
|
navigationTarget: {
|
||||||
root: "PlayerTabs",
|
root: "PlayerTabs",
|
||||||
params: { screen: "PlayerTransfers" },
|
state: {
|
||||||
|
index: 0,
|
||||||
|
routes: [{ name: "PlayerTransfers" }],
|
||||||
|
},
|
||||||
|
followUp: {
|
||||||
|
name: "PlayerTabs",
|
||||||
|
params: { screen: "PlayerTransfers" },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
transferDraft: {
|
transferDraft: {
|
||||||
targetId: malikId,
|
targetId: malikId,
|
||||||
|
|
@ -332,11 +360,32 @@ export function buildScreenshotFixture(scene: ScreenshotScene): ScreenshotFixtur
|
||||||
session: createActiveSession(),
|
session: createActiveSession(),
|
||||||
navigationTarget: {
|
navigationTarget: {
|
||||||
root: "PlayerTabs",
|
root: "PlayerTabs",
|
||||||
params: {
|
state: {
|
||||||
screen: "PlayerChat",
|
index: 0,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: "PlayerChat",
|
||||||
|
state: {
|
||||||
|
index: 1,
|
||||||
|
routes: [
|
||||||
|
{ name: "ChatList" },
|
||||||
|
{
|
||||||
|
name: "ChatThread",
|
||||||
|
params: { chatId: "group-direct-malik" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
followUp: {
|
||||||
|
name: "PlayerTabs",
|
||||||
params: {
|
params: {
|
||||||
screen: "ChatThread",
|
screen: "PlayerChat",
|
||||||
params: { chatId: "group-direct-malik" },
|
params: {
|
||||||
|
screen: "ChatThread",
|
||||||
|
params: { chatId: "group-direct-malik" },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { AppState, type AppStateStatus } from "react-native";
|
import { AppState, type AppStateStatus } from "react-native";
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||||
import type { JoinResponse, SessionPreview, SessionSnapshot } from "../shared/types";
|
import type { JoinResponse, SessionPreview, SessionSnapshot } from "../shared/types";
|
||||||
|
|
@ -20,6 +20,7 @@ import {
|
||||||
} from "./connection";
|
} from "./connection";
|
||||||
|
|
||||||
const STORAGE_KEY = "negopoly:session";
|
const STORAGE_KEY = "negopoly:session";
|
||||||
|
const SCREENSHOT_STORAGE_KEY = "negopoly:screenshot-scene";
|
||||||
|
|
||||||
type StoredSession = {
|
type StoredSession = {
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
|
|
@ -51,12 +52,34 @@ async function clearStoredSession() {
|
||||||
await AsyncStorage.removeItem(STORAGE_KEY);
|
await AsyncStorage.removeItem(STORAGE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function readStoredScreenshotScene(): Promise<ScreenshotScene | null> {
|
||||||
|
try {
|
||||||
|
const raw = await AsyncStorage.getItem(SCREENSHOT_STORAGE_KEY);
|
||||||
|
return raw === "start" ||
|
||||||
|
raw === "lobby" ||
|
||||||
|
raw === "home" ||
|
||||||
|
raw === "transfers" ||
|
||||||
|
raw === "chat"
|
||||||
|
? raw
|
||||||
|
: null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function clearStoredScreenshotScene() {
|
||||||
|
await AsyncStorage.removeItem(SCREENSHOT_STORAGE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
export function useSessionManager() {
|
export function useSessionManager() {
|
||||||
const [sessionId, setSessionId] = useState("");
|
const [sessionId, setSessionId] = useState("");
|
||||||
const [sessionCode, setSessionCode] = useState("");
|
const [sessionCode, setSessionCode] = useState("");
|
||||||
const [playerId, setPlayerId] = useState("");
|
const [playerId, setPlayerId] = useState("");
|
||||||
const [session, setSession] = useState<SessionSnapshot | null>(null);
|
const [session, setSession] = useState<SessionSnapshot | null>(null);
|
||||||
const [screenshot, setScreenshot] = useState<ScreenshotFixture | null>(null);
|
const [screenshot, setScreenshot] = useState<ScreenshotFixture | null>(null);
|
||||||
|
const [bootstrapReady, setBootstrapReady] = useState(false);
|
||||||
|
const [pushRegistrationReady, setPushRegistrationReady] = useState(false);
|
||||||
|
const [screenshotBootstrapPending, setScreenshotBootstrapPending] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [connectionState, setConnectionState] =
|
const [connectionState, setConnectionState] =
|
||||||
useState<SessionConnectionState>("idle");
|
useState<SessionConnectionState>("idle");
|
||||||
|
|
@ -318,25 +341,59 @@ export function useSessionManager() {
|
||||||
screenshotRef.current = screenshot;
|
screenshotRef.current = screenshot;
|
||||||
}, [screenshot]);
|
}, [screenshot]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (screenshot) {
|
||||||
|
setScreenshotBootstrapPending(false);
|
||||||
|
}
|
||||||
|
}, [screenshot]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
sessionRef.current = session;
|
sessionRef.current = session;
|
||||||
}, [session]);
|
}, [session]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let mounted = true;
|
let mounted = true;
|
||||||
readStoredSession().then((stored) => {
|
(async () => {
|
||||||
if (!mounted || !stored || screenshotRef.current) return;
|
let enablePushRegistration = true;
|
||||||
setSessionId(stored.sessionId);
|
try {
|
||||||
setSessionCode(stored.sessionCode);
|
const screenshotScene = await readStoredScreenshotScene();
|
||||||
setPlayerId(stored.playerId);
|
if (!mounted) return;
|
||||||
});
|
if (screenshotScene) {
|
||||||
|
enablePushRegistration = false;
|
||||||
|
setScreenshotBootstrapPending(true);
|
||||||
|
await clearStoredScreenshotScene();
|
||||||
|
if (!mounted) return;
|
||||||
|
activateScreenshotScene(screenshotScene);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const stored = await readStoredSession();
|
||||||
|
if (!mounted || !stored || screenshotRef.current) return;
|
||||||
|
setSessionId(stored.sessionId);
|
||||||
|
setSessionCode(stored.sessionCode);
|
||||||
|
setPlayerId(stored.playerId);
|
||||||
|
} finally {
|
||||||
|
if (mounted) {
|
||||||
|
setPushRegistrationReady(enablePushRegistration);
|
||||||
|
setBootstrapReady(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
mounted = false;
|
mounted = false;
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (screenshot) return;
|
if (
|
||||||
|
!bootstrapReady ||
|
||||||
|
!pushRegistrationReady ||
|
||||||
|
screenshot ||
|
||||||
|
screenshotBootstrapPending ||
|
||||||
|
!sessionId ||
|
||||||
|
!playerId
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let mounted = true;
|
let mounted = true;
|
||||||
registerForPushNotificationsAsync().then((token) => {
|
registerForPushNotificationsAsync().then((token) => {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
@ -345,7 +402,14 @@ export function useSessionManager() {
|
||||||
return () => {
|
return () => {
|
||||||
mounted = false;
|
mounted = false;
|
||||||
};
|
};
|
||||||
}, [screenshot]);
|
}, [
|
||||||
|
bootstrapReady,
|
||||||
|
playerId,
|
||||||
|
pushRegistrationReady,
|
||||||
|
screenshot,
|
||||||
|
screenshotBootstrapPending,
|
||||||
|
sessionId,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (screenshot) return;
|
if (screenshot) return;
|
||||||
|
|
@ -423,9 +487,10 @@ export function useSessionManager() {
|
||||||
};
|
};
|
||||||
}, [playerId, screenshot, sessionId]);
|
}, [playerId, screenshot, sessionId]);
|
||||||
|
|
||||||
const activateScreenshotScene = useCallback((scene: ScreenshotScene) => {
|
function activateScreenshotScene(scene: ScreenshotScene) {
|
||||||
const fixture = buildScreenshotFixture(scene);
|
const fixture = buildScreenshotFixture(scene);
|
||||||
suppressReconnectRef.current = true;
|
suppressReconnectRef.current = true;
|
||||||
|
setPushRegistrationReady(false);
|
||||||
teardownConnection();
|
teardownConnection();
|
||||||
reconnectAttemptRef.current = 0;
|
reconnectAttemptRef.current = 0;
|
||||||
setReconnectAttempt(0);
|
setReconnectAttempt(0);
|
||||||
|
|
@ -438,7 +503,7 @@ export function useSessionManager() {
|
||||||
setSessionCode(fixture.sessionCode);
|
setSessionCode(fixture.sessionCode);
|
||||||
setPlayerId(fixture.playerId);
|
setPlayerId(fixture.playerId);
|
||||||
setSession(fixture.session);
|
setSession(fixture.session);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
async function registerPushTokenFor(targetSessionId: string, targetPlayerId: string) {
|
async function registerPushTokenFor(targetSessionId: string, targetPlayerId: string) {
|
||||||
if (!pushToken) return;
|
if (!pushToken) return;
|
||||||
|
|
|
||||||