diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2020-07-02 15:27:21 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2020-07-02 15:27:21 -0300 |
| commit | 8b7a6fe8c352f06c7ec9d85a309ae747419778e7 (patch) | |
| tree | 3532935d1fb486bbbb14860d9039fdf45fca27ad /android | |
| parent | 5902ecb40a11332764fbdbb5f902868f5b75211e (diff) | |
| parent | bb6424199455898a0a9b026f70b29fd3cb885ebe (diff) | |
| download | mullvadvpn-8b7a6fe8c352f06c7ec9d85a309ae747419778e7.tar.xz mullvadvpn-8b7a6fe8c352f06c7ec9d85a309ae747419778e7.zip | |
Merge branch 'animate-notification-change'
Diffstat (limited to 'android')
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/NotificationBanner.kt | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/NotificationBanner.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/NotificationBanner.kt index 2992ee94eb..6a20bcbd7f 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/NotificationBanner.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/NotificationBanner.kt @@ -1,5 +1,8 @@ package net.mullvad.mullvadvpn.ui.widget +import android.animation.Animator +import android.animation.Animator.AnimatorListener +import android.animation.ObjectAnimator import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater @@ -16,6 +19,41 @@ import net.mullvad.mullvadvpn.util.JobTracker class NotificationBanner : FrameLayout { private val jobTracker = JobTracker() + private val animationListener = object : AnimatorListener { + override fun onAnimationCancel(animation: Animator) {} + override fun onAnimationRepeat(animation: Animator) {} + + override fun onAnimationStart(animation: Animator) { + visibility = View.VISIBLE + } + + override fun onAnimationEnd(animation: Animator) { + synchronized(this@NotificationBanner) { + if (reversedAnimation) { + // Banner is now hidden + val notification = notifications.current + + visibility = View.INVISIBLE + + if (notification != null) { + // Notification changed, restart animation + update(notification) + reversedAnimation = false + animation.start() + } + } + } + } + } + + private val animation = ObjectAnimator.ofFloat(this, "translationY", 0.0f).apply { + addListener(animationListener) + setDuration(350) + + // Ensure there's time for the layout to finish before making the banner visible + setStartDelay(20) + } + private val container = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE).let { service -> val inflater = service as LayoutInflater @@ -31,12 +69,12 @@ class NotificationBanner : FrameLayout { private val message: TextView = container.findViewById(R.id.notification_message) private val icon: View = container.findViewById(R.id.notification_icon) - val notifications = InAppNotificationController { notification -> - if (notification != null) { - update(notification) - } + private var reversedAnimation = false - animateChange() + val notifications = InAppNotificationController { _ -> + synchronized(this@NotificationBanner) { + animateChange() + } } constructor(context: Context) : super(context) {} @@ -58,6 +96,8 @@ class NotificationBanner : FrameLayout { setOnClickListener { jobTracker.newUiJob("click") { onClick() } } + + visibility = View.INVISIBLE } fun onResume() { @@ -72,6 +112,10 @@ class NotificationBanner : FrameLayout { notifications.onDestroy() } + protected override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) { + animation.setFloatValues(-height.toFloat(), 0.0f) + } + private suspend fun onClick() { notifications.current?.onClick?.let { action -> alpha = 0.5f @@ -112,16 +156,20 @@ class NotificationBanner : FrameLayout { } private fun animateChange() { - val shouldShow = notifications.current != null + val notification = notifications.current - if (shouldShow && visibility == View.INVISIBLE) { - visibility = View.VISIBLE - translationY = -height.toFloat() - animate().translationY(0.0F).setDuration(350).start() - } else if (!shouldShow && visibility == View.VISIBLE) { - animate().translationY(-height.toFloat()).setDuration(350).withEndAction { - visibility = View.INVISIBLE - } + if (notification != null && visibility == View.INVISIBLE) { + // Banner is not currently shown but must be shown + reversedAnimation = false + update(notification) + animation.start() + } else if (visibility == View.VISIBLE && (!animation.isRunning() || !reversedAnimation)) { + // Either the banner is shown or it is in the process of being shown, but the + // notification must be hidden or replaced + reversedAnimation = true + animation.reverse() } + // If the banner is animating to be hidden, it will automatically start showing when the + // hide animation ends } } |
