Home | History | Annotate | Download | only in list
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.tv.dvr.ui.list;
     18 
     19 import android.animation.ValueAnimator;
     20 import android.content.Context;
     21 import android.graphics.drawable.Drawable;
     22 import android.support.v17.leanback.widget.RowPresenter;
     23 import android.view.LayoutInflater;
     24 import android.view.View;
     25 import android.view.View.OnClickListener;
     26 import android.view.View.OnFocusChangeListener;
     27 import android.view.ViewGroup;
     28 import android.view.animation.DecelerateInterpolator;
     29 import android.widget.TextView;
     30 
     31 import com.android.tv.R;
     32 import com.android.tv.TvApplication;
     33 import com.android.tv.dvr.DvrUiHelper;
     34 import com.android.tv.dvr.SeriesRecording;
     35 import com.android.tv.dvr.ui.DvrSchedulesActivity;
     36 import com.android.tv.dvr.ui.list.SchedulesHeaderRow.SeriesRecordingHeaderRow;
     37 
     38 /**
     39  * A base class for RowPresenter for {@link SchedulesHeaderRow}
     40  */
     41 public abstract class SchedulesHeaderRowPresenter extends RowPresenter {
     42     private Context mContext;
     43 
     44     public SchedulesHeaderRowPresenter(Context context) {
     45         setHeaderPresenter(null);
     46         setSelectEffectEnabled(false);
     47         mContext = context;
     48     }
     49 
     50     /**
     51      * Returns the context.
     52      */
     53     Context getContext() {
     54         return mContext;
     55     }
     56 
     57     /**
     58      * A ViewHolder for {@link SchedulesHeaderRow}.
     59      */
     60     public static class SchedulesHeaderRowViewHolder extends RowPresenter.ViewHolder {
     61         private TextView mTitle;
     62         private TextView mDescription;
     63 
     64         public SchedulesHeaderRowViewHolder(Context context, ViewGroup parent) {
     65             super(LayoutInflater.from(context).inflate(R.layout.dvr_schedules_header, parent,
     66                     false));
     67             mTitle = (TextView) view.findViewById(R.id.header_title);
     68             mDescription = (TextView) view.findViewById(R.id.header_description);
     69         }
     70     }
     71 
     72     @Override
     73     protected void onBindRowViewHolder(RowPresenter.ViewHolder viewHolder, Object item) {
     74         super.onBindRowViewHolder(viewHolder, item);
     75         SchedulesHeaderRowViewHolder headerViewHolder = (SchedulesHeaderRowViewHolder) viewHolder;
     76         SchedulesHeaderRow header = (SchedulesHeaderRow) item;
     77         headerViewHolder.mTitle.setText(header.getTitle());
     78         headerViewHolder.mDescription.setText(header.getDescription());
     79     }
     80 
     81     /**
     82      * A presenter for {@link com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow}.
     83      */
     84     public static class DateHeaderRowPresenter extends SchedulesHeaderRowPresenter {
     85         public DateHeaderRowPresenter(Context context) {
     86             super(context);
     87         }
     88 
     89         @Override
     90         protected ViewHolder createRowViewHolder(ViewGroup parent) {
     91             return new DateHeaderRowViewHolder(getContext(), parent);
     92         }
     93 
     94         /**
     95          * A ViewHolder for
     96          * {@link com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow}.
     97          */
     98         public static class DateHeaderRowViewHolder extends SchedulesHeaderRowViewHolder {
     99             public DateHeaderRowViewHolder(Context context, ViewGroup parent) {
    100                 super(context, parent);
    101             }
    102         }
    103     }
    104 
    105     /**
    106      * A presenter for {@link SeriesRecordingHeaderRow}.
    107      */
    108     public static class SeriesRecordingHeaderRowPresenter extends SchedulesHeaderRowPresenter {
    109         private final boolean mLtr;
    110         private final Drawable mSettingsDrawable;
    111         private final Drawable mCancelDrawable;
    112         private final Drawable mResumeDrawable;
    113 
    114         private final String mSettingsInfo;
    115         private final String mCancelAllInfo;
    116         private final String mResumeInfo;
    117 
    118         public SeriesRecordingHeaderRowPresenter(Context context) {
    119             super(context);
    120             mLtr = context.getResources().getConfiguration().getLayoutDirection()
    121                     == View.LAYOUT_DIRECTION_LTR;
    122             mSettingsDrawable = context.getDrawable(R.drawable.ic_settings);
    123             mCancelDrawable = context.getDrawable(R.drawable.ic_dvr_cancel_large);
    124             mResumeDrawable = context.getDrawable(R.drawable.ic_record_start);
    125             mSettingsInfo = context.getString(R.string.dvr_series_schedules_settings);
    126             mCancelAllInfo = context.getString(R.string.dvr_series_schedules_stop);
    127             mResumeInfo = context.getString(R.string.dvr_series_schedules_start);
    128         }
    129 
    130         @Override
    131         protected ViewHolder createRowViewHolder(ViewGroup parent) {
    132             return new SeriesHeaderRowViewHolder(getContext(), parent);
    133         }
    134 
    135         @Override
    136         protected void onBindRowViewHolder(RowPresenter.ViewHolder viewHolder, Object item) {
    137             super.onBindRowViewHolder(viewHolder, item);
    138             SeriesHeaderRowViewHolder headerViewHolder =
    139                     (SeriesHeaderRowViewHolder) viewHolder;
    140             SeriesRecordingHeaderRow header = (SeriesRecordingHeaderRow) item;
    141             headerViewHolder.mSeriesSettingsButton.setVisibility(
    142                     header.getSeriesRecording().isStopped() ? View.INVISIBLE : View.VISIBLE);
    143             headerViewHolder.mSeriesSettingsButton.setText(mSettingsInfo);
    144             setTextDrawable(headerViewHolder.mSeriesSettingsButton, mSettingsDrawable);
    145             if (header.getSeriesRecording().isStopped()) {
    146                 headerViewHolder.mToggleStartStopButton.setText(mResumeInfo);
    147                 setTextDrawable(headerViewHolder.mToggleStartStopButton, mResumeDrawable);
    148             } else {
    149                 headerViewHolder.mToggleStartStopButton.setText(mCancelAllInfo);
    150                 setTextDrawable(headerViewHolder.mToggleStartStopButton, mCancelDrawable);
    151             }
    152             headerViewHolder.mSeriesSettingsButton.setOnClickListener(new OnClickListener() {
    153                 @Override
    154                 public void onClick(View view) {
    155                     // TODO: pass channel list for settings.
    156                     DvrUiHelper.startSeriesSettingsActivity(getContext(),
    157                             header.getSeriesRecording().getId(), null, false, false, false);
    158                 }
    159             });
    160             headerViewHolder.mToggleStartStopButton.setOnClickListener(new OnClickListener() {
    161                 @Override
    162                 public void onClick(View view) {
    163                     if (header.getSeriesRecording().isStopped()) {
    164                         // Reset priority to the highest.
    165                         SeriesRecording seriesRecording = SeriesRecording
    166                                 .buildFrom(header.getSeriesRecording())
    167                                 .setPriority(TvApplication.getSingletons(getContext())
    168                                         .getDvrScheduleManager().suggestNewSeriesPriority())
    169                                 .build();
    170                         TvApplication.getSingletons(getContext()).getDvrManager()
    171                                 .updateSeriesRecording(seriesRecording);
    172                         // TODO: pass channel list for settings.
    173                         DvrUiHelper.startSeriesSettingsActivity(getContext(),
    174                                 header.getSeriesRecording().getId(), null, false, false, false);
    175                     } else {
    176                         DvrUiHelper.showCancelAllSeriesRecordingDialog(
    177                                 (DvrSchedulesActivity) view.getContext(),
    178                                 header.getSeriesRecording());
    179                     }
    180                 }
    181             });
    182         }
    183 
    184         private void setTextDrawable(TextView textView, Drawable drawableStart) {
    185             if (mLtr) {
    186                 textView.setCompoundDrawablesWithIntrinsicBounds(drawableStart, null, null, null);
    187             } else {
    188                 textView.setCompoundDrawablesWithIntrinsicBounds(null, null, drawableStart, null);
    189             }
    190         }
    191 
    192         /**
    193          * A ViewHolder for {@link SeriesRecordingHeaderRow}.
    194          */
    195         public static class SeriesHeaderRowViewHolder extends SchedulesHeaderRowViewHolder {
    196             private final TextView mSeriesSettingsButton;
    197             private final TextView mToggleStartStopButton;
    198             private final boolean mLtr;
    199 
    200             private final View mSelector;
    201 
    202             private View mLastFocusedView;
    203             public SeriesHeaderRowViewHolder(Context context, ViewGroup parent) {
    204                 super(context, parent);
    205                 mLtr = context.getResources().getConfiguration().getLayoutDirection()
    206                         == View.LAYOUT_DIRECTION_LTR;
    207                 view.findViewById(R.id.button_container).setVisibility(View.VISIBLE);
    208                 mSeriesSettingsButton = (TextView) view.findViewById(R.id.series_settings);
    209                 mToggleStartStopButton =
    210                         (TextView) view.findViewById(R.id.series_toggle_start_stop);
    211                 mSelector = view.findViewById(R.id.selector);
    212                 OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
    213                     @Override
    214                     public void onFocusChange(View view, boolean focused) {
    215                         view.post(new Runnable() {
    216                             @Override
    217                             public void run() {
    218                                 updateSelector(view);
    219                             }
    220                         });
    221                     }
    222                 };
    223                 mSeriesSettingsButton.setOnFocusChangeListener(onFocusChangeListener);
    224                 mToggleStartStopButton.setOnFocusChangeListener(onFocusChangeListener);
    225             }
    226 
    227             private void updateSelector(View focusedView) {
    228                 int animationDuration = mSelector.getContext().getResources()
    229                         .getInteger(android.R.integer.config_shortAnimTime);
    230                 DecelerateInterpolator interpolator = new DecelerateInterpolator();
    231 
    232                 if (focusedView.hasFocus()) {
    233                     ViewGroup.LayoutParams lp = mSelector.getLayoutParams();
    234                     final int targetWidth = focusedView.getWidth();
    235                     float targetTranslationX;
    236                     if (mLtr) {
    237                         targetTranslationX = focusedView.getLeft() - mSelector.getLeft();
    238                     } else {
    239                         targetTranslationX = focusedView.getRight() - mSelector.getRight();
    240                     }
    241 
    242                     // if the selector is invisible, set the width and translation X directly -
    243                     // don't animate.
    244                     if (mSelector.getAlpha() == 0) {
    245                         mSelector.setTranslationX(targetTranslationX);
    246                         lp.width = targetWidth;
    247                         mSelector.requestLayout();
    248                     }
    249 
    250                     // animate the selector in and to the proper width and translation X.
    251                     final float deltaWidth = lp.width - targetWidth;
    252                     mSelector.animate().cancel();
    253                     mSelector.animate().translationX(targetTranslationX).alpha(1f)
    254                             .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    255                                 @Override
    256                                 public void onAnimationUpdate(ValueAnimator animation) {
    257                                     // Set width to the proper width for this animation step.
    258                                     lp.width = targetWidth + Math.round(
    259                                             deltaWidth * (1f - animation.getAnimatedFraction()));
    260                                     mSelector.requestLayout();
    261                                 }
    262                             }).setDuration(animationDuration).setInterpolator(interpolator).start();
    263                     mLastFocusedView = focusedView;
    264                 } else if (mLastFocusedView == focusedView) {
    265                     mSelector.animate().setUpdateListener(null).cancel();
    266                     mSelector.animate().alpha(0f).setDuration(animationDuration)
    267                             .setInterpolator(interpolator).start();
    268                     mLastFocusedView = null;
    269                 }
    270             }
    271         }
    272     }
    273 }
    274