Browse Source

Improve error management on login screens

feature/bma/flipper
Benoit Marty 2 years ago
parent
commit
b1ad191740
  1. 1
      features/login/build.gradle.kts
  2. 9
      features/login/src/main/java/io/element/android/x/features/login/LoginScreen.kt
  3. 3
      features/login/src/main/java/io/element/android/x/features/login/LoginViewModel.kt
  4. 14
      features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerScreen.kt
  5. 6
      features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewModel.kt
  6. 33
      features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt
  7. 31
      libraries/core/src/main/java/io/element/android/x/core/uri/UrlUtils.kt

1
features/login/build.gradle.kts

@ -10,6 +10,7 @@ dependencies { @@ -10,6 +10,7 @@ dependencies {
implementation(project(":libraries:core"))
implementation(project(":libraries:matrix"))
implementation(project(":libraries:designsystem"))
implementation(project(":libraries:elementresources"))
implementation(libs.mavericks.compose)
implementation(libs.timber)
testImplementation("junit:junit:4.13.2")

9
features/login/src/main/java/io/element/android/x/features/login/LoginScreen.kt

@ -29,6 +29,7 @@ import com.airbnb.mvrx.Success @@ -29,6 +29,7 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel
import io.element.android.x.designsystem.ElementXTheme
import io.element.android.x.features.login.error.loginError
import timber.log.Timber
@Composable
@ -164,14 +165,12 @@ fun LoginContent( @@ -164,14 +165,12 @@ fun LoginContent(
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(
onDone = {
if (state.submitEnabled) onSubmitClicked()
}
onDone = { onSubmitClicked() }
),
)
if (isError) {
if (state.isLoggedIn is Fail) {
Text(
text = (state.isLoggedIn as? Fail)?.toString().orEmpty(),
text = loginError(state.formState, state.isLoggedIn.error),
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(start = 16.dp)

3
features/login/src/main/java/io/element/android/x/features/login/LoginViewModel.kt

@ -3,6 +3,7 @@ package io.element.android.x.features.login @@ -3,6 +3,7 @@ package io.element.android.x.features.login
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshotFlow
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.Uninitialized
import io.element.android.x.matrix.MatrixInstance
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@ -47,9 +48,11 @@ class LoginViewModel(initialState: LoginViewState) : @@ -47,9 +48,11 @@ class LoginViewModel(initialState: LoginViewState) :
fun onSetPassword(password: String) {
formState.value = formState.value.copy(password = password)
setState { copy(isLoggedIn = Uninitialized) }
}
fun onSetName(name: String) {
formState.value = formState.value.copy(login = name)
setState { copy(isLoggedIn = Uninitialized) }
}
}

14
features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerScreen.kt

@ -6,6 +6,7 @@ import androidx.compose.foundation.background @@ -6,6 +6,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
@ -25,6 +26,7 @@ import com.airbnb.mvrx.Loading @@ -25,6 +26,7 @@ import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel
import io.element.android.x.features.login.error.changeServerError
@Composable
fun ChangeServerScreen(
@ -107,12 +109,18 @@ fun ChangeServerContent( @@ -107,12 +109,18 @@ fun ChangeServerContent(
isError = isError,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Send,
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(
onDone = { onChangeServerSubmit() }
)
)
if (isError) {
if (state.changeServerAction is Fail) {
Text(
text = (state.changeServerAction as? Fail)?.toString().orEmpty(),
text = changeServerError(
state.homeserver,
state.changeServerAction.error
),
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(start = 16.dp)

6
features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewModel.kt

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
package io.element.android.x.features.login.changeserver
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.Uninitialized
import io.element.android.x.matrix.MatrixInstance
import kotlinx.coroutines.launch
@ -19,7 +20,10 @@ class ChangeServerViewModel(initialState: ChangeServerViewState) : @@ -19,7 +20,10 @@ class ChangeServerViewModel(initialState: ChangeServerViewState) :
fun setServer(server: String) {
setState {
copy(homeserver = server)
copy(
homeserver = server,
changeServerAction = Uninitialized,
)
}
}

33
features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
package io.element.android.x.features.login.error
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import io.element.android.x.core.uri.isValidUrl
import io.element.android.x.features.login.LoginFormState
import io.element.android.x.element.resources.R as ElementR
@Composable
fun loginError(
data: LoginFormState,
throwable: Throwable?
): String {
return when {
data.login.isEmpty() -> "Please enter a login"
data.password.isEmpty() -> "Please enter a password"
throwable != null -> stringResource(id = ElementR.string.auth_invalid_login_param)
else -> "No error provided"
}
}
@Composable
fun changeServerError(
data: String,
throwable: Throwable?
): String {
return when {
data.isEmpty() -> "Please enter a server URL"
!data.isValidUrl() -> stringResource(id = ElementR.string.login_error_invalid_home_server)
throwable != null -> "That server doesn’t seem right. Please check the address."
else -> "No error provided"
}
}

31
libraries/core/src/main/java/io/element/android/x/core/uri/UrlUtils.kt

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
package io.element.android.x.core.uri
import java.net.URL
fun String.isValidUrl(): Boolean {
return try {
URL(this)
true
} catch (t: Throwable) {
false
}
}
/**
* Ensure string starts with "http". If it is not the case, "https://" is added, only if the String is not empty
*/
fun String.ensureProtocol(): String {
return when {
isEmpty() -> this
!startsWith("http") -> "https://$this"
else -> this
}
}
fun String.ensureTrailingSlash(): String {
return when {
isEmpty() -> this
!endsWith("/") -> "$this/"
else -> this
}
}
Loading…
Cancel
Save