org.jorge.cmp.ui.fragment.FeedListFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.jorge.cmp.ui.fragment.FeedListFragment.java

Source

/*
 * This file is part of LoLin1.
 *
 * LoLin1 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LoLin1 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LoLin1. If not, see <http://www.gnu.org/licenses/>.
 *
 * Created by Jorge Antonio Diaz-Benito Soriano.
 */

package org.jorge.cmp.ui.fragment;

import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.TypedValue;
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.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.crashlytics.android.Crashlytics;

import org.jorge.cmp.LoLin1Application;
import org.jorge.cmp.R;
import org.jorge.cmp.datamodel.FeedArticle;
import org.jorge.cmp.ui.adapter.FeedAdapter;
import org.jorge.cmp.ui.component.ChainableSwipeRefreshLayout;
import org.jorge.cmp.ui.component.StickyParallaxNotifyingScrollView;
import org.jorge.cmp.util.Interface;
import org.jorge.cmp.util.PicassoUtils;

import java.util.concurrent.Executors;

public class FeedListFragment extends Fragment implements Interface.IOnItemInteractionListener {

    private RecyclerView mNewsView;
    private Context mContext;
    private FeedAdapter mFeedAdapter;
    private View mEmptyView;
    private String TAG;
    protected static final String TAG_KEY = "TAG", LM_KEY = "LAYOUT_MANAGER", TABLE_NAME_KEY = "TABLE_NAME";
    public static final String ERROR_RES_ID_KEY = "ERROR";
    private int mDefaultImageId;
    protected ActionBarActivity mActivity;
    private Interface.IOnFeedArticleClickedListener mCallback;
    private LayoutManagerEnum mLMIndicator;
    private Boolean mIsDualPane = Boolean.FALSE;
    private FeedArticle lastClickedArticle;
    private Drawable mActionBarBackgroundDrawable;
    private final Drawable.Callback mDrawableCallback = new Drawable.Callback() {
        @Override
        public void invalidateDrawable(Drawable who) {
            final ActionBar actionBar = mActivity.getSupportActionBar();
            if (actionBar != null)
                actionBar.setBackgroundDrawable(who);
        }

        @Override
        public void scheduleDrawable(Drawable who, Runnable what, long when) {
        }

        @Override
        public void unscheduleDrawable(Drawable who, Runnable what) {
        }
    };
    private StickyParallaxNotifyingScrollView.OnScrollChangedListener mOnScrollChangedListener = new StickyParallaxNotifyingScrollView.OnScrollChangedListener() {
        public void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt) {
            final int headerHeight = mHeaderView.getHeight() - mActivity.getSupportActionBar().getHeight();
            final float ratio = (float) Math.min(Math.max(t, 0), headerHeight) / headerHeight;
            final int newAlpha = (int) (ratio * 255);
            mActionBarBackgroundDrawable.setAlpha(newAlpha);
        }
    };
    private Integer FEED_REFRESH_TIME_MILLIS;
    private ActionBar mActionBar;
    private Float mOriginalElevation;
    private View mHeaderView;
    private TextView mArticleTitleView;
    private StickyParallaxNotifyingScrollView mParallaxScrollView;
    private TextView mArticlePreviewView;
    private ChainableSwipeRefreshLayout mRefreshLayout;
    private final SwipeRefreshLayout.OnRefreshListener mOnRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            mFeedAdapter.requestDataLoad(mActivity.getWindow().getDecorView());
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    try {
                        Thread.sleep(FEED_REFRESH_TIME_MILLIS);
                    } catch (InterruptedException e) {
                        Crashlytics.logException(e);
                    }
                    return null;
                }

                @Override
                protected void onPostExecute(Void aVoid) {
                    super.onPostExecute(aVoid);
                    mRefreshLayout.setRefreshing(Boolean.FALSE);
                    if (mIsDualPane)
                        reCalculateDualPaneDimensions();
                }
            }.executeOnExecutor(Executors.newSingleThreadExecutor());
        }
    };
    private String mTableName;

    protected enum LayoutManagerEnum {
        STAGGEREDGRID, GRID
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mContext = LoLin1Application.getInstance().getContext();
        mActionBarBackgroundDrawable = new ColorDrawable(
                mContext.getResources().getColor(R.color.toolbar_background));
        Bundle args = getArguments();
        if (args == null)
            throw new IllegalStateException("FeedListFragment created without arguments");
        else {
            TAG = args.getString(TAG_KEY);
            mLMIndicator = (LayoutManagerEnum) args.getSerializable(LM_KEY);
            mDefaultImageId = args.getInt(ERROR_RES_ID_KEY);
            mTableName = args.getString(TABLE_NAME_KEY);
        }
        mActivity = (ActionBarActivity) activity;
        mCallback = (Interface.IOnFeedArticleClickedListener) activity;
        FEED_REFRESH_TIME_MILLIS = mContext.getResources().getInteger(R.integer.feed_refresh_time_millis);

        if (mIsDualPane && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            mActionBarBackgroundDrawable.setCallback(mDrawableCallback);
        }
    }

    /**
     * Should be only used in dual-pane mode.
     */
    private void drawLastClickedArticle() {
        if (!mIsDualPane)
            throw new IllegalStateException("Do not use drawLastClickedArticle in modes other " + "than dual-pane");
        PicassoUtils.loadInto(mContext, lastClickedArticle.getImageUrl(), mDefaultImageId,
                (android.widget.ImageView) mHeaderView, TAG);
        final String title = lastClickedArticle.getTitle();
        mHeaderView.setContentDescription(title);
        mArticleTitleView.setText(title);
        mArticlePreviewView.setText(lastClickedArticle.getPreviewText());
        mActionBar.setTitle(lastClickedArticle.getTitle());

        mParallaxScrollView.setOnScrollChangedListener(mOnScrollChangedListener);
        mParallaxScrollView.smoothScrollTo(0, 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        setHasOptionsMenu(Boolean.TRUE);
        final View ret = inflater.inflate(R.layout.fragment_feed_article_list, container, Boolean.FALSE);
        mNewsView = (RecyclerView) ret.findViewById(R.id.feed_article_list_view);

        mRefreshLayout = (ChainableSwipeRefreshLayout) ret.findViewById(R.id.refreshable_layout);
        mRefreshLayout.setColorSchemeResources(R.color.material_orange_500, R.color.material_blue_500);
        TypedValue tv = new TypedValue();
        int actionBarHeight = -1;
        if (mContext.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, Boolean.TRUE)) {
            actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
        }
        if (actionBarHeight == -1)
            throw new IllegalStateException("Couldn't get the ActionBar height attribute");
        final Integer progressBarStartMargin = mContext.getResources()
                .getDimensionPixelSize(R.dimen.swipe_refresh_progress_bar_start_margin),
                progressBarEndMargin = mContext.getResources()
                        .getDimensionPixelSize(R.dimen.swipe_refresh_progress_bar_end_margin);
        mRefreshLayout.setProgressViewOffset(Boolean.FALSE, actionBarHeight + progressBarStartMargin,
                actionBarHeight + progressBarEndMargin);
        mRefreshLayout.setOnRefreshListener(mOnRefreshListener);
        mRefreshLayout.setRecyclerView(mNewsView);

        mActionBar = mActivity.getSupportActionBar();
        mActionBar.setDisplayHomeAsUpEnabled(Boolean.FALSE);
        mActionBar.setBackgroundDrawable(mActionBarBackgroundDrawable);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mOriginalElevation = mActionBar.getElevation();
            mActionBar.setElevation(0); //So that the shadow of the ActionBar doesn't show over
            // the title
        }

        mParallaxScrollView = (StickyParallaxNotifyingScrollView) ret.findViewById(R.id.scroll_view);
        mIsDualPane = mParallaxScrollView != null;
        mHeaderView = ret.findViewById(R.id.image);
        mArticleTitleView = (TextView) ret.findViewById(R.id.title);
        mArticlePreviewView = (TextView) ret.findViewById(android.R.id.text1);
        mNewsView.setOverScrollMode(View.OVER_SCROLL_NEVER);
        mEmptyView = ret.findViewById(android.R.id.empty);
        mFeedAdapter = new FeedAdapter(mContext, this, mDefaultImageId, TAG, mTableName, ret);
        if (mIsDualPane) {
            reCalculateDualPaneDimensions();
        }

        return ret;
    }

    @Override
    public void onResume() {
        mFeedAdapter.requestDataLoad(mActivity.getWindow().getDecorView());
        super.onResume();
    }

    private void reCalculateDualPaneDimensions() {
        lastClickedArticle = mFeedAdapter.getItemCount() > 0 ? mFeedAdapter.getItem(0) : null;
        if (lastClickedArticle != null)
            drawLastClickedArticle();
        else
            mNewsView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.MATCH_PARENT));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        PicassoUtils.cancel(mContext, TAG);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mActionBar.setElevation(mOriginalElevation);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            mActivity.onBackPressed();
            return Boolean.TRUE;
        case R.id.action_browse_to:
            lastClickedArticle.requestBrowseToAction(mContext);
            return Boolean.TRUE;
        case R.id.action_share:
            lastClickedArticle.requestShareAction(mContext);
            return Boolean.TRUE;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mFeedAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onChanged() {
                super.onChanged();
                checkAdapterIsEmpty();
            }
        });
        RecyclerView.LayoutManager layoutManager;
        final Integer columnAmount = mContext.getResources()
                .getInteger(mIsDualPane ? R.integer.dual_feed_column_amount : R.integer.feed_column_amount);
        switch (mLMIndicator) {
        case GRID:
            layoutManager = new GridLayoutManager(mContext, columnAmount);
            break;
        case STAGGEREDGRID:
            layoutManager = new StaggeredGridLayoutManager(columnAmount, StaggeredGridLayoutManager.VERTICAL);
            break;
        default:
            throw new IllegalArgumentException("Illegal LayoutManager indicator: " + mLMIndicator);
        }

        mNewsView.setLayoutManager(layoutManager);
        mNewsView.setItemAnimator(new DefaultItemAnimator());
        mNewsView.setAdapter(mFeedAdapter);
        checkAdapterIsEmpty();
    }

    private void checkAdapterIsEmpty() {
        if (mFeedAdapter.getItemCount() == 0) {
            mEmptyView.setVisibility(View.VISIBLE);
        } else {
            mEmptyView.setVisibility(View.GONE);
        }
    }

    @Override
    public void onItemClick(FeedArticle item) {
        if (mIsDualPane)
            drawLastClickedArticle();
        else {
            mCallback.onFeedArticleClicked(item, ((Object) this).getClass());
            mActivity.getSupportActionBar().show();
        }
    }

    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        if (enter) {
            return AnimationUtils.loadAnimation(mContext, R.anim.move_in_from_bottom);
        } else {
            return AnimationUtils.loadAnimation(mContext, R.anim.move_out_to_bottom);
        }
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);

        if (mIsDualPane && lastClickedArticle != null) {
            inflater.inflate(R.menu.actionbar_article_reader, menu);
        }
    }
}