feat: display login errors and allow try again

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2024-12-21 20:56:03 +01:00
parent fe082dc5f2
commit 3c2556872c
2 changed files with 71 additions and 15 deletions

View File

@ -17,8 +17,11 @@ import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
@ -27,6 +30,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
@ -99,6 +103,7 @@ class MainActivityViewModel @Inject constructor(
val nextDestination = MutableStateFlow<String?>(null) val nextDestination = MutableStateFlow<String?>(null)
var isConnected = MutableStateFlow(false) var isConnected = MutableStateFlow(false)
val isReady = MutableStateFlow(false) val isReady = MutableStateFlow(false)
val couldNotLogIn = MutableStateFlow(false)
private fun hasInternetConnection(): Boolean { private fun hasInternetConnection(): Boolean {
val connectivityManager = val connectivityManager =
@ -174,15 +179,8 @@ class MainActivityViewModel @Inject constructor(
} }
if (canReachRevolt && !valid) { if (canReachRevolt && !valid) {
Log.d("MainActivity", "Session token is invalid, clearing session") Log.d("MainActivity", "Session token is invalid, could not log in")
Toast.makeText( couldNotLogIn.emit(true)
context,
context.getString(R.string.token_invalid_toast),
Toast.LENGTH_SHORT
).show()
kvStorage.remove("sessionToken")
kvStorage.remove("sessionId")
startWithDestination("login/greeting")
} else { } else {
try { try {
Log.d("MainActivity", "Session token is valid, checking onboarding state") Log.d("MainActivity", "Session token is valid, checking onboarding state")
@ -201,25 +199,32 @@ class MainActivityViewModel @Inject constructor(
).show() ).show()
return@launch startWithoutDestination() return@launch startWithoutDestination()
} catch (e: Exception) { } catch (e: Exception) {
Log.e("MainActivity", "Failed to check onboarding state, clearing session", e) Log.e("MainActivity", "Failed to check onboarding state, could not log in", e)
startWithDestination("login/greeting") couldNotLogIn.emit(true)
} }
try { try {
Log.d("MainActivity", "Onboarding state is complete, logging in") Log.d("MainActivity", "Onboarding state is complete, logging in")
throw Exception("Test")
RevoltAPI.loginAs(token) RevoltAPI.loginAs(token)
RevoltAPI.setSessionId(id) RevoltAPI.setSessionId(id)
startWithDestination("chat") startWithDestination("chat")
} catch (e: Exception) { } catch (e: Exception) {
Log.e("MainActivity", "Failed to login, clearing session", e) Log.e("MainActivity", "Failed to login, could not log in", e)
kvStorage.remove("sessionToken") couldNotLogIn.emit(true)
kvStorage.remove("sessionId")
startWithDestination("login/greeting")
} }
} }
} }
} }
fun logOut() {
viewModelScope.launch {
kvStorage.remove("sessionToken")
kvStorage.remove("sessionId")
startWithDestination("login/greeting")
}
}
fun updateNextDestination(destination: String) { fun updateNextDestination(destination: String) {
viewModelScope.launch { viewModelScope.launch {
nextDestination.emit(null) nextDestination.emit(null)
@ -251,6 +256,12 @@ class MainActivityViewModel @Inject constructor(
} }
} }
fun onDismissLoginError() {
viewModelScope.launch {
couldNotLogIn.emit(false)
}
}
init { init {
Log.d("MainActivity", "Starting up") Log.d("MainActivity", "Starting up")
doPreStartupTasks() doPreStartupTasks()
@ -307,7 +318,10 @@ class MainActivity : AppCompatActivity() {
viewModel.isConnected.collectAsState().value, viewModel.isConnected.collectAsState().value,
viewModel.activeAlert.collectAsState().value, viewModel.activeAlert.collectAsState().value,
viewModel.isAlertActive.collectAsState().value, viewModel.isAlertActive.collectAsState().value,
viewModel.couldNotLogIn.collectAsState().value,
viewModel::logOut,
viewModel::onDismissHealthAlert, viewModel::onDismissHealthAlert,
viewModel::onDismissLoginError,
viewModel::checkLoggedInState, viewModel::checkLoggedInState,
viewModel::updateNextDestination viewModel::updateNextDestination
) )
@ -336,7 +350,10 @@ fun AppEntrypoint(
isConnected: Boolean, isConnected: Boolean,
healthNotice: HealthNotice?, healthNotice: HealthNotice?,
isHealthAlertActive: Boolean, isHealthAlertActive: Boolean,
couldNotLogIn: Boolean,
onLogout: () -> Unit = {},
onDismissHealthAlert: () -> Unit = {}, onDismissHealthAlert: () -> Unit = {},
onDismissLoginError: () -> Unit = {},
onRetryConnection: () -> Unit, onRetryConnection: () -> Unit,
onUpdateNextDestination: (String) -> Unit = {} onUpdateNextDestination: (String) -> Unit = {}
) { ) {
@ -357,6 +374,40 @@ fun AppEntrypoint(
} }
} }
if (couldNotLogIn) {
AlertDialog(
onDismissRequest = {
// no-op
},
title = {
Text(stringResource(R.string.could_not_log_in_heading))
},
text = {
Text(stringResource(R.string.could_not_log_in_body))
},
confirmButton = {
TextButton(
onClick = {
onDismissLoginError()
onRetryConnection()
}
) {
Text(stringResource(R.string.could_not_log_in_cta_try_again))
}
},
dismissButton = {
TextButton(
onClick = {
onDismissLoginError()
onLogout()
}
) {
Text(stringResource(R.string.could_not_log_in_cta_logout))
}
}
)
}
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = "default", startDestination = "default",

View File

@ -33,6 +33,11 @@
<string name="service_health_alert_actions_default">Learn more</string> <string name="service_health_alert_actions_default">Learn more</string>
<string name="service_health_alert_actions_dismiss">Dismiss</string> <string name="service_health_alert_actions_dismiss">Dismiss</string>
<string name="could_not_log_in_heading">There was a problem logging you in</string>
<string name="could_not_log_in_body">You might have logged out from another device, or your internet connection might be down.</string>
<string name="could_not_log_in_cta_try_again">Try again</string>
<string name="could_not_log_in_cta_logout">Log out</string>
<string name="login_heading">Let\'s log you in</string> <string name="login_heading">Let\'s log you in</string>
<string name="password_forgot">Forgot password?</string> <string name="password_forgot">Forgot password?</string>
<string name="resend_verification">Resend a verification email</string> <string name="resend_verification">Resend a verification email</string>