From ee60e7b4ce3259b2a266a5827819cd5aa92ca521 Mon Sep 17 00:00:00 2001 From: Kiryl Ivonchyk <32823028+KirillSergeevich@users.noreply.github.com> Date: Fri, 31 Mar 2023 10:51:25 +0200 Subject: [PATCH] 0.1.5 (#9) * add possibility to set player volume * fix method call * add possibility to toggle gyroscope on android * fix android toggle gyro method * fix possibility to toggle gyroscope on Android * edit gyroscope toggling on Android * fixed key in vr player to share state * temporary removed toggling gyroscope, and fixed ios volume setting * minor updates, volume slider * readme update * preparing for publishing * formatting issues resolved --------- Co-authored-by: Max <124910445+maksim-work@users.noreply.github.com> Co-authored-by: Oleksandr Lukianov Co-authored-by: Alex Lukianov <99486519+Dethkrist@users.noreply.github.com> --- CHANGELOG.md | 3 + README.md | 1 + .../vr_player/VideoPlayerController.kt | 16 ++-- example/lib/main.dart | 92 ++++++++++++++++--- ios/Classes/PlayerFlutterView.swift | 9 ++ lib/vr_player.dart | 11 ++- pubspec.yaml | 2 +- 7 files changed, 112 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0041164..95ac2d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.1.5 +setVolume() method added. Player volume slider added. + ## 0.1.4 Fix issue [#1](https://github.com/What-the-Flutter/VR-Player/issues/1) diff --git a/README.md b/README.md index fa42c34..b4255a7 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ The `VrPlayerController` can be used to change the state of a `VrPlayer` Note t `play()` | Play video. `pause()` | Pause video. `seekTo()` | Seek to position. +`setVolume()` | Set video volume level from 0 (no sound) to 1 (max). `fullScreen()` | *(Android only)* Enable/disable fullscreen mode. On IOS you need to pass new width and height to VrPlayer widget `toggleVRMode()` | Switch between 360° mode and VR mode. `onSizeChanged()` | *(Android only)* Reload player when you need to change size of nativeView. diff --git a/android/src/main/kotlin/wtf/flutter/vr_player/VideoPlayerController.kt b/android/src/main/kotlin/wtf/flutter/vr_player/VideoPlayerController.kt index fd64397..075a2f4 100644 --- a/android/src/main/kotlin/wtf/flutter/vr_player/VideoPlayerController.kt +++ b/android/src/main/kotlin/wtf/flutter/vr_player/VideoPlayerController.kt @@ -101,6 +101,10 @@ class VideoPlayerController( } } } + "setVolume" -> { + val volume: Float = methodCall.argument("volume")!! + player?.setVolume(volume) + } "play" -> { player?.play() result.success(true) @@ -112,6 +116,7 @@ class VideoPlayerController( "isPlaying" -> { result.success(player?.isPlaying == true) } + "onSizeChanged" -> { if (mediaEntry?.isVRMediaType == true) { reloadPlayer() @@ -172,7 +177,6 @@ class VideoPlayerController( isVRModeEnabled = !isVRModeEnabled } } - private fun loadMedia(videoUrl: HashMap<*, *>, result: MethodChannel.Result?) { this.videoUrl = videoUrl this.mediaEntry = createMediaEntry(videoUrl) @@ -313,13 +317,11 @@ class VideoPlayerController( val vrSettings = VRSettings() vrSettings.isFlingEnabled = true vrSettings.isVrModeEnabled = false - vrSettings.interactionMode = VRInteractionMode.CardboardMotionWithTouch - vrSettings.isZoomWithPinchEnabled = true - val interactionMode = vrSettings.interactionMode - if (!VRUtil.isModeSupported(context, interactionMode)) { - vrSettings.interactionMode = VRInteractionMode.Touch - } + if (isVRModeEnabled) vrSettings.interactionMode = VRInteractionMode.MotionWithTouch + else vrSettings.interactionMode = VRInteractionMode.Touch + + vrSettings.isZoomWithPinchEnabled = true return vrSettings } diff --git a/example/lib/main.dart b/example/lib/main.dart index 5ad4fbd..48092e8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -56,7 +56,8 @@ class VideoPlayerPage extends StatefulWidget { _VideoPlayerPageState createState() => _VideoPlayerPageState(); } -class _VideoPlayerPageState extends State with TickerProviderStateMixin { +class _VideoPlayerPageState extends State + with TickerProviderStateMixin { late VrPlayerController _viewPlayerController; late AnimationController _animationController; late Animation _animation; @@ -64,6 +65,9 @@ class _VideoPlayerPageState extends State with TickerProviderSt bool _isPlaying = false; bool _isFullScreen = false; bool _isVideoFinished = false; + bool _isLandscapeOrientation = false; + bool _isVolumeSliderShown = false; + bool _isVolumeEnabled = true; late double _playerWidth; late double _playerHeight; String? _duration; @@ -72,16 +76,20 @@ class _VideoPlayerPageState extends State with TickerProviderSt bool isVideoReady = false; String? _currentPosition; double? _seekPosition = 0.0; + double _currentSliderValue = 0.1; @override void initState() { - _animationController = AnimationController(vsync: this, duration: Duration(seconds: 1)); + _animationController = + AnimationController(vsync: this, duration: Duration(seconds: 1)); _animation = Tween(begin: 0.0, end: 1.0).animate(_animationController); _toggleShowingBar(); super.initState(); } void _toggleShowingBar() { + switchVolumeSliderDisplay(false); + _isShowingBar = !_isShowingBar; if (_isShowingBar) { _animationController.forward(); @@ -93,10 +101,15 @@ class _VideoPlayerPageState extends State with TickerProviderSt @override Widget build(BuildContext context) { _playerWidth = MediaQuery.of(context).size.width; - _playerHeight = _isFullScreen ? MediaQuery.of(context).size.height : _playerWidth / 2.0; + _playerHeight = + _isFullScreen ? MediaQuery.of(context).size.height : _playerWidth / 2.0; + _isLandscapeOrientation = + MediaQuery.of(context).orientation == Orientation.landscape; return Scaffold( - appBar: AppBar(title: Text("VR Player")), + appBar: AppBar( + title: Text("VR Player"), + ), body: GestureDetector( onTap: () => _toggleShowingBar(), child: Stack( @@ -141,13 +154,15 @@ class _VideoPlayerPageState extends State with TickerProviderSt inactiveTrackColor: Colors.grey, trackHeight: 5.0, thumbColor: Colors.white, - thumbShape: RoundSliderThumbShape(enabledThumbRadius: 8.0), + thumbShape: + RoundSliderThumbShape(enabledThumbRadius: 8.0), overlayColor: Colors.purple.withAlpha(32), - overlayShape: RoundSliderOverlayShape(overlayRadius: 14.0), + overlayShape: + RoundSliderOverlayShape(overlayRadius: 14.0), ), child: Slider( value: _seekPosition!, - max: _intDuration == null ? 0.0 : _intDuration!.toDouble(), + max: _intDuration?.toDouble() ?? 0.0, onChangeEnd: (value) { _viewPlayerController.seekTo(value.toInt()); }, @@ -161,9 +176,21 @@ class _VideoPlayerPageState extends State with TickerProviderSt _duration?.toString() ?? '99:99', style: TextStyle(color: Colors.white), ), + if (_isFullScreen || _isLandscapeOrientation) + IconButton( + icon: Icon( + _isVolumeEnabled + ? Icons.volume_up_rounded + : Icons.volume_off_rounded, + color: Colors.white, + ), + onPressed: () => switchVolumeSliderDisplay(true), + ), IconButton( icon: Icon( - _isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen, + _isFullScreen + ? Icons.fullscreen_exit + : Icons.fullscreen, color: Colors.white, ), onPressed: fullScreenPressed, @@ -181,7 +208,22 @@ class _VideoPlayerPageState extends State with TickerProviderSt ), ), ), - ) + ), + Positioned( + height: 180.0, + right: 4.0, + top: MediaQuery.of(context).size.height / 4, + child: _isVolumeSliderShown + ? RotatedBox( + quarterTurns: 3, + child: Slider( + value: _currentSliderValue, + divisions: 10, + onChanged: onChangeVolumeSlider, + ), + ) + : SizedBox(), + ), ], ), ), @@ -203,7 +245,10 @@ class _VideoPlayerPageState extends State with TickerProviderSt DeviceOrientation.landscapeRight, DeviceOrientation.landscapeLeft, ]); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); + SystemChrome.setEnabledSystemUIMode( + SystemUiMode.manual, + overlays: [], + ); } else { SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeRight, @@ -211,7 +256,10 @@ class _VideoPlayerPageState extends State with TickerProviderSt DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); + SystemChrome.setEnabledSystemUIMode( + SystemUiMode.manual, + overlays: SystemUiOverlay.values, + ); } } @@ -232,14 +280,18 @@ class _VideoPlayerPageState extends State with TickerProviderSt }); } - void onViewPlayerCreated(VrPlayerController controller, VrPlayerObserver observer) { + void onViewPlayerCreated( + VrPlayerController controller, + VrPlayerObserver observer, + ) { this._viewPlayerController = controller; observer.handleStateChange(this.onReceiveState); observer.handleDurationChange(this.onReceiveDuration); observer.handlePositionChange(this.onChangePosition); observer.handleFinishedChange(this.onReceiveEnded); this._viewPlayerController.loadVideo( - videoUrl: "https://cdn.bitmovin.com/content/assets/playhouse-vr/m3u8s/105560.m3u8", + videoUrl: + "https://cdn.bitmovin.com/content/assets/playhouse-vr/m3u8s/105560.m3u8", ); } @@ -282,6 +334,20 @@ class _VideoPlayerPageState extends State with TickerProviderSt }); } + void onChangeVolumeSlider(double value) { + _viewPlayerController.setVolume(value); + setState(() { + _isVolumeEnabled = value != 0.0; + _currentSliderValue = value; + }); + } + + void switchVolumeSliderDisplay(bool show) { + setState(() { + _isVolumeSliderShown = show; + }); + } + String millisecondsToDateTime(int milliseconds) => setDurationText(Duration(milliseconds: milliseconds)); diff --git a/ios/Classes/PlayerFlutterView.swift b/ios/Classes/PlayerFlutterView.swift index ad124f3..6602cac 100644 --- a/ios/Classes/PlayerFlutterView.swift +++ b/ios/Classes/PlayerFlutterView.swift @@ -109,6 +109,8 @@ final class PlayerFlutterView: NSObject, FlutterPlatformView { onSizeChanged(arguments: call.arguments, result: result) case "isPlaying": isPlaying(arguments: call.arguments, result: result) + case "setVolume" : + setVolume(arguments: call.arguments as? [String: Any], result: result) case "play": play(arguments: call.arguments, result: result) case "pause": @@ -188,6 +190,13 @@ final class PlayerFlutterView: NSObject, FlutterPlatformView { player.pause() result(nil) } + + private func setVolume(arguments: [String: Any]?, result: FlutterResult) { + let volume = arguments?["volume"] as? Float + player.volume = volume ?? 0.0 + result(nil) + } + private func toggleVRMode(arguments: Any?, result: FlutterResult) { guard let vrController = self.player.getController(ofType: PKVRController.self) else { diff --git a/lib/vr_player.dart b/lib/vr_player.dart index 047100d..01b3495 100644 --- a/lib/vr_player.dart +++ b/lib/vr_player.dart @@ -44,6 +44,15 @@ class VrPlayerController { return _channel.invokeMethod('pause'); } + /// Set player volume from 0 to 1 + setVolume(double volume) { + try { + return _channel.invokeMethod('setVolume', {"volume": volume}); + } on PlatformException catch (e) { + print('${e.code}: ${e.message}'); + } + } + /// Enable/disable fullscreen mode /// Works only on Android. On IOS you need to pass new [width] and [height] to [VrPlayer] widget Future fullScreen() { @@ -193,7 +202,7 @@ class VrPlayer extends StatefulWidget { required this.y, required this.width, required this.height, - }); + }) : super(key: key); @override State createState() => _VideoPlayerState(); diff --git a/pubspec.yaml b/pubspec.yaml index b6e832e..cee594b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: vr_player description: The `VrPlayer` lets you play 360° and VR videos smoothly on Android and iOS platforms -version: 0.1.4 +version: 0.1.5 homepage: "https://github.com/What-the-Flutter/VR-Player" environment: