Skip to content

Commit

Permalink
Merge pull request #54 from apivideo/web-inject-player-sdk
Browse files Browse the repository at this point in the history
feat(web) Inject player SDK js bundle
  • Loading branch information
ThibaultBee committed Dec 5, 2023
2 parents 515bb61 + 5877de1 commit a0eee3c
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 95 deletions.
20 changes: 0 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ your app.
- [Project description](#project-description)
- [Getting started](#getting-started)
- [Installation](#installation)
- [Web usage](#web-usage)
- [Documentation](#documentation)
- [Instantiation](#instantiation)
- [1. The ApiVideoPlayerController](#1-the-apivideoplayercontroller)
Expand Down Expand Up @@ -58,25 +57,6 @@ Run the following command at the root of your project.
flutter pub add apivideo_player
```

#### Web usage

If you want to use your application as a web app, you need to add the [api.video player SDK](https://github.com/apivideo/api.video-player-sdk) script in `web/index.html` from the root of your project.

```html
<!DOCTYPE html>
<html>
<head>
...
<!-- Add the following line inside of the head tag -->
<script src="https://unpkg.com/@api.video/player-sdk" defer></script>
</head>

<body>
...
</body>
</html>
```

## Documentation

### Instantiation
Expand Down
1 change: 0 additions & 1 deletion example/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
</script>
<!-- This script adds the flutter initialization JS code -->
<script src="flutter.js" defer></script>
<script src="https://unpkg.com/@api.video/player-sdk" defer></script>
</head>
<body>
<script>
Expand Down
6 changes: 1 addition & 5 deletions lib/src/apivideo_player_life_cycle_observer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ class PlayerLifeCycleObserver extends Object with WidgetsBindingObserver {
case AppLifecycleState.paused:
pause();
break;
case AppLifecycleState.inactive:
break;
case AppLifecycleState.detached:
break;
case AppLifecycleState.hidden:
default:
break;
}
}
Expand Down
162 changes: 97 additions & 65 deletions lib/src/platform/apivideo_player_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ class ApiVideoPlayerPlugin extends ApiVideoPlayerPlatform {
ui_web.platformViewRegistry.registerViewFactory(
'playerDiv$textureId', (int viewId) => videoElement);

_players[textureId]!
..videoOptions = videoOptions
..isCreated = true;
_players[textureId]!.videoOptions = videoOptions;
}

@override
Expand Down Expand Up @@ -171,11 +169,14 @@ class ApiVideoPlayerPlugin extends ApiVideoPlayerPlatform {
);

@override
Future<void> setVolume(int textureId, double volume) => Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'setVolume',
args: [volume],
);
Future<void> setVolume(int textureId, double volume) async {
Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'setVolume',
args: [volume],
);
return;
}

@override
Future<bool> getIsMuted(int textureId) => Utils.getPromiseFromJs<bool>(
Expand All @@ -184,10 +185,13 @@ class ApiVideoPlayerPlugin extends ApiVideoPlayerPlatform {
);

@override
Future<void> setIsMuted(int textureId, bool isMuted) => Utils.callJsMethod(
textureId: textureId,
jsMethodName: isMuted ? 'mute' : 'unmute',
);
Future<void> setIsMuted(int textureId, bool isMuted) async {
Utils.callJsMethod(
textureId: textureId,
jsMethodName: isMuted ? 'mute' : 'unmute',
);
return;
}

@override
Future<bool> getAutoplay(int textureId) async {
Expand All @@ -200,18 +204,19 @@ class ApiVideoPlayerPlugin extends ApiVideoPlayerPlatform {
}

@override
Future<void> setAutoplay(int textureId, bool autoplay) {
Future<void> setAutoplay(int textureId, bool autoplay) async {
if (_players[textureId] == null) {
throw Exception(
'No player found for this texture id: $textureId. Cannot set autoplay value',
);
}
_players[textureId]!.autoplay = autoplay;
return Utils.callJsMethod(
Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'setAutoplay',
args: [autoplay],
);
return;
}

@override
Expand All @@ -221,12 +226,14 @@ class ApiVideoPlayerPlugin extends ApiVideoPlayerPlatform {
);

@override
Future<void> setIsLooping(int textureId, bool isLooping) =>
Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'setLoop',
args: [isLooping],
);
Future<void> setIsLooping(int textureId, bool isLooping) async {
Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'setLoop',
args: [isLooping],
);
return;
}

@override
Future<Size?> getVideoSize(int textureId) async {
Expand All @@ -243,12 +250,14 @@ class ApiVideoPlayerPlugin extends ApiVideoPlayerPlatform {
}

@override
Future<void> setPlaybackRate(int textureId, double speedRate) =>
Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'setPlaybackRate',
args: [speedRate],
);
Future<void> setPlaybackRate(int textureId, double speedRate) async {
Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'setPlaybackRate',
args: [speedRate],
);
return;
}

@override
Future<double> getPlaybackRate(int textureId) =>
Expand Down Expand Up @@ -286,8 +295,23 @@ class ApiVideoPlayerPlugin extends ApiVideoPlayerPlatform {
}

void injectScripts() {
if (document.body?.querySelector('#playersState') == null) {
const String jsString = '''
document.body?.nodes.add(ScriptElement()
..type = 'text/javascript'
..innerHtml = '''
// fix JS module loading - https://github.com/flutter/flutter/issues/126713
if (typeof window.define == 'function') {
delete window.define.amd;
}
delete window.exports;
delete window.module;
''');

document.body!.nodes.add(ScriptElement()
..src = 'https://unpkg.com/@api.video/player-sdk'
..type = 'application/javascript'
..addEventListener('load', (event) {
if (document.body?.querySelector('#playersState') == null) {
const String jsString = '''
window.state = {
getCurrentTime: async function(playerId) {
if (!playerId || !window[playerId]) return;
Expand Down Expand Up @@ -340,45 +364,53 @@ class ApiVideoPlayerPlugin extends ApiVideoPlayerPlatform {
}
};
''';
final ScriptElement script = ScriptElement()
..id = 'playersState'
..innerText = jsString;
script.innerHtml = script.innerHtml?.replaceAll('<br>', '');
document.body?.insertAdjacentElement('beforeend', script);
}
final ScriptElement script = ScriptElement()
..id = 'playersState'
..innerText = jsString;
script.innerHtml = script.innerHtml?.replaceAll('<br>', '');
document.body?.insertAdjacentElement('beforeend', script);
}

final String jsString = '''
window.player$textureId = new PlayerSdk(
"#playerDiv$textureId",
{
id: "${_players[textureId]!.videoOptions!.videoId}",
chromeless: true,
live: ${_players[textureId]!.videoOptions!.type == VideoType.live},
autoplay: ${_players[textureId]!.autoplay},
final player = _players[textureId];
if (player == null) {
throw Exception('No player found for this texture id: $textureId.');
}
);
''';
final ScriptElement script = ScriptElement()
..id = 'apiVideoPlayerJsScript$textureId'
..innerText = jsString;
script.innerHtml = script.innerHtml?.replaceAll('<br>', '');
document.body?.insertAdjacentElement('beforeend', script);

if (_players[textureId]!.playerEvents == null) {
throw Exception('No player events for this texture id: $textureId.');
}
for (var playerEvent in PlayerEventType.values) {
Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'addEventListener',
args: [
playerEvent.displayPlayerSdkName,
(userData) => _players[textureId]!
.playerEvents!
.add(PlayerEvent(type: playerEvent)),
],
);
}

final String jsString = '''
window.player$textureId = new PlayerSdk(
"#playerDiv$textureId",
{
id: "${player.videoOptions!.videoId}",
chromeless: true,
live: ${player.videoOptions!.type == VideoType.live},
autoplay: ${player.autoplay},
}
);
''';
final ScriptElement script = ScriptElement()
..id = 'apiVideoPlayerJsScript$textureId'
..innerText = jsString;
script.innerHtml = script.innerHtml?.replaceAll('<br>', '');
document.body?.insertAdjacentElement('beforeend', script);

if (player.playerEvents == null) {
throw Exception(
'No player events for this texture id: $textureId.');
}
for (var playerEvent in PlayerEventType.values) {
Utils.callJsMethod(
textureId: textureId,
jsMethodName: 'addEventListener',
args: [
playerEvent.displayPlayerSdkName,
(userData) =>
player.playerEvents!.add(PlayerEvent(type: playerEvent)),
],
);
}

player.isCreated = true;
}));

// Hide iframe border
if (document.head != null) {
Expand Down
8 changes: 4 additions & 4 deletions lib/src/platform/web/utils/conversion.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import 'dart:js_util';

class Utils {
/// Calls a JS object method that returns void only.
static Future<void> callJsMethod({
static dynamic callJsMethod({
required int textureId,
required String jsMethodName,
List<dynamic>? args,
}) async {
}) {
ArgumentError.checkNotNull(js.context['player$textureId'], 'player');
js.JsObject.fromBrowserObject(js.context['player$textureId']).callMethod(
return js.JsObject.fromBrowserObject(js.context['player$textureId'])
.callMethod(
jsMethodName,
args,
);
return;
}

/// Handle a JS [Promise] that returns a value other than void
Expand Down

0 comments on commit a0eee3c

Please sign in to comment.