com.linroid.pushapp.view.ContentLoaderView.java Source code

Java tutorial

Introduction

Here is the source code for com.linroid.pushapp.view.ContentLoaderView.java

Source

/*
 * Copyright (c) linroid 2015.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.linroid.pushapp.view;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.linroid.pushapp.R;

import timber.log.Timber;

/**
 * Created by linroid on 2/3/15.
 */
public class ContentLoaderView extends FrameLayout
        implements SwipeRefreshLayout.OnRefreshListener, View.OnClickListener {
    public static final int LOAD_MORE_ITEM_SLOP = 4;
    View loadingView;
    View emptyView;
    View errorView;

    Button emptyRetryBtn;
    Button errorRetryBtn;
    TextView emptyMessageTV;
    TextView errorMessageTV;

    public SwipeRefreshLayout refreshLayout;
    public RecyclerView recyclerView;
    private View contentView;

    private OnRefreshListener refreshListener;
    private OnMoreListener moreListener;

    private boolean loadMore = false;
    private int totalPage = 1;
    private int currentPage = 1;

    private int padding;
    private int paddingLeft;
    private int paddingRight;
    private int paddingTop;
    private int paddingBottom;
    private boolean clipToPadding;

    public static final String DISPLAY_STATE = "display_state";
    public static final int STATE_CONTENT = 0x1;
    public static final int STATE_LOADING = 0x2;
    public static final int STATE_EMPTY = 0x3;
    public static final int STATE_ERROR = 0x4;
    private int displayState = STATE_LOADING;

    public ContentLoaderView(Context context) {
        super(context);
        initViews();
    }

    public ContentLoaderView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
        initViews();
    }

    public ContentLoaderView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initViews();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ContentLoaderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    private void initAttrs(Context ctx, AttributeSet attr) {
        TypedArray ta = ctx.obtainStyledAttributes(attr, R.styleable.ContentLoaderView);
        padding = ta.getDimensionPixelSize(R.styleable.ContentLoaderView_android_padding, -1);
        paddingLeft = ta.getDimensionPixelSize(R.styleable.ContentLoaderView_android_paddingLeft, -1);
        paddingRight = ta.getDimensionPixelSize(R.styleable.ContentLoaderView_android_paddingRight, -1);
        paddingTop = ta.getDimensionPixelSize(R.styleable.ContentLoaderView_android_paddingTop, -1);
        paddingBottom = ta.getDimensionPixelSize(R.styleable.ContentLoaderView_android_paddingBottom, -1);
        clipToPadding = ta.getBoolean(R.styleable.ContentLoaderView_android_clipToPadding, true);
        int errorViewId = ta.getResourceId(R.styleable.ContentLoaderView_errorView, R.layout.content_loader_error);
        int emptyViewId = ta.getResourceId(R.styleable.ContentLoaderView_emptyView, R.layout.content_loader_empty);
        int loadingViewId = ta.getResourceId(R.styleable.ContentLoaderView_loadingView,
                R.layout.content_loader_loading);
        int contentViewId = ta.getResourceId(R.styleable.ContentLoaderView_contentView,
                R.layout.content_loader_content);
        ta.recycle();
        LayoutInflater inflater = LayoutInflater.from(ctx);

        errorView = inflater.inflate(errorViewId, this, false);
        emptyView = inflater.inflate(emptyViewId, this, false);
        loadingView = inflater.inflate(loadingViewId, this, false);
        contentView = inflater.inflate(contentViewId, this, false);
        addView(errorView);
        addView(emptyView);
        addView(loadingView);
        addView(contentView);
    }

    private void initViews() {
        setPadding(0, 0, 0, 0);
        setClickable(true);
        refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresher);
        recyclerView = (RecyclerView) findViewById(R.id.recycler);
        errorRetryBtn = (Button) errorView.findViewById(R.id.btn_error_retry);
        errorMessageTV = (TextView) errorView.findViewById(R.id.error_message);
        emptyRetryBtn = (Button) emptyView.findViewById(R.id.btn_empty_retry);
        emptyMessageTV = (TextView) emptyView.findViewById(R.id.empty_message);

        if (errorRetryBtn != null) {
            errorRetryBtn.setOnClickListener(this);
        }
        if (emptyRetryBtn != null) {
            emptyRetryBtn.setOnClickListener(this);
        }
        contentView = refreshLayout;
        refreshLayout.setEnabled(false);
        refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_purple,
                android.R.color.holo_green_light, android.R.color.holo_red_light,
                android.R.color.holo_orange_light);
        refreshLayout.setOnRefreshListener(this);
        recyclerView.addOnScrollListener(mRecyclerScrollListener);
        if (padding != -1) {
            recyclerView.setPadding(padding, padding, padding, padding);
        } else {
            recyclerView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
        }
        recyclerView.setClipToPadding(clipToPadding);
        setDisplayState(STATE_LOADING);
    }

    RecyclerView.OnScrollListener mRecyclerScrollListener = new RecyclerView.OnScrollListener() {
        int totalItemCount;
        int visibleItemCount;
        int firstVisibleItemPosition;

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            RecyclerView.LayoutManager layoutManager;
            layoutManager = recyclerView.getLayoutManager();
            totalItemCount = layoutManager.getItemCount();
            visibleItemCount = layoutManager.getChildCount();
            View firstVisibleChild = recyclerView.getChildAt(0);
            firstVisibleItemPosition = recyclerView.getChildPosition(firstVisibleChild);
            if (totalPage > currentPage && !loadMore
                    && (firstVisibleItemPosition + visibleItemCount + LOAD_MORE_ITEM_SLOP) >= totalItemCount) {

                loadMore = true;
                if (moreListener != null) {
                    moreListener.onMore(++currentPage);
                    refreshLayout.setEnabled(false);
                    Timber.d("load more page:%d", currentPage);
                }
            }
        }
    };

    public void setAdapter(RecyclerView.Adapter adapter) {
        recyclerView.setAdapter(adapter);
        if (adapter.getItemCount() > 0) {
            setDisplayState(STATE_CONTENT);
        }
        adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onChanged() {
                super.onChanged();
                update();
            }

            @Override
            public void onItemRangeChanged(int positionStart, int itemCount) {
                super.onItemRangeChanged(positionStart, itemCount);
                update();
            }

            @Override
            public void onItemRangeInserted(int positionStart, int itemCount) {
                super.onItemRangeInserted(positionStart, itemCount);
                update();
            }

            @Override
            public void onItemRangeRemoved(int positionStart, int itemCount) {
                super.onItemRangeRemoved(positionStart, itemCount);
                update();
            }

            @Override
            public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
                super.onItemRangeMoved(fromPosition, toPosition, itemCount);
                update();
            }

            private void update() {
                Timber.d("Adapter updated, itemCount:%d", recyclerView.getLayoutManager().getItemCount());
                int itemCount = recyclerView.getLayoutManager().getItemCount();
                if (itemCount > 0) {
                    if (loadMore) {
                        loadMoreCompleted();
                    }
                    setDisplayState(STATE_CONTENT);
                } else {
                    setDisplayState(STATE_EMPTY);
                }
                if (refreshLayout.isRefreshing()) {
                    refreshLayout.setRefreshing(false);
                }
            }
        });
    }

    //    @OnClick(R.id.btn_retry)
    public void onRetryButtonClick() {
        refreshLayout.setRefreshing(true);
        setDisplayState(STATE_CONTENT);
        if (refreshListener != null) {
            refreshListener.onRefresh(false);
        }
    }

    public void notifyLoadFailed(Throwable error) {
        if (refreshLayout.isRefreshing()) {
            refreshLayout.setRefreshing(false);
        }
        loadMore = false;
        if (currentPage == 1 && recyclerView.getLayoutManager().getChildCount() == 0) {
            errorMessageTV.setText(error.getMessage());
            setDisplayState(STATE_ERROR);
        } else {
            setDisplayState(STATE_CONTENT);
            Toast.makeText(getContext(), error.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private void loadMoreCompleted() {
        loadMore = false;
        refreshLayout.setEnabled(true);
        setDisplayState(STATE_CONTENT);
    }

    public void setMoreListener(OnMoreListener moreListener) {
        this.moreListener = moreListener;
    }

    public void setPage(int currentPage, int totalPage) {
        this.currentPage = currentPage;
        this.totalPage = totalPage;
    }

    private void setDisplayState(int state) {
        this.displayState = state;
        loadingView.setVisibility(state == STATE_LOADING ? VISIBLE : GONE);
        emptyView.setVisibility(state == STATE_EMPTY ? VISIBLE : GONE);
        errorView.setVisibility(state == STATE_ERROR ? VISIBLE : GONE);
        contentView.setVisibility(state == STATE_CONTENT ? VISIBLE : GONE);
    }

    public void setOnRefreshListener(OnRefreshListener refreshListener) {
        this.refreshListener = refreshListener;
        refreshLayout.setEnabled(true);
    }

    @Override
    public void onRefresh() {
        currentPage = 1;
        if (refreshListener != null) {
            refreshListener.onRefresh(true);
        }
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Parcelable parcelable = super.onSaveInstanceState();
        SavedState savedState = new SavedState(parcelable);
        savedState.state = this.displayState;
        return savedState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        this.displayState = savedState.state;
        setDisplayState(this.displayState);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_error_retry:
        case R.id.btn_empty_retry: {
            setDisplayState(STATE_LOADING);
            onRefresh();
            break;
        }

        }
    }

    public interface OnRefreshListener {
        void onRefresh(boolean fromSwipe);
    }

    public interface OnMoreListener {
        void onMore(int page);
    }

    static class SavedState extends BaseSavedState {
        private int state;

        SavedState(Parcelable superState) {
            super(superState);
        }

        public SavedState(Parcel source) {
            super(source);
            try {
                state = source.readInt();
            } catch (IllegalArgumentException e) {
                state = STATE_LOADING;
            }
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(state);
        }

        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
            @Override
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
}