| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- import 'dart:async';
- import 'package:chewie/src/chewie_progress_colors.dart';
- import 'package:chewie/src/player_with_controls.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter/widgets.dart';
- import 'package:video_player/video_player.dart';
- import 'package:wakelock/wakelock.dart';
- typedef Widget ChewieRoutePageBuilder(
- BuildContext context,
- Animation<double> animation,
- Animation<double> secondaryAnimation,
- _ChewieControllerProvider controllerProvider);
- /// A Video Player with Material and Cupertino skins.
- ///
- /// `video_player` is pretty low level. Chewie wraps it in a friendly skin to
- /// make it easy to use!
- class Chewie extends StatefulWidget {
- Chewie({
- Key key,
- this.controller,
- }) : assert(controller != null, 'You must provide a chewie controller'),
- super(key: key);
- /// The [ChewieController]
- final ChewieController controller;
- @override
- ChewieState createState() {
- return ChewieState();
- }
- }
- class ChewieState extends State<Chewie> {
- bool _isFullScreen = false;
- @override
- void initState() {
- super.initState();
- widget.controller.addListener(listener);
- }
- @override
- void dispose() {
- widget.controller.removeListener(listener);
- super.dispose();
- }
- @override
- void didUpdateWidget(Chewie oldWidget) {
- if (oldWidget.controller != widget.controller) {
- widget.controller.addListener(listener);
- }
- super.didUpdateWidget(oldWidget);
- }
- void listener() async {
- if (widget.controller.isFullScreen && !_isFullScreen) {
- _isFullScreen = true;
- await _pushFullScreenWidget(context);
- } else if (_isFullScreen) {
- Navigator.of(context, rootNavigator: true).pop();
- _isFullScreen = false;
- }
- }
- @override
- Widget build(BuildContext context) {
- return _ChewieControllerProvider(
- controller: widget.controller,
- child: PlayerWithControls(),
- );
- }
- Widget _buildFullScreenVideo(
- BuildContext context,
- Animation<double> animation,
- _ChewieControllerProvider controllerProvider) {
- return Scaffold(
- resizeToAvoidBottomPadding: false,
- body: Container(
- alignment: Alignment.center,
- color: Colors.black,
- child: controllerProvider,
- ),
- );
- }
- AnimatedWidget _defaultRoutePageBuilder(
- BuildContext context,
- Animation<double> animation,
- Animation<double> secondaryAnimation,
- _ChewieControllerProvider controllerProvider) {
- return AnimatedBuilder(
- animation: animation,
- builder: (BuildContext context, Widget child) {
- return _buildFullScreenVideo(context, animation, controllerProvider);
- },
- );
- }
- Widget _fullScreenRoutePageBuilder(
- BuildContext context,
- Animation<double> animation,
- Animation<double> secondaryAnimation,
- ) {
- var controllerProvider = _ChewieControllerProvider(
- controller: widget.controller,
- child: PlayerWithControls(),
- );
- if (widget.controller.routePageBuilder == null) {
- return _defaultRoutePageBuilder(
- context, animation, secondaryAnimation, controllerProvider);
- }
- return widget.controller.routePageBuilder(
- context, animation, secondaryAnimation, controllerProvider);
- }
- Future<dynamic> _pushFullScreenWidget(BuildContext context) async {
- final isAndroid = Theme.of(context).platform == TargetPlatform.android;
- final TransitionRoute<Null> route = PageRouteBuilder<Null>(
- settings: RouteSettings(isInitialRoute: false),
- pageBuilder: _fullScreenRoutePageBuilder,
- );
- SystemChrome.setEnabledSystemUIOverlays([]);
- if (isAndroid) {
- SystemChrome.setPreferredOrientations([
- DeviceOrientation.landscapeLeft,
- DeviceOrientation.landscapeRight,
- ]);
- }
- if (!widget.controller.allowedScreenSleep) {
- Wakelock.enable();
- }
- await Navigator.of(context, rootNavigator: true).push(route);
- _isFullScreen = false;
- widget.controller.exitFullScreen();
- // The wakelock plugins checks whether it needs to perform an action internally,
- // so we do not need to check Wakelock.isEnabled.
- Wakelock.disable();
- SystemChrome.setEnabledSystemUIOverlays(
- widget.controller.systemOverlaysAfterFullScreen);
- SystemChrome.setPreferredOrientations(
- widget.controller.deviceOrientationsAfterFullScreen);
- }
- }
- /// The ChewieController is used to configure and drive the Chewie Player
- /// Widgets. It provides methods to control playback, such as [pause] and
- /// [play], as well as methods that control the visual appearance of the player,
- /// such as [enterFullScreen] or [exitFullScreen].
- ///
- /// In addition, you can listen to the ChewieController for presentational
- /// changes, such as entering and exiting full screen mode. To listen for
- /// changes to the playback, such as a change to the seek position of the
- /// player, please use the standard information provided by the
- /// `VideoPlayerController`.
- class ChewieController extends ChangeNotifier {
- ChewieController({
- this.videoPlayerController,
- this.aspectRatio,
- this.autoInitialize = false,
- this.autoPlay = false,
- this.startAt,
- this.looping = false,
- this.fullScreenByDefault = false,
- this.cupertinoProgressColors,
- this.materialProgressColors,
- this.placeholder,
- this.overlay,
- this.showControlsOnInitialize = true,
- this.showControls = true,
- this.customControls,
- this.errorBuilder,
- this.allowedScreenSleep = true,
- this.isLive = false,
- this.allowFullScreen = true,
- this.allowMuting = true,
- this.systemOverlaysAfterFullScreen = SystemUiOverlay.values,
- this.deviceOrientationsAfterFullScreen = const [
- DeviceOrientation.portraitUp,
- DeviceOrientation.portraitDown,
- DeviceOrientation.landscapeLeft,
- DeviceOrientation.landscapeRight,
- ],
- this.routePageBuilder = null,
- }) : assert(videoPlayerController != null,
- 'You must provide a controller to play a video') {
- _initialize();
- }
- /// The controller for the video you want to play
- final VideoPlayerController videoPlayerController;
- /// Initialize the Video on Startup. This will prep the video for playback.
- final bool autoInitialize;
- /// Play the video as soon as it's displayed
- final bool autoPlay;
- /// Start video at a certain position
- final Duration startAt;
- /// Whether or not the video should loop
- final bool looping;
- /// Weather or not to show the controls when initializing the widget.
- final bool showControlsOnInitialize;
- /// Whether or not to show the controls at all
- final bool showControls;
- /// Defines customised controls. Check [MaterialControls] or
- /// [CupertinoControls] for reference.
- final Widget customControls;
- /// When the video playback runs into an error, you can build a custom
- /// error message.
- final Widget Function(BuildContext context, String errorMessage) errorBuilder;
- /// The Aspect Ratio of the Video. Important to get the correct size of the
- /// video!
- ///
- /// Will fallback to fitting within the space allowed.
- final double aspectRatio;
- /// The colors to use for controls on iOS. By default, the iOS player uses
- /// colors sampled from the original iOS 11 designs.
- final ChewieProgressColors cupertinoProgressColors;
- /// The colors to use for the Material Progress Bar. By default, the Material
- /// player uses the colors from your Theme.
- final ChewieProgressColors materialProgressColors;
- /// The placeholder is displayed underneath the Video before it is initialized
- /// or played.
- final Widget placeholder;
- /// A widget which is placed between the video and the controls
- final Widget overlay;
- /// Defines if the player will start in fullscreen when play is pressed
- final bool fullScreenByDefault;
- /// Defines if the player will sleep in fullscreen or not
- final bool allowedScreenSleep;
- /// Defines if the controls should be for live stream video
- final bool isLive;
- /// Defines if the fullscreen control should be shown
- final bool allowFullScreen;
- /// Defines if the mute control should be shown
- final bool allowMuting;
- /// Defines the system overlays visible after exiting fullscreen
- final List<SystemUiOverlay> systemOverlaysAfterFullScreen;
- /// Defines the set of allowed device orientations after exiting fullscreen
- final List<DeviceOrientation> deviceOrientationsAfterFullScreen;
- /// Defines a custom RoutePageBuilder for the fullscreen
- final ChewieRoutePageBuilder routePageBuilder;
- static ChewieController of(BuildContext context) {
- final chewieControllerProvider =
- context.inheritFromWidgetOfExactType(_ChewieControllerProvider)
- as _ChewieControllerProvider;
- return chewieControllerProvider.controller;
- }
- bool _isFullScreen = false;
- bool get isFullScreen => _isFullScreen;
- Future _initialize() async {
- await videoPlayerController.setLooping(looping);
- if ((autoInitialize || autoPlay) &&
- !videoPlayerController.value.initialized) {
- await videoPlayerController.initialize();
- }
- if (autoPlay) {
- if (fullScreenByDefault) {
- enterFullScreen();
- }
- await videoPlayerController.play();
- }
- if (startAt != null) {
- await videoPlayerController.seekTo(startAt);
- }
- if (fullScreenByDefault) {
- videoPlayerController.addListener(_fullScreenListener);
- }
- }
- void _fullScreenListener() async {
- if (videoPlayerController.value.isPlaying && !_isFullScreen) {
- enterFullScreen();
- videoPlayerController.removeListener(_fullScreenListener);
- }
- }
- void enterFullScreen() {
- _isFullScreen = true;
- notifyListeners();
- }
- void exitFullScreen() {
- _isFullScreen = false;
- notifyListeners();
- }
- void toggleFullScreen() {
- _isFullScreen = !_isFullScreen;
- notifyListeners();
- }
- Future<void> play() async {
- await videoPlayerController.play();
- }
- Future<void> setLooping(bool looping) async {
- await videoPlayerController.setLooping(looping);
- }
- Future<void> pause() async {
- await videoPlayerController.pause();
- }
- Future<void> seekTo(Duration moment) async {
- await videoPlayerController.seekTo(moment);
- }
- Future<void> setVolume(double volume) async {
- await videoPlayerController.setVolume(volume);
- }
- }
- class _ChewieControllerProvider extends InheritedWidget {
- const _ChewieControllerProvider({
- Key key,
- @required this.controller,
- @required Widget child,
- }) : assert(controller != null),
- assert(child != null),
- super(key: key, child: child);
- final ChewieController controller;
- @override
- bool updateShouldNotify(_ChewieControllerProvider old) =>
- controller != old.controller;
- }
|