package de.geeksfactory.opacclient.frontend;
import android.app.SearchManager;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.util.Pair;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import java.io.IOException;
import de.geeksfactory.opacclient.OpacClient;
import de.geeksfactory.opacclient.R;
import de.geeksfactory.opacclient.apis.OpacApi;
import de.geeksfactory.opacclient.apis.OpacApi.OpacErrorException;
import de.geeksfactory.opacclient.networking.NotReachableException;
import de.geeksfactory.opacclient.networking.SSLSecurityException;
import de.geeksfactory.opacclient.objects.SearchRequestResult;
import de.geeksfactory.opacclient.objects.SearchResult;
import de.geeksfactory.opacclient.utils.BitmapUtils;
import de.geeksfactory.opacclient.utils.ErrorReporter;
/**
* An activity representing a list of SearchResults. This activity has different presentations for
* handset and tablet-size devices. On handsets, the activity presents a list of items, which when
* touched, lead to a {@link SearchResultDetailActivity} representing item details. On tablets, the
* activity presents the list of items and item details side-by-side using two vertical panes.
* <p/>
* The activity makes heavy use of fragments. The list of items is a {@link
* SearchResultListFragment} and the item details (if present) is a {@link
* SearchResultDetailFragment}.
* <p/>
* This activity also implements the required {@link SearchResultListFragment.Callbacks} interface
* to listen for item selections.
*/
public class SearchResultListActivity extends OpacActivity implements
SearchResultListFragment.Callbacks,
SearchResultDetailFragment.Callbacks {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet device.
*/
protected boolean twoPane;
protected SearchResultListFragment listFragment;
protected SearchResultDetailFragment detailFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Show the Up button in the action bar.
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (savedInstanceState == null) {
setup();
} else {
if (savedInstanceState.containsKey("listFragment")) {
listFragment =
(SearchResultListFragment) getSupportFragmentManager()
.getFragment(savedInstanceState, "listFragment");
}
if (savedInstanceState.containsKey("detailFragment")) {
detailFragment =
(SearchResultDetailFragment) getSupportFragmentManager()
.getFragment(savedInstanceState, "detailFragment");
}
}
if (findViewById(R.id.searchresult_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
twoPane = true;
}
}
protected void setup() {
if ("com.google.android.gms.actions.SEARCH_ACTION".equals(getIntent()
.getAction())) {
listFragment = SearchResultListFragment
.getGoogleSearchInstance(getIntent()
.getStringExtra(SearchManager.QUERY));
} else if (getIntent().hasExtra("volumeQuery")) {
listFragment = SearchResultListFragment
.getVolumeSearchInstance(getIntent().getBundleExtra(
"volumeQuery"));
} else {
listFragment = SearchResultListFragment.getInstance(getIntent()
.getBundleExtra("query"));
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.searchresult_list_container, listFragment)
.commit();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater mi = new MenuInflater(this);
mi.inflate(R.menu.activity_search_results, menu);
return super.onCreateOptionsMenu(menu);
}
/**
* Callback method from {@link SearchResultListFragment.Callbacks} indicating that the item with
* the given ID was selected.
*/
@Override
public void onItemSelected(SearchResult result, View coverView, int touchX, int touchY) {
if (result.getChildQuery() != null) {
app.startSearch(this, result.getChildQuery());
} else {
OpacApi api;
try {
api = app.getApi();
} catch (OpacClient.LibraryRemovedException e) {
return;
}
if ((api.getSupportFlags() & OpacApi.SUPPORT_FLAG_ENDLESS_SCROLLING) == 0
&& result.getPage() != listFragment.getLastLoadedPage()) {
new ReloadOldPageTask(result, coverView).execute();
} else {
showDetail(result, coverView, touchX, touchY);
}
}
}
public void showDetail(SearchResult res, View coverView, int touchX, int touchY) {
Bitmap cover = BitmapUtils.bitmapFromBytes(res.getCoverBitmap());
Bitmap smallCover;
if (cover != null && cover.getWidth() * cover.getHeight() > 300 * 300) {
// Android's Parcelable implementation doesn't like huge images
int max = Math.max(cover.getWidth(), cover.getHeight());
int width = (int) ((300f / max) * cover.getWidth());
int height = (int) ((300f / max) * cover.getHeight());
smallCover = Bitmap.createScaledBitmap(cover, width, height, false);
} else {
smallCover = cover;
}
if (twoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
Bundle arguments = new Bundle();
arguments.putInt(SearchResultDetailFragment.ARG_ITEM_NR, res.getNr());
if (res.getId() != null) {
arguments.putString(SearchResultDetailFragment.ARG_ITEM_ID, res.getId());
}
if (res.getCoverBitmap() != null) {
arguments.putParcelable(SearchResultDetailFragment.ARG_ITEM_COVER_BITMAP,
smallCover);
}
if (res.getType() != null) {
arguments.putString(SearchResultDetailFragment.ARG_ITEM_MEDIATYPE,
res.getType().toString());
}
detailFragment = new SearchResultDetailFragment();
detailFragment.setArguments(arguments);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.searchresult_detail_container, detailFragment)
.commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this,
SearchResultDetailActivity.class);
detailIntent.putExtra(SearchResultDetailFragment.ARG_ITEM_NR, res.getNr());
if (res.getId() != null) {
detailIntent.putExtra(SearchResultDetailFragment.ARG_ITEM_ID,
res.getId());
}
if (res.getType() != null) {
detailIntent.putExtra(SearchResultDetailFragment.ARG_ITEM_MEDIATYPE,
res.getType().toString());
}
if (res.getCoverBitmap() != null) {
detailIntent.putExtra(SearchResultDetailFragment.ARG_ITEM_COVER_BITMAP,
smallCover);
detailIntent.putExtra(SearchResultDetailActivity.ARG_TOUCH_POSITION_X, touchX);
detailIntent.putExtra(SearchResultDetailActivity.ARG_TOUCH_POSITION_Y, touchY);
@SuppressWarnings("unchecked")
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
this,
new Pair<>(coverView, getString(R.string.transition_cover)),
new Pair<>((View) toolbar, getString(R.string.transition_toolbar)));
ActivityCompat.startActivity(this, detailIntent, options.toBundle());
} else {
startActivity(detailIntent);
}
}
}
@Override
protected int getContentView() {
return R.layout.activity_searchresult_list;
}
@Override
public void removeFragment() {
getSupportFragmentManager().beginTransaction().remove(detailFragment)
.commit();
}
@Override
public boolean isTwoPane() {
return twoPane;
}
public class ReloadOldPageTask extends AsyncTask<Void, Void, SearchRequestResult> {
private SearchResult searchResult;
private Exception exception;
private View coverView;
private int touchX = 0;
private int touchY = 0;
public ReloadOldPageTask(SearchResult searchResult, View coverView, int touchX,
int touchY) {
this.searchResult = searchResult;
this.coverView = coverView;
this.touchX = touchX;
this.touchY = touchY;
}
public ReloadOldPageTask(SearchResult searchResult, View coverView) {
this.searchResult = searchResult;
this.coverView = coverView;
}
@Override
protected void onPreExecute() {
setProgressBarIndeterminateVisibility(true);
}
@Override
protected SearchRequestResult doInBackground(Void... voids) {
try {
return app.getApi().searchGetPage(searchResult.getPage());
} catch (IOException | OpacErrorException e) {
exception = e;
e.printStackTrace();
} catch (Exception e) {
exception = e;
ErrorReporter.handleException(e);
}
return null;
}
@Override
protected void onPostExecute(SearchRequestResult result) {
setProgressBarIndeterminateVisibility(false);
if (result == null) {
if (exception instanceof OpacErrorException) {
listFragment.showConnectivityError(exception.getMessage());
} else if (exception instanceof SSLSecurityException) {
listFragment.showConnectivityError(getResources()
.getString(R.string.connection_error_detail_security));
} else if (exception instanceof NotReachableException) {
listFragment.showConnectivityError(getResources()
.getString(R.string.connection_error_detail_nre));
} else {
listFragment.showConnectivityError();
}
} else {
// Everything ran correctly, show Detail
listFragment.setLastLoadedPage(searchResult.getPage());
showDetail(searchResult, coverView, touchX, touchY);
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (listFragment != null) {
getSupportFragmentManager().putFragment(outState, "listFragment", listFragment);
}
if (detailFragment != null) {
getSupportFragmentManager().putFragment(outState, "detailFragment", detailFragment);
}
}
}