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  */
14 package android.support.v17.leanback.widget;
15 
16 import android.graphics.Paint;
17 import android.graphics.Paint.FontMetricsInt;
18 import android.support.v17.leanback.R;
19 import android.text.TextUtils;
20 import android.view.LayoutInflater;
21 import android.view.View;
22 import android.view.ViewGroup;
23 import android.widget.TextView;
24 
25 /**
26  * An abstract {@link Presenter} for rendering a detailed description of an
27  * item. Typically this Presenter will be used in a DetailsOveriewRowPresenter.
28  *
29  * <p>Subclasses will override {@link #onBindDescription} to implement the data
30  * binding for this Presenter.
31  */
32 public abstract class AbstractDetailsDescriptionPresenter extends Presenter {
33 
34     public static class ViewHolder extends Presenter.ViewHolder {
35         private final TextView mTitle;
36         private final TextView mSubtitle;
37         private final TextView mBody;
38         private final int mTitleMargin;
39         private final int mUnderTitleBaselineMargin;
40         private final int mUnderSubtitleBaselineMargin;
41         private final int mTitleLineSpacing;
42         private final int mBodyLineSpacing;
43         private final int mBodyMaxLines;
44         private final int mBodyMinLines;
45         private final FontMetricsInt mTitleFontMetricsInt;
46         private final FontMetricsInt mSubtitleFontMetricsInt;
47         private final FontMetricsInt mBodyFontMetricsInt;
48 
ViewHolder(View view)49         public ViewHolder(View view) {
50             super(view);
51             mTitle = (TextView) view.findViewById(R.id.lb_details_description_title);
52             mSubtitle = (TextView) view.findViewById(R.id.lb_details_description_subtitle);
53             mBody = (TextView) view.findViewById(R.id.lb_details_description_body);
54 
55             FontMetricsInt titleFontMetricsInt = getFontMetricsInt(mTitle);
56             final int titleAscent = view.getResources().getDimensionPixelSize(
57                     R.dimen.lb_details_description_title_baseline);
58             // Ascent is negative
59             mTitleMargin = titleAscent + titleFontMetricsInt.ascent;
60 
61             mUnderTitleBaselineMargin = view.getResources().getDimensionPixelSize(
62                     R.dimen.lb_details_description_under_title_baseline_margin);
63             mUnderSubtitleBaselineMargin = view.getResources().getDimensionPixelSize(
64                     R.dimen.lb_details_description_under_subtitle_baseline_margin);
65 
66             mTitleLineSpacing = view.getResources().getDimensionPixelSize(
67                     R.dimen.lb_details_description_title_line_spacing);
68             mBodyLineSpacing = view.getResources().getDimensionPixelSize(
69                     R.dimen.lb_details_description_body_line_spacing);
70 
71             mBodyMaxLines = view.getResources().getInteger(
72                     R.integer.lb_details_description_body_max_lines);
73             mBodyMinLines = view.getResources().getInteger(
74                     R.integer.lb_details_description_body_min_lines);
75 
76             mTitleFontMetricsInt = getFontMetricsInt(mTitle);
77             mSubtitleFontMetricsInt = getFontMetricsInt(mSubtitle);
78             mBodyFontMetricsInt = getFontMetricsInt(mBody);
79 
80             mTitle.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
81                 @Override
82                 public void onLayoutChange(View v, int left, int top, int right,
83                         int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
84                     mBody.setMaxLines(mTitle.getLineCount() > 1 ? mBodyMinLines : mBodyMaxLines);
85                 }
86             });
87         }
88 
getTitle()89         public TextView getTitle() {
90             return mTitle;
91         }
92 
getSubtitle()93         public TextView getSubtitle() {
94             return mSubtitle;
95         }
96 
getBody()97         public TextView getBody() {
98             return mBody;
99         }
100 
getFontMetricsInt(TextView textView)101         private FontMetricsInt getFontMetricsInt(TextView textView) {
102             Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
103             paint.setTextSize(textView.getTextSize());
104             paint.setTypeface(textView.getTypeface());
105             return paint.getFontMetricsInt();
106         }
107     }
108 
109     @Override
onCreateViewHolder(ViewGroup parent)110     public final ViewHolder onCreateViewHolder(ViewGroup parent) {
111         View v = LayoutInflater.from(parent.getContext())
112             .inflate(R.layout.lb_details_description, parent, false);
113         return new ViewHolder(v);
114     }
115 
116     @Override
onBindViewHolder(Presenter.ViewHolder viewHolder, Object item)117     public final void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
118         ViewHolder vh = (ViewHolder) viewHolder;
119         onBindDescription(vh, item);
120 
121         boolean hasTitle = true;
122         if (TextUtils.isEmpty(vh.mTitle.getText())) {
123             vh.mTitle.setVisibility(View.GONE);
124             hasTitle = false;
125         } else {
126             vh.mTitle.setVisibility(View.VISIBLE);
127             vh.mTitle.setLineSpacing(vh.mTitleLineSpacing - vh.mTitle.getLineHeight() +
128                     vh.mTitle.getLineSpacingExtra(), vh.mTitle.getLineSpacingMultiplier());
129         }
130         setTopMargin(vh.mTitle, vh.mTitleMargin);
131 
132         boolean hasSubtitle = true;
133         if (TextUtils.isEmpty(vh.mSubtitle.getText())) {
134             vh.mSubtitle.setVisibility(View.GONE);
135             hasSubtitle = false;
136         } else {
137             vh.mSubtitle.setVisibility(View.VISIBLE);
138             if (hasTitle) {
139                 setTopMargin(vh.mSubtitle, vh.mUnderTitleBaselineMargin +
140                         vh.mSubtitleFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent);
141             } else {
142                 setTopMargin(vh.mSubtitle, 0);
143             }
144         }
145 
146         if (TextUtils.isEmpty(vh.mBody.getText())) {
147             vh.mBody.setVisibility(View.GONE);
148         } else {
149             vh.mBody.setVisibility(View.VISIBLE);
150             vh.mBody.setLineSpacing(vh.mBodyLineSpacing - vh.mBody.getLineHeight() +
151                     vh.mBody.getLineSpacingExtra(), vh.mBody.getLineSpacingMultiplier());
152 
153             if (hasSubtitle) {
154                 setTopMargin(vh.mBody, vh.mUnderSubtitleBaselineMargin +
155                         vh.mBodyFontMetricsInt.ascent - vh.mSubtitleFontMetricsInt.descent);
156             } else if (hasTitle) {
157                 setTopMargin(vh.mBody, vh.mUnderTitleBaselineMargin +
158                         vh.mBodyFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent);
159             } else {
160                 setTopMargin(vh.mBody, 0);
161             }
162         }
163     }
164 
165     /**
166      * Binds the data from the item referenced in the DetailsOverviewRow to the
167      * ViewHolder.
168      *
169      * @param vh The ViewHolder for this details description view.
170      * @param item The item from the DetailsOverviewRow being presented.
171      */
onBindDescription(ViewHolder vh, Object item)172     protected abstract void onBindDescription(ViewHolder vh, Object item);
173 
174     @Override
onUnbindViewHolder(Presenter.ViewHolder viewHolder)175     public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {}
176 
setTopMargin(TextView textView, int topMargin)177     private void setTopMargin(TextView textView, int topMargin) {
178         ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) textView.getLayoutParams();
179         lp.topMargin = topMargin;
180         textView.setLayoutParams(lp);
181     }
182 }
183