Skip to content
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

Made it so that a BetterPlayerEvent with a betterPlayerEventType of pipStart is posted whenever we enter pip mode on iOS devices - DC #4

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions ios/Classes/BetterPlayerPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
double width = [argsMap[@"width"] doubleValue];
double height = [argsMap[@"height"] doubleValue];
[player enablePictureInPicture:CGRectMake(left, top, width, height)];
result(nil);
} else if ([@"isPictureInPictureSupported" isEqualToString:call.method]){
if (@available(iOS 9.0, *)){
if ([AVPictureInPictureController isPictureInPictureSupported]){
Expand Down
9 changes: 6 additions & 3 deletions lib/src/core/better_player_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:better_player/src/subtitles/better_player_subtitles_factory.dart
import 'package:better_player/src/video_player/video_player.dart';
import 'package:better_player/src/video_player/video_player_platform_interface.dart';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

Expand Down Expand Up @@ -1067,15 +1068,15 @@ class BetterPlayerController {
_wasInFullScreenBeforePiP = _isFullScreen;
_wasControlsEnabledBeforePiP = _controlsEnabled;
setControlsEnabled(false);
if (Platform.isAndroid) {
if (defaultTargetPlatform == TargetPlatform.android) {
_wasInFullScreenBeforePiP = _isFullScreen;
await videoPlayerController?.enablePictureInPicture(
left: 0, top: 0, width: 0, height: 0);
enterFullScreen();
_postEvent(BetterPlayerEvent(BetterPlayerEventType.pipStart));
return;
}
if (Platform.isIOS) {
if (defaultTargetPlatform == TargetPlatform.iOS) {
final RenderBox? renderBox = betterPlayerGlobalKey.currentContext!
.findRenderObject() as RenderBox?;
if (renderBox == null) {
Expand All @@ -1085,12 +1086,14 @@ class BetterPlayerController {
return;
}
final Offset position = renderBox.localToGlobal(Offset.zero);
return videoPlayerController?.enablePictureInPicture(
await videoPlayerController?.enablePictureInPicture(
left: position.dx,
top: position.dy,
width: renderBox.size.width,
height: renderBox.size.height,
);
_postEvent(BetterPlayerEvent(BetterPlayerEventType.pipStart));
return;
} else {
BetterPlayerUtils.log("Unsupported PiP in current platform.");
}
Expand Down
45 changes: 45 additions & 0 deletions test/better_player_controller_test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import 'package:better_player/better_player.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';

import 'better_player_mock_controller.dart';
import 'better_player_test_utils.dart';
import 'mock_global_key.dart';
import 'mock_method_channel.dart';
import 'mock_video_player_controller.dart';

Expand Down Expand Up @@ -431,6 +434,48 @@ void main() {
await Future.delayed(const Duration(milliseconds: 3000), () {});
expect(eventCount, 3);
});

test("enablePictureInPicture sends event on iOS", () async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final BetterPlayerController betterPlayerMockController =
BetterPlayerTestUtils.setupBetterPlayerMockController();
final mockVideoPlayerController =
BetterPlayerTestUtils.setupMockVideoPlayerControler();
mockVideoPlayerController.isPipSupported = true;
betterPlayerMockController.videoPlayerController =
mockVideoPlayerController;
final mockGlobalKey = MockGlobalKey();
int pipStartCalls = 0;
betterPlayerMockController.addEventsListener((event) {
if (event.betterPlayerEventType == BetterPlayerEventType.pipStart) {
pipStartCalls += 1;
}
});
betterPlayerMockController.enablePictureInPicture(mockGlobalKey);
await Future.delayed(const Duration(milliseconds: 3000), () {});
expect(pipStartCalls, 1);
});

test("enablePictureInPicture sends event on Android", () async {
debugDefaultTargetPlatformOverride = TargetPlatform.android;
final BetterPlayerController betterPlayerMockController =
BetterPlayerTestUtils.setupBetterPlayerMockController();
final mockVideoPlayerController =
BetterPlayerTestUtils.setupMockVideoPlayerControler();
mockVideoPlayerController.isPipSupported = true;
betterPlayerMockController.videoPlayerController =
mockVideoPlayerController;
final mockGlobalKey = MockGlobalKey();
int pipStartCalls = 0;
betterPlayerMockController.addEventsListener((event) {
if (event.betterPlayerEventType == BetterPlayerEventType.pipStart) {
pipStartCalls += 1;
}
});
betterPlayerMockController.enablePictureInPicture(mockGlobalKey);
await Future.delayed(const Duration(milliseconds: 3000), () {});
expect(pipStartCalls, 1);
});
},
);
}
96 changes: 96 additions & 0 deletions test/mock_build_context.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import 'mock_render_box.dart';

class MockBuildContext extends BuildContext {
@override
bool get debugDoingBuild => throw UnimplementedError();

@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor,
{Object? aspect}) {
throw UnimplementedError();
}

@override
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>(
{Object? aspect}) {
throw UnimplementedError();
}

@override
DiagnosticsNode describeElement(String name,
{DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty}) {
throw UnimplementedError();
}

@override
List<DiagnosticsNode> describeMissingAncestor(
{required Type expectedAncestorType}) {
throw UnimplementedError();
}

@override
DiagnosticsNode describeOwnershipChain(String name) {
throw UnimplementedError();
}

@override
DiagnosticsNode describeWidget(String name,
{DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty}) {
throw UnimplementedError();
}

@override
void dispatchNotification(Notification notification) {}

@override
T? findAncestorRenderObjectOfType<T extends RenderObject>() {
throw UnimplementedError();
}

@override
T? findAncestorStateOfType<T extends State<StatefulWidget>>() {
throw UnimplementedError();
}

@override
T? findAncestorWidgetOfExactType<T extends Widget>() {
throw UnimplementedError();
}

@override
RenderObject? findRenderObject() {
return MockRenderBox();
}

@override
T? findRootAncestorStateOfType<T extends State<StatefulWidget>>() {
throw UnimplementedError();
}

@override
InheritedElement?
getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
throw UnimplementedError();
}

@override
bool get mounted => throw UnimplementedError();

@override
BuildOwner? get owner => throw UnimplementedError();

@override
Size? get size => throw UnimplementedError();

@override
void visitAncestorElements(bool Function(Element element) visitor) {}

@override
void visitChildElements(ElementVisitor visitor) {}

@override
Widget get widget => throw UnimplementedError();
}
9 changes: 9 additions & 0 deletions test/mock_global_key.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:flutter/material.dart';
import 'mock_build_context.dart';

class MockGlobalKey extends GlobalKey {
MockGlobalKey() : super.constructor();

@override
BuildContext? get currentContext => MockBuildContext();
}
11 changes: 11 additions & 0 deletions test/mock_render_box.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:flutter/material.dart';

class MockRenderBox extends RenderBox {
@override
Offset localToGlobal(Offset point, {RenderObject? ancestor}) {
return Offset(0, 0);
}

@override
Size get size => Size.zero;
}
6 changes: 6 additions & 0 deletions test/mock_video_player_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class MockVideoPlayerController extends VideoPlayerController {
bool isLoopingState = false;
double volume = 0.0;
double speed = 1.0;
bool isPipSupported = false;

@override
Future<void> play() async {
Expand Down Expand Up @@ -75,4 +76,9 @@ class MockVideoPlayerController extends VideoPlayerController {
String? clearKey,
String? videoExtension,
}) async {}

@override
Future<bool?> isPictureInPictureSupported() {
return Future.value(isPipSupported);
}
}