improve auth screen login

This commit is contained in:
androidlover5842
2026-02-02 06:29:49 +05:30
parent 8c790fbce0
commit d54a9af5ee
2 changed files with 71 additions and 12 deletions

View File

@@ -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)
}

View File

@@ -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
}
}
} }