From c55358ee89f9fa9d7b9711fa2ef15dd2b140d1d1 Mon Sep 17 00:00:00 2001 From: creativeblaq <76699978+creativeblaq@users.noreply.github.com> Date: Sun, 15 Aug 2021 18:13:34 +0200 Subject: [PATCH] Better UI Changes (#594) * Better UI Changes * Update ci.yml * Feature/july changes (#598) * Fixed play after seeking issue on iOS * Fixed audio track selection issue on iOS/Android * Fixed issue where speed which couldn't be applied on iOS was saved in player state. * Added support for D-pad navigation using a Android TV remote control (#586) * Exposes all active eventListener (#585) * Updated changelog * Added docs * Updated documentation * Updated documentation * Added BetterPlayerMultipleGestureDetector, general refactor * General refactor Co-authored-by: Daniel Zarins <74965667+danielz-nenda@users.noreply.github.com> Co-authored-by: Letalus <41230136+Letalus@users.noreply.github.com> * Updated docs * Updated docs * Updated docs * Updated docs * fixed conflicts * Duplicated named argument 'onLongPress' removed * Better UI Changes * Feature/july changes (#598) * Fixed play after seeking issue on iOS * Fixed audio track selection issue on iOS/Android * Fixed issue where speed which couldn't be applied on iOS was saved in player state. * Added support for D-pad navigation using a Android TV remote control (#586) * Exposes all active eventListener (#585) * Updated changelog * Added docs * Updated documentation * Updated documentation * Added BetterPlayerMultipleGestureDetector, general refactor * General refactor Co-authored-by: Daniel Zarins <74965667+danielz-nenda@users.noreply.github.com> Co-authored-by: Letalus <41230136+Letalus@users.noreply.github.com> * fixed conflicts Co-authored-by: Jakub Co-authored-by: Daniel Zarins <74965667+danielz-nenda@users.noreply.github.com> Co-authored-by: Letalus <41230136+Letalus@users.noreply.github.com> --- docs/media/logo.png | Bin 0 -> 15772 bytes docs/media/style.css | 53 +++ example/lib/pages/hls_subtitles_page.dart | 64 +++- example/lib/pages/playlist_page.dart | 2 +- .../better_player_controls_configuration.dart | 44 +-- .../better_player_controls_state.dart | 104 +++++- .../better_player_cupertino_controls.dart | 71 ++-- .../better_player_material_controls.dart | 327 ++++++++++-------- pubspec.lock | 8 +- 9 files changed, 455 insertions(+), 218 deletions(-) create mode 100644 docs/media/logo.png create mode 100644 docs/media/style.css diff --git a/docs/media/logo.png b/docs/media/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..223c5aa45c232d1b5de04509da0a0980fdd8b970 GIT binary patch literal 15772 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 DNW36J literal 0 HcmV?d00001 diff --git a/docs/media/style.css b/docs/media/style.css new file mode 100644 index 000000000..9c8ba640a --- /dev/null +++ b/docs/media/style.css @@ -0,0 +1,53 @@ + +body .app-nav { + color: #34495e !important; +} +.cover { + color: #34495e !important; +} + +.cover #better-player .anchor span { + color: #34495e !important; +} + +section.cover { + min-height: 100vh; + height: auto !important; + padding: 2em 0.5em; +} + +section.cover .cover-main { + z-index: 0; +} + +section.cover .cover-main > .buttons a { + border-radius: 2rem; + border: 1px solid var(--theme-color, #42b983); + box-sizing: border-box; + color: var(--theme-color, #42b983); + display: inline-block; + font-size: 1.05rem; + letter-spacing: 0.1rem; + margin: 0.5rem 1rem; + padding: 0.75em 2rem; + text-decoration: none; + transition: all 0.15s ease; +} +section.cover .cover-main > .buttons a:last-child { + background-color: var(--theme-color, #42b983); + color: #fff; +} +section.cover .cover-main > .buttons a:last-child:hover { + color: inherit; + opacity: 0.8; +} +section.cover .cover-main > .buttons a:hover { + color: inherit; +} +section.cover blockquote > .buttons > a { + border-bottom: 2px solid var(--theme-color, #42b983); + transition: color 0.3s; +} +section.cover blockquote > .buttons > a:hover { + color: var(--theme-color, #42b983); +} \ No newline at end of file diff --git a/example/lib/pages/hls_subtitles_page.dart b/example/lib/pages/hls_subtitles_page.dart index f86b20954..9471f7c32 100644 --- a/example/lib/pages/hls_subtitles_page.dart +++ b/example/lib/pages/hls_subtitles_page.dart @@ -12,10 +12,42 @@ class _HlsSubtitlesPageState extends State { @override void initState() { + BetterPlayerControlsConfiguration controlsConfiguration = + BetterPlayerControlsConfiguration( + controlBarColor: Colors.black26, + iconsColor: Colors.white, + playIcon: Icons.play_arrow_outlined, + progressBarPlayedColor: Colors.indigo, + progressBarHandleColor: Colors.indigo, + skipBackIcon: Icons.replay_10_outlined, + skipForwardIcon: Icons.forward_10_outlined, + backwardSkipTimeInMilliseconds: 10000, + forwardSkipTimeInMilliseconds: 10000, + enableSkips: true, + enableFullscreen: true, + enablePip: true, + enablePlayPause: true, + enableMute: true, + enableAudioTracks: true, + enableProgressText: true, + enableSubtitles: true, + showControlsOnInitialize: true, + enablePlaybackSpeed: true, + controlBarHeight: 40, + loadingColor: Colors.red, + overflowModalColor: Colors.black54, + overflowModalTextColor: Colors.white, + overflowMenuIconsColor: Colors.white, + ); + BetterPlayerConfiguration betterPlayerConfiguration = BetterPlayerConfiguration( + controlsConfiguration: controlsConfiguration, aspectRatio: 16 / 9, fit: BoxFit.contain, + subtitlesConfiguration: BetterPlayerSubtitlesConfiguration( + fontSize: 16.0, + ) ); BetterPlayerDataSource dataSource = BetterPlayerDataSource( BetterPlayerDataSourceType.network, Constants.hlsPlaylistUrl, @@ -31,22 +63,24 @@ class _HlsSubtitlesPageState extends State { appBar: AppBar( title: Text("HLS subtitles"), ), - body: Column( - children: [ - const SizedBox(height: 8), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text( - "Player with HLS stream which loads subtitles from HLS." - " You can choose subtitles by using overflow menu (3 dots in right corner).", - style: TextStyle(fontSize: 16), + body: SingleChildScrollView( + child: Column( + children: [ + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + "Player with HLS stream which loads subtitles from HLS." + " You can choose subtitles by using overflow menu (3 dots in right corner).", + style: TextStyle(fontSize: 16), + ), + ), + AspectRatio( + aspectRatio: 16 / 9, + child: BetterPlayer(controller: _betterPlayerController), ), - ), - AspectRatio( - aspectRatio: 16 / 9, - child: BetterPlayer(controller: _betterPlayerController), - ), - ], + ], + ), ), ); } diff --git a/example/lib/pages/playlist_page.dart b/example/lib/pages/playlist_page.dart index be688eb9f..df79c2194 100644 --- a/example/lib/pages/playlist_page.dart +++ b/example/lib/pages/playlist_page.dart @@ -30,7 +30,7 @@ class _PlaylistPageState extends State { ); _betterPlayerPlaylistConfiguration = BetterPlayerPlaylistConfiguration( loopVideos: true, - nextVideoDelay: Duration(seconds: 1), + nextVideoDelay: Duration(seconds: 3), ); } diff --git a/lib/src/configuration/better_player_controls_configuration.dart b/lib/src/configuration/better_player_controls_configuration.dart index a5543cab4..a1f034801 100644 --- a/lib/src/configuration/better_player_controls_configuration.dart +++ b/lib/src/configuration/better_player_controls_configuration.dart @@ -1,4 +1,5 @@ // Dart imports: +import 'dart:io'; import 'dart:ui'; // Flutter imports: @@ -172,14 +173,14 @@ class BetterPlayerControlsConfiguration { {this.controlBarColor = Colors.black87, this.textColor = Colors.white, this.iconsColor = Colors.white, - this.playIcon = Icons.play_arrow, - this.pauseIcon = Icons.pause, - this.muteIcon = Icons.volume_up, - this.unMuteIcon = Icons.volume_mute, - this.fullscreenEnableIcon = Icons.fullscreen, - this.fullscreenDisableIcon = Icons.fullscreen_exit, - this.skipBackIcon = Icons.fast_rewind, - this.skipForwardIcon = Icons.fast_forward, + this.playIcon = Icons.play_arrow_outlined, + this.pauseIcon = Icons.pause_outlined, + this.muteIcon = Icons.volume_up_outlined, + this.unMuteIcon = Icons.volume_off_outlined, + this.fullscreenEnableIcon = Icons.fullscreen_outlined, + this.fullscreenDisableIcon = Icons.fullscreen_exit_outlined, + this.skipBackIcon = Icons.replay_10_outlined, + this.skipForwardIcon = Icons.forward_10_outlined, this.enableFullscreen = true, this.enableMute = true, this.enableProgressText = true, @@ -206,15 +207,15 @@ class BetterPlayerControlsConfiguration { this.enablePip = true, this.enableRetry = true, this.overflowMenuCustomItems = const [], - this.overflowMenuIcon = Icons.more_vert, - this.pipMenuIcon = Icons.picture_in_picture, - this.playbackSpeedIcon = Icons.shutter_speed, - this.qualitiesIcon = Icons.hd, - this.subtitlesIcon = Icons.text_fields, - this.audioTracksIcon = Icons.audiotrack, + this.overflowMenuIcon = Icons.more_vert_outlined, + this.pipMenuIcon = Icons.picture_in_picture_outlined, + this.playbackSpeedIcon = Icons.shutter_speed_outlined, + this.qualitiesIcon = Icons.hd_outlined, + this.subtitlesIcon = Icons.closed_caption_outlined, + this.audioTracksIcon = Icons.audiotrack_outlined, this.overflowMenuIconsColor = Colors.black, - this.forwardSkipTimeInMilliseconds = 15000, - this.backwardSkipTimeInMilliseconds = 15000, + this.forwardSkipTimeInMilliseconds = 10000, + this.backwardSkipTimeInMilliseconds = 10000, this.loadingColor = Colors.white, this.loadingWidget, this.backgroundColor = Colors.black, @@ -234,9 +235,12 @@ class BetterPlayerControlsConfiguration { factory BetterPlayerControlsConfiguration.cupertino() { return const BetterPlayerControlsConfiguration( - fullscreenEnableIcon: CupertinoIcons.fullscreen, - fullscreenDisableIcon: CupertinoIcons.fullscreen_exit, - playIcon: CupertinoIcons.play_arrow_solid, - pauseIcon: CupertinoIcons.pause_solid); + fullscreenEnableIcon: CupertinoIcons.arrow_up_left_arrow_down_right, + fullscreenDisableIcon: CupertinoIcons.arrow_down_right_arrow_up_left, + playIcon: CupertinoIcons.play_arrow_solid, + pauseIcon: CupertinoIcons.pause_solid, + skipBackIcon: CupertinoIcons.gobackward_15, + skipForwardIcon: CupertinoIcons.goforward_15, + ); } } diff --git a/lib/src/controls/better_player_controls_state.dart b/lib/src/controls/better_player_controls_state.dart index 7d6cc4f5b..db75ec586 100644 --- a/lib/src/controls/better_player_controls_state.dart +++ b/lib/src/controls/better_player_controls_state.dart @@ -1,4 +1,5 @@ // Dart imports: +import 'dart:io'; import 'dart:math'; // Project imports: @@ -11,6 +12,7 @@ import 'package:better_player/src/video_player/video_player.dart'; // Flutter imports: import 'package:collection/collection.dart' show IterableExtension; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; ///Base class for both material and cupertino controls @@ -123,6 +125,7 @@ abstract class BetterPlayerControlsState padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8), child: Row( children: [ + const SizedBox(width: 8), Icon( icon, color: betterPlayerControlsConfiguration.overflowMenuIconsColor, @@ -164,6 +167,14 @@ abstract class BetterPlayerControlsState padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), child: Row( children: [ + SizedBox(width: isSelected ? 8 : 16), + Visibility( + visible: isSelected, + child: Icon( + Icons.check_outlined, + color: + betterPlayerControlsConfiguration.overflowModalTextColor, + )), const SizedBox(width: 16), Text( "$value x", @@ -233,6 +244,14 @@ abstract class BetterPlayerControlsState padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), child: Row( children: [ + SizedBox(width: isSelected ? 8 : 16), + Visibility( + visible: isSelected, + child: Icon( + Icons.check_outlined, + color: + betterPlayerControlsConfiguration.overflowModalTextColor, + )), const SizedBox(width: 16), Text( subtitlesSource.type == BetterPlayerSubtitlesSourceType.none @@ -292,8 +311,9 @@ abstract class BetterPlayerControlsState final int height = track.height ?? 0; final int bitrate = track.bitrate ?? 0; final String mimeType = (track.mimeType ?? '').replaceAll('video/', ''); - final String trackName = preferredName ?? - "${width}x$height ${BetterPlayerUtils.formatBitrate(bitrate)} $mimeType"; + final String trackName = + preferredName ?? '${width > height ? height : width}p'; + /*"${width}x$height ${BetterPlayerUtils.formatBitrate(bitrate)} $mimeType";*/ final BetterPlayerAsmsTrack? selectedTrack = betterPlayerController!.betterPlayerAsmsTrack; @@ -308,6 +328,14 @@ abstract class BetterPlayerControlsState padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), child: Row( children: [ + SizedBox(width: isSelected ? 8 : 16), + Visibility( + visible: isSelected, + child: Icon( + Icons.check_outlined, + color: + betterPlayerControlsConfiguration.overflowModalTextColor, + )), const SizedBox(width: 16), Text( trackName, @@ -331,6 +359,14 @@ abstract class BetterPlayerControlsState padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), child: Row( children: [ + SizedBox(width: isSelected ? 8 : 16), + Visibility( + visible: isSelected, + child: Icon( + Icons.check_outlined, + color: + betterPlayerControlsConfiguration.overflowModalTextColor, + )), const SizedBox(width: 16), Text( name, @@ -382,6 +418,14 @@ abstract class BetterPlayerControlsState padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), child: Row( children: [ + SizedBox(width: isSelected ? 8 : 16), + Visibility( + visible: isSelected, + child: Icon( + Icons.check_outlined, + color: + betterPlayerControlsConfiguration.overflowModalTextColor, + )), const SizedBox(width: 16), Text( audioTrack.label!, @@ -396,20 +440,68 @@ abstract class BetterPlayerControlsState TextStyle _getOverflowMenuElementTextStyle(bool isSelected) { return TextStyle( fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, - color: betterPlayerControlsConfiguration.overflowModalTextColor, + color: isSelected + ? betterPlayerControlsConfiguration.overflowModalTextColor + : betterPlayerControlsConfiguration.overflowModalTextColor + .withOpacity(0.7), ); } void _showModalBottomSheet(List children) { + Platform.isAndroid + ? _showMaterialBottomSheet(children) + : _showCupertinoModalBottomSheet(children); + } + + void _showCupertinoModalBottomSheet(List children) { + showCupertinoModalPopup( + barrierColor: Colors.transparent, + context: context, + builder: (context) { + return SafeArea( + top: false, + child: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8), + decoration: BoxDecoration( + color: betterPlayerControlsConfiguration.overflowModalColor, + /*shape: RoundedRectangleBorder(side: Bor,borderRadius: 24,)*/ + borderRadius: BorderRadius.only( + topLeft: Radius.circular(24.0), + topRight: Radius.circular(24.0)), + ), + child: Column( + children: children, + ), + ), + ), + ); + }, + ); + } + + void _showMaterialBottomSheet(List children) { showModalBottomSheet( - backgroundColor: betterPlayerControlsConfiguration.overflowModalColor, + backgroundColor: Colors.transparent, context: context, builder: (context) { return SafeArea( top: false, child: SingleChildScrollView( - child: Column( - children: children, + physics: BouncingScrollPhysics(), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8), + decoration: BoxDecoration( + color: betterPlayerControlsConfiguration.overflowModalColor, + /*shape: RoundedRectangleBorder(side: Bor,borderRadius: 24,)*/ + borderRadius: BorderRadius.only( + topLeft: Radius.circular(24.0), + topRight: Radius.circular(24.0)), + ), + child: Column( + children: children, + ), ), ), ); diff --git a/lib/src/controls/better_player_cupertino_controls.dart b/lib/src/controls/better_player_cupertino_controls.dart index 8d520f0ab..422039b42 100644 --- a/lib/src/controls/better_player_cupertino_controls.dart +++ b/lib/src/controls/better_player_cupertino_controls.dart @@ -4,6 +4,7 @@ import 'dart:ui' as ui; // Flutter imports: import 'package:better_player/src/configuration/better_player_controls_configuration.dart'; +import 'package:flutter/cupertino.dart'; import 'package:better_player/src/controls/better_player_multiple_gesture_detector.dart'; import 'package:flutter/material.dart'; @@ -85,8 +86,9 @@ class _BetterPlayerCupertinoControlsState final orientation = MediaQuery.of(context).orientation; final barHeight = orientation == Orientation.portrait ? _controlsConfiguration.controlBarHeight - : _controlsConfiguration.controlBarHeight + 17; - final buttonPadding = orientation == Orientation.portrait ? 16.0 : 24.0; + : _controlsConfiguration.controlBarHeight + 10; + final buttonPadding = 10.0; + _wasLoading = isLoading(_latestValue); return GestureDetector( onTap: () { @@ -181,7 +183,9 @@ class _BetterPlayerCupertinoControlsState ), child: Container( height: barHeight, - color: backgroundColor, + decoration: BoxDecoration( + color: backgroundColor.withOpacity(0.5), + ), child: _betterPlayerController!.isLiveStream() ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -245,6 +249,7 @@ class _BetterPlayerCupertinoControlsState Color backgroundColor, Color iconColor, double barHeight, + double iconSize, double buttonPadding, ) { return GestureDetector( @@ -255,20 +260,22 @@ class _BetterPlayerCupertinoControlsState child: ClipRRect( borderRadius: BorderRadius.circular(10), child: BackdropFilter( - filter: ui.ImageFilter.blur(sigmaX: 10), + filter: ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: Container( height: barHeight, - padding: EdgeInsets.only( - left: buttonPadding, - right: buttonPadding, + padding: EdgeInsets.symmetric( + horizontal: buttonPadding, + ), + decoration: BoxDecoration( + color: backgroundColor.withOpacity(0.5), ), - color: backgroundColor, child: Center( child: Icon( _betterPlayerController!.isFullScreen ? _controlsConfiguration.fullscreenDisableIcon : _controlsConfiguration.fullscreenEnableIcon, color: iconColor, + size: iconSize, ), ), ), @@ -312,6 +319,7 @@ class _BetterPlayerCupertinoControlsState Color backgroundColor, Color iconColor, double barHeight, + double iconSize, double buttonPadding, ) { return GestureDetector( @@ -326,7 +334,9 @@ class _BetterPlayerCupertinoControlsState child: BackdropFilter( filter: ui.ImageFilter.blur(sigmaX: 10.0), child: Container( - color: backgroundColor, + decoration: BoxDecoration( + color: backgroundColor.withOpacity(0.5), + ), child: Container( height: barHeight, padding: EdgeInsets.symmetric( @@ -335,6 +345,7 @@ class _BetterPlayerCupertinoControlsState child: Icon( _controlsConfiguration.overflowMenuIcon, color: iconColor, + size: iconSize, ), ), ), @@ -349,6 +360,7 @@ class _BetterPlayerCupertinoControlsState Color backgroundColor, Color iconColor, double barHeight, + double iconSize, double buttonPadding, ) { return GestureDetector( @@ -370,7 +382,9 @@ class _BetterPlayerCupertinoControlsState child: BackdropFilter( filter: ui.ImageFilter.blur(sigmaX: 10.0), child: Container( - color: backgroundColor, + decoration: BoxDecoration( + color: backgroundColor.withOpacity(0.5), + ), child: Container( height: barHeight, padding: EdgeInsets.symmetric( @@ -381,6 +395,7 @@ class _BetterPlayerCupertinoControlsState ? _controlsConfiguration.muteIcon : _controlsConfiguration.unMuteIcon, color: iconColor, + size: iconSize, ), ), ), @@ -406,6 +421,7 @@ class _BetterPlayerCupertinoControlsState ? _controlsConfiguration.pauseIcon : _controlsConfiguration.playIcon, color: iconColor, + size: barHeight * 0.6, ), ), ); @@ -449,10 +465,13 @@ class _BetterPlayerCupertinoControlsState height: barHeight, color: Colors.transparent, margin: const EdgeInsets.only(left: 10.0), - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), child: Icon( _controlsConfiguration.skipBackIcon, color: iconColor, + size: barHeight * 0.4, ), ), ); @@ -469,6 +488,7 @@ class _BetterPlayerCupertinoControlsState child: Icon( _controlsConfiguration.skipForwardIcon, color: iconColor, + size: barHeight * 0.4, ), ), ); @@ -477,13 +497,14 @@ class _BetterPlayerCupertinoControlsState Widget _buildTopBar( Color backgroundColor, Color iconColor, - double barHeight, + double topBarHeight, double buttonPadding, ) { if (!betterPlayerController!.controlsEnabled) { return const SizedBox(); } - + final barHeight = topBarHeight * 0.8; + final iconSize = topBarHeight * 0.4; return Container( height: barHeight, margin: EdgeInsets.only( @@ -495,26 +516,33 @@ class _BetterPlayerCupertinoControlsState children: [ if (_controlsConfiguration.enableFullscreen) _buildExpandButton( - backgroundColor, iconColor, barHeight, buttonPadding) + backgroundColor, iconColor, barHeight, iconSize, buttonPadding) else const SizedBox(), + const SizedBox( + width: 4, + ), if (_controlsConfiguration.enablePip) _buildPipButton( - backgroundColor, iconColor, barHeight, buttonPadding) + backgroundColor, iconColor, barHeight, iconSize, buttonPadding) else const SizedBox(), - Expanded(child: Container()), + Spacer(), if (_controlsConfiguration.enableMute) _buildMuteButton(_controller, backgroundColor, iconColor, barHeight, - buttonPadding) + iconSize, buttonPadding) else const SizedBox(), + const SizedBox( + width: 4, + ), if (_controlsConfiguration.enableOverflowMenu) _buildMoreButton( _controller, backgroundColor, iconColor, barHeight, + iconSize, buttonPadding, ) else @@ -711,7 +739,7 @@ class _BetterPlayerCupertinoControlsState mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( - Icons.warning, + CupertinoIcons.exclamationmark_triangle, color: _controlsConfiguration.iconsColor, size: 42, ), @@ -747,7 +775,7 @@ class _BetterPlayerCupertinoControlsState } Widget _buildPipButton(Color backgroundColor, Color iconColor, - double barHeight, double buttonPadding) { + double barHeight, double iconSize, double buttonPadding) { return FutureBuilder( future: _betterPlayerController!.isPictureInPictureSupported(), builder: (context, snapshot) { @@ -772,11 +800,14 @@ class _BetterPlayerCupertinoControlsState left: buttonPadding, right: buttonPadding, ), - color: backgroundColor, + decoration: BoxDecoration( + color: backgroundColor.withOpacity(0.5), + ), child: Center( child: Icon( _controlsConfiguration.pipMenuIcon, color: iconColor, + size: iconSize, ), ), ), diff --git a/lib/src/controls/better_player_material_controls.dart b/lib/src/controls/better_player_material_controls.dart index 749345287..c6c76d491 100644 --- a/lib/src/controls/better_player_material_controls.dart +++ b/lib/src/controls/better_player_material_controls.dart @@ -91,7 +91,7 @@ class _BetterPlayerMaterialControlsState BetterPlayerMultipleGestureDetector.of(context)!.onDoubleTap?.call(); } cancelAndRestartTimer(); - _onPlayPause(); + //_onPlayPause(); }, onLongPress: () { if (BetterPlayerMultipleGestureDetector.of(context) != null) { @@ -100,14 +100,18 @@ class _BetterPlayerMaterialControlsState }, child: AbsorbPointer( absorbing: _hideStuff, - child: Column( + child: + Stack( + fit: StackFit.expand, + //crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - _buildTopBar(), if (_wasLoading) - Expanded(child: Center(child: _buildLoadingWidget())) + Center(child: _buildLoadingWidget()) else _buildHitArea(), - _buildBottomBar(), + Positioned(top: 0, left: 0, right: 0, child: _buildTopBar(),), + Positioned(bottom: 0, left: 0, right: 0, child: _buildBottomBar()), + _buildNextVideoWidget(), ], ), ), @@ -187,29 +191,27 @@ class _BetterPlayerMaterialControlsState return const SizedBox(); } - return Row(mainAxisAlignment: MainAxisAlignment.end, children: [ - if (_controlsConfiguration.enablePip) - _buildPipButtonWrapperWidget(_hideStuff, _onPlayerHide) - else - const SizedBox(), - if (_controlsConfiguration.enableOverflowMenu) - AnimatedOpacity( + return Container( + child: (_controlsConfiguration.enableOverflowMenu) ? AnimatedOpacity( opacity: _hideStuff ? 0.0 : 1.0, duration: _controlsConfiguration.controlsHideTime, onEnd: _onPlayerHide, child: Container( + //color: _controlsConfiguration.controlBarColor, height: _controlsConfiguration.controlBarHeight, + width: double.infinity, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ + (_controlsConfiguration.enablePip) + ? _buildPipButtonWrapperWidget(_hideStuff, _onPlayerHide) + : const SizedBox(), _buildMoreButton(), ], ), ), - ) - else - const SizedBox() - ]); + ) : const SizedBox() + ); } Widget _buildPipButton() { @@ -228,8 +230,8 @@ class _BetterPlayerMaterialControlsState ); } - Widget _buildPipButtonWrapperWidget( - bool hideStuff, void Function() onPlayerHide) { + Widget _buildPipButtonWrapperWidget(bool hideStuff, + void Function() onPlayerHide) { return FutureBuilder( future: betterPlayerController!.isPictureInPictureSupported(), builder: (context, snapshot) { @@ -281,34 +283,41 @@ class _BetterPlayerMaterialControlsState duration: _controlsConfiguration.controlsHideTime, onEnd: _onPlayerHide, child: Container( - height: _controlsConfiguration.controlBarHeight, - color: _controlsConfiguration.controlBarColor, - child: Row( - children: [ - if (_controlsConfiguration.enablePlayPause) - _buildPlayPause(_controller!) - else - const SizedBox(), - if (_betterPlayerController!.isLiveStream()) - _buildLiveWidget() - else - _controlsConfiguration.enableProgressText - ? _buildPosition() - : const SizedBox(), + height: _controlsConfiguration.controlBarHeight + 20.0, + //color: _controlsConfiguration.controlBarColor, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(flex: 75, child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (_controlsConfiguration.enablePlayPause) + _buildPlayPause(_controller!) + else + const SizedBox(), + if (_betterPlayerController!.isLiveStream()) + _buildLiveWidget() + else + _controlsConfiguration.enableProgressText + ? Expanded(child: _buildPosition()) + : const SizedBox(), + Spacer(), + if (_controlsConfiguration.enableMute) + _buildMuteButton(_controller) + else + const SizedBox(), + if (_controlsConfiguration.enableFullscreen) + _buildExpandButton() + else + const SizedBox(), + ], + ),), if (_betterPlayerController!.isLiveStream()) const SizedBox() else _controlsConfiguration.enableProgressBar ? _buildProgressBar() : const SizedBox(), - if (_controlsConfiguration.enableMute) - _buildMuteButton(_controller) - else - const SizedBox(), - if (_controlsConfiguration.enableFullscreen) - _buildExpandButton() - else - const SizedBox(), ], ), ), @@ -316,13 +325,11 @@ class _BetterPlayerMaterialControlsState } Widget _buildLiveWidget() { - return Expanded( - child: Text( - _betterPlayerController!.translations.controlsLive, - style: TextStyle( - color: _controlsConfiguration.liveTextColor, - fontWeight: FontWeight.bold), - ), + return Text( + _betterPlayerController!.translations.controlsLive, + style: TextStyle( + color: _controlsConfiguration.liveTextColor, + fontWeight: FontWeight.bold), ); } @@ -353,40 +360,36 @@ class _BetterPlayerMaterialControlsState if (!betterPlayerController!.controlsEnabled) { return const SizedBox(); } - return Expanded( - child: Container( - color: Colors.transparent, - child: Center( - child: AnimatedOpacity( - opacity: _hideStuff ? 0.0 : 1.0, - duration: _controlsConfiguration.controlsHideTime, - child: Stack( - children: [ - _buildMiddleRow(), - _buildNextVideoWidget(), - ], - ), - ), + return Container( + child: Center( + child: AnimatedOpacity( + opacity: _hideStuff ? 0.0 : 1.0, + duration: _controlsConfiguration.controlsHideTime, + child: _buildMiddleRow(), + ), ), ); } Widget _buildMiddleRow() { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), + return Container( + color: Colors.black54, //_controlsConfiguration.controlBarColor, + width: double.infinity, + height: double.infinity, child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (_controlsConfiguration.enableSkips) - _buildSkipButton() - else - const SizedBox(), - _buildReplayButton(), - if (_controlsConfiguration.enableSkips) - _buildForwardButton() - else - const SizedBox(), + (_controlsConfiguration.enableSkips) + ? _buildSkipButton() + : const SizedBox(), + _buildReplayButton(_controller!), + (_controlsConfiguration.enableSkips) + ? _buildForwardButton() + : const SizedBox(), + + ], ), ); @@ -394,18 +397,21 @@ class _BetterPlayerMaterialControlsState Widget _buildHitAreaClickableButton( {Widget? icon, required void Function() onClicked}) { - return BetterPlayerMaterialClickableWidget( - onTap: onClicked, - child: Align( - child: Container( - decoration: BoxDecoration( - color: _controlsConfiguration.controlBarColor, - borderRadius: BorderRadius.circular(48), - ), - child: Padding( - padding: const EdgeInsets.all(12), - child: Stack( - children: [icon!], + return Container( + constraints: BoxConstraints(maxHeight: 80.0, maxWidth: 80.0), + child: BetterPlayerMaterialClickableWidget( + onTap: onClicked, + child: Align( + child: Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(48), + ), + child: Padding( + padding: const EdgeInsets.all(8), + child: Stack( + children: [icon!], + ), ), ), ), @@ -417,7 +423,7 @@ class _BetterPlayerMaterialControlsState return _buildHitAreaClickableButton( icon: Icon( _controlsConfiguration.skipBackIcon, - size: 32, + size: 24, color: _controlsConfiguration.iconsColor, ), onClicked: skipBack, @@ -428,40 +434,46 @@ class _BetterPlayerMaterialControlsState return _buildHitAreaClickableButton( icon: Icon( _controlsConfiguration.skipForwardIcon, - size: 32, + size: 24, color: _controlsConfiguration.iconsColor, ), onClicked: skipForward, ); } - Widget _buildReplayButton() { + Widget _buildReplayButton(VideoPlayerController controller) { final bool isFinished = isVideoFinished(_latestValue); - if (!isFinished) { - return const SizedBox(); - } - return _buildHitAreaClickableButton( - icon: Icon( + icon: isFinished ? Icon( Icons.replay, - size: 32, + size: 42, + color: _controlsConfiguration.iconsColor, + ) : Icon( + controller.value.isPlaying + ? _controlsConfiguration.pauseIcon + : _controlsConfiguration.playIcon, + size: 42, color: _controlsConfiguration.iconsColor, ), onClicked: () { - if (_latestValue != null && _latestValue!.isPlaying) { - if (_displayTapped) { + if (isFinished) { + if (_latestValue != null && _latestValue!.isPlaying) { + if (_displayTapped) { + setState(() { + _hideStuff = true; + }); + } else { + cancelAndRestartTimer(); + } + } else { + _onPlayPause(); + setState(() { _hideStuff = true; }); - } else { - cancelAndRestartTimer(); } } else { _onPlayPause(); - - setState(() { - _hideStuff = true; - }); } }, ); @@ -480,15 +492,16 @@ class _BetterPlayerMaterialControlsState child: Align( alignment: Alignment.bottomRight, child: Container( - margin: const EdgeInsets.only(bottom: 4, right: 24), + margin: EdgeInsets.only(bottom: _controlsConfiguration.controlBarHeight+20, right: 24), decoration: BoxDecoration( color: _controlsConfiguration.controlBarColor, - borderRadius: BorderRadius.circular(32), + borderRadius: BorderRadius.circular(16), ), child: Padding( padding: const EdgeInsets.all(12), child: Text( - "${_betterPlayerController!.translations.controlsNextVideoIn} $time ...", + "${_betterPlayerController!.translations + .controlsNextVideoIn} $time...", style: const TextStyle(color: Colors.white), ), ), @@ -502,9 +515,7 @@ class _BetterPlayerMaterialControlsState ); } - Widget _buildMuteButton( - VideoPlayerController? controller, - ) { + Widget _buildMuteButton(VideoPlayerController? controller,) { return BetterPlayerMaterialClickableWidget( onTap: () { cancelAndRestartTimer(); @@ -538,7 +549,7 @@ class _BetterPlayerMaterialControlsState return BetterPlayerMaterialClickableWidget( onTap: _onPlayPause, child: Container( - height: _controlsConfiguration.controlBarHeight, + height: double.infinity, margin: const EdgeInsets.symmetric(horizontal: 4), padding: const EdgeInsets.symmetric(horizontal: 12), child: Icon( @@ -553,19 +564,30 @@ class _BetterPlayerMaterialControlsState Widget _buildPosition() { final position = - _latestValue != null ? _latestValue!.position : Duration.zero; + _latestValue != null ? _latestValue!.position : Duration.zero; final duration = _latestValue != null && _latestValue!.duration != null ? _latestValue!.duration! : Duration.zero; return Padding( - padding: const EdgeInsets.only(right: 24), - child: Text( - '${BetterPlayerUtils.formatDuration(position)} / ${BetterPlayerUtils.formatDuration(duration)}', - style: TextStyle( - fontSize: 14, - color: _controlsConfiguration.textColor, - decoration: TextDecoration.none, + padding: _controlsConfiguration.enablePlayPause ? EdgeInsets.only( + right: 24) : EdgeInsets.symmetric(horizontal: 22), + child: RichText( + text: TextSpan( + text: '${BetterPlayerUtils.formatDuration(position)}', + style: TextStyle( + fontSize: 10.0, + color: _controlsConfiguration.textColor, + decoration: TextDecoration.none, + ), + children: [ + TextSpan(text: ' / ${BetterPlayerUtils + .formatDuration(duration)}', + style: TextStyle(fontSize: 10.0, + color: Colors.grey, + decoration: TextDecoration.none,), + ) + ] ), ), ); @@ -602,13 +624,13 @@ class _BetterPlayerMaterialControlsState _controlsVisibilityStreamSubscription = _betterPlayerController!.controlsVisibilityStream.listen((state) { - setState(() { - _hideStuff = !state; - }); - if (!_hideStuff) { - cancelAndRestartTimer(); - } - }); + setState(() { + _hideStuff = !state; + }); + if (!_hideStuff) { + cancelAndRestartTimer(); + } + }); } void _onExpandCollapse() { @@ -618,10 +640,10 @@ class _BetterPlayerMaterialControlsState _betterPlayerController!.toggleFullScreen(); _showAfterExpandCollapseTimer = Timer(_controlsConfiguration.controlsHideTime, () { - setState(() { - cancelAndRestartTimer(); - }); - }); + setState(() { + cancelAndRestartTimer(); + }); + }); }); } @@ -640,8 +662,7 @@ class _BetterPlayerMaterialControlsState } else { cancelAndRestartTimer(); - if (!_controller!.value.initialized) { - } else { + if (!_controller!.value.initialized) {} else { if (isFinished) { _betterPlayerController!.seekTo(const Duration()); } @@ -680,27 +701,26 @@ class _BetterPlayerMaterialControlsState } Widget _buildProgressBar() { - return Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 20), - child: BetterPlayerMaterialVideoProgressBar( - _controller, - _betterPlayerController, - onDragStart: () { - _hideTimer?.cancel(); - }, - onDragEnd: () { - _startHideTimer(); - }, - colors: BetterPlayerProgressColors( - playedColor: _controlsConfiguration.progressBarPlayedColor, - handleColor: _controlsConfiguration.progressBarHandleColor, - bufferedColor: _controlsConfiguration.progressBarBufferedColor, - backgroundColor: - _controlsConfiguration.progressBarBackgroundColor), - ), + return Expanded(flex: 40, child: Container( + alignment: Alignment.bottomCenter, + padding: const EdgeInsets.symmetric(horizontal: 12), + child: BetterPlayerMaterialVideoProgressBar( + _controller, + _betterPlayerController, + onDragStart: () { + _hideTimer?.cancel(); + }, + onDragEnd: () { + _startHideTimer(); + }, + colors: BetterPlayerProgressColors( + playedColor: _controlsConfiguration.progressBarPlayedColor, + handleColor: _controlsConfiguration.progressBarHandleColor, + bufferedColor: _controlsConfiguration.progressBarBufferedColor, + backgroundColor: + _controlsConfiguration.progressBarBackgroundColor), ), - ); + )); } void _onPlayerHide() { @@ -710,12 +730,15 @@ class _BetterPlayerMaterialControlsState Widget? _buildLoadingWidget() { if (_controlsConfiguration.loadingWidget != null) { - return _controlsConfiguration.loadingWidget; + return Container( + color: _controlsConfiguration.controlBarColor, + child: _controlsConfiguration.loadingWidget, + ); } return CircularProgressIndicator( valueColor: - AlwaysStoppedAnimation(_controlsConfiguration.loadingColor), + AlwaysStoppedAnimation(_controlsConfiguration.loadingColor), ); } } diff --git a/pubspec.lock b/pubspec.lock index 45f28455e..2be5ac9a2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.6.1" + version: "2.7.0" boolean_selector: dependency: transitive description: @@ -28,7 +28,7 @@ packages: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.1" clock: dependency: transitive description: @@ -146,7 +146,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.0" path: dependency: transitive description: @@ -270,7 +270,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.4.1" typed_data: dependency: transitive description: