Plein écran : attente bornée, repli tourné si l'écran reste en portrait, paysage forcé en mode immersif ; plan : résultat et corrections de la recette

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Pierre MARTIN
2026-11-03 15:40:53 +01:00
co-authored by Claude Opus 5.5
parent b8c2997ec0
commit 155a953c3b
3 changed files with 87 additions and 16 deletions
+27 -6
View File
@@ -52,6 +52,8 @@ const SLIDE_MS = 160;
const PAUSE_MS = 120;
/** Durée du bandeau « Reprendre l'ancienne ». */
export const BANNER_MS = 10_000;
/** Attente au plus de la réponse à une demande de plein écran. */
const FULLSCREEN_WAIT_MS = 1000;
/** Le dernier plateau affiché, gardé pour le redessiner dès l'ouverture. */
export interface CachedBoard {
@@ -276,7 +278,12 @@ export function startApp(options: AppOptions): void {
// ----------------------------------------------------------- Mise en page
function layout(): Layout {
return rotatedActive() || landscapeQuery.matches ? "landscape" : "portrait";
// Plein écran demandé (« le plateau est l'écran ») : paysage dès que
// l'écran est plus large que haut, quelle que soit sa taille.
const immersiveLandscape = immersive && !portraitQuery.matches;
return rotatedActive() || landscapeQuery.matches || immersiveLandscape
? "landscape"
: "portrait";
}
function rotatedActive(): boolean {
@@ -970,25 +977,39 @@ export function startApp(options: AppOptions): void {
// ------------------------------------------------- Plein écran (ADR 0012)
async function enterImmersive(): Promise<void> {
// Certains navigateurs ne répondent jamais à la demande (Firefox sans
// écran) : on n'attend pas plus d'une seconde, la vue paysage
// s'applique quand même.
try {
await document.documentElement.requestFullscreen?.({ navigationUI: "hide" });
await Promise.race([
document.documentElement.requestFullscreen?.({ navigationUI: "hide" }),
new Promise((resolve) => setTimeout(resolve, FULLSCREEN_WAIT_MS)),
]);
} catch {
// Refusé : la vue paysage s'applique quand même.
}
let locked = false;
let locked = false; // vrai : le navigateur a accepté de verrouiller
try {
const orientation = screen.orientation as unknown as {
lock?: (orientation: string) => Promise<void>;
};
if (orientation.lock !== undefined) {
await orientation.lock("landscape");
await Promise.race([
orientation.lock("landscape"),
new Promise((_, reject) => setTimeout(reject, FULLSCREEN_WAIT_MS)),
]);
locked = true;
}
} catch {
// Verrouillage refusé : repli par rotation CSS ci-dessous.
}
// Verrouillage accepté : l'écran tourne dans l'instant. S'il est
// toujours en portrait (navigateur qui accepte sans tourner), repli.
for (let i = 0; locked && portraitQuery.matches && i < 6; i++) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
immersive = true;
rotated = !locked && portraitQuery.matches;
rotated = portraitQuery.matches;
render();
}
@@ -1000,10 +1021,10 @@ export function startApp(options: AppOptions): void {
} catch {
// Rien à déverrouiller.
}
render();
if (document.fullscreenElement) {
await document.exitFullscreen().catch(() => undefined);
}
render();
}
// Sortie du plein écran par le retour du téléphone : la vue revient.