yumi-flutter/lib/modules/room_game/utils/room_game_viewport.dart

146 lines
4.4 KiB
Dart

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<String, dynamic> launchParams, {
required bool fullScreen,
}) {
final candidates = <String>[
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';
}
Map<String, dynamic> buildRoomGameViewportPayload(
BuildContext context, {
required double containerHeight,
double? dialogHeight,
double headerHeight = 0,
double topCrop = 0,
required String screenMode,
required int safeHeight,
double designWidth = roomGameDesignWidth,
double? designHeight,
double? actualWebViewHeight,
}) {
final mediaQuery = MediaQuery.maybeOf(context);
final size = mediaQuery?.size ?? Size.zero;
final padding = mediaQuery?.padding ?? EdgeInsets.zero;
final viewInsets = mediaQuery?.viewInsets ?? EdgeInsets.zero;
final targetDesignHeight =
designHeight ?? (safeHeight > 0 ? safeHeight.toDouble() : null);
final expectedHeight =
targetDesignHeight != null && size.width > 0 && designWidth > 0
? size.width * targetDesignHeight / designWidth
: null;
final availableHeight = resolveRoomGameAvailableHeight(context);
return <String, dynamic>{
'containerWidth': _roundMetric(size.width),
'containerHeight': _roundMetric(containerHeight),
'visibleHeight': _roundMetric(containerHeight),
'webViewHeight': _roundMetric(actualWebViewHeight ?? containerHeight),
'dialogHeight': _roundMetric(
dialogHeight ?? containerHeight + headerHeight,
),
'screenHeight': _roundMetric(size.height),
'headerHeight': _roundMetric(headerHeight),
'topCrop': _roundMetric(topCrop),
'safeAreaTop': _roundMetric(padding.top),
'safeAreaBottom': _roundMetric(padding.bottom),
'viewInsetBottom': _roundMetric(viewInsets.bottom),
'availableHeight': _roundMetric(availableHeight),
'devicePixelRatio': _roundMetric(mediaQuery?.devicePixelRatio ?? 1),
'screenMode': screenMode,
'isCompactViewport':
expectedHeight != null ? containerHeight + 1 < expectedHeight : false,
'designWidth': _roundMetric(designWidth),
if (targetDesignHeight != null)
'designHeight': _roundMetric(targetDesignHeight),
'safeHeight': safeHeight,
};
}
Map<String, dynamic> mergeRoomGameViewportPayload(
Map<String, dynamic> payload,
Map<String, dynamic> viewport,
) {
if (viewport.isEmpty) {
return payload;
}
return <String, dynamic>{
...payload,
'viewport': viewport,
'nativeViewport': viewport,
'containerWidth': viewport['containerWidth'],
'containerHeight': viewport['containerHeight'],
'visibleHeight': viewport['visibleHeight'],
'webViewHeight': viewport['webViewHeight'],
'dialogHeight': viewport['dialogHeight'],
'safeAreaTop': viewport['safeAreaTop'],
'safeAreaBottom': viewport['safeAreaBottom'],
'devicePixelRatio': viewport['devicePixelRatio'],
'screenMode': viewport['screenMode'],
'isCompactViewport': viewport['isCompactViewport'],
};
}
double _roundMetric(double value) {
if (!value.isFinite) {
return 0;
}
return double.parse(value.toStringAsFixed(2));
}