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

Platform Interface PR for Video Player Web Options (https://github.com/flutter/packages/pull/3259).
This commit is contained in:
James Leahy
2023-07-18 00:49:55 +02:00
committed by GitHub
parent 4669c45fbd
commit c4a57a029a
6 changed files with 217 additions and 4 deletions

View File

@ -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

View File

@ -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 {}
@ -365,7 +370,7 @@ 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.
@ -373,6 +378,7 @@ class VideoPlayerOptions {
VideoPlayerOptions({
this.mixWithOthers = false,
this.allowBackgroundPlayback = false,
this.webOptions,
});
/// Set this to true to keep playing video in background, when app goes in background.
@ -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(' ');
}
}

View File

@ -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"

View File

@ -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,
);
});
}

View File

@ -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',
);
},
);
});
});
});
}

View File

@ -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);
},
);
}