rkuenzi-epfl/Wnder

View on GitHub
app/src/main/java/com/github/wnder/ProfileFragment.java

Summary

Maintainability
A
0 mins
Test Coverage
B
81%
package com.github.wnder;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;

import com.github.wnder.networkService.NetworkService;
import com.github.wnder.user.GlobalUser;
import com.github.wnder.user.SignedInUser;
import com.github.wnder.user.User;
import com.github.wnder.user.UserDatabase;
import com.github.wnder.user.UserDatabaseUtils;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.Task;
import com.google.android.material.card.MaterialCardView;
import com.squareup.picasso.Picasso;

import java.util.Locale;

import javax.inject.Inject;

import dagger.hilt.android.AndroidEntryPoint;

/**
 * This class is the fragment for the profile page of the app
 */
@AndroidEntryPoint
public class ProfileFragment extends Fragment {

    //Setup buttons and google signin and texts
    private View signInButton;
    private View logoutButton;
    private TextView noConnection;

    //setup stat cards
    private MaterialCardView nbrOfGuessesCard;
    private MaterialCardView averageScoreCard;
    private MaterialCardView totalScoreCard;

    //setup stat cards texts
    private TextView nbrOfGuessesText;
    private TextView averageScoreText;
    private TextView totalScoreText;

    //setup username and profile pic
    private TextView username;
    private ImageView profilePic;

    //setup sign in client and userdb
    private GoogleSignInClient client;
    private final int RC_SIGN_IN = 10; // Arbitrary number
    @Inject
    public UserDatabase userDb;

    private UserDatabaseUtils userDbUtils;

    @Inject
    public NetworkService networkInfo;

    /**
     * Constructor for the profile fragment
     */
    public ProfileFragment(){
        super(R.layout.fragment_profile);
    }

    /**
     * Executes on view created
     * @param view current view
     * @param savedInstanceState saved instance state
     */
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState){

        //ALL VIEWS ARE INVISIBLE WHEN CREATED

        //setup username and profile pic
        username = view.findViewById(R.id.username);
        profilePic = view.findViewById(R.id.profile_picture);

        //setup text for when no connection or when logged out
        noConnection = view.findViewById(R.id.no_connection_text);
        noConnection.setVisibility(View.INVISIBLE);

        //Setup the stat cards
        nbrOfGuessesCard = view.findViewById(R.id.nbrOfGuessesCard);
        nbrOfGuessesCard.setVisibility(View.INVISIBLE);

        averageScoreCard = view.findViewById(R.id.averageScoreCard);
        averageScoreCard.setVisibility(View.INVISIBLE);

        totalScoreCard = view.findViewById(R.id.totalScoreCard);
        totalScoreCard.setVisibility(View.INVISIBLE);

        //Setup the stat cards texts
        nbrOfGuessesText = view.findViewById(R.id.nbrOfGuesses);
        averageScoreText = view.findViewById(R.id.averageScore);
        totalScoreText = view.findViewById(R.id.totalScore);

        //Sign in and logout buttons
        signInButton = view.findViewById(R.id.signInButton);
        signInButton.setVisibility(View.INVISIBLE);  // Hide the button
        signInButton.setOnClickListener(id -> signIn());

        logoutButton = view.findViewById(R.id.logoutButton);
        logoutButton.setVisibility(View.INVISIBLE);
        logoutButton.setOnClickListener(id -> logout());

        //Setup google sign in
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestEmail()
                .build();

        client = GoogleSignIn.getClient(this.getActivity(), gso);
    }

    /**
     * Executes on fragment start
     */
    @Override
    public void onStart(){
        super.onStart();

        //Checks if user has already signed in
        GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this.getContext());

        //If yes, retrieve this account and set the user
        if(account != null && account.getDisplayName() != null && account.getPhotoUrl() != null) {
            GlobalUser.setUser(new SignedInUser(account.getDisplayName(), account.getPhotoUrl()));
        }

        //update page status
        updateLoginStatus();
    }

    /**
     * Logs out the user
     */
    private void logout(){
        //log out
        client.signOut();
        //global user becomes guest again
        GlobalUser.resetUser();
        //update page status
        updateLoginStatus();
    }

    /**
     * Helps a user sign in
     */
    private void signIn() {
        Intent signInIntent = client.getSignInIntent();
        startActivityForResult(signInIntent, RC_SIGN_IN);
    }

    /**
     * To execute when a user just signed in
     * @param requestCode request code
     * @param resultCode result code
     * @param data intent
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
        if (requestCode == RC_SIGN_IN) {
            // The Task returned from this call is always completed, no need to attach
            // a listener.
            Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
            handleSignInResult(task);
        }
    }

    /**
     * Tool method for onActivityResult: handles sign in result
     * @param completedTask completed task
     */
    private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
        try {
            GoogleSignInAccount account = completedTask.getResult(ApiException.class);

            // Signed in successfully, show authenticated UI.
            GlobalUser.setUser(new SignedInUser(account.getDisplayName(), account.getPhotoUrl()));

            updateLoginStatus();
        } catch (ApiException e) {
            // The ApiException status code indicates the detailed failure reason.
            // Please refer to the GoogleSignInStatusCodes class reference for more information.
            //Log.w("LoginTag", "signInResult:failed code=" + e.getStatusCode());
        }
    }

    /**
     * To call when the logged in/logged out or connection/no connection states change
     */
    private void updateLoginStatus(){
        //Choose right button (sign in or logout)
        if(areWeLoggedIn()){
            logoutButton.setVisibility(View.VISIBLE);
            signInButton.setVisibility(View.INVISIBLE);
        }
        else{
            logoutButton.setVisibility(View.INVISIBLE);
            signInButton.setVisibility(View.VISIBLE);
        }

        //setup right profile picture
        User user = GlobalUser.getUser();
        Picasso.get().load(user.getProfilePicture()).into(profilePic);

        //setup right username
        username.setText(user.getName());
        username.setVisibility(View.VISIBLE);

        userDbUtils = new UserDatabaseUtils(userDb.getPictureList(GlobalUser.getUser(), "guessedPics"), userDb.getAllScores(GlobalUser.getUser()));

        //update network status
        updateNetworkStatus();
    }

    /**
     * ONLY TO BE CALLED AT THE END OF UPDATELOGINSTATUS()
     * update ui depending on logged in/out and connection/no connection state
     */
    private void updateNetworkStatus(){
        //if connection and logged in
        if(networkInfo.isNetworkAvailable() && areWeLoggedIn()){

            //fill in cards with user info
            userDbUtils.getNbrOfGuessedPictures().thenAccept(nbr -> nbrOfGuessesText.setText(String.format(Locale.getDefault(), "%d", nbr)));
            userDbUtils.getAverageScore().thenAccept(average -> averageScoreText.setText(String.format(Locale.getDefault(), "%,.2f", average)));
            userDbUtils.getTotalScore().thenAccept(total -> totalScoreText.setText(String.format(Locale.getDefault(), "%,.2f", total)));

            //display cards
            nbrOfGuessesCard.setVisibility(View.VISIBLE);
            totalScoreCard.setVisibility(View.VISIBLE);
            averageScoreCard.setVisibility(View.VISIBLE);
            noConnection.setVisibility(View.INVISIBLE);
        }
        else{
            //make cards invisible
            nbrOfGuessesCard.setVisibility(View.INVISIBLE);
            totalScoreCard.setVisibility(View.INVISIBLE);
            averageScoreCard.setVisibility(View.INVISIBLE);
            noConnection.setVisibility(View.VISIBLE);

            //empty cards
            nbrOfGuessesText.setText("");
            averageScoreText.setText("");
            totalScoreText.setText("");
        }
    }

    /**
     * Tells us if we are logged in or not
     * @return true if logged in, false otherwise
     */
    private boolean areWeLoggedIn() {
        // just check that the global user is a signed in one
        return (GlobalUser.getUser() instanceof SignedInUser);
    }
}