/* * Copyright � 2016 TIBCO Software,Inc.All rights reserved. * http://community.jaspersoft.com/project/jaspermobile-android * * Unless you have purchased a commercial license agreement from TIBCO Jaspersoft, * the following license terms apply: * * This program is part of TIBCO Jaspersoft Mobile for Android. * * TIBCO Jaspersoft Mobile is free software:you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation,either version 3of the License,or * (at your option)any later version. * * TIBCO Jaspersoft Mobile 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with TIBCO Jaspersoft Mobile for Android.If not,see * <http://www.gnu.org/licenses/lgpl>. */ package com.jaspersoft.android.jaspermobile.ui.view.widget; import android.content.Context; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SimpleItemAnimator; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import android.widget.TextView; import com.jaspersoft.android.jaspermobile.Analytics; import com.jaspersoft.android.jaspermobile.R; import com.jaspersoft.android.jaspermobile.domain.entity.Resource; import com.jaspersoft.android.jaspermobile.ui.contract.CatalogContract; import com.jaspersoft.android.jaspermobile.ui.view.component.ResourcesAdapter; import com.jaspersoft.android.jaspermobile.widget.JasperRecyclerView; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EViewGroup; import org.androidannotations.annotations.ViewById; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import javax.inject.Named; /** * @author Andrew Tivodar * @since 2.3 */ @EViewGroup public abstract class CatalogView extends FrameLayout implements CatalogContract.View, SwipeRefreshLayout.OnRefreshListener { private final static CatalogContract.EventListener EMPTY = new EmptyEventListener(); @ViewById(android.R.id.list) JasperRecyclerView resourcesList; @ViewById(R.id.refreshLayout) SwipeRefreshLayout swipeRefreshLayout; @ViewById(android.R.id.empty) TextView message; @Inject Analytics mAnalytics; @Inject @Named("THRESHOLD") protected int mTreshold; @Inject ResourcesAdapter<?, ?, ?> mAdapter; private CatalogContract.EventListener mEventListener = EMPTY; private boolean mInited; public CatalogView(Context context) { super(context); } public CatalogView(Context context, AttributeSet attrs) { super(context, attrs); } public CatalogView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setEventListener(CatalogContract.EventListener eventListener) { mEventListener = eventListener; } @AfterViews void initViews() { ((SimpleItemAnimator) resourcesList.getItemAnimator()).setSupportsChangeAnimations(false); swipeRefreshLayout.setOnRefreshListener(this); swipeRefreshLayout.setColorSchemeResources( R.color.js_blue, R.color.js_dark_blue, R.color.js_blue, R.color.js_dark_blue); resourcesList.addOnScrollListener(new ScrollListener()); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); resourcesList.setAdapter(mAdapter); if (mInited) return; mEventListener.onInit(); } @Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.message = message.getText().toString(); ss.refreshing = swipeRefreshLayout.isRefreshing(); ss.loading = mAdapter.isLoading(); ss.resources = new ArrayList<>(mAdapter.getResources()); return ss; } @Override protected void onRestoreInstanceState(Parcelable state) { if (!(state instanceof SavedState)) { super.onRestoreInstanceState(state); return; } SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); mAdapter.setResource(ss.resources); if (ss.loading) { mAdapter.showLoading(); } swipeRefreshLayout.setRefreshing(ss.refreshing); message.setText(ss.message); mInited = true; } @Override public void showResources(List<Resource> resources) { mAdapter.setResource(resources); } @Override public void showError() { mAdapter.setResource(new ArrayList<Resource>()); } @Override public void updateResource(int id) { mAdapter.notifyItemChangedById(id); } @Override public void showFirstLoading() { if (mAdapter.getItemCount() > 0) { swipeRefreshLayout.setRefreshing(true); } else { message.setVisibility(View.VISIBLE); message.setText(R.string.loading_msg); } } @Override public void showNextLoading() { mAdapter.showLoading(); } @Override public void hideLoading() { swipeRefreshLayout.setRefreshing(false); message.setVisibility(View.GONE); mAdapter.hideLoading(); } @Override public void onRefresh() { mEventListener.onRefresh(); } private static final class EmptyEventListener implements CatalogContract.EventListener { @Override public void onInit() { } @Override public void onRefresh() { } @Override public void onScrollToEnd() { } } //--------------------------------------------------------------------- // Implements AbsListView.OnScrollListener //--------------------------------------------------------------------- private class ScrollListener extends RecyclerView.OnScrollListener { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); int visibleItemCount = recyclerView.getChildCount(); int totalItemCount = recyclerView.getLayoutManager().getItemCount(); int firstVisibleItem; if (layoutManager instanceof LinearLayoutManager) { firstVisibleItem = ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition(); } else { firstVisibleItem = ((GridLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition(); } if (totalItemCount > 0 && firstVisibleItem + visibleItemCount >= totalItemCount - mTreshold) { mEventListener.onScrollToEnd(); } } } //--------------------------------------------------------------------- // Saved state //--------------------------------------------------------------------- static class SavedState extends BaseSavedState { private final static String MESSAGE_KEY = "message"; private final static String REFRESHING_KEY = "refreshing"; private final static String LOADING_KEY = "loading"; private final static String RESOURCES_KEY = "resources"; String message; boolean refreshing; boolean loading; ArrayList<Resource> resources; SavedState(Parcelable superState) { super(superState); } private SavedState(Parcel in) { super(in); Bundle bundle = in.readBundle(); message = bundle.getString(MESSAGE_KEY); refreshing = bundle.getBoolean(REFRESHING_KEY); loading = bundle.getBoolean(LOADING_KEY); resources = (ArrayList<Resource>) bundle.getSerializable(RESOURCES_KEY); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); Bundle state = new Bundle(); state.putString(MESSAGE_KEY, message); state.putBoolean(REFRESHING_KEY, refreshing); state.putBoolean(LOADING_KEY, loading); state.putSerializable(RESOURCES_KEY, resources); out.writeBundle(state); } 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]; } }; } }