CultureQuestORG/SDP2023

View on GitHub
app/src/main/java/ch/epfl/culturequest/ArtDescriptionDisplayActivity.java

Summary

Maintainability
A
3 hrs
Test Coverage
A
93%
package ch.epfl.culturequest;

import static ch.epfl.culturequest.social.RarityLevel.getRarityLevel;
import static ch.epfl.culturequest.utils.ProfileUtils.POSTS_ADDED;

import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import com.squareup.picasso.Picasso;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import ch.epfl.culturequest.backend.artprocessing.processingobjects.BasicArtDescription;
import ch.epfl.culturequest.backend.artprocessing.utils.DescriptionSerializer;
import ch.epfl.culturequest.database.Database;
import ch.epfl.culturequest.social.Post;
import ch.epfl.culturequest.social.Profile;
import ch.epfl.culturequest.social.ScanBadge;
import ch.epfl.culturequest.storage.FireStorage;

public class ArtDescriptionDisplayActivity extends AppCompatActivity {

    private Bitmap scannedImage;

    private static final int POPUP_DELAY = 5000;

    private Button postButton;
    private Button shareButton;

    private String imageDownloadUrl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_art_description_display);
        findViewById(R.id.back_button).setOnClickListener(view -> onBackPressed());
        postButton = findViewById(R.id.post_button);
        shareButton = findViewById(R.id.share_button);

        // Get serialized artDescription and images from intent
        String serializedArtDescription = getIntent().getStringExtra("artDescription");
        String imageUriExtra = getIntent().getStringExtra("imageUri");
        imageDownloadUrl = getIntent().getStringExtra("downloadUrl");

        // Check if the activity was started from the scanning activity
        boolean scan = getIntent().getBooleanExtra("scanning", true);

        if(scan) {
            Uri imageUri = Uri.parse(imageUriExtra);
            BasicArtDescription artDescription = DescriptionSerializer.deserialize(serializedArtDescription);
            // Get SharedPreferences
            SharedPreferences sharedPreferences = getSharedPreferences("openAI_popup_pref", MODE_PRIVATE);
            boolean doNotShowAgain = sharedPreferences.getBoolean("do_not_show_again", false);
            // Check if artDescription.openAIRequired is true and doNotShowAgain is false
            if (artDescription.isOpenAiRequired() && !doNotShowAgain) {
                showOpenAIPopup();
            }
            // get bitmap from imageUri with the ContentResolver
            try {
                // get bitmap from imageUri with the ContentResolver
                Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                scannedImage = bitmap;
                ((ImageView) findViewById(R.id.artImage)).setImageBitmap(bitmap);
                displayArtInformation(artDescription);
                postButton.setOnClickListener(v -> postImage(imageDownloadUrl, artDescription, List.of(artDescription.getCountry(), artDescription.getCity(), artDescription.getMuseum())));
                shareButton.setOnClickListener(v -> shareImage(imageUri, artDescription));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                finish();
            }
        } else {
            // Deserialize artDescription
            BasicArtDescription artDescription = DescriptionSerializer.deserialize(serializedArtDescription);

            // Get SharedPreferences
            SharedPreferences sharedPreferences = getSharedPreferences("openAI_popup_pref", MODE_PRIVATE);
            boolean doNotShowAgain = sharedPreferences.getBoolean("do_not_show_again", false);

            // Check if artDescription.openAIRequired is true and doNotShowAgain is false
            if (artDescription.isOpenAiRequired() && !doNotShowAgain) {
                showOpenAIPopup();
            }

            // Display art information on the page
            displayArtInformation(artDescription);

            // Display image on the page from the server
            Picasso.get()
                    .load(imageDownloadUrl)
                    .placeholder(android.R.drawable.progress_horizontal)
                    .into((ImageView) findViewById(R.id.artImage));

            // Remove post button as the image was not scanned
            postButton.setVisibility(View.GONE);
            shareButton.setVisibility(View.GONE);
        }
    }

    /**
     * If the user decides not to post the picture
     * we delete the pic from firebase storage.
     */
    @Override
    public void onBackPressed(){
        super.onBackPressed();
        FireStorage.deleteImage(imageDownloadUrl);
    }

    private void displayArtInformation(BasicArtDescription artDescription) {

        // Set Art Name
        TextView artNameView = findViewById(R.id.artName);
        setTextOrFallback(artNameView, artDescription.getName(), "No name found");

        // Set Artist
        TextView artistNameView = findViewById(R.id.artistName);
        setTextOrFallback(artistNameView, artDescription.getArtist(), "No artist found");

        // Set Year
        TextView artYearView = findViewById(R.id.artYear);
        setTextOrFallback(artYearView, artDescription.getYear(), "No year found");

        // Set Summary
        TextView artSummaryView = findViewById(R.id.artSummary);
        setTextOrFallback(artSummaryView, artDescription.getSummary(), "No description found");

        // Set Score
        TextView artScoreView = findViewById(R.id.artScore);
        artScoreView.setText(artDescription.getScore() != null ? "+" + artDescription.getScore().toString() + " pts" : "+30 pts");

        // Set Rarity Badge
        ImageView rarityBadge = findViewById(R.id.rarity);
        setRarityBadge(rarityBadge, artDescription.getScore());

        // Set Country Badge
        ImageView countryBadge = findViewById(R.id.countryBadge);
        TextView countryName = findViewById(R.id.countryName);

        setCountryBadge(countryBadge, countryName, artDescription.getCountry());

        // Set City Badge
        ImageView cityBadge = findViewById(R.id.cityBadge);
        TextView cityName = findViewById(R.id.cityName);

        setCityBadge(cityBadge, cityName, artDescription.getCity());

        // Set Museum Badge
        ImageView museumBadge = findViewById(R.id.museumBadge);
        TextView museumName = findViewById(R.id.museumName);

        setMuseumBadge(museumBadge, museumName, artDescription.getMuseum());
    }

    private void setTextOrFallback(TextView textView, String text, String fallbackText) {
        textView.setText(text != null ? text : fallbackText);
    }

    private void showOpenAIPopup() {
        View popupView = LayoutInflater.from(this).inflate(R.layout.popup_openai_message, null);
        final PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);

        // Show the popup in the center of the screen after the activity has been fully initialized
        findViewById(android.R.id.content).post(() -> {
            if (!isFinishing()) {
                popupWindow.showAtLocation(findViewById(android.R.id.content), Gravity.CENTER, 0, 0);
            }
        });

        // Set the "Do not show it again" button click listener
        Button btnDoNotShowAgain = popupView.findViewById(R.id.btn_do_not_show_again);
        btnDoNotShowAgain.setOnClickListener(view -> {

            SharedPreferences sharedPreferences = getSharedPreferences("openAI_popup_pref", MODE_PRIVATE);
            SharedPreferences.Editor editor = sharedPreferences.edit();
            editor.putBoolean("do_not_show_again", true);
            editor.apply();

            popupWindow.dismiss();
        });

        // Set a delay of 3 seconds before making the popup invisible
        new Handler().postDelayed(() -> {
            if (popupWindow.isShowing()) {
                popupWindow.dismiss();
            }
        }, POPUP_DELAY);
    }

    private void setRarityBadge(ImageView rarityBadge, Integer score) {
        if (score != null) {
            rarityBadge.setImageResource(getRarityLevel(score).getRarenessIcon());
            rarityBadge.setTag(getRarityLevel(score).name());
        } else {
            rarityBadge.setImageResource(getRarityLevel(30).getRarenessIcon());
            rarityBadge.setTag(getRarityLevel(30).name());
        }
    }

    private void setCountryBadge(ImageView countryBadge, TextView countryText, String country) {
        if (country != null) {
            countryBadge.setImageResource(ScanBadge.Country.fromString(country).getBadge());
            countryText.setText(country);
            countryBadge.setTag(ScanBadge.Country.fromString(country).name());
        } else {
            countryBadge.setVisibility(ImageView.GONE);
            countryText.setVisibility(TextView.GONE);
        }
    }

    private void setCityBadge(ImageView cityBadge, TextView cityText, String city) {
        if (city != null) {
            cityBadge.setImageResource(ScanBadge.City.fromString(city).getBadge());
            cityText.setText(city);
            cityBadge.setTag(ScanBadge.City.fromString(city).name());
        } else {
            cityBadge.setVisibility(ImageView.GONE);
            cityText.setVisibility(TextView.GONE);
        }
    }

    private void setMuseumBadge(ImageView museumBadge, TextView museumText, String museum) {
        if (museum != null) {
            museumBadge.setImageResource(ScanBadge.Museum.fromString(museum).getBadge());
            museumText.setText(museum);
            museumBadge.setTag(ScanBadge.Museum.fromString(museum).name());
        } else {
            museumBadge.setVisibility(ImageView.GONE);
            museumText.setVisibility(TextView.GONE);
        }
    }

    /**
     * Uploads an image to the database when the user presses on the post button. it will post
     * the image in the storage at the address: images/uid/postId
     *
     * @param url     the image url to upload
     * @param artwork the artwork to add to the database
     */
    private void postImage(String url, BasicArtDescription artwork, List<String> badges) {
        String postId = UUID.randomUUID().toString();
        Profile activeProfile = Profile.getActiveProfile();
        String uid = activeProfile.getUid();
        Post newPost = new Post(postId, uid, url, artwork.getName(), new Date().getTime(), 0, new ArrayList<>());
        Profile.getActiveProfile().retrievePosts().thenCompose(posts -> {
            boolean alreadyPosted = posts.stream().anyMatch(post -> post.getArtworkName().equals(newPost.getArtworkName()));
            if (alreadyPosted) {
                showAlreadyPostedDialog(newPost);
            } else {
                Database.uploadPost(newPost).whenComplete((lambda, e) -> {
                    if (e == null) {
                        POSTS_ADDED++;
                        activeProfile.incrementScore(artwork.getScore());
                        activeProfile.addBadges(badges);
                        finish();
                    } else {
                        e.printStackTrace();
                    }
                }).exceptionally(l -> {
                    showErrorDialog("Couldn't post picture");
                    return null;
                });
            }
            return null;
        });
    }

    private void showAlreadyPostedDialog(Post post) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(post.getArtworkName() + " is already in your collection!");
        builder.setIcon(R.drawable.image_recognition_error);
        builder.setMessage("This post is already in your collection. You can still post it, but you will not get more points or badges!");
        builder.setCancelable(true);
        builder.setPositiveButton("Post", (dialog, which) -> {
            Database.uploadPost(post).handle((lambda, e) -> {
                if (e != null) {
                    e.printStackTrace();
                }
                POSTS_ADDED++;
                return null;
            });
            dialog.cancel();
            finish();
        });
        builder.setNegativeButton("Cancel", (dialog, id) -> {
            dialog.dismiss();
        });
        builder.create().show();
    }

    private void showErrorDialog(String message) {
        new AlertDialog.Builder(this).setTitle("Error").setMessage(message).setCancelable(false).setPositiveButton("Cancel", (dialog, which) -> dialog.dismiss()).create().show();
    }

    private void shareImage(Uri uri, BasicArtDescription description) {
        Intent shareIntent = new Intent(Intent.ACTION_SEND);
        shareIntent.setType("image/jpeg");
        shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
        shareIntent.putExtra(Intent.EXTRA_TEXT, "I just scanned " + description.getName() + " with \uD835\uDC02\uD835\uDC2E\uD835\uDC25\uD835\uDC2D\uD835\uDC2E\uD835\uDC2B\uD835\uDC1E\uD835\uDC10\uD835\uDC2E\uD835\uDC1E\uD835\uDC2C\uD835\uDC2D!\n\n" +
                "It's a " + getRarityLevel(description.getScore()).name().toLowerCase() + " artwork from " + description.getArtist() + ", displayed at "+ description.getMuseum() + ", " + description.getCity() + ".\n\n" +
                "Download the app here: https://play.google.com/store/apps/details?id=com.culturequest.culturequest");
        shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivity(Intent.createChooser(shareIntent, "Share your scan using"));
    }



}