Skip to content
Snippets Groups Projects
Commit 23da6b7c authored by Mohamed Amine Younes Bouacida's avatar Mohamed Amine Younes Bouacida
Browse files

account creation: clarify availability state

+ change the fragment, layout and presenter in order to add this new feature
+ take  care of any errors in the daemon response (e.g : network disruption)
+ handle the cancel and proceed events properly
+ fix error display regarding password errors

Change-Id: Ie9b11502391108dd1a62b0a5460bff18a8615d12
Gitlab: #628
parent 6f87dbb4
Branches
Tags
No related merge requests found
...@@ -22,7 +22,6 @@ package cx.ring.account; ...@@ -22,7 +22,6 @@ package cx.ring.account;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import com.google.android.material.textfield.TextInputLayout;
import android.text.Editable; import android.text.Editable;
import android.text.InputFilter; import android.text.InputFilter;
import android.view.View; import android.view.View;
...@@ -31,9 +30,14 @@ import android.view.inputmethod.EditorInfo; ...@@ -31,9 +30,14 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Switch; import android.widget.Switch;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.google.android.material.textfield.TextInputLayout;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnCheckedChanged; import butterknife.OnCheckedChanged;
...@@ -42,11 +46,12 @@ import butterknife.OnEditorAction; ...@@ -42,11 +46,12 @@ import butterknife.OnEditorAction;
import butterknife.OnTextChanged; import butterknife.OnTextChanged;
import cx.ring.R; import cx.ring.R;
import cx.ring.dependencyinjection.RingInjectionComponent; import cx.ring.dependencyinjection.RingInjectionComponent;
import cx.ring.mvp.BaseSupportFragment;
import cx.ring.mvp.AccountCreationModel; import cx.ring.mvp.AccountCreationModel;
import cx.ring.mvp.BaseSupportFragment;
import cx.ring.utils.RegisteredNameFilter; import cx.ring.utils.RegisteredNameFilter;
public class RingAccountCreationFragment extends BaseSupportFragment<RingAccountCreationPresenter> implements RingAccountCreationView { public class RingAccountCreationFragment extends BaseSupportFragment<RingAccountCreationPresenter>
implements RingAccountCreationView {
@BindView(R.id.switch_ring_username) @BindView(R.id.switch_ring_username)
protected Switch mUsernameSwitch; protected Switch mUsernameSwitch;
...@@ -78,6 +83,12 @@ public class RingAccountCreationFragment extends BaseSupportFragment<RingAccount ...@@ -78,6 +83,12 @@ public class RingAccountCreationFragment extends BaseSupportFragment<RingAccount
@BindView(R.id.create_account) @BindView(R.id.create_account)
protected Button mCreateAccountButton; protected Button mCreateAccountButton;
@BindView(R.id.ring_username_availability_image_view)
protected ImageView mUsernameAvailabilityImageView;
@BindView(R.id.ring_username_availability_spinner)
protected ProgressBar mUsernameAvailabilitySpinner;
private AccountCreationModel model; private AccountCreationModel model;
public static RingAccountCreationFragment newInstance(AccountCreationModelImpl ringAccountViewModel) { public static RingAccountCreationFragment newInstance(AccountCreationModelImpl ringAccountViewModel) {
...@@ -111,7 +122,8 @@ public class RingAccountCreationFragment extends BaseSupportFragment<RingAccount ...@@ -111,7 +122,8 @@ public class RingAccountCreationFragment extends BaseSupportFragment<RingAccount
super.onResume(); super.onResume();
if (mUsernameBox.getVisibility() == View.VISIBLE) { if (mUsernameBox.getVisibility() == View.VISIBLE) {
mUsernameTxt.requestFocus(); mUsernameTxt.requestFocus();
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) requireActivity().
getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mUsernameTxt, InputMethodManager.SHOW_IMPLICIT); imm.showSoftInput(mUsernameTxt, InputMethodManager.SHOW_IMPLICIT);
} }
} }
...@@ -136,11 +148,6 @@ public class RingAccountCreationFragment extends BaseSupportFragment<RingAccount ...@@ -136,11 +148,6 @@ public class RingAccountCreationFragment extends BaseSupportFragment<RingAccount
presenter.createAccount(); presenter.createAccount();
} }
@OnTextChanged(value = R.id.ring_username, callback = OnTextChanged.Callback.TEXT_CHANGED)
public void onUsernameChanged() {
mUsernameTxt.setError(null);
}
@OnTextChanged(value = R.id.ring_password, callback = OnTextChanged.Callback.TEXT_CHANGED) @OnTextChanged(value = R.id.ring_password, callback = OnTextChanged.Callback.TEXT_CHANGED)
public void afterPasswordChanged(Editable txt) { public void afterPasswordChanged(Editable txt) {
presenter.passwordChanged(txt.toString()); presenter.passwordChanged(txt.toString());
...@@ -165,27 +172,46 @@ public class RingAccountCreationFragment extends BaseSupportFragment<RingAccount ...@@ -165,27 +172,46 @@ public class RingAccountCreationFragment extends BaseSupportFragment<RingAccount
} }
@Override @Override
public void enableTextError() { public void updateUsernameAvailability(UsernameAvailabilityStatus status) {
mUsernameAvailabilitySpinner.setVisibility(View.GONE);
mUsernameAvailabilityImageView.setVisibility(View.VISIBLE);
switch (status){
case ERROR:
mUsernameTxtBox.setErrorEnabled(true); mUsernameTxtBox.setErrorEnabled(true);
mUsernameTxtBox.setError(getString(R.string.looking_for_username_availability)); mUsernameTxtBox.setError(getString(R.string.unknown_error));
} mUsernameAvailabilityImageView.setImageDrawable(getResources().
getDrawable(R.drawable.ic_error_red));
@Override break;
public void disableTextError() { case ERROR_USERNAME_INVALID:
mUsernameTxtBox.setErrorEnabled(false); mUsernameTxtBox.setErrorEnabled(true);
mUsernameTxtBox.setError(null); mUsernameTxtBox.setError(getString(R.string.invalid_username));
} mUsernameAvailabilityImageView.setImageDrawable(getResources().
getDrawable(R.drawable.ic_error_red));
@Override break;
public void showExistingNameError() { case ERROR_USERNAME_TAKEN:
mUsernameTxtBox.setErrorEnabled(true); mUsernameTxtBox.setErrorEnabled(true);
mUsernameTxtBox.setError(getString(R.string.username_already_taken)); mUsernameTxtBox.setError(getString(R.string.username_already_taken));
mUsernameAvailabilityImageView.setImageDrawable(getResources().
getDrawable(R.drawable.ic_error_red));
break;
case LOADING:
mUsernameTxtBox.setErrorEnabled(false);
mUsernameAvailabilityImageView.setVisibility(View.INVISIBLE);
mUsernameAvailabilitySpinner.setVisibility(View.VISIBLE);
break;
case AVAILABLE:
mUsernameTxtBox.setErrorEnabled(false);
mUsernameAvailabilityImageView.setImageDrawable(getResources().
getDrawable(R.drawable.ic_good_green));
break;
case RESET:
mUsernameTxtBox.setErrorEnabled(false);
mUsernameAvailabilityImageView.setVisibility(View.INVISIBLE);
enableNextButton(false);
default:
mUsernameAvailabilityImageView.setVisibility(View.INVISIBLE);
break;
} }
@Override
public void showInvalidNameError() {
mUsernameTxtBox.setErrorEnabled(true);
mUsernameTxtBox.setError(getString(R.string.invalid_username));
} }
@Override @Override
... ...
......
...@@ -72,6 +72,18 @@ public abstract class RingGuidedStepFragment<T extends RootPresenter> extends Gu ...@@ -72,6 +72,18 @@ public abstract class RingGuidedStepFragment<T extends RootPresenter> extends Gu
.icon(icon) .icon(icon)
.build()); .build());
} }
protected static void addDisabledNonFocusableAction(Context context, List<GuidedAction> actions, long id, String title, String desc, Drawable icon) {
actions.add(new GuidedAction.Builder(context)
.id(id)
.title(title)
.description(desc)
.enabled(false)
.focusable(false)
.icon(icon)
.build());
}
protected static void addDisabledAction(Context context, List<GuidedAction> actions, long id, String title, String desc, Drawable icon,boolean next) { protected static void addDisabledAction(Context context, List<GuidedAction> actions, long id, String title, String desc, Drawable icon,boolean next) {
actions.add(new GuidedAction.Builder(context) actions.add(new GuidedAction.Builder(context)
.id(id) .id(id)
... ...
......
...@@ -62,11 +62,15 @@ public class TVRingAccountCreationFragment ...@@ -62,11 +62,15 @@ public class TVRingAccountCreationFragment
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
String newName = s.toString(); String newName = s.toString();
if (!newName.equals(getResources().getString(R.string.register_username))) {
boolean empty = newName.isEmpty(); boolean empty = newName.isEmpty();
/** If the username is empty make sure to set isRegisterUsernameChecked
* to False, this allows to create an account with an empty username */
presenter.ringCheckChanged(!empty); presenter.ringCheckChanged(!empty);
if (!empty) /** Send the newName even when empty (in order to reset the views) */
presenter.userNameChanged(newName); presenter.userNameChanged(newName);
} }
}
}; };
public TVRingAccountCreationFragment() { public TVRingAccountCreationFragment() {
...@@ -108,7 +112,7 @@ public class TVRingAccountCreationFragment ...@@ -108,7 +112,7 @@ public class TVRingAccountCreationFragment
@Override @Override
public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) { public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
addEditTextAction(getActivity(), actions, USERNAME, R.string.register_username, R.string.prompt_new_username); addEditTextAction(getActivity(), actions, USERNAME, R.string.register_username, R.string.prompt_new_username);
addDisabledAction(getActivity(), actions, CHECK, "", "", null); addDisabledNonFocusableAction(getActivity(), actions, CHECK, "", "", null);
addPasswordAction(getActivity(), actions, PASSWORD, getString(R.string.prompt_new_password_optional), getString(R.string.enter_password), ""); addPasswordAction(getActivity(), actions, PASSWORD, getString(R.string.prompt_new_password_optional), getString(R.string.enter_password), "");
addPasswordAction(getActivity(), actions, PASSWORD_CONFIRMATION, getString(R.string.prompt_new_password_repeat), getString(R.string.enter_password), ""); addPasswordAction(getActivity(), actions, PASSWORD_CONFIRMATION, getString(R.string.prompt_new_password_repeat), getString(R.string.enter_password), "");
addDisabledAction(getActivity(), actions, CONTINUE, getString(R.string.action_create), "", null, true); addDisabledAction(getActivity(), actions, CONTINUE, getString(R.string.action_create), "", null, true);
...@@ -128,28 +132,43 @@ public class TVRingAccountCreationFragment ...@@ -128,28 +132,43 @@ public class TVRingAccountCreationFragment
@Override @Override
public long onGuidedActionEditedAndProceed(GuidedAction action) { public long onGuidedActionEditedAndProceed(GuidedAction action) {
if (action.getId() == PASSWORD) { onGuidedActionChange(action);
return GuidedAction.ACTION_ID_NEXT;
}
@Override
public void onGuidedActionEditCanceled(GuidedAction action) {
onGuidedActionChange(action);
}
private void onGuidedActionChange(GuidedAction action){
switch ((int) action.getId()){
case USERNAME:
usernameChanged(action);
break;
case PASSWORD:
passwordChanged(action); passwordChanged(action);
} else if (action.getId() == PASSWORD_CONFIRMATION) { break;
case PASSWORD_CONFIRMATION:
confirmPasswordChanged(action); confirmPasswordChanged(action);
} else if (action.getId() == USERNAME) { break;
}
}
private void usernameChanged(GuidedAction action) {
String username = action.getEditTitle().toString();
ViewGroup view = (ViewGroup) getActionItemView(findActionPositionById(USERNAME)); ViewGroup view = (ViewGroup) getActionItemView(findActionPositionById(USERNAME));
if (view != null) { if (view != null) {
EditText text = view.findViewById(R.id.guidedactions_item_title); EditText text = view.findViewById(R.id.guidedactions_item_title);
text.removeTextChangedListener(mUsernameWatcher); text.removeTextChangedListener(mUsernameWatcher);
} }
String username = action.getEditTitle().toString();
boolean empty = username.isEmpty(); if(username.isEmpty())
if (empty) {
action.setTitle(getString(R.string.register_username)); action.setTitle(getString(R.string.register_username));
} else { else
action.setTitle(username); action.setTitle(username);
}
GuidedAction a = findActionById(CHECK); notifyActionChanged(findActionPositionById(PASSWORD));
a.setEnabled(!empty);
notifyActionChanged(findActionPositionById(CHECK));
}
return GuidedAction.ACTION_ID_NEXT;
} }
private void passwordChanged(GuidedAction action) { private void passwordChanged(GuidedAction action) {
...@@ -180,59 +199,66 @@ public class TVRingAccountCreationFragment ...@@ -180,59 +199,66 @@ public class TVRingAccountCreationFragment
} }
@Override @Override
public void enableTextError() { public void updateUsernameAvailability(UsernameAvailabilityStatus status) {
GuidedAction action = findActionById(CHECK); GuidedAction actionCheck = findActionById(CHECK);
action.setIcon(null); switch (status){
action.setTitle(getString(R.string.looking_for_username_availability)); case ERROR:
notifyActionChanged(findActionPositionById(CHECK)); actionCheck.setTitle(getResources().getString(R.string.generic_error));
} displayErrorIconTitle(actionCheck, getString(R.string.unknown_error));
break;
@Override case ERROR_USERNAME_INVALID:
public void disableTextError() { displayErrorIconTitle(actionCheck,getString(R.string.invalid_username));
GuidedAction action = findActionById(CHECK); break;
action.setIcon(null); case ERROR_USERNAME_TAKEN:
action.setDescription(""); displayErrorIconTitle(actionCheck,
notifyActionChanged(findActionPositionById(CHECK)); getString(R.string.username_already_taken));
} break;
case LOADING:
@Override actionCheck.setIcon(null);
public void showExistingNameError() { actionCheck.setTitle(getResources().
GuidedAction action = findActionById(CHECK); getString(R.string.looking_for_username_availability));
action.setIcon(getResources().getDrawable(R.drawable.ic_error_red)); break;
action.setDescription(getString(R.string.username_already_taken)); case AVAILABLE:
notifyActionChanged(findActionPositionById(CHECK)); actionCheck.setTitle(getString(R.string.username_available));
actionCheck.setIcon(getResources().getDrawable(R.drawable.ic_good_green));
break;
case RESET:
actionCheck.setIcon(null);
actionCheck.setTitle("");
enableNextButton(false);
default:
actionCheck.setIcon(null);
break;
} }
@Override
public void showInvalidNameError() {
GuidedAction action = findActionById(CHECK);
action.setIcon(getResources().getDrawable(R.drawable.ic_error_red));
action.setDescription(getString(R.string.invalid_username));
notifyActionChanged(findActionPositionById(CHECK)); notifyActionChanged(findActionPositionById(CHECK));
} }
@Override @Override
public void showInvalidPasswordError(boolean display) { public void showInvalidPasswordError(boolean display) {
if (display) {
GuidedAction action = findActionById(CONTINUE); GuidedAction action = findActionById(CONTINUE);
action.setIcon(getResources().getDrawable(R.drawable.ic_error_red)); if (display) {
action.setDescription(getString(R.string.error_password_char_count)); displayErrorIconDescription(action,getString(R.string.error_password_char_count));
action.setEnabled(false); action.setEnabled(false);
} else {
action.setDescription("");
} }
notifyActionChanged(findActionPositionById(CONTINUE)); notifyActionChanged(findActionPositionById(CONTINUE));
} }
@Override @Override
public void showNonMatchingPasswordError(boolean display) { public void showNonMatchingPasswordError(boolean display) {
if (display) {
GuidedAction action = findActionById(CONTINUE); GuidedAction action = findActionById(CONTINUE);
action.setIcon(getResources().getDrawable(R.drawable.ic_error_red)); if (display) {
action.setDescription(getString(R.string.error_passwords_not_equals)); displayErrorIconDescription(action,getString(R.string.error_passwords_not_equals));
action.setEnabled(false); action.setEnabled(false);
} else {
action.setDescription("");
} }
notifyActionChanged(findActionPositionById(CONTINUE)); notifyActionChanged(findActionPositionById(CONTINUE));
} }
@Override @Override
public void displayUsernameBox(boolean display) { public void displayUsernameBox(boolean display) {
} }
...@@ -240,17 +266,10 @@ public class TVRingAccountCreationFragment ...@@ -240,17 +266,10 @@ public class TVRingAccountCreationFragment
@Override @Override
public void enableNextButton(boolean enabled) { public void enableNextButton(boolean enabled) {
Log.d(TAG, "enableNextButton: " + enabled); Log.d(TAG, "enableNextButton: " + enabled);
GuidedAction actionCheck = findActionById(CHECK);
GuidedAction actionContinue = findActionById(CONTINUE); GuidedAction actionContinue = findActionById(CONTINUE);
if (enabled) { if (enabled)
actionCheck.setIcon(getResources().getDrawable(R.drawable.ic_good_green));
actionCheck.setTitle(getString(R.string.no_registered_name_for_account));
actionCheck.setDescription("");
actionContinue.setIcon(null); actionContinue.setIcon(null);
actionCheck.setDescription("");
}
actionContinue.setEnabled(enabled); actionContinue.setEnabled(enabled);
notifyActionChanged(findActionPositionById(CHECK));
notifyActionChanged(findActionPositionById(CONTINUE)); notifyActionChanged(findActionPositionById(CONTINUE));
} }
...@@ -270,4 +289,15 @@ public class TVRingAccountCreationFragment ...@@ -270,4 +289,15 @@ public class TVRingAccountCreationFragment
} }
} }
private void displayErrorIconTitle(GuidedAction action, String title) {
action.setIcon(getResources().getDrawable(R.drawable.ic_error_red));
action.setTitle(title);
}
private void displayErrorIconDescription(GuidedAction action, String description) {
action.setIcon(getResources().getDrawable(R.drawable.ic_error_red));
action.setDescription(description);
}
} }
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
android:text="@string/register_username" android:text="@string/register_username"
android:textColor="@color/text_color_primary" /> android:textColor="@color/text_color_primary" />
<LinearLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ring_username_box" android:id="@+id/ring_username_box"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
...@@ -53,9 +53,12 @@ ...@@ -53,9 +53,12 @@
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/ring_username_txt_box" android:id="@+id/ring_username_txt_box"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp"> android:layout_marginBottom="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/ring_username_availability_image_view"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/ring_username" android:id="@+id/ring_username"
...@@ -75,7 +78,26 @@ ...@@ -75,7 +78,26 @@
</com.google.android.material.textfield.TextInputEditText> </com.google.android.material.textfield.TextInputEditText>
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
</LinearLayout> <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ring_username_availability_image_view"
android:layout_width="24dp"
android:layout_height="24dp"
android:visibility="invisible"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/ring_username_txt_box"
android:layout_marginTop="16dp"/>
<ProgressBar
android:id="@+id/ring_username_availability_spinner"
style="?android:attr/progressBarStyle"
android:layout_width="24dp"
android:layout_height="24dp"
android:visibility="gone"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/ring_username_txt_box"
android:layout_marginTop="16dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<Switch <Switch
android:id="@+id/ring_password_switch" android:id="@+id/ring_password_switch"
... ...
......
...@@ -204,12 +204,14 @@ along with this program; if not, write to the Free Software ...@@ -204,12 +204,14 @@ along with this program; if not, write to the Free Software
<!-- Name registration --> <!-- Name registration -->
<string name="error_username_empty">Enter a username</string> <string name="error_username_empty">Enter a username</string>
<string name="no_registered_name_for_account">No registered name found for this account</string> <string name="no_registered_name_for_account">No registered name found for this account</string>
<string name="username_available">Username available !</string>
<string name="register_name">Register name</string> <string name="register_name">Register name</string>
<string name="trying_to_register_name">Trying to register name</string> <string name="trying_to_register_name">Trying to register name</string>
<string name="registered_username">Registered username</string> <string name="registered_username">Registered username</string>
<string name="register_username">Register public username (recommended)</string> <string name="register_username">Register public username (recommended)</string>
<string name="username_already_taken">Username already taken</string> <string name="username_already_taken">Username already taken</string>
<string name="invalid_username">Invalid username</string> <string name="invalid_username">Invalid username</string>
<string name="unknown_error">Unknown error. Please check your network connection!</string>
<string name="looking_for_username_availability">Looking for username availability…</string> <string name="looking_for_username_availability">Looking for username availability…</string>
<string name="account_status_connecting">Connecting</string> <string name="account_status_connecting">Connecting</string>
<string name="account_status_connection_error">Connection error</string> <string name="account_status_connection_error">Connection error</string>
... ...
......
...@@ -34,24 +34,21 @@ import io.reactivex.subjects.PublishSubject; ...@@ -34,24 +34,21 @@ import io.reactivex.subjects.PublishSubject;
public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreationView> { public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreationView> {
public static final String TAG = RingAccountCreationPresenter.class.getSimpleName(); public static final String TAG = RingAccountCreationPresenter.class.getSimpleName();
public static final int PASSWORD_MIN_LENGTH = 6; private static final int PASSWORD_MIN_LENGTH = 6;
private static final long TYPING_DELAY = 350L;
private final PublishSubject<String> contactQuery = PublishSubject.create();
protected AccountService mAccountService; protected AccountService mAccountService;
@Inject @Inject
@Named("UiScheduler") @Named("UiScheduler")
protected Scheduler mUiScheduler; protected Scheduler mUiScheduler;
private AccountCreationModel mAccountCreationModel; private AccountCreationModel mAccountCreationModel;
private boolean isRingUserNameCorrect = false; private boolean isRingUserNameCorrect = false;
private boolean isPasswordCorrect = true; private boolean isPasswordCorrect = true;
private boolean isConfirmCorrect = true; private boolean isConfirmCorrect = true;
private boolean isRegisterUsernameChecked = true; private boolean isRegisterUsernameChecked = true;
private boolean startUsernameAvailabitlityProgressBarAnimation = true;
private String mPasswordConfirm = ""; private String mPasswordConfirm = "";
private final PublishSubject<String> contactQuery = PublishSubject.create();
@Inject @Inject
public RingAccountCreationPresenter(AccountService accountService) { public RingAccountCreationPresenter(AccountService accountService) {
this.mAccountService = accountService; this.mAccountService = accountService;
...@@ -61,28 +58,34 @@ public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreat ...@@ -61,28 +58,34 @@ public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreat
public void bindView(RingAccountCreationView view) { public void bindView(RingAccountCreationView view) {
super.bindView(view); super.bindView(view);
mCompositeDisposable.add(contactQuery mCompositeDisposable.add(contactQuery
.debounce(350, TimeUnit.MILLISECONDS) .debounce(TYPING_DELAY, TimeUnit.MILLISECONDS)
.switchMapSingle(q -> mAccountService.findRegistrationByName("", "", q)) .switchMapSingle(q -> mAccountService.
findRegistrationByName("", "", q))
.observeOn(mUiScheduler) .observeOn(mUiScheduler)
.subscribe(q -> handleBlockchainResult(q.name, q.address, q.state))); .subscribe(q -> handleBlockchainResult(q.name, q.address, q.state)));
} }
public void init(AccountCreationModel accountCreationModel) { public void init(AccountCreationModel accountCreationModel) {
mAccountCreationModel = accountCreationModel; mAccountCreationModel = accountCreationModel;
} }
/**
* Called everytime the provided username for the new account changes
* Sends the new value of the username to the ContactQuery subjet and shows the loading
* animation if it has not been started before
* @param userName
*/
public void userNameChanged(String userName) { public void userNameChanged(String userName) {
if (!userName.isEmpty()) {
mAccountCreationModel.setUsername(userName); mAccountCreationModel.setUsername(userName);
contactQuery.onNext(userName); contactQuery.onNext(userName);
isRingUserNameCorrect = false; isRingUserNameCorrect = false;
getView().enableTextError(); RingAccountCreationView view = getView();
} else {
mAccountCreationModel.setUsername(""); if (startUsernameAvailabitlityProgressBarAnimation) {
getView().disableTextError(); view.updateUsernameAvailability(RingAccountCreationView.
UsernameAvailabilityStatus.LOADING);
startUsernameAvailabitlityProgressBarAnimation = false;
} }
checkForms();
} }
public void ringCheckChanged(boolean isChecked) { public void ringCheckChanged(boolean isChecked) {
...@@ -96,6 +99,12 @@ public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreat ...@@ -96,6 +99,12 @@ public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreat
public void passwordChanged(String password) { public void passwordChanged(String password) {
mAccountCreationModel.setPassword(password); mAccountCreationModel.setPassword(password);
if (!password.isEmpty() && password.length() < PASSWORD_MIN_LENGTH) {
getView().showInvalidPasswordError(true);
isPasswordCorrect = false;
} else {
getView().showInvalidPasswordError(false);
isPasswordCorrect = true;
if (!password.equals(mPasswordConfirm)) { if (!password.equals(mPasswordConfirm)) {
getView().showNonMatchingPasswordError(true); getView().showNonMatchingPasswordError(true);
isConfirmCorrect = false; isConfirmCorrect = false;
...@@ -103,12 +112,6 @@ public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreat ...@@ -103,12 +112,6 @@ public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreat
getView().showNonMatchingPasswordError(false); getView().showNonMatchingPasswordError(false);
isConfirmCorrect = true; isConfirmCorrect = true;
} }
if (!password.isEmpty() && password.length() < PASSWORD_MIN_LENGTH) {
getView().showInvalidPasswordError(true);
isPasswordCorrect = false;
} else {
getView().showInvalidPasswordError(false);
isPasswordCorrect = true;
} }
checkForms(); checkForms();
} }
...@@ -140,38 +143,50 @@ public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreat ...@@ -140,38 +143,50 @@ public class RingAccountCreationPresenter extends RootPresenter<RingAccountCreat
} }
private void checkForms() { private void checkForms() {
getView().enableNextButton(isInputValid()); boolean valid = isInputValid();
getView().enableNextButton(valid);
if(valid && isRingUserNameCorrect)
getView().updateUsernameAvailability(RingAccountCreationView.
UsernameAvailabilityStatus.AVAILABLE);
} }
private void handleBlockchainResult(String name, String address, int state) { private void handleBlockchainResult(String name, String address, int state) {
RingAccountCreationView view = getView(); RingAccountCreationView view = getView();
//Once we get the result, we can show the loading animation again when the user types
startUsernameAvailabitlityProgressBarAnimation = true;
if (view == null) { if (view == null) {
return; return;
} }
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {
view.disableTextError();
view.updateUsernameAvailability(RingAccountCreationView.
UsernameAvailabilityStatus.RESET);
isRingUserNameCorrect = false; isRingUserNameCorrect = false;
} else { } else {
switch (state) { switch (state) {
case 0: case 0:
// on found // on found
view.showExistingNameError(); view.updateUsernameAvailability(RingAccountCreationView.
UsernameAvailabilityStatus.ERROR_USERNAME_TAKEN);
isRingUserNameCorrect = false; isRingUserNameCorrect = false;
break; break;
case 1: case 1:
// invalid name // invalid name
view.showInvalidNameError(); view.updateUsernameAvailability(RingAccountCreationView.
UsernameAvailabilityStatus.ERROR_USERNAME_INVALID);
isRingUserNameCorrect = false; isRingUserNameCorrect = false;
break; break;
case 2: case 2:
// available // available
view.disableTextError(); view.updateUsernameAvailability(RingAccountCreationView.
UsernameAvailabilityStatus.AVAILABLE);
mAccountCreationModel.setUsername(name); mAccountCreationModel.setUsername(name);
isRingUserNameCorrect = true; isRingUserNameCorrect = true;
break; break;
default: default:
// on error // on error
view.disableTextError(); view.updateUsernameAvailability(RingAccountCreationView.
UsernameAvailabilityStatus.ERROR);
isRingUserNameCorrect = false; isRingUserNameCorrect = false;
break; break;
} }
... ...
......
...@@ -23,13 +23,16 @@ import cx.ring.mvp.AccountCreationModel; ...@@ -23,13 +23,16 @@ import cx.ring.mvp.AccountCreationModel;
public interface RingAccountCreationView { public interface RingAccountCreationView {
void enableTextError(); enum UsernameAvailabilityStatus {
ERROR_USERNAME_TAKEN,
void disableTextError(); ERROR_USERNAME_INVALID,
ERROR,
void showExistingNameError(); LOADING,
AVAILABLE,
RESET
}
void showInvalidNameError(); void updateUsernameAvailability(UsernameAvailabilityStatus status);
void showInvalidPasswordError(boolean display); void showInvalidPasswordError(boolean display);
... ...
......
...@@ -59,12 +59,12 @@ import cx.ring.utils.SwigNativeConverter; ...@@ -59,12 +59,12 @@ import cx.ring.utils.SwigNativeConverter;
import cx.ring.utils.VCardUtils; import cx.ring.utils.VCardUtils;
import ezvcard.VCard; import ezvcard.VCard;
import io.reactivex.Completable; import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.Single; import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject; import io.reactivex.subjects.BehaviorSubject;
import io.reactivex.subjects.PublishSubject; import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject; import io.reactivex.subjects.Subject;
import io.reactivex.Observable;
/** /**
* This service handles the accounts (Ring and SIP) * This service handles the accounts (Ring and SIP)
...@@ -970,7 +970,7 @@ public class AccountService { ...@@ -970,7 +970,7 @@ public class AccountService {
public Single<RegisteredName> findRegistrationByName(final String account, final String nameserver, final String name) { public Single<RegisteredName> findRegistrationByName(final String account, final String nameserver, final String name) {
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {
return Single.create(l -> l.onError(new IllegalArgumentException())); return Single.just(new RegisteredName());
} }
return getRegisteredNames() return getRegisteredNames()
.filter(r -> account.equals(r.accountId) && name.equals(r.name)) .filter(r -> account.equals(r.accountId) && name.equals(r.name))
... ...
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment