package io.github.xwz.base.fragments; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Point; import android.os.Bundle; import android.support.v17.leanback.widget.ArrayObjectAdapter; import android.support.v17.leanback.widget.HeaderItem; 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.v17.leanback.widget.VerticalGridView; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import java.util.ArrayList; import java.util.List; import java.util.Map; import io.github.xwz.base.R; import io.github.xwz.base.Utils; import io.github.xwz.base.adapters.CardSelector; import io.github.xwz.base.api.EpisodeBaseModel; import io.github.xwz.base.api.PlayHistory; import io.github.xwz.base.content.ContentManagerBase; import io.github.xwz.base.views.EpisodeDetailsView; public abstract class DetailsFragment extends android.support.v17.leanback.app.RowsFragment { private static final String TAG = "DetailsFragment"; private EpisodeDetailsView mDetailView; private int mHeaderHeight; private EpisodeBaseModel mCurrentEpisode; private EpisodeBaseModel mLoadedEpisode; private ArrayObjectAdapter otherEpisodes; private boolean loadedOtherEpisodes = false; private List<String> mOtherEpisodeUrls = new ArrayList<>(); private final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.d(TAG, "Action: " + action + ", tag: " + intent.getStringExtra(ContentManagerBase.CONTENT_TAG)); if (ContentManagerBase.CONTENT_EPISODE_DONE.equals(action)) { updateEpisodeData(intent); } if (ContentManagerBase.CONTENT_EPISODE_ERROR.equals(action)) { Utils.showToast(getActivity(), "Unable to find episode details."); } } }; protected List<String> getOtherEpisodeUrls() { return mOtherEpisodeUrls; } protected abstract ContentManagerBase getContentManger(); protected EpisodeBaseModel getCurrentEpisode() { return mCurrentEpisode; } protected EpisodeDetailsView getDetailView() { return mDetailView; } protected void setCurrentEpisode(EpisodeBaseModel ep) { mCurrentEpisode = ep; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EpisodeBaseModel episode = (EpisodeBaseModel) getActivity().getIntent().getSerializableExtra(ContentManagerBase.CONTENT_ID); if (episode == null) { episode = getEpisodeFromGlobalSearchIntent(); } if (episode != null) { setupEpisode(episode); } else { Log.e(TAG, "No episode set."); } } private void setupEpisode(EpisodeBaseModel episode) { mLoadedEpisode = episode; selectCurrentEpisode(episode, true); Point size = Utils.getDisplaySize(getActivity()); mHeaderHeight = Math.round(size.y * 0.475f); setupAdapter(episode); setupListeners(); } private EpisodeBaseModel getEpisodeFromGlobalSearchIntent() { Intent intent = getActivity().getIntent(); String action = intent.getAction(); if (ContentManagerBase.GLOBAL_SEARCH_INTENT.equals(action)) { Log.d(TAG, "getEpisodeFromGlobalSearchIntent"); Bundle data = intent.getExtras(); if (data != null) { String href = data.getString(ContentManagerBase.KEY_EXTRA_NAME); Log.d(TAG, "Search result: " + href); return getContentManger().getEpisode(href); } Log.w(TAG, "Unable to find href from search result"); } return null; } private void setupListeners() { setOnItemViewClickedListener(getItemClickedListener()); setOnItemViewSelectedListener(getItemSelectedListener()); } private void setupAdapter(EpisodeBaseModel episode) { ArrayObjectAdapter adapter = new ArrayObjectAdapter(new ListRowPresenter()); otherEpisodes = new ArrayObjectAdapter(new CardSelector()); otherEpisodes.add(0, episode); adapter.add(new ListRow(new HeaderItem(0, null), otherEpisodes)); setAdapter(adapter); } protected void selectCurrentEpisode(EpisodeBaseModel episode, boolean initial) { Log.d(TAG, "Showing details: " + episode); if (!episode.equals(mCurrentEpisode)) { mCurrentEpisode = episode; getContentManger().fetchEpisode(episode); if (mDetailView != null) { mDetailView.setEpisode(episode); } } } private void updateEpisodeData(Intent intent) { String href = intent.getStringExtra(ContentManagerBase.CONTENT_TAG); EpisodeBaseModel ep = getContentManger().getEpisode(href); if (ep != null) { if (ep.equals(mCurrentEpisode)) { mCurrentEpisode.merge(ep); mDetailView.updateEpisode(mCurrentEpisode); } if (ep.equals(mLoadedEpisode) && !loadedOtherEpisodes) { updateRelatedEpisodes(ep.getOtherEpisodes()); loadedOtherEpisodes = true; mOtherEpisodeUrls = mLoadedEpisode.getOtherEpisodeUrls(ContentManagerBase.OTHER_EPISODES); Log.d(TAG, "Other episodes:" + mOtherEpisodeUrls); } } } private void updateRelatedEpisodes(Map<String, List<EpisodeBaseModel>> others) { boolean updated = false; ArrayObjectAdapter adapter = (ArrayObjectAdapter) getAdapter(); for (Map.Entry<String, List<EpisodeBaseModel>> list : others.entrySet()) { String title = list.getKey(); Log.d(TAG, "More: " + title); if (ContentManagerBase.OTHER_EPISODES.equals(title)) { otherEpisodes.addAll(otherEpisodes.size(), list.getValue()); } else { ArrayObjectAdapter more = new ArrayObjectAdapter(new CardSelector()); more.addAll(0, list.getValue()); adapter.add(new ListRow(new HeaderItem(0, title), more)); } updated = true; } if (updated) { adapter.notifyArrayItemRangeChanged(0, adapter.size()); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = super.onCreateView(inflater, container, savedInstanceState); if (view instanceof FrameLayout) { insertHeader(inflater, (FrameLayout) view); } return view; } private void insertHeader(LayoutInflater inflater, FrameLayout container) { VerticalGridView grid = findFirstGrid(container); if (grid != null) { View header = inflater.inflate(R.layout.episode_details_view, container, false); View bottom = inflater.inflate(R.layout.dark_gradient, container, false); container.addView(header, 0); container.addView(bottom, 1); setupGridAlignment(grid); setupHeaderView(grid, header); setupGradient(bottom); } else { Utils.showToast(getActivity(), "No Grid Found!"); } } private void setupGradient(View bottom) { int height = getResources().getDimensionPixelSize(R.dimen.episode_detail_padding_bottom); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) bottom.getLayoutParams(); lp.topMargin = mHeaderHeight; lp.height = height; bottom.setLayoutParams(lp); } private void setupHeaderView(VerticalGridView grid, View header) { mDetailView = new EpisodeDetailsView(getActivity(), header); if (mCurrentEpisode != null) { mDetailView.setEpisode(mCurrentEpisode); } int height = getResources().getDimensionPixelSize(R.dimen.episode_detail_padding_bottom); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) header.getLayoutParams(); lp.height = mHeaderHeight + height; header.setLayoutParams(lp); } private void setupGridAlignment(VerticalGridView grid) { int cardHeight = getResources().getDimensionPixelSize(R.dimen.card_height); int titleHeight = getResources().getDimensionPixelSize(R.dimen.lb_browse_header_height); grid.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_LOW_EDGE); grid.setWindowAlignmentOffset(cardHeight + titleHeight); grid.setWindowAlignmentOffsetPercent(VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) grid.getLayoutParams(); lp.topMargin = mHeaderHeight; grid.setLayoutParams(lp); } private VerticalGridView findFirstGrid(ViewGroup container) { for (int i = 0, k = container.getChildCount(); i < k; i++) { View view = container.getChildAt(i); if (view instanceof VerticalGridView) { return (VerticalGridView) view; } } return null; } protected abstract Class<?> getPlayerActivityClass(); private OnItemViewClickedListener getItemClickedListener() { return new OnItemViewClickedListener() { @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { Log.d(TAG, "Clicked item:" + item); if (item instanceof EpisodeBaseModel) { EpisodeBaseModel ep = (EpisodeBaseModel) item; Intent intent = new Intent(getActivity(), getPlayerActivityClass()); intent.putExtra(ContentManagerBase.CONTENT_ID, ep); String[] others = getOtherEpisodeUrls().toArray(new String[getOtherEpisodeUrls().size()]); intent.putExtra(ContentManagerBase.OTHER_EPISODES, others); startActivity(intent); } } }; } private OnItemViewSelectedListener getItemSelectedListener() { return new OnItemViewSelectedListener() { @Override public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { Log.d(TAG, "Selected item:" + item); if (item instanceof EpisodeBaseModel) { selectCurrentEpisode((EpisodeBaseModel) item, false); } } }; } @Override public void onResume() { super.onResume(); registerReceiver(); } public void onPause() { super.onPause(); LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver); } private void registerReceiver() { Log.i(TAG, "Register receiver"); IntentFilter filter = new IntentFilter(); filter.addAction(ContentManagerBase.CONTENT_EPISODE_START); filter.addAction(ContentManagerBase.CONTENT_EPISODE_DONE); filter.addAction(ContentManagerBase.CONTENT_EPISODE_ERROR); LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, filter); } }