Skip to content
Closed
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
4 changes: 4 additions & 0 deletions packages/video_player/video_player/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.13.1

* Ignores late position updates from pending platform requests after disposal.

## 2.13.0

* Adds `preventsDisplaySleepDuringVideoPlayback` to `VideoPlayerOptions` and
Expand Down
4 changes: 4 additions & 0 deletions packages/video_player/video_player/lib/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,10 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
}

void _updatePosition(Duration position) {
// A pending platform seek or position request can complete after disposal.
if (_isDisposed) {
return;
}
// The underlying native implementation on some platforms sometimes reports
// a position slightly past the reported max duration. Clamp to the duration
// to insulate clients from this behavior.
Expand Down
2 changes: 1 addition & 1 deletion packages/video_player/video_player/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for displaying inline video with other Flutter
widgets on Android, iOS, macOS and web.
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.13.0
version: 2.13.1

environment:
sdk: ^3.12.0
Expand Down
52 changes: 45 additions & 7 deletions packages/video_player/video_player/test/video_player_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,24 @@ void main() {
});

group('seekTo', () {
test('ignores a pending seek result after disposal', () async {
final controller = VideoPlayerController.networkUrl(_localhostUri);
addTearDown(controller.dispose);
await controller.initialize();

final seekCompleter = Completer<void>();
fakeVideoPlayerPlatform.seekCompleter = seekCompleter;
final VideoPlayerValue valueBeforeSeek = controller.value;
final Future<void> pendingSeek = controller.seekTo(const Duration(milliseconds: 500));
expect(fakeVideoPlayerPlatform.calls.last, 'seekTo');

await controller.dispose();
seekCompleter.complete();
await pendingSeek;

expect(controller.value, valueBeforeSeek);
});

test('works', () async {
final controller = VideoPlayerController.networkUrl(_localhostUri);
addTearDown(controller.dispose);
Expand Down Expand Up @@ -1030,13 +1048,11 @@ void main() {
}

expect(isSorted, false, reason: 'Expected captions to be unsorted');
expect(captions.map((Caption c) => c.text).toList(), <String>[
'one',
'two',
'three',
'five',
'four',
], reason: 'Captions should be in original unsorted order');
expect(
captions.map((Caption c) => c.text).toList(),
<String>['one', 'two', 'three', 'five', 'four'],
reason: 'Captions should be in original unsorted order',
);
});

test('works when seeking, includes all captions', () async {
Expand Down Expand Up @@ -1447,6 +1463,26 @@ void main() {
});

group('Platform callbacks', () {
test('ignores a pending completion seek result after disposal', () async {
final controller = VideoPlayerController.networkUrl(_localhostUri);
addTearDown(controller.dispose);
await controller.initialize();

final seekCompleter = Completer<void>();
fakeVideoPlayerPlatform.seekCompleter = seekCompleter;
fakeVideoPlayerPlatform.streams[controller.playerId]!.add(
VideoEvent(eventType: VideoEventType.completed),
);
await Future<void>.delayed(Duration.zero);
expect(fakeVideoPlayerPlatform.calls.last, 'seekTo');
final VideoPlayerValue valueBeforeDisposal = controller.value;

await controller.dispose();
seekCompleter.complete();
await Future<void>.delayed(Duration.zero);
expect(controller.value, valueBeforeDisposal);
});

testWidgets('playing completed', (WidgetTester tester) async {
final controller = VideoPlayerController.networkUrl(_localhostUri);

Expand Down Expand Up @@ -1916,6 +1952,7 @@ void main() {

class FakeVideoPlayerPlatform extends VideoPlayerPlatform {
Completer<bool> initialized = Completer<bool>();
Completer<void>? seekCompleter;
List<String> calls = <String>[];
List<DataSource> dataSources = <DataSource>[];
List<VideoViewType> viewTypes = <VideoViewType>[];
Expand Down Expand Up @@ -2003,6 +2040,7 @@ class FakeVideoPlayerPlatform extends VideoPlayerPlatform {
@override
Future<void> seekTo(int playerId, Duration position) async {
calls.add('seekTo');
await seekCompleter?.future;
_positions[playerId] = position;
}

Expand Down
Loading