Compare commits

...

2 Commits

Author SHA1 Message Date
min
4fe86ee723 Merge pull request 'feat(player): �� ���������� fullscreen-������� � �������� ���������� (APK/desktop)' (#34) from feat/player-native-app-no-fs-prompt-2026-06-15 into main
All checks were successful
CI / Lint (push) Successful in 58s
CI / Build (push) Successful in 1m32s
CI / Secret scan (push) Successful in 21s
CI / PR size check (push) Has been skipped
CI / Deploy to S1 + S2 (push) Successful in 3m1s
2026-06-15 19:25:05 +00:00
min
86620eee1c feat(player): не показывать fullscreen-оверлей в нативном приложении
All checks were successful
CI / Lint (pull_request) Successful in 56s
CI / Build (pull_request) Successful in 1m36s
CI / Secret scan (pull_request) Successful in 24s
CI / PR size check (pull_request) Successful in 7s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
В Android-приложении (Capacitor) и десктопе (Electron) WebView/окно уже
на весь экран — стартовый оверлей «Нажми чтобы играть» избыточен (в
браузере он нужен для user-gesture перед fullscreen, в нативе барьера нет).
Теперь в нативном приложении игра запускается сразу:
- IS_ANDROID_APP: детект по window.Capacitor + метке RubloxAndroid в UA;
- IS_NATIVE_APP = desktop || android;
- gameStarted инициализируется true в нативе → оверлей пропускается;
- handleGameStart/handleMobileStart не дёргают requestFullscreen в нативе.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:14:26 +03:00

View File

@ -31,6 +31,18 @@ import GameLoadingScreen from './GameLoadingScreen';
// preload выставляет window.__RUBLOX_DESKTOP__. // preload выставляет window.__RUBLOX_DESKTOP__.
const IS_DESKTOP_APP = typeof window !== 'undefined' && !!window.__RUBLOX_DESKTOP__; const IS_DESKTOP_APP = typeof window !== 'undefined' && !!window.__RUBLOX_DESKTOP__;
// В Android-приложении (Capacitor-обёртка rublox-android) WebView уже на весь
// экран браузерный fullscreen не нужен, а стартовый оверлей «Нажми чтобы
// играть» избыточен (в браузере он нужен для user-gesture перед FS, в APK
// этого барьера не требуется). Capacitor выставляет window.Capacitor.
const IS_ANDROID_APP = typeof window !== 'undefined'
&& (!!window.Capacitor
|| /RubloxAndroid/i.test(navigator.userAgent || ''));
// Объединённый признак «нативного приложения» (десктоп ИЛИ Android) там,
// где поведение совпадает (не дёргать fullscreen).
const IS_NATIVE_APP = IS_DESKTOP_APP || IS_ANDROID_APP;
// Плеер живёт на player.rublox.pro он не знает SPA-роутов Майнкрафтии // Плеер живёт на player.rublox.pro он не знает SPA-роутов Майнкрафтии
// (/kubikon, /login, /auth). Поэтому вместо navigate(...) делаем // (/kubikon, /login, /auth). Поэтому вместо navigate(...) делаем
// явный window.location.assign на внешний домен. // явный window.location.assign на внешний домен.
@ -236,7 +248,10 @@ const KubikonPlayer = () => {
// ВКЛЮЧИТЬ fullscreen и заблокировать Ctrl+W/Ctrl+T и др. системные // ВКЛЮЧИТЬ fullscreen и заблокировать Ctrl+W/Ctrl+T и др. системные
// хоткеи. Без этого браузер закрывает вкладку при случайном Ctrl+W. // хоткеи. Без этого браузер закрывает вкладку при случайном Ctrl+W.
// requestFullscreen() требует user gesture поэтому без клика никак. // requestFullscreen() требует user gesture поэтому без клика никак.
const [gameStarted, setGameStarted] = useState(false); // В нативном приложении (Electron/Capacitor) fullscreen не нужен (окно и
// так на весь экран), поэтому стартовый оверлей пропускаем игра
// запускается сразу.
const [gameStarted, setGameStarted] = useState(IS_NATIVE_APP);
const [hp, setHp] = useState({ hp: 100, maxHp: 100 }); const [hp, setHp] = useState({ hp: 100, maxHp: 100 });
// Скрипт через game.hud.setVisible(false) полностью скрывает стандартный HUD. // Скрипт через game.hud.setVisible(false) полностью скрывает стандартный HUD.
const [stdHudVisible, setStdHudVisible] = useState(true); const [stdHudVisible, setStdHudVisible] = useState(true);
@ -1130,8 +1145,9 @@ const KubikonPlayer = () => {
|| root.webkitRequestFullscreen || root.webkitRequestFullscreen
|| root.mozRequestFullScreen || root.mozRequestFullScreen
|| root.msRequestFullscreen; || root.msRequestFullscreen;
// В десктоп-приложении окно и так на весь экран FS не нужен. // В нативном приложении (Electron/Capacitor) окно и так на весь
if (req && !IS_DESKTOP_APP) { // экран FS не нужен.
if (req && !IS_NATIVE_APP) {
try { await req.call(root); } catch (e) { /* отменено */ } try { await req.call(root); } catch (e) { /* отменено */ }
} }
setMobileStartTapped(true); setMobileStartTapped(true);
@ -1139,14 +1155,14 @@ const KubikonPlayer = () => {
/** Стартовый клик «Начать игру» запрашивает fullscreen /** Стартовый клик «Начать игру» запрашивает fullscreen
* (Chrome блокирует Ctrl+W/Ctrl+T в fullscreen) и снимает оверлей. * (Chrome блокирует Ctrl+W/Ctrl+T в fullscreen) и снимает оверлей.
* В десктоп-приложении FS не нужен (нет вкладок браузера). */ * В нативном приложении (Electron/Capacitor) FS не нужен. */
const handleGameStart = useCallback(async () => { const handleGameStart = useCallback(async () => {
const root = document.documentElement; const root = document.documentElement;
const req = root.requestFullscreen const req = root.requestFullscreen
|| root.webkitRequestFullscreen || root.webkitRequestFullscreen
|| root.mozRequestFullScreen || root.mozRequestFullScreen
|| root.msRequestFullscreen; || root.msRequestFullscreen;
if (req && !IS_DESKTOP_APP) { if (req && !IS_NATIVE_APP) {
try { await req.call(root); } catch (e) { /* юзер запретил — играем без FS */ } try { await req.call(root); } catch (e) { /* юзер запретил — играем без FS */ }
} }
setGameStarted(true); setGameStarted(true);