Handle account UI login UI progress better

* Show server down error message on 503 status
* Don't allow users to click another login option if another login is in progress
* Reset progress bar's visibility properly

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2023-05-27 18:51:43 +05:30
parent 5ca8c74773
commit cd3cd6f9b7
7 changed files with 110 additions and 12 deletions

View File

@@ -27,6 +27,7 @@ import androidx.appcompat.app.AppCompatActivity
fun AppCompatActivity.close() { fun AppCompatActivity.close() {
setResult(AppCompatActivity.RESULT_OK)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
finishAfterTransition() finishAfterTransition()
} else { } else {

View File

@@ -127,6 +127,14 @@ fun Context.restartApp() {
exitProcess(0) exitProcess(0)
} }
fun Context.getEmptyActivityAnimation(): ActivityOptionsCompat {
return ActivityOptionsCompat.makeCustomAnimation(
this,
android.R.anim.fade_in,
android.R.anim.fade_out
)
}
fun Context.getEmptyActivityBundle(): Bundle? { fun Context.getEmptyActivityBundle(): Bundle? {
return ActivityOptionsCompat.makeCustomAnimation( return ActivityOptionsCompat.makeCustomAnimation(
this, this,

View File

@@ -40,5 +40,6 @@ sealed class AuthState {
object SignedIn : AuthState() object SignedIn : AuthState()
object SignedOut : AuthState() object SignedOut : AuthState()
object Valid : AuthState() object Valid : AuthState()
object Fetching: AuthState()
data class Status(val status: String?) : AuthState() data class Status(val status: String?) : AuthState()
} }

View File

@@ -19,11 +19,14 @@
package com.aurora.store.view.ui.account package com.aurora.store.view.ui.account
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.aurora.extensions.browse import com.aurora.extensions.browse
import com.aurora.extensions.close import com.aurora.extensions.close
import com.aurora.extensions.getEmptyActivityAnimation
import com.aurora.extensions.load import com.aurora.extensions.load
import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.AuthData
import com.aurora.store.R import com.aurora.store.R
@@ -32,6 +35,7 @@ import com.aurora.store.data.event.BusEvent
import com.aurora.store.data.providers.AccountProvider import com.aurora.store.data.providers.AccountProvider
import com.aurora.store.data.providers.AuthProvider import com.aurora.store.data.providers.AuthProvider
import com.aurora.store.databinding.ActivityAccountBinding import com.aurora.store.databinding.ActivityAccountBinding
import com.aurora.store.util.Preferences
import com.aurora.store.view.ui.commons.BaseActivity import com.aurora.store.view.ui.commons.BaseActivity
import com.aurora.store.viewmodel.auth.AuthViewModel import com.aurora.store.viewmodel.auth.AuthViewModel
import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.bitmap.RoundedCorners
@@ -53,6 +57,15 @@ class AccountActivity : BaseActivity() {
private val URL_LICENSE = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/LICENSE" private val URL_LICENSE = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/LICENSE"
private val URL_DISCLAIMER = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/DISCLAIMER.md" private val URL_DISCLAIMER = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/DISCLAIMER.md"
private val startForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_CANCELED) {
resetActions()
} else {
B.btnGoogle.updateProgress(true)
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -74,6 +87,9 @@ class AccountActivity : BaseActivity() {
VM.liveData.observe(this) { VM.liveData.observe(this) {
when (it) { when (it) {
AuthState.Fetching -> {
updateStatus(getString(R.string.requesting_new_session))
}
AuthState.Valid -> { AuthState.Valid -> {
} }
@@ -99,6 +115,7 @@ class AccountActivity : BaseActivity() {
is AuthState.Status -> { is AuthState.Status -> {
updateStatus(it.status) updateStatus(it.status)
resetActions()
} }
} }
} }
@@ -173,13 +190,19 @@ class AccountActivity : BaseActivity() {
B.btnGoogle.updateProgress(false) B.btnGoogle.updateProgress(false)
B.btnAnonymous.addOnClickListener { B.btnAnonymous.addOnClickListener {
B.btnAnonymous.updateProgress(true) if (VM.liveData.value != AuthState.Fetching) {
VM.buildAnonymousAuthData() B.btnAnonymous.updateProgress(true)
VM.buildAnonymousAuthData()
}
} }
B.btnGoogle.addOnClickListener { B.btnGoogle.addOnClickListener {
B.btnGoogle.updateProgress(true) if (VM.liveData.value != AuthState.Fetching) {
openGoogleActivity() B.btnGoogle.updateProgress(true)
Preferences.putBoolean(this, Preferences.PREFERENCE_ADVANCED_SEARCH_IN_CTT, false)
val intent = Intent(this, GoogleActivity::class.java)
startForResult.launch(intent, getEmptyActivityAnimation())
}
} }
B.btnLogout.addOnClickListener { B.btnLogout.addOnClickListener {
@@ -195,6 +218,18 @@ class AccountActivity : BaseActivity() {
} }
} }
private fun resetActions() {
B.btnGoogle.apply {
updateProgress(false)
isEnabled = true
}
B.btnAnonymous.apply {
updateProgress(false)
isEnabled = true
}
}
private fun updateUserProfile() { private fun updateUserProfile() {
authData = AuthProvider.with(this).getAuthData() authData = AuthProvider.with(this).getAuthData()

View File

@@ -19,10 +19,13 @@
package com.aurora.store.view.ui.splash package com.aurora.store.view.ui.splash
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.aurora.extensions.getEmptyActivityAnimation
import com.aurora.extensions.hide import com.aurora.extensions.hide
import com.aurora.extensions.load import com.aurora.extensions.load
import com.aurora.extensions.open import com.aurora.extensions.open
@@ -32,7 +35,9 @@ import com.aurora.store.R
import com.aurora.store.data.AuthState import com.aurora.store.data.AuthState
import com.aurora.store.data.event.BusEvent import com.aurora.store.data.event.BusEvent
import com.aurora.store.databinding.ActivitySplashBinding import com.aurora.store.databinding.ActivitySplashBinding
import com.aurora.store.util.Preferences
import com.aurora.store.view.ui.account.AccountActivity import com.aurora.store.view.ui.account.AccountActivity
import com.aurora.store.view.ui.account.GoogleActivity
import com.aurora.store.view.ui.commons.BaseActivity import com.aurora.store.view.ui.commons.BaseActivity
import com.aurora.store.view.ui.commons.BlacklistActivity import com.aurora.store.view.ui.commons.BlacklistActivity
import com.aurora.store.view.ui.preferences.SettingsActivity import com.aurora.store.view.ui.preferences.SettingsActivity
@@ -47,6 +52,15 @@ class SplashActivity : BaseActivity() {
private lateinit var VM: AuthViewModel private lateinit var VM: AuthViewModel
private lateinit var B: ActivitySplashBinding private lateinit var B: ActivitySplashBinding
private val startForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_CANCELED) {
resetActions()
} else {
B.btnGoogle.updateProgress(true)
}
}
override fun onConnected() { override fun onConnected() {
hideNetworkConnectivitySheet() hideNetworkConnectivitySheet()
} }
@@ -81,6 +95,9 @@ class SplashActivity : BaseActivity() {
VM.liveData.observe(this) { VM.liveData.observe(this) {
when (it) { when (it) {
AuthState.Fetching -> {
updateStatus(getString(R.string.requesting_new_session))
}
AuthState.Valid -> { AuthState.Valid -> {
moveToContent() moveToContent()
} }
@@ -106,6 +123,7 @@ class SplashActivity : BaseActivity() {
is AuthState.Status -> { is AuthState.Status -> {
updateStatus(it.status) updateStatus(it.status)
resetActions()
} }
} }
} }
@@ -194,18 +212,43 @@ class SplashActivity : BaseActivity() {
private fun attachActions() { private fun attachActions() {
B.btnAnonymous.addOnClickListener { B.btnAnonymous.addOnClickListener {
B.btnAnonymous.updateProgress(true) if (VM.liveData.value != AuthState.Fetching) {
VM.buildAnonymousAuthData() B.btnAnonymous.updateProgress(true)
VM.buildAnonymousAuthData()
}
} }
B.btnAnonymousInsecure.addOnClickListener { B.btnAnonymousInsecure.addOnClickListener {
B.btnAnonymousInsecure.updateProgress(true) if (VM.liveData.value != AuthState.Fetching) {
VM.buildInSecureAnonymousAuthData() B.btnAnonymousInsecure.updateProgress(true)
VM.buildInSecureAnonymousAuthData()
}
} }
B.btnGoogle.addOnClickListener { B.btnGoogle.addOnClickListener {
B.btnGoogle.updateProgress(true) if (VM.liveData.value != AuthState.Fetching) {
openGoogleActivity() B.btnGoogle.updateProgress(true)
Preferences.putBoolean(this, Preferences.PREFERENCE_ADVANCED_SEARCH_IN_CTT, false)
val intent = Intent(this, GoogleActivity::class.java)
startForResult.launch(intent, getEmptyActivityAnimation())
}
}
}
private fun resetActions() {
B.btnGoogle.apply {
updateProgress(false)
isEnabled = true
}
B.btnAnonymous.apply {
updateProgress(false)
isEnabled = true
}
B.btnAnonymousInsecure.apply {
updateProgress(false)
isEnabled = true
} }
} }

View File

@@ -20,6 +20,7 @@
package com.aurora.store.viewmodel.auth package com.aurora.store.viewmodel.auth
import android.app.Application import android.app.Application
import android.content.Context
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.aurora.Constants import com.aurora.Constants
@@ -28,6 +29,7 @@ import com.aurora.gplayapi.data.providers.DeviceInfoProvider
import com.aurora.gplayapi.helpers.AuthHelper import com.aurora.gplayapi.helpers.AuthHelper
import com.aurora.gplayapi.helpers.AuthValidator import com.aurora.gplayapi.helpers.AuthValidator
import com.aurora.store.AccountType import com.aurora.store.AccountType
import com.aurora.store.R
import com.aurora.store.data.AuthState import com.aurora.store.data.AuthState
import com.aurora.store.data.RequestState import com.aurora.store.data.RequestState
import com.aurora.store.data.model.InsecureAuth import com.aurora.store.data.model.InsecureAuth
@@ -102,7 +104,7 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application
} }
private fun buildSecureAnonymousAuthData() { private fun buildSecureAnonymousAuthData() {
updateStatus("Requesting new session") liveData.postValue(AuthState.Fetching)
task { task {
var properties = NativeDeviceInfoProvider(getApplication()) var properties = NativeDeviceInfoProvider(getApplication())
@@ -127,6 +129,9 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application
when (playResponse.code) { when (playResponse.code) {
404 -> throw Exception("Server unreachable") 404 -> throw Exception("Server unreachable")
429 -> throw Exception("Oops, You are rate limited") 429 -> throw Exception("Oops, You are rate limited")
503 -> throw Exception(
(getApplication() as Context).getString(R.string.server_maintenance)
)
else -> throw Exception(playResponse.errorString) else -> throw Exception(playResponse.errorString)
} }
} }
@@ -140,7 +145,7 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application
} }
fun buildInSecureAnonymousAuthData() { fun buildInSecureAnonymousAuthData() {
updateStatus("Requesting new session") liveData.postValue(AuthState.Fetching)
task { task {
var properties = NativeDeviceInfoProvider(getApplication()) var properties = NativeDeviceInfoProvider(getApplication())
@@ -166,6 +171,9 @@ class AuthViewModel(application: Application) : BaseAndroidViewModel(application
when (playResponse.code) { when (playResponse.code) {
404 -> throw Exception("Server unreachable") 404 -> throw Exception("Server unreachable")
429 -> throw Exception("Oops, You are rate limited") 429 -> throw Exception("Oops, You are rate limited")
503 -> throw Exception(
(getApplication() as Context).getString(R.string.server_maintenance)
)
else -> throw Exception(playResponse.errorString) else -> throw Exception(playResponse.errorString)
} }
} }

View File

@@ -349,4 +349,6 @@
<string name="spoof_property"><xliff:g id="manufacturer">%1$s</xliff:g> • API <xliff:g id="api">%2$s</xliff:g></string> <string name="spoof_property"><xliff:g id="manufacturer">%1$s</xliff:g> • API <xliff:g id="api">%2$s</xliff:g></string>
<string name="permissions_denied">Required permissions were denied. Please grant them in order to continue the action</string> <string name="permissions_denied">Required permissions were denied. Please grant them in order to continue the action</string>
<string name="search_hint">Search for Apps &amp; Games</string> <string name="search_hint">Search for Apps &amp; Games</string>
<string name="requesting_new_session">Requesting new session</string>
<string name="server_maintenance">Server down for maintenance</string>
</resources> </resources>