Improve username creation error debouncing.

This commit is contained in:
Greyson Parrelli 2023-11-02 16:05:08 -04:00
parent af016a9c79
commit 528e301ce4
3 changed files with 38 additions and 7 deletions

View file

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.profiles.manage;
import android.animation.LayoutTransition;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
@ -9,8 +10,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
@ -24,8 +23,6 @@ import androidx.navigation.Navigation;
import androidx.navigation.fragment.NavHostFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.progressindicator.CircularProgressIndicatorSpec;
import com.google.android.material.progressindicator.IndeterminateDrawable;
import com.google.android.material.textfield.TextInputLayout;
import org.signal.core.util.DimensionUnit;
@ -52,6 +49,17 @@ public class UsernameEditFragment extends LoggingFragment {
private LifecycleDisposable lifecycleDisposable;
private UsernameEditFragmentArgs args;
private static final LayoutTransition ANIMATED_LAYOUT = new LayoutTransition();
private static final LayoutTransition STATIC_LAYOUT = new LayoutTransition();
static {
STATIC_LAYOUT.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
STATIC_LAYOUT.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
STATIC_LAYOUT.disableTransitionType(LayoutTransition.APPEARING);
STATIC_LAYOUT.disableTransitionType(LayoutTransition.DISAPPEARING);
STATIC_LAYOUT.disableTransitionType(LayoutTransition.CHANGING);
}
public static UsernameEditFragment newInstance() {
return new UsernameEditFragment();
}
@ -155,6 +163,8 @@ public class UsernameEditFragment extends LoggingFragment {
presentButtonState(state.buttonState);
presentSummary(state.username);
binding.root.setLayoutTransition(ANIMATED_LAYOUT);
switch (state.usernameStatus) {
case NONE:
usernameInputWrapper.setError(null);
@ -190,6 +200,8 @@ public class UsernameEditFragment extends LoggingFragment {
CharSequence error = usernameInputWrapper.getError();
binding.usernameError.setVisibility(error != null ? View.VISIBLE : View.GONE);
binding.usernameError.setText(usernameInputWrapper.getError());
binding.root.setLayoutTransition(STATIC_LAYOUT);
}
private void presentButtonState(@NonNull UsernameEditViewModel.ButtonState buttonState) {

View file

@ -71,9 +71,19 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr
val invalidReason: InvalidReason? = checkUsername(nickname)
if (invalidReason != null) {
State(ButtonState.SUBMIT_DISABLED, mapUsernameError(invalidReason), state.username)
// We only want to show actual errors after debouncing. But we also don't want to allow users to submit names with errors.
// So we disable submit, but we don't show an error yet.
State(
buttonState = ButtonState.SUBMIT_DISABLED,
usernameStatus = UsernameStatus.NONE,
username = state.username
)
} else {
State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE, state.username)
State(
buttonState = ButtonState.SUBMIT_DISABLED,
usernameStatus = UsernameStatus.NONE,
username = state.username
)
}
}
@ -169,6 +179,13 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr
val invalidReason: InvalidReason? = checkUsername(nickname)
if (invalidReason != null) {
uiState.update { state ->
State(
buttonState = ButtonState.SUBMIT_DISABLED,
usernameStatus = mapUsernameError(invalidReason),
username = state.username
)
}
return
}
@ -229,7 +246,8 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr
}
companion object {
private const val NICKNAME_PUBLISHER_DEBOUNCE_TIMEOUT_MILLIS: Long = 500
private const val NICKNAME_PUBLISHER_DEBOUNCE_TIMEOUT_MILLIS: Long = 1000
private fun mapUsernameError(invalidReason: InvalidReason): UsernameStatus {
return when (invalidReason) {
InvalidReason.TOO_SHORT -> UsernameStatus.TOO_SHORT

View file

@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">