import 'dart:convert'; import 'package:flutter/material.dart'; const double roomGameDesignWidth = 750; double resolveRoomGameAvailableHeight( BuildContext context, { double reservedTop = 12, }) { final mediaQuery = MediaQuery.maybeOf(context); if (mediaQuery == null) { return 0; } final bottomInset = mediaQuery.viewInsets.bottom > mediaQuery.padding.bottom ? mediaQuery.viewInsets.bottom : mediaQuery.padding.bottom; final availableHeight = mediaQuery.size.height - mediaQuery.padding.top - bottomInset - reservedTop; if (!availableHeight.isFinite || availableHeight <= 0) { return mediaQuery.size.height; } return availableHeight.clamp(0.0, mediaQuery.size.height).toDouble(); } double clampRoomGameHeight( double value, double maxHeight, { double minHeight = 0, }) { if (!value.isFinite || value <= 0) { return maxHeight > 0 ? maxHeight : 0; } if (!maxHeight.isFinite || maxHeight <= 0) { return value; } if (minHeight > maxHeight) { return maxHeight; } return value.clamp(minHeight, maxHeight).toDouble(); } String resolveRoomGameScreenMode( Map launchParams, { required bool fullScreen, }) { final candidates = [ launchParams['screenMode']?.toString() ?? '', launchParams['screen_mode']?.toString() ?? '', launchParams['displayMode']?.toString() ?? '', launchParams['gameScreenMode']?.toString() ?? '', ]; for (final candidate in candidates) { final trimmed = candidate.trim(); if (trimmed.isNotEmpty) { return trimmed.toLowerCase(); } } return fullScreen ? 'full' : 'half'; } String buildRoomGameNativeFitScript({ required double visibleHeight, required double expectedHeight, }) { final options = jsonEncode({ 'visibleHeight': _roundMetric(visibleHeight), 'expectedHeight': _roundMetric(expectedHeight), }); return ''' (function() { const options = $options; const fitKey = '__roomGameNativeViewportFit'; function applyFit() { try { const visibleHeight = Number(options.visibleHeight) || window.innerHeight || 0; const expectedHeight = Number(options.expectedHeight) || 0; if (!document.body || !visibleHeight || !expectedHeight) { return; } const rawScale = visibleHeight / expectedHeight; const scale = Math.min(1, rawScale); window[fitKey] = { scale: scale, visibleHeight: visibleHeight, expectedHeight: expectedHeight, compact: scale < 0.999 }; if (scale >= 0.999) { document.documentElement.style.overflow = ''; document.body.style.overflow = ''; document.body.style.transform = ''; document.body.style.transformOrigin = ''; document.body.style.width = ''; document.body.style.minHeight = ''; document.documentElement.removeAttribute('data-room-game-native-fit'); return; } document.documentElement.setAttribute('data-room-game-native-fit', 'true'); document.documentElement.style.overflow = 'hidden'; document.body.style.overflow = 'hidden'; document.body.style.transform = 'scale(' + scale + ')'; document.body.style.transformOrigin = 'top left'; document.body.style.width = (100 / scale) + '%'; document.body.style.minHeight = expectedHeight + 'px'; } catch (_) {} } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', applyFit, { once: true }); } else { applyFit(); } [50, 250, 800, 1600, 3000].forEach(function(delay) { window.setTimeout(applyFit, delay); }); if (!window.__roomGameNativeFitResizeReady) { window.__roomGameNativeFitResizeReady = true; window.addEventListener('resize', applyFit, true); window.addEventListener('orientationchange', function() { window.setTimeout(applyFit, 120); }, true); } })(); '''; } double _roundMetric(double value) { if (!value.isFinite) { return 0; } return double.parse(value.toStringAsFixed(2)); }