1b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri/* 2b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Copyright (C) 2016 The Android Open Source Project 3b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * 4b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * in compliance with the License. You may obtain a copy of the License at 6b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * 7b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * http://www.apache.org/licenses/LICENSE-2.0 8b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * 9b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Unless required by applicable law or agreed to in writing, software distributed under the License 10b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * or implied. See the License for the specific language governing permissions and limitations under 12b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * the License. 13b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 14b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiripackage android.support.v17.leanback.widget; 15b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.animation.ValueAnimator; 18b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.content.Context; 19b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.graphics.Color; 204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.graphics.Rect; 21b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.support.v17.leanback.R; 224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.support.v4.view.ViewCompat; 23b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.ContextThemeWrapper; 24b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.LayoutInflater; 25b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.View; 26b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.view.ViewGroup; 274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport android.view.animation.DecelerateInterpolator; 28b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiriimport android.widget.TextView; 29b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport java.util.ArrayList; 314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiriimport java.util.List; 324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 33b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri/** 34b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Abstract {@link Presenter} class for rendering media items in a playlist format. 354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Media item data provided for this presenter can implement the interface 364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link MultiActionsProvider}, if the media rows wish to contain custom actions. 374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Media items in the playlist are arranged as a vertical list with each row holding each media 384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * item's details provided by the user of this class and a set of optional custom actions. 394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Each media item's details and actions are separately focusable. 404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The appearance of each one of the media row components can be controlled through setting 414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * theme's attributes. 424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The presenter can optionally provide line separators between media rows by setting 434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link #setHasMediaRowSeparator(boolean)} to true. 444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * <p> 454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Subclasses must override {@link #onBindMediaDetails} to implement their media item model 464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * data binding to each row view. 474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * </p> 48b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * <p> 494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The {@link OnItemViewClickedListener} and {@link OnItemViewSelectedListener} 504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * can be used in the same fashion to handle selection or click events on either of 514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * media details or each individual action views. 52b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * </p> 53b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * <p> 54b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * {@link AbstractMediaListHeaderPresenter} can be used in conjunction with this presenter in 554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * order to display a playlist with a header view. 56b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * </p> 57b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 58b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiripublic abstract class AbstractMediaItemPresenter extends RowPresenter { 59b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final static Rect sTempRect = new Rect(); 61b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri private int mBackgroundColor = Color.TRANSPARENT; 62b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri private boolean mBackgroundColorSet; 634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private boolean mMediaRowSeparator; 644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private int mThemeId; 654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private Presenter mMediaItemActionPresenter = new MediaItemActionPresenter(); 67b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 68b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri /** 694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Constructor used for creating an abstract media item presenter. 70b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public AbstractMediaItemPresenter() { 724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri this(0); 73b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 74b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 75b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri /** 76b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Constructor used for creating an abstract media item presenter. 774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param themeId The resource id of the theme that defines attributes controlling the 784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * appearance of different widgets in a media item row. 79b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public AbstractMediaItemPresenter(int themeId) { 814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mThemeId = themeId; 82b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri setHeaderPresenter(null); 83b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 84b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 85b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri /** 864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Sets the theme used to style a media item row components. 874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param themeId The resource id of the theme that defines attributes controlling the 884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * appearance of different widgets in a media item row. 894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void setThemeId(int themeId) { 914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mThemeId = themeId; 924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Return The resource id of the theme that defines attributes controlling the appearance of 964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * different widgets in a media item row. 974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * 984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @return The resource id of the theme that defines attributes controlling the appearance of 994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * different widgets in a media item row. 1004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 1014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public int getThemeId() { 1024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mThemeId; 1034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 1054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 1064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Sets the action presenter rendering each optional custom action within each media item row. 1074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param actionPresenter the presenter to be used for rendering a media item row actions. 1084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 1094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void setActionPresenter(Presenter actionPresenter) { 1104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemActionPresenter = actionPresenter; 1114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 1134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 1144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Return the presenter used to render a media item row actions. 1154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * 1164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @return the presenter used to render a media item row actions. 1174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 1184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public Presenter getActionPresenter() { 1194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaItemActionPresenter; 1204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 1224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 123b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * The ViewHolder for the {@link AbstractMediaItemPresenter}. It references different views 1244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * that place different meta-data corresponding to a media item details, actions, selector, 1254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * listeners, and presenters, 126b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 127b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri public static class ViewHolder extends RowPresenter.ViewHolder { 128b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 1294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final View mMediaRowView; 1304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final View mSelectorView; 1314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final View mMediaItemDetailsView; 1324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final TextView mMediaItemNumberView; 1334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final TextView mMediaItemNameView; 1344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final TextView mMediaItemDurationView; 1354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final View mMediaItemRowSeparator; 1364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final ViewGroup mMediaItemActionsContainer; 1374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private final List<Presenter.ViewHolder> mActionViewHolders; 1384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private MultiActionsProvider.MultiAction[] mMediaItemRowActions; 1394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri AbstractMediaItemPresenter mRowPresenter; 1404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private ValueAnimator mFocusViewAnimator; 141b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 142b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri public ViewHolder(View view) { 143b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri super(view); 1444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mSelectorView = view.findViewById(R.id.mediaRowSelector); 1454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaRowView = view.findViewById(R.id.mediaItemRow); 1464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemDetailsView = view.findViewById(R.id.mediaItemDetails); 1474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemNumberView = (TextView) view.findViewById(R.id.mediaItemNumber); 1484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemNameView = (TextView) view.findViewById(R.id.mediaItemName); 1494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemDurationView = (TextView) view.findViewById(R.id.mediaItemDuration); 1504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemRowSeparator = view.findViewById(R.id.mediaRowSeparator); 1514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemActionsContainer = (ViewGroup) view.findViewById( 1524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri R.id.mediaItemActionsContainer); 1534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mActionViewHolders = new ArrayList<Presenter.ViewHolder>(); 1544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri getMediaItemDetailsView().setOnClickListener(new View.OnClickListener(){ 1554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri @Override 1564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void onClick(View view) { 1574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (getOnItemViewClickedListener() != null) { 1584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri getOnItemViewClickedListener().onItemClicked(null, null, 1594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri ViewHolder.this, getRowObject()); 1604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri }); 1634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri getMediaItemDetailsView().setOnFocusChangeListener(new View.OnFocusChangeListener() { 1644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri @Override 1654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void onFocusChange(View view, boolean hasFocus) { 1664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mFocusViewAnimator = updateSelector(mSelectorView, view, mFocusViewAnimator, 1674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri true); 1684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri }); 1704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 1714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 1734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 1744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Binds the actions in a media item row object to their views. This consists of creating 1754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * (or reusing the existing) action view holders, and populating them with the actions' 1764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * icons. 1774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 1784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void onBindRowActions() { 1794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri for (int i = getMediaItemActionsContainer().getChildCount() - 1; 1804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri i >= mActionViewHolders.size(); i--) { 1814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri getMediaItemActionsContainer().removeViewAt(i); 1824fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mActionViewHolders.remove(i); 1834fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemRowActions = null; 1854fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 1864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri Object rowObject = getRowObject(); 1874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final MultiActionsProvider.MultiAction[] actionList; 1884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (rowObject instanceof MultiActionsProvider) { 1894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri actionList = ((MultiActionsProvider) rowObject).getActions(); 1904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } else { 1914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return; 1924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri Presenter actionPresenter = mRowPresenter.getActionPresenter(); 1944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (actionPresenter == null) { 1954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return; 1964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 1974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 1984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaItemRowActions = actionList; 1994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri for (int i = mActionViewHolders.size(); i < actionList.length; i++) { 2004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final int actionIndex = i; 2014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final Presenter.ViewHolder actionViewHolder = actionPresenter. 2024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri onCreateViewHolder(getMediaItemActionsContainer()); 2034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri getMediaItemActionsContainer().addView(actionViewHolder.view); 2044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mActionViewHolders.add(actionViewHolder); 2054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri actionViewHolder.view.setOnFocusChangeListener(new View.OnFocusChangeListener() { 2064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri @Override 2074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void onFocusChange(View view, boolean hasFocus) { 2084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mFocusViewAnimator = updateSelector(mSelectorView, view, 2094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mFocusViewAnimator, false); 2104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri }); 2124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri actionViewHolder.view.setOnClickListener( 2134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri new View.OnClickListener() { 2144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri @Override 2154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void onClick(View view) { 2164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (getOnItemViewClickedListener() != null) { 2174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri getOnItemViewClickedListener().onItemClicked( 2184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri actionViewHolder, mMediaItemRowActions[actionIndex], 2194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri ViewHolder.this, getRowObject()); 2204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri }); 2234fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 2254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (mMediaItemActionsContainer != null) { 2264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri for (int i = 0; i < actionList.length; i++) { 2274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri Presenter.ViewHolder avh = mActionViewHolders.get(i); 2284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri actionPresenter.onUnbindViewHolder(avh); 2294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri actionPresenter.onBindViewHolder(avh, mMediaItemRowActions[i]); 2304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 2334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 2354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri int findActionIndex(MultiActionsProvider.MultiAction action) { 2364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (mMediaItemRowActions != null) { 2374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri for (int i = 0; i < mMediaItemRowActions.length; i++) { 2384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (mMediaItemRowActions[i] == action) { 2394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return i; 2404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return -1; 2444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 2464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 2474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Notifies an action has changed in this media row and the UI needs to be updated 2484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param action The action whose state has changed 2494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 2504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void notifyActionChanged(MultiActionsProvider.MultiAction action) { 2514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri Presenter actionPresenter = mRowPresenter.getActionPresenter(); 2524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (actionPresenter == null) { 2534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return; 2544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri int actionIndex = findActionIndex(action); 2564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (actionIndex >= 0) { 2574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri Presenter.ViewHolder actionViewHolder = mActionViewHolders.get(actionIndex); 2584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri actionPresenter.onUnbindViewHolder(actionViewHolder); 2594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri actionPresenter.onBindViewHolder(actionViewHolder, action); 2604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 2634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 2644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Notifies the content of the media item details in a row has changed and triggers updating 2654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * the UI. This causes {@link #onBindMediaDetails(ViewHolder, Object)} 2664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * on the user's provided presenter to be called back, allowing them to update UI 2674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * accordingly. 2684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 2694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void notifyDetailsChanged() { 2704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mRowPresenter.onUnbindMediaDetails(this); 2714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mRowPresenter.onBindMediaDetails(this, getRowObject()); 2724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 2734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 2744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 2754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 2764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @return The SelectorView responsible for highlighting the in-focus view within each 2774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * media item row 2784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 2794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public View getSelectorView() { 2804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mSelectorView; 281b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 282b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 283b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri /** 284b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * @return The TextView responsible for rendering the track number 285b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 2864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public TextView getMediaItemNumberView() { 2874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaItemNumberView; 288b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 289b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 290b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri /** 291b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * @return The TextView responsible for rendering the track name 292b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 2934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public TextView getMediaItemNameView() { 2944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaItemNameView; 295b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 296b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 297b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri /** 298b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * @return The TextView responsible for rendering the track duration 299b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 3004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public TextView getMediaItemDurationView() { 3014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaItemDurationView; 3024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 3034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 3054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @return The view container of track details 3064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 3074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public View getMediaItemDetailsView() { 3084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaItemDetailsView; 3094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 3104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 3124fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @return The view responsible for rendering the separator line between media rows 3134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 3144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public View getMediaItemRowSeparator() { 3154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaItemRowSeparator; 3164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 3174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 3194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @return The view containing the set of custom actions 3204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 3214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public ViewGroup getMediaItemActionsContainer() { 3224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaItemActionsContainer; 3234fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 3244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public MultiActionsProvider.MultiAction[] getMediaItemRowActions() { 3264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaItemRowActions; 327b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 328b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 329b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 330b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri @Override 331b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) { 3324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri Context context = parent.getContext(); 3334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (mThemeId != 0) { 3344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri context = new ContextThemeWrapper(context, mThemeId); 3354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 336b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri View view = LayoutInflater.from(context). 337b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri inflate(R.layout.lb_row_media_item, parent, false); 3384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final ViewHolder vh = new ViewHolder(view); 3394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri vh.mRowPresenter = this; 340b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri if (mBackgroundColorSet) { 3414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri vh.mMediaRowView.setBackgroundColor(mBackgroundColor); 342b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 3434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return vh; 344b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 345b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 346b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri @Override 347b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri public boolean isUsingDefaultSelectEffect() { 348b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri return false; 349b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 350b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 351b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri @Override 3524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri protected boolean isClippingChildren() { 3534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return true; 3544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 3554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri @Override 357b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) { 358b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri super.onBindRowViewHolder(vh, item); 3594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final ViewHolder mvh = (ViewHolder) vh; 3614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri onBindRowActions(mvh); 3634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mvh.getMediaItemRowSeparator().setVisibility(hasMediaRowSeparator() ? View.VISIBLE : 3654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri View.GONE); 3664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri onBindMediaDetails((ViewHolder) vh, item); 3684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 3694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 3714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Binds the given media item object action to the given ViewHolder's action views. 3724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param vh ViewHolder for the media item. 3734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 3744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri protected void onBindRowActions(ViewHolder vh) { 3754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri vh.onBindRowActions(); 376b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 377b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 378b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri /** 379b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * Sets the background color for the row views within the playlist. 380b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * If this is not set, a default color, defaultBrandColor, from theme is used. 381b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * This defaultBrandColor defaults to android:attr/colorPrimary on v21, if it's specified. 382b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * @param color The ARGB color used to set as the media list background color. 383b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 384b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri public void setBackgroundColor(int color) { 385b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri mBackgroundColorSet = true; 386b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri mBackgroundColor = color; 387b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri } 388b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 389b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri /** 3904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Specifies whether a line separator should be used between media item rows. 3914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param hasSeparator true if a separator should be displayed, false otherwise. 3924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 3934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void setHasMediaRowSeparator(boolean hasSeparator) { 3944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri mMediaRowSeparator = hasSeparator; 3954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 3964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 3974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public boolean hasMediaRowSeparator() { 3984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return mMediaRowSeparator; 3994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 4004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 4014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Binds the media item details to their views provided by the 402b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * {@link AbstractMediaItemPresenter}. 4034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * This method is to be overridden by the users of this presenter. 4044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The subclasses of this presenter can access and bind individual views for either of the 4054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * media item number, name, or duration (depending on whichever views are visible according to 4064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * the providing theme attributes), by calling {@link ViewHolder#getMediaItemNumberView()}, 4074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link ViewHolder#getMediaItemNameView()}, and {@link ViewHolder#getMediaItemDurationView()}, 4084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * on the {@link ViewHolder} provided as the argument {@code vh} of this presenter. 409b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * 410b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri * @param vh The ViewHolder for this {@link AbstractMediaItemPresenter}. 4114fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param item The media item row object being presented. 412b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri */ 4134fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri protected abstract void onBindMediaDetails(ViewHolder vh, Object item); 4144fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 4154fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 4164fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Unbinds the media item details from their views provided by the 4174fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link AbstractMediaItemPresenter}. 4184fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * This method can be overridden by the subclasses of this presenter if required. 4194fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param vh ViewHolder to unbind from. 4204fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 4214fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri protected void onUnbindMediaDetails(ViewHolder vh) { 4224fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 423b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri 4244fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri /** 4254fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * Each media item row can have multiple focusable elements; the details on the left and a set 4264fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * of optional custom actions on the right. 4274fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * The selector is a highlight that moves to highlight to cover whichever views is in focus. 4284fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * 4294fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param selectorView the selector view used to highlight an individual element within a row. 4304fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param focusChangedView The component within the media row whose focus got changed. 4314fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param layoutAnimator the ValueAnimator producing animation frames for the selector's width 4324fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * and x-translation, generated by this method and stored for the each 4334fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * {@link ViewHolder}. 4344fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * @param isDetails Whether the changed-focused view is for a media item details (true) or 4354fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri * an action (false). 4364fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri */ 4374fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri private static ValueAnimator updateSelector(final View selectorView, 4384fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri View focusChangedView, ValueAnimator layoutAnimator, boolean isDetails) { 4394fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri int animationDuration = focusChangedView.getContext().getResources() 4404fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri .getInteger(android.R.integer.config_shortAnimTime); 4414fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri DecelerateInterpolator interpolator = new DecelerateInterpolator(); 4424fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 4434fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri int layoutDirection = ViewCompat.getLayoutDirection(selectorView); 4444fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (!focusChangedView.hasFocus()) { 4454fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri // if neither of the details or action views are in focus (ie. another row is in focus), 4464fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri // animate the selector out. 4474fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri selectorView.animate().cancel(); 4484fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri selectorView.animate().alpha(0f).setDuration(animationDuration) 4494fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri .setInterpolator(interpolator).start(); 4504fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri // keep existing layout animator 4514fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return layoutAnimator; 4524fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } else { 4534fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri // cancel existing layout animator 4544fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (layoutAnimator != null) { 4554fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri layoutAnimator.cancel(); 4564fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri layoutAnimator = null; 4574fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 4584fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri float currentAlpha = selectorView.getAlpha(); 4594fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri selectorView.animate().alpha(1f).setDuration(animationDuration) 4604fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri .setInterpolator(interpolator).start(); 4614fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 4624fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) 4634fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri selectorView.getLayoutParams(); 4644fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri ViewGroup rootView = (ViewGroup) selectorView.getParent(); 4654fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri sTempRect.set(0, 0, focusChangedView.getWidth(), focusChangedView.getHeight()); 4664fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri rootView.offsetDescendantRectToMyCoords(focusChangedView, sTempRect); 4674fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (isDetails) { 4684fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (layoutDirection == View.LAYOUT_DIRECTION_RTL ) { 4694fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri sTempRect.right += rootView.getHeight(); 4704fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri sTempRect.left -= rootView.getHeight() / 2; 4714fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } else { 4724fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri sTempRect.left -= rootView.getHeight(); 4734fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri sTempRect.right += rootView.getHeight() / 2; 4744fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 4754fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 4764fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final int targetLeft = sTempRect.left; 4774fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final int targetWidth = sTempRect.width(); 4784fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final float deltaWidth = lp.width - targetWidth; 4794fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri final float deltaLeft = lp.leftMargin - targetLeft; 4804fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 4814fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri if (deltaLeft == 0f && deltaWidth == 0f) 4824fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri { 4834fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri // no change needed 4844fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } else if (currentAlpha == 0f) { 4854fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri // change selector to the proper width and marginLeft without animation. 4864fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri lp.width = targetWidth; 4874fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri lp.leftMargin = targetLeft; 4884fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri selectorView.requestLayout(); 4894fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } else { 4904fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri // animate the selector to the proper width and marginLeft. 4914fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri layoutAnimator = ValueAnimator.ofFloat(0f, 1f); 4924fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri layoutAnimator.setDuration(animationDuration); 4934fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri layoutAnimator.setInterpolator(interpolator); 4944fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 4954fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri layoutAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 4964fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri @Override 4974fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri public void onAnimationUpdate(ValueAnimator valueAnimator) { 4984fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri // Set width to the proper width for this animation step. 4994fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri float fractionToEnd = 1f - valueAnimator.getAnimatedFraction(); 5004fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri lp.leftMargin = Math.round(targetLeft + deltaLeft * fractionToEnd); 5014fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri lp.width = Math.round(targetWidth + deltaWidth * fractionToEnd); 5024fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri selectorView.requestLayout(); 5034fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 5044fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri }); 5054fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri layoutAnimator.start(); 5064fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 5074fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri return layoutAnimator; 5084fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri 5094fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 5104fe538f2d65eefc57f618887ccb1226ec1a9741dKeyvan Amiri } 511b6ea4fa686b06fdb91f10998bd1d4b14c14af0ceKeyvan Amiri}