package com.wangdaye.mysplash.me.view.widget; import android.annotation.SuppressLint; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.support.v4.view.ViewCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import com.github.rahatarmanahmed.cpv.CircularProgressView; import com.wangdaye.mysplash.Mysplash; import com.wangdaye.mysplash.R; import com.wangdaye.mysplash.common.data.entity.unsplash.Photo; import com.wangdaye.mysplash.common.i.model.LoadModel; import com.wangdaye.mysplash.common.i.model.PhotosModel; import com.wangdaye.mysplash.common.i.model.ScrollModel; import com.wangdaye.mysplash.common.i.presenter.LoadPresenter; import com.wangdaye.mysplash.common.i.presenter.PagerPresenter; import com.wangdaye.mysplash.common.i.presenter.PhotosPresenter; import com.wangdaye.mysplash.common.i.presenter.ScrollPresenter; import com.wangdaye.mysplash.common.i.presenter.SwipeBackPresenter; import com.wangdaye.mysplash.common.i.view.LoadView; import com.wangdaye.mysplash.common.i.view.PagerView; import com.wangdaye.mysplash.common.i.view.PhotosView; import com.wangdaye.mysplash.common.i.view.ScrollView; import com.wangdaye.mysplash.common.i.view.SwipeBackView; import com.wangdaye.mysplash.common.ui.adapter.PhotoAdapter; import com.wangdaye.mysplash.common.ui.widget.SwipeBackCoordinatorLayout; import com.wangdaye.mysplash.common.ui.widget.nestedScrollView.NestedScrollFrameLayout; import com.wangdaye.mysplash.common.ui.widget.swipeRefreshView.BothWaySwipeRefreshLayout; import com.wangdaye.mysplash.common.utils.AnimUtils; import com.wangdaye.mysplash.common.utils.BackToTopUtils; import com.wangdaye.mysplash.common.utils.DisplayUtils; import com.wangdaye.mysplash.common.utils.manager.ThemeManager; import com.wangdaye.mysplash.me.model.widget.LoadObject; import com.wangdaye.mysplash.me.model.widget.PhotosObject; import com.wangdaye.mysplash.me.model.widget.ScrollObject; import com.wangdaye.mysplash.me.presenter.widget.LoadImplementor; import com.wangdaye.mysplash.me.presenter.widget.PagerImplementor; import com.wangdaye.mysplash.me.presenter.widget.PhotosImplementor; import com.wangdaye.mysplash.me.presenter.widget.ScrollImplementor; import com.wangdaye.mysplash.me.presenter.widget.SwipeBackImplementor; import com.wangdaye.mysplash.me.view.activity.MeActivity; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; /** * Me photo view. * * This view is used to show application user's photos. * * */ @SuppressLint("ViewConstructor") public class MePhotosView extends NestedScrollFrameLayout implements PhotosView, PagerView, LoadView, ScrollView, SwipeBackView, BothWaySwipeRefreshLayout.OnRefreshAndLoadListener { @BindView(R.id.container_loading_view_mini_progressView) CircularProgressView progressView; @BindView(R.id.container_loading_view_mini_retryButton) Button retryButton; @BindView(R.id.container_photo_list_swipeRefreshLayout) BothWaySwipeRefreshLayout refreshLayout; @BindView(R.id.container_photo_list_recyclerView) RecyclerView recyclerView; private PhotosModel photosModel; private PhotosPresenter photosPresenter; private PagerPresenter pagerPresenter; private LoadModel loadModel; private LoadPresenter loadPresenter; private ScrollModel scrollModel; private ScrollPresenter scrollPresenter; private SwipeBackPresenter swipeBackPresenter; private static class SavedState implements Parcelable { String order; int page; boolean over; SavedState(MePhotosView view) { this.order = view.photosModel.getPhotosOrder(); this.page = view.photosModel.getPhotosPage(); this.over = view.photosModel.isOver(); } private SavedState(Parcel in) { this.order = in.readString(); this.page = in.readInt(); this.over = in.readByte() != 0; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel out, int flags) { out.writeString(this.order); out.writeInt(this.page); out.writeByte(this.over ? (byte) 1 : (byte) 0); } public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; } public MePhotosView(MeActivity a, int type, int id) { super(a); this.setId(id); this.initialize(a, type); } // init. @SuppressLint("InflateParams") private void initialize(MeActivity a, int type) { View loadingView = LayoutInflater.from(getContext()) .inflate(R.layout.container_loading_view_mini, this, false); addView(loadingView); View contentView = LayoutInflater.from(getContext()) .inflate(R.layout.container_photo_list, null); addView(contentView); ButterKnife.bind(this, this); initModel(a, type); initPresenter(); initView(); } // init. private void initModel(MeActivity a, int type) { this.photosModel = new PhotosObject( a, new PhotoAdapter(a, new ArrayList<Photo>(Mysplash.DEFAULT_PER_PAGE), a, a), type); this.loadModel = new LoadObject(LoadObject.LOADING_STATE); this.scrollModel = new ScrollObject(); } private void initPresenter() { this.photosPresenter = new PhotosImplementor(photosModel, this); this.pagerPresenter = new PagerImplementor(this); this.loadPresenter = new LoadImplementor(loadModel, this); this.scrollPresenter = new ScrollImplementor(scrollModel, this); this.swipeBackPresenter = new SwipeBackImplementor(this); } private void initView() { retryButton.setVisibility(GONE); refreshLayout.setColorSchemeColors(ThemeManager.getContentColor(getContext())); refreshLayout.setProgressBackgroundColorSchemeColor(ThemeManager.getRootColor(getContext())); refreshLayout.setOnRefreshAndLoadListener(this); refreshLayout.setPermitRefresh(false); refreshLayout.setVisibility(GONE); int navigationBarHeight = DisplayUtils.getNavigationBarHeight(getResources()); refreshLayout.setDragTriggerDistance( BothWaySwipeRefreshLayout.DIRECTION_BOTTOM, navigationBarHeight + getResources().getDimensionPixelSize(R.dimen.normal_margin)); int columnCount = DisplayUtils.getGirdColumnCount(getContext()); recyclerView.setAdapter(photosPresenter.getAdapter()); if (columnCount > 1) { int margin = getResources().getDimensionPixelSize(R.dimen.little_margin); recyclerView.setPadding(margin, margin, 0, 0); } else { recyclerView.setPadding(0, 0, 0, 0); } recyclerView.setLayoutManager( new StaggeredGridLayoutManager(columnCount, StaggeredGridLayoutManager.VERTICAL)); recyclerView.addOnScrollListener(scrollListener); photosPresenter.getAdapter().setRecyclerView(recyclerView); } // control. @Override public boolean isParentOffset() { return true; } // photo. public void updatePhoto(Photo p, boolean refreshView) { photosPresenter.getAdapter().updatePhoto(p, false, refreshView); } /** * Get the photos from the adapter in this view. * * @return Photos in adapter. * */ public List<Photo> getPhotos() { return photosPresenter.getAdapter().getPhotoData(); } /** * Set photos to the adapter in this view. * * @param list Photos that will be set to the adapter. * */ public void setPhotos(List<Photo> list) { if (list == null) { list = new ArrayList<>(); } photosPresenter.getAdapter().setPhotoData(list); if (list.size() == 0) { refreshPager(); } else { setNormalState(); } } // interface. // on click listener. @OnClick(R.id.container_loading_view_mini_retryButton) void retryRefresh() { photosPresenter.initRefresh(getContext()); } // on refresh an load listener. @Override public void onRefresh() { photosPresenter.refreshNew(getContext(), false); } @Override public void onLoad() { photosPresenter.loadMore(getContext(), false); } // on scroll listener. private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); scrollPresenter.autoLoad(dy); } }; // view. // photos view. @Override public void setRefreshing(boolean refreshing) { refreshLayout.setRefreshing(refreshing); } @Override public void setLoading(boolean loading) { refreshLayout.setLoading(loading); } @Override public void setPermitRefreshing(boolean permit) { refreshLayout.setPermitRefresh(permit); } @Override public void setPermitLoading(boolean permit) { refreshLayout.setPermitLoad(permit); } @Override public void initRefreshStart() { loadPresenter.setLoadingState(); } @Override public void requestPhotosSuccess() { loadPresenter.setNormalState(); } @Override public void requestPhotosFailed(String feedback) { loadPresenter.setFailedState(); } // pager view. @Override public void onSaveInstanceState(Bundle bundle) { bundle.putParcelable(String.valueOf(getId()), new SavedState(this)); } @Override public void onRestoreInstanceState(Bundle bundle) { SavedState ss = bundle.getParcelable(String.valueOf(getId())); if (ss != null) { photosPresenter.setOrder(ss.order); photosPresenter.setPage(ss.page); photosPresenter.setOver(ss.over); } } @Override public void checkToRefresh() { // interface if (pagerPresenter.checkNeedRefresh()) { pagerPresenter.refreshPager(); } } @Override public boolean checkNeedRefresh() { return loadPresenter.getLoadState() == LoadObject.FAILED_STATE || (loadPresenter.getLoadState() == LoadObject.LOADING_STATE && !photosPresenter.isRefreshing() && !photosPresenter.isLoading()); } @Override public boolean checkNeedBackToTop() { return scrollPresenter.needBackToTop(); } @Override public void refreshPager() { photosPresenter.initRefresh(getContext()); } @Override public void scrollToPageTop() { // interface. scrollPresenter.scrollToTop(); } @Override public void cancelRequest() { photosPresenter.cancelRequest(); } @Override public void setKey(String key) { photosPresenter.setOrder(key); } @Override public String getKey() { return photosPresenter.getOrder(); } @Override public boolean canSwipeBack(int dir) { return swipeBackPresenter.checkCanSwipeBack(dir); } @Override public int getItemCount() { if (loadPresenter.getLoadState() != LoadObject.NORMAL_STATE) { return 0; } else { return photosPresenter.getAdapter().getRealItemCount(); } } // load view. @Override public void animShow(View v) { AnimUtils.animShow(v); } @Override public void animHide(final View v) { AnimUtils.animHide(v); } @Override public void setLoadingState() { animShow(progressView); animHide(retryButton); } @Override public void setFailedState() { animShow(retryButton); animHide(progressView); } @Override public void setNormalState() { animShow(refreshLayout); animHide(progressView); } @Override public void resetLoadingState() { animShow(progressView); animHide(refreshLayout); } // scroll view. @Override public void scrollToTop() { BackToTopUtils.scrollToTop(recyclerView); } @Override public void autoLoad(int dy) { int[] lastVisibleItems = ((StaggeredGridLayoutManager) recyclerView.getLayoutManager()) .findLastVisibleItemPositions(null); int totalItemCount = photosPresenter.getAdapter().getRealItemCount(); if (photosPresenter.canLoadMore() && lastVisibleItems[lastVisibleItems.length - 1] >= totalItemCount - 10 && totalItemCount > 0 && dy > 0) { photosPresenter.loadMore(getContext(), false); } if (!ViewCompat.canScrollVertically(recyclerView, -1)) { scrollPresenter.setToTop(true); } else { scrollPresenter.setToTop(false); } if (!ViewCompat.canScrollVertically(recyclerView, 1) && photosPresenter.isLoading()) { refreshLayout.setLoading(true); } } @Override public boolean needBackToTop() { return !scrollPresenter.isToTop() && loadPresenter.getLoadState() == LoadObject.NORMAL_STATE; } // swipe back view. @Override public boolean checkCanSwipeBack(int dir) { switch (loadPresenter.getLoadState()) { case LoadObject.NORMAL_STATE: return SwipeBackCoordinatorLayout.canSwipeBack(recyclerView, dir) || photosPresenter.getAdapter().getRealItemCount() <= 0; default: return true; } } }