com.project.salminnella.prescoop.activity.SchoolDetailsActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.project.salminnella.prescoop.activity.SchoolDetailsActivity.java

Source

package com.project.salminnella.prescoop.activity;

import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.gson.Gson;
import com.project.salminnella.prescoop.BuildConfig;
import com.project.salminnella.prescoop.R;
import com.project.salminnella.prescoop.adapter.TabLayoutAdapter;
import com.project.salminnella.prescoop.adapter.YelpAdapter;
import com.project.salminnella.prescoop.dbHelper.DatabaseHelper;
import com.project.salminnella.prescoop.fragment.SchoolsMapFragment;
import com.project.salminnella.prescoop.fragment.TabLayoutFragment;
import com.project.salminnella.prescoop.model.PreSchool;
import com.project.salminnella.prescoop.model.Reports;
import com.project.salminnella.prescoop.utility.Constants;
import com.project.salminnella.prescoop.utility.Utilities;
import com.squareup.picasso.Picasso;
import com.yelp.clientlib.connection.YelpAPI;
import com.yelp.clientlib.connection.YelpAPIFactory;
import com.yelp.clientlib.entities.Business;
import com.yelp.clientlib.entities.SearchResponse;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

/**
 * This activity displays all the details about the school the user has selected.  Contains
 * a tab layout with pageviewer holding all licensing, citation, and inspection report information.
 * Calls yelps API, and filters the list for a match to the school name.
 *
 * An interface for a clickable textview in the Reports tab allows fragment to activity communication.
 * This allows the user to see the web page of the selected report on the school inspection.
 */
public class SchoolDetailsActivity extends AppCompatActivity implements TabLayoutFragment.ListItemClickable {

    // region Member Variables
    private TextView mPhoneNumber;
    private TextView mFacilityNumber;
    private TextView mFacilityCapacity;
    private TextView mFacilityType;
    private TextView mLicenseStatus;
    private TextView mLicenseDate;
    private TextView mSchoolPrice;
    private TextView mSchoolNeighborhood;
    private TextView mSchoolWebLink;
    private TextView mSchoolName;
    private TextView mSchoolAddress;
    private TextView mYelpTitleText;
    private TextView mYelpNumReviews;
    private TextView mYelpSnippet;
    private ImageView mSchoolRating;
    private ImageView mYelpRating;
    private ListView mYelpListView;
    private YelpAdapter mYelpAdapter;
    private Business mYelpSchoolMatch;
    private PreSchool mPreschool;
    private ViewPager mViewPager;
    private DatabaseHelper databaseHelper;
    private FloatingActionButton mFab;
    private boolean saveSchool;
    // endregion Member Variables

    /**
     * Activity is created
     * @param savedInstanceState Bundle
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_school_details);
        databaseHelper = DatabaseHelper.getInstance(SchoolDetailsActivity.this);
        receiveIntent();
        setupToolbar();
        initViews();
        adjustFabIcon();
        populateSchoolDetails();
        callYelpProvider();
        initTabLayout();
        setClickListeners();
    }

    /**
     * Receives Intent data from MainActivity or the Map Fragment.  The Preschool object is used
     * to populate the rest of the school details.
     */
    private void receiveIntent() {
        Intent receiveIntent = getIntent();
        mPreschool = (PreSchool) receiveIntent.getSerializableExtra(Constants.SCHOOL_OBJECT_KEY);
    }

    /**
     * Initializes, and sets up the collapsing toolbar, then loads the backdrop image.
     */
    private void setupToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(
                R.id.collapsing_toolbar);
        if (collapsingToolbarLayout != null) {
            collapsingToolbarLayout.setTitle(mPreschool.getName());
            collapsingToolbarLayout.setExpandedTitleColor(Color.TRANSPARENT);
        }

        loadBackdrop();
    }

    /**
     * Loads the bacdrop image using Picasso, but not all schools have images.
     * When there isn't an image available, the backdrop loads
     * a default 'no image' available instead.
     */
    private void loadBackdrop() {
        final ImageView imageView = (ImageView) findViewById(R.id.backdrop);
        if (mPreschool.getImageUrl().matches("")) {
            Picasso.with(SchoolDetailsActivity.this).load(R.drawable.no_image).into(imageView);
        } else {
            Picasso.with(SchoolDetailsActivity.this).load(mPreschool.getImageUrl()).into(imageView);
        }
    }

    /**
     * Initialize all views in the activity.
     */
    private void initViews() {
        mFab = (FloatingActionButton) findViewById(R.id.fab);
        mSchoolName = (TextView) findViewById(R.id.school_name_text_details);
        mSchoolAddress = (TextView) findViewById(R.id.school_address_text_details);
        mYelpTitleText = (TextView) findViewById(R.id.yelp_title_text_details);
        mYelpRating = (ImageView) findViewById(R.id.yelp_rating);
        mYelpListView = (ListView) findViewById(R.id.yelp_response_list);
        mYelpNumReviews = (TextView) findViewById(R.id.yelp_num_reviews);
        mYelpSnippet = (TextView) findViewById(R.id.yelp_review_snippet_details);
        mViewPager = (ViewPager) findViewById(R.id.viewpager);
        mPhoneNumber = (TextView) findViewById(R.id.school_phone_text_details);
        mFacilityNumber = (TextView) findViewById(R.id.facility_num_text_details);
        mFacilityCapacity = (TextView) findViewById(R.id.facility_capacity_text_details);
        mFacilityType = (TextView) findViewById(R.id.facility_type_text_details);
        mLicenseStatus = (TextView) findViewById(R.id.license_status_text_details);
        mLicenseDate = (TextView) findViewById(R.id.license_date_text_details);
        mSchoolPrice = (TextView) findViewById(R.id.school_price_text_details);
        mSchoolNeighborhood = (TextView) findViewById(R.id.school_neighborhood_text_details);
        mSchoolWebLink = (TextView) findViewById(R.id.school_weblink_text_details);
        mSchoolRating = (ImageView) findViewById(R.id.school_rating_image_details);
    }

    /**
     * When loading the activity, this checks if the school is currently saved as a favorite, and sets
     * it icon on the fab button to match. Full heart if it is a favorite, just an outline if it isn't.
     */
    private void adjustFabIcon() {
        if (isSchoolAlreadySaved()) {
            mFab.setImageDrawable(getResources().getDrawable(R.drawable.ic_favorite_white_24dp));
            saveSchool = true;
        }
    }

    /**
     * Sets the click listeners.  There is a web url link, a list of Yelp reviews, and the fab icon
     */
    private void setClickListeners() {
        mSchoolWebLink.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startIntentToWebView(mPreschool.getWebsiteUrl(), mPreschool.getName(), mPreschool);
            }
        });

        mYelpListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Business clickedYelpBusiness = (Business) mYelpListView.getItemAtPosition(position);
                startIntentToWebView(clickedYelpBusiness.mobileUrl(), Constants.YELP_WEBVIEW_TITLE, mPreschool);
            }
        });

        if (mFab != null) {
            mFab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (saveSchool) {
                        mFab.setImageDrawable(getResources().getDrawable(R.drawable.ic_favorite_border_white_24dp));
                        removeFavoriteSchool();
                        saveSchool = false;
                        Toast.makeText(SchoolDetailsActivity.this, R.string.remove_favorites, Toast.LENGTH_SHORT)
                                .show();
                    } else {
                        mFab.setImageDrawable(getResources().getDrawable(R.drawable.ic_favorite_white_24dp));
                        addFavoriteSchool();
                        saveSchool = true;
                        Toast.makeText(SchoolDetailsActivity.this, R.string.add_favorites, Toast.LENGTH_SHORT)
                                .show();
                    }
                }
            });
        }
    }

    /**
     * This is called from within the API call to yelp. Is not included in above set click listeners
     * because there isn't always results to set the listener on.  Only needed when a resulting list from
     * yelp is created.
     */
    private void setYelpClickListener() {
        mYelpTitleText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startIntentToWebView(mYelpSchoolMatch.mobileUrl(), Constants.YELP_WEBVIEW_TITLE, mPreschool);
            }
        });
    }

    /**
     * Interface method from TabLayoutFragment.ListItemClickable. The reports available to view for
     * each school are shown through a list in the Reports tablayout. This allows the fragment
     * to activity communication.
     * @param view View
     * @param url String
     */
    @Override
    public void listItemClicked(View view, String url) {
        startIntentToWebView(url, Constants.SCHOOL_REPORT_TITLE, mPreschool);
    }

    /**
     * Called from the Fab button click. If user wants to remove the school from their favorites
     */
    private void removeFavoriteSchool() {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                if (isSchoolAlreadySaved()) {
                    databaseHelper.deleteSavedSchool(mPreschool.getName());
                }
                return null;
            }
        }.execute();
    }

    /**
     * Called from the Fab button click. If user wants to add the school to their favorites.
     * Also stores the array list of reports in one column as a GSON string
     */
    private void addFavoriteSchool() {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                if (!isSchoolAlreadySaved()) {
                    String reportsList = arrayListAsString(mPreschool);
                    databaseHelper.insertSavedSchool(mPreschool, reportsList);
                }
                return null;
            }
        }.execute();
    }

    /**
     * Uses the reports list from the Preschool object, and converts it to a string to be easily
     * stored in the SQLite database on the device.
     * @param preschool Preschool
     * @return String
     */
    private String arrayListAsString(PreSchool preschool) {
        if (preschool.getReports() != null) {
            Reports[] reportsArray = preschool.getReports();
            Gson gson = new Gson();

            return gson.toJson(reportsArray);
        } else {
            return null;
        }
    }

    /**
     * This intent takes the url to load into the webview in the WebViewActivity.  The title is
     * for the toolbar, and the preschool object is used to reload the school details when the user
     * comes back.
     * @param url String
     * @param title String
     * @param preschool PreSchool
     */
    private void startIntentToWebView(String url, String title, PreSchool preschool) {
        Intent intentToWebView = new Intent(SchoolDetailsActivity.this, WebViewActivity.class);
        intentToWebView.putExtra(Constants.WEB_URL_KEY, url); // weburl
        intentToWebView.putExtra(Constants.YELP_WEBVIEW_TITLE_KEY, title); // review title
        intentToWebView.putExtra(Constants.SCHOOL_OBJECT_KEY, preschool); // preschool object
        startActivityForResult(intentToWebView, Constants.WEB_REQUEST_CODE);

    }

    /**
     * Populates all school details that are not in the TabLayout
     */
    private void populateSchoolDetails() {
        mSchoolName.setText(mPreschool.getName());
        setSchoolAddressTextView();
        mPhoneNumber.setText(mPreschool.getPhoneNumber());
        mFacilityNumber.setText(String.valueOf(mPreschool.getFacilityNumber()));
        mFacilityCapacity.setText(String.valueOf(mPreschool.getCapacity()));
        mFacilityType.setText(mPreschool.getType());
        mLicenseStatus.setText(mPreschool.getLicenseStatus());
        mLicenseDate.setText(mPreschool.getLicenseDate());
        if (mPreschool.getPrice() == 999) {
            mSchoolPrice.setText(R.string.contact_school_label_details);
        } else {
            String price = "$" + mPreschool.getPrice();
            mSchoolPrice.setText(price);
        }
        mSchoolNeighborhood.setText(mPreschool.getRegion());
        mSchoolWebLink.setText(mPreschool.getWebsiteUrl());
        mSchoolWebLink.setPaintFlags(mSchoolWebLink.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
        mSchoolRating.setImageResource(Utilities.getRatingImage(mPreschool.getRating()));
    }

    /**
     * The street address, city etc, are in separate fields. This puts them into one string
     */
    private void setSchoolAddressTextView() {
        mSchoolAddress.setText(Utilities.buildAddressString(mPreschool.getStreetAddress(), mPreschool.getCity(),
                mPreschool.getState(), mPreschool.getZipCode()));
    }

    /**
     * Calls Yelp API
     */
    private void callYelpProvider() {
        YelpAPIFactory apiFactory = new YelpAPIFactory(BuildConfig.YELP_CONSUMER_KEY,
                BuildConfig.YELP_CONSUMER_SECRET, BuildConfig.YELP_TOKEN, BuildConfig.YELP_TOKEN_SECRET);

        YelpAPI yelpAPI = apiFactory.createAPI();
        Map<String, String> params = new HashMap<>();

        // general params
        params.put(Constants.YELP_SEARCH_PARAM_TERMS, mPreschool.getName());
        params.put(Constants.YELP_SEARCH_PARAM_LIMIT, Constants.YELP_RESPONSE_LIMIT_STRING);
        params.put(Constants.YELP_SEARCH_PARAM_CATEGORY, Constants.YELP_CATEGORY);
        params.put(Constants.YELP_SEARCH_PARAM_SORT, Constants.YELP_SORT);

        Call<SearchResponse> call = yelpAPI.search(Constants.YELP_SEARCH_PARAM_LOCATION, params);
        Callback<SearchResponse> callback = new Callback<SearchResponse>() {
            @Override
            public void onResponse(Call<SearchResponse> call, Response<SearchResponse> response) {
                SearchResponse searchResponse = response.body();
                if (searchResponse.total() == 0) {
                    mYelpTitleText.setText(R.string.empty_yelp_response);
                } else {
                    // Update UI text with the searchResponse.
                    mYelpSchoolMatch = filterYelpResponse(searchResponse);
                    if (mYelpSchoolMatch != null) {
                        mYelpTitleText.setText(mYelpSchoolMatch.name());
                        Picasso.with(SchoolDetailsActivity.this).load(mYelpSchoolMatch.ratingImgUrlLarge())
                                .into(mYelpRating);
                        String reviewText = String.valueOf(mYelpSchoolMatch.reviewCount())
                                + getString(R.string.yelp_reviews_text);
                        mYelpNumReviews.setText(reviewText);
                        mYelpSnippet.setText(mYelpSchoolMatch.snippetText());
                        mYelpTitleText.setPaintFlags(mYelpTitleText.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
                        mYelpTitleText.setTextColor(Color.parseColor(getString(R.string.html_color_num_blue)));
                        setYelpClickListener();
                    } else {
                        mYelpTitleText.setText(R.string.empty_yelp_response_title);
                        ArrayList<Business> businesses = searchResponse.businesses();
                        mYelpAdapter = new YelpAdapter(SchoolDetailsActivity.this, businesses);
                        mYelpListView.setAdapter(mYelpAdapter);
                    }
                }
            }

            @Override
            public void onFailure(Call<SearchResponse> call, Throwable t) {
                // Handle HTTP error
            }
        };

        call.enqueue(callback);
    }

    /**
     * There is always a list of businesses in respose to calling Yelps API.  This one finds the best
     * match and uses it to populate the reviews.
     * Loops through the response to see if the name of the preschool is in there.
     * @param response SearchResponse
     * @return Business - model provided by yelp.
     */
    private Business filterYelpResponse(SearchResponse response) {
        int limit = response.total();
        if (Constants.YELP_RESPONSE_LIMIT_INT < response.total()) {
            limit = Constants.YELP_RESPONSE_LIMIT_INT;
        }
        for (int i = 0; i < limit; i++) {
            int strContains = response.businesses().get(i).name().indexOf(mPreschool.getName());
            if (strContains != -1) {
                return response.businesses().get(i);
            }
        }

        return null;
    }

    /**
     * Initializes and sets up the TabLayout. The Preschool object is passed into the constructor of
     * the adapter to fill in all necessary licensing and reports information.
     */
    private void initTabLayout() {
        // Set PagerAdapter so that it can display items
        mViewPager.setAdapter(new TabLayoutAdapter(getSupportFragmentManager(), mPreschool));

        // Give the TabLayout the ViewPager
        TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
        if (tabLayout != null) {
            tabLayout.setupWithViewPager(mViewPager);
        }
    }

    /**
     * Inflate options menu for the Toolbar
     * @param menu Menu
     * @return Boolean
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_school_details_activity, menu);

        return true;
    }

    /**
     * Handle menu item selections
     * @param item MenuItem
     * @return Boolean
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.maps_menu_item_details) {
            Intent intentToMaps = new Intent(SchoolDetailsActivity.this, SchoolsMapFragment.class);
            intentToMaps.putExtra(Constants.SCHOOL_MARKER_KEY, mPreschool);
            startActivity(intentToMaps);
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * Used to confirm if the school has already been saved to the database.
     * @return Boolean
     */
    private boolean isSchoolAlreadySaved() {
        Cursor bookmarkCursor = databaseHelper.findSavedSchool(mPreschool.getName());
        return bookmarkCursor.getCount() != 0;
    }

    /** When returning from the web activity, the preschool objects needs to sent and returned in order
     * to populate the school details again.
     *
     * @param requestCode int
     * @param resultCode int
     * @param data Intent
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
            if (resultCode == RESULT_OK) {
                mPreschool = (PreSchool) data.getSerializableExtra(Constants.SCHOOL_OBJECT_KEY);
            }
        }
    }
}