Skip to content

Instantly share code, notes, and snippets.

@cdmunoz
Created April 10, 2018 02:55
Show Gist options
  • Save cdmunoz/cfd6ee66986c2d6971ed77ba6c20f5b7 to your computer and use it in GitHub Desktop.
Save cdmunoz/cfd6ee66986c2d6971ed77ba6c20f5b7 to your computer and use it in GitHub Desktop.
package com.earlywarning.zelle.get_started;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.text.InputType;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import butterknife.Bind;
import butterknife.BindString;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.earlywarning.zelle.BuildConfig;
import com.earlywarning.zelle.R;
import com.earlywarning.zelle.authentify.AuthentifySupportActivity;
import com.earlywarning.zelle.common.presentation.SessionTokenManager;
import com.earlywarning.zelle.common.presentation.view.CustomBackPressedEditText;
import com.earlywarning.zelle.common.util.StringUtils;
import com.earlywarning.zelle.common.util.ZelleConstants;
import com.earlywarning.zelle.common.util.ZelleUtils;
import com.earlywarning.zelle.common.widget.LoadingEditText;
import com.earlywarning.zelle.complete_account.CompleteAccountActivity;
import com.earlywarning.zelle.enroll.presentation.add_debit_card.AddDebitCardActivity;
import com.earlywarning.zelle.enroll.presentation.verification_code.VerificationCodeActivity;
import com.earlywarning.zelle.errorstate.RegexValidator;
import com.earlywarning.zelle.login.Token;
import com.earlywarning.zelle.model.User;
import com.earlywarning.zelle.user.presentation.GetStartedView;
import com.earlywarning.zelle.user.presentation.di.DaggerUserComponent;
import com.earlywarning.zelle.user.presentation.di.UserComponent;
import com.jakewharton.rxbinding.widget.RxTextView;
import com.jakewharton.rxbinding.widget.TextViewAfterTextChangeEvent;
import javax.inject.Inject;
import rx.Subscription;
import static com.jakewharton.rxbinding.widget.RxTextView.afterTextChangeEvents;
public class GetStartedActivity extends AuthentifySupportActivity implements GetStartedView {
private static final int DELAY_LOGIN_ERROR_NOTIFICATION = 2000;
@Inject GetStartedPresenter presenter;
@Inject SessionTokenManager sessionTokenManager;
@Bind(R.id.get_started_title) ImageView titleView;
@Bind(R.id.get_started_token_field) LoadingEditText tokenField;
@Bind(R.id.get_started_password_field_wrapper) View passwordFieldWrapper;
@Bind(R.id.get_started_password_field) CustomBackPressedEditText passwordField;
@Bind(R.id.get_started_show_password) CheckBox showPasswordCheckBox;
@Bind(R.id.get_started_validate_cta) Button validateCTA;
@Bind(R.id.get_started_login_cta) Button loginCTA;
@Bind(R.id.get_started_terms) TextView termsView;
@BindString(R.string.regex_phone) String regexPhone;
@BindString(R.string.invalid_phone_number) String phoneNumberNotAllowed;
@BindString(R.string.get_started_user_not_on_white_list) String userNotOnWhiteListMessage;
@BindString(R.string.get_started_max_verification_code_send_count) String
maxVerificationCodeSentMessage;
@BindString(R.string.get_started_terms_link) String stringTermsConditions;
@BindString(R.string.get_started_and) String stringAnd;
@BindString(R.string.get_started_privacy_link) String stringPrivacy;
@BindString(R.string.get_started_hide_password) String stringHidePassword;
@BindString(R.string.get_started_show_password) String stringShowPassword;
@BindString(R.string.get_started_risk_logout) String stringRiskMomentRiskFailureMsg;
@BindString(R.string.verification_code_login_title) String loginTitle;
private UserComponent userComponent;
private Subscription emailPhoneSubscription;
private Subscription passwordSubscription;
/**
* Returns a new intent for this activity
*
* @param context Context
* @return A intent for this activity
*/
public static Intent getIntent(Context context) {
Intent intent = new Intent(context, GetStartedActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);//clear out activities stack
intent.putExtra(ZelleConstants.EXTRA_PARAM_TOKEN, ""); //clear out token
return intent;
}
@Override protected void onDestroy() {
super.onDestroy();
presenter.destroy();
if (null != emailPhoneSubscription) {
emailPhoneSubscription.unsubscribe();
}
if (passwordSubscription != null) {
passwordSubscription.unsubscribe();
}
}
@Override public UserComponent getComponent() {
return userComponent;
}
@Override protected void initialize(Bundle savedInstanceState) {
setContentView(R.layout.activity_get_started);
getComponent().inject(this);
ButterKnife.bind(this);
presenter.setView(this);
presenter.initialize();
initView();
}
@Override protected void initializeInjector() {
userComponent = DaggerUserComponent.builder()
.applicationComponent(getApplicationComponent())
.activityModule(getActivityModule())
.build();
}
@Override protected void onPermissionsDeniedDo() {
}
@Override protected int getStatusBarColor() {
return R.color.color_dark_bar_get_started;
}
@Override public void login(Token token) {
startActivity(VerificationCodeActivity.getIntent(this, token));
finish();
}
@Override public void next(Token token) {
startActivity(VerificationCodeActivity.getIntent(this, token));
finish();
}
@Override public void showHome(User user) {
sessionTokenManager.createSession(user.getSessionToken());
ZelleUtils.saveToken(this, user.getToken().getValue());
ZelleUtils.goHome(this, user);
finish();
}
@OnClick(R.id.get_started_validate_cta) public void onGetStartedClicked(View view) {
view.setEnabled(false);
tokenField.showLoading();
String token = ZelleUtils.unsetMaskToPhoneNumber(tokenField.getText().toString());
//This line help to verify the general error related with EW-2358.
if (token.equals("5555555555") && BuildConfig.BUILD_TYPE.equals("qa")) {
showGenericError();
tokenField.hideAnimation();
} else {
presenter.addDevice(token);
}
}
@Override public String getToken() {
return ZelleUtils.getToken(this);
}
@Override public String getPassword() {
return passwordField.getText().toString();
}
@Override public void showLoginForm() {
passwordFieldWrapper.setVisibility(View.VISIBLE);
passwordField.setVisibility(View.VISIBLE);
showPasswordCheckBox.setVisibility(View.VISIBLE);
passwordFieldWrapper.requestFocus();
loginCTA.setVisibility(View.VISIBLE);
validateCTA.setVisibility(View.GONE);
tokenField.setEnabled(true);
tokenField.hideAnimation();
new Handler().postDelayed(() -> {
passwordField.requestFocus();
new Handler().postDelayed(() -> {
ZelleUtils.showSoftKeyboard(passwordField, GetStartedActivity.this);
}, ZelleConstants.SHORT_DELAY_ANIMATION);
}, ZelleConstants.SHORT_DELAY_ANIMATION);
}
@Override public void fillPhoneField() {
tokenField.setText(ZelleUtils.getToken(this));
tokenField.requestFocus();
ZelleUtils.showSoftKeyboard(tokenField, this);
}
@Override public boolean isLogoutError() {
return getIntent().hasExtra(ZelleConstants.EXTRA_PARAM_FILL_PHONE_NUMBER_INIT);
}
@Override public void showLogoutError() {
tokenField.setText("");
getErrorStateManager().showErrorState(stringRiskMomentRiskFailureMsg);
tokenField.hideAnimation();
}
@Override public void showNotAllowed() {
getErrorStateManager().showErrorState(phoneNumberNotAllowed);
tokenField.hideAnimation();
new Handler().postDelayed(() -> getErrorStateManager().hideNotification(),
ZelleConstants.HIDE_ERROR_NOTIFICATION_LONG_TIMEOUT);
}
@Override public void showNotOnWhiteList() {
getErrorStateManager().showErrorState(userNotOnWhiteListMessage);
tokenField.hideAnimation();
}
@Override public void showMaxVerificationCodesSent() {
getErrorStateManager().showErrorState(maxVerificationCodeSentMessage);
tokenField.hideAnimation();
}
@Override public String getUserToken() {
return ZelleUtils.unsetMaskToPhoneNumber(tokenField.getText().toString());
}
@Override public String getLoginTitle() {
return loginTitle;
}
@Override public void showLoginError() {
tokenField.hideAnimation();
getErrorStateManager().showErrorState(getString(R.string.login_error));
new Handler().postDelayed(() -> getErrorStateManager().hideNotification(),
DELAY_LOGIN_ERROR_NOTIFICATION);
}
@Override public void saveToken(String token) {
ZelleUtils.saveToken(this, token);
}
@Override public void goToDebitCard(User user) {
sessionTokenManager.createSession(user.getSessionToken());
finish();
Intent intent = AddDebitCardActivity.getIntent(this, user);
startActivity(intent);
}
@Override public void goToCompleteAccount(User user) {
sessionTokenManager.createSession(user.getSessionToken());
finish();
Intent intent = CompleteAccountActivity.getIntent(this, user);
startActivity(intent);
}
@OnClick(R.id.get_started_login_cta) public void onLoginClicked(View view) {
view.setEnabled(false);
ZelleUtils.hideSoftKeyboard(view, this);
titleView.setVisibility(View.VISIBLE);
presenter.verifyPassword();
}
@OnClick(R.id.get_started_show_password) public void onTogglePasswordDisplay() {
Boolean showPassword = showPasswordCheckBox.isChecked();
if (showPassword) {
//we want to toggle password display ON
passwordField.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
passwordField.setTypeface(tokenField.getTypeface());//proper typeface to password field
showPasswordCheckBox.setHint(stringHidePassword);
} else {
//we want to toggle password display OFF
passwordField.setInputType(
InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
passwordField.setTypeface(tokenField.getTypeface());//proper typeface to password field
showPasswordCheckBox.setHint(stringShowPassword);
}
passwordField.setSelection(passwordField.length());
}
// Override method for hide animation when generic error is showed
@Override public void showGenericError() {
super.showGenericError();
tokenField.hideAnimation();
}
private void initView() {
getErrorStateManager().setTextValidator(tokenField, new RegexValidator(regexPhone), false);
emailPhoneSubscription = afterTextChangeEvents(tokenField).subscribe(this::textChanged);
passwordField.setOnFocusChangeListener((view, hasFocus) -> passwordFieldFocused(hasFocus));
passwordField.setOnEditorActionListener((view, action, event) -> passwordFieldTyped(action));
passwordField.setOnClickListener(v -> titleView.setVisibility(View.GONE));
passwordSubscription = RxTextView.textChanges(passwordField).subscribe(charSequence -> {
validateLogin();
});
tokenField.setLayoutContents(titleView);
passwordField.setLayoutContents(titleView);
buildTermsView();
}
private void setFieldsForGetStarted() {
loginCTA.setVisibility(View.GONE);
passwordFieldWrapper.setVisibility(View.GONE);
passwordField.setVisibility(View.GONE);
showPasswordCheckBox.setVisibility(View.GONE);
validateCTA.setVisibility(View.VISIBLE);
titleView.setVisibility(View.VISIBLE);
tokenField.hideAnimation();
tokenField.setFocusableInTouchMode(true);
passwordField.setText("");
}
private void passwordFieldFocused(boolean hasFocus) {
if (hasFocus) {
titleView.setVisibility(View.GONE);
} else {
passwordField.clearFocus();
ZelleUtils.hideSoftKeyboard(passwordField, GetStartedActivity.this);
if (passwordFieldWrapper.getVisibility() == View.VISIBLE) {
titleView.setVisibility(View.GONE);
} else {
titleView.setVisibility(View.VISIBLE);
}
}
}
private boolean passwordFieldTyped(int actionId) {
if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT) {
passwordField.clearFocus();
ZelleUtils.hideSoftKeyboard(passwordField, GetStartedActivity.this);
ZelleUtils.showGoneView(titleView);
}
return false;
}
private void textChanged(TextViewAfterTextChangeEvent textViewAfterTextChangeEvent) {
EditText editText = (EditText) textViewAfterTextChangeEvent.view();
String text = editText.getText().toString();
boolean isValidPhoneNumber = ZelleUtils.validatePhoneNumber(text);
boolean isValidEmail = ZelleUtils.validateEmail(text);
tokenField.showValid(isValidEmail || isValidPhoneNumber);
if (isValidPhoneNumber) {
tokenField.setFocusable(false);
tokenField.setFocusableInTouchMode(true);
validateCTA.setEnabled(true);
} else {
if (ZelleUtils.unsetMaskToPhoneNumber(text).length()
< ZelleConstants.PHONE_NUMBER_MAX_LENGTH) {
setFieldsForGetStarted();
validateCTA.setEnabled(false);
}
}
String formattedPhone = ZelleUtils.formatPhone(text);
if (!TextUtils.isEmpty(text) && !text.equals(formattedPhone)) {
editText.setText(formattedPhone);
editText.setSelection(editText.getText().length());
}
if (getErrorStateManager().isErrorShown()) getErrorStateManager().hideNotification();
}
/**
* In order to avoid multiple views and view childs in get started screen and to improve
* performance in the general view, this method uses an SpannableStringBuilder to set in just one
* textview different texts, even with clickable behavior
*/
private void buildTermsView() {
SpannableStringBuilder spanTxt =
StringUtils.getSpannableStringForTermsAndConditions(this, "", stringTermsConditions,
stringAnd, stringPrivacy);
termsView.setMovementMethod(LinkMovementMethod.getInstance());
termsView.setText(spanTxt, TextView.BufferType.SPANNABLE);
}
private void validateLogin() {
String phoneEntry = tokenField.getText().toString();
String passwordEntry = passwordField.getText().toString();
boolean isValidPhoneNumber = ZelleUtils.validatePhoneNumber(phoneEntry);
boolean isValidPassword = ZelleUtils.validatePassword(passwordEntry);
loginCTA.setEnabled(isValidPhoneNumber && isValidPassword);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment