Unverified Commit 2625c52c authored by Hussein El Feky's avatar Hussein El Feky Committed by GitHub

Added animation when expanding/collapsing login options

parent acb0f6f3
package chat.rocket.android.authentication.loginoptions.ui package chat.rocket.android.authentication.loginoptions.ui
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.PorterDuff import android.graphics.PorterDuff
...@@ -7,10 +10,13 @@ import android.os.Bundle ...@@ -7,10 +10,13 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.widget.Button import android.widget.Button
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.appcompat.view.ContextThemeWrapper import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.marginTop
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager import chat.rocket.android.analytics.AnalyticsManager
...@@ -62,32 +68,32 @@ internal const val REQUEST_CODE_FOR_CAS = 2 ...@@ -62,32 +68,32 @@ internal const val REQUEST_CODE_FOR_CAS = 2
internal const val REQUEST_CODE_FOR_SAML = 3 internal const val REQUEST_CODE_FOR_SAML = 3
fun newInstance( fun newInstance(
serverName: String, serverName: String,
state: String? = null, state: String? = null,
facebookOauthUrl: String? = null, facebookOauthUrl: String? = null,
githubOauthUrl: String? = null, githubOauthUrl: String? = null,
googleOauthUrl: String? = null, googleOauthUrl: String? = null,
linkedinOauthUrl: String? = null, linkedinOauthUrl: String? = null,
gitlabOauthUrl: String? = null, gitlabOauthUrl: String? = null,
wordpressOauthUrl: String? = null, wordpressOauthUrl: String? = null,
casLoginUrl: String? = null, casLoginUrl: String? = null,
casToken: String? = null, casToken: String? = null,
casServiceName: String? = null, casServiceName: String? = null,
casServiceNameTextColor: Int = 0, casServiceNameTextColor: Int = 0,
casServiceButtonColor: Int = 0, casServiceButtonColor: Int = 0,
customOauthUrl: String? = null, customOauthUrl: String? = null,
customOauthServiceName: String? = null, customOauthServiceName: String? = null,
customOauthServiceNameTextColor: Int = 0, customOauthServiceNameTextColor: Int = 0,
customOauthServiceButtonColor: Int = 0, customOauthServiceButtonColor: Int = 0,
samlUrl: String? = null, samlUrl: String? = null,
samlToken: String? = null, samlToken: String? = null,
samlServiceName: String? = null, samlServiceName: String? = null,
samlServiceNameTextColor: Int = 0, samlServiceNameTextColor: Int = 0,
samlServiceButtonColor: Int = 0, samlServiceButtonColor: Int = 0,
totalSocialAccountsEnabled: Int = 0, totalSocialAccountsEnabled: Int = 0,
isLoginFormEnabled: Boolean, isLoginFormEnabled: Boolean,
isNewAccountCreationEnabled: Boolean, isNewAccountCreationEnabled: Boolean,
deepLinkInfo: LoginDeepLinkInfo? = null deepLinkInfo: LoginDeepLinkInfo? = null
): Fragment = LoginOptionsFragment().apply { ): Fragment = LoginOptionsFragment().apply {
arguments = Bundle(23).apply { arguments = Bundle(23).apply {
putString(SERVER_NAME, serverName) putString(SERVER_NAME, serverName)
...@@ -186,9 +192,9 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -186,9 +192,9 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
} }
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_authentication_login_options) ): View? = container?.inflate(R.layout.fragment_authentication_login_options)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...@@ -253,11 +259,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -253,11 +259,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
private fun setupCas() { private fun setupCas() {
if (casLoginUrl != null && casToken != null && casServiceName != null) { if (casLoginUrl != null && casToken != null && casServiceName != null) {
addCasButton( addCasButton(
casLoginUrl.toString(), casLoginUrl.toString(),
casToken.toString(), casToken.toString(),
casServiceName.toString(), casServiceName.toString(),
casServiceNameTextColor, casServiceNameTextColor,
casServiceButtonColor casServiceButtonColor
) )
} }
} }
...@@ -265,11 +271,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -265,11 +271,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
private fun setupCustomOauth() { private fun setupCustomOauth() {
if (customOauthUrl != null && state != null && customOauthServiceName != null) { if (customOauthUrl != null && state != null && customOauthServiceName != null) {
addCustomOauthButton( addCustomOauthButton(
customOauthUrl.toString(), customOauthUrl.toString(),
state.toString(), state.toString(),
customOauthServiceName.toString(), customOauthServiceName.toString(),
customOauthServiceTextColor, customOauthServiceTextColor,
customOauthServiceButtonColor customOauthServiceButtonColor
) )
} }
} }
...@@ -277,11 +283,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -277,11 +283,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
private fun setupSaml() { private fun setupSaml() {
if (samlUrl != null && samlToken != null && samlServiceName != null) { if (samlUrl != null && samlToken != null && samlServiceName != null) {
addSamlButton( addSamlButton(
samlUrl.toString(), samlUrl.toString(),
samlToken.toString(), samlToken.toString(),
samlServiceName.toString(), samlServiceName.toString(),
samlServiceTextColor, samlServiceTextColor,
samlServiceButtonColor samlServiceButtonColor
) )
} }
} }
...@@ -311,40 +317,40 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -311,40 +317,40 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
override fun enableLoginByFacebook() = enableAccountButton(button_facebook) override fun enableLoginByFacebook() = enableAccountButton(button_facebook)
override fun setupFacebookButtonListener(facebookOauthUrl: String, state: String) = override fun setupFacebookButtonListener(facebookOauthUrl: String, state: String) =
setupButtonListener(button_facebook, facebookOauthUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button_facebook, facebookOauthUrl, state, REQUEST_CODE_FOR_OAUTH)
override fun enableLoginByGithub() = enableAccountButton(button_github) override fun enableLoginByGithub() = enableAccountButton(button_github)
override fun setupGithubButtonListener(githubUrl: String, state: String) = override fun setupGithubButtonListener(githubUrl: String, state: String) =
setupButtonListener(button_github, githubUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button_github, githubUrl, state, REQUEST_CODE_FOR_OAUTH)
override fun enableLoginByGoogle() = enableAccountButton(button_google) override fun enableLoginByGoogle() = enableAccountButton(button_google)
override fun setupGoogleButtonListener(googleUrl: String, state: String) = override fun setupGoogleButtonListener(googleUrl: String, state: String) =
setupButtonListener(button_google, googleUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button_google, googleUrl, state, REQUEST_CODE_FOR_OAUTH)
override fun enableLoginByLinkedin() = enableAccountButton(button_linkedin) override fun enableLoginByLinkedin() = enableAccountButton(button_linkedin)
override fun setupLinkedinButtonListener(linkedinUrl: String, state: String) = override fun setupLinkedinButtonListener(linkedinUrl: String, state: String) =
setupButtonListener(button_linkedin, linkedinUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button_linkedin, linkedinUrl, state, REQUEST_CODE_FOR_OAUTH)
override fun enableLoginByGitlab() = enableAccountButton(button_gitlab) override fun enableLoginByGitlab() = enableAccountButton(button_gitlab)
override fun setupGitlabButtonListener(gitlabUrl: String, state: String) = override fun setupGitlabButtonListener(gitlabUrl: String, state: String) =
setupButtonListener(button_gitlab, gitlabUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button_gitlab, gitlabUrl, state, REQUEST_CODE_FOR_OAUTH)
override fun enableLoginByWordpress() = enableAccountButton(button_wordpress) override fun enableLoginByWordpress() = enableAccountButton(button_wordpress)
override fun setupWordpressButtonListener(wordpressUrl: String, state: String) = override fun setupWordpressButtonListener(wordpressUrl: String, state: String) =
setupButtonListener(button_wordpress, wordpressUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button_wordpress, wordpressUrl, state, REQUEST_CODE_FOR_OAUTH)
// CAS service account. // CAS service account.
override fun addCasButton( override fun addCasButton(
caslUrl: String, caslUrl: String,
casToken: String, casToken: String,
serviceName: String, serviceName: String,
serviceNameColor: Int, serviceNameColor: Int,
buttonColor: Int buttonColor: Int
) { ) {
val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor) val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor)
setupButtonListener(button, caslUrl, casToken, REQUEST_CODE_FOR_CAS) setupButtonListener(button, caslUrl, casToken, REQUEST_CODE_FOR_CAS)
...@@ -353,11 +359,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -353,11 +359,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
// Custom OAuth account. // Custom OAuth account.
override fun addCustomOauthButton( override fun addCustomOauthButton(
customOauthUrl: String, customOauthUrl: String,
state: String, state: String,
serviceName: String, serviceName: String,
serviceNameColor: Int, serviceNameColor: Int,
buttonColor: Int buttonColor: Int
) { ) {
val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor) val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor)
setupButtonListener(button, customOauthUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button, customOauthUrl, state, REQUEST_CODE_FOR_OAUTH)
...@@ -366,11 +372,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -366,11 +372,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
// SAML account. // SAML account.
override fun addSamlButton( override fun addSamlButton(
samlUrl: String, samlUrl: String,
samlToken: String, samlToken: String,
serviceName: String, serviceName: String,
serviceNameColor: Int, serviceNameColor: Int,
buttonColor: Int buttonColor: Int
) { ) {
val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor) val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor)
setupButtonListener(button, samlUrl, samlToken, REQUEST_CODE_FOR_SAML) setupButtonListener(button, samlUrl, samlToken, REQUEST_CODE_FOR_SAML)
...@@ -421,12 +427,12 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -421,12 +427,12 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
when (requestCode) { when (requestCode) {
REQUEST_CODE_FOR_OAUTH -> { REQUEST_CODE_FOR_OAUTH -> {
presenter.authenticateWithOauth( presenter.authenticateWithOauth(
data.getStringExtra(INTENT_OAUTH_CREDENTIAL_TOKEN), data.getStringExtra(INTENT_OAUTH_CREDENTIAL_TOKEN),
data.getStringExtra(INTENT_OAUTH_CREDENTIAL_SECRET) data.getStringExtra(INTENT_OAUTH_CREDENTIAL_SECRET)
) )
} }
REQUEST_CODE_FOR_CAS -> presenter.authenticateWithCas( REQUEST_CODE_FOR_CAS -> presenter.authenticateWithCas(
data.getStringExtra(INTENT_SSO_TOKEN) data.getStringExtra(INTENT_SSO_TOKEN)
) )
REQUEST_CODE_FOR_SAML -> data.apply { REQUEST_CODE_FOR_SAML -> data.apply {
presenter.authenticateWithSaml(getStringExtra(INTENT_SSO_TOKEN)) presenter.authenticateWithSaml(getStringExtra(INTENT_SSO_TOKEN))
...@@ -470,22 +476,22 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -470,22 +476,22 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
} }
private fun setupButtonListener( private fun setupButtonListener(
button: Button, button: Button,
accountUrl: String, accountUrl: String,
argument: String, argument: String,
requestCode: Int requestCode: Int
) { ) {
ui { activity -> ui { activity ->
button.setOnClickListener { button.setOnClickListener {
when (requestCode) { when (requestCode) {
REQUEST_CODE_FOR_OAUTH -> startActivityForResult( REQUEST_CODE_FOR_OAUTH -> startActivityForResult(
activity.oauthWebViewIntent(accountUrl, argument), REQUEST_CODE_FOR_OAUTH activity.oauthWebViewIntent(accountUrl, argument), REQUEST_CODE_FOR_OAUTH
) )
REQUEST_CODE_FOR_CAS -> startActivityForResult( REQUEST_CODE_FOR_CAS -> startActivityForResult(
activity.ssoWebViewIntent(accountUrl, argument), REQUEST_CODE_FOR_CAS activity.ssoWebViewIntent(accountUrl, argument), REQUEST_CODE_FOR_CAS
) )
REQUEST_CODE_FOR_SAML -> startActivityForResult( REQUEST_CODE_FOR_SAML -> startActivityForResult(
activity.ssoWebViewIntent(accountUrl, argument), REQUEST_CODE_FOR_SAML activity.ssoWebViewIntent(accountUrl, argument), REQUEST_CODE_FOR_SAML
) )
} }
...@@ -498,22 +504,22 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -498,22 +504,22 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
* Gets a stylized custom service button. * Gets a stylized custom service button.
*/ */
private fun getCustomServiceButton( private fun getCustomServiceButton(
buttonText: String, buttonText: String,
buttonTextColor: Int, buttonTextColor: Int,
buttonBgColor: Int buttonBgColor: Int
): Button { ): Button {
val params: LinearLayout.LayoutParams = LinearLayout.LayoutParams( val params: LinearLayout.LayoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT LinearLayout.LayoutParams.WRAP_CONTENT
) )
val marginTop = resources.getDimensionPixelSize(R.dimen.button_account_margin_top) val marginTop = resources.getDimensionPixelSize(R.dimen.button_account_margin_top)
params.setMargins(0, marginTop, 0, 0) params.setMargins(0, marginTop, 0, 0)
val button = Button( val button = Button(
ContextThemeWrapper(context, R.style.Authentication_Button), ContextThemeWrapper(context, R.style.Authentication_Button),
null, null,
R.style.Authentication_Button R.style.Authentication_Button
) )
button.layoutParams = params button.layoutParams = params
button.text = buttonText button.text = buttonText
...@@ -525,24 +531,87 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -525,24 +531,87 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
private fun showThreeAccountsMethods() { private fun showThreeAccountsMethods() {
(0..accounts_container.childCount) (0..accounts_container.childCount)
.mapNotNull { accounts_container.getChildAt(it) as? Button } .mapNotNull { accounts_container.getChildAt(it) as? Button }
.filter { it.isClickable } .filter { it.isClickable }
.take(3) .take(3)
.forEach { it.isVisible = true } .forEach { it.isVisible = true }
} }
private fun expandAccountsView() { private fun expandAccountsView() {
(0..accounts_container.childCount) val collapsedHeight = accounts_container.height
.mapNotNull { accounts_container.getChildAt(it) as? Button } var expandedHeight = collapsedHeight
.filter { it.isClickable && !it.isVisible } val optionHeight = accounts_container.getChildAt(1).height +
.forEach { it.isVisible = true } accounts_container.getChildAt(1).marginTop
for (i in 0 until accounts_container.childCount) {
val bt = accounts_container.getChildAt(i) as Button
if (bt.isClickable && !bt.isVisible) {
expandedHeight += optionHeight
}
}
val animation = ValueAnimator.ofInt(collapsedHeight, expandedHeight)
animation.addUpdateListener {
val params = accounts_container.layoutParams
params.height = animation.animatedValue as Int
accounts_container.layoutParams = params
}
animation.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animator: Animator) {
for (i in 0 until accounts_container.childCount) {
val bt = accounts_container.getChildAt(i) as Button
if (!bt.isVisible) {
bt.isVisible = true
val anim = AlphaAnimation(0.0f, 1.0f)
anim.duration = 400
bt.startAnimation(anim)
}
}
}
})
animation.setDuration(400).start()
} }
private fun collapseAccountsView() { private fun collapseAccountsView() {
(0..accounts_container.childCount) val expandedHeight = accounts_container.height
.mapNotNull { accounts_container.getChildAt(it) as? Button } var collapsedHeight = expandedHeight
.filter { it.isClickable && it.isVisible } val optionHeight = accounts_container.getChildAt(1).height +
.drop(3) accounts_container.getChildAt(1).marginTop
.forEach { it.isVisible = false } for (i in 3 until accounts_container.childCount) {
val bt = accounts_container.getChildAt(i) as Button
if (bt.isClickable && bt.isVisible) {
collapsedHeight -= optionHeight
}
}
val animation = ValueAnimator.ofInt(expandedHeight, collapsedHeight)
animation.addUpdateListener {
val params = accounts_container.layoutParams
params.height = animation.animatedValue as Int
accounts_container.layoutParams = params
}
animation.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animator: Animator) {
for (i in 3 until accounts_container.childCount) {
val bt = accounts_container.getChildAt(i) as Button
if (bt.isVisible) {
val anim = AlphaAnimation(1.0f, 0.0f)
anim.duration = 400
anim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {
}
override fun onAnimationEnd(animation: Animation) {
bt.isVisible = false
}
override fun onAnimationRepeat(animation: Animation) {
}
})
bt.startAnimation(anim)
}
}
}
})
animation.setDuration(400).start()
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment