gyrodraw/GyroDraw

View on GitHub
app/src/main/java/ch/epfl/sweng/GyroDraw/home/HomeActivity.java

Summary

Maintainability
B
5 hrs
Test Coverage
package ch.epfl.sweng.GyroDraw.home;

import static ch.epfl.sweng.GyroDraw.firebase.AccountAttributes.FRIENDS;
import static ch.epfl.sweng.GyroDraw.firebase.AccountAttributes.USERNAME;
import static ch.epfl.sweng.GyroDraw.firebase.FbDatabase.checkForDatabaseError;
import static ch.epfl.sweng.GyroDraw.firebase.FbDatabase.getAccountAttribute;
import static ch.epfl.sweng.GyroDraw.utils.LayoutUtils.bounceButton;
import static ch.epfl.sweng.GyroDraw.utils.LayoutUtils.getLeagueColorId;
import static ch.epfl.sweng.GyroDraw.utils.LayoutUtils.getLeagueImageId;
import static ch.epfl.sweng.GyroDraw.utils.LayoutUtils.getLeagueTextId;
import static ch.epfl.sweng.GyroDraw.utils.LayoutUtils.getMainAmplitude;
import static ch.epfl.sweng.GyroDraw.utils.LayoutUtils.getMainFrequency;
import static ch.epfl.sweng.GyroDraw.utils.LayoutUtils.isPointInsideView;
import static ch.epfl.sweng.GyroDraw.utils.LayoutUtils.pressButton;
import static ch.epfl.sweng.GyroDraw.utils.OnlineStatus.OFFLINE;
import static ch.epfl.sweng.GyroDraw.utils.OnlineStatus.ONLINE;
import static ch.epfl.sweng.GyroDraw.utils.OnlineStatus.changeOnlineStatus;
import static ch.epfl.sweng.GyroDraw.utils.OnlineStatus.changeToOfflineOnDisconnect;

import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import ch.epfl.sweng.GyroDraw.MainActivity;
import ch.epfl.sweng.GyroDraw.NoBackPressActivity;
import ch.epfl.sweng.GyroDraw.R;
import ch.epfl.sweng.GyroDraw.auth.Account;
import ch.epfl.sweng.GyroDraw.firebase.FbAuthentication;
import ch.epfl.sweng.GyroDraw.firebase.FbDatabase;
import ch.epfl.sweng.GyroDraw.firebase.OnSuccessValueEventListener;
import ch.epfl.sweng.GyroDraw.game.LoadingScreenActivity;
import ch.epfl.sweng.GyroDraw.game.drawing.DrawingOfflineActivity;
import ch.epfl.sweng.GyroDraw.home.battleLog.BattleLogActivity;
import ch.epfl.sweng.GyroDraw.home.gallery.GalleryActivity;
import ch.epfl.sweng.GyroDraw.home.leaderboard.LeaderboardActivity;
import ch.epfl.sweng.GyroDraw.home.leagues.LeaguesActivity;
import ch.epfl.sweng.GyroDraw.localDatabase.LocalDbForAccount;
import ch.epfl.sweng.GyroDraw.localDatabase.LocalDbHandlerForAccount;
import ch.epfl.sweng.GyroDraw.shop.ShopActivity;
import ch.epfl.sweng.GyroDraw.utils.GlideUtils;
import ch.epfl.sweng.GyroDraw.utils.LayoutUtils.AnimMode;
import ch.epfl.sweng.GyroDraw.utils.OnSwipeTouchListener;
import ch.epfl.sweng.GyroDraw.utils.network.ConnectivityWrapper;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.ValueEventListener;

/**
 * Class representing the homepage of the app.
 */
public class HomeActivity extends NoBackPressActivity {

    public static final String GAME_MODE = "mode";

    private static final String TAG = "HomeActivity";

    private static final int DRAW_BUTTON_FREQUENCY = 20;
    private static final int LEAGUE_IMAGE_FREQUENCY = 30;
    private static final double DRAW_BUTTON_AMPLITUDE = 0.2;
    
    private static final int NORMAL_MODE = 0;
    private static final int SPECIAL_MODE = 1;

    private static boolean enableBackgroundAnimation = true;

    private Dialog profileWindow;
    private Dialog friendRequestWindow;

    private ValueEventListener listenerFriendsRequest = new OnSuccessValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            for (DataSnapshot child : dataSnapshot.getChildren()) {
                Integer stateValue = child.getValue(Integer.class);
                if (stateValue != null) {
                    FriendsRequestState state = FriendsRequestState.fromInteger(stateValue);

                    if (state == FriendsRequestState.RECEIVED) {
                        getFriendsUsernameAndShowPopUp(child.getKey());
                    }
                }
            }
        }
    };

    /**
     * Disables the background animation. This method should be in every HomeActivity test.
     */
    @VisibleForTesting
    public static void disableBackgroundAnimation() {
        enableBackgroundAnimation = false;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        profileWindow = new Dialog(this);

        friendRequestWindow = new Dialog(this);
        friendRequestWindow.setCancelable(false);

        if (enableBackgroundAnimation) {
            GlideUtils.startBackgroundAnimation(this);
        }

        LocalDbForAccount localDb = new LocalDbHandlerForAccount(this, null, 1);
        localDb.retrieveAccount(Account.getInstance(this));

        // Update the user online status on Firebase and set the onDisconnect listener
        updateUserStatusOnFirebase();

        // Add listener to check for new friends requests
        addListenerForFriendsRequests();

        final ImageView drawButton = findViewById(R.id.drawButton);
        final ImageView practiceButton = findViewById(R.id.practiceButton);
        final ImageView mysteryButton = findViewById(R.id.mysteryButton);
        final Button usernameButton = findViewById(R.id.usernameButton);
        final ImageView leaderboardButton = findViewById(R.id.leaderboardButton);
        final ImageView shopButton = findViewById(R.id.shopButton);
        final ImageView galleryButton = findViewById(R.id.galleryButton);
        final ImageView battleLogButton = findViewById(R.id.battleLogButton);
        final TextView shopText = findViewById(R.id.shopText);
        final TextView galleryText = findViewById(R.id.galleryText);
        final TextView leaderboardText = findViewById(R.id.leaderboardText);
        final TextView battleLogText = findViewById(R.id.battleLogText);
        final ImageView trophiesButton = findViewById(R.id.trophiesButton);
        final TextView trophiesCount = findViewById(R.id.trophiesCount);
        final ImageView starsButton = findViewById(R.id.starsButton);
        final TextView starsCount = findViewById(R.id.starsCount);
        final ImageView leagueImage = findViewById(R.id.leagueImage);
        final TextView leagueText = findViewById(R.id.leagueText);

        usernameButton.setText(Account.getInstance(this).getUsername());
        trophiesCount.setText(String.valueOf(Account.getInstance(this).getTrophies()));
        starsCount.setText(String.valueOf(Account.getInstance(this).getStars()));

        leagueText.setTypeface(typeOptimus);
        usernameButton.setTypeface(typeMuro);
        trophiesCount.setTypeface(typeMuro);
        starsCount.setTypeface(typeMuro);
        shopText.setTypeface(typeMuro);
        galleryText.setTypeface(typeMuro);
        leaderboardText.setTypeface(typeMuro);
        battleLogText.setTypeface(typeMuro);

        setListener(drawButton, DRAW_BUTTON_AMPLITUDE, DRAW_BUTTON_FREQUENCY);
        setListener(leaderboardButton, getMainAmplitude(), getMainFrequency());
        setListener(shopButton, getMainAmplitude(), getMainFrequency());
        setListener(galleryButton, getMainAmplitude(), getMainFrequency());
        setListener(battleLogButton, getMainAmplitude(), getMainFrequency());
        setListener(trophiesButton, getMainAmplitude(), getMainFrequency());
        setListener(starsButton, getMainAmplitude(), getMainFrequency());
        setListener(leagueImage, getMainAmplitude(), LEAGUE_IMAGE_FREQUENCY);
        setListener(usernameButton, getMainAmplitude(), getMainFrequency());
        setListener(practiceButton, getMainAmplitude(), getMainFrequency());
        setListener(mysteryButton, getMainAmplitude(), getMainFrequency());

        findViewById(R.id.backgroundAnimation).setOnTouchListener(new OnSwipeTouchListener(this) {
            @Override
            public void onSwipeRight() {
                launchActivity(ShopActivity.class);
            }
        });

        setLeague();
    }

    /**
     * Changes the user's state on Firebase to online.
     */
    private void updateUserStatusOnFirebase() {
        String userId = Account.getInstance(getApplicationContext())
                .getUserId();

        changeOnlineStatus(userId, ONLINE, FbDatabase.createCompletionListener());

        // On user disconnection, update Firebase
        changeToOfflineOnDisconnect(userId);
    }

    private void addListenerForFriendsRequests() {
        FbDatabase.setListenerToAccountAttribute(Account.getInstance(this).getUserId(),
                FRIENDS, listenerFriendsRequest);
    }

    @VisibleForTesting
    public Dialog getFriendRequestWindow() {
        return friendRequestWindow;
    }

    /**
     * Signs the current user out and starts the {@link MainActivity}.
     */
    private void signOut() {
        FbAuthentication.signOut(this, new OnCompleteListener<Void>() {
            public void onComplete(@NonNull Task<Void> task) {
                if (task.isSuccessful()) {
                    final Toast toastSignOut = Toast.makeText(getApplicationContext(),
                            "Signing out...", Toast.LENGTH_SHORT);
                    toastSignOut.show();

                    // Update Firebase, delete the account instance and launch MainActivity
                    changeOnlineStatus(
                            Account.getInstance(getApplicationContext()).getUserId(),
                            OFFLINE, new DatabaseReference.CompletionListener() {
                                @Override
                                public void onComplete(
                                        @Nullable DatabaseError databaseError,
                                        @NonNull DatabaseReference databaseReference) {
                                    checkForDatabaseError(databaseError);
                                    successfulSignOut(toastSignOut);
                                }
                            });
                } else {
                    Log.e(TAG, "Sign out failed!");
                }
            }
        });
        profileWindow.dismiss();
    }

    private void successfulSignOut(Toast toast) {
        Account.deleteAccount();
        toast.cancel();
        launchActivity(MainActivity.class);
        overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
        finish();
    }

    private void setListener(final View view, final double amplitude, final int frequency) {
        final Context context = this;
        view.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View view, MotionEvent event) {
                int id = view.getId();
                AnimMode animMode;

                switch (id) {
                    case R.id.starsButton:
                        animMode = AnimMode.LEFT;
                        break;
                    case R.id.trophiesButton:
                        animMode = AnimMode.LEFT;
                        break;
                    case R.id.practiceButton:
                        animMode = AnimMode.LEFT;
                        break;
                    case R.id.mysteryButton:
                        animMode = AnimMode.RIGHT;
                        break;
                    default:
                        animMode = AnimMode.CENTER;
                }

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        if (id == R.id.drawButton) {
                            ((ImageView) view)
                                    .setImageResource(R.drawable.draw_button_pressed);
                        }
                        pressButton(view, animMode, context);
                        break;
                    case MotionEvent.ACTION_UP:
                        if (id == R.id.drawButton) {
                            ((ImageView) view)
                                    .setImageResource(R.drawable.draw_button);
                        }
                        bounceButton(view, amplitude, frequency, animMode, context);
                        if (isPointInsideView(event.getRawX(), event.getRawY(), view)) {
                            listenerEventSelector(view, id);
                        }
                        break;
                    default:
                }
                return true;
            }
        });
    }

    // Sets the listener for the friend request popup buttons using the given userId
    // as the id of the sender of the request
    private void setFriendsRequestListener(final View view, final String userId) {
        final Context context = this;
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                int id = view.getId();
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        pressButton(view, AnimMode.CENTER, context);
                        break;
                    case MotionEvent.ACTION_UP:
                        listenerFriendsRequestEventSelector(id, userId);
                        bounceButton(view, context);
                        break;
                    default:
                }
                return true;
            }
        });
    }

    private void listenerEventSelector(final View view, int resourceId) {
        switch (resourceId) {
            case R.id.drawButton:
                ((ImageView) view).setImageResource(R.drawable.draw_button);
                launchOnlineGame(NORMAL_MODE);
                break;
            case R.id.leaderboardButton:
                launchActivity(LeaderboardActivity.class);
                break;
            case R.id.shopButton:
                launchActivity(ShopActivity.class);
                break;
            case R.id.galleryButton:
                launchActivity(GalleryActivity.class);
                break;
            case R.id.battleLogButton:
                launchActivity(BattleLogActivity.class);
                break;
            case R.id.leagueImage:
                launchActivity(LeaguesActivity.class);
                break;
            case R.id.usernameButton:
                showProfilePopup();
                break;
            case R.id.signOutButton:
                signOut();
                break;
            case R.id.crossText:
                profileWindow.dismiss();
                break;
            case R.id.practiceButton:
                launchActivity(DrawingOfflineActivity.class);
                break;
            case R.id.mysteryButton:
                launchOnlineGame(SPECIAL_MODE);
                break;
            default:
        }
    }

    private void launchOnlineGame(int gameMode) {
        if (ConnectivityWrapper.isOnline(this)) {
            // Prevents that the user launches two online games at the same time.
            setGameButtons(false);
            Intent intent = new Intent(this, LoadingScreenActivity.class);
            intent.putExtra(GAME_MODE, gameMode);
            startActivity(intent);
        } else {
            Toast.makeText(this, R.string.no_internet, Toast.LENGTH_LONG).show();
        }
    }

    // Listener for the friends request popup buttons
    private void listenerFriendsRequestEventSelector(int resourceId, String userId) {
        switch (resourceId) {
            case R.id.acceptButton:
                Account.getInstance(this).addFriend(userId);
                friendRequestWindow.dismiss();
                break;
            case R.id.rejectButton:
                Account.getInstance(this).removeFriend(userId);
                friendRequestWindow.dismiss();
                break;
            default:
        }
    }

    private void setMuroFont() {
        TextView profileTextView = profileWindow.findViewById(R.id.profileText);
        profileTextView.setTypeface(typeMuro);
        TextView gamesWonText = profileWindow.findViewById(R.id.gamesWonText);
        gamesWonText.setTypeface(typeMuro);
        TextView gamesLostText = profileWindow.findViewById(R.id.gamesLostText);
        gamesLostText.setTypeface(typeMuro);
        TextView averageStarsText = profileWindow.findViewById(R.id.averageStarsText);
        averageStarsText.setTypeface(typeMuro);
        TextView maxTrophiesText = profileWindow.findViewById(R.id.maxTrophiesText);
        maxTrophiesText.setTypeface(typeMuro);
        TextView gamesWonNumber = profileWindow.findViewById(R.id.gamesWonNumber);
        gamesWonNumber.setTypeface(typeMuro);
        TextView gamesLostNumber = profileWindow.findViewById(R.id.gamesLostNumber);
        gamesLostNumber.setTypeface(typeMuro);
        TextView averageStarsNumber = profileWindow.findViewById(R.id.averageStarsNumber);
        averageStarsNumber.setTypeface(typeMuro);
        TextView maxTrophiesNumber = profileWindow.findViewById(R.id.maxTrophiesNumber);
        maxTrophiesNumber.setTypeface(typeMuro);
        TextView crossText = profileWindow.findViewById(R.id.crossText);
        crossText.setTypeface(typeMuro);
        Button signOutButton = profileWindow.findViewById(R.id.signOutButton);
        signOutButton.setTypeface(typeMuro);
    }

    private void showProfilePopup() {
        profileWindow.setContentView(R.layout.activity_profile_pop_up);
        Account userAccount = Account.getInstance(this);

        this.setMuroFont();

        TextView gamesWonNumber = profileWindow.findViewById(R.id.gamesWonNumber);
        gamesWonNumber.setText(String.valueOf(userAccount.getMatchesWon()));
        TextView gamesLostNumber = profileWindow.findViewById(R.id.gamesLostNumber);
        gamesLostNumber.setText(String.valueOf(userAccount.getTotalMatches()));

        double roundedAverage = Math.round(userAccount.getAverageRating() * 10) / 10.;
        TextView averageStarsNumber = profileWindow.findViewById(R.id.averageStarsNumber);
        averageStarsNumber.setText(String.valueOf(roundedAverage));

        TextView maxTrophiesNumber = profileWindow.findViewById(R.id.maxTrophiesNumber);
        maxTrophiesNumber.setText(String.valueOf(userAccount.getMaxTrophies()));
        TextView crossText = profileWindow.findViewById(R.id.crossText);
        setListener(crossText, getMainAmplitude(), getMainFrequency());
        Button signOutButton = profileWindow.findViewById(R.id.signOutButton);
        setListener(signOutButton, getMainAmplitude(), getMainFrequency());

        profileWindow.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        profileWindow.show();
    }

    /**
     * Gets the username corresponding to the given id and shows the friends request popup.
     *
     * @param id id from user that has sent a request
     */
    @VisibleForTesting
    public void getFriendsUsernameAndShowPopUp(final String id) {
        getAccountAttribute(id, USERNAME, new OnSuccessValueEventListener() {

            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                String name = dataSnapshot.getValue(String.class);
                showFriendRequestPopup(name, id);
            }
        });
    }

    /**
     * Displays the friends request popup.
     *
     * @param name name of the user that sent the request
     * @param id id of the user that sent the request
     */
    @VisibleForTesting
    public void showFriendRequestPopup(String name, String id) {
        assert name != null : "name is null";

        friendRequestWindow.setContentView(R.layout.activity_friend_request_pop_up);

        TextView requestSender = friendRequestWindow.findViewById(R.id.requestSender);
        requestSender.setTypeface(typeMuro);
        requestSender.setText(name);

        TextView requestMessage = friendRequestWindow.findViewById(R.id.requestMessage);
        requestMessage.setTypeface(typeMuro);

        Button acceptButton = friendRequestWindow.findViewById(R.id.acceptButton);
        acceptButton.setTypeface(typeMuro);
        setFriendsRequestListener(acceptButton, id);

        Button rejectButton = friendRequestWindow.findViewById(R.id.rejectButton);
        rejectButton.setTypeface(typeMuro);
        setFriendsRequestListener(rejectButton, id);

        friendRequestWindow.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        friendRequestWindow.show();
    }

    private void setLeague() {
        String league = Account.getInstance(this).getCurrentLeague();
        TextView leagueText = findViewById(R.id.leagueText);

        leagueText.setText(getLeagueTextId(league));
        leagueText.setTextColor(getResources().getColor(getLeagueColorId(league)));
        ((ImageView) findViewById(R.id.leagueImage)).setImageResource(getLeagueImageId(league));
    }

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

        Account account = Account.getInstance(this);

        // Update values of the text views
        ((TextView) findViewById(R.id.starsCount)).setText(String.valueOf(account.getStars()));
        ((TextView) findViewById(R.id.trophiesCount)).setText(String.valueOf(
                account.getTrophies()));
        setGameButtons(true);
    }

    /**
     * Sets the game buttons locked or unlocked.
     *
     * @param state the target state
     */
    private void setGameButtons(boolean state) {
        findViewById(R.id.practiceButton).setEnabled(state);
        findViewById(R.id.drawButton).setEnabled(state);
        findViewById(R.id.mysteryButton).setEnabled(state);
    }
}