improve auth screen login
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package com.android.trisolarispms.ui.auth
|
||||
|
||||
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.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -48,6 +51,10 @@ fun AuthScreen(viewModel: AuthViewModel = viewModel()) {
|
||||
val phoneCountries = remember { phoneCountryOptions() }
|
||||
val phoneCountrySearch = remember { mutableStateOf("") }
|
||||
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) {
|
||||
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(
|
||||
modifier = Modifier
|
||||
.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) {
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
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.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import java.net.UnknownHostException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class AuthViewModel(
|
||||
@@ -68,6 +69,15 @@ class AuthViewModel(
|
||||
_state.update { it.copy(error = null) }
|
||||
}
|
||||
|
||||
fun retryAfterConnectivityIssue() {
|
||||
val currentUser = auth.currentUser
|
||||
if (currentUser != null) {
|
||||
verifyExistingSession(currentUser.uid)
|
||||
} else {
|
||||
clearError()
|
||||
}
|
||||
}
|
||||
|
||||
fun reportError(message: String) {
|
||||
setError(message)
|
||||
}
|
||||
@@ -96,7 +106,7 @@ class AuthViewModel(
|
||||
}
|
||||
|
||||
override fun onVerificationFailed(e: FirebaseException) {
|
||||
setError(e.localizedMessage ?: "Verification failed")
|
||||
setError(mapThrowableToMessage(e, fallback = "Verification failed"))
|
||||
}
|
||||
|
||||
override fun onCodeSent(
|
||||
@@ -168,7 +178,7 @@ class AuthViewModel(
|
||||
val response = api.verifyAuth()
|
||||
handleVerifyResponse(userId, response)
|
||||
} 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()
|
||||
handleVerifyResponse(userId, response)
|
||||
} catch (e: Exception) {
|
||||
setError(e.localizedMessage ?: "Session verify failed")
|
||||
setError(mapThrowableToMessage(e, fallback = "Session verify failed"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,7 +261,7 @@ class AuthViewModel(
|
||||
noProperties = false,
|
||||
unauthorized = false,
|
||||
propertyRoles = emptyMap(),
|
||||
error = "API verify failed: ${response.code()}"
|
||||
error = mapHttpError(response.code(), "API verify failed")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -309,10 +319,10 @@ class AuthViewModel(
|
||||
)
|
||||
}
|
||||
} else {
|
||||
setError("Update failed: ${response.code()}")
|
||||
setError(mapHttpError(response.code(), "Update failed"))
|
||||
}
|
||||
} 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