/* * Copyright (C) 2016 Simon Vig Therkildsen * * 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 net.simonvt.cathode.ui.shows.upcoming; import android.app.Activity; import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.MenuItem; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import net.simonvt.cathode.CathodeApp; import net.simonvt.cathode.R; import net.simonvt.cathode.database.SimpleCursor; import net.simonvt.cathode.database.SimpleCursorLoader; import net.simonvt.cathode.jobqueue.Job; import net.simonvt.cathode.jobqueue.JobManager; import net.simonvt.cathode.provider.ProviderSchematic.Shows; import net.simonvt.cathode.remote.sync.SyncWatching; import net.simonvt.cathode.remote.sync.shows.SyncWatchedShows; import net.simonvt.cathode.settings.UpcomingTime; import net.simonvt.cathode.settings.UpcomingTimePreference; import net.simonvt.cathode.ui.ShowsNavigationListener; import net.simonvt.cathode.ui.adapter.HeaderSpanLookup; import net.simonvt.cathode.ui.fragment.ToolbarSwipeRefreshRecyclerFragment; import net.simonvt.cathode.ui.lists.ListDialog; import net.simonvt.cathode.ui.shows.upcoming.UpcomingSortByPreference.UpcomingSortByListener; import net.simonvt.cathode.util.DataHelper; public class UpcomingShowsFragment extends ToolbarSwipeRefreshRecyclerFragment<RecyclerView.ViewHolder> implements UpcomingAdapter.OnRemoveListener, ListDialog.Callback, LoaderCallbacks<SimpleCursor>, UpcomingAdapter.OnItemClickListener { public static final String TAG = "net.simonvt.cathode.ui.shows.upcoming.UpcomingShowsFragment"; private static final int LOADER_SHOWS_UPCOMING = 1; private static final String DIALOG_SORT = "net.simonvt.cathode.ui.shows.upcoming.UpcomingShowsFragment.sortDialog"; @Inject JobManager jobManager; @Inject UpcomingTimePreference upcomingTimePreference; @Inject UpcomingSortByPreference upcomingSortByPreference; UpcomingSortBy sortBy; private ShowsNavigationListener navigationListener; private int columnCount; private UpcomingAdapter adapter; boolean scrollToTop; @Override public void onAttach(Activity activity) { super.onAttach(activity); navigationListener = (ShowsNavigationListener) activity; } @Override public void onCreate(Bundle inState) { super.onCreate(inState); CathodeApp.inject(getActivity(), this); sortBy = upcomingSortByPreference.get(); upcomingSortByPreference.registerListener(upcomingSortByListener); setTitle(R.string.title_shows_upcoming); setEmptyText(R.string.empty_show_upcoming); columnCount = getResources().getInteger(R.integer.showsColumns); upcomingTimePreference.registerListener(upcomingTimeChangeListener); getLoaderManager().initLoader(LOADER_SHOWS_UPCOMING, null, this); } private UpcomingSortByListener upcomingSortByListener = new UpcomingSortByListener() { @Override public void onUpcomingSortByChanged(UpcomingSortBy sortBy) { UpcomingShowsFragment.this.sortBy = sortBy; scrollToTop = true; getLoaderManager().restartLoader(LOADER_SHOWS_UPCOMING, null, UpcomingShowsFragment.this); } }; @Override public void onDestroy() { upcomingTimePreference.unregisterListener(upcomingTimeChangeListener); upcomingSortByPreference.unregisterListener(upcomingSortByListener); super.onDestroy(); } @Override protected int getColumnCount() { return columnCount; } @Override protected GridLayoutManager.SpanSizeLookup getSpanSizeLookup() { return new HeaderSpanLookup(ensureAdapter(), columnCount); } private UpcomingTimePreference.UpcomingTimeChangeListener upcomingTimeChangeListener = new UpcomingTimePreference.UpcomingTimeChangeListener() { @Override public void onUpcomingTimeChanged(UpcomingTime message) { getLoaderManager().restartLoader(LOADER_SHOWS_UPCOMING, null, UpcomingShowsFragment.this); } }; @Override public boolean displaysMenuIcon() { return amITopLevel(); } @Override public void createMenu(Toolbar toolbar) { super.createMenu(toolbar); toolbar.inflateMenu(R.menu.fragment_shows_upcoming); } @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.sort_by: ArrayList<ListDialog.Item> items = new ArrayList<>(); items.add(new ListDialog.Item(R.id.sort_title, R.string.sort_title)); items.add(new ListDialog.Item(R.id.sort_next_episode, R.string.sort_next_episode)); items.add(new ListDialog.Item(R.id.sort_last_watched, R.string.sort_last_watched)); ListDialog.newInstance(R.string.action_sort_by, items, UpcomingShowsFragment.this) .show(getFragmentManager(), DIALOG_SORT); return true; case R.id.menu_search: navigationListener.onSearchClicked(); return true; default: return super.onMenuItemClick(item); } } @Override public void onEpisodeClicked(long episodeId, String showTitle) { navigationListener.onDisplayEpisode(episodeId, showTitle); } @Override public void onItemSelected(int id) { switch (id) { case R.id.sort_title: if (sortBy != UpcomingSortBy.TITLE) { upcomingSortByPreference.set(UpcomingSortBy.TITLE); } break; case R.id.sort_next_episode: if (sortBy != UpcomingSortBy.NEXT_EPISODE) { upcomingSortByPreference.set(UpcomingSortBy.NEXT_EPISODE); } break; case R.id.sort_last_watched: if (sortBy != UpcomingSortBy.LAST_WATCHED) { upcomingSortByPreference.set(UpcomingSortBy.LAST_WATCHED); } break; } } @Override public void onRemove(long showId) { Loader loader = getLoaderManager().getLoader(LOADER_SHOWS_UPCOMING); if (loader != null) { SimpleCursorLoader cursorLoader = (SimpleCursorLoader) loader; cursorLoader.throttle(SimpleCursorLoader.DEFAULT_THROTTLE); List<Cursor> cursors = ((UpcomingAdapter) getAdapter()).getCursors(); for (Cursor cursor : cursors) { ((SimpleCursor) cursor).remove(showId); } ((UpcomingAdapter) getAdapter()).notifyChanged(); } } private Job.OnDoneListener onDoneListener = new Job.OnDoneListener() { @Override public void onDone(Job job) { setRefreshing(false); } }; @Override public void onRefresh() { jobManager.addJob(new SyncWatching()); Job job = new SyncWatchedShows(); job.registerOnDoneListener(onDoneListener); jobManager.addJob(job); } private UpcomingAdapter ensureAdapter() { if (adapter == null) { adapter = new UpcomingAdapter(getActivity(), this, this); adapter.addHeader(R.string.header_aired); adapter.addHeader(R.string.header_upcoming); } return adapter; } protected void setCursor(SimpleCursor cursor) { UpcomingAdapter adapter = (UpcomingAdapter) getAdapter(); if (adapter == null) { adapter = ensureAdapter(); setAdapter(adapter); } final long currentTime = System.currentTimeMillis(); SimpleCursor airedCursor = new SimpleCursor(cursor.getColumnNames()); SimpleCursor unairedCursor = new SimpleCursor(cursor.getColumnNames()); cursor.moveToPosition(-1); while (cursor.moveToNext()) { Object[] data = cursor.get(); final long firstAired = DataHelper.getFirstAired(cursor); if (firstAired <= currentTime) { airedCursor.add(data); } else { unairedCursor.add(data); } } adapter.updateCursorForHeader(R.string.header_aired, airedCursor); adapter.updateCursorForHeader(R.string.header_upcoming, unairedCursor); if (scrollToTop) { getRecyclerView().scrollToPosition(0); scrollToTop = false; } } @Override public Loader<SimpleCursor> onCreateLoader(int id, Bundle args) { return new SimpleCursorLoader(getActivity(), Shows.SHOWS_UPCOMING, UpcomingAdapter.PROJECTION, null, null, sortBy.getSortOrder()); } @Override public void onLoadFinished(Loader<SimpleCursor> loader, SimpleCursor data) { setCursor(data); } @Override public void onLoaderReset(Loader<SimpleCursor> loader) { } }