/* * Copyright (C) 2014 The Android Open Source Project * * 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 com.androideasyapps.phoenix; import android.content.Intent; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.support.v17.leanback.app.BackgroundManager; import android.support.v17.leanback.app.BrowseFragment; import android.support.v17.leanback.widget.ArrayObjectAdapter; import android.support.v17.leanback.widget.HeaderItem; import android.support.v17.leanback.widget.ImageCardView; import android.support.v17.leanback.widget.ListRow; import android.support.v17.leanback.widget.ListRowPresenter; import android.support.v17.leanback.widget.OnItemViewClickedListener; import android.support.v17.leanback.widget.OnItemViewSelectedListener; import android.support.v17.leanback.widget.Presenter; import android.support.v17.leanback.widget.Row; import android.support.v17.leanback.widget.RowPresenter; import android.support.v4.app.ActivityOptionsCompat; import android.util.DisplayMetrics; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import com.androideasyapps.phoenix.dao.H2PersistenceManager; import com.androideasyapps.phoenix.dao.MediaFile; import com.androideasyapps.phoenix.dao.TVSeriesGroupMediaFileDAO; import com.androideasyapps.phoenix.recommend.UpdateRecommendationsService; import com.androideasyapps.phoenix.services.phoenix.ViewItemMediaFileAdapter; import com.androideasyapps.phoenix.services.phoenix.model.ViewItem; import com.androideasyapps.phoenix.services.phoenix.model.ViewReply; import com.androideasyapps.phoenix.settings.SettingsActivity; import com.androideasyapps.phoenix.shared.AppInstance; import com.androideasyapps.phoenix.shared.MediaSource; import com.androideasyapps.phoenix.shared.MediaSyncEvent; import com.androideasyapps.phoenix.shared.SageTVSyncService; import com.androideasyapps.phoenix.util.MediaUtil; import com.squareup.otto.Subscribe; import com.squareup.picasso.Picasso; import com.squareup.picasso.Target; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; import java.util.Collection; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import rx.Observable; import rx.Subscriber; import rx.android.observables.AndroidObservable; import rx.functions.Action0; import rx.functions.Action1; public class MainFragment extends BrowseFragment { private static final Logger log = LoggerFactory.getLogger(MainFragment.class); private static final String TAG = "MainFragment"; private static final int BACKGROUND_UPDATE_DELAY = 300; private ArrayObjectAdapter mRowsAdapter; private Drawable mDefaultBackground; private Target mBackgroundTarget; private DisplayMetrics mMetrics; private Timer mBackgroundTimer; private final Handler mHandler = new Handler(); private URI mBackgroundURI; CardPresenter mCardPresenter; @Override public void onActivityCreated(Bundle savedInstanceState) { Log.i(TAG, "onCreate"); super.onActivityCreated(savedInstanceState); prepareBackgroundManager(); setupUIElements(); loadRows(); setupEventListeners(); } @Override public void onDestroy() { super.onDestroy(); if (null != mBackgroundTimer) { Log.d(TAG, "onDestroy: " + mBackgroundTimer.toString()); mBackgroundTimer.cancel(); } AppInstance.getInstance(getActivity()).bus().unregister(this); } private void loadRows() { mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter()); mCardPresenter = new CardPresenter(); int i=0; mRowsAdapter.clear(); for (MediaSource source: AppInstance.getInstance(getActivity()).getMediaSources().values()) { // build recently added movies, unwatched ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(mCardPresenter); HeaderItem header = new HeaderItem(i++, source.title, null); mRowsAdapter.add(new ListRow(header, listRowAdapter)); populateSource(listRowAdapter, source); } // build Scheduled Recordings... ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(mCardPresenter); HeaderItem header = new HeaderItem(i++, "Scheduled Recordings", null); mRowsAdapter.add(new ListRow(header, listRowAdapter)); populateScheduledRecordings(listRowAdapter); // TV Gaps // ArrayObjectAdapter gapsRowAdapter = new ArrayObjectAdapter(mCardPresenter); // HeaderItem gapsHeader = new HeaderItem(i++, "TV Gaps", null); // mRowsAdapter.add(new ListRow(gapsHeader, gapsRowAdapter)); // populateTVGaps(gapsRowAdapter); // build Prefs HeaderItem gridHeader = new HeaderItem(i, "PREFERENCES", null); SettingsPresenter mGridPresenter = new SettingsPresenter(); ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter); gridRowAdapter.add(getResources().getString(R.string.refresh)); gridRowAdapter.add(getResources().getString(R.string.start_recommendations)); // gridRowAdapter.add(getString(R.string.error_fragment)); gridRowAdapter.add(getResources().getString(R.string.personal_settings)); mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter)); setAdapter(mRowsAdapter); } private void populateTVGaps(final ArrayObjectAdapter gapsRowAdapter) { TVGapsUtil.getTVGapFilesObserable(AppInstance.getInstance(getActivity()).getDAOManager()).subscribe(new Action1<Collection<MediaFile>>() { @Override public void call(Collection<MediaFile> mediaFiles) { if (mediaFiles!=null && mediaFiles.size()>0) { gapsRowAdapter.addAll(0, mediaFiles); } } }); } private void populateSource(ArrayObjectAdapter listRowAdapter, MediaSource source) { if (source.subGroupMediaSource==null) { populateListRowAdapter(listRowAdapter, source.query); } else { populateListRowAdapterForGroup(listRowAdapter, source); } } private void populateScheduledRecordings(final ArrayObjectAdapter listRowAdapter) { AppInstance.getInstance(getActivity()).getPhoenixService().getScheduledRecordings().subscribe(new Action1<ViewReply>() { @Override public void call(ViewReply viewReply) { if (viewReply.reply!=null && viewReply.reply.children!=null) { for (ViewItem vi: viewReply.reply.children) { listRowAdapter.add(new ViewItemMediaFileAdapter(vi)); } } else { log.warn("No Items for getScheduledRecordings()"); } } }); } private void populateListRowAdapterForGroup(final ArrayObjectAdapter listRowAdapter, final MediaSource source) { getMediaItemsUsingGroupedQuery(AppInstance.getInstance(this.getActivity()).getDAOManager(), source.query).subscribe(new Action1<Collection<MediaFile>>() { @Override public void call(Collection<MediaFile> mediaFiles) { if (mediaFiles != null) { for (MediaFile mf : mediaFiles) { listRowAdapter.add(mf); mf.setUserdata(source.title); } } } }); } private void populateListRowAdapter(final ArrayObjectAdapter listRowAdapter, final String query) { AppInstance.getInstance(getActivity()).getMediaItems(AppInstance.getInstance(this.getActivity()).getDAOManager(), query).subscribe(new Action1<Collection<MediaFile>>() { @Override public void call(Collection<MediaFile> mediaFiles) { if (mediaFiles != null && mediaFiles.size() > 0) { for (MediaFile mf : mediaFiles) { listRowAdapter.add(mf); } } else { log.warn("No Media FOR: " + query); } } }); } Observable<Collection<MediaFile>> getMediaItemsUsingGroupedQuery(final Future<H2PersistenceManager> dao, final String query) { return Observable.create(new Observable.OnSubscribe<Collection<MediaFile>>() { @Override public void call(Subscriber<? super Collection<MediaFile>> subscriber) { subscriber.onStart(); try { TVSeriesGroupMediaFileDAO tvDAO = new TVSeriesGroupMediaFileDAO(dao.get()); subscriber.onNext(tvDAO.rawQuery(query)); } catch (Exception e) { subscriber.onError(e); } subscriber.onCompleted(); } }); } private void prepareBackgroundManager() { BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity()); backgroundManager.attach(getActivity().getWindow()); mBackgroundTarget = new PicassoBackgroundManagerTarget(backgroundManager); mDefaultBackground = getResources().getDrawable(R.drawable.default_background); mMetrics = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics); } private void setupUIElements() { // setBadgeDrawable(getActivity().getResources().getDrawable( // R.drawable.videos_by_google_banner)); setTitle(getString(R.string.browse_title)); // Badge, when set, takes precedent // over title setHeadersState(HEADERS_ENABLED); setHeadersTransitionOnBackEnabled(true); // set fastLane (or headers) background color setBrandColor(getResources().getColor(R.color.fastlane_background)); // set search icon color setSearchAffordanceColor(getResources().getColor(R.color.search_opaque)); } private void setupEventListeners() { setOnSearchClickedListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(getActivity(), SageTVSearchActivity.class); startActivity(intent); } }); setOnItemViewClickedListener(new ItemViewClickedListener()); setOnItemViewSelectedListener(new ItemViewSelectedListener()); AppInstance.getInstance(getActivity()).bus().register(this); } @Subscribe public void onMediaSync(MediaSyncEvent event) { log.info("Subscribing to Media Sync items"); final AtomicInteger counter = new AtomicInteger(); AndroidObservable.bindFragment(this, event.getObservable()).subscribe(new Action1<MediaFile>() { @Override public void call(MediaFile mediaFile) { } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { log.error("Error During Sync", throwable); } }, new Action0() { @Override public void call() { log.info("Reloading Rows"); loadRows(); Toast.makeText(getActivity(), R.string.msg_syncing_mediafiles_complete, Toast.LENGTH_LONG).show(); } }); } private final class ItemViewClickedListener implements OnItemViewClickedListener { @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { if (item instanceof MediaFile) { MediaFile movie = (MediaFile) item; Log.d(TAG, "Item: " + item.toString()); Intent intent = new Intent(getActivity(), DetailsActivity.class); //intent.putExtra(DetailsActivity.MOVIE, movie); AppInstance.getInstance(MainFragment.this.getActivity()).setSelectedMediaFile(movie); Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation( getActivity(), ((ImageCardView) itemViewHolder.view).getMainImageView(), DetailsActivity.SHARED_ELEMENT_NAME).toBundle(); getActivity().startActivity(intent, bundle); } else if (item instanceof String) { if (((String) item).contains(getString(R.string.refresh))) { Toast.makeText(getActivity(), R.string.msg_syncing_mediafiles, Toast.LENGTH_LONG).show(); SageTVSyncService.startSageTVSync(getActivity(), null); } else if (((String) item).contains(getString(R.string.start_recommendations))) { Intent intent = new Intent(getActivity(), UpdateRecommendationsService.class); getActivity().startService(intent); Toast.makeText(getActivity(), "Recommendations will soon show on the Home screen", Toast.LENGTH_SHORT).show(); } else if (((String) item).contains(getString(R.string.error_fragment))) { Intent intent = new Intent(getActivity(), BrowseErrorActivity.class); startActivity(intent); } else if (((String) item).contains(getString(R.string.personal_settings))) { Intent i = new Intent(getActivity(), SettingsActivity.class); startActivity(i); } else { Toast.makeText(getActivity(), ((String) item), Toast.LENGTH_SHORT) .show(); } } } } private final class ItemViewSelectedListener implements OnItemViewSelectedListener { @Override public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { if (item instanceof MediaFile) { mBackgroundURI = URI.create(MediaUtil.getBackgroundURL(AppInstance.getInstance(MainFragment.this.getActivity()).getServer(), (MediaFile) item, MediaUtil.DEFAULT_BACKGROUND_WIDTH)); startBackgroundTimer(); } } } protected void setDefaultBackground(Drawable background) { mDefaultBackground = background; } protected void setDefaultBackground(int resourceId) { mDefaultBackground = getResources().getDrawable(resourceId); } protected void updateBackground(URI uri) { Picasso.with(getActivity()) .load(uri.toString()) .resize(mMetrics.widthPixels, mMetrics.heightPixels) .centerCrop() .error(mDefaultBackground) .into(mBackgroundTarget); } protected void updateBackground(Drawable drawable) { BackgroundManager.getInstance(getActivity()).setDrawable(drawable); } protected void clearBackground() { BackgroundManager.getInstance(getActivity()).setDrawable(mDefaultBackground); } private void startBackgroundTimer() { if (null != mBackgroundTimer) { mBackgroundTimer.cancel(); } mBackgroundTimer = new Timer(); mBackgroundTimer.schedule(new UpdateBackgroundTask(), BACKGROUND_UPDATE_DELAY); } private class UpdateBackgroundTask extends TimerTask { @Override public void run() { mHandler.post(new Runnable() { @Override public void run() { if (mBackgroundURI != null) { updateBackground(mBackgroundURI); } } }); } } private class SettingsPresenter extends Presenter { private static final int GRID_ITEM_WIDTH = 300; private static final int GRID_ITEM_HEIGHT = 300; @Override public ViewHolder onCreateViewHolder(ViewGroup parent) { TextView view = new TextView(parent.getContext()); view.setLayoutParams(new ViewGroup.LayoutParams(GRID_ITEM_WIDTH, GRID_ITEM_HEIGHT)); view.setFocusable(true); view.setFocusableInTouchMode(true); view.setBackgroundColor(getResources().getColor(R.color.default_background)); view.setTextColor(Color.WHITE); view.setGravity(Gravity.CENTER); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder viewHolder, Object item) { ((TextView) viewHolder.view).setText((String) item); } @Override public void onUnbindViewHolder(ViewHolder viewHolder) { } } }