Refactor classes and improve docs
This commit is contained in:
parent
97425c97f6
commit
d31ff882b5
14 changed files with 246 additions and 105 deletions
23
.vscode/launch.json
vendored
23
.vscode/launch.json
vendored
|
|
@ -5,9 +5,30 @@
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Flutter",
|
"name": "Current Device",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "dart"
|
"type": "dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Android",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"deviceId": "android"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "iPhone",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"deviceId": "iphone"
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"compounds": [
|
||||||
|
{
|
||||||
|
"name": "All Devices",
|
||||||
|
"configurations": [
|
||||||
|
"Android",
|
||||||
|
"iPhone"
|
||||||
|
],
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
15
Makefile
15
Makefile
|
|
@ -1,6 +1,8 @@
|
||||||
|
.PHONY: pigeon deploy-receiver open-android open-ios run-all
|
||||||
|
|
||||||
pigeon: # Generates the typesafe bridge between host and flutter
|
pigeon: # Generates the typesafe bridge between host and flutter
|
||||||
flutter pub run pigeon \
|
flutter pub run pigeon \
|
||||||
--input lib/src/PlatformBridgeApisDefinition.dart \
|
--input pigeon/PlatformBridgeApisDefinition.dart \
|
||||||
--dart_out lib/src/PlatformBridgeApis.dart \
|
--dart_out lib/src/PlatformBridgeApis.dart \
|
||||||
--objc_header_out ios/Classes/PlatformBridgeApis.h \
|
--objc_header_out ios/Classes/PlatformBridgeApis.h \
|
||||||
--objc_source_out ios/Classes/PlatformBridgeApis.m \
|
--objc_source_out ios/Classes/PlatformBridgeApis.m \
|
||||||
|
|
@ -8,4 +10,13 @@ pigeon: # Generates the typesafe bridge between host and flutter
|
||||||
--java_package "com.gianlucaparadise.flutter_cast_framework"
|
--java_package "com.gianlucaparadise.flutter_cast_framework"
|
||||||
|
|
||||||
deploy-receiver:
|
deploy-receiver:
|
||||||
surge receiver
|
surge receiver
|
||||||
|
|
||||||
|
open-android:
|
||||||
|
studio example/android
|
||||||
|
|
||||||
|
open-ios:
|
||||||
|
open example/ios/Runner.xcworkspace
|
||||||
|
|
||||||
|
run-all:
|
||||||
|
cd example && flutter run -d all
|
||||||
15
README.md
15
README.md
|
|
@ -12,6 +12,9 @@ Currently only the following APIs are integrated (both Android and iOS):
|
||||||
* Session state
|
* Session state
|
||||||
* Send custom message
|
* Send custom message
|
||||||
* Listen to received custom messages
|
* Listen to received custom messages
|
||||||
|
* Load RemoteMediaRequestData
|
||||||
|
* Play, Pause, Stop media
|
||||||
|
* Expanded controls
|
||||||
* Cast Button
|
* Cast Button
|
||||||
* Chromecast connection
|
* Chromecast connection
|
||||||
|
|
||||||
|
|
@ -136,4 +139,14 @@ I used this project to test the capabilities of the following technologies:
|
||||||
|
|
||||||
* Chromecast API (Sender - Android SDK)
|
* Chromecast API (Sender - Android SDK)
|
||||||
* Flutter
|
* Flutter
|
||||||
* Flutter custom platform-specific code
|
* Flutter custom platform-specific code
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
* Volume in Expanded Controls
|
||||||
|
* Currently connected cast device name
|
||||||
|
* CC in Expanded Controls
|
||||||
|
* Handle Ad Break
|
||||||
|
* Handle progress seek
|
||||||
|
* Handle queue
|
||||||
|
* Handle mini-player
|
||||||
|
|
|
||||||
|
|
@ -32,18 +32,27 @@ class _MyAppState extends State<MyApp> {
|
||||||
super.initState();
|
super.initState();
|
||||||
castFramework = FlutterCastFramework.create([castNamespace]);
|
castFramework = FlutterCastFramework.create([castNamespace]);
|
||||||
castFramework.castContext.state.addListener(_onCastStateChanged);
|
castFramework.castContext.state.addListener(_onCastStateChanged);
|
||||||
castFramework.castContext.sessionManager.state
|
|
||||||
.addListener(_onSessionStateChanged);
|
final sessionManager = castFramework.castContext.sessionManager;
|
||||||
castFramework.castContext.sessionManager.onMessageReceived =
|
sessionManager.state.addListener(_onSessionStateChanged);
|
||||||
_onMessageReceived;
|
sessionManager.onMessageReceived = _onMessageReceived;
|
||||||
castFramework.castContext.sessionManager.onStatusUpdated =
|
sessionManager.remoteMediaClient.playerState
|
||||||
_onRemoteMediaClientStatusUpdated;
|
.addListener(_onRemoteMediaClientStatusUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
// Clean up the controller when the widget is disposed.
|
// Clean up the controller when the widget is disposed.
|
||||||
textMessageController.dispose();
|
textMessageController.dispose();
|
||||||
|
|
||||||
|
castFramework.castContext.state.removeListener(_onCastStateChanged);
|
||||||
|
|
||||||
|
final sessionManager = castFramework.castContext.sessionManager;
|
||||||
|
sessionManager.state.removeListener(_onSessionStateChanged);
|
||||||
|
sessionManager.onMessageReceived = null;
|
||||||
|
sessionManager.remoteMediaClient.playerState
|
||||||
|
.removeListener(_onRemoteMediaClientStatusUpdated);
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,7 +77,9 @@ class _MyAppState extends State<MyApp> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onRemoteMediaClientStatusUpdated(PlayerState playerState) {
|
void _onRemoteMediaClientStatusUpdated() {
|
||||||
|
final playerState = castFramework
|
||||||
|
.castContext.sessionManager.remoteMediaClient.playerState.value;
|
||||||
debugPrint("RemoteMediaClient status updated - playerState $playerState");
|
debugPrint("RemoteMediaClient status updated - playerState $playerState");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,6 @@ library cast;
|
||||||
|
|
||||||
export 'src/cast/CastContext.dart';
|
export 'src/cast/CastContext.dart';
|
||||||
export 'src/cast/SessionManager.dart';
|
export 'src/cast/SessionManager.dart';
|
||||||
|
export 'src/cast/RemoteMediaClient.dart';
|
||||||
export 'src/flutter_cast_framework.dart';
|
export 'src/flutter_cast_framework.dart';
|
||||||
export 'src/PlatformBridgeApis.dart';
|
export 'src/PlatformBridgeApis.dart' hide CastFlutterApi, CastHostApi;
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,33 @@
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import '../PlatformBridgeApis.dart';
|
import '../PlatformBridgeApis.dart';
|
||||||
import 'SessionManager.dart';
|
import 'SessionManager.dart';
|
||||||
|
|
||||||
|
/// Class wrapping the global context fot the Cast SDK
|
||||||
class CastContext {
|
class CastContext {
|
||||||
final ValueNotifier<CastState> state = ValueNotifier(CastState.unavailable);
|
|
||||||
final CastHostApi _hostApi;
|
|
||||||
|
|
||||||
CastContext(this._hostApi);
|
CastContext(this._hostApi);
|
||||||
|
|
||||||
|
final CastHostApi _hostApi;
|
||||||
|
|
||||||
|
/// Listenable connection state of the cast device
|
||||||
|
ValueListenable<CastState> get state => _stateNotifier;
|
||||||
|
final _stateNotifier = ValueNotifier(CastState.unavailable);
|
||||||
|
|
||||||
|
/// Display the native dialog to select the cast device to connect
|
||||||
void showCastChooserDialog() {
|
void showCastChooserDialog() {
|
||||||
_hostApi.showCastDialog();
|
_hostApi.showCastDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Internal method that shouldn't be visible
|
||||||
|
@internal
|
||||||
void onCastStateChanged(int castState) {
|
void onCastStateChanged(int castState) {
|
||||||
state.value = CastState.values[castState];
|
_stateNotifier.value = CastState.values[castState];
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionManager? _sessionManager;
|
SessionManager? _sessionManager;
|
||||||
|
|
||||||
|
/// Returns the SessionManager.
|
||||||
SessionManager get sessionManager {
|
SessionManager get sessionManager {
|
||||||
var result = _sessionManager;
|
var result = _sessionManager;
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
|
@ -26,10 +37,16 @@ class CastContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The possible casting states.
|
||||||
enum CastState {
|
enum CastState {
|
||||||
|
/// Cast connection has never been initialized.
|
||||||
idle, // 0
|
idle, // 0
|
||||||
|
/// No Cast devices are available.
|
||||||
unavailable, // 1
|
unavailable, // 1
|
||||||
|
/// Cast devices are available, but a Cast session is not established.
|
||||||
unconnected, // 2
|
unconnected, // 2
|
||||||
|
/// A Cast session is being established.
|
||||||
connecting, // 3
|
connecting, // 3
|
||||||
|
/// A Cast session is established.
|
||||||
connected, // 4
|
connected, // 4
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,88 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
import '../../cast.dart';
|
||||||
import '../PlatformBridgeApis.dart';
|
import '../PlatformBridgeApis.dart';
|
||||||
|
|
||||||
typedef ProgressListener = void Function(int progressMs, int durationMs);
|
typedef ProgressListener = void Function(int progressMs, int durationMs);
|
||||||
|
|
||||||
|
/// Class for controlling a media player application running on a receiver.
|
||||||
class RemoteMediaClient {
|
class RemoteMediaClient {
|
||||||
final CastHostApi _hostApi;
|
|
||||||
|
|
||||||
ProgressListener? onProgressUpdated;
|
|
||||||
|
|
||||||
RemoteMediaClient(this._hostApi);
|
RemoteMediaClient(this._hostApi);
|
||||||
|
|
||||||
|
final CastHostApi _hostApi;
|
||||||
|
|
||||||
|
/// Listenable state of the remote media player
|
||||||
|
ValueListenable<PlayerState> get playerState => _playerStateNotifier;
|
||||||
|
final _playerStateNotifier = ValueNotifier(PlayerState.unknown);
|
||||||
|
|
||||||
|
/// Callback to get updates on the progress of the currently playing media.
|
||||||
|
ProgressListener? onProgressUpdated;
|
||||||
|
|
||||||
|
/// Called when updated media metadata is received.
|
||||||
|
VoidCallback? onMetadataUpdated;
|
||||||
|
|
||||||
|
/// Called when updated player queue status information is received.
|
||||||
|
VoidCallback? onQueueStatusUpdated;
|
||||||
|
|
||||||
|
/// Called when updated player queue preload status information is received,
|
||||||
|
/// for example, the next item to play has been preloaded.
|
||||||
|
VoidCallback? onPreloadStatusUpdated;
|
||||||
|
|
||||||
|
/// Called when there is an outgoing request to the receiver.
|
||||||
|
VoidCallback? onSendingRemoteMediaRequest;
|
||||||
|
|
||||||
|
/// Called when updated ad break status information is received.
|
||||||
|
VoidCallback? onAdBreakStatusUpdated;
|
||||||
|
|
||||||
|
/// Called when receiving media error message.
|
||||||
|
VoidCallback? onMediaError;
|
||||||
|
|
||||||
|
/// Loads a new media item with specified options.
|
||||||
void load(MediaLoadRequestData request) {
|
void load(MediaLoadRequestData request) {
|
||||||
_hostApi.loadMediaLoadRequestData(request);
|
_hostApi.loadMediaLoadRequestData(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Begins (or resumes) playback of the current media item.
|
||||||
void play() {
|
void play() {
|
||||||
_hostApi.play();
|
_hostApi.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pauses playback of the current media item.
|
||||||
void pause() {
|
void pause() {
|
||||||
_hostApi.pause();
|
_hostApi.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stops playback of the current media item.
|
||||||
void stop() {
|
void stop() {
|
||||||
_hostApi.stop();
|
_hostApi.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the current media information
|
||||||
Future<MediaInfo> getMediaInfo() async {
|
Future<MediaInfo> getMediaInfo() async {
|
||||||
|
// FIXME: can remove future? we could avoid to call host and rely on listener callbacks (maybe onMetadataUpdated)
|
||||||
return await _hostApi.getMediaInfo();
|
return await _hostApi.getMediaInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Internal method that shouldn't be visible
|
||||||
|
@internal
|
||||||
|
void dispatchPlayerStateUpdate(PlayerState playerState) {
|
||||||
|
this._playerStateNotifier.value = playerState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State of the remote media player
|
||||||
|
enum PlayerState {
|
||||||
|
/// Constant indicating unknown player state.
|
||||||
|
unknown, // 0
|
||||||
|
/// Constant indicating that the media player is idle.
|
||||||
|
idle, // 1
|
||||||
|
/// Constant indicating that the media player is playing.
|
||||||
|
playing, // 2
|
||||||
|
/// Constant indicating that the media player is paused.
|
||||||
|
paused, // 3
|
||||||
|
/// Constant indicating that the media player is buffering.
|
||||||
|
buffering, // 4
|
||||||
|
/// Constant indicating that the media player is loading.
|
||||||
|
loading, // 5
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,33 @@
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
import '../PlatformBridgeApis.dart';
|
import '../PlatformBridgeApis.dart';
|
||||||
import 'RemoteMediaClient.dart';
|
import 'RemoteMediaClient.dart';
|
||||||
|
|
||||||
|
/// A class that manages Session instances. The application can attach a
|
||||||
|
/// listeners to be notified of session events.
|
||||||
class SessionManager {
|
class SessionManager {
|
||||||
final CastHostApi _hostApi;
|
|
||||||
|
|
||||||
SessionManager(this._hostApi);
|
SessionManager(this._hostApi);
|
||||||
|
|
||||||
final state = ValueNotifier(SessionState.idle);
|
final CastHostApi _hostApi;
|
||||||
final playerState = ValueNotifier(PlayerState.unknown);
|
|
||||||
|
|
||||||
|
/// Listenable session state of the cast device
|
||||||
|
ValueListenable<SessionState> get state => _stateNotifier;
|
||||||
|
final _stateNotifier = ValueNotifier(SessionState.idle);
|
||||||
|
|
||||||
|
/// Internal method that shouldn't be visible
|
||||||
|
@internal
|
||||||
void onSessionStateChanged(SessionState sessionState) {
|
void onSessionStateChanged(SessionState sessionState) {
|
||||||
switch (sessionState) {
|
switch (sessionState) {
|
||||||
case SessionState.session_starting:
|
case SessionState.starting:
|
||||||
case SessionState.session_started:
|
case SessionState.started:
|
||||||
case SessionState.session_start_failed:
|
case SessionState.start_failed:
|
||||||
case SessionState.session_ending:
|
case SessionState.ending:
|
||||||
case SessionState.session_ended:
|
case SessionState.ended:
|
||||||
case SessionState.session_resuming:
|
case SessionState.resuming:
|
||||||
case SessionState.session_resumed:
|
case SessionState.resumed:
|
||||||
case SessionState.session_resume_failed:
|
case SessionState.resume_failed:
|
||||||
case SessionState.session_suspended:
|
case SessionState.suspended:
|
||||||
state.value = sessionState;
|
_stateNotifier.value = sessionState;
|
||||||
break;
|
break;
|
||||||
case SessionState.idle:
|
case SessionState.idle:
|
||||||
// Not raised
|
// Not raised
|
||||||
|
|
@ -29,21 +35,11 @@ class SessionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatchOnPlayerStateUpdated(PlayerState playerState) {
|
/// Callback called when the Cast Receiver sent a message
|
||||||
this.playerState.value = playerState;
|
|
||||||
onStatusUpdated?.call(playerState);
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageReceivedCallback? onMessageReceived;
|
MessageReceivedCallback? onMessageReceived;
|
||||||
|
|
||||||
StatusUpdatedCallback? onStatusUpdated;
|
/// Internal method that shouldn't be visible
|
||||||
VoidCallback? onMetadataUpdated;
|
@internal
|
||||||
VoidCallback? onQueueStatusUpdated;
|
|
||||||
VoidCallback? onPreloadStatusUpdated;
|
|
||||||
VoidCallback? onSendingRemoteMediaRequest;
|
|
||||||
VoidCallback? onAdBreakStatusUpdated;
|
|
||||||
VoidCallback? onMediaError;
|
|
||||||
|
|
||||||
void platformOnMessageReceived(CastMessage castMessage) {
|
void platformOnMessageReceived(CastMessage castMessage) {
|
||||||
var thisOnMessageReceived = onMessageReceived;
|
var thisOnMessageReceived = onMessageReceived;
|
||||||
|
|
||||||
|
|
@ -54,6 +50,7 @@ class SessionManager {
|
||||||
thisOnMessageReceived(namespace, message);
|
thisOnMessageReceived(namespace, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a string message to the Cast Receiver using the input namespace
|
||||||
void sendMessage(String namespace, String message) {
|
void sendMessage(String namespace, String message) {
|
||||||
final castMessage = CastMessage();
|
final castMessage = CastMessage();
|
||||||
castMessage.namespace = namespace;
|
castMessage.namespace = namespace;
|
||||||
|
|
@ -62,6 +59,8 @@ class SessionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteMediaClient? _remoteMediaClient;
|
RemoteMediaClient? _remoteMediaClient;
|
||||||
|
|
||||||
|
/// Returns the RemoteMediaClient for remote media control.
|
||||||
RemoteMediaClient get remoteMediaClient {
|
RemoteMediaClient get remoteMediaClient {
|
||||||
var result = _remoteMediaClient;
|
var result = _remoteMediaClient;
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
|
@ -74,26 +73,16 @@ class SessionManager {
|
||||||
typedef MessageReceivedCallback = void Function(
|
typedef MessageReceivedCallback = void Function(
|
||||||
String namespace, String message);
|
String namespace, String message);
|
||||||
|
|
||||||
|
/// State of the session
|
||||||
enum SessionState {
|
enum SessionState {
|
||||||
idle,
|
idle,
|
||||||
session_starting,
|
starting,
|
||||||
session_started,
|
started,
|
||||||
session_start_failed,
|
start_failed,
|
||||||
session_ending,
|
ending,
|
||||||
session_ended,
|
ended,
|
||||||
session_resuming,
|
resuming,
|
||||||
session_resumed,
|
resumed,
|
||||||
session_resume_failed,
|
resume_failed,
|
||||||
session_suspended,
|
suspended,
|
||||||
}
|
|
||||||
|
|
||||||
typedef StatusUpdatedCallback = void Function(PlayerState);
|
|
||||||
|
|
||||||
enum PlayerState {
|
|
||||||
unknown, // 0
|
|
||||||
idle, // 1
|
|
||||||
playing, // 2
|
|
||||||
paused, // 3
|
|
||||||
buffering, // 4
|
|
||||||
loading, // 5
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ class ExpandedControlsPlayer extends StatelessWidget {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 36, vertical: 0),
|
padding: const EdgeInsets.symmetric(horizontal: 36, vertical: 0),
|
||||||
child: ValueListenableBuilder(
|
child: ValueListenableBuilder(
|
||||||
valueListenable: sessionManager.playerState,
|
valueListenable: sessionManager.remoteMediaClient.playerState,
|
||||||
builder: (context, value, child) {
|
builder: (context, value, child) {
|
||||||
final playerState = value as PlayerState;
|
final playerState = value as PlayerState;
|
||||||
return Row(
|
return Row(
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,51 @@
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_cast_framework/cast.dart';
|
import 'package:flutter_cast_framework/cast.dart';
|
||||||
|
import 'package:flutter_cast_framework/src/cast/RemoteMediaClient.dart';
|
||||||
|
|
||||||
import 'PlatformBridgeApis.dart';
|
import 'PlatformBridgeApis.dart';
|
||||||
import 'cast/CastContext.dart';
|
import 'cast/CastContext.dart';
|
||||||
|
|
||||||
class FlutterCastFramework extends CastFlutterApi {
|
/// Entrypoint for the Flutter Cast Framework
|
||||||
|
class FlutterCastFramework {
|
||||||
final _hostApi = CastHostApi();
|
final _hostApi = CastHostApi();
|
||||||
late CastContext castContext;
|
late _CastFlutterApiImplementor _castFlutterApiImplementor;
|
||||||
|
|
||||||
/// List of namespaces to listen for custom messages
|
/// Get the entrypoint for the Cast SDK. This is immutable and it is expected to never change.
|
||||||
late List<String> namespaces = [];
|
CastContext get castContext => _castFlutterApiImplementor.castContext;
|
||||||
|
|
||||||
|
/// Create the Flutter Cast Framework.
|
||||||
|
/// namespaces is the list of namespaces to listen for custom messages.
|
||||||
FlutterCastFramework.create(List<String> namespaces) {
|
FlutterCastFramework.create(List<String> namespaces) {
|
||||||
debugPrint("FlutterCastFramework created!");
|
debugPrint("FlutterCastFramework created!");
|
||||||
this.namespaces = namespaces;
|
final castContext = CastContext(_hostApi);
|
||||||
this.castContext = CastContext(_hostApi);
|
this._castFlutterApiImplementor = new _CastFlutterApiImplementor(
|
||||||
CastFlutterApi.setup(this);
|
castContext: castContext,
|
||||||
|
namespaces: namespaces,
|
||||||
|
);
|
||||||
|
|
||||||
|
CastFlutterApi.setup(this._castFlutterApiImplementor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This implements Pigeon's API called by the Host platform. This is implemented
|
||||||
|
/// in a separate class to hide the methods
|
||||||
|
class _CastFlutterApiImplementor extends CastFlutterApi {
|
||||||
|
final CastContext castContext;
|
||||||
|
final List<String> namespaces = [];
|
||||||
|
|
||||||
|
SessionManager get sessionManager => castContext.sessionManager;
|
||||||
|
RemoteMediaClient get remoteMediaClient =>
|
||||||
|
castContext.sessionManager.remoteMediaClient;
|
||||||
|
|
||||||
|
_CastFlutterApiImplementor({
|
||||||
|
required this.castContext,
|
||||||
|
List<String>? namespaces,
|
||||||
|
}) {
|
||||||
|
if (namespaces != null) {
|
||||||
|
this.namespaces.addAll(namespaces);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//region CastFlutterApi implementation
|
|
||||||
@override
|
@override
|
||||||
List<String?> getSessionMessageNamespaces() {
|
List<String?> getSessionMessageNamespaces() {
|
||||||
return namespaces;
|
return namespaces;
|
||||||
|
|
@ -31,106 +58,96 @@ class FlutterCastFramework extends CastFlutterApi {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onMessageReceived(CastMessage castMessage) {
|
void onMessageReceived(CastMessage castMessage) {
|
||||||
castContext.sessionManager.platformOnMessageReceived(castMessage);
|
sessionManager.platformOnMessageReceived(castMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
//region Session State handling
|
//region Session State handling
|
||||||
@override
|
@override
|
||||||
void onSessionEnded() {
|
void onSessionEnded() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.ended);
|
||||||
.onSessionStateChanged(SessionState.session_ended);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSessionEnding() {
|
void onSessionEnding() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.ending);
|
||||||
.onSessionStateChanged(SessionState.session_ending);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSessionResumeFailed() {
|
void onSessionResumeFailed() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.resume_failed);
|
||||||
.onSessionStateChanged(SessionState.session_resume_failed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSessionResumed() {
|
void onSessionResumed() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.resumed);
|
||||||
.onSessionStateChanged(SessionState.session_resumed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSessionResuming() {
|
void onSessionResuming() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.resuming);
|
||||||
.onSessionStateChanged(SessionState.session_resuming);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSessionStartFailed() {
|
void onSessionStartFailed() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.start_failed);
|
||||||
.onSessionStateChanged(SessionState.session_start_failed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSessionStarted() {
|
void onSessionStarted() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.started);
|
||||||
.onSessionStateChanged(SessionState.session_started);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSessionStarting() {
|
void onSessionStarting() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.starting);
|
||||||
.onSessionStateChanged(SessionState.session_starting);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSessionSuspended() {
|
void onSessionSuspended() {
|
||||||
castContext.sessionManager
|
sessionManager.onSessionStateChanged(SessionState.suspended);
|
||||||
.onSessionStateChanged(SessionState.session_suspended);
|
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
//region RemoteMediaClient
|
//region RemoteMediaClient
|
||||||
@override
|
@override
|
||||||
void onAdBreakStatusUpdated() {
|
void onAdBreakStatusUpdated() {
|
||||||
castContext.sessionManager.onAdBreakStatusUpdated?.call();
|
remoteMediaClient.onAdBreakStatusUpdated?.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onMediaError() {
|
void onMediaError() {
|
||||||
castContext.sessionManager.onMediaError?.call();
|
remoteMediaClient.onMediaError?.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onMetadataUpdated() {
|
void onMetadataUpdated() {
|
||||||
castContext.sessionManager.onMetadataUpdated?.call();
|
remoteMediaClient.onMetadataUpdated?.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onPreloadStatusUpdated() {
|
void onPreloadStatusUpdated() {
|
||||||
castContext.sessionManager.onPreloadStatusUpdated?.call();
|
remoteMediaClient.onPreloadStatusUpdated?.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onQueueStatusUpdated() {
|
void onQueueStatusUpdated() {
|
||||||
castContext.sessionManager.onQueueStatusUpdated?.call();
|
remoteMediaClient.onQueueStatusUpdated?.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onSendingRemoteMediaRequest() {
|
void onSendingRemoteMediaRequest() {
|
||||||
castContext.sessionManager.onSendingRemoteMediaRequest?.call();
|
remoteMediaClient.onSendingRemoteMediaRequest?.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onStatusUpdated(int playerStateRaw) {
|
void onStatusUpdated(int playerStateRaw) {
|
||||||
final playerState = PlayerState.values[playerStateRaw];
|
final playerState = PlayerState.values[playerStateRaw];
|
||||||
castContext.sessionManager.dispatchOnPlayerStateUpdated(playerState);
|
remoteMediaClient.dispatchPlayerStateUpdate(playerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onProgressUpdated(int progressMs, int durationMs) {
|
void onProgressUpdated(int progressMs, int durationMs) {
|
||||||
castContext.sessionManager.remoteMediaClient.onProgressUpdated
|
remoteMediaClient.onProgressUpdated?.call(progressMs, durationMs);
|
||||||
?.call(progressMs, durationMs);
|
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,6 @@ library widgets;
|
||||||
export 'src/cast/widgets/CastButton.dart';
|
export 'src/cast/widgets/CastButton.dart';
|
||||||
export 'src/cast/widgets/CastIcon.dart';
|
export 'src/cast/widgets/CastIcon.dart';
|
||||||
export 'src/cast/widgets/expanded_controls/ExpandedControls.dart';
|
export 'src/cast/widgets/expanded_controls/ExpandedControls.dart';
|
||||||
|
export 'src/cast/widgets/expanded_controls/ExpandedControlsPlayer.dart';
|
||||||
|
export 'src/cast/widgets/expanded_controls/ExpandedControlsProgress.dart';
|
||||||
|
export 'src/cast/widgets/expanded_controls/ExpandedControlsToolbar.dart';
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.10"
|
version: "0.12.10"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_svg: ^0.22.0
|
flutter_svg: ^0.22.0
|
||||||
|
meta: ^1.7.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue