add rwd/ffwd double tap indicator & pause/play on long press
This commit is contained in:
		| @ -11,7 +11,6 @@ import android.view.* | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.core.view.GestureDetectorCompat | ||||
| import androidx.core.view.isVisible | ||||
| import androidx.core.view.postDelayed | ||||
| import com.google.android.exoplayer2.ExoPlayer | ||||
| import com.google.android.exoplayer2.MediaItem | ||||
| import com.google.android.exoplayer2.Player | ||||
| @ -23,7 +22,10 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory | ||||
| import com.google.android.exoplayer2.util.Util | ||||
| import kotlinx.android.synthetic.main.activity_player.* | ||||
| import kotlinx.android.synthetic.main.player_controls.* | ||||
| import kotlinx.coroutines.* | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.GlobalScope | ||||
| import kotlinx.coroutines.launch | ||||
| import kotlinx.coroutines.withContext | ||||
| import org.mosad.teapod.parser.AoDParser | ||||
| import org.mosad.teapod.preferences.Preferences | ||||
| import org.mosad.teapod.ui.fragments.MediaFragment | ||||
| @ -34,7 +36,6 @@ import java.util.* | ||||
| import java.util.concurrent.TimeUnit | ||||
| import kotlin.concurrent.scheduleAtFixedRate | ||||
|  | ||||
|  | ||||
| class PlayerActivity : AppCompatActivity() { | ||||
|  | ||||
|     private lateinit var player: SimpleExoPlayer | ||||
| @ -257,12 +258,52 @@ class PlayerActivity : AppCompatActivity() { | ||||
|         Log.d(javaClass.name, "Released player") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * TODO set position of rewind/fast forward indicators programmatically | ||||
|      */ | ||||
|  | ||||
|     private fun rewind() { | ||||
|         player.seekTo(player.currentPosition - rwdTime) | ||||
|  | ||||
|         // hide/show needed components | ||||
|         exo_double_tap_indicator.visibility = View.VISIBLE | ||||
|         ffwd_10_indicator.visibility = View.INVISIBLE | ||||
|         ffwd_10.visibility = View.INVISIBLE | ||||
|  | ||||
|         rwd_10_indicator.onAnimationEndCallback = { | ||||
|             exo_double_tap_indicator.visibility = View.GONE | ||||
|             ffwd_10_indicator.visibility = View.VISIBLE | ||||
|             ffwd_10.visibility = View.VISIBLE | ||||
|         } | ||||
|  | ||||
|         // run animation | ||||
|         rwd_10_indicator.runOnClickAnimation() | ||||
|     } | ||||
|  | ||||
|     private fun forward() { | ||||
|         player.seekTo(player.currentPosition + fwdTime) | ||||
|  | ||||
|         // hide/show needed components | ||||
|         exo_double_tap_indicator.visibility = View.VISIBLE | ||||
|         rwd_10_indicator.visibility = View.INVISIBLE | ||||
|         ffwd_10.visibility = View.INVISIBLE | ||||
|  | ||||
|         ffwd_10_indicator.onAnimationEndCallback = { | ||||
|             exo_double_tap_indicator.visibility = View.GONE | ||||
|             rwd_10_indicator.visibility = View.VISIBLE | ||||
|             ffwd_10.visibility = View.VISIBLE | ||||
|         } | ||||
|  | ||||
|         // run animation | ||||
|         ffwd_10_indicator.runOnClickAnimation() | ||||
|     } | ||||
|  | ||||
|     private fun togglePausePlay() { | ||||
|         if (player.isPlaying) { | ||||
|             player.pause() | ||||
|         } else { | ||||
|             player.play() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun playNextEpisode() { | ||||
| @ -282,7 +323,7 @@ class PlayerActivity : AppCompatActivity() { | ||||
|             // watchedCallback for next ep | ||||
|             currentEpisode = nextEp // set current ep to next ep | ||||
|             episodeId = nextEp.id | ||||
|             MediaFragment.instance.updateWatchedState(nextEp) // TODO i don't like this | ||||
|             MediaFragment.instance.updateWatchedState(nextEp) | ||||
|  | ||||
|             nextEpisode = selectNextEpisode() | ||||
|         } | ||||
| @ -362,15 +403,14 @@ class PlayerActivity : AppCompatActivity() { | ||||
|         button_next_ep.animate() | ||||
|             .alpha(0.0f) | ||||
|             .setListener(object : AnimatorListenerAdapter() { | ||||
|             override fun onAnimationEnd(animation: Animator?) { | ||||
|                 super.onAnimationEnd(animation) | ||||
|                 button_next_ep.visibility = View.GONE | ||||
|             } | ||||
|         }) | ||||
|                 override fun onAnimationEnd(animation: Animator?) { | ||||
|                     super.onAnimationEnd(animation) | ||||
|                     button_next_ep.visibility = View.GONE | ||||
|                 } | ||||
|             }) | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     inner class PlayerGestureListener : GestureDetector.SimpleOnGestureListener() { | ||||
|  | ||||
|         /** | ||||
| @ -386,22 +426,7 @@ class PlayerActivity : AppCompatActivity() { | ||||
|          */ | ||||
|         override fun onDoubleTap(e: MotionEvent?): Boolean { | ||||
|             val eventPosX = e?.x?.toInt() ?: 0 | ||||
|             val eventPosY = e?.y?.toInt() ?: 0 | ||||
|             val viewCenterX = video_view.measuredWidth / 2 | ||||
|             val viewCenterY = video_view.measuredHeight / 2 | ||||
|  | ||||
|             // Show ripple effect (Jellyfin Android App) TODO replace this with a netflix player like animation? | ||||
|             video_view.foreground?.apply { | ||||
|                 val left = if (eventPosX < viewCenterX) 0 else viewCenterX | ||||
|                 val right = if (eventPosX < viewCenterX) viewCenterX else video_view.measuredWidth | ||||
|  | ||||
|                 setBounds(left, viewCenterY - viewCenterX / 2, right, viewCenterY + viewCenterX / 2) | ||||
|                 setHotspot(eventPosX.toFloat(), eventPosY.toFloat()) | ||||
|                 state = intArrayOf(android.R.attr.state_enabled, android.R.attr.state_pressed) | ||||
|                 video_view.postDelayed(100) { | ||||
|                     state = IntArray(0) | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // if the event position is on the left side rewind, if it's on the right forward | ||||
|             if (eventPosX < viewCenterX) { | ||||
| @ -420,6 +445,10 @@ class PlayerActivity : AppCompatActivity() { | ||||
|             return true | ||||
|         } | ||||
|  | ||||
|         override fun onLongPress(e: MotionEvent?) { | ||||
|             togglePausePlay() | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -10,24 +10,18 @@ import android.widget.FrameLayout | ||||
| import kotlinx.android.synthetic.main.button_fast_forward.view.* | ||||
| import org.mosad.teapod.R | ||||
|  | ||||
| class FastForwardButton(context: Context, attrs: AttributeSet): FrameLayout(context, attrs) { | ||||
| class FastForwardButton(context: Context, attrs: AttributeSet?): FrameLayout(context, attrs) { | ||||
|  | ||||
|     private val animationDuration: Long = 800 | ||||
|     private val buttonAnimation: ObjectAnimator | ||||
|     private val labelAnimation: ObjectAnimator | ||||
|  | ||||
|     var onAnimationEndCallback: (() -> Unit)? = null | ||||
|  | ||||
|     init { | ||||
|         inflate(context, R.layout.button_fast_forward, this) | ||||
|     } | ||||
|  | ||||
|     fun setOnButtonClickListener(func: FastForwardButton.() -> Unit) { | ||||
|         imageButton.setOnClickListener { | ||||
|             func() | ||||
|             runOnClickAnimation() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun runOnClickAnimation() { | ||||
|         // run button animation | ||||
|         ObjectAnimator.ofFloat(imageButton, View.ROTATION, 0f, 50f).apply { | ||||
|         buttonAnimation = ObjectAnimator.ofFloat(imageButton, View.ROTATION, 0f, 50f).apply { | ||||
|             duration = animationDuration / 4 | ||||
|             repeatCount = 1 | ||||
|             repeatMode = ObjectAnimator.REVERSE | ||||
| @ -36,29 +30,39 @@ class FastForwardButton(context: Context, attrs: AttributeSet): FrameLayout(cont | ||||
|                     imageButton.isEnabled = false // disable button | ||||
|                     imageButton.setBackgroundResource(R.drawable.ic_baseline_forward_24) | ||||
|                 } | ||||
|                 override fun onAnimationEnd(animation: Animator?) { | ||||
|                     imageButton.isEnabled = true // enable button | ||||
|                 } | ||||
|             }) | ||||
|             start() | ||||
|         } | ||||
|  | ||||
|         // run lbl animation | ||||
|         textView.visibility = View.VISIBLE | ||||
|         ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, 35f).apply { | ||||
|         labelAnimation = ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, 35f).apply { | ||||
|             duration = animationDuration | ||||
|             addListener(object : AnimatorListenerAdapter() { | ||||
|                 // the label animation takes longer then the button animation, reset stuff in here | ||||
|                 override fun onAnimationEnd(animation: Animator?) { | ||||
|                     imageButton.isEnabled = true // enable button | ||||
|                     imageButton.setBackgroundResource(R.drawable.ic_baseline_forward_10_24) | ||||
|  | ||||
|                     textView.visibility = View.GONE | ||||
|                     textView.animate().translationX(0f) | ||||
|  | ||||
|                     onAnimationEndCallback?.invoke() | ||||
|                 } | ||||
|             }) | ||||
|             start() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun setOnButtonClickListener(func: FastForwardButton.() -> Unit) { | ||||
|         imageButton.setOnClickListener { | ||||
|             func() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun runOnClickAnimation() { | ||||
|         // run button animation | ||||
|         buttonAnimation.start() | ||||
|  | ||||
|         // run lbl animation | ||||
|         textView.visibility = View.VISIBLE | ||||
|         labelAnimation.start() | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -13,21 +13,15 @@ import org.mosad.teapod.R | ||||
| class RewindButton(context: Context, attrs: AttributeSet): FrameLayout(context, attrs) { | ||||
|  | ||||
|     private val animationDuration: Long = 800 | ||||
|     private val buttonAnimation: ObjectAnimator | ||||
|     private val labelAnimation: ObjectAnimator | ||||
|  | ||||
|     var onAnimationEndCallback: (() -> Unit)? = null | ||||
|  | ||||
|     init { | ||||
|         inflate(context, R.layout.button_rewind, this) | ||||
|     } | ||||
|  | ||||
|     fun setOnButtonClickListener(func: RewindButton.() -> Unit) { | ||||
|         imageButton.setOnClickListener { | ||||
|             func() | ||||
|             runOnClickAnimation() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun runOnClickAnimation() { | ||||
|         // run button animation | ||||
|         ObjectAnimator.ofFloat(imageButton, View.ROTATION, 0f, -50f).apply { | ||||
|         buttonAnimation = ObjectAnimator.ofFloat(imageButton, View.ROTATION, 0f, -50f).apply { | ||||
|             duration = animationDuration / 4 | ||||
|             repeatCount = 1 | ||||
|             repeatMode = ObjectAnimator.REVERSE | ||||
| @ -36,16 +30,10 @@ class RewindButton(context: Context, attrs: AttributeSet): FrameLayout(context, | ||||
|                     imageButton.isEnabled = false // disable button | ||||
|                     imageButton.setBackgroundResource(R.drawable.ic_baseline_rewind_24) | ||||
|                 } | ||||
|                 override fun onAnimationEnd(animation: Animator?) { | ||||
|                     imageButton.isEnabled = true // enable button | ||||
|                 } | ||||
|             }) | ||||
|             start() | ||||
|         } | ||||
|  | ||||
|         // run lbl animation | ||||
|         textView.visibility = View.VISIBLE | ||||
|         ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, -35f).apply { | ||||
|         labelAnimation = ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, -35f).apply { | ||||
|             duration = animationDuration | ||||
|             addListener(object : AnimatorListenerAdapter() { | ||||
|                 override fun onAnimationEnd(animation: Animator?) { | ||||
| @ -54,11 +42,26 @@ class RewindButton(context: Context, attrs: AttributeSet): FrameLayout(context, | ||||
|  | ||||
|                     textView.visibility = View.GONE | ||||
|                     textView.animate().translationX(0f) | ||||
|  | ||||
|                     onAnimationEndCallback?.invoke() | ||||
|                 } | ||||
|             }) | ||||
|             start() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun setOnButtonClickListener(func: RewindButton.() -> Unit) { | ||||
|         imageButton.setOnClickListener { | ||||
|             func() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun runOnClickAnimation() { | ||||
|         // run button animation | ||||
|         buttonAnimation.start() | ||||
|  | ||||
|         // run lbl animation | ||||
|         textView.visibility = View.VISIBLE | ||||
|         labelAnimation.start() | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -2,10 +2,11 @@ | ||||
| <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:id="@+id/player_layout" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:keepScreenOn="true" | ||||
|     android:background="#000000" | ||||
|     android:keepScreenOn="true" | ||||
|     tools:context=".PlayerActivity"> | ||||
|  | ||||
|     <com.google.android.exoplayer2.ui.StyledPlayerView | ||||
| @ -15,9 +16,9 @@ | ||||
|         android:layout_gravity="center" | ||||
|         android:animateLayoutChanges="true" | ||||
|         android:foreground="@drawable/ripple_background" | ||||
|         app:controller_layout_id="@layout/player_controls" | ||||
|         app:fastforward_increment="10000" | ||||
|         app:rewind_increment="10000" | ||||
|         app:controller_layout_id="@layout/player_controls"/> | ||||
|         app:rewind_increment="10000" /> | ||||
|  | ||||
|     <com.google.android.material.progressindicator.ProgressIndicator | ||||
|         android:id="@+id/loading" | ||||
| @ -28,6 +29,50 @@ | ||||
|         app:indicatorColor="@color/exo_white" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <LinearLayout | ||||
|         android:id="@+id/exo_double_tap_indicator" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_gravity="center" | ||||
|         android:gravity="center" | ||||
|         android:orientation="horizontal" | ||||
|         android:visibility="gone"> | ||||
|  | ||||
|         <Space | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="1dp" | ||||
|             android:layout_weight="1" /> | ||||
|  | ||||
|         <org.mosad.teapod.ui.components.RewindButton | ||||
|             android:id="@+id/rwd_10_indicator" | ||||
|             android:layout_width="100dp" | ||||
|             android:layout_height="wrap_content" /> | ||||
|  | ||||
|         <Space | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="1dp" | ||||
|             android:layout_weight="1" /> | ||||
|  | ||||
|         <Space | ||||
|             android:layout_width="60dp" | ||||
|             android:layout_height="1dp" /> | ||||
|  | ||||
|         <Space | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="1dp" | ||||
|             android:layout_weight="1" /> | ||||
|  | ||||
|         <org.mosad.teapod.ui.components.FastForwardButton | ||||
|             android:id="@+id/ffwd_10_indicator" | ||||
|             android:layout_width="100dp" | ||||
|             android:layout_height="wrap_content" /> | ||||
|  | ||||
|         <Space | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="1dp" | ||||
|             android:layout_weight="1" /> | ||||
|     </LinearLayout> | ||||
|  | ||||
|     <com.google.android.material.button.MaterialButton | ||||
|         android:id="@+id/button_next_ep" | ||||
|         android:layout_width="wrap_content" | ||||
|  | ||||
		Reference in New Issue
	
	Block a user