DishDelish/dishdelish-app

View on GitHub
app/src/main/java/com/github/siela1915/bootcamp/RecipeActivity.java

Summary

Maintainability
C
7 hrs
Test Coverage
A
92%
package com.github.siela1915.bootcamp;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.constraintlayout.widget.Group;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.transition.AutoTransition;
import androidx.transition.TransitionManager;

import com.github.siela1915.bootcamp.Recipes.Comment;
import com.github.siela1915.bootcamp.Recipes.Ingredient;
import com.github.siela1915.bootcamp.Recipes.Recipe;
import com.github.siela1915.bootcamp.Recipes.Unit;
import com.github.siela1915.bootcamp.Tools.LanguageFilter;
import com.github.siela1915.bootcamp.firebase.Database;
import com.github.siela1915.bootcamp.firebase.FirebaseInstanceManager;
import com.github.siela1915.bootcamp.firebase.UserDatabase;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.FirebaseDatabase;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class RecipeActivity extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener {

    private Recipe recipe;
    private ShoppingListManager shoppingListManager;

    private Database database;

    private FirebaseAuth firebaseAuth;
    private static final DecimalFormat nutritionalValueFormat = new DecimalFormat("0.00");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recipe);

        firebaseAuth = FirebaseInstanceManager.getAuth();
        FirebaseDatabase firebaseDatabase = FirebaseInstanceManager.getDatabase(getApplicationContext());
        database = new Database(firebaseDatabase);

        shoppingListManager = new ShoppingListManager(this);


        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        recipe = getIntent().getParcelableExtra("Recipe");

        setPageContents();

        Button rateButton = (Button) findViewById(R.id.rateButton);
        rateButton.setOnClickListener(v -> {

            if (firebaseAuth.getCurrentUser() == null) {
                Toast.makeText(this, "Sign in to rate this recipe", Toast.LENGTH_SHORT).show();
            } else {
                Intent ratingIntent = new Intent(v.getContext(), RatingActivity.class);
                ratingIntent.putExtra("Recipe", recipe);

                v.getContext().startActivity(ratingIntent);
            }
        });

        Button cookNow = findViewById(R.id.cookNowButton);
        cookNow.setOnClickListener(v -> {
             Intent cookNowIntent = new Intent(v.getContext(), CookNowActivity.class);
             cookNowIntent.putExtra("Recipe", recipe);

             v.getContext().startActivity(cookNowIntent);
        });


        setNutritionalValueOnClickListener();
    }

    private void setNutritionalValueOnClickListener() {
        // collapsible card for nutritional values
        CardView nutritionalValuesCard = findViewById(R.id.nutritionalValueCard);
        ImageView expandNutritionalValues = findViewById(R.id.nutritionalCollapseToggle);
        Group nutritionalValuesContent = findViewById(R.id.card_group);

        expandNutritionalValues.setOnClickListener(view -> {
            TransitionManager.beginDelayedTransition(nutritionalValuesCard, new AutoTransition());

            if (nutritionalValuesContent.getVisibility() == View.VISIBLE) {
                nutritionalValuesContent.setVisibility(View.GONE);
                expandNutritionalValues.setImageResource(android.R.drawable.arrow_down_float);
            } else {
                nutritionalValuesContent.setVisibility(View.VISIBLE);
                expandNutritionalValues.setImageResource(android.R.drawable.arrow_up_float);
            }
        });

    }

    @Override
    public boolean onSupportNavigateUp() {
        finish();
        return true;
    }

    private void setPageContents() {

        ImageView recipePicture = (ImageView) findViewById(R.id.recipePicture);
        TextView recipeNameText = (TextView) findViewById(R.id.recipeNameText);
        ImageView userAvatar = (ImageView) findViewById(R.id.userAvatar);
        TextView userNameText = (TextView) findViewById(R.id.userNameText);
        TextView prepTime = (TextView) findViewById(R.id.prepTimeNbMins);
        TextView kcalCount = (TextView) findViewById(R.id.kcalCount);
        TextView cookTime = (TextView) findViewById(R.id.cookTimeNbMins);
        TextView nbServings = (TextView) findViewById(R.id.nbServings);
        RecyclerView ingredientsList = (RecyclerView) findViewById(R.id.ingredientsList);
        TextView utensilsList = (TextView) findViewById(R.id.utensilsList);
        TextView stepsText = (TextView) findViewById(R.id.stepsText);
        RecyclerView commentsList = (RecyclerView) findViewById(R.id.commentsList);
        RatingBar ratingBar = (RatingBar) findViewById(R.id.ratingBar);
        TextView servings = (TextView) findViewById(R.id.servings);
        TextView calories = (TextView) findViewById(R.id.nutritionalValuesCaloriesValue);
        TextView fat = (TextView) findViewById(R.id.nutritionalValuesFatValue);
        TextView carbohydrates = (TextView) findViewById(R.id.nutritionalValuesCarbohydratesValue);
        TextView sugar = (TextView) findViewById(R.id.nutritionalValuesSugarValue);
        TextView protein = (TextView) findViewById(R.id.nutritionalValuesProteinValue);

        ToggleButton heart = (ToggleButton) findViewById(R.id.favoriteButton);
        heart.setTag("empty");

        if (firebaseAuth.getCurrentUser() != null) {
            database.getFavorites().addOnSuccessListener(favs -> {
                if (favs.contains(recipe.uniqueKey)) {
                    heart.setBackground(getDrawable(R.drawable.heart_full));

                    heart.setOnCheckedChangeListener(null);
                    heart.setChecked(true);
                    heart.setOnCheckedChangeListener(this);

                    heart.setTag("full");
                }
            });
        }

        heart.setOnCheckedChangeListener(this);

        new DownloadImageTask(recipePicture).execute(recipe.image);

        UserDatabase userDb = new UserDatabase(FirebaseInstanceManager.getDatabase(getApplicationContext()));

        userDb.getUser(recipe.getUserId()).addOnSuccessListener(user -> {
            userNameText.setText(user.getDisplayName());
            new DownloadImageTask(userAvatar).execute(user.getPhotoUrl());
        });

        recipeNameText.setText(recipe.recipeName);

        ratingBar.setRating((float) recipe.rating);
        prepTime.setText(String.valueOf(recipe.prepTime));

        cookTime.setText(String.valueOf(recipe.cookTime));
        utensilsList.setText(String.join(", ", recipe.utensils.getUtensils()));

        stepsText.setText(String.join("\n\n", recipe.steps));


        // Set Ingredient List content
        setIngredientListContents(ingredientsList);

        // Set Nutritional Values
        calories.setText(nutritionalValueFormat.format(recipe.calories));
        fat.setText(nutritionalValueFormat.format(recipe.fat));
        carbohydrates.setText(nutritionalValueFormat.format(recipe.carbohydrates));
        sugar.setText(nutritionalValueFormat.format(recipe.sugar));
        protein.setText(nutritionalValueFormat.format(recipe.protein));

        // Set servings info
        setServingInfo(nbServings, servings, ingredientsList);

        // Set Comment fields
        setCommentContents(commentsList);

    }

    private void modifyIngredientAmounts(int n, int previous, RecyclerView ingredientsList) {
        IngredientAdapter adapter = (IngredientAdapter) ingredientsList.getAdapter();
        List<Ingredient> data = adapter.getData();

        for (int i = 0; i < data.size(); i++) {
            Ingredient original = recipe.getIngredientList().get(i);
            String ingredient = original.getIngredient();
            String info = original.getUnit().getInfo();
            int oldValue = original.getUnit().getValue();
            double temp = ((double) n / recipe.servings);
            int newValue = (int) (Math.ceil(temp * oldValue));

            data.set(i, new Ingredient(ingredient, new Unit(newValue, info)));
            adapter.notifyItemChanged(i);
        }
    }

    private void setIngredientListContents(RecyclerView ingredientsList) {

        ingredientsList.setLayoutManager(new LinearLayoutManager(this));
        IngredientAdapter ingredientAdapter = new IngredientAdapter(getApplicationContext(), new ArrayList<>(recipe.getIngredientList()), shoppingListManager);
        ingredientsList.setAdapter(ingredientAdapter);

    }

    private void setCommentContents(RecyclerView commentsList) {

        commentsList.setLayoutManager(new LinearLayoutManager(this));
        for(Comment c : recipe.comments){
            c.setContent(LanguageFilter.filterLanguage(c.getContent()));
        }
        CommentAdapter commentAdapter = new CommentAdapter(getApplicationContext(),
                recipe.comments, recipe);
        commentsList.setAdapter(commentAdapter);

        EditText commentBox = (EditText) findViewById(R.id.enterComment);
        Button sendComment = (Button) findViewById(R.id.sendCommentButton);

        sendComment.setOnClickListener(view -> {
            String input = commentBox.getText().toString();
            if (!input.isEmpty()) {
                commentBox.setText("");

                if (firebaseAuth.getCurrentUser() == null) {
                    Toast.makeText(this, "Sign in to add a comment", Toast.LENGTH_SHORT).show();
                } else {
                    recipe.comments.add(new Comment(LanguageFilter.filterLanguage(input), firebaseAuth.getCurrentUser().getUid()));
                    // Update the database with the new comment
                    database.updateAsync(recipe).addOnCompleteListener(task -> {
                        if (task.isSuccessful()) {
                            commentAdapter.notifyItemInserted(recipe.comments.size() - 1);
                        } else {
                            Toast.makeText(this, "Error adding new comment", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        });


    }

    private void setServingInfo(TextView nbServings, TextView servings, RecyclerView ingredientsList) {

        nbServings.setText(String.valueOf(recipe.servings));
        servings.setText(String.valueOf(recipe.servings));

        Button plusButton = (Button) findViewById(R.id.plusButton);
        Button minusButton = (Button) findViewById(R.id.minusButton);

        plusButton.setOnClickListener(v -> {

            int old = Integer.valueOf(nbServings.getText().toString());
            int newVal = old + 1;

            nbServings.setText(String.valueOf(newVal));
            servings.setText(String.valueOf(newVal));

            modifyIngredientAmounts(newVal, old, ingredientsList);

        });

        minusButton.setOnClickListener(v -> {
            int old = Integer.valueOf(nbServings.getText().toString());
            if (old > 1) {
                int newVal = old - 1;
                nbServings.setText(String.valueOf(newVal));
                servings.setText(String.valueOf(newVal));

                modifyIngredientAmounts(newVal, old, ingredientsList);
            }
        });

    }

    /**
     * @param buttonView The compound button view whose state has changed.
     * @param isChecked  The new checked state of buttonView.
     */
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {

            // Add the recipe to favorites
            database.addFavorite(recipe.uniqueKey).addOnSuccessListener(arg -> {
                // Show a success message to the user
                Toast.makeText(this, "Recipe added to favorites", Toast.LENGTH_SHORT).show();

                //change background
                buttonView.setBackground(getDrawable(R.drawable.heart_full));
                recipe.setLikes(recipe.likes + 1);

                // for testing
                buttonView.setTag("full");

            }).addOnFailureListener(e -> {
                // Show an error message to the user
                Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();

                // remove onCheckedChangeListener before changing the state manually so that it is not triggered
                buttonView.setOnCheckedChangeListener(null);
                buttonView.setChecked(false);
                buttonView.setOnCheckedChangeListener(this);
                buttonView.setTag("add fail");

            });

        } else {

            // remove this recipe from favorites
            database.removeFavorite(recipe.uniqueKey).addOnSuccessListener(s -> {

                // display success message
                Toast.makeText(this, "Recipe removed from favorites", Toast.LENGTH_SHORT).show();

                // change background
                buttonView.setBackground(getDrawable(R.drawable.heart_empty));

                recipe.setLikes(recipe.likes - 1);

                // for testing
                buttonView.setTag("removed");

            }).addOnFailureListener(e -> {

                // display error message
                Toast.makeText(this, "Error removing recipe from favorites: " + e.getMessage(), Toast.LENGTH_SHORT).show();

                buttonView.setOnCheckedChangeListener(null);
                buttonView.setChecked(true);
                buttonView.setOnCheckedChangeListener(this);
                buttonView.setTag("remove fail");

            });
        }
    }
}