improve auth screen login
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
package com.android.trisolarispms.ui.auth
|
package com.android.trisolarispms.ui.auth
|
||||||
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@@ -48,6 +51,10 @@ fun AuthScreen(viewModel: AuthViewModel = viewModel()) {
|
|||||||
val phoneCountries = remember { phoneCountryOptions() }
|
val phoneCountries = remember { phoneCountryOptions() }
|
||||||
val phoneCountrySearch = remember { mutableStateOf("") }
|
val phoneCountrySearch = remember { mutableStateOf("") }
|
||||||
val now = remember { mutableStateOf(System.currentTimeMillis()) }
|
val now = remember { mutableStateOf(System.currentTimeMillis()) }
|
||||||
|
val hasNetwork = remember(context, state.error) { hasInternetConnection(context) }
|
||||||
|
val noNetworkError = state.error?.contains("No internet connection", ignoreCase = true) == true
|
||||||
|
val isCheckingExistingSession = state.isLoading && !state.apiVerified && state.userId != null
|
||||||
|
val shouldHideAuthForm = !hasNetwork || noNetworkError || isCheckingExistingSession
|
||||||
|
|
||||||
LaunchedEffect(state.resendAvailableAt) {
|
LaunchedEffect(state.resendAvailableAt) {
|
||||||
while (state.resendAvailableAt != null) {
|
while (state.resendAvailableAt != null) {
|
||||||
@@ -56,6 +63,30 @@ fun AuthScreen(viewModel: AuthViewModel = viewModel()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldHideAuthForm) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(24.dp),
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
if (isCheckingExistingSession) {
|
||||||
|
Text(text = "Checking session...", style = MaterialTheme.typography.headlineSmall)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
CircularProgressIndicator()
|
||||||
|
} else {
|
||||||
|
Text(text = "No internet connection", style = MaterialTheme.typography.headlineSmall)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(text = "Please connect to the internet and try again.")
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Button(onClick = viewModel::retryAfterConnectivityIssue) {
|
||||||
|
Text("Retry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -200,12 +231,6 @@ fun AuthScreen(viewModel: AuthViewModel = viewModel()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.userId != null) {
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
Text(text = "Firebase user: ${state.userId}")
|
|
||||||
Text(text = "API verified: ${state.apiVerified}")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.noProperties) {
|
if (state.noProperties) {
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
Text(
|
Text(
|
||||||
@@ -215,3 +240,10 @@ fun AuthScreen(viewModel: AuthViewModel = viewModel()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun hasInternetConnection(context: Context): Boolean {
|
||||||
|
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager ?: return false
|
||||||
|
val network = cm.activeNetwork ?: return false
|
||||||
|
val capabilities = cm.getNetworkCapabilities(network) ?: return false
|
||||||
|
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.tasks.await
|
import kotlinx.coroutines.tasks.await
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import java.net.UnknownHostException
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class AuthViewModel(
|
class AuthViewModel(
|
||||||
@@ -68,6 +69,15 @@ class AuthViewModel(
|
|||||||
_state.update { it.copy(error = null) }
|
_state.update { it.copy(error = null) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun retryAfterConnectivityIssue() {
|
||||||
|
val currentUser = auth.currentUser
|
||||||
|
if (currentUser != null) {
|
||||||
|
verifyExistingSession(currentUser.uid)
|
||||||
|
} else {
|
||||||
|
clearError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun reportError(message: String) {
|
fun reportError(message: String) {
|
||||||
setError(message)
|
setError(message)
|
||||||
}
|
}
|
||||||
@@ -96,7 +106,7 @@ class AuthViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onVerificationFailed(e: FirebaseException) {
|
override fun onVerificationFailed(e: FirebaseException) {
|
||||||
setError(e.localizedMessage ?: "Verification failed")
|
setError(mapThrowableToMessage(e, fallback = "Verification failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCodeSent(
|
override fun onCodeSent(
|
||||||
@@ -168,7 +178,7 @@ class AuthViewModel(
|
|||||||
val response = api.verifyAuth()
|
val response = api.verifyAuth()
|
||||||
handleVerifyResponse(userId, response)
|
handleVerifyResponse(userId, response)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
setError(e.localizedMessage ?: "Sign-in failed")
|
setError(mapThrowableToMessage(e, fallback = "Sign-in failed"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,7 +210,7 @@ class AuthViewModel(
|
|||||||
val response = api.verifyAuth()
|
val response = api.verifyAuth()
|
||||||
handleVerifyResponse(userId, response)
|
handleVerifyResponse(userId, response)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
setError(e.localizedMessage ?: "Session verify failed")
|
setError(mapThrowableToMessage(e, fallback = "Session verify failed"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +261,7 @@ class AuthViewModel(
|
|||||||
noProperties = false,
|
noProperties = false,
|
||||||
unauthorized = false,
|
unauthorized = false,
|
||||||
propertyRoles = emptyMap(),
|
propertyRoles = emptyMap(),
|
||||||
error = "API verify failed: ${response.code()}"
|
error = mapHttpError(response.code(), "API verify failed")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,10 +319,10 @@ class AuthViewModel(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setError("Update failed: ${response.code()}")
|
setError(mapHttpError(response.code(), "Update failed"))
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
setError(e.localizedMessage ?: "Update failed")
|
setError(mapThrowableToMessage(e, fallback = "Update failed"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,4 +346,21 @@ class AuthViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun mapHttpError(code: Int, prefix: String): String {
|
||||||
|
return if (code >= 500) {
|
||||||
|
"Server down. Please try again."
|
||||||
|
} else {
|
||||||
|
"$prefix: $code"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mapThrowableToMessage(throwable: Throwable, fallback: String): String {
|
||||||
|
return when {
|
||||||
|
throwable is UnknownHostException -> "No internet connection."
|
||||||
|
throwable.localizedMessage?.contains("Unable to resolve host", ignoreCase = true) == true ->
|
||||||
|
"No internet connection."
|
||||||
|
else -> throwable.localizedMessage ?: fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user