Преглед на файлове

Fixes #114: Better support for playback errors (#126)

Brian Egan преди 6 години
родител
ревизия
2c0e5e1a4e

+ 38 - 38
example/lib/auto_rotate.dart

@@ -1,10 +1,10 @@
+import 'package:auto_orientation/auto_orientation.dart';
 import 'package:chewie/chewie.dart';
 import 'package:chewie/src/chewie_player.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:video_player/video_player.dart';
-import 'package:auto_orientation/auto_orientation.dart';
 
 void main() {
   runApp(
@@ -37,41 +37,42 @@ class _ChewieDemoState extends State<ChewieDemo> {
     _videoPlayerController2 = VideoPlayerController.network(
         'https://www.sample-videos.com/video123/mp4/480/big_buck_bunny_480p_20mb.mp4');
     _chewieController = ChewieController(
-      videoPlayerController: _videoPlayerController1,
-      aspectRatio: 3 / 2,
-      autoPlay: true,
-      looping: true,
-      routePageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondAnimation, provider) {
-        return AnimatedBuilder(
-          animation: animation,
-          builder: (BuildContext context, Widget child) {
-            return VideoScaffold(
-              child: Scaffold(
-                resizeToAvoidBottomPadding: false,
-                body: Container(
-                  alignment: Alignment.center,
-                  color: Colors.black,
-                  child: provider,
+        videoPlayerController: _videoPlayerController1,
+        aspectRatio: 3 / 2,
+        autoPlay: true,
+        looping: true,
+        routePageBuilder: (BuildContext context, Animation<double> animation,
+            Animation<double> secondAnimation, provider) {
+          return AnimatedBuilder(
+            animation: animation,
+            builder: (BuildContext context, Widget child) {
+              return VideoScaffold(
+                child: Scaffold(
+                  resizeToAvoidBottomPadding: 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,
         );
-      }
-      // 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,
-    );
   }
 
   @override
@@ -192,16 +193,15 @@ class _ChewieDemoState extends State<ChewieDemo> {
 }
 
 class VideoScaffold extends StatefulWidget {
-  final Widget child;
-
   const VideoScaffold({Key key, this.child}) : super(key: key);
 
+  final Widget child;
+
   @override
   State<StatefulWidget> createState() => _VideoScaffoldState();
 }
 
 class _VideoScaffoldState extends State<VideoScaffold> {
-
   @override
   void initState() {
     SystemChrome.setPreferredOrientations([
@@ -213,7 +213,7 @@ class _VideoScaffoldState extends State<VideoScaffold> {
   }
 
   @override
-  dispose(){
+  dispose() {
     SystemChrome.setPreferredOrientations([
       DeviceOrientation.portraitUp,
       DeviceOrientation.portraitDown,

+ 2 - 2
example/lib/main.dart

@@ -33,7 +33,7 @@ class _ChewieDemoState extends State<ChewieDemo> {
     _videoPlayerController1 = VideoPlayerController.network(
         'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4');
     _videoPlayerController2 = VideoPlayerController.network(
-        'https://www.sample-videos.com/video123/mp4/480/big_buck_bunny_480p_20mb.mp4');
+        'https://www.sample-videos.com/video123/mp4/480/asdasdas.mp4');
     _chewieController = ChewieController(
       videoPlayerController: _videoPlayerController1,
       aspectRatio: 3 / 2,
@@ -129,7 +129,7 @@ class _ChewieDemoState extends State<ChewieDemo> {
                     },
                     child: Padding(
                       padding: EdgeInsets.symmetric(vertical: 16.0),
-                      child: Text("Video 2"),
+                      child: Text("Error Video"),
                     ),
                   ),
                 )

+ 14 - 11
lib/src/chewie_player.dart

@@ -78,8 +78,7 @@ class ChewieState extends State<Chewie> {
   Widget _buildFullScreenVideo(
       BuildContext context,
       Animation<double> animation,
-      _ChewieControllerProvider controllerProvider
-  ) {
+      _ChewieControllerProvider controllerProvider) {
     return Scaffold(
       resizeToAvoidBottomPadding: false,
       body: Container(
@@ -94,8 +93,7 @@ class ChewieState extends State<Chewie> {
       BuildContext context,
       Animation<double> animation,
       Animation<double> secondaryAnimation,
-      _ChewieControllerProvider controllerProvider
-  ) {
+      _ChewieControllerProvider controllerProvider) {
     return AnimatedBuilder(
       animation: animation,
       builder: (BuildContext context, Widget child) {
@@ -115,9 +113,11 @@ class ChewieState extends State<Chewie> {
     );
 
     if (widget.controller.routePageBuilder == null) {
-      return _defaultRoutePageBuilder(context, animation, secondaryAnimation, controllerProvider);
+      return _defaultRoutePageBuilder(
+          context, animation, secondaryAnimation, controllerProvider);
     }
-    return widget.controller.routePageBuilder(context, animation, secondaryAnimation, controllerProvider);
+    return widget.controller.routePageBuilder(
+        context, animation, secondaryAnimation, controllerProvider);
   }
 
   Future<dynamic> _pushFullScreenWidget(BuildContext context) async {
@@ -180,6 +180,7 @@ class ChewieController extends ChangeNotifier {
     this.overlay,
     this.showControls = true,
     this.customControls,
+    this.errorBuilder,
     this.allowedScreenSleep = true,
     this.isLive = false,
     this.allowFullScreen = true,
@@ -219,6 +220,10 @@ class ChewieController extends ChangeNotifier {
   /// [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!
   ///
@@ -240,7 +245,6 @@ class ChewieController extends ChangeNotifier {
   /// 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;
 
@@ -266,7 +270,9 @@ class ChewieController extends ChangeNotifier {
   final ChewieRoutePageBuilder routePageBuilder;
 
   static ChewieController of(BuildContext context) {
-    final chewieControllerProvider = _ChewieControllerProvider.of(context);
+    final chewieControllerProvider =
+        context.inheritFromWidgetOfExactType(_ChewieControllerProvider)
+            as _ChewieControllerProvider;
 
     return chewieControllerProvider.controller;
   }
@@ -351,9 +357,6 @@ class _ChewieControllerProvider extends InheritedWidget {
 
   final ChewieController controller;
 
-  static _ChewieControllerProvider of(BuildContext context) => context.inheritFromWidgetOfExactType(_ChewieControllerProvider) as _ChewieControllerProvider;
-
-
   @override
   bool updateShouldNotify(_ChewieControllerProvider old) =>
       controller != old.controller;

+ 18 - 1
lib/src/cupertino_controls.dart

@@ -12,7 +12,7 @@ import 'package:open_iconic_flutter/open_iconic_flutter.dart';
 import 'package:video_player/video_player.dart';
 
 class CupertinoControls extends StatefulWidget {
-  CupertinoControls({
+  const CupertinoControls({
     @required this.backgroundColor,
     @required this.iconColor,
   });
@@ -40,6 +40,23 @@ class _CupertinoControlsState extends State<CupertinoControls> {
 
   @override
   Widget build(BuildContext context) {
+    chewieController = ChewieController.of(context);
+
+    if (_latestValue.hasError) {
+      return chewieController.errorBuilder != null
+          ? chewieController.errorBuilder(
+              context,
+              chewieController.videoPlayerController.value.errorDescription,
+            )
+          : Center(
+              child: Icon(
+                OpenIconicIcons.ban,
+                color: Colors.white,
+                size: 42,
+              ),
+            );
+    }
+
     final backgroundColor = widget.backgroundColor;
     final iconColor = widget.iconColor;
     chewieController = ChewieController.of(context);

+ 16 - 18
lib/src/cupertino_progress_bar.dart

@@ -59,21 +59,19 @@ class _VideoProgressBarState extends State<CupertinoVideoProgressBar> {
     }
 
     return GestureDetector(
-      child: (controller.value.hasError)
-          ? Text(controller.value.errorDescription)
-          : Center(
-              child: Container(
-                height: MediaQuery.of(context).size.height,
-                width: MediaQuery.of(context).size.width,
-                color: Colors.transparent,
-                child: CustomPaint(
-                  painter: _ProgressBarPainter(
-                    controller.value,
-                    widget.colors,
-                  ),
-                ),
-              ),
+      child: Center(
+        child: Container(
+          height: MediaQuery.of(context).size.height,
+          width: MediaQuery.of(context).size.width,
+          color: Colors.transparent,
+          child: CustomPaint(
+            painter: _ProgressBarPainter(
+              controller.value,
+              widget.colors,
             ),
+          ),
+        ),
+      ),
       onHorizontalDragStart: (DragStartDetails details) {
         if (!controller.value.initialized) {
           return;
@@ -146,10 +144,10 @@ class _ProgressBarPainter extends CustomPainter {
     if (!value.initialized) {
       return;
     }
-    final double playedPartPercent = value.position.inMilliseconds /
-        value.duration.inMilliseconds;
-    final double playedPart = playedPartPercent > 1? size.width
-        : playedPartPercent * size.width;
+    final double playedPartPercent =
+        value.position.inMilliseconds / value.duration.inMilliseconds;
+    final double playedPart =
+        playedPartPercent > 1 ? size.width : playedPartPercent * size.width;
     for (DurationRange range in value.buffered) {
       final double start = range.startFraction(value.duration) * size.width;
       final double end = range.endFraction(value.duration) * size.width;

+ 20 - 7
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 {
-  MaterialControls({Key key}) : super(key: key);
+  const MaterialControls({Key key}) : super(key: key);
 
   @override
   State<StatefulWidget> createState() {
@@ -33,10 +33,23 @@ class _MaterialControlsState extends State<MaterialControls> {
 
   @override
   Widget build(BuildContext context) {
+    if (_latestValue.hasError) {
+      return chewieController.errorBuilder != null
+          ? chewieController.errorBuilder(
+              context,
+              chewieController.videoPlayerController.value.errorDescription,
+            )
+          : Center(
+              child: Icon(
+                Icons.error,
+                color: Colors.white,
+                size: 42,
+              ),
+            );
+    }
+
     return GestureDetector(
-      onTap: () {
-        _cancelAndRestartTimer();
-      },
+      onTap: () => _cancelAndRestartTimer(),
       child: AbsorbPointer(
         absorbing: _hideStuff,
         child: Column(
@@ -45,9 +58,9 @@ class _MaterialControlsState extends State<MaterialControls> {
                         !_latestValue.isPlaying &&
                         _latestValue.duration == null ||
                     _latestValue.isBuffering
-                ? Expanded(
-                    child: Center(
-                      child: CircularProgressIndicator(),
+                ? const Expanded(
+                    child: const Center(
+                      child: const CircularProgressIndicator(),
                     ),
                   )
                 : _buildHitArea(),

+ 16 - 18
lib/src/material_progress_bar.dart

@@ -59,21 +59,19 @@ class _VideoProgressBarState extends State<MaterialVideoProgressBar> {
     }
 
     return GestureDetector(
-      child: (controller.value.hasError)
-          ? Text(controller.value.errorDescription)
-          : Center(
-              child: Container(
-                height: MediaQuery.of(context).size.height / 2,
-                width: MediaQuery.of(context).size.width,
-                color: Colors.transparent,
-                child: CustomPaint(
-                  painter: _ProgressBarPainter(
-                    controller.value,
-                    widget.colors,
-                  ),
-                ),
-              ),
+      child: Center(
+        child: Container(
+          height: MediaQuery.of(context).size.height / 2,
+          width: MediaQuery.of(context).size.width,
+          color: Colors.transparent,
+          child: CustomPaint(
+            painter: _ProgressBarPainter(
+              controller.value,
+              widget.colors,
             ),
+          ),
+        ),
+      ),
       onHorizontalDragStart: (DragStartDetails details) {
         if (!controller.value.initialized) {
           return;
@@ -144,10 +142,10 @@ class _ProgressBarPainter extends CustomPainter {
     if (!value.initialized) {
       return;
     }
-    final double playedPartPercent = value.position.inMilliseconds /
-        value.duration.inMilliseconds;
-    final double playedPart = playedPartPercent > 1? size.width
-        : playedPartPercent * size.width;
+    final double playedPartPercent =
+        value.position.inMilliseconds / value.duration.inMilliseconds;
+    final double playedPart =
+        playedPartPercent > 1 ? size.width : playedPartPercent * size.width;
     for (DurationRange range in value.buffered) {
       final double start = range.startFraction(value.duration) * size.width;
       final double end = range.endFraction(value.duration) * size.width;