Firebase login/registration process for a dating appRegistration and loginLogin and registration functionsSimple login and authentication appUser registration factory for AngularJS + Firebase appLogin UI for an Android appAngular Guards - Firebase loggedInAndVerifiedMake methods shorter when parsing Firebase dataJava Swing MVC implementation for login processFirebase Plotter for IonicAndroid app to take a photos and show them in a gallery

Why doesn't the fusion process of the sun speed up?

Recursively updating the MLE as new observations stream in

When did hardware antialiasing start being available?

Why is participating in the European Parliamentary elections used as a threat?

Why does Surtur say that Thor is Asgard's doom?

Imaginary part of expression too difficult to calculate

Hackerrank All Women's Codesprint 2019: Name the Product

Asserting that Atheism and Theism are both faith based positions

Exposing a company lying about themselves in a tightly knit industry: Is my career at risk on the long run?

Can "few" be used as a subject? If so, what is the rule?

Would this string work as string?

What is 管理しきれず?

DisplayForm problem with pi in FractionBox

label a part of commutative diagram

How are passwords stolen from companies if they only store hashes?

Does fire aspect on a sword, destroy mob drops?

Could any one tell what PN is this Chip? Thanks~

Help with identifying unique aircraft over NE Pennsylvania

Why is there so much iron?

Knife as defense against stray dogs

If I cast the Enlarge/Reduce spell on an arrow, what weapon could it count as?

What is the tangent at a sharp point on a curve?

Did Nintendo change its mind about 68000 SNES?

Have any astronauts/cosmonauts died in space?



Firebase login/registration process for a dating app


Registration and loginLogin and registration functionsSimple login and authentication appUser registration factory for AngularJS + Firebase appLogin UI for an Android appAngular Guards - Firebase loggedInAndVerifiedMake methods shorter when parsing Firebase dataJava Swing MVC implementation for login processFirebase Plotter for IonicAndroid app to take a photos and show them in a gallery













0












$begingroup$


I am developing another bigger project, I want to try a simple DatingApp and currently I try to develop a Login and Registration Form. There is no special register / login button, the code will later decide wether email is registered (-> login) or not (-> register). But even though it's working I am not sure if I make things to complex:



First I want so show a very simple overview of the logic I try to develop:



enter image description here



The App launches with the LogoActivity as a simple SplashScreen. In here the Activity decides which Activity and Fragment is about to be displayed next. It has a sharedElementTransition connected to the AuthOptionActivity.



The AuthOptionActivity only contains the Logo and a fragment Container.

Depending on the AuthStatus it will show the AuthOptionFragment, containing a Layout with two Buttons. Here you can decide which way you want to use for your registration.



In case there is for example an email-registered user but he is not verified yet the AuthOptionActivity will show the MailAuthFragment instead of the AuthOptionFragment.



The MailAuthOptionFragment itself contains another two ChildFragments.

The EnterMailSubFragment contains two EditText-Views and the ConfirmMailSubFragment is just a Text containing the Email Adress and a clickable resend textview (not implemented yet).



The code so far implemented is working but it is not as clear as I want it to be.



Logo Activity



public class LogoActivity extends AppCompatActivity 

private ImageView mLogo;
private Handler mHandler;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logo);
this.init();


private void init()
mLogo = findViewById(R.id.activity_logo_logo);
AuthHandler.performStartUpCheck(new AuthHandler.StartupAuthStatus()
@Override
public void noUser()
Toast.makeText(LogoActivity.this, "No User", Toast.LENGTH_SHORT).show();
performSharedElementTransactionToAuthOption();


@Override
public void onError(String e)
Toast.makeText(LogoActivity.this, e, Toast.LENGTH_SHORT).show();
performSharedElementTransactionToAuthOption();


@Override
public void onPhone()
Toast.makeText(LogoActivity.this, "Phone", Toast.LENGTH_SHORT).show();
//direct to loadingActivity


@Override
public void onEmail(boolean isVerified)
Toast.makeText(LogoActivity.this, "Email" + String.valueOf(isVerified), Toast.LENGTH_SHORT).show();
if(isVerified)
//direct to LoadingActivity
else
performSharedElementTransactionToAuthOption();


);
//this.performSharedElementTransaction();


private void performSharedElementTransactionToAuthOption()
//check for auth and proceed to Loading
Intent pIntent = new Intent(LogoActivity.this, AuthOptionActivity.class);
ActivityOptions mOptions = ActivityOptions.makeSceneTransitionAnimation(LogoActivity.this, mLogo, mLogo.getTransitionName());
startActivity(pIntent, mOptions.toBundle());



private void performTransactionToLoadingScreen()
/**dummy**/


@Override
protected void onStop()
//Call finish here to avoid flickering
this.finish();
super.onStop();




Nothing so special here, I am quite happy with that class. Disregard some comments, they are just for me as a reminder.



AuthHandler



public class AuthHandler 

public interface StartupAuthStatus
void noUser();
void onError(String e);
void onPhone();
void onEmail(boolean isVerified);


public interface SignInStatus
void onEmail(boolean isVerified);


private FirebaseAuth mAuth;
private FirebaseFirestore mFirestore;

/**STARTUP PROCEDURE**/

public static void performStartUpCheck(final StartupAuthStatus mCallback)
final FirebaseAuth mAuth = FirebaseAuth.getInstance();
checkStartupAuthStatus(mAuth, mCallback);



private static void checkStartupAuthStatus(FirebaseAuth mAuth, StartupAuthStatus mCallback)
mAuth = FirebaseAuth.getInstance();
checkForCurrentUser(mAuth,mCallback);


private static void checkForCurrentUser(FirebaseAuth mAuth, StartupAuthStatus mCallback)
if(mAuth.getCurrentUser()!=null)
checkRegistrationMethod(mAuth, mCallback);
else
mCallback.noUser();



private static void checkRegistrationMethod(final FirebaseAuth mAuth, final StartupAuthStatus mCallback)
if(mAuth.getUid() == null)
mCallback.onError("NullPointerInUID");
return;

FirebaseFirestore.getInstance().collection("Registration").document(mAuth.getUid()).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>()
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task)
if(task.getResult() != null && task.getResult().exists())
Map<String, Object> mData = task.getResult().getData();
String mRegistrationForm = (String) mData.get("reg");
if(mRegistrationForm.equals("mail"))
checkMailVerificationStatus(mAuth, mCallback);
else if(mRegistrationForm.equals("phone"))
mCallback.onPhone();



).addOnFailureListener(new OnFailureListener()
@Override
public void onFailure(@NonNull Exception e)
mCallback.onError(e.getMessage());
mAuth.signOut();

);


private static void checkMailVerificationStatus(FirebaseAuth mAuth, StartupAuthStatus mCallback)
if(mAuth.getCurrentUser().isEmailVerified())
mCallback.onEmail(true);
else
mCallback.onEmail(false);



/**LOGIN PROCEDURE**/

public static void enterUserWithEmailAndPassword(String mEmail, String mPassword)
FirebaseAuth mAuth = FirebaseAuth.getInstance();
createUserWithEmailAndPassword(mAuth, mEmail, mPassword);


private static void createUserWithEmailAndPassword(FirebaseAuth mAuth, String mEmail, String mPassword)



private static void signUserWithEmailAndPassword(FirebaseAuth mAuth, String mEmail, String mPassword)



private static void sendVerificationEmail(FirebaseAuth mAuth)



private static void setupRegistrationModel(String mModelType)



/**DELETE PROCEDURE**/



This class is made to "outsource" the code mess. Here I am not sure if it's a common or even usefull way to handle this. The Database contains Users (with a lot of Data later) and a Pool of Registrations, here I only store the choosen registration form (field reg(String): "phone" or "mail").



I need to seperate it somehow as the email-registrated-user needs to verify the email.



AuthOptionActivity



public class AuthOptionActivity extends AppCompatActivity 

@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_authoption);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
getWindow().setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(android.R.transition.move));

this.checkAuthStatus();


@Override
public void onBackPressed()
findViewById(R.id.activity_authoption_logo).setTransitionName(null);
super.onBackPressed();
/** Problem occured: SharedViewElement will be visible after App was closed.
* Reason: The View will try to perform the ExitTransition
* Solution 1: Delete super.onBackPressed(); and override with finish();
* Solution 2: Set Transitionname to Null**/


/**The SlideEnter Transition is variable, on First Startup we want a smooth slide in,
* for phoneauth we want a Left-Side Slide and for Email a Right-Side Slide.
* The Exit Animation is always slide-out-bottom-smooth.
* The Reenter Animation is always slide-in-bottom-smooth and due to overlapping
* the ExitTransition of the View before BackPress will be hidden and is always 0**/

private void performFragmentTransaction(Fragment mFragment, String mTag, Boolean mAddToBackStack, int mEnterTransition)
FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.setCustomAnimations(mEnterTransition, 0, R.anim.slide_in_bottom_smooth, 0);
if(mAddToBackStack)
mFragmentTransaction.addToBackStack(mTag);

mFragmentTransaction.replace(R.id.activity_authoption_container, mFragment, mTag);
mFragmentTransaction.commit();



/**Check Auth Status: if CurrentUser != null but not Email verified -> Show MailAuth**/
private void checkAuthStatus()
if(FirebaseAuth.getInstance().getCurrentUser()!=null && !FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
//very bad way to force a backstack, still looking for a solution
this.showAuthOptionFragment();
this.showMailAuth();
else
this.showAuthOptionFragment();



/**Handle Fragment Transaction including Listener**/
private void showAuthOptionFragment()
this.performFragmentTransaction(AuthOptionFragment.newInstance(new AuthOptionFragment.ClickListener()
@Override
public void onMail()
showMailAuth();


@Override
public void onPhone()
showPhoneAuth();

), "AuthOption", false, R.anim.slide_in_bottom);


private void showPhoneAuth()
this.performFragmentTransaction(_PhoneAuthFragment.newInstance(new _PhoneAuthFragment.AuthStatusListener()
@Override
public void onCancel()
//PhoneAuthFragment contains a "back" Button it will fire "onCancel()"
onBackPressed();


@Override
public void onSuccess()
//show LoadingScreen

), "PhoneAuth", true, R.anim.slide_in_left_smooth);


private void showMailAuth()
this.performFragmentTransaction(_MailAuthFragment.newInstance(new _MailAuthFragment.AuthStatusListener()
@Override
public void onCancel()
//MailAuthFragment contains a "back" Button it will fire "onCancel()"
onBackPressed();


@Override
public void onSuccess()
//show LoadingScreen

), "MailAuth", true, R.anim.slide_in_right_smooth);





For this activity I have some questions:



  1. I am checking the Auth Status & email again to decide which fragment to show. It's easy and simple, but repetitive (it will occur again in MailAuthFragment). Is it a common way to repetitive use FirebaseAuth instances?

  2. I have seen a couple of fragment -> activity communication solutions using onAttach etc. Is my solution to pass a CustomListener(interface) in the newInstance method okay? Is there any bug that could occur using it that way?

    I pretty much like it as it makes the handling easier.

MailAuthOptionFragment



public class _MailAuthFragment extends Fragment 

public interface AuthStatusListener
void onCancel();
void onSuccess();


private AuthStatusListener mCallback;
private String mActiveWindow;
private CheckCancelButton mCheckCancelButton;

private String mEmail;
private String mPassword;

@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);


@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
View mView = inflater.inflate(R.layout.fragment_mailauth, container, false);
this.checkAuthStatus();
this.initButton(mView);
return mView;


/**PUBLIC METHODS**/

/**Set the Fragment Listener for AuthOptionActivity**/
public void setListener(AuthStatusListener mCallback)
this.mCallback = mCallback;


/**Replaces hard coded Instances as Listener will be passed directly**/
public static _MailAuthFragment newInstance(AuthStatusListener mCallback)
_MailAuthFragment mFragment = new _MailAuthFragment();
mFragment.setListener(mCallback);
return mFragment;


/**PRIVATE METHODS**/

/**Check AuthStatus, if CurrentUser!=null but not verified -> Show VerificationScreen**/
private void checkAuthStatus()
if(FirebaseAuth.getInstance().getCurrentUser() != null && !FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
this.showConfirmEmailSubFragment(R.anim.slide_in_right_smooth);
else
this.showEnterEmailSubFragment(R.anim.slide_in_right_smooth);



/**Handle Registration Process Fragments**/
private void performFragmentTransaction(Fragment mFragment, String mTag, int mEnterAnim)
mActiveWindow = mTag;
FragmentTransaction mFragmentTransaction = getChildFragmentManager().beginTransaction();
mFragmentTransaction.setCustomAnimations(mEnterAnim, 0);
mFragmentTransaction.replace(R.id.fragment_mailauth_container, mFragment, mTag);
mFragmentTransaction.commit();


/**MailAuth receives any valid TextChange from SubFragment**/
private void showEnterEmailSubFragment(int mEnterAnim)

this.performFragmentTransaction(EnterMailSubFragment.newInstance(new EnterMailSubFragment.EnterMailListener()
@Override
public void onEmailChanged(String mEmail)
_MailAuthFragment.this.mEmail = mEmail;


@Override
public void onPasswordChanged(String mPassword)
_MailAuthFragment.this.mPassword = mPassword;

), "EnterMail", mEnterAnim);



/**MailAuth receives resend VerificationEmailRequest from SubFragment**/
private void showConfirmEmailSubFragment(int mEnterAnim)
this.performFragmentTransaction(new ConfirmMailSubFragment(), "ConfirmMail", R.anim.slide_in_right_smooth);


private void initButton(final View mView)
/**Custom Button using AfterEffects, Bodymovin and LottieView, contains some commands like "transform to tick"**/
mCheckCancelButton = new CheckCancelButton((LottieAnimationView)mView.findViewById(R.id.fragment_mailauth_nextBtn));
mCheckCancelButton.setCustomClickListener(new CheckCancelButton.CheckCancelButtonClickListener()
@Override
public void onClick()
switch(mActiveWindow)
case "EnterMail":
// the received Email and Password will be passed to AuthHandlerClass - not implemented yet
break;
case "ConfirmMail":
// the AuthHandler will reloard the currentUser and check for email verification Status - not implemented yet
break;


);





Checking AuthStatus again and choosing whether to show the EnterEmailSubFragment or the ConfirmEmailSubFragment. This class contains a button handling both SubFragment pages. This leads to that switch-case method. Not sure if that is a proper way.



EnterMailSubFragment



public class EnterMailSubFragment extends Fragment 

public interface EnterMailListener
void onEmailChanged(String mEmail);
void onPasswordChanged(String mPassword);


private EnterMailListener mCallback;
private EditText mEmail, mPassword;
private ImageView mEmailWarning, mPasswordWarning;

@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
View mView = inflater.inflate(R.layout.subfragment_mailauth, container, false);
this.initUiWidgets(mView);
this.initEditText(mView);
return mView;


public void setEnterMailListener(EnterMailListener mMailListener)
this.mCallback = mMailListener;


public static EnterMailSubFragment newInstance(EnterMailListener mMailListener)
EnterMailSubFragment mFragment = new EnterMailSubFragment();
mFragment.setEnterMailListener(mMailListener);
return mFragment;


private void initUiWidgets(View mView)
mEmail = mView.findViewById(R.id.subfragment_mailauth_email_ET);
mPassword = mView.findViewById(R.id.subfragment_mailauth_password_et);
mEmailWarning = mView.findViewById(R.id.subfragment_mailauth_email_warning);
mPasswordWarning = mView.findViewById(R.id.subfragment_mailauth_password_warning);


/**Any Valid Entry will be passed to MailFragment**/

private void initEditText(final View mView)
mEmail.addTextChangedListener(new TextWatcher()
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)



@Override
public void onTextChanged(CharSequence s, int start, int before, int count)



@Override
public void afterTextChanged(Editable s)
if(mEmail.getText() != null && Patterns.EMAIL_ADDRESS.matcher(mEmail.getText().toString()).matches())
mEmailWarning.setVisibility(View.GONE);
mCallback.onEmailChanged(mEmail.getText().toString());
else
mEmailWarning.setVisibility(View.VISIBLE);


);

mPassword.addTextChangedListener(new TextWatcher()
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)



@Override
public void onTextChanged(CharSequence s, int start, int before, int count)


@Override
public void afterTextChanged(Editable s)
if(mPassword.getText() != null && mPassword.getText().length() >= 6)
mPasswordWarning.setVisibility(View.GONE);
mCallback.onPasswordChanged(mPassword.getText().toString());
else
mPasswordWarning.setVisibility(View.VISIBLE);


);




The Textwatcher checks every entry and transfers it to the MailAuthFragment as MailAuthFragment handels the button event (this is for design puposes, I want the content to move and the button is meant to stay in its position).



ConfirmMailAuthSubFragment



public class ConfirmMailSubFragment extends Fragment 

public interface ConfirmMailListener
void onResendEmail();


private ConfirmMailListener mCallback;

@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);


@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
View mView = inflater.inflate(R.layout.subfragment_confirmmail, container, false);

return mView;


public void setConfirmMailListener(ConfirmMailListener mCallback)
this.mCallback = mCallback;


public static ConfirmMailSubFragment newInstance(ConfirmMailListener mCallback)
ConfirmMailSubFragment mFragment = new ConfirmMailSubFragment();
mFragment.setConfirmMailListener(mCallback);
return mFragment;




Nothing special here yet. It will handle the Button Event "Resend Verification Mail" and transfer it to MailAuthFragment.



I know it's a very early stage of my code but as beautiful as it looks with that slide in animations I am not sure if I am running in the wrong direction or making stuff unnecessary complex.










share|improve this question











$endgroup$
















    0












    $begingroup$


    I am developing another bigger project, I want to try a simple DatingApp and currently I try to develop a Login and Registration Form. There is no special register / login button, the code will later decide wether email is registered (-> login) or not (-> register). But even though it's working I am not sure if I make things to complex:



    First I want so show a very simple overview of the logic I try to develop:



    enter image description here



    The App launches with the LogoActivity as a simple SplashScreen. In here the Activity decides which Activity and Fragment is about to be displayed next. It has a sharedElementTransition connected to the AuthOptionActivity.



    The AuthOptionActivity only contains the Logo and a fragment Container.

    Depending on the AuthStatus it will show the AuthOptionFragment, containing a Layout with two Buttons. Here you can decide which way you want to use for your registration.



    In case there is for example an email-registered user but he is not verified yet the AuthOptionActivity will show the MailAuthFragment instead of the AuthOptionFragment.



    The MailAuthOptionFragment itself contains another two ChildFragments.

    The EnterMailSubFragment contains two EditText-Views and the ConfirmMailSubFragment is just a Text containing the Email Adress and a clickable resend textview (not implemented yet).



    The code so far implemented is working but it is not as clear as I want it to be.



    Logo Activity



    public class LogoActivity extends AppCompatActivity 

    private ImageView mLogo;
    private Handler mHandler;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState)
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_logo);
    this.init();


    private void init()
    mLogo = findViewById(R.id.activity_logo_logo);
    AuthHandler.performStartUpCheck(new AuthHandler.StartupAuthStatus()
    @Override
    public void noUser()
    Toast.makeText(LogoActivity.this, "No User", Toast.LENGTH_SHORT).show();
    performSharedElementTransactionToAuthOption();


    @Override
    public void onError(String e)
    Toast.makeText(LogoActivity.this, e, Toast.LENGTH_SHORT).show();
    performSharedElementTransactionToAuthOption();


    @Override
    public void onPhone()
    Toast.makeText(LogoActivity.this, "Phone", Toast.LENGTH_SHORT).show();
    //direct to loadingActivity


    @Override
    public void onEmail(boolean isVerified)
    Toast.makeText(LogoActivity.this, "Email" + String.valueOf(isVerified), Toast.LENGTH_SHORT).show();
    if(isVerified)
    //direct to LoadingActivity
    else
    performSharedElementTransactionToAuthOption();


    );
    //this.performSharedElementTransaction();


    private void performSharedElementTransactionToAuthOption()
    //check for auth and proceed to Loading
    Intent pIntent = new Intent(LogoActivity.this, AuthOptionActivity.class);
    ActivityOptions mOptions = ActivityOptions.makeSceneTransitionAnimation(LogoActivity.this, mLogo, mLogo.getTransitionName());
    startActivity(pIntent, mOptions.toBundle());



    private void performTransactionToLoadingScreen()
    /**dummy**/


    @Override
    protected void onStop()
    //Call finish here to avoid flickering
    this.finish();
    super.onStop();




    Nothing so special here, I am quite happy with that class. Disregard some comments, they are just for me as a reminder.



    AuthHandler



    public class AuthHandler 

    public interface StartupAuthStatus
    void noUser();
    void onError(String e);
    void onPhone();
    void onEmail(boolean isVerified);


    public interface SignInStatus
    void onEmail(boolean isVerified);


    private FirebaseAuth mAuth;
    private FirebaseFirestore mFirestore;

    /**STARTUP PROCEDURE**/

    public static void performStartUpCheck(final StartupAuthStatus mCallback)
    final FirebaseAuth mAuth = FirebaseAuth.getInstance();
    checkStartupAuthStatus(mAuth, mCallback);



    private static void checkStartupAuthStatus(FirebaseAuth mAuth, StartupAuthStatus mCallback)
    mAuth = FirebaseAuth.getInstance();
    checkForCurrentUser(mAuth,mCallback);


    private static void checkForCurrentUser(FirebaseAuth mAuth, StartupAuthStatus mCallback)
    if(mAuth.getCurrentUser()!=null)
    checkRegistrationMethod(mAuth, mCallback);
    else
    mCallback.noUser();



    private static void checkRegistrationMethod(final FirebaseAuth mAuth, final StartupAuthStatus mCallback)
    if(mAuth.getUid() == null)
    mCallback.onError("NullPointerInUID");
    return;

    FirebaseFirestore.getInstance().collection("Registration").document(mAuth.getUid()).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>()
    @Override
    public void onComplete(@NonNull Task<DocumentSnapshot> task)
    if(task.getResult() != null && task.getResult().exists())
    Map<String, Object> mData = task.getResult().getData();
    String mRegistrationForm = (String) mData.get("reg");
    if(mRegistrationForm.equals("mail"))
    checkMailVerificationStatus(mAuth, mCallback);
    else if(mRegistrationForm.equals("phone"))
    mCallback.onPhone();



    ).addOnFailureListener(new OnFailureListener()
    @Override
    public void onFailure(@NonNull Exception e)
    mCallback.onError(e.getMessage());
    mAuth.signOut();

    );


    private static void checkMailVerificationStatus(FirebaseAuth mAuth, StartupAuthStatus mCallback)
    if(mAuth.getCurrentUser().isEmailVerified())
    mCallback.onEmail(true);
    else
    mCallback.onEmail(false);



    /**LOGIN PROCEDURE**/

    public static void enterUserWithEmailAndPassword(String mEmail, String mPassword)
    FirebaseAuth mAuth = FirebaseAuth.getInstance();
    createUserWithEmailAndPassword(mAuth, mEmail, mPassword);


    private static void createUserWithEmailAndPassword(FirebaseAuth mAuth, String mEmail, String mPassword)



    private static void signUserWithEmailAndPassword(FirebaseAuth mAuth, String mEmail, String mPassword)



    private static void sendVerificationEmail(FirebaseAuth mAuth)



    private static void setupRegistrationModel(String mModelType)



    /**DELETE PROCEDURE**/



    This class is made to "outsource" the code mess. Here I am not sure if it's a common or even usefull way to handle this. The Database contains Users (with a lot of Data later) and a Pool of Registrations, here I only store the choosen registration form (field reg(String): "phone" or "mail").



    I need to seperate it somehow as the email-registrated-user needs to verify the email.



    AuthOptionActivity



    public class AuthOptionActivity extends AppCompatActivity 

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState)
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_authoption);
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    getWindow().setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(android.R.transition.move));

    this.checkAuthStatus();


    @Override
    public void onBackPressed()
    findViewById(R.id.activity_authoption_logo).setTransitionName(null);
    super.onBackPressed();
    /** Problem occured: SharedViewElement will be visible after App was closed.
    * Reason: The View will try to perform the ExitTransition
    * Solution 1: Delete super.onBackPressed(); and override with finish();
    * Solution 2: Set Transitionname to Null**/


    /**The SlideEnter Transition is variable, on First Startup we want a smooth slide in,
    * for phoneauth we want a Left-Side Slide and for Email a Right-Side Slide.
    * The Exit Animation is always slide-out-bottom-smooth.
    * The Reenter Animation is always slide-in-bottom-smooth and due to overlapping
    * the ExitTransition of the View before BackPress will be hidden and is always 0**/

    private void performFragmentTransaction(Fragment mFragment, String mTag, Boolean mAddToBackStack, int mEnterTransition)
    FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
    mFragmentTransaction.setCustomAnimations(mEnterTransition, 0, R.anim.slide_in_bottom_smooth, 0);
    if(mAddToBackStack)
    mFragmentTransaction.addToBackStack(mTag);

    mFragmentTransaction.replace(R.id.activity_authoption_container, mFragment, mTag);
    mFragmentTransaction.commit();



    /**Check Auth Status: if CurrentUser != null but not Email verified -> Show MailAuth**/
    private void checkAuthStatus()
    if(FirebaseAuth.getInstance().getCurrentUser()!=null && !FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
    //very bad way to force a backstack, still looking for a solution
    this.showAuthOptionFragment();
    this.showMailAuth();
    else
    this.showAuthOptionFragment();



    /**Handle Fragment Transaction including Listener**/
    private void showAuthOptionFragment()
    this.performFragmentTransaction(AuthOptionFragment.newInstance(new AuthOptionFragment.ClickListener()
    @Override
    public void onMail()
    showMailAuth();


    @Override
    public void onPhone()
    showPhoneAuth();

    ), "AuthOption", false, R.anim.slide_in_bottom);


    private void showPhoneAuth()
    this.performFragmentTransaction(_PhoneAuthFragment.newInstance(new _PhoneAuthFragment.AuthStatusListener()
    @Override
    public void onCancel()
    //PhoneAuthFragment contains a "back" Button it will fire "onCancel()"
    onBackPressed();


    @Override
    public void onSuccess()
    //show LoadingScreen

    ), "PhoneAuth", true, R.anim.slide_in_left_smooth);


    private void showMailAuth()
    this.performFragmentTransaction(_MailAuthFragment.newInstance(new _MailAuthFragment.AuthStatusListener()
    @Override
    public void onCancel()
    //MailAuthFragment contains a "back" Button it will fire "onCancel()"
    onBackPressed();


    @Override
    public void onSuccess()
    //show LoadingScreen

    ), "MailAuth", true, R.anim.slide_in_right_smooth);





    For this activity I have some questions:



    1. I am checking the Auth Status & email again to decide which fragment to show. It's easy and simple, but repetitive (it will occur again in MailAuthFragment). Is it a common way to repetitive use FirebaseAuth instances?

    2. I have seen a couple of fragment -> activity communication solutions using onAttach etc. Is my solution to pass a CustomListener(interface) in the newInstance method okay? Is there any bug that could occur using it that way?

      I pretty much like it as it makes the handling easier.

    MailAuthOptionFragment



    public class _MailAuthFragment extends Fragment 

    public interface AuthStatusListener
    void onCancel();
    void onSuccess();


    private AuthStatusListener mCallback;
    private String mActiveWindow;
    private CheckCancelButton mCheckCancelButton;

    private String mEmail;
    private String mPassword;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState)
    super.onCreate(savedInstanceState);


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    View mView = inflater.inflate(R.layout.fragment_mailauth, container, false);
    this.checkAuthStatus();
    this.initButton(mView);
    return mView;


    /**PUBLIC METHODS**/

    /**Set the Fragment Listener for AuthOptionActivity**/
    public void setListener(AuthStatusListener mCallback)
    this.mCallback = mCallback;


    /**Replaces hard coded Instances as Listener will be passed directly**/
    public static _MailAuthFragment newInstance(AuthStatusListener mCallback)
    _MailAuthFragment mFragment = new _MailAuthFragment();
    mFragment.setListener(mCallback);
    return mFragment;


    /**PRIVATE METHODS**/

    /**Check AuthStatus, if CurrentUser!=null but not verified -> Show VerificationScreen**/
    private void checkAuthStatus()
    if(FirebaseAuth.getInstance().getCurrentUser() != null && !FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
    this.showConfirmEmailSubFragment(R.anim.slide_in_right_smooth);
    else
    this.showEnterEmailSubFragment(R.anim.slide_in_right_smooth);



    /**Handle Registration Process Fragments**/
    private void performFragmentTransaction(Fragment mFragment, String mTag, int mEnterAnim)
    mActiveWindow = mTag;
    FragmentTransaction mFragmentTransaction = getChildFragmentManager().beginTransaction();
    mFragmentTransaction.setCustomAnimations(mEnterAnim, 0);
    mFragmentTransaction.replace(R.id.fragment_mailauth_container, mFragment, mTag);
    mFragmentTransaction.commit();


    /**MailAuth receives any valid TextChange from SubFragment**/
    private void showEnterEmailSubFragment(int mEnterAnim)

    this.performFragmentTransaction(EnterMailSubFragment.newInstance(new EnterMailSubFragment.EnterMailListener()
    @Override
    public void onEmailChanged(String mEmail)
    _MailAuthFragment.this.mEmail = mEmail;


    @Override
    public void onPasswordChanged(String mPassword)
    _MailAuthFragment.this.mPassword = mPassword;

    ), "EnterMail", mEnterAnim);



    /**MailAuth receives resend VerificationEmailRequest from SubFragment**/
    private void showConfirmEmailSubFragment(int mEnterAnim)
    this.performFragmentTransaction(new ConfirmMailSubFragment(), "ConfirmMail", R.anim.slide_in_right_smooth);


    private void initButton(final View mView)
    /**Custom Button using AfterEffects, Bodymovin and LottieView, contains some commands like "transform to tick"**/
    mCheckCancelButton = new CheckCancelButton((LottieAnimationView)mView.findViewById(R.id.fragment_mailauth_nextBtn));
    mCheckCancelButton.setCustomClickListener(new CheckCancelButton.CheckCancelButtonClickListener()
    @Override
    public void onClick()
    switch(mActiveWindow)
    case "EnterMail":
    // the received Email and Password will be passed to AuthHandlerClass - not implemented yet
    break;
    case "ConfirmMail":
    // the AuthHandler will reloard the currentUser and check for email verification Status - not implemented yet
    break;


    );





    Checking AuthStatus again and choosing whether to show the EnterEmailSubFragment or the ConfirmEmailSubFragment. This class contains a button handling both SubFragment pages. This leads to that switch-case method. Not sure if that is a proper way.



    EnterMailSubFragment



    public class EnterMailSubFragment extends Fragment 

    public interface EnterMailListener
    void onEmailChanged(String mEmail);
    void onPasswordChanged(String mPassword);


    private EnterMailListener mCallback;
    private EditText mEmail, mPassword;
    private ImageView mEmailWarning, mPasswordWarning;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState)
    super.onCreate(savedInstanceState);

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    View mView = inflater.inflate(R.layout.subfragment_mailauth, container, false);
    this.initUiWidgets(mView);
    this.initEditText(mView);
    return mView;


    public void setEnterMailListener(EnterMailListener mMailListener)
    this.mCallback = mMailListener;


    public static EnterMailSubFragment newInstance(EnterMailListener mMailListener)
    EnterMailSubFragment mFragment = new EnterMailSubFragment();
    mFragment.setEnterMailListener(mMailListener);
    return mFragment;


    private void initUiWidgets(View mView)
    mEmail = mView.findViewById(R.id.subfragment_mailauth_email_ET);
    mPassword = mView.findViewById(R.id.subfragment_mailauth_password_et);
    mEmailWarning = mView.findViewById(R.id.subfragment_mailauth_email_warning);
    mPasswordWarning = mView.findViewById(R.id.subfragment_mailauth_password_warning);


    /**Any Valid Entry will be passed to MailFragment**/

    private void initEditText(final View mView)
    mEmail.addTextChangedListener(new TextWatcher()
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after)



    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count)



    @Override
    public void afterTextChanged(Editable s)
    if(mEmail.getText() != null && Patterns.EMAIL_ADDRESS.matcher(mEmail.getText().toString()).matches())
    mEmailWarning.setVisibility(View.GONE);
    mCallback.onEmailChanged(mEmail.getText().toString());
    else
    mEmailWarning.setVisibility(View.VISIBLE);


    );

    mPassword.addTextChangedListener(new TextWatcher()
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after)



    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count)


    @Override
    public void afterTextChanged(Editable s)
    if(mPassword.getText() != null && mPassword.getText().length() >= 6)
    mPasswordWarning.setVisibility(View.GONE);
    mCallback.onPasswordChanged(mPassword.getText().toString());
    else
    mPasswordWarning.setVisibility(View.VISIBLE);


    );




    The Textwatcher checks every entry and transfers it to the MailAuthFragment as MailAuthFragment handels the button event (this is for design puposes, I want the content to move and the button is meant to stay in its position).



    ConfirmMailAuthSubFragment



    public class ConfirmMailSubFragment extends Fragment 

    public interface ConfirmMailListener
    void onResendEmail();


    private ConfirmMailListener mCallback;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState)
    super.onCreate(savedInstanceState);


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
    View mView = inflater.inflate(R.layout.subfragment_confirmmail, container, false);

    return mView;


    public void setConfirmMailListener(ConfirmMailListener mCallback)
    this.mCallback = mCallback;


    public static ConfirmMailSubFragment newInstance(ConfirmMailListener mCallback)
    ConfirmMailSubFragment mFragment = new ConfirmMailSubFragment();
    mFragment.setConfirmMailListener(mCallback);
    return mFragment;




    Nothing special here yet. It will handle the Button Event "Resend Verification Mail" and transfer it to MailAuthFragment.



    I know it's a very early stage of my code but as beautiful as it looks with that slide in animations I am not sure if I am running in the wrong direction or making stuff unnecessary complex.










    share|improve this question











    $endgroup$














      0












      0








      0





      $begingroup$


      I am developing another bigger project, I want to try a simple DatingApp and currently I try to develop a Login and Registration Form. There is no special register / login button, the code will later decide wether email is registered (-> login) or not (-> register). But even though it's working I am not sure if I make things to complex:



      First I want so show a very simple overview of the logic I try to develop:



      enter image description here



      The App launches with the LogoActivity as a simple SplashScreen. In here the Activity decides which Activity and Fragment is about to be displayed next. It has a sharedElementTransition connected to the AuthOptionActivity.



      The AuthOptionActivity only contains the Logo and a fragment Container.

      Depending on the AuthStatus it will show the AuthOptionFragment, containing a Layout with two Buttons. Here you can decide which way you want to use for your registration.



      In case there is for example an email-registered user but he is not verified yet the AuthOptionActivity will show the MailAuthFragment instead of the AuthOptionFragment.



      The MailAuthOptionFragment itself contains another two ChildFragments.

      The EnterMailSubFragment contains two EditText-Views and the ConfirmMailSubFragment is just a Text containing the Email Adress and a clickable resend textview (not implemented yet).



      The code so far implemented is working but it is not as clear as I want it to be.



      Logo Activity



      public class LogoActivity extends AppCompatActivity 

      private ImageView mLogo;
      private Handler mHandler;

      @Override
      protected void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_logo);
      this.init();


      private void init()
      mLogo = findViewById(R.id.activity_logo_logo);
      AuthHandler.performStartUpCheck(new AuthHandler.StartupAuthStatus()
      @Override
      public void noUser()
      Toast.makeText(LogoActivity.this, "No User", Toast.LENGTH_SHORT).show();
      performSharedElementTransactionToAuthOption();


      @Override
      public void onError(String e)
      Toast.makeText(LogoActivity.this, e, Toast.LENGTH_SHORT).show();
      performSharedElementTransactionToAuthOption();


      @Override
      public void onPhone()
      Toast.makeText(LogoActivity.this, "Phone", Toast.LENGTH_SHORT).show();
      //direct to loadingActivity


      @Override
      public void onEmail(boolean isVerified)
      Toast.makeText(LogoActivity.this, "Email" + String.valueOf(isVerified), Toast.LENGTH_SHORT).show();
      if(isVerified)
      //direct to LoadingActivity
      else
      performSharedElementTransactionToAuthOption();


      );
      //this.performSharedElementTransaction();


      private void performSharedElementTransactionToAuthOption()
      //check for auth and proceed to Loading
      Intent pIntent = new Intent(LogoActivity.this, AuthOptionActivity.class);
      ActivityOptions mOptions = ActivityOptions.makeSceneTransitionAnimation(LogoActivity.this, mLogo, mLogo.getTransitionName());
      startActivity(pIntent, mOptions.toBundle());



      private void performTransactionToLoadingScreen()
      /**dummy**/


      @Override
      protected void onStop()
      //Call finish here to avoid flickering
      this.finish();
      super.onStop();




      Nothing so special here, I am quite happy with that class. Disregard some comments, they are just for me as a reminder.



      AuthHandler



      public class AuthHandler 

      public interface StartupAuthStatus
      void noUser();
      void onError(String e);
      void onPhone();
      void onEmail(boolean isVerified);


      public interface SignInStatus
      void onEmail(boolean isVerified);


      private FirebaseAuth mAuth;
      private FirebaseFirestore mFirestore;

      /**STARTUP PROCEDURE**/

      public static void performStartUpCheck(final StartupAuthStatus mCallback)
      final FirebaseAuth mAuth = FirebaseAuth.getInstance();
      checkStartupAuthStatus(mAuth, mCallback);



      private static void checkStartupAuthStatus(FirebaseAuth mAuth, StartupAuthStatus mCallback)
      mAuth = FirebaseAuth.getInstance();
      checkForCurrentUser(mAuth,mCallback);


      private static void checkForCurrentUser(FirebaseAuth mAuth, StartupAuthStatus mCallback)
      if(mAuth.getCurrentUser()!=null)
      checkRegistrationMethod(mAuth, mCallback);
      else
      mCallback.noUser();



      private static void checkRegistrationMethod(final FirebaseAuth mAuth, final StartupAuthStatus mCallback)
      if(mAuth.getUid() == null)
      mCallback.onError("NullPointerInUID");
      return;

      FirebaseFirestore.getInstance().collection("Registration").document(mAuth.getUid()).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>()
      @Override
      public void onComplete(@NonNull Task<DocumentSnapshot> task)
      if(task.getResult() != null && task.getResult().exists())
      Map<String, Object> mData = task.getResult().getData();
      String mRegistrationForm = (String) mData.get("reg");
      if(mRegistrationForm.equals("mail"))
      checkMailVerificationStatus(mAuth, mCallback);
      else if(mRegistrationForm.equals("phone"))
      mCallback.onPhone();



      ).addOnFailureListener(new OnFailureListener()
      @Override
      public void onFailure(@NonNull Exception e)
      mCallback.onError(e.getMessage());
      mAuth.signOut();

      );


      private static void checkMailVerificationStatus(FirebaseAuth mAuth, StartupAuthStatus mCallback)
      if(mAuth.getCurrentUser().isEmailVerified())
      mCallback.onEmail(true);
      else
      mCallback.onEmail(false);



      /**LOGIN PROCEDURE**/

      public static void enterUserWithEmailAndPassword(String mEmail, String mPassword)
      FirebaseAuth mAuth = FirebaseAuth.getInstance();
      createUserWithEmailAndPassword(mAuth, mEmail, mPassword);


      private static void createUserWithEmailAndPassword(FirebaseAuth mAuth, String mEmail, String mPassword)



      private static void signUserWithEmailAndPassword(FirebaseAuth mAuth, String mEmail, String mPassword)



      private static void sendVerificationEmail(FirebaseAuth mAuth)



      private static void setupRegistrationModel(String mModelType)



      /**DELETE PROCEDURE**/



      This class is made to "outsource" the code mess. Here I am not sure if it's a common or even usefull way to handle this. The Database contains Users (with a lot of Data later) and a Pool of Registrations, here I only store the choosen registration form (field reg(String): "phone" or "mail").



      I need to seperate it somehow as the email-registrated-user needs to verify the email.



      AuthOptionActivity



      public class AuthOptionActivity extends AppCompatActivity 

      @Override
      protected void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_authoption);
      if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
      getWindow().setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(android.R.transition.move));

      this.checkAuthStatus();


      @Override
      public void onBackPressed()
      findViewById(R.id.activity_authoption_logo).setTransitionName(null);
      super.onBackPressed();
      /** Problem occured: SharedViewElement will be visible after App was closed.
      * Reason: The View will try to perform the ExitTransition
      * Solution 1: Delete super.onBackPressed(); and override with finish();
      * Solution 2: Set Transitionname to Null**/


      /**The SlideEnter Transition is variable, on First Startup we want a smooth slide in,
      * for phoneauth we want a Left-Side Slide and for Email a Right-Side Slide.
      * The Exit Animation is always slide-out-bottom-smooth.
      * The Reenter Animation is always slide-in-bottom-smooth and due to overlapping
      * the ExitTransition of the View before BackPress will be hidden and is always 0**/

      private void performFragmentTransaction(Fragment mFragment, String mTag, Boolean mAddToBackStack, int mEnterTransition)
      FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
      mFragmentTransaction.setCustomAnimations(mEnterTransition, 0, R.anim.slide_in_bottom_smooth, 0);
      if(mAddToBackStack)
      mFragmentTransaction.addToBackStack(mTag);

      mFragmentTransaction.replace(R.id.activity_authoption_container, mFragment, mTag);
      mFragmentTransaction.commit();



      /**Check Auth Status: if CurrentUser != null but not Email verified -> Show MailAuth**/
      private void checkAuthStatus()
      if(FirebaseAuth.getInstance().getCurrentUser()!=null && !FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
      //very bad way to force a backstack, still looking for a solution
      this.showAuthOptionFragment();
      this.showMailAuth();
      else
      this.showAuthOptionFragment();



      /**Handle Fragment Transaction including Listener**/
      private void showAuthOptionFragment()
      this.performFragmentTransaction(AuthOptionFragment.newInstance(new AuthOptionFragment.ClickListener()
      @Override
      public void onMail()
      showMailAuth();


      @Override
      public void onPhone()
      showPhoneAuth();

      ), "AuthOption", false, R.anim.slide_in_bottom);


      private void showPhoneAuth()
      this.performFragmentTransaction(_PhoneAuthFragment.newInstance(new _PhoneAuthFragment.AuthStatusListener()
      @Override
      public void onCancel()
      //PhoneAuthFragment contains a "back" Button it will fire "onCancel()"
      onBackPressed();


      @Override
      public void onSuccess()
      //show LoadingScreen

      ), "PhoneAuth", true, R.anim.slide_in_left_smooth);


      private void showMailAuth()
      this.performFragmentTransaction(_MailAuthFragment.newInstance(new _MailAuthFragment.AuthStatusListener()
      @Override
      public void onCancel()
      //MailAuthFragment contains a "back" Button it will fire "onCancel()"
      onBackPressed();


      @Override
      public void onSuccess()
      //show LoadingScreen

      ), "MailAuth", true, R.anim.slide_in_right_smooth);





      For this activity I have some questions:



      1. I am checking the Auth Status & email again to decide which fragment to show. It's easy and simple, but repetitive (it will occur again in MailAuthFragment). Is it a common way to repetitive use FirebaseAuth instances?

      2. I have seen a couple of fragment -> activity communication solutions using onAttach etc. Is my solution to pass a CustomListener(interface) in the newInstance method okay? Is there any bug that could occur using it that way?

        I pretty much like it as it makes the handling easier.

      MailAuthOptionFragment



      public class _MailAuthFragment extends Fragment 

      public interface AuthStatusListener
      void onCancel();
      void onSuccess();


      private AuthStatusListener mCallback;
      private String mActiveWindow;
      private CheckCancelButton mCheckCancelButton;

      private String mEmail;
      private String mPassword;

      @Override
      public void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);


      @Nullable
      @Override
      public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
      View mView = inflater.inflate(R.layout.fragment_mailauth, container, false);
      this.checkAuthStatus();
      this.initButton(mView);
      return mView;


      /**PUBLIC METHODS**/

      /**Set the Fragment Listener for AuthOptionActivity**/
      public void setListener(AuthStatusListener mCallback)
      this.mCallback = mCallback;


      /**Replaces hard coded Instances as Listener will be passed directly**/
      public static _MailAuthFragment newInstance(AuthStatusListener mCallback)
      _MailAuthFragment mFragment = new _MailAuthFragment();
      mFragment.setListener(mCallback);
      return mFragment;


      /**PRIVATE METHODS**/

      /**Check AuthStatus, if CurrentUser!=null but not verified -> Show VerificationScreen**/
      private void checkAuthStatus()
      if(FirebaseAuth.getInstance().getCurrentUser() != null && !FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
      this.showConfirmEmailSubFragment(R.anim.slide_in_right_smooth);
      else
      this.showEnterEmailSubFragment(R.anim.slide_in_right_smooth);



      /**Handle Registration Process Fragments**/
      private void performFragmentTransaction(Fragment mFragment, String mTag, int mEnterAnim)
      mActiveWindow = mTag;
      FragmentTransaction mFragmentTransaction = getChildFragmentManager().beginTransaction();
      mFragmentTransaction.setCustomAnimations(mEnterAnim, 0);
      mFragmentTransaction.replace(R.id.fragment_mailauth_container, mFragment, mTag);
      mFragmentTransaction.commit();


      /**MailAuth receives any valid TextChange from SubFragment**/
      private void showEnterEmailSubFragment(int mEnterAnim)

      this.performFragmentTransaction(EnterMailSubFragment.newInstance(new EnterMailSubFragment.EnterMailListener()
      @Override
      public void onEmailChanged(String mEmail)
      _MailAuthFragment.this.mEmail = mEmail;


      @Override
      public void onPasswordChanged(String mPassword)
      _MailAuthFragment.this.mPassword = mPassword;

      ), "EnterMail", mEnterAnim);



      /**MailAuth receives resend VerificationEmailRequest from SubFragment**/
      private void showConfirmEmailSubFragment(int mEnterAnim)
      this.performFragmentTransaction(new ConfirmMailSubFragment(), "ConfirmMail", R.anim.slide_in_right_smooth);


      private void initButton(final View mView)
      /**Custom Button using AfterEffects, Bodymovin and LottieView, contains some commands like "transform to tick"**/
      mCheckCancelButton = new CheckCancelButton((LottieAnimationView)mView.findViewById(R.id.fragment_mailauth_nextBtn));
      mCheckCancelButton.setCustomClickListener(new CheckCancelButton.CheckCancelButtonClickListener()
      @Override
      public void onClick()
      switch(mActiveWindow)
      case "EnterMail":
      // the received Email and Password will be passed to AuthHandlerClass - not implemented yet
      break;
      case "ConfirmMail":
      // the AuthHandler will reloard the currentUser and check for email verification Status - not implemented yet
      break;


      );





      Checking AuthStatus again and choosing whether to show the EnterEmailSubFragment or the ConfirmEmailSubFragment. This class contains a button handling both SubFragment pages. This leads to that switch-case method. Not sure if that is a proper way.



      EnterMailSubFragment



      public class EnterMailSubFragment extends Fragment 

      public interface EnterMailListener
      void onEmailChanged(String mEmail);
      void onPasswordChanged(String mPassword);


      private EnterMailListener mCallback;
      private EditText mEmail, mPassword;
      private ImageView mEmailWarning, mPasswordWarning;

      @Override
      public void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);

      @Nullable
      @Override
      public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
      View mView = inflater.inflate(R.layout.subfragment_mailauth, container, false);
      this.initUiWidgets(mView);
      this.initEditText(mView);
      return mView;


      public void setEnterMailListener(EnterMailListener mMailListener)
      this.mCallback = mMailListener;


      public static EnterMailSubFragment newInstance(EnterMailListener mMailListener)
      EnterMailSubFragment mFragment = new EnterMailSubFragment();
      mFragment.setEnterMailListener(mMailListener);
      return mFragment;


      private void initUiWidgets(View mView)
      mEmail = mView.findViewById(R.id.subfragment_mailauth_email_ET);
      mPassword = mView.findViewById(R.id.subfragment_mailauth_password_et);
      mEmailWarning = mView.findViewById(R.id.subfragment_mailauth_email_warning);
      mPasswordWarning = mView.findViewById(R.id.subfragment_mailauth_password_warning);


      /**Any Valid Entry will be passed to MailFragment**/

      private void initEditText(final View mView)
      mEmail.addTextChangedListener(new TextWatcher()
      @Override
      public void beforeTextChanged(CharSequence s, int start, int count, int after)



      @Override
      public void onTextChanged(CharSequence s, int start, int before, int count)



      @Override
      public void afterTextChanged(Editable s)
      if(mEmail.getText() != null && Patterns.EMAIL_ADDRESS.matcher(mEmail.getText().toString()).matches())
      mEmailWarning.setVisibility(View.GONE);
      mCallback.onEmailChanged(mEmail.getText().toString());
      else
      mEmailWarning.setVisibility(View.VISIBLE);


      );

      mPassword.addTextChangedListener(new TextWatcher()
      @Override
      public void beforeTextChanged(CharSequence s, int start, int count, int after)



      @Override
      public void onTextChanged(CharSequence s, int start, int before, int count)


      @Override
      public void afterTextChanged(Editable s)
      if(mPassword.getText() != null && mPassword.getText().length() >= 6)
      mPasswordWarning.setVisibility(View.GONE);
      mCallback.onPasswordChanged(mPassword.getText().toString());
      else
      mPasswordWarning.setVisibility(View.VISIBLE);


      );




      The Textwatcher checks every entry and transfers it to the MailAuthFragment as MailAuthFragment handels the button event (this is for design puposes, I want the content to move and the button is meant to stay in its position).



      ConfirmMailAuthSubFragment



      public class ConfirmMailSubFragment extends Fragment 

      public interface ConfirmMailListener
      void onResendEmail();


      private ConfirmMailListener mCallback;

      @Override
      public void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);


      @Nullable
      @Override
      public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
      View mView = inflater.inflate(R.layout.subfragment_confirmmail, container, false);

      return mView;


      public void setConfirmMailListener(ConfirmMailListener mCallback)
      this.mCallback = mCallback;


      public static ConfirmMailSubFragment newInstance(ConfirmMailListener mCallback)
      ConfirmMailSubFragment mFragment = new ConfirmMailSubFragment();
      mFragment.setConfirmMailListener(mCallback);
      return mFragment;




      Nothing special here yet. It will handle the Button Event "Resend Verification Mail" and transfer it to MailAuthFragment.



      I know it's a very early stage of my code but as beautiful as it looks with that slide in animations I am not sure if I am running in the wrong direction or making stuff unnecessary complex.










      share|improve this question











      $endgroup$




      I am developing another bigger project, I want to try a simple DatingApp and currently I try to develop a Login and Registration Form. There is no special register / login button, the code will later decide wether email is registered (-> login) or not (-> register). But even though it's working I am not sure if I make things to complex:



      First I want so show a very simple overview of the logic I try to develop:



      enter image description here



      The App launches with the LogoActivity as a simple SplashScreen. In here the Activity decides which Activity and Fragment is about to be displayed next. It has a sharedElementTransition connected to the AuthOptionActivity.



      The AuthOptionActivity only contains the Logo and a fragment Container.

      Depending on the AuthStatus it will show the AuthOptionFragment, containing a Layout with two Buttons. Here you can decide which way you want to use for your registration.



      In case there is for example an email-registered user but he is not verified yet the AuthOptionActivity will show the MailAuthFragment instead of the AuthOptionFragment.



      The MailAuthOptionFragment itself contains another two ChildFragments.

      The EnterMailSubFragment contains two EditText-Views and the ConfirmMailSubFragment is just a Text containing the Email Adress and a clickable resend textview (not implemented yet).



      The code so far implemented is working but it is not as clear as I want it to be.



      Logo Activity



      public class LogoActivity extends AppCompatActivity 

      private ImageView mLogo;
      private Handler mHandler;

      @Override
      protected void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_logo);
      this.init();


      private void init()
      mLogo = findViewById(R.id.activity_logo_logo);
      AuthHandler.performStartUpCheck(new AuthHandler.StartupAuthStatus()
      @Override
      public void noUser()
      Toast.makeText(LogoActivity.this, "No User", Toast.LENGTH_SHORT).show();
      performSharedElementTransactionToAuthOption();


      @Override
      public void onError(String e)
      Toast.makeText(LogoActivity.this, e, Toast.LENGTH_SHORT).show();
      performSharedElementTransactionToAuthOption();


      @Override
      public void onPhone()
      Toast.makeText(LogoActivity.this, "Phone", Toast.LENGTH_SHORT).show();
      //direct to loadingActivity


      @Override
      public void onEmail(boolean isVerified)
      Toast.makeText(LogoActivity.this, "Email" + String.valueOf(isVerified), Toast.LENGTH_SHORT).show();
      if(isVerified)
      //direct to LoadingActivity
      else
      performSharedElementTransactionToAuthOption();


      );
      //this.performSharedElementTransaction();


      private void performSharedElementTransactionToAuthOption()
      //check for auth and proceed to Loading
      Intent pIntent = new Intent(LogoActivity.this, AuthOptionActivity.class);
      ActivityOptions mOptions = ActivityOptions.makeSceneTransitionAnimation(LogoActivity.this, mLogo, mLogo.getTransitionName());
      startActivity(pIntent, mOptions.toBundle());



      private void performTransactionToLoadingScreen()
      /**dummy**/


      @Override
      protected void onStop()
      //Call finish here to avoid flickering
      this.finish();
      super.onStop();




      Nothing so special here, I am quite happy with that class. Disregard some comments, they are just for me as a reminder.



      AuthHandler



      public class AuthHandler 

      public interface StartupAuthStatus
      void noUser();
      void onError(String e);
      void onPhone();
      void onEmail(boolean isVerified);


      public interface SignInStatus
      void onEmail(boolean isVerified);


      private FirebaseAuth mAuth;
      private FirebaseFirestore mFirestore;

      /**STARTUP PROCEDURE**/

      public static void performStartUpCheck(final StartupAuthStatus mCallback)
      final FirebaseAuth mAuth = FirebaseAuth.getInstance();
      checkStartupAuthStatus(mAuth, mCallback);



      private static void checkStartupAuthStatus(FirebaseAuth mAuth, StartupAuthStatus mCallback)
      mAuth = FirebaseAuth.getInstance();
      checkForCurrentUser(mAuth,mCallback);


      private static void checkForCurrentUser(FirebaseAuth mAuth, StartupAuthStatus mCallback)
      if(mAuth.getCurrentUser()!=null)
      checkRegistrationMethod(mAuth, mCallback);
      else
      mCallback.noUser();



      private static void checkRegistrationMethod(final FirebaseAuth mAuth, final StartupAuthStatus mCallback)
      if(mAuth.getUid() == null)
      mCallback.onError("NullPointerInUID");
      return;

      FirebaseFirestore.getInstance().collection("Registration").document(mAuth.getUid()).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>()
      @Override
      public void onComplete(@NonNull Task<DocumentSnapshot> task)
      if(task.getResult() != null && task.getResult().exists())
      Map<String, Object> mData = task.getResult().getData();
      String mRegistrationForm = (String) mData.get("reg");
      if(mRegistrationForm.equals("mail"))
      checkMailVerificationStatus(mAuth, mCallback);
      else if(mRegistrationForm.equals("phone"))
      mCallback.onPhone();



      ).addOnFailureListener(new OnFailureListener()
      @Override
      public void onFailure(@NonNull Exception e)
      mCallback.onError(e.getMessage());
      mAuth.signOut();

      );


      private static void checkMailVerificationStatus(FirebaseAuth mAuth, StartupAuthStatus mCallback)
      if(mAuth.getCurrentUser().isEmailVerified())
      mCallback.onEmail(true);
      else
      mCallback.onEmail(false);



      /**LOGIN PROCEDURE**/

      public static void enterUserWithEmailAndPassword(String mEmail, String mPassword)
      FirebaseAuth mAuth = FirebaseAuth.getInstance();
      createUserWithEmailAndPassword(mAuth, mEmail, mPassword);


      private static void createUserWithEmailAndPassword(FirebaseAuth mAuth, String mEmail, String mPassword)



      private static void signUserWithEmailAndPassword(FirebaseAuth mAuth, String mEmail, String mPassword)



      private static void sendVerificationEmail(FirebaseAuth mAuth)



      private static void setupRegistrationModel(String mModelType)



      /**DELETE PROCEDURE**/



      This class is made to "outsource" the code mess. Here I am not sure if it's a common or even usefull way to handle this. The Database contains Users (with a lot of Data later) and a Pool of Registrations, here I only store the choosen registration form (field reg(String): "phone" or "mail").



      I need to seperate it somehow as the email-registrated-user needs to verify the email.



      AuthOptionActivity



      public class AuthOptionActivity extends AppCompatActivity 

      @Override
      protected void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_authoption);
      if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
      getWindow().setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(android.R.transition.move));

      this.checkAuthStatus();


      @Override
      public void onBackPressed()
      findViewById(R.id.activity_authoption_logo).setTransitionName(null);
      super.onBackPressed();
      /** Problem occured: SharedViewElement will be visible after App was closed.
      * Reason: The View will try to perform the ExitTransition
      * Solution 1: Delete super.onBackPressed(); and override with finish();
      * Solution 2: Set Transitionname to Null**/


      /**The SlideEnter Transition is variable, on First Startup we want a smooth slide in,
      * for phoneauth we want a Left-Side Slide and for Email a Right-Side Slide.
      * The Exit Animation is always slide-out-bottom-smooth.
      * The Reenter Animation is always slide-in-bottom-smooth and due to overlapping
      * the ExitTransition of the View before BackPress will be hidden and is always 0**/

      private void performFragmentTransaction(Fragment mFragment, String mTag, Boolean mAddToBackStack, int mEnterTransition)
      FragmentTransaction mFragmentTransaction = getSupportFragmentManager().beginTransaction();
      mFragmentTransaction.setCustomAnimations(mEnterTransition, 0, R.anim.slide_in_bottom_smooth, 0);
      if(mAddToBackStack)
      mFragmentTransaction.addToBackStack(mTag);

      mFragmentTransaction.replace(R.id.activity_authoption_container, mFragment, mTag);
      mFragmentTransaction.commit();



      /**Check Auth Status: if CurrentUser != null but not Email verified -> Show MailAuth**/
      private void checkAuthStatus()
      if(FirebaseAuth.getInstance().getCurrentUser()!=null && !FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
      //very bad way to force a backstack, still looking for a solution
      this.showAuthOptionFragment();
      this.showMailAuth();
      else
      this.showAuthOptionFragment();



      /**Handle Fragment Transaction including Listener**/
      private void showAuthOptionFragment()
      this.performFragmentTransaction(AuthOptionFragment.newInstance(new AuthOptionFragment.ClickListener()
      @Override
      public void onMail()
      showMailAuth();


      @Override
      public void onPhone()
      showPhoneAuth();

      ), "AuthOption", false, R.anim.slide_in_bottom);


      private void showPhoneAuth()
      this.performFragmentTransaction(_PhoneAuthFragment.newInstance(new _PhoneAuthFragment.AuthStatusListener()
      @Override
      public void onCancel()
      //PhoneAuthFragment contains a "back" Button it will fire "onCancel()"
      onBackPressed();


      @Override
      public void onSuccess()
      //show LoadingScreen

      ), "PhoneAuth", true, R.anim.slide_in_left_smooth);


      private void showMailAuth()
      this.performFragmentTransaction(_MailAuthFragment.newInstance(new _MailAuthFragment.AuthStatusListener()
      @Override
      public void onCancel()
      //MailAuthFragment contains a "back" Button it will fire "onCancel()"
      onBackPressed();


      @Override
      public void onSuccess()
      //show LoadingScreen

      ), "MailAuth", true, R.anim.slide_in_right_smooth);





      For this activity I have some questions:



      1. I am checking the Auth Status & email again to decide which fragment to show. It's easy and simple, but repetitive (it will occur again in MailAuthFragment). Is it a common way to repetitive use FirebaseAuth instances?

      2. I have seen a couple of fragment -> activity communication solutions using onAttach etc. Is my solution to pass a CustomListener(interface) in the newInstance method okay? Is there any bug that could occur using it that way?

        I pretty much like it as it makes the handling easier.

      MailAuthOptionFragment



      public class _MailAuthFragment extends Fragment 

      public interface AuthStatusListener
      void onCancel();
      void onSuccess();


      private AuthStatusListener mCallback;
      private String mActiveWindow;
      private CheckCancelButton mCheckCancelButton;

      private String mEmail;
      private String mPassword;

      @Override
      public void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);


      @Nullable
      @Override
      public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
      View mView = inflater.inflate(R.layout.fragment_mailauth, container, false);
      this.checkAuthStatus();
      this.initButton(mView);
      return mView;


      /**PUBLIC METHODS**/

      /**Set the Fragment Listener for AuthOptionActivity**/
      public void setListener(AuthStatusListener mCallback)
      this.mCallback = mCallback;


      /**Replaces hard coded Instances as Listener will be passed directly**/
      public static _MailAuthFragment newInstance(AuthStatusListener mCallback)
      _MailAuthFragment mFragment = new _MailAuthFragment();
      mFragment.setListener(mCallback);
      return mFragment;


      /**PRIVATE METHODS**/

      /**Check AuthStatus, if CurrentUser!=null but not verified -> Show VerificationScreen**/
      private void checkAuthStatus()
      if(FirebaseAuth.getInstance().getCurrentUser() != null && !FirebaseAuth.getInstance().getCurrentUser().isEmailVerified())
      this.showConfirmEmailSubFragment(R.anim.slide_in_right_smooth);
      else
      this.showEnterEmailSubFragment(R.anim.slide_in_right_smooth);



      /**Handle Registration Process Fragments**/
      private void performFragmentTransaction(Fragment mFragment, String mTag, int mEnterAnim)
      mActiveWindow = mTag;
      FragmentTransaction mFragmentTransaction = getChildFragmentManager().beginTransaction();
      mFragmentTransaction.setCustomAnimations(mEnterAnim, 0);
      mFragmentTransaction.replace(R.id.fragment_mailauth_container, mFragment, mTag);
      mFragmentTransaction.commit();


      /**MailAuth receives any valid TextChange from SubFragment**/
      private void showEnterEmailSubFragment(int mEnterAnim)

      this.performFragmentTransaction(EnterMailSubFragment.newInstance(new EnterMailSubFragment.EnterMailListener()
      @Override
      public void onEmailChanged(String mEmail)
      _MailAuthFragment.this.mEmail = mEmail;


      @Override
      public void onPasswordChanged(String mPassword)
      _MailAuthFragment.this.mPassword = mPassword;

      ), "EnterMail", mEnterAnim);



      /**MailAuth receives resend VerificationEmailRequest from SubFragment**/
      private void showConfirmEmailSubFragment(int mEnterAnim)
      this.performFragmentTransaction(new ConfirmMailSubFragment(), "ConfirmMail", R.anim.slide_in_right_smooth);


      private void initButton(final View mView)
      /**Custom Button using AfterEffects, Bodymovin and LottieView, contains some commands like "transform to tick"**/
      mCheckCancelButton = new CheckCancelButton((LottieAnimationView)mView.findViewById(R.id.fragment_mailauth_nextBtn));
      mCheckCancelButton.setCustomClickListener(new CheckCancelButton.CheckCancelButtonClickListener()
      @Override
      public void onClick()
      switch(mActiveWindow)
      case "EnterMail":
      // the received Email and Password will be passed to AuthHandlerClass - not implemented yet
      break;
      case "ConfirmMail":
      // the AuthHandler will reloard the currentUser and check for email verification Status - not implemented yet
      break;


      );





      Checking AuthStatus again and choosing whether to show the EnterEmailSubFragment or the ConfirmEmailSubFragment. This class contains a button handling both SubFragment pages. This leads to that switch-case method. Not sure if that is a proper way.



      EnterMailSubFragment



      public class EnterMailSubFragment extends Fragment 

      public interface EnterMailListener
      void onEmailChanged(String mEmail);
      void onPasswordChanged(String mPassword);


      private EnterMailListener mCallback;
      private EditText mEmail, mPassword;
      private ImageView mEmailWarning, mPasswordWarning;

      @Override
      public void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);

      @Nullable
      @Override
      public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
      View mView = inflater.inflate(R.layout.subfragment_mailauth, container, false);
      this.initUiWidgets(mView);
      this.initEditText(mView);
      return mView;


      public void setEnterMailListener(EnterMailListener mMailListener)
      this.mCallback = mMailListener;


      public static EnterMailSubFragment newInstance(EnterMailListener mMailListener)
      EnterMailSubFragment mFragment = new EnterMailSubFragment();
      mFragment.setEnterMailListener(mMailListener);
      return mFragment;


      private void initUiWidgets(View mView)
      mEmail = mView.findViewById(R.id.subfragment_mailauth_email_ET);
      mPassword = mView.findViewById(R.id.subfragment_mailauth_password_et);
      mEmailWarning = mView.findViewById(R.id.subfragment_mailauth_email_warning);
      mPasswordWarning = mView.findViewById(R.id.subfragment_mailauth_password_warning);


      /**Any Valid Entry will be passed to MailFragment**/

      private void initEditText(final View mView)
      mEmail.addTextChangedListener(new TextWatcher()
      @Override
      public void beforeTextChanged(CharSequence s, int start, int count, int after)



      @Override
      public void onTextChanged(CharSequence s, int start, int before, int count)



      @Override
      public void afterTextChanged(Editable s)
      if(mEmail.getText() != null && Patterns.EMAIL_ADDRESS.matcher(mEmail.getText().toString()).matches())
      mEmailWarning.setVisibility(View.GONE);
      mCallback.onEmailChanged(mEmail.getText().toString());
      else
      mEmailWarning.setVisibility(View.VISIBLE);


      );

      mPassword.addTextChangedListener(new TextWatcher()
      @Override
      public void beforeTextChanged(CharSequence s, int start, int count, int after)



      @Override
      public void onTextChanged(CharSequence s, int start, int before, int count)


      @Override
      public void afterTextChanged(Editable s)
      if(mPassword.getText() != null && mPassword.getText().length() >= 6)
      mPasswordWarning.setVisibility(View.GONE);
      mCallback.onPasswordChanged(mPassword.getText().toString());
      else
      mPasswordWarning.setVisibility(View.VISIBLE);


      );




      The Textwatcher checks every entry and transfers it to the MailAuthFragment as MailAuthFragment handels the button event (this is for design puposes, I want the content to move and the button is meant to stay in its position).



      ConfirmMailAuthSubFragment



      public class ConfirmMailSubFragment extends Fragment 

      public interface ConfirmMailListener
      void onResendEmail();


      private ConfirmMailListener mCallback;

      @Override
      public void onCreate(@Nullable Bundle savedInstanceState)
      super.onCreate(savedInstanceState);


      @Nullable
      @Override
      public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
      View mView = inflater.inflate(R.layout.subfragment_confirmmail, container, false);

      return mView;


      public void setConfirmMailListener(ConfirmMailListener mCallback)
      this.mCallback = mCallback;


      public static ConfirmMailSubFragment newInstance(ConfirmMailListener mCallback)
      ConfirmMailSubFragment mFragment = new ConfirmMailSubFragment();
      mFragment.setConfirmMailListener(mCallback);
      return mFragment;




      Nothing special here yet. It will handle the Button Event "Resend Verification Mail" and transfer it to MailAuthFragment.



      I know it's a very early stage of my code but as beautiful as it looks with that slide in animations I am not sure if I am running in the wrong direction or making stuff unnecessary complex.







      java android authentication firebase






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 7 mins ago









      200_success

      130k17153419




      130k17153419










      asked 1 hour ago









      J. LoJ. Lo

      62




      62




















          0






          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f215717%2ffirebase-login-registration-process-for-a-dating-app%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f215717%2ffirebase-login-registration-process-for-a-dating-app%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          名間水力發電廠 目录 沿革 設施 鄰近設施 註釋 外部連結 导航菜单23°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.7113923°50′10″N 120°42′41″E / 23.83611°N 120.71139°E / 23.83611; 120.71139計畫概要原始内容臺灣第一座BOT 模式開發的水力發電廠-名間水力電廠名間水力發電廠 水利署首件BOT案原始内容《小檔案》名間電廠 首座BOT水力發電廠原始内容名間電廠BOT - 經濟部水利署中區水資源局

          Prove that NP is closed under karp reduction?Space(n) not closed under Karp reductions - what about NTime(n)?Class P is closed under rotation?Prove or disprove that $NL$ is closed under polynomial many-one reductions$mathbfNC_2$ is closed under log-space reductionOn Karp reductionwhen can I know if a class (complexity) is closed under reduction (cook/karp)Check if class $PSPACE$ is closed under polyonomially space reductionIs NPSPACE also closed under polynomial-time reduction and under log-space reduction?Prove PSPACE is closed under complement?Prove PSPACE is closed under union?

          Is my guitar’s action too high? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)Strings too stiff on a recently purchased acoustic guitar | Cort AD880CEIs the action of my guitar really high?Μy little finger is too weak to play guitarWith guitar, how long should I give my fingers to strengthen / callous?When playing a fret the guitar sounds mutedPlaying (Barre) chords up the guitar neckI think my guitar strings are wound too tight and I can't play barre chordsF barre chord on an SG guitarHow to find to the right strings of a barre chord by feel?High action on higher fret on my steel acoustic guitar