package edu.alaska.gina.feeder.gina_puffinfeeder_android_viewer;
import android.app.Fragment;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.Toast;
import com.octo.android.robospice.SpiceManager;
import com.octo.android.robospice.persistence.DurationInMillis;
import com.octo.android.robospice.persistence.exception.SpiceException;
import com.octo.android.robospice.request.listener.RequestListener;
import edu.alaska.gina.feeder.gina_puffinfeeder_android_viewer.network.JsonSpiceService;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
/**
* Fragment used to display the list of feed images in a GridView.
* Created by bobby on 6/14/13.
*/
class ImageFeedFragment extends Fragment {
private static String JSON_CACHE_KEY;
private final SpiceManager mSpiceManager = new SpiceManager(JsonSpiceService.class);
private Menu aBarMenu;
private final Feed imageFeed = new Feed();
private final ArrayList<FeedImage> mList = new ArrayList<FeedImage>();
private final ArrayList<String> mTitles = new ArrayList<String>();
private final ArrayList<String[]> mUrls = new ArrayList<String[]>();
private final ArrayList<DateTime> mTimes = new ArrayList<DateTime>();
private PicassoImageAdapter mImageAdapter;
private int page = 1;
/** Overridden Methods. */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_image_feed, container, false);
setHasOptionsMenu(true);
Bundle extras = getArguments();
imageFeed.setStatusBoolean(extras.getBoolean("status"));
imageFeed.setEntries(extras.getString("entries"));
imageFeed.setSlug(extras.getString("slug"));
imageFeed.setDescription(extras.getString("description"));
imageFeed.setMoreinfo(extras.getString("info"));
JSON_CACHE_KEY = imageFeed.getSlug() + "_json";
getActivity().setProgressBarIndeterminateVisibility(true);
refreshThumbs(false, false);
mImageAdapter = new PicassoImageAdapter(this.getActivity(), mList);
if (getActivity().getActionBar() != null)
getActivity().getActionBar().setTitle(imageFeed.getTitle());
return v;
}
@Override
public void onStart() {
super.onStart();
GridView gridView = (GridView) getActivity().findViewById(R.id.image_grid);
gridView.setAdapter(mImageAdapter);
adaptGridViewSize(gridView);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent photoView = new Intent(getActivity(), FullscreenImageViewerActivity.class);
ArrayList<String> times = new ArrayList<String>();
for (DateTime d : mTimes)
times.add(d.toString());
Bundle args = new Bundle();
args.putAll(encodeBundle(mUrls, "url", 3));
args.putAll(encodeBundle(mTitles, "title"));
args.putAll(encodeBundle(times, "time"));
args.putString("description", imageFeed.getDescription());
args.putString("info", imageFeed.getMoreinfo());
args.putString("feed_name", imageFeed.getTitle());
args.putInt("position", position);
photoView.putExtras(args);
getActivity().startActivity(photoView);
}
});
mImageAdapter.notifyDataSetChanged();
}
@Override
public void onPause() {
if (mSpiceManager.isStarted())
mSpiceManager.shouldStop();
super.onPause();
}
@Override
public void onStop() {
if (mSpiceManager.isStarted())
mSpiceManager.shouldStop();
super.onStop();
}
@Override
public void onDetach() {
if (mSpiceManager.isStarted())
mSpiceManager.shouldStop();
super.onDetach();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
aBarMenu = menu;
if (page <= 1)
aBarMenu.findItem(R.id.action_load_prev).setIcon(R.drawable.ic_navigation_back_dud);
else
aBarMenu.findItem(R.id.action_load_prev).setIcon(R.drawable.ic_navigation_back);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_load_next:
refreshThumbs(true, true);
return true;
case R.id.action_load_prev:
if (page > 1)
refreshThumbs(true, false);
return true;
case R.id.action_refresh:
refreshThumbs(false, true);
return true;
case R.id.action_load_first:
if (page <= 1)
Toast.makeText(getActivity(), "Already on first page.", Toast.LENGTH_SHORT).show();
refreshThumbs(false, false);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
adaptGridViewSize((GridView) getActivity().findViewById(R.id.image_grid));
}
/** Class to run after RoboSpice task completion. */
private class ImageFeedRequestListener implements RequestListener<FeedImage[]> {
@Override
public void onRequestFailure(SpiceException spiceException) {
Log.d(getString(R.string.app_tag), "Image Feed load fail! " + spiceException.getMessage());
Toast.makeText(getActivity(), "Image Feed load fail!", Toast.LENGTH_SHORT).show();
getActivity().setProgressBarIndeterminateVisibility(false);
//mSpiceManager.shouldStop();
}
@Override
public void onRequestSuccess(FeedImage[] feedImages) {
if (page <= 1) {
aBarMenu.findItem(R.id.action_load_prev).setIcon(R.drawable.ic_navigation_back_dud);
aBarMenu.findItem(R.id.action_load_first).setIcon(R.drawable.ic_navigation_first_dud);
}
else {
aBarMenu.findItem(R.id.action_load_prev).setIcon(R.drawable.ic_navigation_back);
aBarMenu.findItem(R.id.action_load_first).setIcon(R.drawable.ic_navigation_first);
}
if (mList.size() > 0 && !feedImages[0].equals(mList.get(0)))
mList.clear();
if (mList.size() <= 0) {
Collections.addAll(mList, feedImages);
DateTimeFormatter formatter = DateTimeFormat.forPattern(getString(R.string.event_at_pattern));
mTitles.clear();
mUrls.clear();
mTimes.clear();
for (FeedImage f : mList) {
mTitles.add(f.getTitle());
mUrls.add(f.getPreviews().getAll());
mTimes.add(formatter.parseDateTime(f.getEvent_at()));
}
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mImageAdapter.notifyDataSetChanged();
getActivity().setProgressBarIndeterminateVisibility(false);
}
});
}
}
}
/**
* Method run to start to refresh the list of FeedImages on page reload or new page load.
* (true, true) loads next page.
* (true, false) loads the previous page.
* (false, false) loads first page of results.
* (false, true) reloads the same page.
* @param isNew "true" if loading a new page. "false" otherwise.
* @param isNext "true" is loading the next page. "false" otherwise.
*/
void refreshThumbs(boolean isNew, boolean isNext) {
getActivity().setProgressBarIndeterminateVisibility(true);
if (!mSpiceManager.isStarted())
mSpiceManager.start(getActivity().getBaseContext());
if (isNew) {
if (isNext)
page++;
else
page--;
}
else if (!isNext)
page = 1;
mSpiceManager.execute(new FeedImagesJsonRequest(imageFeed, page), JSON_CACHE_KEY, DurationInMillis.ALWAYS_EXPIRED, new ImageFeedRequestListener());
}
/**
* Takes an ArrayList of Strings and puts them in a bundle.
* Key Format: image_[key]_[num]
* @param notEncoded ArrayList of Strings to be bundled.
* @param key String used as part of the identifier in the bundle.
* @return Bundle containing all Strings from initial ArrayList.
*/
Bundle encodeBundle(ArrayList<String> notEncoded, String key) {
Bundle encoded = new Bundle();
for (int i = 0; i < notEncoded.size(); i++)
encoded.putString("image_" + key + "_" + i, notEncoded.get(i));
return encoded;
}
/**
* Takes an ArrayList of String Arrays and puts them in a bundle.
* Key Format: image_[key]_[image num]_[size num]
* @param notEncoded ArrayList of String Arrays to be bundled.
* @param key String used as part of the identifier in the bundle.
* @param numSizes Number of items in each String Array.
* @return Bundle containing all Strings from initial ArrayList.
*/
Bundle encodeBundle(ArrayList<String[]> notEncoded, String key, int numSizes) {
Bundle encoded = new Bundle();
encoded.putInt("num_image_sizes", numSizes);
for (int i = 0; i < notEncoded.size(); i++)
for (int j = 0; j < numSizes; j++)
encoded.putString("image_" + key + "_" + i + "_" + j, notEncoded.get(i)[j]);
return encoded;
}
/** Methods used to dynamically adapt GridView thumbnail sizing. */
/**
* Method containing the logic behind dynamic resizing.
* @param gv GridView to be adjusted.
*/
void adaptGridViewSize(GridView gv) {
int thumbMax = 250;
int spacing = 2;
DisplayMetrics d = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(d);
float trueMaxThumbWidth = maxTW(2, spacing, d);
if (trueMaxThumbWidth <= thumbMax) {
gv.setNumColumns(2);
gv.setColumnWidth((int) trueMaxThumbWidth);
gv.setHorizontalSpacing(spacing);
return;
}
int numCols;
float maxCols = numCols(thumbMax, spacing, d);
if (maxCols - ((int) maxCols) > 0.5)
numCols = ((int) maxCols) + 1;
else
numCols = ((int) maxCols);
gv.setHorizontalSpacing(spacing);
gv.setVerticalSpacing(spacing);
int tWidth = (int) maxTW(numCols, spacing, d);
gv.setColumnWidth(tWidth);
gv.setNumColumns(numCols);
}
/**
* Calculates the maximum thumbnail width given number of columns, spacing, and display size.
* @param numCols Number of columns to calculate for.
* @param spacing Space between images in regular pixels (px).
* @param d Screen information (in DisplayMetrics object).
* @return Maximum width of thumbnails (px) given parameters.
*/
float maxTW(float numCols, float spacing, DisplayMetrics d) {
return (d.widthPixels - ((numCols + 1) * spacing)) / numCols;
}
/**
* Calculates the number of columns possible given thumbnail width (px), spacing (px),
* and screen dimensions.
* @param thumbWidth Width of the thumbnails (px).
* @param spacing Space between images (px).
* @param d Screen information (in DisplayMetrics object).
* @return Maximum number of columns given parameters.
*/
float numCols(float thumbWidth, float spacing, DisplayMetrics d) {
return (d.widthPixels - spacing) / (spacing + thumbWidth);
}
}