import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import '../facade_controller.dart'; import '../helpers/misc.dart'; import 'device_method.dart'; import 'mobile_cocos_widget_controller.dart'; import 'cocos_widget_platform.dart'; int _nextCocosCreationId = 0; /// Android specific settings for [CocosWidget]. class AndroidCocosWidgetFlutter { /// Whether to render [CocosWidget] with a [AndroidViewSurface] to build the Flutter Cocos widget. /// /// This implementation uses hybrid composition to render the Flutter Cocos /// Widget on Android. This comes at the cost of some performance on Android /// versions below 10. See /// https://flutter.dev/docs/development/platform-integration/platform-views#performance for more /// information. /// /// Defaults to true. static bool get useAndroidViewSurface { final CocosWidgetPlatform platform = CocosWidgetPlatform.instance; if (platform is MethodChannelCocosWidget) { return platform.useAndroidViewSurface; } return false; } /// Set whether to render [CocosWidget] with a [AndroidViewSurface] to build the Flutter Cocos widget. /// /// This implementation uses hybrid composition to render the Cocos Widget /// Widget on Android. This comes at the cost of some performance on Android /// versions below 10. See /// https://flutter.dev/docs/development/platform-integration/platform-views#performance for more /// information. /// /// Defaults to true. static set useAndroidViewSurface(bool useAndroidViewSurface) { final CocosWidgetPlatform platform = CocosWidgetPlatform.instance; if (platform is MethodChannelCocosWidget) { platform.useAndroidViewSurface = useAndroidViewSurface; } } } typedef MobileCocosWidgetState = _CocosWidgetState; class CocosWidget extends StatefulWidget { CocosWidget({ Key? key, required this.onCocosCreated, this.onCocosMessage, this.fullscreen = false, this.enablePlaceholder = false, this.runImmediately = false, this.unloadOnDispose = false, this.printSetupLog = true, this.onCocosUnloaded, this.gestureRecognizers, this.placeholder, this.useAndroidViewSurface = false, this.onCocosSceneLoaded, this.uiLevel = 1, this.borderRadius = BorderRadius.zero, this.layoutDirection, this.hideStatus = false, this.webUrl, }); ///Event fires when the Cocos player is created. final CocosCreatedCallback onCocosCreated; /// WebGL url source. final String? webUrl; ///Event fires when the [CocosWidget] gets a message from Cocos. final CocosMessageCallback? onCocosMessage; ///Event fires when the [CocosWidget] gets a scene loaded from Cocos. final CocosSceneChangeCallback? onCocosSceneLoaded; ///Event fires when the [CocosWidget] Cocos player gets unloaded. final CocosUnloadCallback? onCocosUnloaded; final Set>? gestureRecognizers; /// Set to true to force Cocos to fullscreen final bool fullscreen; /// Set to true to force Cocos to fullscreen final bool hideStatus; /// Controls the layer in which Cocos widget is rendered in flutter (defaults to 1) final int uiLevel; /// This flag tells android to load Cocos as the flutter app starts (Android only) final bool runImmediately; /// This flag tells android to unload Cocos whenever widget is disposed final bool unloadOnDispose; /// This flag enables placeholder widget final bool enablePlaceholder; /// This flag enables placeholder widget final bool printSetupLog; /// This flag allows you use AndroidView instead of PlatformViewLink for android final bool? useAndroidViewSurface; /// This is just a helper to render a placeholder widget final Widget? placeholder; /// Border radius final BorderRadius borderRadius; /// The layout direction to use for the embedded view. /// /// If this is null, the ambient [Directionality] is used instead. If there is /// no ambient [Directionality], [TextDirection.ltr] is used. final TextDirection? layoutDirection; @override _CocosWidgetState createState() => _CocosWidgetState(); } class _CocosWidgetState extends State { late int _CocosId; CocosWidgetController? _controller; @override void initState() { super.initState(); if (!kIsWeb) { _CocosId = _nextCocosCreationId++; } else { _CocosId = 0; } } @override Future dispose() async { if (!kIsWeb) { if (_nextCocosCreationId > 0) --_nextCocosCreationId; } try { _controller?.dispose(); _controller = null; } catch (e) { // todo: implement } super.dispose(); } @override Widget build(BuildContext context) { final Map CocosOptions = { 'fullscreen': widget.fullscreen, 'uiLevel': widget.uiLevel, 'hideStatus': widget.hideStatus, 'unloadOnDispose': widget.unloadOnDispose, 'runImmediately': widget.runImmediately, }; if (widget.enablePlaceholder) { return widget.placeholder ?? Text('Placeholder mode enabled, no native code will be called'); } return CocosWidgetPlatform.instance.buildViewWithTextDirection( _CocosId, _onPlatformViewCreated, cocosOptions: CocosOptions, textDirection: widget.layoutDirection ?? Directionality.maybeOf(context) ?? TextDirection.ltr, gestureRecognizers: widget.gestureRecognizers, useAndroidViewSurf: widget.useAndroidViewSurface, cocosSrcUrl: widget.webUrl, ); } Future _onPlatformViewCreated(int id) async { final controller = await MobileCocosWidgetController.init(id, this); _controller = controller; widget.onCocosCreated(controller); if (widget.printSetupLog) { log('*********************************************'); log('** flutter Cocos controller setup complete **'); log('*********************************************'); } } }