diff --git a/android/src/main/java/com/gianlucaparadise/flutter_cast_framework/PlatformBridgeApis.java b/android/src/main/java/com/gianlucaparadise/flutter_cast_framework/PlatformBridgeApis.java index c5eba66..9dc9610 100644 --- a/android/src/main/java/com/gianlucaparadise/flutter_cast_framework/PlatformBridgeApis.java +++ b/android/src/main/java/com/gianlucaparadise/flutter_cast_framework/PlatformBridgeApis.java @@ -491,6 +491,7 @@ public class PlatformBridgeApis { void pause(); void stop(); void showTracksChooserDialog(); + void skipAd(); /** The codec used by CastHostApi. */ static MessageCodec getCodec() { @@ -704,6 +705,25 @@ public class PlatformBridgeApis { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.CastHostApi.skipAd", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + api.skipAd(); + wrapped.put("result", null); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } } } private static class CastFlutterApiCodec extends StandardMessageCodec { diff --git a/android/src/main/kotlin/com/gianlucaparadise/flutter_cast_framework/FlutterCastFrameworkPlugin.kt b/android/src/main/kotlin/com/gianlucaparadise/flutter_cast_framework/FlutterCastFrameworkPlugin.kt index d47c77e..30c56e7 100644 --- a/android/src/main/kotlin/com/gianlucaparadise/flutter_cast_framework/FlutterCastFrameworkPlugin.kt +++ b/android/src/main/kotlin/com/gianlucaparadise/flutter_cast_framework/FlutterCastFrameworkPlugin.kt @@ -336,6 +336,11 @@ class FlutterCastFrameworkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwa .show(activity.supportFragmentManager, "FlutterCastFrameworkTracksChooserDialog") } + override fun skipAd() { + val remoteMediaClient: RemoteMediaClient = remoteMediaClient ?: return + remoteMediaClient.skipAd() + } + override fun setMute(muted: Boolean?) { if (muted == null) return val castSession = mCastSession ?: return diff --git a/ios/Classes/PlatformBridgeApis.h b/ios/Classes/PlatformBridgeApis.h index 3cfb4f4..a60240f 100644 --- a/ios/Classes/PlatformBridgeApis.h +++ b/ios/Classes/PlatformBridgeApis.h @@ -133,6 +133,7 @@ NSObject *CastHostApiGetCodec(void); - (void)pauseWithError:(FlutterError *_Nullable *_Nonnull)error; - (void)stopWithError:(FlutterError *_Nullable *_Nonnull)error; - (void)showTracksChooserDialogWithError:(FlutterError *_Nullable *_Nonnull)error; +- (void)skipAdWithError:(FlutterError *_Nullable *_Nonnull)error; @end extern void CastHostApiSetup(id binaryMessenger, NSObject *_Nullable api); diff --git a/ios/Classes/PlatformBridgeApis.m b/ios/Classes/PlatformBridgeApis.m index 1815a9e..102472e 100644 --- a/ios/Classes/PlatformBridgeApis.m +++ b/ios/Classes/PlatformBridgeApis.m @@ -540,6 +540,24 @@ void CastHostApiSetup(id binaryMessenger, NSObject) { + remoteMediaClient?.skipAd() + } // MARK: - GCKSessionManagerListener // onSessionSuspended diff --git a/lib/src/PlatformBridgeApis.dart b/lib/src/PlatformBridgeApis.dart index d7aad8f..f70304c 100644 --- a/lib/src/PlatformBridgeApis.dart +++ b/lib/src/PlatformBridgeApis.dart @@ -585,6 +585,29 @@ class CastHostApi { return; } } + + Future skipAd() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.CastHostApi.skipAd', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send(null) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } } class _CastFlutterApiCodec extends StandardMessageCodec { diff --git a/lib/src/cast/RemoteMediaClient.dart b/lib/src/cast/RemoteMediaClient.dart index e0ecb85..580ce08 100644 --- a/lib/src/cast/RemoteMediaClient.dart +++ b/lib/src/cast/RemoteMediaClient.dart @@ -79,6 +79,11 @@ class RemoteMediaClient { _hostApi.showTracksChooserDialog(); } + /// Skips the playing ad. + void skipAd() { + _hostApi.skipAd(); + } + /// Internal method that shouldn't be visible @internal void dispatchPlayerStateUpdate(PlayerState playerState) { diff --git a/lib/src/cast/widgets/expanded_controls/ExpandedControls.dart b/lib/src/cast/widgets/expanded_controls/ExpandedControls.dart index 56a1b97..1800dcc 100644 --- a/lib/src/cast/widgets/expanded_controls/ExpandedControls.dart +++ b/lib/src/cast/widgets/expanded_controls/ExpandedControls.dart @@ -137,6 +137,11 @@ class _ExpandedControlsState extends State { .updateProgress(progressMs, durationMs, whenSkippableMs); } + void _onSkipAd() { + final sessionManager = widget.castFramework.castContext.sessionManager; + sessionManager.remoteMediaClient.skipAd(); + } + Widget _getDecoratedToolbar(MediaInfo? mediaInfo) { // Title and subtitle can't be retrieved at the moment // final title = mediaInfo?.mediaMetadata?.strings[MediaMetadataKey.title] @@ -221,7 +226,7 @@ class _ExpandedControlsState extends State { controller: widget.adSkipBoxController, skipAdButtonText: widget.skipAdButtonText, skipAdTimerText: widget.skipAdTimerText, - onSkipPressed: () {/* TODO: skip ad */}, + onSkipPressed: _onSkipAd, ), ]; } diff --git a/pigeon/PlatformBridgeApisDefinition.dart b/pigeon/PlatformBridgeApisDefinition.dart index 838063d..a9cd186 100644 --- a/pigeon/PlatformBridgeApisDefinition.dart +++ b/pigeon/PlatformBridgeApisDefinition.dart @@ -267,6 +267,7 @@ abstract class CastHostApi { void pause(); void stop(); void showTracksChooserDialog(); + void skipAd(); //endregion }