diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/utils/PlayerGestureHelper.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/utils/PlayerGestureHelper.kt
index 30bd3f6f..05981bc7 100644
--- a/app/phone/src/main/java/dev/jdtech/jellyfin/utils/PlayerGestureHelper.kt
+++ b/app/phone/src/main/java/dev/jdtech/jellyfin/utils/PlayerGestureHelper.kt
@@ -10,9 +10,13 @@ import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
+import android.view.ViewPropertyAnimator
import android.view.WindowInsets
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF
+import android.view.animation.AccelerateInterpolator
+import android.view.animation.DecelerateInterpolator
+import android.widget.ImageView
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView
import dev.jdtech.jellyfin.AppPreferences
@@ -72,8 +76,6 @@ class PlayerGestureHelper(
val viewWidth = playerView.measuredWidth
val areaWidth = viewWidth / 5 // Divide the view into 5 parts: 2:1:2
- val currentPos = playerView.player?.currentPosition ?: 0
-
// Define the areas and their boundaries
val leftmostAreaStart = 0
val middleAreaStart = areaWidth * 2
@@ -82,15 +84,15 @@ class PlayerGestureHelper(
when (e.x.toInt()) {
in leftmostAreaStart until middleAreaStart -> {
// Tapped on the leftmost area (seek backward)
- playerView.player?.seekTo((currentPos - appPreferences.playerSeekBackIncrement).coerceAtLeast(0))
+ rewind()
}
in middleAreaStart until rightmostAreaStart -> {
// Tapped on the middle area (toggle pause/unpause)
- playerView.player?.playWhenReady = !playerView.player?.playWhenReady!!
+ togglePlayback()
}
in rightmostAreaStart until viewWidth -> {
// Tapped on the rightmost area (seek forward)
- playerView.player?.seekTo(currentPos + appPreferences.playerSeekForwardIncrement)
+ fastForward()
}
}
return true
@@ -98,6 +100,68 @@ class PlayerGestureHelper(
},
)
+ private fun fastForward() {
+ val currentPosition = playerView.player?.currentPosition ?: 0
+ val fastForwardPosition = currentPosition + appPreferences.playerSeekForwardIncrement
+ seekTo(fastForwardPosition)
+ animateRipple(activity.binding.imageFfwdAnimationRipple)
+ }
+
+ private fun rewind() {
+ val currentPosition = playerView.player?.currentPosition ?: 0
+ val rewindPosition = currentPosition - appPreferences.playerSeekBackIncrement
+ seekTo(rewindPosition.coerceAtLeast(0))
+ animateRipple(activity.binding.imageRewindAnimationRipple)
+ }
+
+ private fun togglePlayback() {
+ playerView.player?.playWhenReady = !playerView.player?.playWhenReady!!
+ animateRipple(activity.binding.imagePlaybackAnimationRipple)
+ }
+
+ private fun seekTo(position: Long) {
+ playerView.player?.seekTo(position)
+ }
+
+ private fun animateRipple(image: ImageView) {
+ image
+ .animateSeekingRippleStart()
+ .withEndAction {
+ resetRippleImage(image)
+ }
+ .start()
+ }
+
+ private fun ImageView.animateSeekingRippleStart(): ViewPropertyAnimator {
+ val rippleImageHeight = this.height
+ val playerViewHeight = playerView.height.toFloat()
+ val playerViewWidth = playerView.width.toFloat()
+ val scaleDifference = playerViewHeight / rippleImageHeight
+ val playerViewAspectRatio = playerViewWidth / playerViewHeight
+ val scaleValue = scaleDifference * playerViewAspectRatio
+ return animate()
+ .alpha(1f)
+ .scaleX(scaleValue)
+ .scaleY(scaleValue)
+ .setDuration(180)
+ .setInterpolator(DecelerateInterpolator())
+ }
+
+ private fun resetRippleImage(image: ImageView) {
+ image
+ .animateSeekingRippleEnd()
+ .withEndAction {
+ image.scaleX = 1f
+ image.scaleY = 1f
+ }
+ .start()
+ }
+
+ private fun ImageView.animateSeekingRippleEnd() = animate()
+ .alpha(0f)
+ .setDuration(150)
+ .setInterpolator(AccelerateInterpolator())
+
private val seekGestureDetector = GestureDetector(
playerView.context,
object : GestureDetector.SimpleOnGestureListener() {
diff --git a/app/phone/src/main/res/layout/activity_player.xml b/app/phone/src/main/res/layout/activity_player.xml
index ec44e30f..ee2e8977 100644
--- a/app/phone/src/main/res/layout/activity_player.xml
+++ b/app/phone/src/main/res/layout/activity_player.xml
@@ -113,4 +113,30 @@
tools:ignore="ContentDescription" />
+
+
+
+
+
diff --git a/core/src/main/res/drawable/transparent_circle.xml b/core/src/main/res/drawable/transparent_circle.xml
new file mode 100644
index 00000000..a8e538b9
--- /dev/null
+++ b/core/src/main/res/drawable/transparent_circle.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file