Android Open Source - XKCD-Reader Comic Fragment






From Project

Back to project page XKCD-Reader.

License

The source code is released under:

Apache License

If you think the Android project XKCD-Reader listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.davidtpate.xkcd.ui;
/*from   w  w w . j av  a2s. c  o m*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.InjectView;
import com.davidtpate.xkcd.R;
import com.davidtpate.xkcd.model.Comic;
import com.davidtpate.xkcd.model.Constants;
import com.davidtpate.xkcd.provider.SystemUiStateProvider;
import com.davidtpate.xkcd.ui.base.BaseFragment;
import com.davidtpate.xkcd.util.ComicUtil;
import com.davidtpate.xkcd.util.Ln;
import com.github.kevinsawicki.http.HttpRequest;
import com.google.gson.Gson;
import com.squareup.picasso.Picasso;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import uk.co.senab.photoview.PhotoView;
import uk.co.senab.photoview.PhotoViewAttacher;

import static com.nineoldandroids.view.ViewPropertyAnimator.animate;

public class ComicFragment extends BaseFragment {
    @InjectView(R.id.ll_comic_information) LinearLayout mComicInformation;
    @InjectView(R.id.tv_title) TextView mTitle;
    @InjectView(R.id.tv_subtitle) TextView mSubTitle;
    @InjectView(R.id.tv_comic_details) TextView mComicDetails;
    @InjectView(R.id.iv_comic) PhotoView mComicImage;

    protected int mActionBarHeight;
    protected int mComicNumber = Constants.LATEST_COMIC_NUMBER;
    protected Comic mComic = null;
    protected SystemUiStateProvider mSystemUiStateProvider;

    protected BroadcastReceiver mToggleFullscreenReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            boolean isSystemUiVisible =
                intent.getBooleanExtra(Constants.Extra.EXTRA_SYSTEM_UI_VISIBILITY, false);
            if (isSystemUiVisible) {
                goFullscreen();
            } else {
                exitFullscreen();
            }
        }
    };

    protected PhotoViewAttacher.OnPhotoTapListener mPhotoTapListener =
        new PhotoViewAttacher.OnPhotoTapListener() {

            @Override
            public void onPhotoTap(View view, float x, float y) {
                Intent intent = new Intent(Constants.Intent.BROADCAST_TOGGLE_FULLSCREEN);
                intent.putExtra(Constants.Extra.EXTRA_SYSTEM_UI_VISIBILITY,
                    mSystemUiStateProvider.isSystemUiVisible());
                LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
            }
        };

    /**
     * Factory method to generate a new instance of the fragment given a comic number.
     *
     * @param comicNumber The number representing the comic to load
     * @return A new instance of ComicFragment with extras
     */
    public static ComicFragment newInstance(int comicNumber) {
        final ComicFragment f = new ComicFragment();

        final Bundle args = new Bundle();
        args.putInt(Constants.Extra.EXTRA_COMIC_NUMBER, comicNumber);
        f.setArguments(args);

        return f;
    }

    @Override public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        loadSavedInstanceState(getArguments());
        loadSavedInstanceState(savedInstanceState);
    }

    /**
     * Called when the fragment is visible to the user and actively running.
     * This is generally
     * tied to {@link android.app.Activity#onResume() Activity.onResume} of the containing
     * Activity's lifecycle.
     */
    @Override public void onResume() {
        super.onResume();
        if (mSystemUiStateProvider.isSystemUiVisible()) {
            exitFullscreen();
        } else {
            goFullscreen();
        }
    }

    /**
     * Called when the fragment's activity has been created and this
     * fragment's view hierarchy instantiated.  It can be used to do final
     * initialization once these pieces are in place, such as retrieving
     * views or restoring state.  It is also useful for fragments that use
     * {@link #setRetainInstance(boolean)} to retain their instance,
     * as this callback tells the fragment when it is fully associated with
     * the new activity instance.  This is called after {@link #onCreateView}
     * and before {@link #onViewStateRestored(android.os.Bundle)}.
     *
     * @param savedInstanceState If the fragment is being re-created from
     * a previous saved state, this is the state.
     */
    @Override public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        loadSavedInstanceState(savedInstanceState);

        try {
            mSystemUiStateProvider = (SystemUiStateProvider) getActivity();
        } catch (ClassCastException e) {
            Ln.e(e, "The parent activity must implement the SystemUiStateProvider interface");
        }

        // Calculate ActionBar height
        TypedValue tv = new TypedValue();
        if (getActivity().getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
            mActionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
                getActivity().getResources().getDisplayMetrics());
        }

        LocalBroadcastManager.getInstance(getActivity())
            .registerReceiver(mToggleFullscreenReceiver,
                new IntentFilter(Constants.Intent.BROADCAST_TOGGLE_FULLSCREEN));

        mComicImage.setOnPhotoTapListener(mPhotoTapListener);
    }

    /**
     * Called to have the fragment instantiate its user interface view.
     * This is optional, and non-graphical fragments can return null (which
     * is the default implementation).  This will be called between
     * {@link #onCreate(android.os.Bundle)} and {@link #onActivityCreated(android.os.Bundle)}.
     *
     * <p>If you return a View from here, you will later be called in
     * {@link #onDestroyView} when the view is being released.
     *
     * @param inflater The LayoutInflater object that can be used to inflate
     * any views in the fragment,
     * @param container If non-null, this is the parent view that the fragment's
     * UI should be attached to.  The fragment should not add the view itself,
     * but this can be used to generate the LayoutParams of the view.
     * @param savedInstanceState If non-null, this fragment is being re-constructed
     * from a previous saved state as given here.
     * @return Return the View for the fragment's UI, or null.
     */
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.comic_fragment, container, false);
        ResolveComicTask resolveComicTask = new ResolveComicTask();
        resolveComicTask.execute(mComicNumber);
        return view;
    }

    /**
     * Called to ask the fragment to save its current dynamic state, so it
     * can later be reconstructed in a new instance of its process is
     * restarted.  If a new instance of the fragment later needs to be
     * created, the data you place in the Bundle here will be available
     * in the Bundle given to {@link #onCreate(android.os.Bundle)},
     * {@link #onCreateView(android.view.LayoutInflater, android.view.ViewGroup,
     * android.os.Bundle)}, and
     * {@link #onActivityCreated(android.os.Bundle)}.
     *
     * <p>This corresponds to {@link android.app.Activity#onSaveInstanceState(android.os.Bundle)
     * Activity.onSaveInstanceState(Bundle)} and most of the discussion there
     * applies here as well.  Note however: <em>this method may be called
     * at any time before {@link #onDestroy()}</em>.  There are many situations
     * where a fragment may be mostly torn down (such as when placed on the
     * back stack with no UI showing), but its state will not be saved until
     * its owning activity actually needs to save its state.
     *
     * @param outState Bundle in which to place your saved state.
     */
    @Override public void onSaveInstanceState(Bundle outState) {
        outState.putInt(Constants.Extra.EXTRA_COMIC_NUMBER, mComicNumber);

        if (mComic != null) {
            outState.putParcelable(Constants.Extra.EXTRA_COMIC, mComic);
        }

        super.onSaveInstanceState(outState);
    }

    /**
     * Called when the fragment is no longer in use.  This is called
     * after {@link #onStop()} and before {@link #onDetach()}.
     */
    @Override public void onDestroy() {
        LocalBroadcastManager.getInstance(getActivity())
            .unregisterReceiver(mToggleFullscreenReceiver);
        super.onDestroy();
    }

    protected void loadSavedInstanceState(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            mComicNumber = savedInstanceState.getInt(Constants.Extra.EXTRA_COMIC_NUMBER,
                Constants.LATEST_COMIC_NUMBER);

            if (savedInstanceState.containsKey(Constants.Extra.EXTRA_COMIC)) {
                mComic = savedInstanceState.getParcelable(Constants.Extra.EXTRA_COMIC);
            }
        }
    }

    protected void goFullscreen() {
        animate(mComicInformation).setDuration(500).y(-400);
        mComicInformation.postDelayed(new Runnable() {
            @Override public void run() {
                mComicInformation.setVisibility(View.GONE);
            }
        }, 600);

    }

    protected void exitFullscreen() {
        mComicInformation.setVisibility(View.VISIBLE);
        animate(mComicInformation).setDuration(500).y(mActionBarHeight);
    }

    private class ResolveComicTask extends AsyncTask<Integer, Void, Comic> {

        /**
         * Override this method to perform a computation on a background thread. The
         * specified parameters are the parameters passed to {@link #execute}
         * by the caller of this task.
         *
         * This method can call {@link #publishProgress} to publish updates
         * on the UI thread.
         *
         * @param comicNumber The parameters of the task.
         * @return A result, defined by the subclass of this task.
         * @see #onPreExecute()
         * @see #onPostExecute
         * @see #publishProgress
         */
        @Override protected Comic doInBackground(Integer... comicNumber) {
            // Should only ever be a single comic number, so let's enforce it.
            if (comicNumber != null && comicNumber.length == 1) {
                HttpRequest request = HttpRequest.get(ComicUtil.getComicApiUrl(comicNumber[0]));
                if (request.code() == 200) {
                    String response = request.body();
                    request.disconnect();
                    Gson gson = new Gson();
                    Comic comicResponse = gson.fromJson(response, Comic.class);

                    return comicResponse;
                } else {
                    request.disconnect();
                    return null;
                }
            }
            return null;
        }

        /**
         * <p>Runs on the UI thread after {@link #doInBackground}. The
         * specified result is the value returned by {@link #doInBackground}.</p>
         *
         * <p>This method won't be invoked if the task was cancelled.</p>
         *
         * @param comic The result of the operation computed by {@link #doInBackground}.
         * @see #onPreExecute
         * @see #doInBackground
         * @see #onCancelled(Object)
         */
        @Override protected void onPostExecute(Comic comic) {
            super.onPostExecute(comic);
            if (comic != null && mTitle != null) {
                mComic = comic;
                mTitle.setText(comic.getTitle() + " (#" + comic.getNumber() + ")");
                mSubTitle.setText(comic.getSubTitle());
                Calendar cal = Calendar.getInstance();
                cal.set(Integer.valueOf(comic.getYear()), Integer.valueOf(comic.getMonth()),
                    Integer.valueOf(comic.getDay()));
                SimpleDateFormat dateFormat = new SimpleDateFormat("'Posted: 'EEE, MMM dd yyyy");
                mComicDetails.setText(dateFormat.format(cal.getTime()));
                Picasso.with(getActivity())
                    .load(comic.getImageUrl())
                    .placeholder(R.drawable.loading_spinner_76)
                    .into(mComicImage);
            }
        }
    }
}




Java Source Code List

android.support.v4.app.FixedFragmentStatePagerAdapter.java
com.android.debug.hv.ViewServer.java
com.davidtpate.xkcd.BaseApplication.java
com.davidtpate.xkcd.adapter.ComicPagerAdapter.java
com.davidtpate.xkcd.model.Comic.java
com.davidtpate.xkcd.model.Constants.java
com.davidtpate.xkcd.preferences.SharedPreferencesHelper.java
com.davidtpate.xkcd.provider.SystemUiStateProvider.java
com.davidtpate.xkcd.ui.About.java
com.davidtpate.xkcd.ui.ComicFragmentActivity.java
com.davidtpate.xkcd.ui.ComicFragment.java
com.davidtpate.xkcd.ui.CurrentComic.java
com.davidtpate.xkcd.ui.base.BaseActivity.java
com.davidtpate.xkcd.ui.base.BaseFragmentActivity.java
com.davidtpate.xkcd.ui.base.BaseFragment.java
com.davidtpate.xkcd.ui.base.BaseListActivity.java
com.davidtpate.xkcd.ui.base.BaseListFragment.java
com.davidtpate.xkcd.ui.dialog.JumpToDialogFragment.java
com.davidtpate.xkcd.util.AndroidUtil.java
com.davidtpate.xkcd.util.ComicUtil.java
com.davidtpate.xkcd.util.Ln.java
com.davidtpate.xkcd.util.MathUtil.java
com.davidtpate.xkcd.util.Strings.java