Skip to content

[video_player] Add optional web options [Platform interface] #4433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## NEXT
## 6.2.0

* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
* Adds web options to customize control's list and displaying context menu.

## 6.1.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ abstract class VideoPlayerPlatform extends PlatformInterface {
Future<void> setMixWithOthers(bool mixWithOthers) {
throw UnimplementedError('setMixWithOthers() has not been implemented.');
}

/// Sets additional options on web
Future<void> setWebOptions(int textureId, VideoPlayerWebOptions options) {
throw UnimplementedError('setWebOptions() has not been implemented.');
}
}

class _PlaceholderImplementation extends VideoPlayerPlatform {}
Expand Down Expand Up @@ -365,14 +370,15 @@ class DurationRange {
/// [VideoPlayerOptions] can be optionally used to set additional player settings
@immutable
class VideoPlayerOptions {
/// set additional optional player settings
/// Set additional optional player settings
// TODO(stuartmorgan): Temporarily suppress warnings about not using const
// in all of the other video player packages, fix this, and then update
// the other packages to use const.
// ignore: prefer_const_constructors_in_immutables
VideoPlayerOptions({
this.mixWithOthers = false,
this.allowBackgroundPlayback = false,
this.webOptions,
});

/// Set this to true to keep playing video in background, when app goes in background.
Expand All @@ -385,4 +391,86 @@ class VideoPlayerOptions {
/// Note: This option will be silently ignored in the web platform (there is
/// currently no way to implement this feature in this platform).
final bool mixWithOthers;

/// Additional web controls
final VideoPlayerWebOptions? webOptions;
}

/// [VideoPlayerWebOptions] can be optionally used to set additional web settings
@immutable
class VideoPlayerWebOptions {
/// [VideoPlayerWebOptions] can be optionally used to set additional web settings
const VideoPlayerWebOptions({
this.controls = const VideoPlayerWebOptionsControls.disabled(),
this.allowContextMenu = true,
this.allowRemotePlayback = true,
});

/// Additional settings for how control options are displayed
final VideoPlayerWebOptionsControls controls;

/// Whether context menu (right click) is allowed
final bool allowContextMenu;

/// Whether remote playback is allowed
final bool allowRemotePlayback;
}

/// [VideoPlayerWebOptions] can be used to set how control options are displayed
@immutable
class VideoPlayerWebOptionsControls {
/// Enables controls and sets how the options are displayed
const VideoPlayerWebOptionsControls.enabled({
this.allowDownload = true,
this.allowFullscreen = true,
this.allowPlaybackRate = true,
this.allowPictureInPicture = true,
}) : enabled = true;

/// Disables control options. Default behavior.
const VideoPlayerWebOptionsControls.disabled()
: enabled = false,
allowDownload = false,
allowFullscreen = false,
allowPlaybackRate = false,
allowPictureInPicture = false;

/// Whether native controls are enabled
final bool enabled;

/// Whether downloaded control is displayed
///
/// Only applicable when [controlsEnabled] is true
final bool allowDownload;

/// Whether fullscreen control is enabled
///
/// Only applicable when [controlsEnabled] is true
final bool allowFullscreen;

/// Whether playback rate control is displayed
///
/// Only applicable when [controlsEnabled] is true
final bool allowPlaybackRate;

/// Whether picture in picture control is displayed
///
/// Only applicable when [controlsEnabled] is true
final bool allowPictureInPicture;

/// A string representation of disallowed controls
String get controlsList {
final List<String> controlsList = <String>[];
if (!allowDownload) {
controlsList.add('nodownload');
}
if (!allowFullscreen) {
controlsList.add('nofullscreen');
}
if (!allowPlaybackRate) {
controlsList.add('noplaybackrate');
}

return controlsList.join(' ');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/video_player/
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
version: 6.1.0
version: 6.2.0

environment:
sdk: ">=2.18.0 <4.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@ void main() {
// Store the initial instance before any tests change it.
final VideoPlayerPlatform initialInstance = VideoPlayerPlatform.instance;

test('default implementation throws uninimpletemented', () async {
test('default implementation init throws unimplemented', () async {
await expectLater(() => initialInstance.init(), throwsUnimplementedError);
});

test('default implementation setWebOptions throws unimplemented', () async {
await expectLater(
() => initialInstance.setWebOptions(
1,
const VideoPlayerWebOptions(),
),
throwsUnimplementedError,
);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_test/flutter_test.dart';
import 'package:video_player_platform_interface/video_player_platform_interface.dart';

void main() {
group('VideoPlayerWebOptionsControls', () {
late VideoPlayerWebOptionsControls controls;

group('when disabled', () {
setUp(() {
controls = const VideoPlayerWebOptionsControls.disabled();
});

test(
'expect enabled isFalse',
() {
expect(controls.enabled, isFalse);
},
);
});

group('when enabled', () {
group('and all options are allowed', () {
setUp(() {
controls = const VideoPlayerWebOptionsControls.enabled();
});

test(
'expect enabled isTrue',
() {
expect(controls.enabled, isTrue);
expect(controls.allowDownload, isTrue);
expect(controls.allowFullscreen, isTrue);
expect(controls.allowPlaybackRate, isTrue);
expect(controls.allowPictureInPicture, isTrue);
},
);

test(
'expect controlsList isEmpty',
() {
expect(controls.controlsList, isEmpty);
},
);
});

group('and some options are disallowed', () {
setUp(() {
controls = const VideoPlayerWebOptionsControls.enabled(
allowDownload: false,
allowFullscreen: false,
allowPlaybackRate: false,
);
});

test(
'expect enabled isTrue',
() {
expect(controls.enabled, isTrue);
expect(controls.allowDownload, isFalse);
expect(controls.allowFullscreen, isFalse);
expect(controls.allowPlaybackRate, isFalse);
expect(controls.allowPictureInPicture, isTrue);
},
);

test(
'expect controlsList is correct',
() {
expect(
controls.controlsList,
'nodownload nofullscreen noplaybackrate',
);
},
);
});
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_test/flutter_test.dart';
import 'package:video_player_platform_interface/video_player_platform_interface.dart';

void main() {
test(
'VideoPlayerOptions controls defaults to VideoPlayerWebOptionsControls.disabled()',
() {
const VideoPlayerWebOptions options = VideoPlayerWebOptions();
expect(options.controls, const VideoPlayerWebOptionsControls.disabled());
},
);

test(
'VideoPlayerOptions allowContextMenu defaults to true',
() {
const VideoPlayerWebOptions options = VideoPlayerWebOptions();
expect(options.allowContextMenu, isTrue);
},
);

test(
'VideoPlayerOptions allowRemotePlayback defaults to true',
() {
const VideoPlayerWebOptions options = VideoPlayerWebOptions();
expect(options.allowRemotePlayback, isTrue);
},
);
}