/* * 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.lists; import android.app.Activity; import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v7.widget.Toolbar; import android.view.MenuItem; import javax.inject.Inject; import net.simonvt.cathode.CathodeApp; import net.simonvt.cathode.R; import net.simonvt.cathode.api.enumeration.Privacy; 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.DatabaseContract.EpisodeColumns; import net.simonvt.cathode.provider.DatabaseContract.LastModifiedColumns; import net.simonvt.cathode.provider.DatabaseContract.ListItemColumns; import net.simonvt.cathode.provider.DatabaseContract.ListsColumns; import net.simonvt.cathode.provider.DatabaseContract.MovieColumns; import net.simonvt.cathode.provider.DatabaseContract.PersonColumns; import net.simonvt.cathode.provider.DatabaseContract.SeasonColumns; import net.simonvt.cathode.provider.DatabaseContract.ShowColumns; import net.simonvt.cathode.provider.DatabaseSchematic.Tables; import net.simonvt.cathode.provider.ListWrapper; import net.simonvt.cathode.provider.ProviderSchematic; import net.simonvt.cathode.remote.sync.lists.SyncList; import net.simonvt.cathode.scheduler.ListsTaskScheduler; import net.simonvt.cathode.ui.LibraryType; import net.simonvt.cathode.ui.NavigationListener; import net.simonvt.cathode.ui.fragment.ToolbarSwipeRefreshRecyclerFragment; import net.simonvt.cathode.util.SqlCoalesce; import net.simonvt.cathode.util.SqlColumn; import net.simonvt.schematic.Cursors; public class ListFragment extends ToolbarSwipeRefreshRecyclerFragment<ListAdapter.ListViewHolder> implements ListAdapter.ListListener { public static final String TAG = "net.simonvt.cathode.ui.lists.ListFragment"; private static final String ARG_LIST_ID = "net.simonvt.cathode.ui.lists.ListFragment.lidtId"; private static final String ARG_LIST_NAME = "net.simonvt.cathode.ui.lists.ListFragment.listName"; static final String DIALOG_UPDATE = "net.simonvt.cathode.ui.lists.ListFragment.updateListsDialog"; static final String DIALOG_DELETE = "net.simonvt.cathode.ui.lists.ListFragment.deleteListsDialog"; private static final int LOADER_LIST_INFO = 1; private static final int LOADER_LIST_ITEMS = 2; @Inject ListsTaskScheduler listScheduler; @Inject JobManager jobManager; private NavigationListener navigationListener; private long listId; private ListAdapter adapter; private int columnCount; private Cursor listInfo; public static Bundle getArgs(long listId, String listName) { Bundle args = new Bundle(); args.putLong(ARG_LIST_ID, listId); args.putString(ARG_LIST_NAME, listName); return args; } @Override public void onAttach(Activity activity) { super.onAttach(activity); navigationListener = (NavigationListener) activity; } @Override public void onCreate(Bundle inState) { super.onCreate(inState); CathodeApp.inject(getActivity(), this); Bundle args = getArguments(); listId = args.getLong(ARG_LIST_ID); String listName = args.getString(ARG_LIST_NAME); setTitle(listName); columnCount = getResources().getInteger(R.integer.listColumns); getLoaderManager().initLoader(LOADER_LIST_ITEMS, null, itemsLoader); getLoaderManager().initLoader(LOADER_LIST_INFO, null, infoLoader); } @Override protected int getColumnCount() { return columnCount; } public long getListId() { return listId; } private Job.OnDoneListener onDoneListener = new Job.OnDoneListener() { @Override public void onDone(Job job) { setRefreshing(false); } }; @Override public void onRefresh() { new Thread(new Runnable() { @Override public void run() { final long traktId = ListWrapper.getTraktId(getActivity().getContentResolver(), listId); Job job = new SyncList(traktId); job.registerOnDoneListener(onDoneListener); jobManager.addJob(job); } }).start(); } @Override public void createMenu(Toolbar toolbar) { toolbar.inflateMenu(R.menu.fragment_list); } @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.menu_list_edit: if (listInfo != null && listInfo.moveToFirst()) { final String name = Cursors.getString(listInfo, ListsColumns.NAME); final String description = Cursors.getString(listInfo, ListsColumns.DESCRIPTION); final Privacy privacy = Privacy.fromValue(Cursors.getString(listInfo, ListsColumns.PRIVACY)); final boolean displayNumbers = Cursors.getBoolean(listInfo, ListsColumns.DISPLAY_NUMBERS); final boolean allowComments = Cursors.getBoolean(listInfo, ListsColumns.ALLOW_COMMENTS); UpdateListFragment updateFragment = new UpdateListFragment(); updateFragment.setArguments( UpdateListFragment.getArgs(listId, name, description, privacy, displayNumbers, allowComments)); updateFragment.show(getFragmentManager(), DIALOG_UPDATE); } return true; case R.id.menu_list_delete: DeleteListDialog.newInstance(listId).show(getFragmentManager(), DIALOG_DELETE); return true; } return super.onMenuItemClick(item); } @Override public void onShowClick(long showId, String title, String overview) { navigationListener.onDisplayShow(showId, title, overview, LibraryType.WATCHED); } @Override public void onSeasonClick(long showId, long seasonId, String showTitle, int seasonNumber) { navigationListener.onDisplaySeason(showId, seasonId, showTitle, seasonNumber, LibraryType.WATCHED); } @Override public void onEpisodeClick(long id) { navigationListener.onDisplayEpisode(id, null); } @Override public void onMovieClicked(long movieId, String title, String overview) { navigationListener.onDisplayMovie(movieId, title, overview); } @Override public void onPersonClick(long personId) { navigationListener.onDisplayPerson(personId); } @Override public void onRemoveItem(int position, long id) { Loader loader = getLoaderManager().getLoader(LOADER_LIST_ITEMS); if (loader != null) { ((SimpleCursorLoader) loader).throttle(SimpleCursorLoader.DEFAULT_THROTTLE); } final SimpleCursor cursor = (SimpleCursor) adapter.getCursor(position); final long itemId = Cursors.getLong(cursor, ListItemColumns.ITEM_ID); final int itemType = Cursors.getInt(cursor, ListItemColumns.ITEM_TYPE); listScheduler.removeItem(listId, itemType, itemId); cursor.remove(id); adapter.notifyChanged(); } private void setCursor(SimpleCursor cursor) { if (adapter == null) { adapter = new ListAdapter(getActivity(), this); setAdapter(adapter); } adapter.changeCursor(cursor); } private LoaderManager.LoaderCallbacks<SimpleCursor> infoLoader = new LoaderManager.LoaderCallbacks<SimpleCursor>() { @Override public Loader<SimpleCursor> onCreateLoader(int id, Bundle args) { return new SimpleCursorLoader(getContext(), ProviderSchematic.Lists.withId(listId), new String[] { ListsColumns.ID, ListsColumns.NAME, ListsColumns.DESCRIPTION, ListsColumns.PRIVACY, ListsColumns.DISPLAY_NUMBERS, ListsColumns.ALLOW_COMMENTS, }, null, null, null); } @Override public void onLoadFinished(Loader<SimpleCursor> loader, SimpleCursor data) { listInfo = data; if (listInfo.moveToFirst()) { final String name = Cursors.getString(listInfo, ListsColumns.NAME); setTitle(name); } } @Override public void onLoaderReset(Loader<SimpleCursor> loader) { } }; private static final String[] PROJECTION = { SqlColumn.table(Tables.LIST_ITEMS).column(ListItemColumns.ID), ListItemColumns.ITEM_TYPE, ListItemColumns.ITEM_ID, SqlCoalesce.coaloesce(SqlColumn.table(Tables.SHOWS).column(ShowColumns.OVERVIEW), SqlColumn.table(Tables.MOVIES).column(MovieColumns.OVERVIEW)).as( ListItemColumns.OVERVIEW), SqlColumn.table(Tables.SHOWS).column(ShowColumns.TITLE), SqlColumn.table(Tables.SHOWS).column(ShowColumns.WATCHED_COUNT), SqlColumn.table(Tables.SHOWS).column(ShowColumns.IN_COLLECTION_COUNT), SqlColumn.table(Tables.SHOWS).column(ShowColumns.IN_WATCHLIST), SqlColumn.table(Tables.SHOWS).column(ShowColumns.RATING), SqlColumn.table(Tables.SHOWS).column(LastModifiedColumns.LAST_MODIFIED), SqlColumn.table(Tables.SEASONS).column(SeasonColumns.SEASON), SqlColumn.table(Tables.SEASONS).column(SeasonColumns.SHOW_ID), SqlColumn.table(Tables.SEASONS).column(LastModifiedColumns.LAST_MODIFIED), "(SELECT " + ShowColumns.TITLE + " FROM " + Tables.SHOWS + " WHERE " + Tables.SHOWS + "." + ShowColumns.ID + "=" + Tables.SEASONS + "." + SeasonColumns.SHOW_ID + ") AS seasonShowTitle", "(SELECT " + ShowColumns.POSTER + " FROM " + Tables.SHOWS + " WHERE " + Tables.SHOWS + "." + ShowColumns.ID + "=" + Tables.SEASONS + "." + SeasonColumns.SHOW_ID + ") AS seasonShowPoster", SqlColumn.table(Tables.EPISODES).column(EpisodeColumns.TITLE), SqlColumn.table(Tables.EPISODES).column(EpisodeColumns.SEASON), SqlColumn.table(Tables.EPISODES).column(EpisodeColumns.EPISODE), SqlColumn.table(Tables.EPISODES).column(EpisodeColumns.WATCHED), SqlColumn.table(Tables.EPISODES).column(EpisodeColumns.FIRST_AIRED), SqlColumn.table(Tables.EPISODES).column(LastModifiedColumns.LAST_MODIFIED), "(SELECT " + ShowColumns.TITLE + " FROM " + Tables.SHOWS + " WHERE " + Tables.SHOWS + "." + ShowColumns.ID + "=" + Tables.EPISODES + "." + EpisodeColumns.SHOW_ID + ") AS episodeShowTitle", SqlColumn.table(Tables.MOVIES).column(MovieColumns.TITLE), SqlColumn.table(Tables.MOVIES).column(MovieColumns.WATCHED), SqlColumn.table(Tables.MOVIES).column(MovieColumns.IN_COLLECTION), SqlColumn.table(Tables.MOVIES).column(MovieColumns.IN_WATCHLIST), SqlColumn.table(Tables.MOVIES).column(MovieColumns.WATCHING), SqlColumn.table(Tables.MOVIES).column(MovieColumns.CHECKED_IN), SqlColumn.table(Tables.MOVIES).column(LastModifiedColumns.LAST_MODIFIED), SqlColumn.table(Tables.PEOPLE).column(PersonColumns.NAME), SqlColumn.table(Tables.PEOPLE).column(LastModifiedColumns.LAST_MODIFIED), }; LoaderManager.LoaderCallbacks<SimpleCursor> itemsLoader = new LoaderManager.LoaderCallbacks<SimpleCursor>() { @Override public Loader<SimpleCursor> onCreateLoader(int id, Bundle args) { return new SimpleCursorLoader(getActivity(), ProviderSchematic.ListItems.inList(listId), PROJECTION, null, null, null); } @Override public void onLoadFinished(Loader loader, SimpleCursor data) { setCursor(data); } @Override public void onLoaderReset(Loader loader) { } }; }