diff --git a/example/lib/auto_rotate.dart b/example/lib/auto_rotate.dart deleted file mode 100644 index 0e8999c57..000000000 --- a/example/lib/auto_rotate.dart +++ /dev/null @@ -1,244 +0,0 @@ -import 'package:auto_orientation/auto_orientation.dart'; -import 'package:chewie/chewie.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:video_player/video_player.dart'; - -void main() { - runApp( - const ChewieDemo(), - ); -} - -class ChewieDemo extends StatefulWidget { - // ignore: use_key_in_widget_constructors - const ChewieDemo({this.title = 'Chewie Demo'}); - - final String title; - - @override - State createState() { - return _ChewieDemoState(); - } -} - -class _ChewieDemoState extends State { - TargetPlatform _platform; - VideoPlayerController _videoPlayerController1; - VideoPlayerController _videoPlayerController2; - ChewieController _chewieController; - - @override - void initState() { - super.initState(); - initializeAutoRotatePlayer(); - } - - Future initializeAutoRotatePlayer() async { - _videoPlayerController1 = VideoPlayerController.network( - 'https://assets.mixkit.co/videos/preview/mixkit-forest-stream-in-the-sunlight-529-large.mp4'); - await _videoPlayerController1.initialize(); - _videoPlayerController2 = VideoPlayerController.network( - 'https://assets.mixkit.co/videos/preview/mixkit-a-girl-blowing-a-bubble-gum-at-an-amusement-park-1226-large.mp4'); - await _videoPlayerController2.initialize(); - _chewieController = ChewieController( - videoPlayerController: _videoPlayerController1, - autoPlay: true, - looping: true, - routePageBuilder: (BuildContext context, Animation animation, - Animation secondAnimation, provider) { - return AnimatedBuilder( - animation: animation, - builder: (BuildContext context, Widget child) { - return VideoScaffold( - child: Scaffold( - resizeToAvoidBottomInset: false, - body: Container( - alignment: Alignment.center, - color: Colors.black, - child: provider, - ), - ), - ); - }, - ); - } - // Try playing around with some of these other options: - - // showControls: false, - // materialProgressColors: ChewieProgressColors( - // playedColor: Colors.red, - // handleColor: Colors.blue, - // backgroundColor: Colors.grey, - // bufferedColor: Colors.lightGreen, - // ), - // placeholder: Container( - // color: Colors.grey, - // ), - // autoInitialize: true, - ); - setState(() {}); - } - - @override - void dispose() { - _videoPlayerController1.dispose(); - _videoPlayerController2.dispose(); - _chewieController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: widget.title, - theme: ThemeData.light().copyWith( - platform: _platform ?? Theme.of(context).platform, - ), - home: Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Column( - children: [ - Expanded( - child: Center( - child: _chewieController != null && - _chewieController - .videoPlayerController.value.initialized - ? Chewie( - controller: _chewieController, - ) - : Column( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - CircularProgressIndicator(), - SizedBox(height: 20), - Text('Loading'), - ], - ), - ), - ), - TextButton( - onPressed: () { - _chewieController.enterFullScreen(); - }, - child: const Text('Fullscreen'), - ), - Row( - children: [ - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _chewieController.dispose(); - _videoPlayerController1.pause(); - _videoPlayerController1.seekTo(const Duration()); - _chewieController = ChewieController( - videoPlayerController: _videoPlayerController1, - autoPlay: true, - looping: true, - ); - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("Landscape Video"), - ), - ), - ), - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _chewieController.dispose(); - _videoPlayerController2.pause(); - _videoPlayerController2.seekTo(const Duration()); - _chewieController = ChewieController( - videoPlayerController: _videoPlayerController2, - autoPlay: true, - looping: true, - ); - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("Portrait Video"), - ), - ), - ) - ], - ), - Row( - children: [ - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _platform = TargetPlatform.android; - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("Android controls"), - ), - ), - ), - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _platform = TargetPlatform.iOS; - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("iOS controls"), - ), - ), - ) - ], - ) - ], - ), - ), - ); - } -} - -class VideoScaffold extends StatefulWidget { - const VideoScaffold({Key key, this.child}) : super(key: key); - - final Widget child; - - @override - State createState() => _VideoScaffoldState(); -} - -class _VideoScaffoldState extends State { - @override - void initState() { - SystemChrome.setPreferredOrientations([ - DeviceOrientation.landscapeRight, - DeviceOrientation.landscapeLeft, - ]); - AutoOrientation.portraitUpMode(); - super.initState(); - } - - @override - void dispose() { - SystemChrome.setPreferredOrientations([ - DeviceOrientation.portraitUp, - DeviceOrientation.portraitDown, - ]); - AutoOrientation.portraitUpMode(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return widget.child; - } -} diff --git a/example/lib/main.dart b/example/lib/main.dart index 33dae4e0f..080ea395d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,10 +22,10 @@ class ChewieDemo extends StatefulWidget { } class _ChewieDemoState extends State { - TargetPlatform _platform; - VideoPlayerController _videoPlayerController1; - VideoPlayerController _videoPlayerController2; - ChewieController _chewieController; + TargetPlatform? _platform; + late VideoPlayerController _videoPlayerController1; + late VideoPlayerController _videoPlayerController2; + ChewieController? _chewieController; @override void initState() { @@ -37,17 +37,19 @@ class _ChewieDemoState extends State { void dispose() { _videoPlayerController1.dispose(); _videoPlayerController2.dispose(); - _chewieController.dispose(); + _chewieController?.dispose(); super.dispose(); } Future initializePlayer() async { _videoPlayerController1 = VideoPlayerController.network( 'https://assets.mixkit.co/videos/preview/mixkit-forest-stream-in-the-sunlight-529-large.mp4'); - await _videoPlayerController1.initialize(); _videoPlayerController2 = VideoPlayerController.network( 'https://assets.mixkit.co/videos/preview/mixkit-a-girl-blowing-a-bubble-gum-at-an-amusement-park-1226-large.mp4'); - await _videoPlayerController2.initialize(); + await Future.wait([ + _videoPlayerController1.initialize(), + _videoPlayerController2.initialize() + ]); _chewieController = ChewieController( videoPlayerController: _videoPlayerController1, autoPlay: true, @@ -85,10 +87,10 @@ class _ChewieDemoState extends State { Expanded( child: Center( child: _chewieController != null && - _chewieController - .videoPlayerController.value.initialized + _chewieController! + .videoPlayerController.value.isInitialized ? Chewie( - controller: _chewieController, + controller: _chewieController!, ) : Column( mainAxisAlignment: MainAxisAlignment.center, @@ -102,7 +104,7 @@ class _ChewieDemoState extends State { ), TextButton( onPressed: () { - _chewieController.enterFullScreen(); + _chewieController!.enterFullScreen(); }, child: const Text('Fullscreen'), ), @@ -112,7 +114,7 @@ class _ChewieDemoState extends State { child: TextButton( onPressed: () { setState(() { - _chewieController.dispose(); + _chewieController!.dispose(); _videoPlayerController1.pause(); _videoPlayerController1.seekTo(const Duration()); _chewieController = ChewieController( @@ -132,7 +134,7 @@ class _ChewieDemoState extends State { child: TextButton( onPressed: () { setState(() { - _chewieController.dispose(); + _chewieController!.dispose(); _videoPlayerController2.pause(); _videoPlayerController2.seekTo(const Duration()); _chewieController = ChewieController( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index cf43f3982..8f4d2db53 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -2,29 +2,26 @@ name: chewie_example description: An example of how to use the chewie for Flutter environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' dependencies: - auto_orientation: ^1.0.6 chewie: path: ../ cupertino_icons: ^1.0.0 flutter: sdk: flutter - video_player: ^1.0.0 + video_player: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter lint: ^1.3.0 - # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index b24240fc8..0d8d12e5e 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -5,7 +5,7 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import 'package:chewie_example/auto_rotate.dart'; +import 'package:chewie_example/main.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 60e37f435..7edc1dc5b 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -21,10 +21,9 @@ typedef ChewieRoutePageBuilder = Widget Function( /// make it easy to use! class Chewie extends StatefulWidget { const Chewie({ - Key key, - @required this.controller, - }) : assert(controller != null, 'You must provide a chewie controller'), - super(key: key); + Key? key, + required this.controller, + }) : super(key: key); /// The [ChewieController] final ChewieController controller; @@ -99,7 +98,7 @@ class ChewieState extends State { ) { return AnimatedBuilder( animation: animation, - builder: (BuildContext context, Widget child) { + builder: (BuildContext context, Widget? child) { return _buildFullScreenVideo(context, animation, controllerProvider); }, ); @@ -119,7 +118,7 @@ class ChewieState extends State { return _defaultRoutePageBuilder( context, animation, secondaryAnimation, controllerProvider); } - return widget.controller.routePageBuilder( + return widget.controller.routePageBuilder!( context, animation, secondaryAnimation, controllerProvider); } @@ -156,7 +155,7 @@ class ChewieState extends State { if (widget.controller.systemOverlaysOnEnterFullScreen != null) { /// Optional user preferred settings SystemChrome.setEnabledSystemUIOverlays( - widget.controller.systemOverlaysOnEnterFullScreen); + widget.controller.systemOverlaysOnEnterFullScreen!); } else { /// Default behavior SystemChrome.setEnabledSystemUIOverlays([]); @@ -165,7 +164,7 @@ class ChewieState extends State { if (widget.controller.deviceOrientationsOnEnterFullScreen != null) { /// Optional user preferred settings SystemChrome.setPreferredOrientations( - widget.controller.deviceOrientationsOnEnterFullScreen); + widget.controller.deviceOrientationsOnEnterFullScreen!); } else { final isLandscapeVideo = videoWidth > videoHeight; final isPortraitVideo = videoWidth < videoHeight; @@ -207,7 +206,7 @@ class ChewieState extends State { /// `VideoPlayerController`. class ChewieController extends ChangeNotifier { ChewieController({ - @required this.videoPlayerController, + required this.videoPlayerController, this.aspectRatio, this.autoInitialize = false, this.autoPlay = false, @@ -233,9 +232,7 @@ class ChewieController extends ChangeNotifier { this.systemOverlaysAfterFullScreen = SystemUiOverlay.values, this.deviceOrientationsAfterFullScreen = DeviceOrientation.values, this.routePageBuilder, - }) : assert(videoPlayerController != null, - 'You must provide a controller to play a video'), - assert(playbackSpeeds.every((speed) => speed > 0), + }) : assert(playbackSpeeds.every((speed) => speed > 0), 'The playbackSpeeds values must all be greater than 0') { _initialize(); } @@ -250,7 +247,7 @@ class ChewieController extends ChangeNotifier { final bool autoPlay; /// Start video at a certain position - final Duration startAt; + final Duration? startAt; /// Whether or not the video should loop final bool looping; @@ -263,32 +260,33 @@ class ChewieController extends ChangeNotifier { /// Defines customised controls. Check [MaterialControls] or /// [CupertinoControls] for reference. - final Widget customControls; + final Widget? customControls; - /// When the video playback runs into an error, you can build a custom + /// When the video playback runs into an error, you can build a custom /// error message. - final Widget Function(BuildContext context, String errorMessage) errorBuilder; + 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; + 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; + 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; + final ChewieProgressColors? materialProgressColors; /// The placeholder is displayed underneath the Video before it is initialized /// or played. - final Widget placeholder; + final Widget? placeholder; /// A widget which is placed between the video and the controls - final Widget overlay; + final Widget? overlay; /// Defines if the player will start in fullscreen when play is pressed final bool fullScreenByDefault; @@ -312,10 +310,10 @@ class ChewieController extends ChangeNotifier { final List playbackSpeeds; /// Defines the system overlays visible on entering fullscreen - final List systemOverlaysOnEnterFullScreen; + final List? systemOverlaysOnEnterFullScreen; /// Defines the set of allowed device orientations on entering fullscreen - final List deviceOrientationsOnEnterFullScreen; + final List? deviceOrientationsOnEnterFullScreen; /// Defines the system overlays visible after exiting fullscreen final List systemOverlaysAfterFullScreen; @@ -324,11 +322,11 @@ class ChewieController extends ChangeNotifier { final List deviceOrientationsAfterFullScreen; /// Defines a custom RoutePageBuilder for the fullscreen - final ChewieRoutePageBuilder routePageBuilder; + final ChewieRoutePageBuilder? routePageBuilder; static ChewieController of(BuildContext context) { - final chewieControllerProvider = - context.dependOnInheritedWidgetOfExactType<_ChewieControllerProvider>(); + final chewieControllerProvider = context + .dependOnInheritedWidgetOfExactType<_ChewieControllerProvider>()!; return chewieControllerProvider.controller; } @@ -343,7 +341,7 @@ class ChewieController extends ChangeNotifier { await videoPlayerController.setLooping(looping); if ((autoInitialize || autoPlay) && - !videoPlayerController.value.initialized) { + !videoPlayerController.value.isInitialized) { await videoPlayerController.initialize(); } @@ -356,7 +354,7 @@ class ChewieController extends ChangeNotifier { } if (startAt != null) { - await videoPlayerController.seekTo(startAt); + await videoPlayerController.seekTo(startAt!); } if (fullScreenByDefault) { @@ -414,12 +412,10 @@ class ChewieController extends ChangeNotifier { 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); + Key? key, + required this.controller, + required Widget child, + }) : super(key: key, child: child); final ChewieController controller; diff --git a/lib/src/cupertino_controls.dart b/lib/src/cupertino_controls.dart index fd4bf1d43..36531631c 100644 --- a/lib/src/cupertino_controls.dart +++ b/lib/src/cupertino_controls.dart @@ -13,9 +13,9 @@ import 'package:video_player/video_player.dart'; class CupertinoControls extends StatefulWidget { const CupertinoControls({ - @required this.backgroundColor, - @required this.iconColor, - Key key, + required this.backgroundColor, + required this.iconColor, + Key? key, }) : super(key: key); final Color backgroundColor; @@ -29,28 +29,33 @@ class CupertinoControls extends StatefulWidget { class _CupertinoControlsState extends State with SingleTickerProviderStateMixin { - VideoPlayerValue _latestValue; - double _latestVolume; + late VideoPlayerValue _latestValue; + double? _latestVolume; bool _hideStuff = true; - Timer _hideTimer; + Timer? _hideTimer; final marginSize = 5.0; - Timer _expandCollapseTimer; - Timer _initTimer; + Timer? _expandCollapseTimer; + Timer? _initTimer; bool _dragging = false; - VideoPlayerController controller; - ChewieController chewieController; - AnimationController playPauseIconAnimationController; + late VideoPlayerController controller; + // We know that _chewieController is set in didChangeDependencies + ChewieController get chewieController => _chewieController!; + ChewieController? _chewieController; + late AnimationController playPauseIconAnimationController = + AnimationController( + vsync: this, + duration: const Duration(milliseconds: 400), + reverseDuration: const Duration(milliseconds: 400), + ); @override Widget build(BuildContext context) { - chewieController = ChewieController.of(context); - if (_latestValue.hasError) { return chewieController.errorBuilder != null - ? chewieController.errorBuilder( + ? chewieController.errorBuilder!( context, - chewieController.videoPlayerController.value.errorDescription, + chewieController.videoPlayerController.value.errorDescription!, ) : const Center( child: Icon( @@ -63,8 +68,6 @@ class _CupertinoControlsState extends State final backgroundColor = widget.backgroundColor; final iconColor = widget.iconColor; - chewieController = ChewieController.of(context); - controller = chewieController.videoPlayerController; final orientation = MediaQuery.of(context).orientation; final barHeight = orientation == Orientation.portrait ? 30.0 : 47.0; final buttonPadding = orientation == Orientation.portrait ? 16.0 : 24.0; @@ -107,16 +110,10 @@ class _CupertinoControlsState extends State @override void didChangeDependencies() { - final _oldController = chewieController; - chewieController = ChewieController.of(context); + final _oldController = _chewieController; + _chewieController = ChewieController.of(context); controller = chewieController.videoPlayerController; - playPauseIconAnimationController ??= AnimationController( - vsync: this, - duration: const Duration(milliseconds: 400), - reverseDuration: const Duration(milliseconds: 400), - ); - if (_oldController != chewieController) { _dispose(); _initialize(); @@ -223,12 +220,11 @@ class _CupertinoControlsState extends State } Expanded _buildHitArea() { - final bool isFinished = _latestValue.duration != null && - _latestValue.position >= _latestValue.duration; + final bool isFinished = _latestValue.position >= _latestValue.duration; return Expanded( child: GestureDetector( - onTap: _latestValue != null && _latestValue.isPlaying + onTap: _latestValue.isPlaying ? _cancelAndRestartTimer : () { _hideTimer?.cancel(); @@ -241,10 +237,7 @@ class _CupertinoControlsState extends State color: Colors.transparent, child: Center( child: AnimatedOpacity( - opacity: - _latestValue != null && !_latestValue.isPlaying && !_dragging - ? 1.0 - : 0.0, + opacity: !_latestValue.isPlaying && !_dragging ? 1.0 : 0.0, duration: const Duration(milliseconds: 300), child: GestureDetector( child: Container( @@ -310,9 +303,7 @@ class _CupertinoControlsState extends State right: buttonPadding, ), child: Icon( - (_latestValue != null && _latestValue.volume > 0) - ? Icons.volume_up - : Icons.volume_off, + _latestValue.volume > 0 ? Icons.volume_up : Icons.volume_off, color: iconColor, size: 16, ), @@ -347,8 +338,7 @@ class _CupertinoControlsState extends State } Widget _buildPosition(Color iconColor) { - final position = - _latestValue != null ? _latestValue.position : const Duration(); + final position = _latestValue.position; return Padding( padding: const EdgeInsets.only(right: 12.0), @@ -363,9 +353,7 @@ class _CupertinoControlsState extends State } Widget _buildRemaining(Color iconColor) { - final position = _latestValue != null && _latestValue.duration != null - ? _latestValue.duration - _latestValue.position - : const Duration(); + final position = _latestValue.duration - _latestValue.position; return Padding( padding: const EdgeInsets.only(right: 12.0), @@ -512,8 +500,7 @@ class _CupertinoControlsState extends State _updateState(); - if ((controller.value != null && controller.value.isPlaying) || - chewieController.autoPlay) { + if (controller.value.isPlaying || chewieController.autoPlay) { _startHideTimer(); } @@ -592,12 +579,7 @@ class _CupertinoControlsState extends State } void _playPause() { - bool isFinished; - if (_latestValue.duration != null) { - isFinished = _latestValue.position >= _latestValue.duration; - } else { - isFinished = false; - } + final isFinished = _latestValue.position >= _latestValue.duration; setState(() { if (controller.value.isPlaying) { @@ -607,7 +589,7 @@ class _CupertinoControlsState extends State } else { _cancelAndRestartTimer(); - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { controller.initialize().then((_) { controller.play(); }); @@ -655,10 +637,10 @@ class _CupertinoControlsState extends State class _PlaybackSpeedDialog extends StatelessWidget { const _PlaybackSpeedDialog({ - Key key, - @required List speeds, - @required double selected, - }) : _speeds = speeds, + Key? key, + required List speeds, + required double selected, + }) : _speeds = speeds, _selected = selected, super(key: key); diff --git a/lib/src/cupertino_progress_bar.dart b/lib/src/cupertino_progress_bar.dart index 40bd7f6f1..2537949de 100644 --- a/lib/src/cupertino_progress_bar.dart +++ b/lib/src/cupertino_progress_bar.dart @@ -6,19 +6,19 @@ import 'package:video_player/video_player.dart'; class CupertinoVideoProgressBar extends StatefulWidget { CupertinoVideoProgressBar( this.controller, { - ChewieProgressColors colors, + ChewieProgressColors? colors, this.onDragEnd, this.onDragStart, this.onDragUpdate, - Key key, + Key? key, }) : colors = colors ?? ChewieProgressColors(), super(key: key); final VideoPlayerController controller; final ChewieProgressColors colors; - final Function() onDragStart; - final Function() onDragEnd; - final Function() onDragUpdate; + final Function()? onDragStart; + final Function()? onDragEnd; + final Function()? onDragUpdate; @override _VideoProgressBarState createState() { @@ -43,7 +43,7 @@ class _VideoProgressBarState extends State { return GestureDetector( onHorizontalDragStart: (DragStartDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } _controllerWasPlaying = controller.value.isPlaying; @@ -51,31 +51,25 @@ class _VideoProgressBarState extends State { controller.pause(); } - if (widget.onDragStart != null) { - widget.onDragStart(); - } + widget.onDragStart?.call(); }, onHorizontalDragUpdate: (DragUpdateDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } seekToRelativePosition(details.globalPosition); - if (widget.onDragUpdate != null) { - widget.onDragUpdate(); - } + widget.onDragUpdate?.call(); }, onHorizontalDragEnd: (DragEndDetails details) { if (_controllerWasPlaying) { controller.play(); } - if (widget.onDragEnd != null) { - widget.onDragEnd(); - } + widget.onDragEnd?.call(); }, onTapDown: (TapDownDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } seekToRelativePosition(details.globalPosition); @@ -124,7 +118,7 @@ class _ProgressBarPainter extends CustomPainter { ), colors.backgroundPaint, ); - if (!value.initialized) { + if (!value.isInitialized) { return; } final double playedPartPercent = diff --git a/lib/src/material_controls.dart b/lib/src/material_controls.dart index 1ee649d9c..9d39524e1 100644 --- a/lib/src/material_controls.dart +++ b/lib/src/material_controls.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; class MaterialControls extends StatefulWidget { - const MaterialControls({Key key}) : super(key: key); + const MaterialControls({Key? key}) : super(key: key); @override State createState() { @@ -18,37 +18,43 @@ class MaterialControls extends StatefulWidget { class _MaterialControlsState extends State with SingleTickerProviderStateMixin { - VideoPlayerValue _latestValue; - double _latestVolume; + late VideoPlayerValue _latestValue; + double? _latestVolume; bool _hideStuff = true; - Timer _hideTimer; - Timer _initTimer; - Timer _showAfterExpandCollapseTimer; + Timer? _hideTimer; + Timer? _initTimer; + Timer? _showAfterExpandCollapseTimer; bool _dragging = false; bool _displayTapped = false; final barHeight = 48.0; final marginSize = 5.0; - VideoPlayerController controller; - ChewieController chewieController; - AnimationController playPauseIconAnimationController; + late VideoPlayerController controller; + ChewieController? _chewieController; + // We know that _chewieController is set in didChangeDependencies + ChewieController get chewieController => _chewieController!; + late AnimationController playPauseIconAnimationController = + AnimationController( + vsync: this, + duration: const Duration(milliseconds: 400), + reverseDuration: const Duration(milliseconds: 400), + ); @override Widget build(BuildContext context) { if (_latestValue.hasError) { - return chewieController.errorBuilder != null - ? chewieController.errorBuilder( - context, - chewieController.videoPlayerController.value.errorDescription, - ) - : const Center( - child: Icon( - Icons.error, - color: Colors.white, - size: 42, - ), - ); + return chewieController.errorBuilder?.call( + context, + chewieController.videoPlayerController.value.errorDescription!, + ) ?? + const Center( + child: Icon( + Icons.error, + color: Colors.white, + size: 42, + ), + ); } return MouseRegion( @@ -61,10 +67,7 @@ class _MaterialControlsState extends State absorbing: _hideStuff, child: Column( children: [ - if (_latestValue != null && - !_latestValue.isPlaying && - _latestValue.duration == null || - _latestValue.isBuffering) + if (_latestValue.isBuffering) const Expanded( child: Center( child: CircularProgressIndicator(), @@ -95,16 +98,10 @@ class _MaterialControlsState extends State @override void didChangeDependencies() { - final _oldController = chewieController; - chewieController = ChewieController.of(context); + final _oldController = _chewieController; + _chewieController = ChewieController.of(context); controller = chewieController.videoPlayerController; - playPauseIconAnimationController ??= AnimationController( - vsync: this, - duration: const Duration(milliseconds: 400), - reverseDuration: const Duration(milliseconds: 400), - ); - if (_oldController != chewieController) { _dispose(); _initialize(); @@ -116,7 +113,7 @@ class _MaterialControlsState extends State AnimatedOpacity _buildBottomBar( BuildContext context, ) { - final iconColor = Theme.of(context).textTheme.button.color; + final iconColor = Theme.of(context).textTheme.button!.color; return AnimatedOpacity( opacity: _hideStuff ? 0.0 : 1.0, @@ -176,7 +173,7 @@ class _MaterialControlsState extends State return Expanded( child: GestureDetector( onTap: () { - if (_latestValue != null && _latestValue.isPlaying) { + if (_latestValue.isPlaying) { if (_displayTapped) { setState(() { _hideStuff = true; @@ -196,10 +193,7 @@ class _MaterialControlsState extends State color: Colors.transparent, child: Center( child: AnimatedOpacity( - opacity: - _latestValue != null && !_latestValue.isPlaying && !_dragging - ? 1.0 - : 0.0, + opacity: !_latestValue.isPlaying && !_dragging ? 1.0 : 0.0, duration: const Duration(milliseconds: 300), child: GestureDetector( child: Container( @@ -297,9 +291,7 @@ class _MaterialControlsState extends State right: 8.0, ), child: Icon( - (_latestValue != null && _latestValue.volume > 0) - ? Icons.volume_up - : Icons.volume_off, + _latestValue.volume > 0 ? Icons.volume_up : Icons.volume_off, ), ), ), @@ -325,13 +317,9 @@ class _MaterialControlsState extends State ); } - Widget _buildPosition(Color iconColor) { - final position = _latestValue != null && _latestValue.position != null - ? _latestValue.position - : Duration.zero; - final duration = _latestValue != null && _latestValue.duration != null - ? _latestValue.duration - : Duration.zero; + Widget _buildPosition(Color? iconColor) { + final position = _latestValue.position; + final duration = _latestValue.duration; return Padding( padding: const EdgeInsets.only(right: 24.0), @@ -359,8 +347,7 @@ class _MaterialControlsState extends State _updateState(); - if ((controller.value != null && controller.value.isPlaying) || - chewieController.autoPlay) { + if (controller.value.isPlaying || chewieController.autoPlay) { _startHideTimer(); } @@ -388,12 +375,7 @@ class _MaterialControlsState extends State } void _playPause() { - bool isFinished; - if (_latestValue.duration != null) { - isFinished = _latestValue.position >= _latestValue.duration; - } else { - isFinished = false; - } + final isFinished = _latestValue.position >= _latestValue.duration; setState(() { if (controller.value.isPlaying) { @@ -404,7 +386,7 @@ class _MaterialControlsState extends State } else { _cancelAndRestartTimer(); - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { controller.initialize().then((_) { controller.play(); playPauseIconAnimationController.forward(); @@ -468,10 +450,10 @@ class _MaterialControlsState extends State class _PlaybackSpeedDialog extends StatelessWidget { const _PlaybackSpeedDialog({ - Key key, - @required List speeds, - @required double selected, - }) : _speeds = speeds, + Key? key, + required List speeds, + required double selected, + }) : _speeds = speeds, _selected = selected, super(key: key); diff --git a/lib/src/material_progress_bar.dart b/lib/src/material_progress_bar.dart index 906af563a..7f6f0f1d7 100644 --- a/lib/src/material_progress_bar.dart +++ b/lib/src/material_progress_bar.dart @@ -6,19 +6,19 @@ import 'package:video_player/video_player.dart'; class MaterialVideoProgressBar extends StatefulWidget { MaterialVideoProgressBar( this.controller, { - ChewieProgressColors colors, + ChewieProgressColors? colors, this.onDragEnd, this.onDragStart, this.onDragUpdate, - Key key, + Key? key, }) : colors = colors ?? ChewieProgressColors(), super(key: key); final VideoPlayerController controller; final ChewieProgressColors colors; - final Function() onDragStart; - final Function() onDragEnd; - final Function() onDragUpdate; + final Function()? onDragStart; + final Function()? onDragEnd; + final Function()? onDragUpdate; @override _VideoProgressBarState createState() { @@ -27,14 +27,11 @@ class MaterialVideoProgressBar extends StatefulWidget { } class _VideoProgressBarState extends State { - _VideoProgressBarState() { - listener = () { - if (!mounted) return; - setState(() {}); - }; + void listener() { + if (!mounted) return; + setState(() {}); } - VoidCallback listener; bool _controllerWasPlaying = false; VideoPlayerController get controller => widget.controller; @@ -63,7 +60,7 @@ class _VideoProgressBarState extends State { return GestureDetector( onHorizontalDragStart: (DragStartDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } _controllerWasPlaying = controller.value.isPlaying; @@ -71,31 +68,25 @@ class _VideoProgressBarState extends State { controller.pause(); } - if (widget.onDragStart != null) { - widget.onDragStart(); - } + widget.onDragStart?.call(); }, onHorizontalDragUpdate: (DragUpdateDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } seekToRelativePosition(details.globalPosition); - if (widget.onDragUpdate != null) { - widget.onDragUpdate(); - } + widget.onDragUpdate?.call(); }, onHorizontalDragEnd: (DragEndDetails details) { if (_controllerWasPlaying) { controller.play(); } - if (widget.onDragEnd != null) { - widget.onDragEnd(); - } + widget.onDragEnd?.call(); }, onTapDown: (TapDownDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } seekToRelativePosition(details.globalPosition); @@ -142,7 +133,7 @@ class _ProgressBarPainter extends CustomPainter { ), colors.backgroundPaint, ); - if (!value.initialized) { + if (!value.isInitialized) { return; } final double playedPartPercent = diff --git a/lib/src/player_with_controls.dart b/lib/src/player_with_controls.dart index d1fa33605..88d4cb0de 100644 --- a/lib/src/player_with_controls.dart +++ b/lib/src/player_with_controls.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; class PlayerWithControls extends StatelessWidget { - const PlayerWithControls({Key key}) : super(key: key); + const PlayerWithControls({Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/pubspec.yaml b/pubspec.yaml index cb63a43a5..c5656428f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,15 +4,15 @@ version: 0.12.2 homepage: https://github.com/brianegan/chewie environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.22.0 <2.0.0" dependencies: - cupertino_icons: ^1.0.0 + cupertino_icons: ^1.0.2 flutter: sdk: flutter - video_player: ^1.0.0 - wakelock: ^0.2.1+1 + video_player: ^2.0.0 + wakelock: ^0.4.0 dev_dependencies: flutter_test: