Alvaro2112/Money_run

View on GitHub
app/src/main/java/sdp/moneyrun/ui/authentication/LoginActivity.java

Summary

Maintainability
A
0 mins
Test Coverage
A
96%
package sdp.moneyrun.ui.authentication;

import android.Manifest;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;

import java.util.Objects;

import sdp.moneyrun.R;
import sdp.moneyrun.database.DatabaseProxy;
import sdp.moneyrun.database.UserDatabaseProxy;
import sdp.moneyrun.permissions.PermissionsRequester;
import sdp.moneyrun.ui.menu.MenuActivity;
import sdp.moneyrun.user.User;

@SuppressWarnings("FieldCanBeLocal")
public class LoginActivity extends AppCompatActivity {

    private final String TAG = LoginActivity.class.getSimpleName();
    private final ActivityResultLauncher<String[]> requestPermissionsLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), map -> {
    });
    private final String coarseLocation = Manifest.permission.ACCESS_COARSE_LOCATION;
    private final String fineLocation = Manifest.permission.ACCESS_FINE_LOCATION;
    private final String ERROR_MISSING_EMAIL = "Email is required";
    private final String ERROR_MISSING_PASSWORD = "Password is required";
    private final String ERROR_INVALID_EMAIL_FORMAT = "Email format is invalid";
    private FirebaseAuth mAuth;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Objects.requireNonNull(getSupportActionBar()).hide();
        setContentView(R.layout.activity_login);

        PermissionsRequester locationPermissionsRequester = new PermissionsRequester(
                this,
                requestPermissionsLauncher,
                "In order to work properly, this app needs to use location services.",
                true,
                coarseLocation,
                fineLocation);
        locationPermissionsRequester.requestPermission();

        mAuth = FirebaseAuth.getInstance();

        final Button loginButton = findViewById(R.id.loginButton);
        setLogIn(loginButton);

        final Button guestButton = findViewById(R.id.guestButton);
        setGuestButton(guestButton);
        DatabaseProxy.addOfflineListener(this, TAG);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        DatabaseProxy.removeOfflineListener();
    }

    @Override
    public void onStart() {
        super.onStart();

        // Check if user is signed in (non-null) and update UI accordingly.
        FirebaseUser currentUser = mAuth.getCurrentUser();
        if (currentUser != null) {
            updateUI(currentUser);
        }
    }

    /**
     * link from signUp button to signUp page
     */
    public void signUp(View view) {
        MediaPlayer.create(this, R.raw.button_press).start();
        Intent intent = new Intent(this, SignUpActivity.class);
        startActivity(intent);
        finish();
    }

    /**
     * set the listener that defines the behaviour on button click
     *
     * @param loginButton
     */
    private void setLogIn(@NonNull Button loginButton) {
        loginButton.setOnClickListener(clicked -> {
            MediaPlayer.create(this, R.raw.button_press).start();
            EditText emailView = findViewById(R.id.loginEmailAddress);
            EditText passwordView = findViewById(R.id.loginPassword);
            String email = emailView.getText().toString().trim();
            String password = passwordView.getText().toString().trim();

            if (email.isEmpty()) {
                emailView.setError(ERROR_MISSING_EMAIL);
                emailView.requestFocus();

            } else if (password.isEmpty()) {
                passwordView.setError(ERROR_MISSING_PASSWORD);
                passwordView.requestFocus();
            } else if (!isEmailValid(email)) {
                emailView.setError(ERROR_INVALID_EMAIL_FORMAT);
                emailView.requestFocus();
            } else {
                submitLogin(email, password);
            }
        });

    }

    /**
     * Send authentication attempt to backend
     *
     * @param email
     * @param password
     */
    private void submitLogin(@NonNull String email, @NonNull String password) {
        mAuth.signInWithEmailAndPassword(email, password)
                .addOnCompleteListener(LoginActivity.this, task -> {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        Log.d(TAG, "signInWithEmail:success");
                        FirebaseUser user = mAuth.getCurrentUser();
                        updateUI(user);
                    } else {
                        // If sign in fails, display a message to the user.
                        Log.w(TAG, "signInWithEmail:failure", task.getException());
                        String errorMessage = task.getException().getMessage() == null
                                ? "Reason unknown"
                                : task.getException().getMessage();
                        Toast.makeText(
                                LoginActivity.this,
                                "Authentication failed: " + errorMessage,
                                Toast.LENGTH_SHORT).show();
                    }
                });
    }

    /**
     * On successful login goes to menu
     *
     * @param user
     */
    private void updateUI(@Nullable FirebaseUser user) {
        if (user != null) {
            Intent menuIntent = new Intent(LoginActivity.this, MenuActivity.class);
            getUserFromDB(user.getUid(), menuIntent);
        }
    }

    private void getUserFromDB(@NonNull String userId, @NonNull Intent menuIntent) {
        UserDatabaseProxy pdb = new UserDatabaseProxy();
        Task<DataSnapshot> t = pdb.getUserTask(userId);
        t.addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                User user = pdb.getUserFromTask(task);

                // If no user has been found, we need to create a new instance in the database
                if (user == null) {
                    Intent intent = new Intent(this, RegisterUserActivity.class);
                    intent.putExtra("userId", userId);
                    startActivity(intent);
                }

                // Otherwise, the user exists and we go to the menu
                else {
                    menuIntent.putExtra("user", user);
                    startActivity(menuIntent);
                }
                finish();
            }
        });
    }

    /**
     * Ensures that email has basic email format
     *
     * @param email
     * @return
     */
    private boolean isEmailValid(@NonNull CharSequence email) {
        return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
    }

    @NonNull
    public ActivityResultLauncher<String[]> getRequestPermissionsLauncher() {
        return requestPermissionsLauncher;
    }

    /**
     * Should transfer the user to register activity so it can create a temporary
     * profile used only in this session of login
     *
     * @param guestButton offline mode option
     */
    public void setGuestButton(@Nullable Button guestButton) {
        if (guestButton == null)
            throw new IllegalArgumentException("Guest button was clicked but was null");
        guestButton.setOnClickListener(v -> {
            MediaPlayer.create(this, R.raw.button_press).start();
            Intent guestMenuIntent = new Intent(LoginActivity.this, RegisterUserActivity.class);
            guestMenuIntent.putExtra("guestUser", true);
            startActivity(guestMenuIntent);
            finish();
        });
    }

    @Override
    public void onBackPressed() {
    }

}