mirror of
https://github.com/flutter/packages.git
synced 2025-07-03 09:08:54 +08:00
[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:
@ -1,6 +1,7 @@
|
|||||||
## NEXT
|
## 6.2.0
|
||||||
|
|
||||||
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
|
* 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
|
## 6.1.0
|
||||||
|
|
||||||
|
@ -102,6 +102,11 @@ abstract class VideoPlayerPlatform extends PlatformInterface {
|
|||||||
Future<void> setMixWithOthers(bool mixWithOthers) {
|
Future<void> setMixWithOthers(bool mixWithOthers) {
|
||||||
throw UnimplementedError('setMixWithOthers() has not been implemented.');
|
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 {}
|
class _PlaceholderImplementation extends VideoPlayerPlatform {}
|
||||||
@ -365,7 +370,7 @@ class DurationRange {
|
|||||||
/// [VideoPlayerOptions] can be optionally used to set additional player settings
|
/// [VideoPlayerOptions] can be optionally used to set additional player settings
|
||||||
@immutable
|
@immutable
|
||||||
class VideoPlayerOptions {
|
class VideoPlayerOptions {
|
||||||
/// set additional optional player settings
|
/// Set additional optional player settings
|
||||||
// TODO(stuartmorgan): Temporarily suppress warnings about not using const
|
// TODO(stuartmorgan): Temporarily suppress warnings about not using const
|
||||||
// in all of the other video player packages, fix this, and then update
|
// in all of the other video player packages, fix this, and then update
|
||||||
// the other packages to use const.
|
// the other packages to use const.
|
||||||
@ -373,6 +378,7 @@ class VideoPlayerOptions {
|
|||||||
VideoPlayerOptions({
|
VideoPlayerOptions({
|
||||||
this.mixWithOthers = false,
|
this.mixWithOthers = false,
|
||||||
this.allowBackgroundPlayback = false,
|
this.allowBackgroundPlayback = false,
|
||||||
|
this.webOptions,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Set this to true to keep playing video in background, when app goes in background.
|
/// 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
|
/// Note: This option will be silently ignored in the web platform (there is
|
||||||
/// currently no way to implement this feature in this platform).
|
/// currently no way to implement this feature in this platform).
|
||||||
final bool mixWithOthers;
|
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(' ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
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
|
# 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
|
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
|
||||||
version: 6.1.0
|
version: 6.2.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.18.0 <4.0.0"
|
sdk: ">=2.18.0 <4.0.0"
|
||||||
|
@ -9,7 +9,17 @@ void main() {
|
|||||||
// Store the initial instance before any tests change it.
|
// Store the initial instance before any tests change it.
|
||||||
final VideoPlayerPlatform initialInstance = VideoPlayerPlatform.instance;
|
final VideoPlayerPlatform initialInstance = VideoPlayerPlatform.instance;
|
||||||
|
|
||||||
test('default implementation throws uninimpletemented', () async {
|
test('default implementation init throws unimplemented', () async {
|
||||||
await expectLater(() => initialInstance.init(), throwsUnimplementedError);
|
await expectLater(() => initialInstance.init(), throwsUnimplementedError);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('default implementation setWebOptions throws unimplemented', () async {
|
||||||
|
await expectLater(
|
||||||
|
() => initialInstance.setWebOptions(
|
||||||
|
1,
|
||||||
|
const VideoPlayerWebOptions(),
|
||||||
|
),
|
||||||
|
throwsUnimplementedError,
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -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',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -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);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
Reference in New Issue
Block a user