summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-07-02 15:27:21 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-07-02 15:27:21 -0300
commit8b7a6fe8c352f06c7ec9d85a309ae747419778e7 (patch)
tree3532935d1fb486bbbb14860d9039fdf45fca27ad /android
parent5902ecb40a11332764fbdbb5f902868f5b75211e (diff)
parentbb6424199455898a0a9b026f70b29fd3cb885ebe (diff)
downloadmullvadvpn-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.kt76
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
}
}