package com.florianmski.tracktoid.ui.fragments.traktitems; import android.app.AlertDialog; import android.content.DialogInterface; import android.database.Cursor; import android.os.Bundle; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.OrientationHelper; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.widget.FrameLayout; import com.florianmski.tracktoid.utils.DateHelper; import com.florianmski.tracktoid.utils.DbHelper; import com.florianmski.tracktoid.R; import com.florianmski.tracktoid.TraktoidTheme; import com.florianmski.tracktoid.utils.Utils; import com.florianmski.tracktoid.adapters.RecyclerAdapter; import com.florianmski.tracktoid.adapters.lists.RecyclerTraktItemAdapter; import com.florianmski.tracktoid.data.WEpisode; import com.florianmski.tracktoid.data.WSeason; import com.florianmski.tracktoid.data.WShow; import com.florianmski.tracktoid.data.database.ProviderSchematic; import com.florianmski.tracktoid.data.database.columns.EpisodeColumns; import com.florianmski.tracktoid.data.database.columns.SeasonColumns; import com.florianmski.tracktoid.data.database.utils.CVUtils; import com.florianmski.tracktoid.image.ImagesTest; import com.florianmski.tracktoid.image.Type; import com.florianmski.tracktoid.rx.observables.CursorObservable; import com.florianmski.tracktoid.rx.observables.TraktFallbackTransformer; import com.florianmski.tracktoid.rx.observables.TraktObservable; import com.florianmski.tracktoid.trakt.TraktManager; import com.florianmski.tracktoid.trakt.TraktSender; import com.florianmski.tracktoid.ui.activities.CommentsActivity; import com.florianmski.tracktoid.ui.activities.EpisodeActivity; import com.florianmski.tracktoid.ui.activities.PagerSeasonActivity; import com.florianmski.tracktoid.ui.widgets.FlagsView; import com.florianmski.tracktoid.ui.widgets.Placeholder; import com.florianmski.tracktoid.ui.widgets.TraktActionView; import com.florianmski.tracktoid.ui.widgets.TraktImageView; import com.squareup.picasso.Picasso; import com.uwetrottmann.trakt.v2.entities.Airs; import com.uwetrottmann.trakt.v2.entities.Episode; import com.uwetrottmann.trakt.v2.entities.EpisodeCheckinResponse; import com.uwetrottmann.trakt.v2.entities.Season; import com.uwetrottmann.trakt.v2.entities.Show; import com.uwetrottmann.trakt.v2.enums.Extended; import com.uwetrottmann.trakt.v2.exceptions.OAuthUnauthorizedException; import org.joda.time.DateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; import rx.Observable; import rx.Observer; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; public class ShowFragment extends MediaBaseFragment<WShow, EpisodeCheckinResponse> { private FrameLayout flNextEpisode; private TraktImageView tivNextEpisode; private FlagsView fvNextEpisode; private RecyclerView rvSeasons; private final Observer<WEpisode> observerNextEpisode = new Observer<WEpisode>() { @Override public void onCompleted() {} @Override public void onError(Throwable throwable) { throwable.printStackTrace(); } @Override public void onNext(final WEpisode wEpisode) { if(wEpisode == null) flNextEpisode.setVisibility(View.GONE); else { flNextEpisode.setVisibility(View.VISIBLE); final Episode e = wEpisode.getTraktItem(); fvNextEpisode.init(new FlagsView.Flags.Builder(wEpisode.getTraktBase()) .title("Next episode") .subtitle(Utils.getSeasonEpisodeString(e.season, e.number)) .theme(getTheme()).build()); Picasso.with(getActivity()) .load(ImagesTest.getUrl(Type.SCREENSHOT, e.images)) .placeholder(new Placeholder(getActivity(), TraktoidTheme.SHOW).getDrawable()) .into(tivNextEpisode); flNextEpisode.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EpisodeActivity.launch(getActivity(), wEpisode); } }); } } }; private RecyclerAdapter.OnItemClickListener seasonsListener = new RecyclerAdapter.OnItemClickListener() { @Override public void onItemClick(View v, int position) { RecyclerTraktItemAdapter<WSeason> adapter = (RecyclerTraktItemAdapter<WSeason>)rvSeasons.getAdapter(); int length = adapter.getItemCount(); String seasonIds[] = new String[length]; int seasons[] = new int[length]; for(int i = 0; i < length; i++) { // I want the natural order so I reverse the reverse order (clear enough?) WSeason season = adapter.getItem2((length-1) - i); seasonIds[i] = String.valueOf(season.getIds().trakt); seasons[i] = season.getTraktItem().season.number; } PagerSeasonActivity.launch(getActivity(), getActionBar().getTitle(), id, seasonIds, seasons, (length-1) - position); } }; private final Observer<List<WSeason>> observerSeasons = new Observer<List<WSeason>>() { @Override public void onCompleted() {} @Override public void onError(Throwable throwable) {} @Override public void onNext(final List<WSeason> wSeasons) { if(wSeasons == null) rvSeasons.setVisibility(View.GONE); else { rvSeasons.setVisibility(View.VISIBLE); RecyclerTraktItemAdapter adapter = new RecyclerTraktItemAdapter<>(getActivity(), wSeasons, getTheme(), seasonsListener) .imageType(Type.POSTER) .titleVisible(true); rvSeasons.setAdapter(adapter); } } }; public ShowFragment() {} public static ShowFragment newInstance(String id) { ShowFragment f = new ShowFragment(); Bundle args = getBundle(id); f.setArguments(args); return f; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Subscription subscriptionNextEpisode = createNextEpisodeObservable() .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observerNextEpisode); subscriptions.add(subscriptionNextEpisode); Subscription subscriptionSeasons = createSeasonsObservable() .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observerSeasons); subscriptions.add(subscriptionSeasons); tavCollection.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { createDialog("collected", v); } }); tavSeen.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { createDialog("watched", v); } }); } private void createDialog(String action, final View v) { boolean marked = ((TraktActionView)v).isChecked(); String futurStatus = String.format("%smark", (marked ? "un" : "")); String message = String.format("Do you really want to %s as %s all the aired episodes of this show?", futurStatus, action); new AlertDialog.Builder(getActivity()) .setMessage(message) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { ((TraktActionView)v).toggle(); } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) {} }) .create() .show(); } @Override public TraktSender.Builder addItemToBuilder(TraktSender.Builder builder) { return builder.show(item.getTraktItem()); } @Override public Observable<WShow> getDownloadAndInsertItemObservable() { return Observable.create(new TraktObservable<WShow>() { @Override public WShow fire() throws OAuthUnauthorizedException { DbHelper.downloadAndInsertShowContent(getActivity(), item.getTraktItem()); return item; } }); } @Override public Observable<EpisodeCheckinResponse> getCheckinObservable() { throw new UnsupportedOperationException("not supported yet!"); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); flNextEpisode = (FrameLayout) view.findViewById(R.id.frameLayoutNextEpisode); tivNextEpisode = (TraktImageView) flNextEpisode.findViewById(R.id.traktImageViewNextEpisode); fvNextEpisode = (FlagsView) flNextEpisode.findViewById(R.id.flagsViewNextEpisode); rvSeasons = (RecyclerView) view.findViewById(R.id.recyclerViewSeasons); rvSeasons.setHasFixedSize(true); rvSeasons.setLayoutManager(new GridLayoutManager(getActivity(), 1, OrientationHelper.HORIZONTAL, false)); } private Observable<WEpisode> createNextEpisodeObservable() { return Observable.create(new CursorObservable<WEpisode>( getActivity(), ProviderSchematic.Episodes.fromShow(id), null, EpisodeColumns.WATCHED + "=?" + " AND " + EpisodeColumns.SEASON + "!=?", new String[]{String.valueOf(0), String.valueOf(0)}, EpisodeColumns.SEASON + ", " + EpisodeColumns.NUMBER + " LIMIT 1") { @Override protected WEpisode toObject(Cursor cursor) { return WEpisode.unpack(cursor); } }); } private Observable<List<WSeason>> createSeasonsObservable() { return Observable.create(new CursorObservable<List<WSeason>>( getActivity(), ProviderSchematic.Seasons.fromShow(id), ProviderSchematic.Seasons.PROJECTION, null, null, SeasonColumns.NUMBER + " DESC") { @Override protected List<WSeason> toObject(Cursor cursor) { return WSeason.unpackList(cursor); } }).compose(new TraktFallbackTransformer<>(new TraktObservable<List<WSeason>>() { @Override public List<WSeason> fire() throws OAuthUnauthorizedException { List<Season> seasons = TraktManager.getInstance().seasons().summary(id, Extended.FULLIMAGES); List<WSeason> wSeasons = new ArrayList<>(); for(Season season : seasons) wSeasons.add(new WSeason(new CVUtils.SeasonCV.SeasonEntity(season))); Collections.reverse(wSeasons); return wSeasons; } })); } @Override public void refreshView(WShow item) { this.item = item; tlInfos.removeAllViews(); DateTime firstAired = item.getTraktItem().first_aired; if(firstAired != null) addInfo("Premiered", DateHelper.getDate(getActivity(), firstAired)); String country = item.getTraktItem().country; if(country != null) addInfo("Country", country.toUpperCase()); Integer runtime = item.getTraktItem().runtime; if(runtime != null) addInfo("Runtime", DateHelper.getRuntime(runtime)); Double rating = item.getTraktItem().rating; if(rating != null && item.getTraktItem().votes > 0) addInfo("Ratings", String.format("%.01f/10", rating)); refreshGeneralView(item.getTraktBase()); setTitle(item.getTraktItem().title); setSubtitle(String.valueOf(item.getTraktItem().year)); } @Override public String getDateText(boolean invalidTime) { Airs airs = item.getTraktItem().airs; String unknownAirTime = "Unknown air time"; if(invalidTime || airs == null) return unknownAirTime; else { StringBuilder builder = new StringBuilder(); if(airs.day != null) builder.append(airs.day).append(" "); if(airs.time != null) builder.append("at ").append(airs.time).append(" "); if(item.getTraktItem().network != null) builder.append("on ").append(item.getTraktItem().network); String res = builder.toString(); if(TextUtils.isEmpty(res)) return unknownAirTime; // capitalize first letter return res.substring(0, 1).toUpperCase() + res.substring(1); } } @Override public WShow getTraktObject() { Show show = TraktManager.getInstance().shows().summary(id, Extended.FULLIMAGES); return new WShow(show); } @Override public CursorObservable<WShow> getCursorObservable() { return new CursorObservable<WShow>( getActivity(), ProviderSchematic.Shows.withId(id), ProviderSchematic.Shows.PROJECTION, null, null, null) { @Override protected WShow toObject(Cursor cursor) { return WShow.unpack(cursor); } }; } @Override public void launchCommentActivity() { CommentsActivity.launchShow(getActivity(), id); } @Override public void onDestroy() { super.onDestroy(); } @Override public TraktoidTheme getTheme() { return TraktoidTheme.SHOW; } }