From f9806b841a166524ce39ae3e26858645f57ad4ee Mon Sep 17 00:00:00 2001 From: sarbagyastha Date: Fri, 15 Nov 2019 15:14:17 +0545 Subject: [PATCH] Fix for #108 and #113 --- CHANGELOG.md | 5 +++ README.md | 8 +++- example/lib/main.dart | 33 +++++++++----- lib/src/enums/player_state.dart | 7 +-- lib/src/player/fullscreen_youtube_player.dart | 7 +++ lib/src/player/raw_youtube_player.dart | 24 +++++++--- lib/src/player/youtube_player.dart | 44 ++++++++++++------- lib/src/utils/youtube_player_controller.dart | 22 ++++------ lib/src/utils/youtube_player_flags.dart | 8 +++- lib/src/widgets/live_bottom_bar.dart | 2 +- lib/src/widgets/play_pause_button.dart | 2 +- lib/src/widgets/progress_bar.dart | 6 +-- lib/src/widgets/touch_shutter.dart | 8 ++-- pubspec.yaml | 2 +- 14 files changed, 112 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd616dc4..51c2976d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 6.0.2 +* Added `onEnded` callback for `YoutubePlayer` widget. (Fixes [#108](https://github.com/sarbagyastha/youtube_player_flutter/issues/108)) +* Removed `isEvaluationReady` & `isLoaded` flags as it had no use anyway. +* Added `controlsVisibleAtStart` flag. (Fixes [#113](https://github.com/sarbagyastha/youtube_player_flutter/issues/113)) + ## 6.0.1 * **(New Feature)** Added `title` and `author` property to `YoutubePlayerController`. * Removed **DataConnectionChecker** dependency. diff --git a/README.md b/README.md index ab4341c7..9f9c68c2 100644 --- a/README.md +++ b/README.md @@ -121,8 +121,12 @@ print(videoId); // BBAyRBTfsOU [Detailed Example](https://github.com/sarbagyastha/youtube_player_flutter/tree/master/example) -## Note -Know more about the configuration options [here](https://pub.dartlang.org/documentation/youtube_player_flutter/latest/youtube_player_flutter/youtube_player_flutter-library.html). +## Quick Links +* [YoutubePlayer](https://pub.dev/documentation/youtube_player_flutter/latest/youtube_player_flutter/YoutubePlayer-class.html) +* [YoutubePlayerController](https://pub.dev/documentation/youtube_player_flutter/latest/youtube_player_flutter/YoutubePlayerController-class.html) +* [YoutubePlayerFlags](https://pub.dev/documentation/youtube_player_flutter/latest/youtube_player_flutter/YoutubePlayerFlags-class.html) +* [YoutubePlayerValue](https://pub.dev/documentation/youtube_player_flutter/latest/youtube_player_flutter/YoutubePlayerValue-class.html) + ## Download Download apk from above(in badges) and try the plugin. diff --git a/example/lib/main.dart b/example/lib/main.dart index 5a26817a..ab308de6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -59,18 +59,30 @@ class _MyHomePageState extends State { bool _muted = false; bool _isPlayerReady = false; + final List _ids = [ + 'gQDByCdjUXw', + 'iLnmTe5Q2Qw', + '_WoCV4c6XOE', + 'KmzdUe0RSJo', + '6jZDSSZZxjQ', + 'p2lYr3vM_1w', + '7QUtEmBT_-w', + '34_PXCzGw1M', + ]; + int count = 0; + @override void initState() { super.initState(); _controller = YoutubePlayerController( - initialVideoId: 'p2lYr3vM_1w', + initialVideoId: 'QbjA8EiZJPk', flags: YoutubePlayerFlags( mute: false, autoPlay: true, - forceHideAnnotation: true, disableDragSeek: false, - loop: true, + loop: false, isLive: false, + controlsVisibleAtStart: true, ), )..addListener(listener); _idController = TextEditingController(); @@ -80,9 +92,6 @@ class _MyHomePageState extends State { void listener() { if (_isPlayerReady) { - if (_controller.value.playerState == PlayerState.ended) { - _showSnackBar('Video Ended!'); - } if (mounted && !_controller.value.isFullScreen) { setState(() { _playerState = _controller.value.playerState; @@ -167,6 +176,10 @@ class _MyHomePageState extends State { onReady: () { _isPlayerReady = true; }, + onEnded: (id) { + _controller.load(_ids[count++]); + _showSnackBar('Next Video Started!'); + }, ), Padding( padding: EdgeInsets.all(8.0), @@ -335,11 +348,11 @@ class _MyHomePageState extends State { Color _getStateColor(PlayerState state) { switch (state) { case PlayerState.unknown: - return Colors.redAccent; - case PlayerState.unStarted: return Colors.grey[700]; - case PlayerState.ended: + case PlayerState.unStarted: return Colors.pink; + case PlayerState.ended: + return Colors.red; case PlayerState.playing: return Colors.blueAccent; case PlayerState.paused: @@ -348,8 +361,6 @@ class _MyHomePageState extends State { return Colors.yellow; case PlayerState.cued: return Colors.blue[900]; - case PlayerState.stopped: - return Colors.red; default: return Colors.blue; } diff --git a/lib/src/enums/player_state.dart b/lib/src/enums/player_state.dart index 77f4a3dd..ad60fa30 100644 --- a/lib/src/enums/player_state.dart +++ b/lib/src/enums/player_state.dart @@ -12,9 +12,7 @@ enum PlayerState { /// Denotes state when player loads first video. unStarted, - /// Denotes state when player ends playing a video. - /// - /// Fires only once after video ends and switches to [PlayerState.stopped]. + /// Denotes state when player has ended playing a video. ended, /// Denotes state when player is playing video. @@ -28,7 +26,4 @@ enum PlayerState { /// Denotes state when player loads video and is ready to be played. cued, - - /// Denotes state when player has stopped playing videos. - stopped, } diff --git a/lib/src/player/fullscreen_youtube_player.dart b/lib/src/player/fullscreen_youtube_player.dart index 21abf7ac..1ceb84bd 100644 --- a/lib/src/player/fullscreen_youtube_player.dart +++ b/lib/src/player/fullscreen_youtube_player.dart @@ -21,6 +21,7 @@ Future showFullScreenYoutubePlayer({ Duration controlsTimeOut, Color liveUIColor, VoidCallback onReady, + void Function(String) onEnded, ProgressBarColors progressColors, String thumbnailUrl, }) async => @@ -36,6 +37,7 @@ Future showFullScreenYoutubePlayer({ controlsTimeOut: controlsTimeOut, liveUIColor: liveUIColor, onReady: onReady, + onEnded: onEnded, progressColors: progressColors, thumbnailUrl: thumbnailUrl, ), @@ -58,6 +60,9 @@ class _FullScreenYoutubePlayer extends StatefulWidget { /// {@macro youtube_player_flutter.onReady} final VoidCallback onReady; + /// {@macro youtube_player_flutter.onEnded} + final void Function(String) onEnded; + /// {@macro youtube_player_flutter.liveUIColor} final Color liveUIColor; @@ -80,6 +85,7 @@ class _FullScreenYoutubePlayer extends StatefulWidget { this.bufferIndicator, this.progressColors, this.onReady, + this.onEnded, this.liveUIColor = Colors.red, this.topActions, this.bottomActions, @@ -104,6 +110,7 @@ class _FullScreenYoutubePlayerState extends State<_FullScreenYoutubePlayer> { controlsTimeOut: widget.controlsTimeOut, liveUIColor: widget.liveUIColor, onReady: widget.onReady, + onEnded: widget.onEnded, progressColors: widget.progressColors, thumbnailUrl: widget.thumbnailUrl, topActions: widget.topActions, diff --git a/lib/src/player/raw_youtube_player.dart b/lib/src/player/raw_youtube_player.dart index 4ec60f45..a24f8f2e 100644 --- a/lib/src/player/raw_youtube_player.dart +++ b/lib/src/player/raw_youtube_player.dart @@ -17,8 +17,14 @@ import '../utils/youtube_player_controller.dart'; /// /// Use [YoutubePlayer] instead. class RawYoutubePlayer extends StatefulWidget { + /// {@macro youtube_player_flutter.onEnded} + final void Function(String videoId) onEnded; + /// Creates a [RawYoutubePlayer] widget. - RawYoutubePlayer({Key key}) : super(key: key); + RawYoutubePlayer({ + Key key, + this.onEnded, + }) : super(key: key); @override _RawYoutubePlayerState createState() => _RawYoutubePlayerState(); @@ -92,8 +98,13 @@ class _RawYoutubePlayerState extends State ); break; case '0': + if (widget.onEnded != null) { + widget.onEnded(controller.value.videoId); + } controller.updateValue( - controller.value.copyWith(playerState: PlayerState.ended), + controller.value.copyWith( + playerState: PlayerState.ended, + ), ); break; case '1': @@ -116,13 +127,16 @@ class _RawYoutubePlayerState extends State break; case '3': controller.updateValue( - controller.value - .copyWith(playerState: PlayerState.buffering), + controller.value.copyWith( + playerState: PlayerState.buffering, + ), ); break; case '5': controller.updateValue( - controller.value.copyWith(playerState: PlayerState.cued), + controller.value.copyWith( + playerState: PlayerState.cued, + ), ); break; default: diff --git a/lib/src/player/youtube_player.dart b/lib/src/player/youtube_player.dart index 0597afeb..a54db4de 100644 --- a/lib/src/player/youtube_player.dart +++ b/lib/src/player/youtube_player.dart @@ -7,7 +7,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; -import '../enums/player_state.dart'; import '../enums/thumbnail_quality.dart'; import '../utils/errors.dart'; import '../utils/youtube_player_controller.dart'; @@ -88,6 +87,13 @@ class YoutubePlayer extends StatefulWidget { /// {@endtemplate} final VoidCallback onReady; + /// {@template youtube_player_flutter.onEnded} + /// Called when player had ended playing a video. + /// + /// Returns video id that has ended playing. + /// {@endtemplate} + final void Function(String videoId) onEnded; + /// {@template youtube_player_flutter.liveUIColor} /// Overrides color of Live UI when enabled. /// {@endtemplate} @@ -135,6 +141,7 @@ class YoutubePlayer extends StatefulWidget { this.progressIndicatorColor = Colors.red, this.progressColors, this.onReady, + this.onEnded, this.liveUIColor = Colors.red, this.topActions, this.bottomActions, @@ -201,17 +208,19 @@ class _YoutubePlayerState extends State { if (controller.value.isReady && _initialLoad) { _initialLoad = false; if (controller.flags.autoPlay) controller.play(); - controller.updateValue( - controller.value.copyWith(videoId: controller.initialVideoId), - ); if (controller.flags.mute) controller.mute(); if (widget.onReady != null) widget.onReady(); + if (controller.flags.controlsVisibleAtStart) { + controller.updateValue( + controller.value.copyWith(isControlsVisible: true), + ); + } } if (controller.value.toggleFullScreen) { controller.updateValue( controller.value.copyWith( toggleFullScreen: false, - showControls: false, + isControlsVisible: false, ), ); if (controller.value.isFullScreen) { @@ -247,14 +256,6 @@ class _YoutubePlayerState extends State { Future.delayed(Duration(seconds: 2), () => controller.play()); } } - if (controller.value.playerState == PlayerState.ended) { - controller.updateValue( - controller.value.copyWith(playerState: PlayerState.stopped), - ); - if (controller.flags.loop) { - controller.load(controller.value.videoId); - } - } if (mounted) setState(() {}); } @@ -329,7 +330,16 @@ class _YoutubePlayerState extends State { fit: StackFit.expand, overflow: Overflow.visible, children: [ - RawYoutubePlayer(), + RawYoutubePlayer( + onEnded: (String id) { + if (controller.flags.loop) { + controller.load(controller.value.videoId); + } + if (widget.onEnded != null) { + widget.onEnded(id); + } + }, + ), if (!controller.flags.hideThumbnail) AnimatedOpacity( opacity: controller.value.hasPlayed ? 0 : 1, @@ -350,7 +360,7 @@ class _YoutubePlayerState extends State { ), if (!controller.flags.hideControls && controller.value.position > Duration(milliseconds: 100) && - !controller.value.showControls && + !controller.value.isControlsVisible && widget.showVideoProgressIndicator && !controller.flags.isLive && !controller.value.isFullScreen) @@ -380,7 +390,7 @@ class _YoutubePlayerState extends State { right: 0, child: AnimatedOpacity( opacity: !controller.flags.hideControls && - controller.value.showControls + controller.value.isControlsVisible ? 1 : 0, duration: Duration(milliseconds: 300), @@ -411,7 +421,7 @@ class _YoutubePlayerState extends State { right: 0, child: AnimatedOpacity( opacity: !controller.flags.hideControls && - controller.value.showControls + controller.value.isControlsVisible ? 1 : 0, duration: Duration(milliseconds: 300), diff --git a/lib/src/utils/youtube_player_controller.dart b/lib/src/utils/youtube_player_controller.dart index 0f18e8cc..297503f1 100644 --- a/lib/src/utils/youtube_player_controller.dart +++ b/lib/src/utils/youtube_player_controller.dart @@ -16,8 +16,7 @@ class YoutubePlayerValue { /// of a [YoutubePlayerController]. YoutubePlayerValue({ this.isReady = false, - this.showControls = false, - this.isLoaded = false, + this.isControlsVisible = false, this.hasPlayed = false, this.duration = const Duration(), this.position = const Duration(), @@ -40,11 +39,8 @@ class YoutubePlayerValue { /// Returns true when the player is ready to play videos. final bool isReady; - /// Whether to show controls or not. - final bool showControls; - - /// Returns true once video loads. - final bool isLoaded; + /// Defines whether or not the controls are visible. + final bool isControlsVisible; /// Returns true once the video start playing for the first time. final bool hasPlayed; @@ -55,7 +51,7 @@ class YoutubePlayerValue { /// The current position of the video. final Duration position; - /// The position up to which the video is buffered. + /// The position up to which the video is buffered.i final double buffered; /// Reports true if video is playing. @@ -107,7 +103,7 @@ class YoutubePlayerValue { /// the old one. YoutubePlayerValue copyWith({ bool isReady, - bool showControls, + bool isControlsVisible, bool isLoaded, bool hasPlayed, Duration duration, @@ -129,8 +125,7 @@ class YoutubePlayerValue { }) { return YoutubePlayerValue( isReady: isReady ?? this.isReady, - showControls: showControls ?? this.showControls, - isLoaded: isLoaded ?? this.isLoaded, + isControlsVisible: isControlsVisible ?? this.isControlsVisible, duration: duration ?? this.duration, hasPlayed: hasPlayed ?? this.hasPlayed, position: position ?? this.position, @@ -158,8 +153,7 @@ class YoutubePlayerValue { 'title: $title, ' 'author: $author, ' 'isReady: $isReady, ' - 'showControls: $showControls, ' - 'isLoaded: $isLoaded, ' + 'isControlsVisible: $isControlsVisible, ' 'duration: $duration, ' 'position: $position, ' 'buffered: $buffered, ' @@ -303,7 +297,7 @@ class YoutubePlayerController extends ValueNotifier { value.copyWith( isReady: false, isFullScreen: false, - showControls: false, + isControlsVisible: false, playerState: PlayerState.unknown, hasPlayed: false, duration: Duration(), diff --git a/lib/src/utils/youtube_player_flags.dart b/lib/src/utils/youtube_player_flags.dart index 6dccd8f6..dfcb3300 100644 --- a/lib/src/utils/youtube_player_flags.dart +++ b/lib/src/utils/youtube_player_flags.dart @@ -4,11 +4,16 @@ /// Defines player flags for [YoutubePlayer]. class YoutubePlayerFlags { - /// if set to true, hides the controls. + /// If set to true, hides the controls. /// /// Default is false. final bool hideControls; + /// Is set to true, controls will be visible at start. + /// + /// Default is false. + final bool controlsVisibleAtStart; + /// Define whether to auto play the video after initialization or not. /// /// Default is true. @@ -60,6 +65,7 @@ class YoutubePlayerFlags { /// Creates [YoutubePlayerFlags]. const YoutubePlayerFlags({ this.hideControls = false, + this.controlsVisibleAtStart = false, this.autoPlay = true, this.mute = false, this.isLive = false, diff --git a/lib/src/widgets/live_bottom_bar.dart b/lib/src/widgets/live_bottom_bar.dart index e53427c1..35b2e2fd 100644 --- a/lib/src/widgets/live_bottom_bar.dart +++ b/lib/src/widgets/live_bottom_bar.dart @@ -66,7 +66,7 @@ class _LiveBottomBarState extends State { @override Widget build(BuildContext context) { return Visibility( - visible: _controller.value.showControls, + visible: _controller.value.isControlsVisible, child: Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/src/widgets/play_pause_button.dart b/lib/src/widgets/play_pause_button.dart index 235fe0bc..784ceab1 100644 --- a/lib/src/widgets/play_pause_button.dart +++ b/lib/src/widgets/play_pause_button.dart @@ -82,7 +82,7 @@ class _PlayPauseButtonState extends State return Visibility( visible: _controller.value.playerState == PlayerState.cued || !_controller.value.isPlaying || - _controller.value.showControls, + _controller.value.isControlsVisible, child: Material( color: Colors.transparent, child: InkWell( diff --git a/lib/src/widgets/progress_bar.dart b/lib/src/widgets/progress_bar.dart index 727d283d..82e94130 100644 --- a/lib/src/widgets/progress_bar.dart +++ b/lib/src/widgets/progress_bar.dart @@ -123,7 +123,7 @@ class _ProgressBarState extends State { void _dragEndActions() { _controller.updateValue( - _controller.value.copyWith(showControls: false, isDragging: false), + _controller.value.copyWith(isControlsVisible: false, isDragging: false), ); _controller.seekTo(_position, allowSeekAhead: true); setState(() { @@ -136,7 +136,7 @@ class _ProgressBarState extends State { return GestureDetector( onHorizontalDragDown: (details) { _controller.updateValue( - _controller.value.copyWith(showControls: true, isDragging: true), + _controller.value.copyWith(isControlsVisible: true, isDragging: true), ); _seekToRelativePosition(details.globalPosition); setState(() { @@ -237,7 +237,7 @@ class _ProgressBarPainter extends CustomPainter { if (touchDown) { handlePaint.color = _handleColor.withOpacity(0.4); - canvas.drawCircle(progressPoint, handleRadius * 2, handlePaint); + canvas.drawCircle(progressPoint, handleRadius * 3, handlePaint); } handlePaint.color = _handleColor; diff --git a/lib/src/widgets/touch_shutter.dart b/lib/src/widgets/touch_shutter.dart index d14999b3..7821fcec 100644 --- a/lib/src/widgets/touch_shutter.dart +++ b/lib/src/widgets/touch_shutter.dart @@ -69,7 +69,7 @@ class _TouchShutterState extends State { void _toggleControls() { _controller.updateValue( _controller.value.copyWith( - showControls: !_controller.value.showControls, + isControlsVisible: !_controller.value.isControlsVisible, ), ); _timer?.cancel(); @@ -77,7 +77,7 @@ class _TouchShutterState extends State { if (!_controller.value.isDragging) { _controller.updateValue( _controller.value.copyWith( - showControls: false, + isControlsVisible: false, ), ); } @@ -99,7 +99,7 @@ class _TouchShutterState extends State { onHorizontalDragUpdate: (details) { _controller.updateValue( _controller.value.copyWith( - showControls: false, + isControlsVisible: false, ), ); delta = details.globalPosition.dx - dragStartPos; @@ -122,7 +122,7 @@ class _TouchShutterState extends State { }, child: AnimatedContainer( duration: Duration(milliseconds: 300), - color: _controller.value.showControls + color: _controller.value.isControlsVisible ? Colors.black.withAlpha(150) : Colors.transparent, child: _dragging diff --git a/pubspec.yaml b/pubspec.yaml index 7304bd91..2f11f440 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: youtube_player_flutter description: Flutter plugin for playing or streaming inline YouTube videos using the official iFrame player API. This plugin supports both Android and iOS. -version: 6.0.1 +version: 6.0.2 author: Sarbagya Dhaubanjar repository: https://github.com/sarbagyastha/youtube_player_flutter homepage: https://sarbagyastha.com.np