Skip to content

Commit

Permalink
Merge pull request #201 from bitmovin/feature/player-info-widget
Browse files Browse the repository at this point in the history
Introduce player info widget and add it to event subscription sample
  • Loading branch information
hawk23 authored Nov 29, 2024
2 parents 8a07108 + 435b041 commit 6614544
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 3 deletions.
12 changes: 11 additions & 1 deletion example/lib/pages/event_subscription.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:bitmovin_player_example/controls.dart';
import 'package:bitmovin_player_example/env/env.dart';
import 'package:bitmovin_player_example/events.dart';
import 'package:bitmovin_player_example/platform.dart';
import 'package:bitmovin_player_example/player_info.dart';
import 'package:bitmovin_player_example/player_view_container.dart';
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
Expand All @@ -17,6 +18,7 @@ class EventSubscription extends StatefulWidget {

class _EventSubscriptionState extends State<EventSubscription> {
final _eventsKey = GlobalKey<EventsState>();
final _playerInfoKey = GlobalKey<PlayerInfoState>();
final _sourceConfig = SourceConfig(
url: isIOS
? 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8'
Expand All @@ -32,6 +34,8 @@ class _EventSubscriptionState extends State<EventSubscription> {
final _logger = Logger();

void _onEvent(Event event) {
_playerInfoKey.currentState?.updatePlayerInfo(_player, event);

final eventName = '${event.runtimeType}';
final eventData = '$eventName ${event.toJson()}';
_logger.d(eventData);
Expand Down Expand Up @@ -115,10 +119,16 @@ class _EventSubscriptionState extends State<EventSubscription> {
),
Expanded(
child: Container(
margin: const EdgeInsets.fromLTRB(10, 10, 10, 40),
margin: const EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Events(key: _eventsKey),
),
),
Expanded(
child: Container(
margin: const EdgeInsets.fromLTRB(10, 10, 10, 10),
child: PlayerInfo(key: _playerInfoKey),
),
),
],
),
);
Expand Down
98 changes: 98 additions & 0 deletions example/lib/player_info.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import 'package:bitmovin_player/bitmovin_player.dart';
import 'package:flutter/material.dart';

/// Maintains a table of player information that is updated dynamically based
/// on received player events. Player state only gets added to the table if at
/// least one event has been received for the corresponding state.
class PlayerInfo extends StatefulWidget {
const PlayerInfo({super.key});

@override
State<StatefulWidget> createState() => PlayerInfoState();
}

class PlayerInfoState extends State<PlayerInfo> {
final Map<String, dynamic> _data = {};

Future<void> updatePlayerInfo(Player player, Event event) async {
if (event is ReadyEvent) {
final isLive = await player.isLive;
_updatePlayerInfoForField('isLive', Future.value(isLive));

final availableSubtitles = await player.availableSubtitles;
final subtitleLanguages = availableSubtitles.map((element) {
return element.label;
}).toList();

if (subtitleLanguages.isNotEmpty) {
_updatePlayerInfoForField(
'availableSubtitles',
Future.value(
subtitleLanguages.join(', '),
),
);
}

if (isLive) {
_updatePlayerInfoForField('maxTimeShift', player.maxTimeShift);
} else {
_updatePlayerInfoForField('duration', player.duration);
}
}
if (event is PlayingEvent || event is PausedEvent) {
_updatePlayerInfoForField('isPlaying', player.isPlaying);
}
if (event is TimeChangedEvent) {
_updatePlayerInfoForField('currentTime', player.currentTime);
final isLive = await player.isLive;
if (isLive) {
_updatePlayerInfoForField('timeShift', player.timeShift);
}
}
if (event is SubtitleChangedEvent) {
final subtitle = await player.subtitle;
_updatePlayerInfoForField('subtitle', Future.value(subtitle.label));
}
if (event is CastAvailableEvent) {
_updatePlayerInfoForField('isCastAvailable', player.isCastAvailable);
}
if (event is CastStartedEvent || event is CastStoppedEvent) {
_updatePlayerInfoForField('isCasting', player.isCasting);
}
}

void _updatePlayerInfoForField(String field, Future<dynamic> value) {
value.then((dynamic value) {
setState(() {
_data[field] = value.toString();
});
});
}

@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _data.length,
itemBuilder: (context, index) {
final key = _data.keys.elementAt(index);
final value = _data[key];

return Padding(
padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 1),
child: Row(
children: [
Expanded(
flex: 2,
child: Text(key),
),
Expanded(
flex: 3,
child: Text(value.toString()),
),
],
),
);
},
);
}
}
4 changes: 2 additions & 2 deletions lib/src/platform/web/player_platform_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ class PlayerPlatformWeb extends PlayerPlatformInterface {
return div;
}

// TODO(mario): implement subtitle tracks API for Web
@override
Future<List<SubtitleTrack>> get availableSubtitles async =>
throw UnimplementedError();
Future<List<SubtitleTrack>> get availableSubtitles async => [];

@override
Future<void> castStop() async => _player.castStop();
Expand Down

0 comments on commit 6614544

Please sign in to comment.