DetailsOverviewRowPresenter.java revision 056561d81012983d2d27b8665c4aeabb427174cb
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.widget;
15
16import android.content.Context;
17import android.graphics.Color;
18import android.support.v17.leanback.R;
19import android.support.v7.widget.RecyclerView;
20import android.util.Log;
21import android.util.TypedValue;
22import android.view.LayoutInflater;
23import android.view.View;
24import android.view.ViewGroup;
25import android.widget.FrameLayout;
26import android.widget.ImageView;
27
28import java.util.Collection;
29
30/**
31 * DetailsOverviewRowPresenter renders {@link DetailsOverviewRow} to display an
32 * overview of an item. Typically this row will be the first row in a fragment
33 * such as {@link android.support.v17.leanback.app.DetailsFragment
34 * DetailsFragment}.
35 *
36 * <p>The detailed description is rendered using a {@link Presenter}.
37 */
38public class DetailsOverviewRowPresenter extends RowPresenter {
39
40    private static final String TAG = "DetailsOverviewRowPresenter";
41    private static final boolean DEBUG = false;
42
43    private static final int MORE_ACTIONS_FADE_MS = 100;
44
45    public static class ViewHolder extends RowPresenter.ViewHolder {
46        final ImageView mImageView;
47        final FrameLayout mDetailsDescriptionFrame;
48        final HorizontalGridView mActionsRow;
49        final View mMoreActionsView;
50        Presenter.ViewHolder mDetailsDescriptionViewHolder;
51        int mNumItems;
52        boolean mShowMoreRight;
53        boolean mShowMoreLeft;
54        boolean mShowMoreActions;
55
56        void bind(ItemBridgeAdapter bridgeAdapter) {
57            mNumItems = bridgeAdapter.getItemCount();
58            bridgeAdapter.setAdapterListener(mAdapterListener);
59
60            mMoreActionsView.setAlpha(0f);
61            mShowMoreRight = false;
62            mShowMoreActions = false;
63
64            mShowMoreLeft = true;
65            showMoreLeft(false);
66        }
67
68        final ItemBridgeAdapter.AdapterListener mAdapterListener =
69                new ItemBridgeAdapter.AdapterListener() {
70
71            @Override
72            public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
73                checkFirstAndLastPosition(false);
74            }
75            @Override
76            public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
77                checkFirstAndLastPosition(false);
78            }
79        };
80
81        final RecyclerView.OnScrollListener mScrollListener =
82                new RecyclerView.OnScrollListener() {
83
84            @Override
85            public void onScrollStateChanged(int newState) {
86            }
87            @Override
88            public void onScrolled(int dx, int dy) {
89                checkFirstAndLastPosition(true);
90            }
91        };
92
93        private int getViewCenter(View view) {
94            return (view.getRight() - view.getLeft()) / 2;
95        }
96
97        private void checkFirstAndLastPosition(boolean fromScroll) {
98            RecyclerView.ViewHolder viewHolder;
99
100            viewHolder = mActionsRow.findViewHolderForPosition(mNumItems - 1);
101            boolean showRight = (viewHolder == null ||
102                    viewHolder.itemView.getRight() > mActionsRow.getWidth());
103
104            boolean showMore = (viewHolder == null ||
105                    getViewCenter(viewHolder.itemView) > mActionsRow.getWidth());
106
107            viewHolder = mActionsRow.findViewHolderForPosition(0);
108            boolean showLeft = (viewHolder == null || viewHolder.itemView.getLeft() < 0);
109
110            if (DEBUG) Log.v(TAG, "checkFirstAndLast fromScroll " + fromScroll +
111                    " showRight " + showRight + " showLeft " + showLeft);
112
113            showMoreActions(showMore);
114            showMoreRight(showRight);
115            showMoreLeft(showLeft);
116        }
117
118        private void showMoreLeft(boolean show) {
119            if (show != mShowMoreLeft) {
120                mActionsRow.setFadingLeftEdge(show);
121                mShowMoreLeft = show;
122            }
123        }
124
125        private void showMoreRight(boolean show) {
126            if (show != mShowMoreRight) {
127                mActionsRow.setFadingRightEdge(show);
128                mShowMoreRight = show;
129            }
130        }
131
132        private void showMoreActions(boolean show) {
133            if (show != mShowMoreActions) {
134                mMoreActionsView.animate().alpha(show ? 1f : 0).setDuration(
135                        MORE_ACTIONS_FADE_MS).start();
136                mShowMoreActions = show;
137            }
138        }
139
140        public ViewHolder(View rootView) {
141            super(rootView);
142            mImageView = (ImageView) rootView.findViewById(R.id.details_overview_image);
143            mDetailsDescriptionFrame =
144                    (FrameLayout) rootView.findViewById(R.id.details_overview_description);
145            mActionsRow =
146                    (HorizontalGridView) rootView.findViewById(R.id.details_overview_actions);
147            mActionsRow.setOnScrollListener(mScrollListener);
148
149            final int fadeLength = rootView.getResources().getDimensionPixelSize(
150                    R.dimen.lb_details_overview_actions_fade_size);
151            mActionsRow.setFadingRightEdgeLength(fadeLength);
152            mActionsRow.setFadingRightEdgeOffset(-fadeLength);
153            mActionsRow.setFadingLeftEdgeLength(fadeLength);
154            mActionsRow.setFadingLeftEdgeOffset(-fadeLength);
155
156            mMoreActionsView = rootView.findViewById(R.id.details_overview_actions_more);
157        }
158    }
159
160    private final Presenter mDetailsPresenter;
161    private final ActionPresenterSelector mActionPresenterSelector;
162    private final ItemBridgeAdapter mActionBridgeAdapter;
163    private int mBackgroundColor = Color.TRANSPARENT;
164    private boolean mBackgroundColorSet;
165    private boolean mIsStyleLarge = true;
166
167    /**
168     * Constructor that uses the given {@link Presenter} to render the detailed
169     * description for the row.
170     */
171    public DetailsOverviewRowPresenter(Presenter detailsPresenter) {
172        setHeaderPresenter(null);
173        setSelectEffectEnabled(false);
174        mDetailsPresenter = detailsPresenter;
175        mActionPresenterSelector = new ActionPresenterSelector();
176        mActionBridgeAdapter = new ItemBridgeAdapter();
177    }
178
179    /**
180     * Sets the listener for action click events.
181     */
182    public void setOnActionClickedListener(OnActionClickedListener listener) {
183        mActionPresenterSelector.setOnActionClickedListener(listener);
184    }
185
186    /**
187     * Gets the listener for action click events.
188     */
189    public OnActionClickedListener getOnActionClickedListener() {
190        return mActionPresenterSelector.getOnActionClickedListener();
191    }
192
193    /**
194     * Sets the background color.  If not set a default from the theme will be used.
195     */
196    public void setBackgroundColor(int color) {
197        mBackgroundColor = color;
198        mBackgroundColorSet = true;
199    }
200
201    /**
202     * Returns the background color.  If no background color was set, returns transparent.
203     */
204    public int getBackgroundColor() {
205        return mBackgroundColor;
206    }
207
208    /**
209     * Sets the layout style to be large or small.
210     * The default is large.
211     */
212    public void setStyleLarge(boolean large) {
213        mIsStyleLarge = large;
214    }
215
216    /**
217     * Returns true if the layout style is large.
218     */
219    public boolean isStyleLarge() {
220        return mIsStyleLarge;
221    }
222
223    private int getDefaultBackgroundColor(Context context) {
224        TypedValue outValue = new TypedValue();
225        context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true);
226        return context.getResources().getColor(outValue.resourceId);
227    }
228
229    @Override
230    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
231        View v = LayoutInflater.from(parent.getContext())
232            .inflate(R.layout.lb_details_overview, parent, false);
233        ViewHolder vh = new ViewHolder(v);
234
235        vh.mDetailsDescriptionViewHolder =
236            mDetailsPresenter.onCreateViewHolder(vh.mDetailsDescriptionFrame);
237        vh.mDetailsDescriptionFrame.addView(vh.mDetailsDescriptionViewHolder.view);
238
239        initDetailsOverview(v.findViewById(R.id.details_overview));
240
241        return vh;
242    }
243
244    private void initDetailsOverview(View view) {
245        int resId = mIsStyleLarge ? R.dimen.lb_details_overview_height_large :
246            R.dimen.lb_details_overview_height_small;
247
248        ViewGroup.LayoutParams lp = view.getLayoutParams();
249        lp.height = view.getResources().getDimensionPixelSize(resId);
250        view.setLayoutParams(lp);
251
252        view.setBackgroundColor(mBackgroundColorSet ?
253                mBackgroundColor : getDefaultBackgroundColor(view.getContext()));
254
255    }
256
257    @Override
258    protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) {
259        super.onBindRowViewHolder(holder, item);
260
261        DetailsOverviewRow row = (DetailsOverviewRow) item;
262        ViewHolder vh = (ViewHolder) holder;
263        if (row.getImageDrawable() != null) {
264            vh.mImageView.setImageDrawable(row.getImageDrawable());
265        }
266        if (vh.mDetailsDescriptionViewHolder == null) {
267        }
268        mDetailsPresenter.onBindViewHolder(vh.mDetailsDescriptionViewHolder, row);
269
270        mActionBridgeAdapter.clear();
271        ArrayObjectAdapter aoa = new ArrayObjectAdapter(mActionPresenterSelector);
272        aoa.addAll(0, (Collection)row.getActions());
273
274        mActionBridgeAdapter.setAdapter(aoa);
275        vh.mActionsRow.setAdapter(mActionBridgeAdapter);
276
277        vh.bind(mActionBridgeAdapter);
278    }
279
280    @Override
281    protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) {
282        super.onUnbindRowViewHolder(holder);
283
284        ViewHolder vh = (ViewHolder) holder;
285        if (vh.mDetailsDescriptionViewHolder != null) {
286            mDetailsPresenter.onUnbindViewHolder(vh.mDetailsDescriptionViewHolder);
287        }
288
289        vh.mActionsRow.setAdapter(null);
290    }
291}
292