diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 7ffa295b2..463e8e6b4 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -12,6 +12,7 @@ import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:video_player/video_player.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; +import 'package:chewie/src/helpers/fullscreen_controller.dart'; typedef ChewieRoutePageBuilder = Widget Function( @@ -139,7 +140,7 @@ class ChewieState extends State { ), ); - if (kIsWeb && !_resumeAppliedInFullScreen) { + if (kIsWeb && !_resumeAppliedInFullScreen && !widget.controller.useNativeWebFullscreen) { _resumeAppliedInFullScreen = true; WidgetsBinding.instance.addPostFrameCallback((_) async { if (!mounted) return; @@ -189,7 +190,7 @@ class ChewieState extends State { final wasPlaying = widget.controller.videoPlayerController.value.isPlaying; - if (kIsWeb) { + if (kIsWeb && !widget.controller.useNativeWebFullscreen) { await _reInitializeControllers(wasPlaying); } @@ -335,13 +336,17 @@ class ChewieController extends ChangeNotifier { this.hideControlsTimer = defaultHideControlsTimer, this.controlsSafeAreaMinimum = EdgeInsets.zero, this.pauseOnBackgroundTap = false, + this.useNativeWebFullscreen = true, }) : assert( playbackSpeeds.every((speed) => speed > 0), 'The playbackSpeeds values must all be greater than 0', - ) { + ), + textureId = _textureCounter++ { _initialize(); } + static int _textureCounter = 1; + ChewieController copyWith({ VideoPlayerController? videoPlayerController, OptionsTranslation? optionsTranslation, @@ -394,6 +399,7 @@ class ChewieController extends ChangeNotifier { )? routePageBuilder, bool? pauseOnBackgroundTap, + bool? useNativeWebFullscreen, }) { return ChewieController( draggableProgressBar: draggableProgressBar ?? this.draggableProgressBar, @@ -458,6 +464,7 @@ class ChewieController extends ChangeNotifier { progressIndicatorDelay: progressIndicatorDelay ?? this.progressIndicatorDelay, pauseOnBackgroundTap: pauseOnBackgroundTap ?? this.pauseOnBackgroundTap, + useNativeWebFullscreen: useNativeWebFullscreen ?? this.useNativeWebFullscreen, ); } @@ -630,6 +637,16 @@ class ChewieController extends ChangeNotifier { /// Defines if the player should pause when the background is tapped final bool pauseOnBackgroundTap; + // The texture ID of the video player. + final int textureId; + + /// Defines if native fullscreen should be used on web + /// Default: true + final bool useNativeWebFullscreen; + + // Internal Fullscreen Controller for native web fullscreen handling + final FullscreenController _fullscreenController = FullscreenController(); + static ChewieController of(BuildContext context) { final chewieControllerProvider = context .dependOnInheritedWidgetOfExactType()!; @@ -686,6 +703,10 @@ class ChewieController extends ChangeNotifier { } void toggleFullScreen() { + if (kIsWeb && useNativeWebFullscreen) { + _fullscreenController.toggleFullscreen(textureId); + return; + } _isFullScreen = !_isFullScreen; notifyListeners(); } diff --git a/lib/src/helpers/fullscreen_controller.dart b/lib/src/helpers/fullscreen_controller.dart new file mode 100644 index 000000000..ce3b7c539 --- /dev/null +++ b/lib/src/helpers/fullscreen_controller.dart @@ -0,0 +1 @@ +export 'fullscreen_controller_unsupported.dart' if (dart.library.html) 'fullscreen_controller_web.dart'; \ No newline at end of file diff --git a/lib/src/helpers/fullscreen_controller_unsupported.dart b/lib/src/helpers/fullscreen_controller_unsupported.dart new file mode 100644 index 000000000..abeeea9e0 --- /dev/null +++ b/lib/src/helpers/fullscreen_controller_unsupported.dart @@ -0,0 +1,6 @@ +class FullscreenController { + void toggleFullscreen(int textureId) { + // This is a stub for non-web platforms. + // Fullscreen is handled by the chewie controller itself on mobile. + } +} \ No newline at end of file diff --git a/lib/src/helpers/fullscreen_controller_web.dart b/lib/src/helpers/fullscreen_controller_web.dart new file mode 100644 index 000000000..f4d31f00e --- /dev/null +++ b/lib/src/helpers/fullscreen_controller_web.dart @@ -0,0 +1,35 @@ +import 'package:web/web.dart' as web; +import 'package:flutter/foundation.dart'; + +class FullscreenController { + void toggleFullscreen(int textureId) { + + final videoElement = web.document.getElementById('videoElement-$textureId'); + + if (videoElement == null) { + // As a fallback, we try to find ANY video element. This is not robust if there are multiple videos. + final fallbackVideoElement = web.document.querySelector('video'); + if (fallbackVideoElement != null) { + _requestFullscreen(fallbackVideoElement); + } else { + debugPrint('Error: No video element found for fullscreen toggle.'); + } + return; + } + + _requestFullscreen(videoElement); + } + + void _requestFullscreen(web.Element videoElement) { + if (web.document.fullscreenElement == null) { + try { + videoElement.requestFullscreen(); + } catch (e) { + debugPrint('Error requesting fullscreen: $e'); + } + } else { + web.document.exitFullscreen(); + } + } +} + diff --git a/pubspec.yaml b/pubspec.yaml index 047272a27..f515eff5d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: provider: ^6.1.5+1 video_player: ^2.10.0 wakelock_plus: ^1.3.2 + web: ^1.1.1 dev_dependencies: flutter_test: