package com.ghostflying.portalwaitinglist.fragment;
import android.app.Fragment;
import android.app.LoaderManager;
import android.content.Intent;
import android.content.Loader;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
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.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.ghostflying.portalwaitinglist.MainActivity;
import com.ghostflying.portalwaitinglist.ObservableScrollView;
import com.ghostflying.portalwaitinglist.R;
import com.ghostflying.portalwaitinglist.loader.SearchResultLoader;
import com.ghostflying.portalwaitinglist.model.PortalDetail;
import com.ghostflying.portalwaitinglist.model.PortalEvent;
import com.ghostflying.portalwaitinglist.util.SettingUtil;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.io.FileOutputStream;
import java.text.DateFormat;
import java.util.Date;
public class ReDesignDetailFragment extends Fragment
implements ObservableScrollView.Callbacks, LoaderManager.LoaderCallbacks<PortalDetail> {
static final String ARG_CLICKED_PORTAL_NAME = "clickedPortal";
static final String ARG_FIRST_EVENT_ID = "firstEventId";
PortalDetail clickedPortal;
String firstEventId;
ObservableScrollView mScrollView;
ImageView mPhotoView;
View mPhotoViewContainer;
View mHeaderBox;
View mDetailsContainer;
TextView mPortalName;
TextView mPortalSummary;
TextView mPortalAddress;
View mPortalAddressView;
Toolbar mToolbar;
View mPortalEventListContainer;
Menu mMenu;
private DateFormat localDateFormat;
private int mPhotoHeightPixels;
private int mHeaderHeightPixels;
private boolean mHasPhoto;
private float mMaxHeaderElevation;
private String addressUrl;
private GoogleApiClient mClient;
private static final Uri BASE_APP_URI = Uri.parse(
"android-app://com.ghostflying.portalwaitinglist/http/portalwaitinglist.ghostflying.com/portal/");
private static final String BASE_WEB_URL = "http://portalwaitinglist.ghostflying.com/portal/";
private Uri appUri;
public static ReDesignDetailFragment newInstance(Parcelable clickedPortal) {
ReDesignDetailFragment fragment = new ReDesignDetailFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_CLICKED_PORTAL_NAME, clickedPortal);
fragment.setArguments(args);
return fragment;
}
public static ReDesignDetailFragment newInstance(String messageId) {
ReDesignDetailFragment fragment = new ReDesignDetailFragment();
Bundle args = new Bundle();
args.putString(ARG_FIRST_EVENT_ID, messageId);
fragment.setArguments(args);
return fragment;
}
public ReDesignDetailFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
localDateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
mClient = new GoogleApiClient.Builder(getActivity()).addApi(AppIndex.APP_INDEX_API).build();
if (getArguments() != null) {
clickedPortal = getArguments().getParcelable(ARG_CLICKED_PORTAL_NAME);
firstEventId = getArguments().getString(ARG_FIRST_EVENT_ID);
}
}
@Override
public void onStart(){
super.onStart();
if (clickedPortal != null)
recordView();
}
private void recordView() {
mClient.connect();
final String TITLE = clickedPortal.getName();
String messageId = clickedPortal.getEvents().get(0).getMessageId();
appUri = BASE_APP_URI.buildUpon().appendPath(messageId).build();
final Uri WEB_URI = Uri.parse(BASE_WEB_URL + messageId);
AppIndex.AppIndexApi.view(mClient, getActivity(), appUri, TITLE, WEB_URI, null);
}
@Override
public void onStop(){
super.onStop();
AppIndex.AppIndexApi.viewEnd(mClient, getActivity(), appUri);
mClient.disconnect();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_re_design_detail, container, false);
// toolbar
mToolbar = (Toolbar)view.findViewById(R.id.detail_toolbar);
mToolbar.setTitle("");
((ActionBarActivity)getActivity()).setSupportActionBar(mToolbar);
mToolbar.setNavigationIcon(R.drawable.ic_up);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (firstEventId != null){
startActivity(new Intent(getActivity(), MainActivity.class));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
getActivity().finishAfterTransition();
}
else
getActivity().finish();
}
});
// remove the elevation to make header unify
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
mToolbar.setElevation(0);
mScrollView = (ObservableScrollView)view.findViewById(R.id.scroll_view);
mScrollView.addCallbacks(this);
// Header
mHeaderBox = view.findViewById(R.id.header_portal);
mPhotoView = (ImageView)view.findViewById(R.id.portal_photo);
mPhotoViewContainer = view.findViewById(R.id.portal_photo_container);
mPortalName = (TextView)view.findViewById(R.id.portal_name);
mPortalSummary = (TextView)view.findViewById(R.id.portal_status_in_detail);
mMaxHeaderElevation = getResources().getDimensionPixelSize(
R.dimen.portal_detail_max_header_elevation);
// details
mDetailsContainer = view.findViewById(R.id.detail_container);
mPortalAddress = (TextView)view.findViewById(R.id.portal_address_in_detail);
mPortalAddressView = view.findViewById(R.id.portal_address_view_in_detail);
mPortalEventListContainer = view.findViewById(R.id.portal_event_list);
// set observer for views
ViewTreeObserver vto = mScrollView.getViewTreeObserver();
if (vto.isAlive()) {
vto.addOnGlobalLayoutListener(mGlobalLayoutListener);
}
// menu
setHasOptionsMenu(true);
if (clickedPortal != null)
showPortal(clickedPortal);
else {
getLoaderManager().initLoader(0, null, this);
}
return view;
}
private void showPortal(PortalDetail portal){
mPortalName.setText(portal.getName());
mPortalSummary.setText(getSummaryText(portal));
String address = portal.getAddress();
if (address != null){
mPortalAddress.setText(address);
}
else {
mPortalAddressView.setVisibility(View.GONE);
}
addEventViews(portal, (ViewGroup)mPortalEventListContainer);
// photo
String photoUrl = portal.getImageUrl();
if (SettingUtil.getIfShowImages() && photoUrl != null && photoUrl.startsWith("http")){
mHasPhoto = true;
// download and show the image of portal
Picasso.with(getActivity())
.load(photoUrl.replaceFirst("http://", "https://"))
.placeholder(R.drawable.portal_photo_placeholder)
.resizeDimen(R.dimen.portal_detail_photo_width, R.dimen.portal_detail_photo_height)
.into(mPhotoView);
}
else {
mHasPhoto = false;
}
// set color
setColors(portal);
removeMapMenuOnDemand(portal);
if (firstEventId != null && mHasPhoto){
ViewGroup.LayoutParams lp;
lp = mPhotoViewContainer.getLayoutParams();
lp.height = getResources().getDimensionPixelSize(R.dimen.portal_detail_photo_height);
mPhotoViewContainer.setLayoutParams(lp);
}
}
private void removeMapMenuOnDemand(PortalDetail portal) {
if (portal != null && mMenu != null){
// check if there is available address url
addressUrl = portal.getAddressUrl();
if (addressUrl == null || !addressUrl.startsWith("http"))
mMenu.removeItem(R.id.menu_item_view_map);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_re_design_detail, menu);
mMenu = menu;
removeMapMenuOnDemand(clickedPortal);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.menu_item_view_map:
if (addressUrl != null)
openUrl(addressUrl);
return true;
case R.id.menu_item_share:
new ShareTask().execute();
return true;
}
return super.onOptionsItemSelected(item);
}
private void openUrl(String url){
Intent webIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(webIntent);
}
private void doShare(Bitmap generated){
// save file to external
File file = new File(getActivity().getExternalCacheDir(),
"ScreenShot-" + Long.toString(new Date().getTime()) + ".png");
try{
FileOutputStream fOut = new FileOutputStream(file);
generated.compress(Bitmap.CompressFormat.PNG, 100, fOut);
fOut.flush();
fOut.close();
}
catch (Exception e){
handleException(e);
return;
}
// share file to other apps
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/*");
Uri uri = Uri.fromFile(file);
share.putExtra(Intent.EXTRA_STREAM, uri);
share.putExtra(Intent.EXTRA_TEXT, clickedPortal.getName());
startActivity(Intent.createChooser(share, "Share Portal"));
}
private void handleException(Exception e){
e.printStackTrace();
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getActivity(), R.string.write_error_toast, Toast.LENGTH_SHORT).show();
}
});
}
private Bitmap getBitmapFromView(View v) {
// store the origin state
int originWidth = v.getMeasuredWidth();
int originHeight = v.getMeasuredHeight();
// capture the view
int specWidth = View.MeasureSpec.makeMeasureSpec(originWidth, View.MeasureSpec.EXACTLY);
int specHeight = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
v.measure(specWidth, specHeight);
Bitmap b = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Canvas c = new Canvas(b);
c.drawColor(getResources().getColor(R.color.default_background));
v.draw(c);
// restore the view
specHeight = View.MeasureSpec.makeMeasureSpec(originHeight, View.MeasureSpec.EXACTLY);
v.measure(specWidth, specHeight);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
return b;
}
private void addEventViews(PortalDetail portalDetail, ViewGroup container){
LayoutInflater inflater = LayoutInflater.from(container.getContext());
for (PortalEvent event : portalDetail.getEvents()){
View view = inflater.inflate(R.layout.portal_event_in_re_design_detail,
container, false);
((ImageView)view.findViewById(R.id.event_result)).setImageResource(
getEventResultIconResource(event.getOperationResult())
);
((TextView)view.findViewById(R.id.event_description)).setText(getEventDescription(event));
((TextView)view.findViewById(R.id.event_date))
.setText(localDateFormat.format(event.getDate()) +
" (" + getDateDiffStr(event.getDate()) + getString(R.string.days_ago) + ")");
container.addView(view);
}
}
private String getEventDescription(PortalEvent event){
String description = null;
switch (event.getOperationType()){
case SUBMISSION:
description = getString(R.string.event_description_submission);
break;
case EDIT:
description = getString(R.string.event_description_edit);
break;
case INVALID:
description = getString(R.string.event_description_invalid);
break;
}
switch (event.getOperationResult()){
case PROPOSED:
description += getString(R.string.event_description_proposed);
break;
case ACCEPTED:
description += getString(R.string.event_description_accepted);
break;
case DUPLICATE:
description += getString(R.string.event_description_duplicated);
break;
case REJECTED:
description += getString(R.string.event_description_rejected);
break;
}
return description;
}
private int getEventResultIconResource(PortalEvent.OperationResult result){
switch (result){
case PROPOSED:
return R.drawable.ic_waiting_40dp;
case ACCEPTED:
return R.drawable.ic_accepted_40dp;
case DUPLICATE:
case REJECTED:
return R.drawable.ic_rejected_40dp;
}
return R.drawable.ic_launcher;
}
private String getSummaryText(PortalDetail portalDetail){
// return the summary text for portals
// if portal is still waiting, the text is like Waiting for xxx days.
// if portal is accepted/rejected, the text is like Accepted/Rejected xxx days ago.
if (!portalDetail.isReviewed()){
return getString(R.string.waiting) + getString(R.string.date_for) +
getDateDiffStr(portalDetail.getLastUpdated()) + getString(R.string.days);
}
else if (portalDetail.isAccepted()){
return getString(R.string.accepted) + " " +
getDateDiffStr(portalDetail.getLastUpdated()) + " " + getString(R.string.day_ago);
}
else if (portalDetail.isRejected()){
return getString(R.string.rejected) + " " +
getDateDiffStr(portalDetail.getLastUpdated()) + " " + getString(R.string.day_ago);
}
else
return getString(R.string.default_status);
}
private String getDateDiffStr(Date date){
long diff = new Date().getTime() - date.getTime();
int dayDiff = Math.round(diff / 1000 / 3600 / 24);
return Integer.toString(dayDiff);
}
private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener
= new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
recomputePhotoAndScrollingMetrics();
}
};
@Override
public void onScrollChanged(int deltaX, int deltaY) {
// Reposition the header bar -- it's normally anchored to the top of the content,
// but locks to the top of the screen on scroll
// clone from Google IO
int scrollY = mScrollView.getScrollY();
float newTop = Math.max(mPhotoHeightPixels, scrollY);
mHeaderBox.setTranslationY(newTop);
float gapFillProgress = 1;
if (mPhotoHeightPixels != 0) {
gapFillProgress = Math.min(Math.max(getProgress(scrollY,
0,
mPhotoHeightPixels), 0), 1);
}
ViewCompat.setElevation(mHeaderBox, gapFillProgress * mMaxHeaderElevation);
// Move background photo (parallax effect)
mPhotoViewContainer.setTranslationY(scrollY * 0.5f);
}
private void recomputePhotoAndScrollingMetrics() {
// clone from Google IO
mHeaderHeightPixels = mHeaderBox.getHeight();
mPhotoHeightPixels = 0;
if (mHasPhoto) {
mPhotoHeightPixels = mPhotoView.getHeight();
}
ViewGroup.LayoutParams lp;
lp = mPhotoViewContainer.getLayoutParams();
if (lp.height != mPhotoHeightPixels) {
lp.height = mPhotoHeightPixels;
mPhotoViewContainer.setLayoutParams(lp);
}
ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)
mDetailsContainer.getLayoutParams();
if (mlp.topMargin != mHeaderHeightPixels + mPhotoHeightPixels) {
mlp.topMargin = mHeaderHeightPixels + mPhotoHeightPixels;
mDetailsContainer.setLayoutParams(mlp);
}
onScrollChanged(0, 0); // trigger scroll handling
}
private void setColors(PortalDetail portal){
int actionBarBg;
int statusBarBg;
if (portal.isAccepted()){
actionBarBg = getResources().getColor(R.color.portal_detail_action_bar_bg_accepted);
statusBarBg = getResources().getColor(R.color.portal_detail_status_bar_bg_accepted);
}
else if (portal.isRejected()){
actionBarBg = getResources().getColor(R.color.portal_detail_action_bar_bg_rejected);
statusBarBg = getResources().getColor(R.color.portal_detail_status_bar_bg_rejected);
}
else {
actionBarBg = getResources().getColor(R.color.portal_detail_action_bar_bg_waiting);
statusBarBg = getResources().getColor(R.color.portal_detail_status_bar_bg_waiting);
}
mToolbar.setBackgroundColor(actionBarBg);
mHeaderBox.setBackgroundColor(actionBarBg);
mPhotoViewContainer.setBackgroundColor(statusBarBg);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
getActivity().getWindow().setStatusBarColor(statusBarBg);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mScrollView == null) {
return;
}
ViewTreeObserver vto = mScrollView.getViewTreeObserver();
if (vto.isAlive()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
vto.removeOnGlobalLayoutListener(mGlobalLayoutListener);
else
vto.removeGlobalOnLayoutListener(mGlobalLayoutListener);
}
}
public float getProgress(int value, int min, int max) {
if (min == max) {
throw new IllegalArgumentException("Max (" + max + ") cannot equal min (" + min + ")");
}
return (value - min) / (float) (max - min);
}
@Override
public Loader<PortalDetail> onCreateLoader(int id, Bundle args) {
return new SearchResultLoader(getActivity(), firstEventId);
}
@Override
public void onLoadFinished(Loader<PortalDetail> loader, PortalDetail data) {
if (data != null){
clickedPortal = data;
showPortal(data);
recordView();
}
}
@Override
public void onLoaderReset(Loader<PortalDetail> loader) {
}
public class ShareTask extends AsyncTask<Void, Void, Void> {
Bitmap bitmap;
ScreenShotDialogFragment dialogFragment;
@Override
protected void onPreExecute() {
dialogFragment = ScreenShotDialogFragment.newInstance();
dialogFragment.show(getFragmentManager(), null);
bitmap = getBitmapFromView(getView());
}
@Override
protected Void doInBackground(Void... params) {
doShare(bitmap);
return null;
}
@Override
protected void onPostExecute(Void result){
dialogFragment.dismiss();
}
}
}