launch method

Future<void> launch(
  1. BuildContext context, {
  2. EdgeInsets padding = EdgeInsets.zero,
})

Implementation

Future<void> launch(
    BuildContext context, {
      EdgeInsets padding = EdgeInsets.zero,
    }) async {
  OverlayState? overlayState = Overlay.of(context);
  if (userToken.isEmpty) {
    print('Error: Token not available.');
    return;
  }
  // If an external teardown removed the overlay without clearing our reference, reset it.
  if (overlayEntry != null && overlayEntry?.mounted == false) {
    overlayEntry = null;
  }
  // Prevent multiple overlays from stacking
  if (isOverviewVisible) {
    return;
  }
  // Choose WebView host based on the selected environment to avoid token/env mismatches
  final String webviewHost = (() {
    switch (_environment) {
      case 'staging':
        return 'webview-staging.promptbet.ai';
      case 'dev':
        return 'webview-dev.promptbet.ai';
      default:
        return 'webview.promptbet.ai';
    }
  })();
  overlayEntry = OverlayEntry(
    builder: (BuildContext context) {
      return SafeArea(
        child: Padding(
          padding: MediaQuery.of(context).viewInsets.bottom > 0 ? padding.copyWith(bottom: 0) : padding,
          child: Scaffold(
            backgroundColor: Colors.transparent,
            resizeToAvoidBottomInset: true,
            body: InAppWebView(
              initialUrlRequest: URLRequest(
                url: WebUri.uri(Uri.https(
                    webviewHost,
                    '/',
                    {
                      'isNative': 'true',
                      'token': userToken,
                      'sdkVersion': sdkVersion,
                    })),
              ),
              initialSettings: InAppWebViewSettings(
                javaScriptEnabled: true,
                domStorageEnabled: true,
                databaseEnabled: true,
                cacheEnabled: true,
                clearCache: false,
                sharedCookiesEnabled: true,
                thirdPartyCookiesEnabled: true,
                incognito: false,
                disableDefaultErrorPage: false,
                supportZoom: false,
                builtInZoomControls: false,
                displayZoomControls: false,
                useWideViewPort: false,
                loadWithOverviewMode: false,
                hardwareAcceleration: true,
              ),
              onConsoleMessage: (controller, consoleMessage) {
                print(consoleMessage);
              },
              onLoadStop: (controller, url) async {
                print("WebView loaded: $url");
                await controller.evaluateJavascript(source: """
                            window.addEventListener('message', function(event) {
                              if (event.source === window.parent) {
                                window.flutter_inappwebview.callHandler('onParentMessage', event.data);
                              }
                            });
                          """);
              },
              onWebViewCreated: (controller) {
                _webViewController = controller;
                controller.addJavaScriptHandler(
                  handlerName: 'onParentMessage',
                  callback: (args) async {
                    try {
                      if (args.isEmpty || args[0] == null || args[0] is! Map) {
                        print("Invalid message payload from window.parent: $args");
                        return;
                      }
                      final dynamic messageData = args[0];
                      print("Message received from window.parent: $messageData");
                      if (messageData['type'] == 'close') {
                        if (messageData['reason'] != 'completed' && isOverviewVisible) {
                          closeDialog();
                        }
                      } else if (messageData['type'] == 'consent') {
                        await _handleConsent();
                      } else if (messageData['type'] == 'mic-start') {
                        // Assume conversationId is always provided by caller
                        final String conversationId = messageData['conversationId'].toString();
                        await _startStreaming(conversationId: conversationId);
                      } else if (messageData['type'] == 'mic-end') {
                        await _stopStreaming();
                      } else if (messageData['type'] == 'play-audio') {
                        final dynamic url = messageData['url'] ?? messageData['src'] ?? messageData['audio'] ?? messageData['value'];
                        if (url is String && url.isNotEmpty) {
                          await _playAudioUrl(url);
                        } else {
                          print('play-audio event missing valid url');
                        }
                      } else if (messageData['type'] == 'stop-audio') {
                        try {
                          await _audioPlayer.stop();
                          await _notifyWeb(
                              'audioPlaybackStatusFromApp', "false");
                        } catch (e) {
                          print('Error stopping audio: $e');
                          await _notifyWeb(
                              'audioPlaybackStatusFromApp', "false");
                        }
                      } else if (messageData['type'] == 'bet') {
                        callbackFn(messageData as Map<String, dynamic>);
                      } else {
                        callbackFn(messageData as Map<String, dynamic>);
                      }
                    } catch (e) {
                      print('Error handling parent message: $e');
                    }
                  },
                );
              },
            ),
          ),
        ),
      );
    },
  );
  overlayState.insert(overlayEntry!);
}