package com.gaiagps.iburn.fragment; import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; import android.widget.TextView; import android.widget.Toast; import com.gaiagps.iburn.Constants; import com.gaiagps.iburn.IntentUtil; import com.gaiagps.iburn.R; import com.gaiagps.iburn.Subscriber; import com.gaiagps.iburn.activity.PlayaItemViewActivity; import com.gaiagps.iburn.adapters.AdapterListener; import com.gaiagps.iburn.adapters.CursorRecyclerViewAdapter; import com.gaiagps.iburn.adapters.DividerItemDecoration; import com.gaiagps.iburn.database.DataProvider; import com.gaiagps.iburn.database.PlayaDatabase; import com.tonicartos.superslim.LayoutManager; import rx.Subscription; import timber.log.Timber; /** * Base class for iBurn list views describing Camps, Art, and Events. * <p> * Created by davidbrodsky on 8/3/13. */ public abstract class PlayaListViewFragment extends Fragment implements AdapterListener, Subscriber { public static final String ARG_SCROLL_POS = "spos"; protected CursorRecyclerViewAdapter adapter; protected RecyclerView mRecyclerView; protected TextView mEmptyText; protected Subscription subscription; private int lastScrollPos; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { lastScrollPos = savedInstanceState.getInt(ARG_SCROLL_POS, 0); Timber.d("%s onCreate with scroll ps %d", getClass().getSimpleName(), lastScrollPos); } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); adapter = getAdapter(); mRecyclerView.setAdapter(adapter); } public void onSaveInstanceState(Bundle outState) { // Save the scroll position with this instance and in Bundle for retrieval whether or not // this instance is recreated lastScrollPos = getScrollPosition(); outState.putInt(ARG_SCROLL_POS, lastScrollPos); Timber.d("%s onSaveInstanceState with scroll pos %d", getClass().getSimpleName(), lastScrollPos); } @Override public void onStop() { super.onStop(); unsubscribeFromData(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Timber.d("%s onCreateView", getClass().getSimpleName()); View v = inflater.inflate(R.layout.fragment_playa_list_view, container, false); //super.onCreateView(inflater, container, savedInstanceState); mEmptyText = (TextView) v.findViewById(android.R.id.empty); mRecyclerView = ((RecyclerView) v.findViewById(android.R.id.list)); mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST)); return v; } /** * Handle notifications that the data corresponding to our query changed, * and we should update UI */ protected void onDataChanged(Cursor newData) { if (newData == null) { Timber.w("Got null data onDataChanged"); return; } Timber.d("%s onDataChanged Had %d items. Now %d items", getClass().getSimpleName(), adapter.getItemCount(), newData.getCount()); boolean adapterWasEmpty = adapter.getItemCount() == 0; if (adapterWasEmpty && newData.getCount() > 0) { // Fade in the initial data, but let updates happen without animation AlphaAnimation fadeAnimation = new AlphaAnimation(0, 1); fadeAnimation.setDuration(250); fadeAnimation.setStartOffset(100); fadeAnimation.setFillAfter(true); fadeAnimation.setFillEnabled(true); mRecyclerView.startAnimation(fadeAnimation); } if (newData.getCount() == 0) { setListShown(false); } else { setListShown(true); } // Important to use changeCursor bc, unlike swapCursor, it can be executed asynchronously adapter.changeCursor(newData); Timber.d("%s Scrolling to prior scroll position %d", getClass().getSimpleName(), lastScrollPos); mRecyclerView.scrollToPosition(lastScrollPos); } /** * Provide a {@link CursorRecyclerViewAdapter} to bind data to Recyclerview items. * This will be called during {@link #onActivityCreated(Bundle)}, so {@link #getActivity()} * is guaranteed to be non-null. */ protected abstract CursorRecyclerViewAdapter getAdapter(); protected abstract Subscription createSubscription(); /** * Subscribe to the data describing this fragment's view */ @Override public void subscribeToData() { if (subscription == null || subscription.isUnsubscribed()) { subscription = createSubscription(); } } /** * Unsubscribe from the data describing this fragment's view */ protected void unsubscribeFromData() { if (subscription != null && !subscription.isUnsubscribed()) subscription.unsubscribe(); } public void reSubscribeToData() { unsubscribeFromData(); subscribeToData(); } public String getEmptyText() { return getString(R.string.no_items_found); } public void setListShown(boolean doShow) { if (doShow) { mRecyclerView.setVisibility(View.VISIBLE); mEmptyText.setVisibility(View.GONE); } else { mRecyclerView.setVisibility(View.INVISIBLE); // Using GONE caused the recyclerview to improperly render after a transition to the empty state mEmptyText.setText(getEmptyText()); mEmptyText.setVisibility(View.VISIBLE); } } public void setListShownNoAnimation(boolean doShow) { setListShown(doShow); } @Override public void onItemSelected(int modelId, Constants.PlayaItemType type) { IntentUtil.viewItemDetail(getActivity(), modelId, type); } public void onItemFavoriteButtonSelected(int modelId, Constants.PlayaItemType type) { final String modelTable; switch (type) { case CAMP: modelTable = PlayaDatabase.CAMPS; break; case ART: modelTable = PlayaDatabase.ART; break; case EVENT: modelTable = PlayaDatabase.EVENTS; break; default: throw new IllegalArgumentException("Invalid type " + type); } DataProvider.getInstance(getActivity().getApplicationContext()) .subscribe(dataProvider -> { dataProvider.toggleFavorite(modelTable, modelId); }, throwable -> Timber.e(throwable, "Failed to update favorite")); } /** * @return the current scroll position, or 0 if no scrolling has occurred */ private int getScrollPosition() { if (mRecyclerView != null) { int scrollPos = 0; if (mRecyclerView.getLayoutManager() instanceof LayoutManager) { scrollPos = ((LayoutManager) mRecyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition(); } else if (mRecyclerView.getLayoutManager() instanceof LinearLayoutManager) { scrollPos = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition(); } Timber.d("%s onSaveInstanceState scrollPos %d", getClass().getSimpleName(), scrollPos); return scrollPos; } return 0; } }