diff --git a/CHANGELOG.md b/CHANGELOG.md index f71888d53..0d4bd8ea0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 0.0.77 +* Fixed full screen safe area issue in cupertino controls. +* Fixed subtitles duplication after changing data source. +* Fixed progress bar issues when changing position of the video. +* [BREAKING_CHANGE] Changed min. Flutter version to 2.2.3. +* Changed log level in ExoPlayer to Error. +* Added url parameter for changedResolution event. +* Added [videoExtension] support for network data source for scenario where video source has no extension and cache manager requires it. +* Added parameters to [changedTrack] event. +* Added [changedPlaylistItem] event. +* Added [autoDetectFullscreenAspectRatio] parameter in [BetterPlayerConfiguration] (by https://github.com/Brazol) +* Updated license. +* Updated screenshots. + ## 0.0.76 * Fixed iOS build issue. * [BREAKING_CHANGE] Changed min required iOS version to 11. diff --git a/LICENSE b/LICENSE index f49a4e16e..cf5a15060 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2020 Jakub Homlala and Better Player / Chewie / Video Player contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/analysis_options.yaml b/analysis_options.yaml index 5fc901eea..aa322b6ae 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -18,4 +18,5 @@ linter: invalid_dependency: false sort_pub_dependencies: false avoid_unnecessary_containers: false + use_setters_to_change_properties: false diff --git a/android/src/main/java/com/jhomlala/better_player/BetterPlayer.java b/android/src/main/java/com/jhomlala/better_player/BetterPlayer.java index e8442b7f4..f37b86c49 100644 --- a/android/src/main/java/com/jhomlala/better_player/BetterPlayer.java +++ b/android/src/main/java/com/jhomlala/better_player/BetterPlayer.java @@ -121,6 +121,8 @@ final class BetterPlayer { TextureRegistry.SurfaceTextureEntry textureEntry, CustomDefaultLoadControl customDefaultLoadControl, Result result) { + com.google.android.exoplayer2.util.Log.setLogLevel( + com.google.android.exoplayer2.util.Log.LOG_LEVEL_ERROR); this.eventChannel = eventChannel; this.textureEntry = textureEntry; trackSelector = new DefaultTrackSelector(context); @@ -568,7 +570,7 @@ public void onCancel(Object o) { exoPlayer.addListener(new Player.Listener() { @Override public void onPlaybackStateChanged(int playbackState) { - + if (playbackState == Player.STATE_BUFFERING) { sendBufferingUpdate(true); Map event = new HashMap<>(); diff --git a/docs/install.md b/doc/install.md similarity index 100% rename from docs/install.md rename to doc/install.md diff --git a/docs/_coverpage.md b/docs/_coverpage.md index 80585b42e..617556f05 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -12,4 +12,4 @@ - Supports both Android and iOS [GitHub](https://github.com/jhomlala/betterplayer) -[Get Started](#README) \ No newline at end of file +[Get Started](https://jhomlala.github.io/betterplayer/#/README) \ No newline at end of file diff --git a/docs/events.md b/docs/events.md index bdc2b856c..de80c8ca7 100644 --- a/docs/events.md +++ b/docs/events.md @@ -17,7 +17,14 @@ You can listen to video player events like: changedSubtitles, changedTrack, changedPlayerVisibility, - changedResolution + changedResolution, + pipStart, + pipStop, + setupDataSource, + bufferingStart, + bufferingUpdate, + bufferingEnd, + changedPlaylistItem ``` After creating `BetterPlayerController` you can add event listener this way: diff --git a/docs/generalconfiguration.md b/docs/generalconfiguration.md index 8abf05ed0..31ee2d543 100644 --- a/docs/generalconfiguration.md +++ b/docs/generalconfiguration.md @@ -101,6 +101,10 @@ final List translations; /// ignored. final bool autoDetectFullscreenDeviceOrientation; +///Defines if player should auto detect full screen aspect ration of the video. +///If [deviceOrientationsOnFullScreen] is true this is done automaticaly also. +final bool autoDetectFullscreenAspectRatio; + ///Defines flag which enables/disables lifecycle handling (pause on app closed, ///play on app resumed). Default value is true. final bool handleLifecycle; diff --git a/flutter_01.png b/flutter_01.png deleted file mode 100644 index e69de29bb..000000000 diff --git a/flutter_02.png b/flutter_02.png deleted file mode 100644 index ff602c127..000000000 Binary files a/flutter_02.png and /dev/null differ diff --git a/ios/Classes/BetterPlayer.h b/ios/Classes/BetterPlayer.h index ca900b8df..3e721a32e 100644 --- a/ios/Classes/BetterPlayer.h +++ b/ios/Classes/BetterPlayer.h @@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)setMixWithOthers:(bool)mixWithOthers; - (void)seekTo:(int)location; - (void)setDataSourceAsset:(NSString*)asset withKey:(NSString*)key withCertificateUrl:(NSString*)certificateUrl withLicenseUrl:(NSString*)licenseUrl cacheKey:(NSString*)cacheKey cacheManager:(CacheManager*)cacheManager overriddenDuration:(int) overriddenDuration; -- (void)setDataSourceURL:(NSURL*)url withKey:(NSString*)key withCertificateUrl:(NSString*)certificateUrl withLicenseUrl:(NSString*)licenseUrl withHeaders:(NSDictionary*)headers withCache:(BOOL)useCache cacheKey:(NSString*)cacheKey cacheManager:(CacheManager*)cacheManager overriddenDuration:(int) overriddenDuration; +- (void)setDataSourceURL:(NSURL*)url withKey:(NSString*)key withCertificateUrl:(NSString*)certificateUrl withLicenseUrl:(NSString*)licenseUrl withHeaders:(NSDictionary*)headers withCache:(BOOL)useCache cacheKey:(NSString*)cacheKey cacheManager:(CacheManager*)cacheManager overriddenDuration:(int) overriddenDuration videoExtension: (NSString*) videoExtension; - (void)setVolume:(double)volume; - (void)setSpeed:(double)speed result:(FlutterResult)result; - (void) setAudioTrack:(NSString*) name index:(int) index; diff --git a/ios/Classes/BetterPlayer.m b/ios/Classes/BetterPlayer.m index 822de3f4c..2837ef651 100644 --- a/ios/Classes/BetterPlayer.m +++ b/ios/Classes/BetterPlayer.m @@ -192,10 +192,10 @@ - (CGAffineTransform)fixTransform:(AVAssetTrack*)videoTrack { - (void)setDataSourceAsset:(NSString*)asset withKey:(NSString*)key withCertificateUrl:(NSString*)certificateUrl withLicenseUrl:(NSString*)licenseUrl cacheKey:(NSString*)cacheKey cacheManager:(CacheManager*)cacheManager overriddenDuration:(int) overriddenDuration{ NSString* path = [[NSBundle mainBundle] pathForResource:asset ofType:nil]; - return [self setDataSourceURL:[NSURL fileURLWithPath:path] withKey:key withCertificateUrl:certificateUrl withLicenseUrl:(NSString*)licenseUrl withHeaders: @{} withCache: false cacheKey:cacheKey cacheManager:cacheManager overriddenDuration:overriddenDuration]; + return [self setDataSourceURL:[NSURL fileURLWithPath:path] withKey:key withCertificateUrl:certificateUrl withLicenseUrl:(NSString*)licenseUrl withHeaders: @{} withCache: false cacheKey:cacheKey cacheManager:cacheManager overriddenDuration:overriddenDuration videoExtension: nil]; } -- (void)setDataSourceURL:(NSURL*)url withKey:(NSString*)key withCertificateUrl:(NSString*)certificateUrl withLicenseUrl:(NSString*)licenseUrl withHeaders:(NSDictionary*)headers withCache:(BOOL)useCache cacheKey:(NSString*)cacheKey cacheManager:(CacheManager*)cacheManager overriddenDuration:(int) overriddenDuration{ +- (void)setDataSourceURL:(NSURL*)url withKey:(NSString*)key withCertificateUrl:(NSString*)certificateUrl withLicenseUrl:(NSString*)licenseUrl withHeaders:(NSDictionary*)headers withCache:(BOOL)useCache cacheKey:(NSString*)cacheKey cacheManager:(CacheManager*)cacheManager overriddenDuration:(int) overriddenDuration videoExtension: (NSString*) videoExtension{ _overriddenDuration = 0; if (headers == [NSNull null] || headers == NULL){ headers = @{}; @@ -206,7 +206,11 @@ - (void)setDataSourceURL:(NSURL*)url withKey:(NSString*)key withCertificateUrl:( if (cacheKey == [NSNull null]){ cacheKey = nil; } - item = [cacheManager getCachingPlayerItemForNormalPlayback:url cacheKey:cacheKey headers:headers]; + if (videoExtension == [NSNull null]){ + videoExtension = nil; + } + + item = [cacheManager getCachingPlayerItemForNormalPlayback:url cacheKey:cacheKey videoExtension: videoExtension headers:headers]; } else { AVURLAsset* asset = [AVURLAsset URLAssetWithURL:url options:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers}]; diff --git a/ios/Classes/BetterPlayerPlugin.m b/ios/Classes/BetterPlayerPlugin.m index ae036a298..ed50403fa 100644 --- a/ios/Classes/BetterPlayerPlugin.m +++ b/ios/Classes/BetterPlayerPlugin.m @@ -309,6 +309,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSDictionary* headers = dataSource[@"headers"]; NSString* cacheKey = dataSource[@"cacheKey"]; NSNumber* maxCacheSize = dataSource[@"maxCacheSize"]; + NSString* videoExtension = dataSource[@"videoExtension"]; + int overriddenDuration = 0; if ([dataSource objectForKey:@"overriddenDuration"] != [NSNull null]){ overriddenDuration = [dataSource[@"overriddenDuration"] intValue]; @@ -337,7 +339,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } [player setDataSourceAsset:assetPath withKey:key withCertificateUrl:certificateUrl withLicenseUrl: licenseUrl cacheKey:cacheKey cacheManager:_cacheManager overriddenDuration:overriddenDuration]; } else if (uriArg) { - [player setDataSourceURL:[NSURL URLWithString:uriArg] withKey:key withCertificateUrl:certificateUrl withLicenseUrl: licenseUrl withHeaders:headers withCache: useCache cacheKey:cacheKey cacheManager:_cacheManager overriddenDuration:overriddenDuration]; + [player setDataSourceURL:[NSURL URLWithString:uriArg] withKey:key withCertificateUrl:certificateUrl withLicenseUrl: licenseUrl withHeaders:headers withCache: useCache cacheKey:cacheKey cacheManager:_cacheManager overriddenDuration:overriddenDuration videoExtension: videoExtension]; } else { result(FlutterMethodNotImplemented); } @@ -426,15 +428,20 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { NSString* cacheKey = dataSource[@"cacheKey"]; NSDictionary* headers = dataSource[@"headers"]; NSNumber* maxCacheSize = dataSource[@"maxCacheSize"]; + NSString* videoExtension = dataSource[@"videoExtension"]; + if (headers == [ NSNull null ]){ headers = @{}; } + if (videoExtension == [NSNull null]){ + videoExtension = nil; + } if (urlArg != [NSNull null]){ NSURL* url = [NSURL URLWithString:urlArg]; - if ([_cacheManager isPreCacheSupportedWithUrl:url]){ + if ([_cacheManager isPreCacheSupportedWithUrl:url videoExtension:videoExtension]){ [_cacheManager setMaxCacheSize:maxCacheSize]; - [_cacheManager preCacheURL:url cacheKey:cacheKey withHeaders:headers completionHandler:^(BOOL success){ + [_cacheManager preCacheURL:url cacheKey:cacheKey videoExtension:videoExtension withHeaders:headers completionHandler:^(BOOL success){ }]; } else { NSLog(@"Pre cache is not supported for given data source."); @@ -447,9 +454,10 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } else if ([@"stopPreCache" isEqualToString:call.method]){ NSString* urlArg = argsMap[@"url"]; NSString* cacheKey = argsMap[@"cacheKey"]; + NSString* videoExtension = argsMap[@"videoExtension"]; if (urlArg != [NSNull null]){ NSURL* url = [NSURL URLWithString:urlArg]; - if ([_cacheManager isPreCacheSupportedWithUrl:url]){ + if ([_cacheManager isPreCacheSupportedWithUrl:url videoExtension:videoExtension]){ [_cacheManager stopPreCache:url cacheKey:cacheKey completionHandler:^(BOOL success){ }]; diff --git a/ios/Classes/CacheManager.swift b/ios/Classes/CacheManager.swift index c6cb80c98..f6fafff96 100644 --- a/ios/Classes/CacheManager.swift +++ b/ios/Classes/CacheManager.swift @@ -53,13 +53,13 @@ import PINCache } // MARK: - Logic - @objc public func preCacheURL(_ url: URL, cacheKey: String?, withHeaders headers: Dictionary, completionHandler: ((_ success:Bool) -> Void)?) { + @objc public func preCacheURL(_ url: URL, cacheKey: String?, videoExtension: String?, withHeaders headers: Dictionary, completionHandler: ((_ success:Bool) -> Void)?) { self.completionHandler = completionHandler let _key: String = cacheKey ?? url.absoluteString // Make sure the item is not already being downloaded if self._preCachedURLs[_key] == nil { - if let item = self.getCachingPlayerItem(url, cacheKey: _key, headers: headers){ + if let item = self.getCachingPlayerItem(url, cacheKey: _key, videoExtension: videoExtension, headers: headers){ if !self._existsInStorage { self._preCachedURLs[_key] = item item.download() @@ -87,20 +87,20 @@ import PINCache } ///Gets caching player item for normal playback. - @objc public func getCachingPlayerItemForNormalPlayback(_ url: URL, cacheKey: String?, headers: Dictionary) -> AVPlayerItem? { - let mimeTypeResult = getMimeType(url:url) + @objc public func getCachingPlayerItemForNormalPlayback(_ url: URL, cacheKey: String?, videoExtension: String?, headers: Dictionary) -> AVPlayerItem? { + let mimeTypeResult = getMimeType(url:url, explicitVideoExtension: videoExtension) if (mimeTypeResult.1 == "application/vnd.apple.mpegurl"){ let reverseProxyURL = server?.reverseProxyURL(from: url)! let playerItem = AVPlayerItem(url: reverseProxyURL!) return playerItem } else { - return getCachingPlayerItem(url, cacheKey: cacheKey, headers: headers) + return getCachingPlayerItem(url, cacheKey: cacheKey, videoExtension: videoExtension, headers: headers) } } // Get a CachingPlayerItem either from the network if it's not cached or from the cache. - @objc public func getCachingPlayerItem(_ url: URL, cacheKey: String?, headers: Dictionary) -> CachingPlayerItem? { + @objc public func getCachingPlayerItem(_ url: URL, cacheKey: String?,videoExtension: String?, headers: Dictionary) -> CachingPlayerItem? { let playerItem: CachingPlayerItem let _key: String = cacheKey ?? url.absoluteString // Fetch ongoing pre-cached url if it exists @@ -113,7 +113,7 @@ import PINCache if data != nil { // The file is cached. self._existsInStorage = true - let mimeTypeResult = getMimeType(url:url) + let mimeTypeResult = getMimeType(url:url, explicitVideoExtension: videoExtension) if (mimeTypeResult.1.isEmpty){ NSLog("Cache error: couldn't find mime type for url: \(url.absoluteURL). For this URL cache didn't work and video will be played without cache.") playerItem = CachingPlayerItem(url: url, cacheKey: _key, headers: headers) @@ -136,8 +136,11 @@ import PINCache self._preCachedURLs = Dictionary() } - private func getMimeType(url: URL) -> (String,String){ - let videoExtension = url.pathExtension + private func getMimeType(url: URL, explicitVideoExtension: String?) -> (String,String){ + var videoExtension = url.pathExtension + if (explicitVideoExtension != nil){ + videoExtension = explicitVideoExtension! + } var mimeType = "" switch (videoExtension){ case "m3u": @@ -194,8 +197,8 @@ import PINCache } ///Checks wheter pre cache is supported for given url. - @objc public func isPreCacheSupported(url: URL) -> Bool{ - let mimeTypeResult = getMimeType(url:url) + @objc public func isPreCacheSupported(url: URL, videoExtension: String?) -> Bool{ + let mimeTypeResult = getMimeType(url:url, explicitVideoExtension: videoExtension) return !mimeTypeResult.1.isEmpty && mimeTypeResult.1 != "application/vnd.apple.mpegurl" } } diff --git a/lib/src/asms/better_player_asms_track.dart b/lib/src/asms/better_player_asms_track.dart index 57d07a4d5..0a11df79b 100644 --- a/lib/src/asms/better_player_asms_track.dart +++ b/lib/src/asms/better_player_asms_track.dart @@ -21,8 +21,15 @@ class BetterPlayerAsmsTrack { ///mimeType of the video track final String? mimeType; - BetterPlayerAsmsTrack(this.id, this.width, this.height, this.bitrate, - this.frameRate, this.codecs, this.mimeType); + BetterPlayerAsmsTrack( + this.id, + this.width, + this.height, + this.bitrate, + this.frameRate, + this.codecs, + this.mimeType, + ); factory BetterPlayerAsmsTrack.defaultTrack() { return BetterPlayerAsmsTrack('', 0, 0, 0, 0, '', ''); diff --git a/lib/src/asms/better_player_asms_utils.dart b/lib/src/asms/better_player_asms_utils.dart index a723cc3e2..6ccfa73db 100644 --- a/lib/src/asms/better_player_asms_utils.dart +++ b/lib/src/asms/better_player_asms_utils.dart @@ -1,11 +1,6 @@ -// Dart imports: import 'dart:convert'; import 'dart:io'; - -// Package imports: import 'package:better_player/src/core/better_player_utils.dart'; - -// Project imports: import 'package:better_player/src/dash/better_player_dash_utils.dart'; import 'package:better_player/src/hls/better_player_hls_utils.dart'; diff --git a/lib/src/configuration/better_player_configuration.dart b/lib/src/configuration/better_player_configuration.dart index a493f9a78..5eaf5c157 100644 --- a/lib/src/configuration/better_player_configuration.dart +++ b/lib/src/configuration/better_player_configuration.dart @@ -1,5 +1,3 @@ -// Flutter imports: -// Project imports: import 'package:better_player/better_player.dart'; import 'package:better_player/src/configuration/better_player_translations.dart'; import 'package:better_player/src/subtitles/better_player_subtitles_configuration.dart'; @@ -100,6 +98,10 @@ class BetterPlayerConfiguration { /// ignored. final bool autoDetectFullscreenDeviceOrientation; + ///Defines if player should auto detect full screen aspect ration of the video. + ///If [deviceOrientationsOnFullScreen] is true this is done automaticaly also. + final bool autoDetectFullscreenAspectRatio; + ///Defines flag which enables/disables lifecycle handling (pause on app closed, ///play on app resumed). Default value is true. final bool handleLifecycle; @@ -153,6 +155,7 @@ class BetterPlayerConfiguration { this.playerVisibilityChangedBehavior, this.translations, this.autoDetectFullscreenDeviceOrientation = false, + this.autoDetectFullscreenAspectRatio = false, this.handleLifecycle = true, this.autoDispose = true, this.expandToFill = true, diff --git a/lib/src/configuration/better_player_controls_configuration.dart b/lib/src/configuration/better_player_controls_configuration.dart index 85d923322..180a2ab67 100644 --- a/lib/src/configuration/better_player_controls_configuration.dart +++ b/lib/src/configuration/better_player_controls_configuration.dart @@ -1,10 +1,5 @@ -// Dart imports: import 'dart:ui'; - -// Flutter imports: import 'package:better_player/better_player.dart'; - -// Project imports: import 'package:better_player/src/controls/better_player_overflow_menu_item.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/src/configuration/better_player_data_source.dart b/lib/src/configuration/better_player_data_source.dart index b13c5bcb6..bccdfa4d7 100644 --- a/lib/src/configuration/better_player_data_source.dart +++ b/lib/src/configuration/better_player_data_source.dart @@ -1,5 +1,3 @@ -// Project imports: - import 'package:better_player/src/configuration/better_player_buffering_configuration.dart'; import 'package:better_player/src/configuration/better_player_data_source_type.dart'; import 'package:better_player/src/configuration/better_player_drm_configuration.dart'; @@ -62,7 +60,7 @@ class BetterPlayerDataSource { ///Video format hint when data source url has not valid extension. final BetterPlayerVideoFormat? videoFormat; - ///Extension of video without dot. Used only in memory data source. + ///Extension of video without dot. final String? videoExtension; ///Configuration of content protection diff --git a/lib/src/configuration/better_player_event.dart b/lib/src/configuration/better_player_event.dart index 9d22a82ae..19b1536f3 100644 --- a/lib/src/configuration/better_player_event.dart +++ b/lib/src/configuration/better_player_event.dart @@ -1,4 +1,3 @@ -// Project imports: import 'package:better_player/src/configuration/better_player_event_type.dart'; ///Event that happens in player. It can be used to determine current player state diff --git a/lib/src/configuration/better_player_event_type.dart b/lib/src/configuration/better_player_event_type.dart index e0c0e8bd4..1a7391f34 100644 --- a/lib/src/configuration/better_player_event_type.dart +++ b/lib/src/configuration/better_player_event_type.dart @@ -23,4 +23,5 @@ enum BetterPlayerEventType { bufferingStart, bufferingUpdate, bufferingEnd, + changedPlaylistItem, } diff --git a/lib/src/controls/better_player_controls_state.dart b/lib/src/controls/better_player_controls_state.dart index 3e1f92549..4991bbc04 100644 --- a/lib/src/controls/better_player_controls_state.dart +++ b/lib/src/controls/better_player_controls_state.dart @@ -1,16 +1,11 @@ -// Dart imports: import 'dart:io'; import 'dart:math'; - -// Project imports: import 'package:better_player/better_player.dart'; import 'package:better_player/src/asms/better_player_asms_audio_track.dart'; import 'package:better_player/src/asms/better_player_asms_track.dart'; import 'package:better_player/src/controls/better_player_clickable_widget.dart'; import 'package:better_player/src/core/better_player_utils.dart'; 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'; diff --git a/lib/src/controls/better_player_cupertino_controls.dart b/lib/src/controls/better_player_cupertino_controls.dart index c00186e48..4e67b83d1 100644 --- a/lib/src/controls/better_player_cupertino_controls.dart +++ b/lib/src/controls/better_player_cupertino_controls.dart @@ -1,19 +1,14 @@ -// Dart imports: import 'dart:async'; - -// 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'; - -// Project imports: import 'package:better_player/src/controls/better_player_controls_state.dart'; import 'package:better_player/src/controls/better_player_cupertino_progress_bar.dart'; +import 'package:better_player/src/controls/better_player_multiple_gesture_detector.dart'; import 'package:better_player/src/controls/better_player_progress_colors.dart'; import 'package:better_player/src/core/better_player_controller.dart'; import 'package:better_player/src/core/better_player_utils.dart'; import 'package:better_player/src/video_player/video_player.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; class BetterPlayerCupertinoControls extends StatefulWidget { ///Callback used to send information if player bar is hidden or not @@ -87,8 +82,27 @@ class _BetterPlayerCupertinoControlsState ? _controlsConfiguration.controlBarHeight : _controlsConfiguration.controlBarHeight + 10; const buttonPadding = 10.0; + final isFullScreen = _betterPlayerController?.isFullScreen == true; _wasLoading = isLoading(_latestValue); + final controlsColumn = Column(children: [ + _buildTopBar( + backgroundColor, + iconColor, + barHeight, + buttonPadding, + ), + if (_wasLoading) + Expanded(child: Center(child: _buildLoadingWidget())) + else + _buildHitArea(), + _buildNextVideoWidget(), + _buildBottomBar( + backgroundColor, + iconColor, + barHeight, + ), + ]); return GestureDetector( onTap: () { if (BetterPlayerMultipleGestureDetector.of(context) != null) { @@ -113,28 +127,9 @@ class _BetterPlayerCupertinoControlsState } }, child: AbsorbPointer( - absorbing: _hideStuff, - child: Column( - children: [ - _buildTopBar( - backgroundColor, - iconColor, - barHeight, - buttonPadding, - ), - if (_wasLoading) - Expanded(child: Center(child: _buildLoadingWidget())) - else - _buildHitArea(), - _buildNextVideoWidget(), - _buildBottomBar( - backgroundColor, - iconColor, - barHeight, - ), - ], - ), - ), + absorbing: _hideStuff, + child: + isFullScreen ? SafeArea(child: controlsColumn) : controlsColumn), ); } diff --git a/lib/src/controls/better_player_cupertino_progress_bar.dart b/lib/src/controls/better_player_cupertino_progress_bar.dart index a0158769c..d7a3f5f19 100644 --- a/lib/src/controls/better_player_cupertino_progress_bar.dart +++ b/lib/src/controls/better_player_cupertino_progress_bar.dart @@ -1,5 +1,4 @@ -// Flutter imports: -// Project imports: +import 'dart:async'; import 'package:better_player/src/controls/better_player_progress_colors.dart'; import 'package:better_player/src/core/better_player_controller.dart'; import 'package:better_player/src/video_player/video_player.dart'; @@ -48,6 +47,10 @@ class _VideoProgressBarState BetterPlayerController? get betterPlayerController => widget.betterPlayerController; + bool shouldPlayAfterDragEnd = false; + Duration? lastSeek; + Timer? _updateBlockTimer; + @override void initState() { super.initState(); @@ -57,30 +60,14 @@ class _VideoProgressBarState @override void deactivate() { controller!.removeListener(listener); + _cancelUpdateBlockTimer(); super.deactivate(); } @override Widget build(BuildContext context) { - void seekToRelativePosition(Offset globalPosition) { - final RenderObject? renderObject = context.findRenderObject(); - if (renderObject != null) { - final box = renderObject as RenderBox; - final Offset tapPos = box.globalToLocal(globalPosition); - final double relative = tapPos.dx / box.size.width; - if (relative > 0) { - final Duration position = controller!.value.duration! * relative; - controller!.seekTo(position); - } - if (relative >= 1) { - betterPlayerController!.seekTo(controller!.value.duration!); - } - } - } - final bool enableProgressBarDrag = betterPlayerController! .betterPlayerConfiguration.controlsConfiguration.enableProgressBarDrag; - return GestureDetector( onHorizontalDragStart: (DragStartDetails details) { if (!controller!.value.initialized || !enableProgressBarDrag) { @@ -109,10 +96,12 @@ class _VideoProgressBarState if (!enableProgressBarDrag) { return; } - if (_controllerWasPlaying) { - controller!.play(); + betterPlayerController?.play(); + shouldPlayAfterDragEnd = true; } + _setupUpdateBlockTimer(); + if (widget.onDragEnd != null) { widget.onDragEnd!(); } @@ -123,6 +112,7 @@ class _VideoProgressBarState } seekToRelativePosition(details.globalPosition); + _setupUpdateBlockTimer(); }, child: Center( child: Container( @@ -131,7 +121,7 @@ class _VideoProgressBarState color: Colors.transparent, child: CustomPaint( painter: _ProgressBarPainter( - controller!.value, + _getValue(), widget.colors, ), ), @@ -139,6 +129,53 @@ class _VideoProgressBarState ), ); } + + void _setupUpdateBlockTimer() { + _updateBlockTimer = Timer(const Duration(milliseconds: 1000), () { + lastSeek = null; + _cancelUpdateBlockTimer(); + }); + } + + void _cancelUpdateBlockTimer() { + _updateBlockTimer?.cancel(); + _updateBlockTimer = null; + } + + VideoPlayerValue _getValue() { + if (lastSeek != null) { + return controller!.value.copyWith(position: lastSeek); + } else { + return controller!.value; + } + } + + void seekToRelativePosition(Offset globalPosition) async { + final RenderObject? renderObject = context.findRenderObject(); + if (renderObject != null) { + final box = renderObject as RenderBox; + final Offset tapPos = box.globalToLocal(globalPosition); + final double relative = tapPos.dx / box.size.width; + if (relative > 0) { + final Duration position = controller!.value.duration! * relative; + lastSeek = position; + await betterPlayerController!.seekTo(position); + onFinishedLastSeek(); + if (relative >= 1) { + lastSeek = controller!.value.duration; + await betterPlayerController!.seekTo(controller!.value.duration!); + onFinishedLastSeek(); + } + } + } + } + + void onFinishedLastSeek() { + if (shouldPlayAfterDragEnd) { + shouldPlayAfterDragEnd = false; + betterPlayerController?.play(); + } + } } class _ProgressBarPainter extends CustomPainter { diff --git a/lib/src/controls/better_player_material_controls.dart b/lib/src/controls/better_player_material_controls.dart index 0000ab5f0..ce12034d5 100644 --- a/lib/src/controls/better_player_material_controls.dart +++ b/lib/src/controls/better_player_material_controls.dart @@ -1,7 +1,4 @@ -// Dart imports: import 'dart:async'; - -// Project imports: import 'package:better_player/src/configuration/better_player_controls_configuration.dart'; import 'package:better_player/src/controls/better_player_clickable_widget.dart'; import 'package:better_player/src/controls/better_player_controls_state.dart'; diff --git a/lib/src/controls/better_player_material_progress_bar.dart b/lib/src/controls/better_player_material_progress_bar.dart index 3f0012462..fcc066b53 100644 --- a/lib/src/controls/better_player_material_progress_bar.dart +++ b/lib/src/controls/better_player_material_progress_bar.dart @@ -1,5 +1,4 @@ -// Flutter imports: -// Project imports: +import 'dart:async'; import 'package:better_player/better_player.dart'; import 'package:better_player/src/controls/better_player_progress_colors.dart'; import 'package:better_player/src/video_player/video_player.dart'; @@ -48,6 +47,10 @@ class _VideoProgressBarState BetterPlayerController? get betterPlayerController => widget.betterPlayerController; + bool shouldPlayAfterDragEnd = false; + Duration? lastSeek; + Timer? _updateBlockTimer; + @override void initState() { super.initState(); @@ -57,27 +60,12 @@ class _VideoProgressBarState @override void deactivate() { controller!.removeListener(listener); + _cancelUpdateBlockTimer(); super.deactivate(); } @override Widget build(BuildContext context) { - void seekToRelativePosition(Offset globalPosition) { - final RenderObject? renderObject = context.findRenderObject(); - if (renderObject != null) { - final box = renderObject as RenderBox; - final Offset tapPos = box.globalToLocal(globalPosition); - final double relative = tapPos.dx / box.size.width; - if (relative > 0) { - final Duration position = controller!.value.duration! * relative; - betterPlayerController!.seekTo(position); - } - if (relative >= 1) { - betterPlayerController!.seekTo(controller!.value.duration!); - } - } - } - final bool enableProgressBarDrag = betterPlayerController! .betterPlayerConfiguration.controlsConfiguration.enableProgressBarDrag; @@ -113,8 +101,10 @@ class _VideoProgressBarState } if (_controllerWasPlaying) { - controller!.play(); + betterPlayerController?.play(); + shouldPlayAfterDragEnd = true; } + _setupUpdateBlockTimer(); if (widget.onDragEnd != null) { widget.onDragEnd!(); @@ -125,6 +115,7 @@ class _VideoProgressBarState return; } seekToRelativePosition(details.globalPosition); + _setupUpdateBlockTimer(); }, child: Center( child: Container( @@ -133,7 +124,7 @@ class _VideoProgressBarState color: Colors.transparent, child: CustomPaint( painter: _ProgressBarPainter( - controller!.value, + _getValue(), widget.colors, ), ), @@ -141,6 +132,53 @@ class _VideoProgressBarState ), ); } + + void _setupUpdateBlockTimer() { + _updateBlockTimer = Timer(const Duration(milliseconds: 1000), () { + lastSeek = null; + _cancelUpdateBlockTimer(); + }); + } + + void _cancelUpdateBlockTimer() { + _updateBlockTimer?.cancel(); + _updateBlockTimer = null; + } + + VideoPlayerValue _getValue() { + if (lastSeek != null) { + return controller!.value.copyWith(position: lastSeek); + } else { + return controller!.value; + } + } + + void seekToRelativePosition(Offset globalPosition) async { + final RenderObject? renderObject = context.findRenderObject(); + if (renderObject != null) { + final box = renderObject as RenderBox; + final Offset tapPos = box.globalToLocal(globalPosition); + final double relative = tapPos.dx / box.size.width; + if (relative > 0) { + final Duration position = controller!.value.duration! * relative; + lastSeek = position; + await betterPlayerController!.seekTo(position); + onFinishedLastSeek(); + if (relative >= 1) { + lastSeek = controller!.value.duration; + await betterPlayerController!.seekTo(controller!.value.duration!); + onFinishedLastSeek(); + } + } + } + } + + void onFinishedLastSeek() { + if (shouldPlayAfterDragEnd) { + shouldPlayAfterDragEnd = false; + betterPlayerController?.play(); + } + } } class _ProgressBarPainter extends CustomPainter { diff --git a/lib/src/core/better_player.dart b/lib/src/core/better_player.dart index e7c31fa00..3f6b081e0 100644 --- a/lib/src/core/better_player.dart +++ b/lib/src/core/better_player.dart @@ -1,18 +1,11 @@ -// Dart imports: import 'dart:async'; - -// Project imports: import 'package:better_player/better_player.dart'; import 'package:better_player/src/configuration/better_player_controller_event.dart'; import 'package:better_player/src/core/better_player_utils.dart'; import 'package:better_player/src/core/better_player_with_controls.dart'; - -// Flutter imports: import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; - -// Package imports: import 'package:visibility_detector/visibility_detector.dart'; import 'package:wakelock/wakelock.dart'; diff --git a/lib/src/core/better_player_controller.dart b/lib/src/core/better_player_controller.dart index 6bb7e0c65..a34dd4b7d 100644 --- a/lib/src/core/better_player_controller.dart +++ b/lib/src/core/better_player_controller.dart @@ -1,8 +1,5 @@ -// Dart imports: import 'dart:async'; import 'dart:io'; - -// Project imports: import 'package:better_player/better_player.dart'; import 'package:better_player/src/asms/better_player_asms_audio_track.dart'; import 'package:better_player/src/asms/better_player_asms_data_holder.dart'; @@ -17,8 +14,6 @@ import 'package:better_player/src/configuration/better_player_event_type.dart'; import 'package:better_player/src/configuration/better_player_translations.dart'; import 'package:better_player/src/configuration/better_player_video_format.dart'; import 'package:better_player/src/core/better_player_controller_provider.dart'; - -// Flutter imports: import 'package:better_player/src/core/better_player_utils.dart'; import 'package:better_player/src/subtitles/better_player_subtitle.dart'; import 'package:better_player/src/subtitles/better_player_subtitles_factory.dart'; @@ -26,8 +21,6 @@ import 'package:better_player/src/video_player/video_player.dart'; import 'package:better_player/src/video_player/video_player_platform_interface.dart'; import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/material.dart'; - -// Package imports: import 'package:path_provider/path_provider.dart'; ///Class used to control overall Better Player behavior. Main class to change @@ -248,6 +241,7 @@ class BetterPlayerController { _hasCurrentDataSourceStarted = false; _hasCurrentDataSourceInitialized = false; _betterPlayerDataSource = betterPlayerDataSource; + _betterPlayerSubtitlesSourceList.clear(); ///Build videoPlayerController if null if (videoPlayerController == null) { @@ -448,33 +442,35 @@ class BetterPlayerController { switch (betterPlayerDataSource.type) { case BetterPlayerDataSourceType.network: await videoPlayerController?.setNetworkDataSource( - betterPlayerDataSource.url, - headers: _getHeaders(), - useCache: - _betterPlayerDataSource!.cacheConfiguration?.useCache ?? false, - maxCacheSize: - _betterPlayerDataSource!.cacheConfiguration?.maxCacheSize ?? 0, - maxCacheFileSize: - _betterPlayerDataSource!.cacheConfiguration?.maxCacheFileSize ?? - 0, - cacheKey: _betterPlayerDataSource?.cacheConfiguration?.key, - showNotification: _betterPlayerDataSource - ?.notificationConfiguration?.showNotification, - title: _betterPlayerDataSource?.notificationConfiguration?.title, - author: _betterPlayerDataSource?.notificationConfiguration?.author, - imageUrl: - _betterPlayerDataSource?.notificationConfiguration?.imageUrl, - notificationChannelName: _betterPlayerDataSource - ?.notificationConfiguration?.notificationChannelName, - overriddenDuration: _betterPlayerDataSource!.overriddenDuration, - formatHint: _getVideoFormat(_betterPlayerDataSource!.videoFormat), - licenseUrl: _betterPlayerDataSource?.drmConfiguration?.licenseUrl, - certificateUrl: - _betterPlayerDataSource?.drmConfiguration?.certificateUrl, - drmHeaders: _betterPlayerDataSource?.drmConfiguration?.headers, - activityName: _betterPlayerDataSource - ?.notificationConfiguration?.activityName, - clearKey: _betterPlayerDataSource?.drmConfiguration?.clearKey); + betterPlayerDataSource.url, + headers: _getHeaders(), + useCache: + _betterPlayerDataSource!.cacheConfiguration?.useCache ?? false, + maxCacheSize: + _betterPlayerDataSource!.cacheConfiguration?.maxCacheSize ?? 0, + maxCacheFileSize: + _betterPlayerDataSource!.cacheConfiguration?.maxCacheFileSize ?? + 0, + cacheKey: _betterPlayerDataSource?.cacheConfiguration?.key, + showNotification: _betterPlayerDataSource + ?.notificationConfiguration?.showNotification, + title: _betterPlayerDataSource?.notificationConfiguration?.title, + author: _betterPlayerDataSource?.notificationConfiguration?.author, + imageUrl: + _betterPlayerDataSource?.notificationConfiguration?.imageUrl, + notificationChannelName: _betterPlayerDataSource + ?.notificationConfiguration?.notificationChannelName, + overriddenDuration: _betterPlayerDataSource!.overriddenDuration, + formatHint: _getVideoFormat(_betterPlayerDataSource!.videoFormat), + licenseUrl: _betterPlayerDataSource?.drmConfiguration?.licenseUrl, + certificateUrl: + _betterPlayerDataSource?.drmConfiguration?.certificateUrl, + drmHeaders: _betterPlayerDataSource?.drmConfiguration?.headers, + activityName: + _betterPlayerDataSource?.notificationConfiguration?.activityName, + clearKey: _betterPlayerDataSource?.drmConfiguration?.clearKey, + videoExtension: _betterPlayerDataSource!.videoExtension, + ); break; case BetterPlayerDataSourceType.file: @@ -889,6 +885,7 @@ class BetterPlayerController { void playNextVideo() { _nextVideoTime = 0; _nextVideoTimeStreamController.add(_nextVideoTime); + _postEvent(BetterPlayerEvent(BetterPlayerEventType.changedPlaylistItem)); cancelNextVideoTimer(); } @@ -898,7 +895,16 @@ class BetterPlayerController { if (videoPlayerController == null) { throw StateError("The data source has not been initialized"); } - _postEvent(BetterPlayerEvent(BetterPlayerEventType.changedTrack)); + _postEvent(BetterPlayerEvent(BetterPlayerEventType.changedTrack, + parameters: { + "id": track.id, + "width": track.width, + "height": track.height, + "bitrate": track.bitrate, + "frameRate": track.frameRate, + "codecs": track.codecs, + "mimeType": track.mimeType, + })); videoPlayerController! .setTrackParameters(track.width, track.height, track.bitrate); @@ -956,7 +962,10 @@ class BetterPlayerController { if (wasPlayingBeforeChange) { play(); } - _postEvent(BetterPlayerEvent(BetterPlayerEventType.changedResolution)); + _postEvent(BetterPlayerEvent( + BetterPlayerEventType.changedResolution, + parameters: {"url": url}, + )); } ///Setup translations for given locale. In normal use cases it shouldn't be @@ -1228,6 +1237,7 @@ class BetterPlayerController { maxCacheSize: cacheConfig.maxCacheSize, maxCacheFileSize: cacheConfig.maxCacheFileSize, cacheKey: cacheConfig.key, + videoExtension: betterPlayerDataSource.videoExtension, ); return VideoPlayerController.preCache(dataSource, cacheConfig.preCacheSize); diff --git a/lib/src/core/better_player_controller_provider.dart b/lib/src/core/better_player_controller_provider.dart index 31b3a9d6a..903b5b54d 100644 --- a/lib/src/core/better_player_controller_provider.dart +++ b/lib/src/core/better_player_controller_provider.dart @@ -1,5 +1,3 @@ -// Flutter imports: -// Project imports: import 'package:better_player/src/core/better_player_controller.dart'; import 'package:flutter/material.dart'; diff --git a/lib/src/core/better_player_with_controls.dart b/lib/src/core/better_player_with_controls.dart index 506cbb76f..669ad75f9 100644 --- a/lib/src/core/better_player_with_controls.dart +++ b/lib/src/core/better_player_with_controls.dart @@ -1,15 +1,8 @@ -// Dart imports: import 'dart:async'; import 'dart:io'; import 'dart:math'; - -// Flutter imports: -import 'package:better_player/src/configuration/better_player_controller_event.dart'; -import 'package:flutter/material.dart'; - -// Project imports: import 'package:better_player/better_player.dart'; - +import 'package:better_player/src/configuration/better_player_controller_event.dart'; import 'package:better_player/src/controls/better_player_cupertino_controls.dart'; import 'package:better_player/src/controls/better_player_material_controls.dart'; import 'package:better_player/src/core/better_player_controller.dart'; @@ -17,6 +10,7 @@ import 'package:better_player/src/core/better_player_utils.dart'; import 'package:better_player/src/subtitles/better_player_subtitles_configuration.dart'; import 'package:better_player/src/subtitles/better_player_subtitles_drawer.dart'; import 'package:better_player/src/video_player/video_player.dart'; +import 'package:flutter/material.dart'; class BetterPlayerWithControls extends StatefulWidget { final BetterPlayerController? controller; @@ -82,8 +76,10 @@ class _BetterPlayerWithControlsState extends State { double? aspectRatio; if (betterPlayerController.isFullScreen) { - if (betterPlayerController - .betterPlayerConfiguration.autoDetectFullscreenDeviceOrientation) { + if (betterPlayerController.betterPlayerConfiguration + .autoDetectFullscreenDeviceOrientation || + betterPlayerController + .betterPlayerConfiguration.autoDetectFullscreenAspectRatio) { aspectRatio = betterPlayerController.videoPlayerController?.value.aspectRatio ?? 1.0; diff --git a/lib/src/dash/better_player_dash_utils.dart b/lib/src/dash/better_player_dash_utils.dart index 9d7f74fd7..c137599c7 100644 --- a/lib/src/dash/better_player_dash_utils.dart +++ b/lib/src/dash/better_player_dash_utils.dart @@ -1,14 +1,11 @@ -// External Package imports: +import 'package:better_player/src/asms/better_player_asms_audio_track.dart'; import 'package:better_player/src/asms/better_player_asms_data_holder.dart'; +import 'package:better_player/src/asms/better_player_asms_subtitle.dart'; +import 'package:better_player/src/asms/better_player_asms_track.dart'; import 'package:better_player/src/core/better_player_utils.dart'; import 'package:better_player/src/hls/hls_parser/mime_types.dart'; import 'package:xml/xml.dart'; -// Project imports: -import 'package:better_player/src/asms/better_player_asms_audio_track.dart'; -import 'package:better_player/src/asms/better_player_asms_subtitle.dart'; -import 'package:better_player/src/asms/better_player_asms_track.dart'; - ///DASH helper class class BetterPlayerDashUtils { static Future parse( diff --git a/lib/src/hls/better_player_hls_utils.dart b/lib/src/hls/better_player_hls_utils.dart index b44e77d88..8d5ad8593 100644 --- a/lib/src/hls/better_player_hls_utils.dart +++ b/lib/src/hls/better_player_hls_utils.dart @@ -1,13 +1,10 @@ -// Package imports: import 'package:better_player/src/asms/better_player_asms_audio_track.dart'; import 'package:better_player/src/asms/better_player_asms_data_holder.dart'; import 'package:better_player/src/asms/better_player_asms_subtitle.dart'; import 'package:better_player/src/asms/better_player_asms_subtitle_segment.dart'; +import 'package:better_player/src/asms/better_player_asms_track.dart'; import 'package:better_player/src/asms/better_player_asms_utils.dart'; import 'package:better_player/src/core/better_player_utils.dart'; - -// Project imports: -import 'package:better_player/src/asms/better_player_asms_track.dart'; import 'package:better_player/src/hls/hls_parser/hls_master_playlist.dart'; import 'package:better_player/src/hls/hls_parser/hls_media_playlist.dart'; import 'package:better_player/src/hls/hls_parser/hls_playlist_parser.dart'; diff --git a/lib/src/hls/hls_parser/util.dart b/lib/src/hls/hls_parser/util.dart index d2fe2938f..8f3aa025f 100644 --- a/lib/src/hls/hls_parser/util.dart +++ b/lib/src/hls/hls_parser/util.dart @@ -128,10 +128,11 @@ class Util { : codecs!.trim().split(RegExp('(\\s*,\\s*)')); static bool checkBitPositionIsSet(int number, int bitPosition) { - if ((number & (1 << (bitPosition - 1))) > 0) + if ((number & (1 << (bitPosition - 1))) > 0) { return true; - else + } else { return false; + } } } diff --git a/lib/src/list/better_player_list_video_player.dart b/lib/src/list/better_player_list_video_player.dart index 884eb9e89..590ca4697 100644 --- a/lib/src/list/better_player_list_video_player.dart +++ b/lib/src/list/better_player_list_video_player.dart @@ -1,5 +1,3 @@ -// Flutter imports: -// Project imports: import 'package:better_player/better_player.dart'; import 'package:better_player/src/configuration/better_player_configuration.dart'; import 'package:better_player/src/configuration/better_player_data_source.dart'; diff --git a/lib/src/list/better_player_list_video_player_controller.dart b/lib/src/list/better_player_list_video_player_controller.dart index efd83ecaf..e26e804d0 100644 --- a/lib/src/list/better_player_list_video_player_controller.dart +++ b/lib/src/list/better_player_list_video_player_controller.dart @@ -1,4 +1,3 @@ -// Project imports: import 'package:better_player/better_player.dart'; ///Controller of Better Player List Video Player. diff --git a/lib/src/playlist/better_player_playlist.dart b/lib/src/playlist/better_player_playlist.dart index 2f08d1719..4a2671ea8 100644 --- a/lib/src/playlist/better_player_playlist.dart +++ b/lib/src/playlist/better_player_playlist.dart @@ -1,4 +1,3 @@ -// Project imports: import 'package:better_player/better_player.dart'; import 'package:better_player/src/configuration/better_player_configuration.dart'; import 'package:better_player/src/configuration/better_player_data_source.dart'; diff --git a/lib/src/subtitles/better_player_subtitles_drawer.dart b/lib/src/subtitles/better_player_subtitles_drawer.dart index 57122876d..66226ede4 100644 --- a/lib/src/subtitles/better_player_subtitles_drawer.dart +++ b/lib/src/subtitles/better_player_subtitles_drawer.dart @@ -1,16 +1,9 @@ -// Dart imports: import 'dart:async'; - -// Project imports: import 'package:better_player/better_player.dart'; import 'package:better_player/src/subtitles/better_player_subtitle.dart'; import 'package:better_player/src/subtitles/better_player_subtitles_configuration.dart'; import 'package:better_player/src/video_player/video_player.dart'; - -// Flutter imports: import 'package:flutter/material.dart'; - -// Package imports: import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; class BetterPlayerSubtitlesDrawer extends StatefulWidget { diff --git a/lib/src/subtitles/better_player_subtitles_factory.dart b/lib/src/subtitles/better_player_subtitles_factory.dart index c9fa829f9..868df68c1 100644 --- a/lib/src/subtitles/better_player_subtitles_factory.dart +++ b/lib/src/subtitles/better_player_subtitles_factory.dart @@ -1,12 +1,8 @@ -// Dart imports: import 'dart:convert'; import 'dart:io'; - -// Project imports: import 'package:better_player/better_player.dart'; import 'package:better_player/src/core/better_player_utils.dart'; import 'package:better_player/src/subtitles/better_player_subtitles_source.dart'; - import 'better_player_subtitle.dart'; import 'better_player_subtitles_source_type.dart'; diff --git a/lib/src/subtitles/better_player_subtitles_source.dart b/lib/src/subtitles/better_player_subtitles_source.dart index 54d8c3446..2e6b6a018 100644 --- a/lib/src/subtitles/better_player_subtitles_source.dart +++ b/lib/src/subtitles/better_player_subtitles_source.dart @@ -1,4 +1,3 @@ -// Project imports: import 'package:better_player/src/asms/better_player_asms_subtitle_segment.dart'; import 'better_player_subtitles_source_type.dart'; diff --git a/lib/src/video_player/method_channel_video_player.dart b/lib/src/video_player/method_channel_video_player.dart index ea8f5f06c..0f70fc21a 100644 --- a/lib/src/video_player/method_channel_video_player.dart +++ b/lib/src/video_player/method_channel_video_player.dart @@ -1,20 +1,13 @@ // Copyright 2017 The Chromium Authors. All rights reserved. -// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - -// Dart imports: import 'dart:async'; import 'dart:ui'; - -// Flutter imports: import 'package:better_player/src/configuration/better_player_buffering_configuration.dart'; import 'package:better_player/src/core/better_player_utils.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; - -// Project imports: import 'video_player_platform_interface.dart'; const MethodChannel _channel = MethodChannel('better_player_channel'); @@ -101,7 +94,8 @@ class MethodChannelVideoPlayer extends VideoPlayerPlatform { 'certificateUrl': dataSource.certificateUrl, 'drmHeaders': dataSource.drmHeaders, 'activityName': dataSource.activityName, - 'clearKey': dataSource.clearKey + 'clearKey': dataSource.clearKey, + 'videoExtension': dataSource.videoExtension, }; break; case DataSourceType.file: @@ -306,6 +300,7 @@ class MethodChannelVideoPlayer extends VideoPlayerPlatform { 'maxCacheFileSize': dataSource.maxCacheFileSize, 'preCacheSize': preCacheSize, 'cacheKey': dataSource.cacheKey, + 'videoExtension': dataSource.videoExtension, }; return _channel.invokeMethod( 'preCache', diff --git a/lib/src/video_player/video_player.dart b/lib/src/video_player/video_player.dart index 03e3ad501..ee161c315 100644 --- a/lib/src/video_player/video_player.dart +++ b/lib/src/video_player/video_player.dart @@ -5,17 +5,11 @@ // Dart imports: import 'dart:async'; import 'dart:io'; - -// Project imports: import 'package:better_player/src/configuration/better_player_buffering_configuration.dart'; import 'package:better_player/src/video_player/video_player_platform_interface.dart'; - -// Flutter imports: import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; - -// Package imports: import 'package:meta/meta.dart'; import 'package:pedantic/pedantic.dart'; @@ -324,45 +318,50 @@ class VideoPlayerController extends ValueNotifier { /// **Android only**: The [formatHint] option allows the caller to override /// the video format detection code. /// ClearKey DRM only supported on Android. - Future setNetworkDataSource(String dataSource, - {VideoFormat? formatHint, - Map? headers, - bool useCache = false, - int? maxCacheSize, - int? maxCacheFileSize, - String? cacheKey, - bool? showNotification, - String? title, - String? author, - String? imageUrl, - String? notificationChannelName, - Duration? overriddenDuration, - String? licenseUrl, - String? certificateUrl, - Map? drmHeaders, - String? activityName, - String? clearKey}) { + Future setNetworkDataSource( + String dataSource, { + VideoFormat? formatHint, + Map? headers, + bool useCache = false, + int? maxCacheSize, + int? maxCacheFileSize, + String? cacheKey, + bool? showNotification, + String? title, + String? author, + String? imageUrl, + String? notificationChannelName, + Duration? overriddenDuration, + String? licenseUrl, + String? certificateUrl, + Map? drmHeaders, + String? activityName, + String? clearKey, + String? videoExtension, + }) { return _setDataSource( DataSource( - sourceType: DataSourceType.network, - uri: dataSource, - formatHint: formatHint, - headers: headers, - useCache: useCache, - maxCacheSize: maxCacheSize, - maxCacheFileSize: maxCacheFileSize, - cacheKey: cacheKey, - showNotification: showNotification, - title: title, - author: author, - imageUrl: imageUrl, - notificationChannelName: notificationChannelName, - overriddenDuration: overriddenDuration, - licenseUrl: licenseUrl, - certificateUrl: certificateUrl, - drmHeaders: drmHeaders, - activityName: activityName, - clearKey: clearKey), + sourceType: DataSourceType.network, + uri: dataSource, + formatHint: formatHint, + headers: headers, + useCache: useCache, + maxCacheSize: maxCacheSize, + maxCacheFileSize: maxCacheFileSize, + cacheKey: cacheKey, + showNotification: showNotification, + title: title, + author: author, + imageUrl: imageUrl, + notificationChannelName: notificationChannelName, + overriddenDuration: overriddenDuration, + licenseUrl: licenseUrl, + certificateUrl: certificateUrl, + drmHeaders: drmHeaders, + activityName: activityName, + clearKey: clearKey, + videoExtension: videoExtension, + ), ); } diff --git a/lib/src/video_player/video_player_platform_interface.dart b/lib/src/video_player/video_player_platform_interface.dart index 060770884..7e3a07b5a 100644 --- a/lib/src/video_player/video_player_platform_interface.dart +++ b/lib/src/video_player/video_player_platform_interface.dart @@ -179,7 +179,7 @@ abstract class VideoPlayerPlatform { // This method makes sure that VideoPlayer isn't implemented with `implements`. // - // See class doc for more details on why implementing this class is forbidden. + // See class docs for more details on why implementing this class is forbidden. // // This private method is called by the instance setter, which fails if the class is // implemented with `implements`. @@ -209,29 +209,30 @@ class DataSource { /// The [package] argument must be non-null when the asset comes from a /// package and null otherwise. /// - DataSource( - {required this.sourceType, - this.uri, - this.formatHint, - this.asset, - this.package, - this.headers, - this.useCache = false, - this.maxCacheSize = _maxCacheSize, - this.maxCacheFileSize = _maxCacheFileSize, - this.cacheKey, - this.showNotification = false, - this.title, - this.author, - this.imageUrl, - this.notificationChannelName, - this.overriddenDuration, - this.licenseUrl, - this.certificateUrl, - this.drmHeaders, - this.activityName, - this.clearKey}) - : assert(uri == null || asset == null); + DataSource({ + required this.sourceType, + this.uri, + this.formatHint, + this.asset, + this.package, + this.headers, + this.useCache = false, + this.maxCacheSize = _maxCacheSize, + this.maxCacheFileSize = _maxCacheFileSize, + this.cacheKey, + this.showNotification = false, + this.title, + this.author, + this.imageUrl, + this.notificationChannelName, + this.overriddenDuration, + this.licenseUrl, + this.certificateUrl, + this.drmHeaders, + this.activityName, + this.clearKey, + this.videoExtension, + }) : assert(uri == null || asset == null); /// Describes the type of data source this [VideoPlayerController] /// is constructed with. @@ -307,6 +308,8 @@ class DataSource { final String? clearKey; + final String? videoExtension; + /// Key to compare DataSource String get key { String? result = ""; diff --git a/media/1.png b/media/1.png index b75624305..faa733630 100644 Binary files a/media/1.png and b/media/1.png differ diff --git a/media/10.png b/media/10.png index 7b04a05ed..39999f53f 100644 Binary files a/media/10.png and b/media/10.png differ diff --git a/media/11.png b/media/11.png index 3abab099b..79196ce52 100644 Binary files a/media/11.png and b/media/11.png differ diff --git a/media/12.png b/media/12.png index f5a0819dd..47803a755 100644 Binary files a/media/12.png and b/media/12.png differ diff --git a/media/13.png b/media/13.png index 5a9b19d66..11b140ca0 100644 Binary files a/media/13.png and b/media/13.png differ diff --git a/media/14.png b/media/14.png index 78466ba22..0d2647191 100644 Binary files a/media/14.png and b/media/14.png differ diff --git a/media/2.png b/media/2.png index 65970bec8..3e62a8761 100644 Binary files a/media/2.png and b/media/2.png differ diff --git a/media/3.png b/media/3.png index 83bb5d697..f34a0853c 100644 Binary files a/media/3.png and b/media/3.png differ diff --git a/media/4.png b/media/4.png index eee4ce351..1e5037e8d 100644 Binary files a/media/4.png and b/media/4.png differ diff --git a/media/5.png b/media/5.png index 639845868..bdca9707c 100644 Binary files a/media/5.png and b/media/5.png differ diff --git a/media/6.png b/media/6.png index 0e4e7fd8d..30c1a9ae0 100644 Binary files a/media/6.png and b/media/6.png differ diff --git a/media/7.png b/media/7.png index d2743fd04..a1dae923c 100644 Binary files a/media/7.png and b/media/7.png differ diff --git a/media/8.png b/media/8.png index 7a5b6e652..91b6d88c4 100644 Binary files a/media/8.png and b/media/8.png differ diff --git a/media/9.png b/media/9.png index 776b1f606..ae75867ee 100644 Binary files a/media/9.png and b/media/9.png differ diff --git a/pubspec.yaml b/pubspec.yaml index 951507ed1..71bae4471 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: better_player description: Advanced video player based on video_player and Chewie. It's solves many typical use cases and it's easy to run. -version: 0.0.76 +version: 0.0.77 # Disabled because of warning from analyzer # authors: # - Jakub Homlala @@ -9,7 +9,7 @@ documentation: https://jhomlala.github.io/betterplayer/ environment: sdk: '>=2.12.0 <3.0.0' - flutter: ">=1.10.0" + flutter: ">=2.2.3" dependencies: flutter: diff --git a/test/better_player_controller_test.dart b/test/better_player_controller_test.dart index 285148df5..815621618 100644 --- a/test/better_player_controller_test.dart +++ b/test/better_player_controller_test.dart @@ -7,7 +7,7 @@ import 'mock_video_player_controller.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - MockMethodChannel mockMethodChannel = MockMethodChannel(); + final MockMethodChannel mockMethodChannel = MockMethodChannel(); group( "BetterPlayerController tests", diff --git a/test/mock_method_channel.dart b/test/mock_method_channel.dart index 2644e923b..c8b01865c 100644 --- a/test/mock_method_channel.dart +++ b/test/mock_method_channel.dart @@ -6,7 +6,6 @@ class MockMethodChannel { final List eventsChannels = []; Future? handle(MethodCall methodCall) async { - print("Handle: " + methodCall.toString()); if (methodCall.method == "create") { final int id = getNextId(); _createEventChannel(id); diff --git a/test/mock_video_player_controller.dart b/test/mock_video_player_controller.dart index 18bf88436..b9bceebab 100644 --- a/test/mock_video_player_controller.dart +++ b/test/mock_video_player_controller.dart @@ -54,22 +54,25 @@ class MockVideoPlayerController extends VideoPlayerController { } @override - Future setNetworkDataSource(String dataSource, - {VideoFormat? formatHint, - Map? headers, - bool useCache = false, - int? maxCacheSize, - int? maxCacheFileSize, - String? cacheKey, - bool? showNotification, - String? title, - String? author, - String? imageUrl, - String? notificationChannelName, - Duration? overriddenDuration, - String? licenseUrl, - String? certificateUrl, - Map? drmHeaders, - String? activityName, - String? clearKey}) async {} + Future setNetworkDataSource( + String dataSource, { + VideoFormat? formatHint, + Map? headers, + bool useCache = false, + int? maxCacheSize, + int? maxCacheFileSize, + String? cacheKey, + bool? showNotification, + String? title, + String? author, + String? imageUrl, + String? notificationChannelName, + Duration? overriddenDuration, + String? licenseUrl, + String? certificateUrl, + Map? drmHeaders, + String? activityName, + String? clearKey, + String? videoExtension, + }) async {} }