New player UI animations (#651)

* fix autoplay not starting from beginning of episode

* Add player aniamtions

* add a central integer value

* fix a visual bug

* fix an RTL/LTR bug
This commit is contained in:
Quickdesh 2022-07-11 03:25:00 +05:30 committed by GitHub
parent d8c2c17631
commit 48feecd1c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 175 additions and 78 deletions

View file

@ -210,18 +210,18 @@ class PlayerActivity :
binding.seekView.visibility = View.GONE
}
// Fade out Volume Bar
// Slide out Volume Bar
internal val volumeViewRunnable = Runnable {
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
if (!playerControls.shouldHideUiForSeek) playerControls.binding.volumeView.startAnimation(fadeAnimation)
AnimationUtils.loadAnimation(this, R.anim.player_exit_left).also { slideAnimation ->
if (!playerControls.shouldHideUiForSeek) playerControls.binding.volumeView.startAnimation(slideAnimation)
playerControls.binding.volumeView.visibility = View.GONE
}
}
// Fade out Brightness Bar
// Slide out Brightness Bar
internal val brightnessViewRunnable = Runnable {
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
if (!playerControls.shouldHideUiForSeek) playerControls.binding.brightnessView.startAnimation(fadeAnimation)
AnimationUtils.loadAnimation(this, R.anim.player_exit_right).also { slideAnimation ->
if (!playerControls.shouldHideUiForSeek) playerControls.binding.brightnessView.startAnimation(slideAnimation)
playerControls.binding.brightnessView.visibility = View.GONE
}
}
@ -240,11 +240,13 @@ class PlayerActivity :
callback = volumeViewRunnable
itemView = playerControls.binding.volumeView
delay = 750L
if (!itemView.isVisible) itemView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.player_enter_left))
}
"brightness" -> {
callback = brightnessViewRunnable
itemView = playerControls.binding.brightnessView
delay = 750L
if (!itemView.isVisible) itemView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.player_enter_right))
}
else -> return
}
@ -505,7 +507,7 @@ class PlayerActivity :
// Fade out Player information text
private val playerInformationRunnable = Runnable {
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
AnimationUtils.loadAnimation(this, R.anim.fade_out_short).also { fadeAnimation ->
playerControls.binding.playerInformation.startAnimation(fadeAnimation)
playerControls.binding.playerInformation.visibility = View.GONE
}
@ -640,7 +642,7 @@ class PlayerActivity :
}
private val doubleTapPlayPauseRunnable = Runnable {
AnimationUtils.loadAnimation(this, R.anim.fade_out_medium).also { fadeAnimation ->
AnimationUtils.loadAnimation(this, R.anim.player_fade_out).also { fadeAnimation ->
binding.playPauseView.startAnimation(fadeAnimation)
binding.playPauseView.visibility = View.GONE
}
@ -656,7 +658,7 @@ class PlayerActivity :
!player.paused!! -> { binding.playPauseView.setImageResource(R.drawable.ic_play_arrow_72dp) }
}
AnimationUtils.loadAnimation(this, R.anim.fade_in_medium).also { fadeAnimation ->
AnimationUtils.loadAnimation(this, R.anim.player_fade_in).also { fadeAnimation ->
binding.playPauseView.startAnimation(fadeAnimation)
binding.playPauseView.visibility = View.VISIBLE
}

View file

@ -81,7 +81,7 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
shouldHideUiForSeek = false
activity.player.paused = wasPausedBeforeSeeking
if (showControls) {
AnimationUtils.loadAnimation(activity, R.anim.fade_in_medium).also { fadeAnimation ->
AnimationUtils.loadAnimation(activity, R.anim.player_fade_in).also { fadeAnimation ->
binding.topControlsGroup.startAnimation(fadeAnimation)
binding.topControlsGroup.isVisible = true
@ -91,11 +91,14 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
binding.bottomControlsGroup.startAnimation(fadeAnimation)
binding.bottomControlsGroup.isVisible = true
}
showControls = false
} else {
showControls = true
animationHandler.removeCallbacks(controlsViewRunnable)
animationHandler.postDelayed(controlsViewRunnable, 500L)
animationHandler.removeCallbacks(nonSeekViewRunnable)
animationHandler.postDelayed(nonSeekViewRunnable, 700L)
animationHandler.postDelayed(nonSeekViewRunnable, 600L + resources.getInteger(R.integer.player_animation_duration).toLong())
}
}
@ -281,21 +284,38 @@ class PlayerControlsView @JvmOverloads constructor(context: Context, attrs: Attr
private fun fadeOutView(view: View) {
animationHandler.removeCallbacks(controlsViewRunnable)
AnimationUtils.loadAnimation(context, R.anim.fade_out_medium).also { fadeAnimation ->
AnimationUtils.loadAnimation(context, R.anim.player_fade_out).also { fadeAnimation ->
view.startAnimation(fadeAnimation)
view.visibility = View.GONE
}
binding.seekBarGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_exit_bottom))
if (!showControls) {
binding.topControlsGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_exit_top))
binding.bottomRightControlsGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_exit_right))
binding.bottomLeftControlsGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_exit_left))
binding.middleControlsGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_fade_out))
showControls = false
}
}
private fun fadeInView(view: View) {
animationHandler.removeCallbacks(controlsViewRunnable)
AnimationUtils.loadAnimation(context, R.anim.fade_in_short).also { fadeAnimation ->
AnimationUtils.loadAnimation(context, R.anim.player_fade_in).also { fadeAnimation ->
view.startAnimation(fadeAnimation)
view.visibility = View.VISIBLE
}
binding.seekBarGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_enter_bottom))
binding.topControlsGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_enter_top))
binding.bottomRightControlsGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_enter_right))
binding.bottomLeftControlsGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_enter_left))
binding.middleControlsGroup.startAnimation(AnimationUtils.loadAnimation(context, R.anim.player_fade_in))
}
internal fun pauseForDialog(): StateRestoreCallback {
private fun pauseForDialog(): StateRestoreCallback {
val wasPlayerPaused = activity.player.paused ?: true // default to not changing state
activity.player.paused = true
return {

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/player_animation_duration"
android:interpolator="@android:interpolator/fast_out_slow_in">
<translate
android:fromYDelta="100%p"
android:toYDelta="0" />
</set>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/player_animation_duration"
android:interpolator="@android:interpolator/fast_out_slow_in">
<translate
android:fromXDelta="-100%p"
android:toXDelta="0" />
</set>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/player_animation_duration"
android:interpolator="@android:interpolator/fast_out_slow_in">
<translate
android:fromXDelta="100%p"
android:toXDelta="0" />
</set>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/player_animation_duration"
android:interpolator="@android:interpolator/fast_out_slow_in">
<translate
android:fromYDelta="-100%p"
android:toYDelta="0" />
</set>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/player_animation_duration">
<translate
android:toYDelta="100%p"
android:fromYDelta="0" />
</set>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/player_animation_duration">
<translate
android:toXDelta="-100%p"
android:fromXDelta="0" />
</set>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/player_animation_duration">
<translate
android:toXDelta="100%p"
android:fromXDelta="0" />
</set>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/player_animation_duration">
<translate
android:toYDelta="-100%p"
android:fromYDelta="0" />
</set>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="150"
android:duration="@integer/player_animation_duration"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:interpolator="@android:interpolator/linear"/>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="150"
android:duration="@integer/player_animation_duration"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:interpolator="@android:interpolator/linear"/>

View file

@ -265,80 +265,83 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="48dp"
android:layoutDirection="ltr"
android:visibility="visible">
<!-- Bottom Controls (Right)-->
<ImageButton
android:id="@+id/lockBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginLeft="10dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="Lock player"
android:src="@drawable/ic_lock_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:tint="?attr/colorOnPrimarySurface" />
<ImageButton
android:id="@+id/rotateBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="Rotate player"
android:onClick="rotatePlayer"
android:src="@drawable/ic_screen_rotation_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/lockBtn"
app:tint="?attr/colorOnPrimarySurface" />
<Button
android:id="@+id/cycleSpeedBtn"
<LinearLayout
android:id="@+id/bottomLeftControlsGroup"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:onClick="cycleSpeed"
android:text=".."
android:textColor="?attr/colorOnPrimarySurface"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/rotateBtn" />
app:layout_constraintLeft_toLeftOf="parent">
<!-- Top Controls (Left)-->
<ImageButton
android:id="@+id/lockBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginLeft="10dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="Lock player"
android:src="@drawable/ic_lock_24dp"
app:tint="?attr/colorOnPrimarySurface" />
<ImageButton
android:id="@+id/pipBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginRight="10dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/action_player_pip"
android:src="@drawable/ic_picture_in_picture_24dp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<ImageButton
android:id="@+id/rotateBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="Rotate player"
android:onClick="rotatePlayer"
android:src="@drawable/ic_screen_rotation_24dp"
app:tint="?attr/colorOnPrimarySurface" />
<ImageButton
android:id="@+id/cycleViewModeBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="Cycle view modes"
android:onClick="cycleViewMode"
android:src="@drawable/ic_fullscreen_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@id/pipBtn"
app:tint="?attr/colorOnPrimarySurface" />
<Button
android:id="@+id/cycleSpeedBtn"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:onClick="cycleSpeed"
android:text=".."
android:textColor="?attr/colorOnPrimarySurface" />
<Button
android:id="@+id/controls_skip_intro_btn"
</LinearLayout>
<LinearLayout
android:id="@+id/bottomRightControlsGroup"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:onClick="skipIntro"
android:textColor="?attr/colorOnPrimarySurface"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@id/cycleViewModeBtn" />
app:layout_constraintRight_toRightOf="parent">
<Button
android:id="@+id/controls_skip_intro_btn"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:onClick="skipIntro"
android:textColor="?attr/colorOnPrimarySurface" />
<ImageButton
android:id="@+id/cycleViewModeBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="Cycle view modes"
android:onClick="cycleViewMode"
android:src="@drawable/ic_fullscreen_black_24dp"
app:tint="?attr/colorOnPrimarySurface" />
<ImageButton
android:id="@+id/pipBtn"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginRight="10dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/action_player_pip"
android:src="@drawable/ic_picture_in_picture_24dp"
android:visibility="visible" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="player_animation_duration">200</integer>
</resources>