From e259c405bbb7e3bd48fdcdbf6f5fa1fa7652bdeb Mon Sep 17 00:00:00 2001 From: Jcuhfehl <91626737+Jcuhfehl@users.noreply.github.com> Date: Sat, 27 Nov 2021 16:03:17 +0100 Subject: [PATCH] Add brightness swipe controls (#69) * Add brightness swipe control * Add background to the overlays Co-authored-by: Jarne Demeulemeester <32322857+jarnedemeulemeester@users.noreply.github.com> --- .../dev/jdtech/jellyfin/PlayerActivity.kt | 28 +--- .../jellyfin/utils/PlayerGestureHelper.kt | 129 ++++++++++++++++++ .../jellyfin/utils/VerticalSwipeListener.kt | 60 -------- app/src/main/res/drawable/ic_sun.xml | 69 ++++++++++ app/src/main/res/drawable/ic_volume.xml | 20 +++ .../main/res/drawable/overlay_background.xml | 6 + .../res/drawable/progress_scale_drawable.xml | 19 +++ app/src/main/res/layout/activity_player.xml | 74 ++++++++++ app/src/main/res/values/colors.xml | 2 + 9 files changed, 326 insertions(+), 81 deletions(-) create mode 100644 app/src/main/java/dev/jdtech/jellyfin/utils/PlayerGestureHelper.kt delete mode 100644 app/src/main/java/dev/jdtech/jellyfin/utils/VerticalSwipeListener.kt create mode 100644 app/src/main/res/drawable/ic_sun.xml create mode 100644 app/src/main/res/drawable/ic_volume.xml create mode 100644 app/src/main/res/drawable/overlay_background.xml create mode 100644 app/src/main/res/drawable/progress_scale_drawable.xml diff --git a/app/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt b/app/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt index 918414c9..8cf8accb 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/PlayerActivity.kt @@ -1,6 +1,7 @@ package dev.jdtech.jellyfin -import android.os.Build +import android.content.Context +import android.media.AudioManager import android.os.Bundle import android.view.View import android.view.WindowManager @@ -17,19 +18,17 @@ import dev.jdtech.jellyfin.dialogs.SpeedSelectionDialogFragment import dev.jdtech.jellyfin.dialogs.TrackSelectionDialogFragment import dev.jdtech.jellyfin.mpv.MPVPlayer import dev.jdtech.jellyfin.mpv.TrackType -import dev.jdtech.jellyfin.utils.AudioController -import dev.jdtech.jellyfin.utils.VerticalSwipeListener +import dev.jdtech.jellyfin.utils.PlayerGestureHelper import dev.jdtech.jellyfin.viewmodels.PlayerActivityViewModel import timber.log.Timber -import kotlin.math.max @AndroidEntryPoint class PlayerActivity : BasePlayerActivity() { - private lateinit var binding: ActivityPlayerBinding + lateinit var binding: ActivityPlayerBinding + private lateinit var playerGestureHelper: PlayerGestureHelper override val viewModel: PlayerActivityViewModel by viewModels() private val args: PlayerActivityArgs by navArgs() - private val audioController by lazy { AudioController(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -42,10 +41,11 @@ class PlayerActivity : BasePlayerActivity() { binding.playerView.player = viewModel.player val playerControls = binding.playerView.findViewById(R.id.player_controls) - setupVolumeControl() configureInsets(playerControls) + playerGestureHelper = PlayerGestureHelper(this, binding.playerView, getSystemService(Context.AUDIO_SERVICE) as AudioManager) + binding.playerView.findViewById(R.id.back_button).setOnClickListener { onBackPressed() } @@ -158,19 +158,5 @@ class PlayerActivity : BasePlayerActivity() { viewModel.initializePlayer(args.items) hideSystemUI() } - - private fun setupVolumeControl() { - val height = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - windowManager.currentWindowMetrics.bounds.height() - } else { - windowManager.defaultDisplay.height - } - binding.playerView.setOnTouchListener(VerticalSwipeListener( - onUp = { audioController.volumeUp() }, - onDown = { audioController.volumeDown() }, - onTouch = { audioController.showVolumeSlider() }, - threshold = max(height / 8, 100) - )) - } } diff --git a/app/src/main/java/dev/jdtech/jellyfin/utils/PlayerGestureHelper.kt b/app/src/main/java/dev/jdtech/jellyfin/utils/PlayerGestureHelper.kt new file mode 100644 index 00000000..d769b07f --- /dev/null +++ b/app/src/main/java/dev/jdtech/jellyfin/utils/PlayerGestureHelper.kt @@ -0,0 +1,129 @@ +package dev.jdtech.jellyfin.utils + +import android.media.AudioManager +import android.provider.Settings +import android.view.GestureDetector +import android.view.MotionEvent +import android.view.View +import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL +import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF +import com.google.android.exoplayer2.ui.PlayerView +import dev.jdtech.jellyfin.PlayerActivity +import timber.log.Timber +import kotlin.math.abs + +class PlayerGestureHelper( + private val activity: PlayerActivity, + private val playerView: PlayerView, + private val audioManager: AudioManager +) { + /** + * Tracks a value during a swipe gesture (between multiple onScroll calls). + * When the gesture starts it's reset to an initial value and gets increased or decreased + * (depending on the direction) as the gesture progresses. + */ + private var swipeGestureValueTrackerVolume = -1f + private var swipeGestureValueTrackerBrightness = -1f + + private val gestureDetector = GestureDetector(playerView.context, object : GestureDetector.SimpleOnGestureListener() { + override fun onDoubleTap(e: MotionEvent): Boolean { + return true + } + + override fun onSingleTapUp(e: MotionEvent?): Boolean { + playerView.apply { + if (!isControllerVisible) showController() else hideController() + } + return true + } + + override fun onScroll(firstEvent: MotionEvent, currentEvent: MotionEvent, distanceX: Float, distanceY: Float): Boolean { + // Check whether swipe was oriented vertically + if (abs(distanceY / distanceX) < 2) + return false + + val viewCenterX = playerView.measuredWidth / 2 + + // Distance to swipe to go from min to max + val distanceFull = playerView.measuredHeight + val ratioChange = distanceY / distanceFull + + if (firstEvent.x.toInt() > viewCenterX) { + // Swiping on the right, change volume + + val currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) + if (swipeGestureValueTrackerVolume == -1f) swipeGestureValueTrackerVolume = currentVolume.toFloat() + + val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) + val change = ratioChange * maxVolume + swipeGestureValueTrackerVolume += change + + val toSet = swipeGestureValueTrackerVolume.toInt().coerceIn(0, maxVolume) + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, toSet, 0) + + activity.binding.gestureVolumeLayout.visibility = View.VISIBLE + activity.binding.gestureVolumeProgressBar.max = maxVolume + activity.binding.gestureVolumeProgressBar.progress = toSet + activity.binding.gestureVolumeText.text = "${(toSet.toFloat()/maxVolume.toFloat()).times(100).toInt()}%" + } else { + // Swiping on the left, change brightness + val window = activity.window + val brightnessRange = BRIGHTNESS_OVERRIDE_OFF..BRIGHTNESS_OVERRIDE_FULL + + // Initialize on first swipe + if (swipeGestureValueTrackerBrightness == -1f) { + val brightness = window.attributes.screenBrightness + Timber.d("Brightness ${Settings.System.getFloat(activity.contentResolver, Settings.System.SCREEN_BRIGHTNESS)}") + swipeGestureValueTrackerBrightness = when (brightness) { + in brightnessRange -> brightness + else -> Settings.System.getFloat(activity.contentResolver, Settings.System.SCREEN_BRIGHTNESS)/255 + } + } + swipeGestureValueTrackerBrightness = (swipeGestureValueTrackerBrightness + ratioChange).coerceIn(brightnessRange) + val lp = window.attributes + lp.screenBrightness = swipeGestureValueTrackerBrightness + window.attributes = lp + + activity.binding.gestureBrightnessLayout.visibility = View.VISIBLE + activity.binding.gestureBrightnessProgressBar.max = BRIGHTNESS_OVERRIDE_FULL.times(100).toInt() + activity.binding.gestureBrightnessProgressBar.progress = lp.screenBrightness.times(100).toInt() + activity.binding.gestureBrightnessText.text = "${(lp.screenBrightness/BRIGHTNESS_OVERRIDE_FULL).times(100).toInt()}%" + } + return true + } + }) + + private val hideGestureVolumeIndicatorOverlayAction = Runnable { + activity.binding.gestureVolumeLayout.visibility = View.GONE + } + + private val hideGestureBrightnessIndicatorOverlayAction = Runnable { + activity.binding.gestureBrightnessLayout.visibility = View.GONE + } + + init { + @Suppress("ClickableViewAccessibility") + playerView.setOnTouchListener { _, event -> + if (playerView.useController) { + when (event.pointerCount) { + 1 -> gestureDetector.onTouchEvent(event) + } + } + if(event.action == MotionEvent.ACTION_UP) { + activity.binding.gestureVolumeLayout.apply { + if (visibility == View.VISIBLE) { + removeCallbacks(hideGestureVolumeIndicatorOverlayAction) + postDelayed(hideGestureVolumeIndicatorOverlayAction, 1000) + } + } + activity.binding.gestureBrightnessLayout.apply { + if (visibility == View.VISIBLE) { + removeCallbacks(hideGestureBrightnessIndicatorOverlayAction) + postDelayed(hideGestureBrightnessIndicatorOverlayAction, 1000) + } + } + } + true + } + } +} diff --git a/app/src/main/java/dev/jdtech/jellyfin/utils/VerticalSwipeListener.kt b/app/src/main/java/dev/jdtech/jellyfin/utils/VerticalSwipeListener.kt deleted file mode 100644 index c96c8b02..00000000 --- a/app/src/main/java/dev/jdtech/jellyfin/utils/VerticalSwipeListener.kt +++ /dev/null @@ -1,60 +0,0 @@ -package dev.jdtech.jellyfin.utils - -import android.annotation.SuppressLint -import android.view.MotionEvent -import android.view.MotionEvent.ACTION_DOWN -import android.view.MotionEvent.ACTION_MOVE -import android.view.MotionEvent.ACTION_UP -import android.view.View -import kotlin.math.absoluteValue - -/** - * Never consumes touch events. Can report when swipe starts with onTouch. - */ -internal class VerticalSwipeListener( - private val onUp: () -> Unit, - private val onDown: () -> Unit, - private val onTouch: () -> Unit = {}, - private val threshold: Int = 150, -): View.OnTouchListener { - - private var verticalStart = 0f - private var distance = 0f - private var dispatchTouchEvent = true - - @SuppressLint("ClickableViewAccessibility") - override fun onTouch(v: View, event: MotionEvent): Boolean { - when(event.action) { - ACTION_DOWN -> verticalStart = event.y - ACTION_UP -> dispatchTouchEvent = true - ACTION_MOVE -> event.reportSwipe() - else -> Unit - } - - return false - } - - private fun MotionEvent.reportSwipe() { - reportFirstTouch() - - distance = verticalStart - y - if (distance.tooShort()) return - - verticalStart = y - - if (distance > 0) { - onUp() - } else { - onDown() - } - } - - private fun reportFirstTouch() { - if (dispatchTouchEvent) { - onTouch() - dispatchTouchEvent = false - } - } - - private fun Float.tooShort() = absoluteValue < threshold -} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_sun.xml b/app/src/main/res/drawable/ic_sun.xml new file mode 100644 index 00000000..8e72a2b2 --- /dev/null +++ b/app/src/main/res/drawable/ic_sun.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_volume.xml b/app/src/main/res/drawable/ic_volume.xml new file mode 100644 index 00000000..12d753f2 --- /dev/null +++ b/app/src/main/res/drawable/ic_volume.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/overlay_background.xml b/app/src/main/res/drawable/overlay_background.xml new file mode 100644 index 00000000..e47146b7 --- /dev/null +++ b/app/src/main/res/drawable/overlay_background.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/progress_scale_drawable.xml b/app/src/main/res/drawable/progress_scale_drawable.xml new file mode 100644 index 00000000..7543659f --- /dev/null +++ b/app/src/main/res/drawable/progress_scale_drawable.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_player.xml b/app/src/main/res/layout/activity_player.xml index d8ae92df..65efc487 100644 --- a/app/src/main/res/layout/activity_player.xml +++ b/app/src/main/res/layout/activity_player.xml @@ -13,4 +13,78 @@ android:background="@color/black" app:show_buffering="always" /> + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index eabe5563..37aaa762 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -13,6 +13,8 @@ #A9BDD1 #D7E0E9 #EEF2F6 + #4DFFFFFF + #4D000000 #FF000000 #FFFFFFFF #EB5757