/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.tv.dvr.ui.list; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.v17.leanback.widget.RowPresenter; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnFocusChangeListener; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.widget.TextView; import com.android.tv.R; import com.android.tv.TvApplication; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.ui.DvrUiHelper; import com.android.tv.dvr.ui.list.SchedulesHeaderRow.SeriesRecordingHeaderRow; /** * A base class for RowPresenter for {@link SchedulesHeaderRow} */ abstract class SchedulesHeaderRowPresenter extends RowPresenter { private Context mContext; public SchedulesHeaderRowPresenter(Context context) { setHeaderPresenter(null); setSelectEffectEnabled(false); mContext = context; } /** * Returns the context. */ Context getContext() { return mContext; } /** * A ViewHolder for {@link SchedulesHeaderRow}. */ public static class SchedulesHeaderRowViewHolder extends RowPresenter.ViewHolder { private TextView mTitle; private TextView mDescription; public SchedulesHeaderRowViewHolder(Context context, ViewGroup parent) { super(LayoutInflater.from(context).inflate(R.layout.dvr_schedules_header, parent, false)); mTitle = (TextView) view.findViewById(R.id.header_title); mDescription = (TextView) view.findViewById(R.id.header_description); } } @Override protected void onBindRowViewHolder(RowPresenter.ViewHolder viewHolder, Object item) { super.onBindRowViewHolder(viewHolder, item); SchedulesHeaderRowViewHolder headerViewHolder = (SchedulesHeaderRowViewHolder) viewHolder; SchedulesHeaderRow header = (SchedulesHeaderRow) item; headerViewHolder.mTitle.setText(header.getTitle()); headerViewHolder.mDescription.setText(header.getDescription()); } /** * A presenter for {@link SchedulesHeaderRow.DateHeaderRow}. */ public static class DateHeaderRowPresenter extends SchedulesHeaderRowPresenter { public DateHeaderRowPresenter(Context context) { super(context); } @Override protected ViewHolder createRowViewHolder(ViewGroup parent) { return new DateHeaderRowViewHolder(getContext(), parent); } /** * A ViewHolder for * {@link SchedulesHeaderRow.DateHeaderRow}. */ public static class DateHeaderRowViewHolder extends SchedulesHeaderRowViewHolder { public DateHeaderRowViewHolder(Context context, ViewGroup parent) { super(context, parent); } } } /** * A presenter for {@link SeriesRecordingHeaderRow}. */ public static class SeriesRecordingHeaderRowPresenter extends SchedulesHeaderRowPresenter { private final boolean mLtr; private final Drawable mSettingsDrawable; private final Drawable mCancelDrawable; private final Drawable mResumeDrawable; private final String mSettingsInfo; private final String mCancelAllInfo; private final String mResumeInfo; public SeriesRecordingHeaderRowPresenter(Context context) { super(context); mLtr = context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; mSettingsDrawable = context.getDrawable(R.drawable.ic_settings); mCancelDrawable = context.getDrawable(R.drawable.ic_dvr_cancel_large); mResumeDrawable = context.getDrawable(R.drawable.ic_record_start); mSettingsInfo = context.getString(R.string.dvr_series_schedules_settings); mCancelAllInfo = context.getString(R.string.dvr_series_schedules_stop); mResumeInfo = context.getString(R.string.dvr_series_schedules_start); } @Override protected ViewHolder createRowViewHolder(ViewGroup parent) { return new SeriesHeaderRowViewHolder(getContext(), parent); } @Override protected void onBindRowViewHolder(RowPresenter.ViewHolder viewHolder, Object item) { super.onBindRowViewHolder(viewHolder, item); SeriesHeaderRowViewHolder headerViewHolder = (SeriesHeaderRowViewHolder) viewHolder; SeriesRecordingHeaderRow header = (SeriesRecordingHeaderRow) item; headerViewHolder.mSeriesSettingsButton.setVisibility( header.getSeriesRecording().isStopped() ? View.INVISIBLE : View.VISIBLE); headerViewHolder.mSeriesSettingsButton.setText(mSettingsInfo); setTextDrawable(headerViewHolder.mSeriesSettingsButton, mSettingsDrawable); if (header.getSeriesRecording().isStopped()) { headerViewHolder.mToggleStartStopButton.setText(mResumeInfo); setTextDrawable(headerViewHolder.mToggleStartStopButton, mResumeDrawable); } else { headerViewHolder.mToggleStartStopButton.setText(mCancelAllInfo); setTextDrawable(headerViewHolder.mToggleStartStopButton, mCancelDrawable); } headerViewHolder.mSeriesSettingsButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { DvrUiHelper.startSeriesSettingsActivity(getContext(), header.getSeriesRecording().getId(), header.getPrograms(), false, false, false, null); } }); headerViewHolder.mToggleStartStopButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (header.getSeriesRecording().isStopped()) { // Reset priority to the highest. SeriesRecording seriesRecording = SeriesRecording .buildFrom(header.getSeriesRecording()) .setPriority(TvApplication.getSingletons(getContext()) .getDvrScheduleManager().suggestNewSeriesPriority()) .build(); TvApplication.getSingletons(getContext()).getDvrManager() .updateSeriesRecording(seriesRecording); DvrUiHelper.startSeriesSettingsActivity(getContext(), header.getSeriesRecording().getId(), header.getPrograms(), false, false, false, null); } else { DvrUiHelper.showCancelAllSeriesRecordingDialog( (DvrSchedulesActivity) view.getContext(), header.getSeriesRecording()); } } }); } private void setTextDrawable(TextView textView, Drawable drawableStart) { textView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, null, null, null); } /** * A ViewHolder for {@link SeriesRecordingHeaderRow}. */ public static class SeriesHeaderRowViewHolder extends SchedulesHeaderRowViewHolder { private final TextView mSeriesSettingsButton; private final TextView mToggleStartStopButton; private final boolean mLtr; private final View mSelector; private View mLastFocusedView; public SeriesHeaderRowViewHolder(Context context, ViewGroup parent) { super(context, parent); mLtr = context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; view.findViewById(R.id.button_container).setVisibility(View.VISIBLE); mSeriesSettingsButton = (TextView) view.findViewById(R.id.series_settings); mToggleStartStopButton = (TextView) view.findViewById(R.id.series_toggle_start_stop); mSelector = view.findViewById(R.id.selector); OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() { @Override public void onFocusChange(View view, boolean focused) { view.post(new Runnable() { @Override public void run() { updateSelector(view); } }); } }; mSeriesSettingsButton.setOnFocusChangeListener(onFocusChangeListener); mToggleStartStopButton.setOnFocusChangeListener(onFocusChangeListener); } private void updateSelector(View focusedView) { int animationDuration = mSelector.getContext().getResources() .getInteger(android.R.integer.config_shortAnimTime); DecelerateInterpolator interpolator = new DecelerateInterpolator(); if (focusedView.hasFocus()) { ViewGroup.LayoutParams lp = mSelector.getLayoutParams(); final int targetWidth = focusedView.getWidth(); float targetTranslationX; if (mLtr) { targetTranslationX = focusedView.getLeft() - mSelector.getLeft(); } else { targetTranslationX = focusedView.getRight() - mSelector.getRight(); } // if the selector is invisible, set the width and translation X directly - // don't animate. if (mSelector.getAlpha() == 0) { mSelector.setTranslationX(targetTranslationX); lp.width = targetWidth; mSelector.requestLayout(); } // animate the selector in and to the proper width and translation X. final float deltaWidth = lp.width - targetWidth; mSelector.animate().cancel(); mSelector.animate().translationX(targetTranslationX).alpha(1f) .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // Set width to the proper width for this animation step. lp.width = targetWidth + Math.round( deltaWidth * (1f - animation.getAnimatedFraction())); mSelector.requestLayout(); } }).setDuration(animationDuration).setInterpolator(interpolator).start(); mLastFocusedView = focusedView; } else if (mLastFocusedView == focusedView) { mSelector.animate().setUpdateListener(null).cancel(); mSelector.animate().alpha(0f).setDuration(animationDuration) .setInterpolator(interpolator).start(); mLastFocusedView = null; } } } } }