只做flutter侧兜底
This commit is contained in:
parent
83fb6465f9
commit
4cf895b11e
@ -388,11 +388,8 @@ class BaishunJsBridge {
|
||||
static String buildConfigScript(
|
||||
BaishunBridgeConfigModel config, {
|
||||
String? jsCallbackPath,
|
||||
Map<String, dynamic> viewportPayload = const <String, dynamic>{},
|
||||
}) {
|
||||
final payload = jsonEncode(
|
||||
_mergeViewportPayload(config.toJson(), viewportPayload),
|
||||
);
|
||||
final payload = jsonEncode(config.toJson());
|
||||
final encodedCallbackPath = jsonEncode(jsCallbackPath?.trim() ?? '');
|
||||
return '''
|
||||
(function() {
|
||||
@ -440,15 +437,8 @@ class BaishunJsBridge {
|
||||
}
|
||||
window.__baishunLastConfig = config;
|
||||
window.baishunBridgeConfig = config;
|
||||
const viewport = config.viewport || config.nativeViewport || {};
|
||||
window.__baishunViewport = viewport;
|
||||
window.baishunViewport = viewport;
|
||||
window.NativeBridge = window.NativeBridge || {};
|
||||
window.NativeBridge.config = config;
|
||||
window.NativeBridge.viewport = viewport;
|
||||
window.NativeBridge.getViewport = function() {
|
||||
return viewport;
|
||||
};
|
||||
const callbackPath = explicitCallbackPath || window.__baishunLastJsCallback || '';
|
||||
let callbackInvoked = false;
|
||||
if (explicitCallbackPath) {
|
||||
@ -465,7 +455,6 @@ class BaishunJsBridge {
|
||||
gsp: config.gsp,
|
||||
code: maskText(config.code),
|
||||
codeLength: config.code ? String(config.code).length : 0,
|
||||
viewport: config.viewport || config.nativeViewport || null,
|
||||
callbackPath: callbackPath
|
||||
});
|
||||
}
|
||||
@ -497,30 +486,6 @@ class BaishunJsBridge {
|
||||
''';
|
||||
}
|
||||
|
||||
static Map<String, dynamic> _mergeViewportPayload(
|
||||
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'],
|
||||
};
|
||||
}
|
||||
|
||||
static String buildWalletUpdateScript({Map<String, dynamic>? payload}) {
|
||||
final safePayload = jsonEncode(
|
||||
payload ??
|
||||
|
||||
@ -172,14 +172,6 @@ class LeaderJsBridge {
|
||||
normalizedPayload.entry && typeof normalizedPayload.entry === 'object'
|
||||
? normalizedPayload.entry
|
||||
: {};
|
||||
const viewport =
|
||||
normalizedPayload.viewport && typeof normalizedPayload.viewport === 'object'
|
||||
? normalizedPayload.viewport
|
||||
: (
|
||||
launchConfig.viewport && typeof launchConfig.viewport === 'object'
|
||||
? launchConfig.viewport
|
||||
: {}
|
||||
);
|
||||
window.__leaderLaunchPayload = normalizedPayload;
|
||||
window.__leaderLaunchPayloadText = payloadText;
|
||||
window.leaderLaunchPayload = normalizedPayload;
|
||||
@ -187,21 +179,14 @@ class LeaderJsBridge {
|
||||
window.leaderLaunchConfig = launchConfig;
|
||||
window.__leaderLaunchEntry = entry;
|
||||
window.leaderLaunchEntry = entry;
|
||||
window.__leaderViewport = viewport;
|
||||
window.leaderViewport = viewport;
|
||||
window.NativeBridge = window.NativeBridge || {};
|
||||
window.NativeBridge.config = launchConfig;
|
||||
window.NativeBridge.launchConfig = launchConfig;
|
||||
window.NativeBridge.entry = entry;
|
||||
window.NativeBridge.viewport = viewport;
|
||||
window.NativeBridge.getConfig = function(callback) {
|
||||
invokeCallback(callback, launchConfig);
|
||||
return launchConfig;
|
||||
};
|
||||
window.NativeBridge.getViewport = function(callback) {
|
||||
invokeCallback(callback, viewport);
|
||||
return viewport;
|
||||
};
|
||||
window.NativeBridge.getLaunchPayload = function(callback) {
|
||||
invokeCallback(callback, normalizedPayload);
|
||||
return normalizedPayload;
|
||||
@ -222,8 +207,7 @@ class LeaderJsBridge {
|
||||
? String(launchConfig.code).slice(0, 6) + '***'
|
||||
: '',
|
||||
codeLength: launchConfig.code ? String(launchConfig.code).length : 0,
|
||||
entryUrl: entry.entryUrl || '',
|
||||
viewport: viewport
|
||||
entryUrl: entry.entryUrl || ''
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
const double roomGameDesignWidth = 750;
|
||||
@ -62,79 +64,74 @@ String resolveRoomGameScreenMode(
|
||||
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,
|
||||
String buildRoomGameNativeFitScript({
|
||||
required double visibleHeight,
|
||||
required double expectedHeight,
|
||||
}) {
|
||||
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);
|
||||
final options = jsonEncode(<String, dynamic>{
|
||||
'visibleHeight': _roundMetric(visibleHeight),
|
||||
'expectedHeight': _roundMetric(expectedHeight),
|
||||
});
|
||||
return '''
|
||||
(function() {
|
||||
const options = $options;
|
||||
const fitKey = '__roomGameNativeViewportFit';
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
function applyFit() {
|
||||
try {
|
||||
const visibleHeight = Number(options.visibleHeight) || window.innerHeight || 0;
|
||||
const expectedHeight = Number(options.expectedHeight) || 0;
|
||||
if (!document.body || !visibleHeight || !expectedHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, dynamic> mergeRoomGameViewportPayload(
|
||||
Map<String, dynamic> payload,
|
||||
Map<String, dynamic> viewport,
|
||||
) {
|
||||
if (viewport.isEmpty) {
|
||||
return payload;
|
||||
}
|
||||
const rawScale = visibleHeight / expectedHeight;
|
||||
const scale = Math.min(1, rawScale);
|
||||
window[fitKey] = {
|
||||
scale: scale,
|
||||
visibleHeight: visibleHeight,
|
||||
expectedHeight: expectedHeight,
|
||||
compact: scale < 0.999
|
||||
};
|
||||
|
||||
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'],
|
||||
};
|
||||
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) {
|
||||
|
||||
@ -105,6 +105,7 @@ class _BaishunGamePageState extends State<BaishunGamePage> {
|
||||
_didFinishPageLoad = true;
|
||||
_log('page_finished url=${_clip(url, 240)}');
|
||||
await _injectBridge(reason: 'page_finished');
|
||||
await _applyNativeViewportFit(reason: 'page_finished');
|
||||
},
|
||||
onWebResourceError: (WebResourceError error) {
|
||||
_log(
|
||||
@ -260,19 +261,18 @@ class _BaishunGamePageState extends State<BaishunGamePage> {
|
||||
_hasDeliveredLaunchConfig = true;
|
||||
final rawConfig = widget.launchModel.bridgeConfig;
|
||||
final config = _buildEffectiveBridgeConfig(rawConfig);
|
||||
final viewport = _buildViewportPayload();
|
||||
_log(
|
||||
'send_config jsCallback=${jsCallbackPath ?? ''} '
|
||||
'force=$force config=${_stringifyForLog(<String, dynamic>{..._buildConfigSummary(config, rawConfig: rawConfig), 'viewport': viewport})}',
|
||||
'force=$force config=${_stringifyForLog(_buildConfigSummary(config, rawConfig: rawConfig))}',
|
||||
);
|
||||
try {
|
||||
await _controller.runJavaScript(
|
||||
BaishunJsBridge.buildConfigScript(
|
||||
config,
|
||||
jsCallbackPath: jsCallbackPath,
|
||||
viewportPayload: viewport,
|
||||
),
|
||||
);
|
||||
await _applyNativeViewportFit(reason: 'send_config');
|
||||
} catch (error) {
|
||||
_log('send_config_error error=${_clip(error.toString(), 300)}');
|
||||
}
|
||||
@ -330,6 +330,7 @@ class _BaishunGamePageState extends State<BaishunGamePage> {
|
||||
_isLoading = false;
|
||||
_errorMessage = null;
|
||||
});
|
||||
await _applyNativeViewportFit(reason: 'game_loaded');
|
||||
break;
|
||||
case BaishunBridgeActions.gameRecharge:
|
||||
_log('game_recharge open_wallet');
|
||||
@ -611,45 +612,51 @@ class _BaishunGamePageState extends State<BaishunGamePage> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
String _resolveScreenMode() {
|
||||
return resolveRoomGameScreenMode(
|
||||
widget.game.launchParams,
|
||||
fullScreen: widget.game.fullScreen,
|
||||
);
|
||||
}
|
||||
|
||||
double _calculateWebViewHeight(BuildContext context) {
|
||||
final mediaQuery = MediaQuery.maybeOf(context);
|
||||
final screenSize = mediaQuery?.size ?? Size.zero;
|
||||
final safeHeight = _resolveSafeHeight();
|
||||
final fallbackHeight = screenSize.height * 0.5;
|
||||
final preferredHeight = _calculatePreferredWebViewHeight(context);
|
||||
final maxHeight = resolveRoomGameAvailableHeight(
|
||||
context,
|
||||
reservedTop: 12.w,
|
||||
);
|
||||
return clampRoomGameHeight(preferredHeight, maxHeight);
|
||||
}
|
||||
|
||||
double _calculatePreferredWebViewHeight(BuildContext context) {
|
||||
final mediaQuery = MediaQuery.maybeOf(context);
|
||||
final screenSize = mediaQuery?.size ?? Size.zero;
|
||||
final safeHeight = _resolveSafeHeight();
|
||||
final fallbackHeight = screenSize.height * 0.5;
|
||||
if (safeHeight <= 0 || screenSize.width <= 0) {
|
||||
return clampRoomGameHeight(fallbackHeight, maxHeight);
|
||||
return fallbackHeight;
|
||||
}
|
||||
|
||||
final ratio = roomGameDesignWidth / safeHeight;
|
||||
final webViewHeight = screenSize.width / ratio;
|
||||
return clampRoomGameHeight(webViewHeight, maxHeight);
|
||||
return screenSize.width / ratio;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _buildViewportPayload() {
|
||||
Future<void> _applyNativeViewportFit({String reason = 'manual'}) async {
|
||||
final topCrop = 28.w;
|
||||
final webViewHeight = _calculateWebViewHeight(context);
|
||||
final safeHeight = _resolveSafeHeight();
|
||||
return buildRoomGameViewportPayload(
|
||||
context,
|
||||
containerHeight: webViewHeight,
|
||||
dialogHeight: webViewHeight,
|
||||
topCrop: topCrop,
|
||||
screenMode: _resolveScreenMode(),
|
||||
safeHeight: safeHeight,
|
||||
designHeight: safeHeight > 0 ? safeHeight.toDouble() : null,
|
||||
actualWebViewHeight: webViewHeight + topCrop,
|
||||
final visibleHeight = _calculateWebViewHeight(context) + topCrop;
|
||||
final expectedHeight = _calculatePreferredWebViewHeight(context);
|
||||
if (expectedHeight <= visibleHeight + 1) {
|
||||
return;
|
||||
}
|
||||
_log(
|
||||
'native_fit reason=$reason visible=${visibleHeight.toStringAsFixed(1)} '
|
||||
'expected=${expectedHeight.toStringAsFixed(1)}',
|
||||
);
|
||||
try {
|
||||
await _controller.runJavaScript(
|
||||
buildRoomGameNativeFitScript(
|
||||
visibleHeight: visibleHeight,
|
||||
expectedHeight: expectedHeight,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
_log(
|
||||
'native_fit_error reason=$reason error=${_clip(error.toString(), 300)}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -215,10 +215,9 @@ class _LeaderGamePageState extends State<LeaderGamePage> {
|
||||
}
|
||||
try {
|
||||
await _controller.runJavaScript(
|
||||
LeaderJsBridge.bootstrapScript(
|
||||
launchPayload: _buildLaunchPayload(viewport: _buildViewportPayload()),
|
||||
),
|
||||
LeaderJsBridge.bootstrapScript(launchPayload: _buildLaunchPayload()),
|
||||
);
|
||||
await _applyNativeViewportFit(reason: reason);
|
||||
} catch (error) {
|
||||
_log(
|
||||
'inject_bridge_error reason=$reason error=${_clip(error.toString(), 300)}',
|
||||
@ -347,11 +346,7 @@ class _LeaderGamePageState extends State<LeaderGamePage> {
|
||||
}
|
||||
|
||||
double _calculateBodyHeight(BuildContext context, double headerHeight) {
|
||||
final mediaQuery = MediaQuery.maybeOf(context);
|
||||
final screenSize = mediaQuery?.size ?? Size.zero;
|
||||
final screenMode = _resolveScreenMode();
|
||||
final safeHeight = _resolveSafeHeight();
|
||||
final fallback = screenSize.width;
|
||||
final maxDialogHeight = resolveRoomGameAvailableHeight(
|
||||
context,
|
||||
reservedTop: 24.w,
|
||||
@ -365,19 +360,58 @@ class _LeaderGamePageState extends State<LeaderGamePage> {
|
||||
return maxBodyHeight;
|
||||
}
|
||||
|
||||
return clampRoomGameHeight(
|
||||
_calculatePreferredBodyHeight(context),
|
||||
maxBodyHeight,
|
||||
);
|
||||
}
|
||||
|
||||
double _calculatePreferredBodyHeight(BuildContext context) {
|
||||
final mediaQuery = MediaQuery.maybeOf(context);
|
||||
final screenSize = mediaQuery?.size ?? Size.zero;
|
||||
final screenMode = _resolveScreenMode();
|
||||
final safeHeight = _resolveSafeHeight();
|
||||
final fallback = screenSize.width;
|
||||
|
||||
if (safeHeight > 0 && screenSize.width > 0) {
|
||||
final ratio = roomGameDesignWidth / safeHeight;
|
||||
final bodyHeight = screenSize.width / ratio;
|
||||
return clampRoomGameHeight(bodyHeight, maxBodyHeight);
|
||||
return screenSize.width / ratio;
|
||||
}
|
||||
|
||||
if (screenMode == 'hd') {
|
||||
final bodyHeight =
|
||||
screenSize.width * _hdDesignHeight / roomGameDesignWidth;
|
||||
return clampRoomGameHeight(bodyHeight, maxBodyHeight);
|
||||
return screenSize.width * _hdDesignHeight / roomGameDesignWidth;
|
||||
}
|
||||
|
||||
return clampRoomGameHeight(fallback, maxBodyHeight);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
Future<void> _applyNativeViewportFit({String reason = 'manual'}) async {
|
||||
final screenMode = _resolveScreenMode();
|
||||
if (screenMode == 'full') {
|
||||
return;
|
||||
}
|
||||
final headerHeight = 44.w;
|
||||
final visibleHeight = _calculateBodyHeight(context, headerHeight);
|
||||
final expectedHeight = _calculatePreferredBodyHeight(context);
|
||||
if (expectedHeight <= visibleHeight + 1) {
|
||||
return;
|
||||
}
|
||||
_log(
|
||||
'native_fit reason=$reason visible=${visibleHeight.toStringAsFixed(1)} '
|
||||
'expected=${expectedHeight.toStringAsFixed(1)}',
|
||||
);
|
||||
try {
|
||||
await _controller.runJavaScript(
|
||||
buildRoomGameNativeFitScript(
|
||||
visibleHeight: visibleHeight,
|
||||
expectedHeight: expectedHeight,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
_log(
|
||||
'native_fit_error reason=$reason error=${_clip(error.toString(), 300)}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _log(String message) {
|
||||
@ -440,20 +474,14 @@ class _LeaderGamePageState extends State<LeaderGamePage> {
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> _buildLaunchPayload({
|
||||
Map<String, dynamic> viewport = const <String, dynamic>{},
|
||||
}) {
|
||||
final launchConfig = mergeRoomGameViewportPayload(
|
||||
widget.launchModel.launchConfig.toJson(),
|
||||
viewport,
|
||||
);
|
||||
final payload = <String, dynamic>{
|
||||
Map<String, dynamic> _buildLaunchPayload() {
|
||||
return <String, dynamic>{
|
||||
'provider': widget.launchModel.provider,
|
||||
'gameId': widget.launchModel.gameId,
|
||||
'providerGameId': widget.launchModel.providerGameId,
|
||||
'gameSessionId': widget.launchModel.gameSessionId,
|
||||
'entry': widget.launchModel.entry.toJson(),
|
||||
'launchConfig': launchConfig,
|
||||
'launchConfig': widget.launchModel.launchConfig.toJson(),
|
||||
'roomState': widget.launchModel.roomState.toJson(),
|
||||
'game': <String, dynamic>{
|
||||
'gameId': widget.game.gameId,
|
||||
@ -463,25 +491,6 @@ class _LeaderGamePageState extends State<LeaderGamePage> {
|
||||
'launchMode': widget.game.launchMode,
|
||||
},
|
||||
};
|
||||
return mergeRoomGameViewportPayload(payload, viewport);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _buildViewportPayload() {
|
||||
final headerHeight = 44.w;
|
||||
final bodyHeight = _calculateBodyHeight(context, headerHeight);
|
||||
final safeHeight = _resolveSafeHeight();
|
||||
return buildRoomGameViewportPayload(
|
||||
context,
|
||||
containerHeight: bodyHeight,
|
||||
dialogHeight: bodyHeight + headerHeight,
|
||||
headerHeight: headerHeight,
|
||||
screenMode: _resolveScreenMode(),
|
||||
safeHeight: safeHeight,
|
||||
designHeight:
|
||||
safeHeight > 0
|
||||
? safeHeight.toDouble()
|
||||
: (_resolveScreenMode() == 'hd' ? _hdDesignHeight : null),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _buildLaunchPayloadForLog() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user