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'; } double resolveRoomGameCompatibilityBottomHeight(BuildContext context) { final mediaQuery = MediaQuery.maybeOf(context); if (mediaQuery == null) { return 0; } return (mediaQuery.size.width * 0.19).clamp(56.0, 88.0).toDouble(); } class RoomGameCompatibilityBottomFrame extends StatelessWidget { const RoomGameCompatibilityBottomFrame({super.key, required this.height}); final double height; @override Widget build(BuildContext context) { if (height <= 0) { return const SizedBox.shrink(); } return SizedBox( height: height, width: double.infinity, child: CustomPaint(painter: _RoomGameBottomFramePainter()), ); } } class _RoomGameBottomFramePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final frameRect = Offset.zero & size; final backgroundPaint = Paint() ..shader = const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFF0E392E), Color(0xFF082A23)], ).createShader(frameRect); canvas.drawRect(frameRect, backgroundPaint); canvas.save(); canvas.clipRect(frameRect); final patternPaint = Paint() ..color = const Color(0xFF2C5B4A).withValues(alpha: 0.20) ..style = PaintingStyle.stroke ..strokeWidth = 1.5; final motifWidth = size.width / 8; final motifHeight = size.height / 2.4; for (double x = -motifWidth; x < size.width + motifWidth; x += motifWidth) { for ( double y = -motifHeight * 0.2; y < size.height + motifHeight; y += motifHeight * 0.72 ) { final rect = Rect.fromCenter( center: Offset(x + motifWidth * 0.52, y + motifHeight * 0.55), width: motifWidth * 0.9, height: motifHeight, ); canvas.drawArc(rect, -0.35, 4.5, false, patternPaint); canvas.drawArc( rect.translate(motifWidth * 0.34, 0), 2.75, 3.6, false, patternPaint, ); } } canvas.restore(); final borderPaint = Paint() ..color = const Color(0xFFE9D58A) ..style = PaintingStyle.stroke ..strokeWidth = 3; final innerBorderPaint = Paint() ..color = const Color(0xFF8F7136).withValues(alpha: 0.75) ..style = PaintingStyle.stroke ..strokeWidth = 1; canvas.drawRect(frameRect.deflate(1.5), borderPaint); canvas.drawRect(frameRect.deflate(5), innerBorderPaint); final highlightPaint = Paint() ..shader = const LinearGradient( colors: [ Color(0x00F6E8A7), Color(0x99F6E8A7), Color(0x00F6E8A7), ], ).createShader(Rect.fromLTWH(0, 0, size.width, 3)); canvas.drawRect(Rect.fromLTWH(0, 0, size.width, 3), highlightPaint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }