parent
24fc4c113d
commit
a8f3ce3307
@ -1,17 +0,0 @@ |
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter/services.dart'; |
||||
|
||||
import 'flutter_cocos_view_platform_interface.dart'; |
||||
|
||||
/// An implementation of [FlutterCocosViewPlatform] that uses method channels. |
||||
class MethodChannelFlutterCocosView extends FlutterCocosViewPlatform { |
||||
/// The method channel used to interact with the native platform. |
||||
@visibleForTesting |
||||
final methodChannel = const MethodChannel('flutter_cocos_view'); |
||||
|
||||
@override |
||||
Future<String?> getPlatformVersion() async { |
||||
final version = await methodChannel.invokeMethod<String>('getPlatformVersion'); |
||||
return version; |
||||
} |
||||
} |
@ -1,29 +0,0 @@ |
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; |
||||
|
||||
import 'flutter_cocos_view_method_channel.dart'; |
||||
|
||||
abstract class FlutterCocosViewPlatform extends PlatformInterface { |
||||
/// Constructs a FlutterCocosViewPlatform. |
||||
FlutterCocosViewPlatform() : super(token: _token); |
||||
|
||||
static final Object _token = Object(); |
||||
|
||||
static FlutterCocosViewPlatform _instance = MethodChannelFlutterCocosView(); |
||||
|
||||
/// The default instance of [FlutterCocosViewPlatform] to use. |
||||
/// |
||||
/// Defaults to [MethodChannelFlutterCocosView]. |
||||
static FlutterCocosViewPlatform get instance => _instance; |
||||
|
||||
/// Platform-specific implementations should set this with their own |
||||
/// platform-specific class that extends [FlutterCocosViewPlatform] when |
||||
/// they register themselves. |
||||
static set instance(FlutterCocosViewPlatform instance) { |
||||
PlatformInterface.verifyToken(instance, _token); |
||||
_instance = instance; |
||||
} |
||||
|
||||
Future<String?> getPlatformVersion() { |
||||
throw UnimplementedError('platformVersion() has not been implemented.'); |
||||
} |
||||
} |
@ -0,0 +1,103 @@ |
||||
typedef void CocosCreatedCallback(CocosWidgetController controller); |
||||
|
||||
abstract class CocosWidgetController { |
||||
static dynamic webRegistrar; |
||||
|
||||
/// Method required for web initialization |
||||
static void registerWith(dynamic registrar) { |
||||
webRegistrar = registrar; |
||||
} |
||||
|
||||
/// Initialize [CocosWidgetController] with [id] |
||||
/// Mainly for internal use when instantiating a [CocosWidgetController] passed |
||||
/// in [CocosWidget.onCocosCreated] callback. |
||||
static Future<CocosWidgetController> init( |
||||
int id, dynamic CocosWidgetState) async { |
||||
throw UnimplementedError('init() has not been implemented.'); |
||||
} |
||||
|
||||
/// Checks to see if Cocos player is ready to be used |
||||
/// Returns `true` if Cocos player is ready. |
||||
Future<bool?>? isReady() { |
||||
throw UnimplementedError('isReady() has not been implemented.'); |
||||
} |
||||
|
||||
/// Get the current pause state of the Cocos player |
||||
/// Returns `true` if Cocos player is paused. |
||||
Future<bool?>? isPaused() { |
||||
throw UnimplementedError('isPaused() has not been implemented.'); |
||||
} |
||||
|
||||
/// Get the current load state of the Cocos player |
||||
/// Returns `true` if Cocos player is loaded. |
||||
Future<bool?>? isLoaded() { |
||||
throw UnimplementedError('isLoaded() has not been implemented.'); |
||||
} |
||||
|
||||
/// Helper method to know if Cocos has been put in background mode (WIP) unstable |
||||
/// Returns `true` if Cocos player is in background. |
||||
Future<bool?>? inBackground() { |
||||
throw UnimplementedError('inBackground() has not been implemented.'); |
||||
} |
||||
|
||||
/// Creates a Cocos player if it's not already created. Please only call this if Cocos is not ready, |
||||
/// or is in unloaded state. Use [isLoaded] to check. |
||||
/// Returns `true` if Cocos player was created succesfully. |
||||
Future<bool?>? create() { |
||||
throw UnimplementedError('create() has not been implemented.'); |
||||
} |
||||
|
||||
/// Post message to Cocos from flutter. This method takes in a string [message]. |
||||
/// The [gameObject] must match the name of an actual Cocos game object in a scene at runtime, and the [methodName], |
||||
/// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method |
||||
/// |
||||
/// ```dart |
||||
/// postMessage("GameManager", "openScene", "ThirdScene") |
||||
/// ``` |
||||
Future<void>? postMessage(String gameObject, methodName, message) { |
||||
throw UnimplementedError('postMessage() has not been implemented.'); |
||||
} |
||||
|
||||
/// Post message to Cocos from flutter. This method takes in a Json or map structure as the [message]. |
||||
/// The [gameObject] must match the name of an actual Cocos game object in a scene at runtime, and the [methodName], |
||||
/// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method |
||||
/// |
||||
/// ```dart |
||||
/// postJsonMessage("GameManager", "openScene", {"buildIndex": 3, "name": "ThirdScene"}) |
||||
/// ``` |
||||
Future<void>? postJsonMessage( |
||||
String gameObject, String methodName, Map<String, dynamic> message) { |
||||
throw UnimplementedError('postJsonMessage() has not been implemented.'); |
||||
} |
||||
|
||||
/// Pause the Cocos in-game player with this method |
||||
Future<void>? pause() { |
||||
throw UnimplementedError('pause() has not been implemented.'); |
||||
} |
||||
|
||||
/// Resume the Cocos in-game player with this method idf it is in a paused state |
||||
Future<void>? resume() { |
||||
throw UnimplementedError('resume() has not been implemented.'); |
||||
} |
||||
|
||||
/// Sometimes you want to open Cocos in it's own process and openInNativeProcess does just that. |
||||
/// It works for Android and iOS is WIP |
||||
Future<void>? openInNativeProcess() { |
||||
throw UnimplementedError('openInNativeProcess() has not been implemented.'); |
||||
} |
||||
|
||||
/// Unloads Cocos player from th current process (Works on Android only for now) |
||||
/// iOS is WIP. For more information please read [Cocos Docs](https://docs.Cocos3d.com/2020.2/Documentation/Manual/CocosasaLibrary.html) |
||||
Future<void>? unload() { |
||||
throw UnimplementedError('unload() has not been implemented.'); |
||||
} |
||||
|
||||
/// Quits Cocos player. Note that this kills the current flutter process, thus quiting the app |
||||
Future<void>? quit() { |
||||
throw UnimplementedError('quit() has not been implemented.'); |
||||
} |
||||
|
||||
void dispose() { |
||||
throw UnimplementedError('dispose() has not been implemented.'); |
||||
} |
||||
} |
@ -0,0 +1,89 @@ |
||||
import 'package:flutter/cupertino.dart'; |
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter/gestures.dart'; |
||||
import 'package:flutter_cocos_view/src/facade_controller.dart'; |
||||
|
||||
import 'helpers/misc.dart'; |
||||
|
||||
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, |
||||
}); |
||||
|
||||
///Event fires when the Cocos player is created. |
||||
final CocosCreatedCallback onCocosCreated; |
||||
|
||||
///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<Factory<OneSequenceGestureRecognizer>>? 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<CocosWidget> { |
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return Text( |
||||
'$defaultTargetPlatform is not yet supported by the Cocos player plugin'); |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
import 'package:flutter_cocos_view/src/helpers/types.dart'; |
||||
|
||||
class CocosEvent<T> { |
||||
/// The ID of the Cocos this event is associated to. |
||||
final int cocosId; |
||||
|
||||
/// The value wrapped by this event |
||||
final T value; |
||||
|
||||
/// Build a Cocos Event, that relates a mapId with a given value. |
||||
/// |
||||
/// The `cocosId` is the id of the map that triggered the event. |
||||
/// `value` may be `null` in events that don't transport any meaningful data. |
||||
CocosEvent(this.cocosId, this.value); |
||||
} |
||||
|
||||
class CocosSceneLoadedEvent extends CocosEvent<SceneLoaded?> { |
||||
CocosSceneLoadedEvent(int cocosId, SceneLoaded? value) |
||||
: super(cocosId, value); |
||||
} |
||||
|
||||
class CocosLoadedEvent extends CocosEvent<void> { |
||||
CocosLoadedEvent(int cocosId, void value) : super(cocosId, value); |
||||
} |
||||
|
||||
class CocosUnLoadedEvent extends CocosEvent<void> { |
||||
CocosUnLoadedEvent(int cocosId, void value) : super(cocosId, value); |
||||
} |
||||
|
||||
class CocosCreatedEvent extends CocosEvent<void> { |
||||
CocosCreatedEvent(int cocosId, void value) : super(cocosId, value); |
||||
} |
||||
|
||||
class CocosMessageEvent extends CocosEvent<dynamic> { |
||||
CocosMessageEvent(int cocosId, dynamic value) : super(cocosId, value); |
||||
} |
@ -0,0 +1,27 @@ |
||||
import 'package:flutter_cocos_view/src/helpers/types.dart'; |
||||
|
||||
/// Error thrown when an unknown cocos ID is provided to a method channel API. |
||||
class UnknownCocosIDError extends Error { |
||||
/// Creates an assertion error with the provided [cocosId] and optional |
||||
/// [message]. |
||||
UnknownCocosIDError(this.cocosId, [this.message]); |
||||
|
||||
/// The unknown ID. |
||||
final int cocosId; |
||||
|
||||
/// Message describing the assertion error. |
||||
final Object? message; |
||||
|
||||
String toString() { |
||||
if (message != null) { |
||||
return "Unknown cocos ID $cocosId: ${Error.safeToString(message)}"; |
||||
} |
||||
return "Unknown cocos ID $cocosId"; |
||||
} |
||||
} |
||||
|
||||
typedef void CocosMessageCallback(dynamic handler); |
||||
|
||||
typedef void CocosSceneChangeCallback(SceneLoaded? message); |
||||
|
||||
typedef void CocosUnloadCallback(); |
@ -0,0 +1,31 @@ |
||||
class SceneLoaded { |
||||
final String? name; |
||||
final int? buildIndex; |
||||
final bool? isLoaded; |
||||
final bool? isValid; |
||||
|
||||
SceneLoaded({this.name, this.buildIndex, this.isLoaded, this.isValid}); |
||||
|
||||
/// Mainly for internal use when calling [CameraUpdate.newCameraPosition]. |
||||
dynamic toMap() => <String, dynamic>{ |
||||
'name': name, |
||||
'buildIndex': buildIndex, |
||||
'isLoaded': isLoaded, |
||||
'isValid': isValid, |
||||
}; |
||||
|
||||
/// Deserializes [SceneLoaded] from a map. |
||||
/// |
||||
/// Mainly for internal use. |
||||
static SceneLoaded? fromMap(dynamic json) { |
||||
if (json == null) { |
||||
return null; |
||||
} |
||||
return SceneLoaded( |
||||
name: json['name'], |
||||
buildIndex: json['buildIndex'], |
||||
isLoaded: json['isLoaded'], |
||||
isValid: json['isValid'], |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,201 @@ |
||||
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<Factory<OneSequenceGestureRecognizer>>? 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<CocosWidget> { |
||||
late int _CocosId; |
||||
|
||||
CocosWidgetController? _controller; |
||||
|
||||
@override |
||||
void initState() { |
||||
super.initState(); |
||||
|
||||
if (!kIsWeb) { |
||||
_CocosId = _nextCocosCreationId++; |
||||
} else { |
||||
_CocosId = 0; |
||||
} |
||||
} |
||||
|
||||
@override |
||||
Future<void> 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<String, dynamic> CocosOptions = <String, dynamic>{ |
||||
'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<void> _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('*********************************************'); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,154 @@ |
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter/gestures.dart'; |
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter/services.dart'; |
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; |
||||
|
||||
import '../helpers/events.dart'; |
||||
import 'device_method.dart'; |
||||
|
||||
abstract class CocosWidgetPlatform extends PlatformInterface { |
||||
/// Constructs a CocosViewFlutterPlatform. |
||||
CocosWidgetPlatform() : super(token: _token); |
||||
|
||||
static final Object _token = Object(); |
||||
|
||||
static CocosWidgetPlatform _instance = MethodChannelCocosWidget(); |
||||
|
||||
/// The default instance of [CocosWidgetPlatform] to use. |
||||
/// |
||||
/// Defaults to [MethodChannelCocosWidgetFlutter]. |
||||
static CocosWidgetPlatform get instance => _instance; |
||||
|
||||
/// Platform-specific plugins should set this with their own platform-specific |
||||
/// class that extends [CocosWidgetPlatform] when they register themselves. |
||||
static set instance(CocosWidgetPlatform instance) { |
||||
PlatformInterface.verifyToken(instance, _token); |
||||
_instance = instance; |
||||
} |
||||
|
||||
/// /// Initializes the platform interface with [id]. |
||||
/// |
||||
/// This method is called when the plugin is first initialized. |
||||
Future<void> init(int cocosId) { |
||||
throw UnimplementedError('init() has not been implemented.'); |
||||
} |
||||
|
||||
Future<bool?> isReady({required int cocosId}) async { |
||||
throw UnimplementedError('init() has not been implemented.'); |
||||
} |
||||
|
||||
Future<bool?> isPaused({required int cocosId}) async { |
||||
throw UnimplementedError('isPaused() has not been implemented.'); |
||||
} |
||||
|
||||
Future<bool?> isLoaded({required int cocosId}) async { |
||||
throw UnimplementedError('isLoaded() has not been implemented.'); |
||||
} |
||||
|
||||
Future<bool?> inBackground({required int cocosId}) async { |
||||
throw UnimplementedError('inBackground() has not been implemented.'); |
||||
} |
||||
|
||||
Future<bool?> createCocosPlayer({required int cocosId}) async { |
||||
throw UnimplementedError('createCocosPlayer() has not been implemented.'); |
||||
} |
||||
|
||||
Future<void> postMessage( |
||||
{required int cocosId, |
||||
required String gameObject, |
||||
required String methodName, |
||||
required String message}) { |
||||
throw UnimplementedError('postMessage() has not been implemented.'); |
||||
} |
||||
|
||||
Future<void> postJsonMessage( |
||||
{required int cocosId, |
||||
required String gameObject, |
||||
required String methodName, |
||||
required Map message}) { |
||||
throw UnimplementedError('postJsonMessage() has not been implemented.'); |
||||
} |
||||
|
||||
Future<void> pausePlayer({required int cocosId}) async { |
||||
throw UnimplementedError('pausePlayer() has not been implemented.'); |
||||
} |
||||
|
||||
Future<void> resumePlayer({required int cocosId}) async { |
||||
throw UnimplementedError('resumePlayer() has not been implemented.'); |
||||
} |
||||
|
||||
/// Opens cocos in it's own activity. Android only. |
||||
Future<void> openInNativeProcess({required int cocosId}) async { |
||||
throw UnimplementedError('openInNativeProcess() has not been implemented.'); |
||||
} |
||||
|
||||
Future<void> unloadPlayer({required int cocosId}) async { |
||||
throw UnimplementedError('unloadPlayer() has not been implemented.'); |
||||
} |
||||
|
||||
Future<void> quitPlayer({required int cocosId}) async { |
||||
throw UnimplementedError('quitPlayer() has not been implemented.'); |
||||
} |
||||
|
||||
Stream<CocosMessageEvent> onCocosMessage({required int cocosId}) { |
||||
throw UnimplementedError('onCocosMessage() has not been implemented.'); |
||||
} |
||||
|
||||
Stream<CocosLoadedEvent> onCocosUnloaded({required int cocosId}) { |
||||
throw UnimplementedError('onCocosUnloaded() has not been implemented.'); |
||||
} |
||||
|
||||
Stream<CocosCreatedEvent> onCocosCreated({required int cocosId}) { |
||||
throw UnimplementedError('onCocosUnloaded() has not been implemented.'); |
||||
} |
||||
|
||||
Stream<CocosSceneLoadedEvent> onCocosSceneLoaded({required int cocosId}) { |
||||
throw UnimplementedError('onCocosSceneLoaded() has not been implemented.'); |
||||
} |
||||
|
||||
/// Dispose of whatever resources the `cocosId` is holding on to. |
||||
void dispose({required int cocosId}) { |
||||
throw UnimplementedError('dispose() has not been implemented.'); |
||||
} |
||||
|
||||
/// Returns a widget displaying the cocos view |
||||
Widget buildView( |
||||
int creationId, |
||||
PlatformViewCreatedCallback onPlatformViewCreated, { |
||||
Map<String, dynamic> cocosOptions = const {}, |
||||
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers, |
||||
bool? useAndroidViewSurf, |
||||
String? cocosSrcUrl, |
||||
}) { |
||||
throw UnimplementedError('buildView() has not been implemented.'); |
||||
} |
||||
|
||||
/// Returns a widget displaying the cocos view. |
||||
/// |
||||
/// This method is similar to [buildView], but contains a parameter for |
||||
/// platforms that require a text direction. |
||||
/// |
||||
/// Default behavior passes all parameters except `textDirection` to |
||||
/// [buildView]. This is for backward compatibility with existing |
||||
/// implementations. Platforms that use the text direction should override |
||||
/// this as the primary implementation, and delegate to it from buildView. |
||||
Widget buildViewWithTextDirection( |
||||
int creationId, |
||||
PlatformViewCreatedCallback onPlatformViewCreated, { |
||||
required TextDirection textDirection, |
||||
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers, |
||||
Map<String, dynamic> cocosOptions = const <String, dynamic>{}, |
||||
bool? useAndroidViewSurf, |
||||
String? cocosSrcUrl, |
||||
}) { |
||||
return buildView( |
||||
creationId, |
||||
onPlatformViewCreated, |
||||
gestureRecognizers: gestureRecognizers, |
||||
cocosOptions: cocosOptions, |
||||
useAndroidViewSurf: useAndroidViewSurf, |
||||
cocosSrcUrl: cocosSrcUrl, |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,299 @@ |
||||
import 'dart:async'; |
||||
import 'dart:convert'; |
||||
|
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter/gestures.dart'; |
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter/rendering.dart'; |
||||
import 'package:flutter/services.dart'; |
||||
import 'package:stream_transform/stream_transform.dart'; |
||||
|
||||
import '../helpers/events.dart'; |
||||
import '../helpers/misc.dart'; |
||||
import '../helpers/types.dart'; |
||||
import 'cocos_widget_platform.dart'; |
||||
import 'windows_cocos_widget_view.dart'; |
||||
|
||||
class MethodChannelCocosWidget extends CocosWidgetPlatform { |
||||
// Every method call passes the int cocosId |
||||
late final Map<int, MethodChannel> _channels = {}; |
||||
|
||||
/// Set [CocosWidgetFlutterPlatform] to use [AndroidViewSurface] to build the Google Maps 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 false. |
||||
bool useAndroidViewSurface = true; |
||||
|
||||
/// Accesses the MethodChannel associated to the passed cocosId. |
||||
MethodChannel channel(int cocosId) { |
||||
MethodChannel? channel = _channels[cocosId]; |
||||
if (channel == null) { |
||||
throw UnknownCocosIDError(cocosId); |
||||
} |
||||
return channel; |
||||
} |
||||
|
||||
MethodChannel ensureChannelInitialized(int cocosId) { |
||||
MethodChannel? channel = _channels[cocosId]; |
||||
if (channel == null) { |
||||
channel = MethodChannel('plugin.xraph.com/cocos_view_$cocosId'); |
||||
|
||||
channel.setMethodCallHandler( |
||||
(MethodCall call) => _handleMethodCall(call, cocosId)); |
||||
_channels[cocosId] = channel; |
||||
} |
||||
return channel; |
||||
} |
||||
|
||||
/// Initializes the platform interface with [id]. |
||||
/// |
||||
/// This method is called when the plugin is first initialized. |
||||
@override |
||||
Future<void> init(int cocosId) { |
||||
MethodChannel channel = ensureChannelInitialized(cocosId); |
||||
return channel.invokeMethod<void>('cocos#waitForCocos'); |
||||
} |
||||
|
||||
/// Dispose of the native resources. |
||||
@override |
||||
Future<void> dispose({int? cocosId}) async { |
||||
try { |
||||
if (cocosId != null) await channel(cocosId).invokeMethod('cocos#dispose'); |
||||
} catch (e) { |
||||
// ignore |
||||
} |
||||
} |
||||
|
||||
// The controller we need to broadcast the different events coming |
||||
// from handleMethodCall. |
||||
// |
||||
// It is a `broadcast` because multiple controllers will connect to |
||||
// different stream views of this Controller. |
||||
final StreamController<CocosEvent> _cocosStreamController = |
||||
StreamController<CocosEvent>.broadcast(); |
||||
|
||||
// Returns a filtered view of the events in the _controller, by cocosId. |
||||
Stream<CocosEvent> _events(int cocosId) => |
||||
_cocosStreamController.stream.where((event) => event.cocosId == cocosId); |
||||
|
||||
Future<dynamic> _handleMethodCall(MethodCall call, int cocosId) async { |
||||
switch (call.method) { |
||||
case "events#onCocosMessage": |
||||
_cocosStreamController.add(CocosMessageEvent(cocosId, call.arguments)); |
||||
break; |
||||
case "events#onCocosUnloaded": |
||||
_cocosStreamController.add(CocosLoadedEvent(cocosId, call.arguments)); |
||||
break; |
||||
case "events#onCocosSceneLoaded": |
||||
_cocosStreamController.add(CocosSceneLoadedEvent( |
||||
cocosId, SceneLoaded.fromMap(call.arguments))); |
||||
break; |
||||
case "events#onCocosCreated": |
||||
_cocosStreamController.add(CocosCreatedEvent(cocosId, call.arguments)); |
||||
break; |
||||
default: |
||||
throw UnimplementedError("Unimplemented ${call.method} method"); |
||||
} |
||||
} |
||||
|
||||
@override |
||||
Future<bool?> isPaused({required int cocosId}) async { |
||||
return await channel(cocosId).invokeMethod('cocos#isPaused'); |
||||
} |
||||
|
||||
@override |
||||
Future<bool?> isReady({required int cocosId}) async { |
||||
return await channel(cocosId).invokeMethod('cocos#isReady'); |
||||
} |
||||
|
||||
@override |
||||
Future<bool?> isLoaded({required int cocosId}) async { |
||||
return await channel(cocosId).invokeMethod('cocos#isLoaded'); |
||||
} |
||||
|
||||
@override |
||||
Future<bool?> inBackground({required int cocosId}) async { |
||||
return await channel(cocosId).invokeMethod('cocos#inBackground'); |
||||
} |
||||
|
||||
@override |
||||
Future<bool?> createCocosPlayer({required int cocosId}) async { |
||||
return await channel(cocosId).invokeMethod('cocos#createPlayer'); |
||||
} |
||||
|
||||
@override |
||||
Stream<CocosMessageEvent> onCocosMessage({required int cocosId}) { |
||||
return _events(cocosId).whereType<CocosMessageEvent>(); |
||||
} |
||||
|
||||
@override |
||||
Stream<CocosLoadedEvent> onCocosUnloaded({required int cocosId}) { |
||||
return _events(cocosId).whereType<CocosLoadedEvent>(); |
||||
} |
||||
|
||||
@override |
||||
Stream<CocosCreatedEvent> onCocosCreated({required int cocosId}) { |
||||
return _events(cocosId).whereType<CocosCreatedEvent>(); |
||||
} |
||||
|
||||
@override |
||||
Stream<CocosSceneLoadedEvent> onCocosSceneLoaded({required int cocosId}) { |
||||
return _events(cocosId).whereType<CocosSceneLoadedEvent>(); |
||||
} |
||||
|
||||
@override |
||||
Widget buildViewWithTextDirection( |
||||
int creationId, |
||||
PlatformViewCreatedCallback onPlatformViewCreated, { |
||||
required TextDirection textDirection, |
||||
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers, |
||||
Map<String, dynamic> cocosOptions = const <String, dynamic>{}, |
||||
bool? useAndroidViewSurf, |
||||
bool? height, |
||||
bool? width, |
||||
bool? cocosWebSource, |
||||
String? cocosSrcUrl, |
||||
}) { |
||||
final String _viewType = 'plugin.xraph.com/cocos_view'; |
||||
|
||||
if (useAndroidViewSurf != null) useAndroidViewSurface = useAndroidViewSurf; |
||||
|
||||
final Map<String, dynamic> creationParams = cocosOptions; |
||||
|
||||
if (defaultTargetPlatform == TargetPlatform.windows) { |
||||
return WindowsCocosWidgetView(); |
||||
} |
||||
|
||||
if (defaultTargetPlatform == TargetPlatform.android) { |
||||
if (!useAndroidViewSurface) { |
||||
return AndroidView( |
||||
viewType: _viewType, |
||||
onPlatformViewCreated: onPlatformViewCreated, |
||||
gestureRecognizers: gestureRecognizers, |
||||
creationParams: creationParams, |
||||
creationParamsCodec: const StandardMessageCodec(), |
||||
hitTestBehavior: PlatformViewHitTestBehavior.opaque, |
||||
layoutDirection: TextDirection.ltr, |
||||
); |
||||
} |
||||
|
||||
return PlatformViewLink( |
||||
viewType: _viewType, |
||||
surfaceFactory: ( |
||||
BuildContext context, |
||||
PlatformViewController controller, |
||||
) { |
||||
return AndroidViewSurface( |
||||
controller: controller as AndroidViewController, |
||||
gestureRecognizers: gestureRecognizers ?? |
||||
const <Factory<OneSequenceGestureRecognizer>>{}, |
||||
hitTestBehavior: PlatformViewHitTestBehavior.opaque, |
||||
); |
||||
}, |
||||
onCreatePlatformView: (PlatformViewCreationParams params) { |
||||
final controller = PlatformViewsService.initExpensiveAndroidView( |
||||
id: params.id, |
||||
viewType: _viewType, |
||||
layoutDirection: TextDirection.ltr, |
||||
creationParams: creationParams, |
||||
creationParamsCodec: const StandardMessageCodec(), |
||||
onFocus: () => params.onFocusChanged(true), |
||||
); |
||||
|
||||
controller |
||||
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) |
||||
..addOnPlatformViewCreatedListener(onPlatformViewCreated) |
||||
..create(); |
||||
return controller; |
||||
}, |
||||
); |
||||
} else if (defaultTargetPlatform == TargetPlatform.iOS) { |
||||
return UiKitView( |
||||
viewType: _viewType, |
||||
onPlatformViewCreated: onPlatformViewCreated, |
||||
gestureRecognizers: gestureRecognizers, |
||||
creationParams: creationParams, |
||||
creationParamsCodec: const StandardMessageCodec(), |
||||
); |
||||
} |
||||
return Text( |
||||
'$defaultTargetPlatform is not yet supported by the cocos player plugin'); |
||||
} |
||||
|
||||
@override |
||||
Widget buildView( |
||||
int creationId, |
||||
PlatformViewCreatedCallback onPlatformViewCreated, { |
||||
Map<String, dynamic> cocosOptions = const {}, |
||||
Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers, |
||||
bool? useAndroidViewSurf, |
||||
String? cocosSrcUrl, |
||||
}) { |
||||
return buildViewWithTextDirection( |
||||
creationId, |
||||
onPlatformViewCreated, |
||||
textDirection: TextDirection.ltr, |
||||
gestureRecognizers: gestureRecognizers, |
||||
cocosOptions: cocosOptions, |
||||
useAndroidViewSurf: useAndroidViewSurf, |
||||
cocosSrcUrl: cocosSrcUrl, |
||||
); |
||||
} |
||||
|
||||
@override |
||||
Future<void> postMessage({ |
||||
required int cocosId, |
||||
required String gameObject, |
||||
required String methodName, |
||||
required String message, |
||||
}) async { |
||||
await channel(cocosId).invokeMethod('cocos#postMessage', <String, dynamic>{ |
||||
'gameObject': gameObject, |
||||
'methodName': methodName, |
||||
'message': message, |
||||
}); |
||||
} |
||||
|
||||
@override |
||||
Future<void> postJsonMessage({ |
||||
required int cocosId, |
||||
required String gameObject, |
||||
required String methodName, |
||||
required Map message, |
||||
}) async { |
||||
await channel(cocosId).invokeMethod('cocos#postMessage', <String, dynamic>{ |
||||
'gameObject': gameObject, |
||||
'methodName': methodName, |
||||
'message': json.encode(message), |
||||
}); |
||||
} |
||||
|
||||
@override |
||||
Future<void> pausePlayer({required int cocosId}) async { |
||||
await channel(cocosId).invokeMethod('cocos#pausePlayer'); |
||||
} |
||||
|
||||
@override |
||||
Future<void> resumePlayer({required int cocosId}) async { |
||||
await channel(cocosId).invokeMethod('cocos#resumePlayer'); |
||||
} |
||||
|
||||
@override |
||||
Future<void> openInNativeProcess({required int cocosId}) async { |
||||
await channel(cocosId).invokeMethod('cocos#openInNativeProcess'); |
||||
} |
||||
|
||||
@override |
||||
Future<void> unloadPlayer({required int cocosId}) async { |
||||
await channel(cocosId).invokeMethod('cocos#unloadPlayer'); |
||||
} |
||||
|
||||
@override |
||||
Future<void> quitPlayer({required int cocosId}) async { |
||||
await channel(cocosId).invokeMethod('cocos#quitPlayer'); |
||||
} |
||||
} |
@ -0,0 +1,4 @@ |
||||
export '../facade_controller.dart'; |
||||
export '../helpers/events.dart'; |
||||
export '../helpers/misc.dart'; |
||||
export '../helpers/types.dart'; |
@ -0,0 +1,213 @@ |
||||
import 'dart:async'; |
||||
|
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter/services.dart'; |
||||
|
||||
import '../facade_controller.dart'; |
||||
import '../helpers/events.dart'; |
||||
import 'device_method.dart'; |
||||
import 'cocos_widget.dart'; |
||||
import 'cocos_widget_platform.dart'; |
||||
|
||||
class MobileCocosWidgetController extends CocosWidgetController { |
||||
final MobileCocosWidgetState _cocosWidgetState; |
||||
|
||||
/// The cocosId for this controller |
||||
final int cocosId; |
||||
|
||||
/// used for cancel the subscription |
||||
StreamSubscription? _onCocosMessageSub, |
||||
_onCocosSceneLoadedSub, |
||||
_onCocosUnloadedSub; |
||||
|
||||
MobileCocosWidgetController._(this._cocosWidgetState, |
||||
{required this.cocosId}) { |
||||
_connectStreams(cocosId); |
||||
} |
||||
|
||||
/// Initialize [CocosWidgetController] with [id] |
||||
/// Mainly for internal use when instantiating a [CocosWidgetController] passed |
||||
/// in [CocosWidget.onCocosCreated] callback. |
||||
static Future<MobileCocosWidgetController> init( |
||||
int id, MobileCocosWidgetState cocosWidgetState) async { |
||||
await CocosWidgetPlatform.instance.init(id); |
||||
return MobileCocosWidgetController._( |
||||
cocosWidgetState, |
||||
cocosId: id, |
||||
); |
||||
} |
||||
|
||||
@visibleForTesting |
||||
MethodChannel? get channel { |
||||
if (CocosWidgetPlatform.instance is MethodChannelCocosWidget) { |
||||
return (CocosWidgetPlatform.instance as MethodChannelCocosWidget) |
||||
.channel(cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
void _connectStreams(int cocosId) { |
||||
if (_cocosWidgetState.widget.onCocosMessage != null) { |
||||
_onCocosMessageSub = CocosWidgetPlatform.instance |
||||
.onCocosMessage(cocosId: cocosId) |
||||
.listen((CocosMessageEvent e) => |
||||
_cocosWidgetState.widget.onCocosMessage!(e.value)); |
||||
} |
||||
|
||||
if (_cocosWidgetState.widget.onCocosSceneLoaded != null) { |
||||
_onCocosSceneLoadedSub = CocosWidgetPlatform.instance |
||||
.onCocosSceneLoaded(cocosId: cocosId) |
||||
.listen((CocosSceneLoadedEvent e) => |
||||
_cocosWidgetState.widget.onCocosSceneLoaded!(e.value)); |
||||
} |
||||
|
||||
if (_cocosWidgetState.widget.onCocosUnloaded != null) { |
||||
_onCocosUnloadedSub = CocosWidgetPlatform.instance |
||||
.onCocosUnloaded(cocosId: cocosId) |
||||
.listen((_) => _cocosWidgetState.widget.onCocosUnloaded!()); |
||||
} |
||||
} |
||||
|
||||
/// Checks to see if cocos player is ready to be used |
||||
/// Returns `true` if cocos player is ready. |
||||
Future<bool?>? isReady() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.isReady(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Get the current pause state of the cocos player |
||||
/// Returns `true` if cocos player is paused. |
||||
Future<bool?>? isPaused() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.isPaused(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Get the current load state of the cocos player |
||||
/// Returns `true` if cocos player is loaded. |
||||
Future<bool?>? isLoaded() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.isLoaded(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Helper method to know if Cocos has been put in background mode (WIP) unstable |
||||
/// Returns `true` if cocos player is in background. |
||||
Future<bool?>? inBackground() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.inBackground(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Creates a cocos player if it's not already created. Please only call this if cocos is not ready, |
||||
/// or is in unloaded state. Use [isLoaded] to check. |
||||
/// Returns `true` if cocos player was created succesfully. |
||||
Future<bool?>? create() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.createCocosPlayer(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Post message to cocos from flutter. This method takes in a string [message]. |
||||
/// The [gameObject] must match the name of an actual cocos game object in a scene at runtime, and the [methodName], |
||||
/// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method |
||||
/// |
||||
/// ```dart |
||||
/// postMessage("GameManager", "openScene", "ThirdScene") |
||||
/// ``` |
||||
Future<void>? postMessage(String gameObject, methodName, message) { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.postMessage( |
||||
cocosId: cocosId, |
||||
gameObject: gameObject, |
||||
methodName: methodName, |
||||
message: message, |
||||
); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Post message to cocos from flutter. This method takes in a Json or map structure as the [message]. |
||||
/// The [gameObject] must match the name of an actual cocos game object in a scene at runtime, and the [methodName], |
||||
/// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method |
||||
/// |
||||
/// ```dart |
||||
/// postJsonMessage("GameManager", "openScene", {"buildIndex": 3, "name": "ThirdScene"}) |
||||
/// ``` |
||||
Future<void>? postJsonMessage( |
||||
String gameObject, String methodName, Map<String, dynamic> message) { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.postJsonMessage( |
||||
cocosId: cocosId, |
||||
gameObject: gameObject, |
||||
methodName: methodName, |
||||
message: message, |
||||
); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Pause the cocos in-game player with this method |
||||
Future<void>? pause() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.pausePlayer(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Resume the cocos in-game player with this method idf it is in a paused state |
||||
Future<void>? resume() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.resumePlayer(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Sometimes you want to open cocos in it's own process and openInNativeProcess does just that. |
||||
/// It works for Android and iOS is WIP |
||||
Future<void>? openInNativeProcess() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.openInNativeProcess(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Unloads cocos player from th current process (Works on Android only for now) |
||||
/// iOS is WIP. For more information please read [Cocos Docs](https://docs.cocos3d.com/2020.2/Documentation/Manual/CocosasaLibrary.html) |
||||
Future<void>? unload() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.unloadPlayer(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// Quits cocos player. Note that this kills the current flutter process, thus quiting the app |
||||
Future<void>? quit() { |
||||
if (!_cocosWidgetState.widget.enablePlaceholder) { |
||||
return CocosWidgetPlatform.instance.quitPlayer(cocosId: cocosId); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// cancel the subscriptions when dispose called |
||||
void _cancelSubscriptions() { |
||||
_onCocosMessageSub?.cancel(); |
||||
_onCocosSceneLoadedSub?.cancel(); |
||||
_onCocosUnloadedSub?.cancel(); |
||||
|
||||
_onCocosMessageSub = null; |
||||
_onCocosSceneLoadedSub = null; |
||||
_onCocosUnloadedSub = null; |
||||
} |
||||
|
||||
void dispose() { |
||||
_cancelSubscriptions(); |
||||
CocosWidgetPlatform.instance.dispose(cocosId: cocosId); |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
class WindowsCocosWidgetView extends StatefulWidget { |
||||
const WindowsCocosWidgetView({super.key}); |
||||
|
||||
@override |
||||
State<WindowsCocosWidgetView> createState() => _WindowsCocosWidgetViewState(); |
||||
} |
||||
|
||||
class _WindowsCocosWidgetViewState extends State<WindowsCocosWidgetView> { |
||||
@override |
||||
Widget build(BuildContext context) { |
||||
// TODO: Rex Update windows view |
||||
return const MouseRegion( |
||||
child: Texture( |
||||
textureId: 0, |
||||
), |
||||
); |
||||
} |
||||
} |
@ -1,27 +0,0 @@ |
||||
import 'package:flutter/services.dart'; |
||||
import 'package:flutter_test/flutter_test.dart'; |
||||
import 'package:flutter_cocos_view/flutter_cocos_view_method_channel.dart'; |
||||
|
||||
void main() { |
||||
TestWidgetsFlutterBinding.ensureInitialized(); |
||||
|
||||
MethodChannelFlutterCocosView platform = MethodChannelFlutterCocosView(); |
||||
const MethodChannel channel = MethodChannel('flutter_cocos_view'); |
||||
|
||||
setUp(() { |
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( |
||||
channel, |
||||
(MethodCall methodCall) async { |
||||
return '42'; |
||||
}, |
||||
); |
||||
}); |
||||
|
||||
tearDown(() { |
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null); |
||||
}); |
||||
|
||||
test('getPlatformVersion', () async { |
||||
expect(await platform.getPlatformVersion(), '42'); |
||||
}); |
||||
} |
@ -1,29 +0,0 @@ |
||||
import 'package:flutter_test/flutter_test.dart'; |
||||
import 'package:flutter_cocos_view/flutter_cocos_view.dart'; |
||||
import 'package:flutter_cocos_view/flutter_cocos_view_platform_interface.dart'; |
||||
import 'package:flutter_cocos_view/flutter_cocos_view_method_channel.dart'; |
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; |
||||
|
||||
class MockFlutterCocosViewPlatform |
||||
with MockPlatformInterfaceMixin |
||||
implements FlutterCocosViewPlatform { |
||||
|
||||
@override |
||||
Future<String?> getPlatformVersion() => Future.value('42'); |
||||
} |
||||
|
||||
void main() { |
||||
final FlutterCocosViewPlatform initialPlatform = FlutterCocosViewPlatform.instance; |
||||
|
||||
test('$MethodChannelFlutterCocosView is the default instance', () { |
||||
expect(initialPlatform, isInstanceOf<MethodChannelFlutterCocosView>()); |
||||
}); |
||||
|
||||
test('getPlatformVersion', () async { |
||||
FlutterCocosView flutterCocosViewPlugin = FlutterCocosView(); |
||||
MockFlutterCocosViewPlatform fakePlatform = MockFlutterCocosViewPlatform(); |
||||
FlutterCocosViewPlatform.instance = fakePlatform; |
||||
|
||||
expect(await flutterCocosViewPlugin.getPlatformVersion(), '42'); |
||||
}); |
||||
} |
Loading…
Reference in new issue