blob: dfbfc43289f82899c1dd4c40962d73f716ee5870 [file] [log] [blame]
/*
* Copyright (C) 2015 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.deskclock.alarms.dataadapter;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.deskclock.AnimatorUtils;
import com.android.deskclock.ItemAdapter;
import com.android.deskclock.R;
import com.android.deskclock.data.DataModel;
import com.android.deskclock.data.Weekdays;
import com.android.deskclock.events.Events;
import com.android.deskclock.provider.Alarm;
import com.android.deskclock.provider.AlarmInstance;
import java.util.Calendar;
import java.util.List;
/**
* A ViewHolder containing views for an alarm item in collapsed stated.
*/
public final class CollapsedAlarmViewHolder extends AlarmItemViewHolder {
public static final int VIEW_TYPE = R.layout.alarm_time_collapsed;
private final TextView alarmLabel;
public final TextView daysOfWeek;
private final TextView upcomingInstanceLabel;
private final View hairLine;
private CollapsedAlarmViewHolder(View itemView) {
super(itemView);
alarmLabel = (TextView) itemView.findViewById(R.id.label);
daysOfWeek = (TextView) itemView.findViewById(R.id.days_of_week);
upcomingInstanceLabel = (TextView) itemView.findViewById(R.id.upcoming_instance_label);
hairLine = itemView.findViewById(R.id.hairline);
// Expand handler
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Events.sendAlarmEvent(R.string.action_expand_implied, R.string.label_deskclock);
getItemHolder().expand();
}
});
alarmLabel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Events.sendAlarmEvent(R.string.action_expand_implied, R.string.label_deskclock);
getItemHolder().expand();
}
});
arrow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Events.sendAlarmEvent(R.string.action_expand, R.string.label_deskclock);
getItemHolder().expand();
}
});
// Edit time handler
clock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getItemHolder().getAlarmTimeClickHandler().onClockClicked(getItemHolder().item);
Events.sendAlarmEvent(R.string.action_expand_implied, R.string.label_deskclock);
getItemHolder().expand();
}
});
itemView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
@Override
protected void onBindItemView(AlarmItemHolder itemHolder) {
super.onBindItemView(itemHolder);
final Alarm alarm = itemHolder.item;
final AlarmInstance alarmInstance = itemHolder.getAlarmInstance();
final Context context = itemView.getContext();
bindRepeatText(context, alarm);
bindReadOnlyLabel(context, alarm);
bindUpcomingInstance(context, alarm);
bindPreemptiveDismissButton(context, alarm, alarmInstance);
}
private void bindReadOnlyLabel(Context context, Alarm alarm) {
if (alarm.label != null && alarm.label.length() != 0) {
alarmLabel.setText(alarm.label);
alarmLabel.setVisibility(View.VISIBLE);
alarmLabel.setContentDescription(context.getString(R.string.label_description)
+ " " + alarm.label);
} else {
alarmLabel.setVisibility(View.GONE);
}
}
private void bindRepeatText(Context context, Alarm alarm) {
if (alarm.daysOfWeek.isRepeating()) {
final Weekdays.Order weekdayOrder = DataModel.getDataModel().getWeekdayOrder();
final String daysOfWeekText = alarm.daysOfWeek.toString(context, weekdayOrder);
daysOfWeek.setText(daysOfWeekText);
final String string = alarm.daysOfWeek.toAccessibilityString(context, weekdayOrder);
daysOfWeek.setContentDescription(string);
daysOfWeek.setVisibility(View.VISIBLE);
} else {
daysOfWeek.setVisibility(View.GONE);
}
}
private void bindUpcomingInstance(Context context, Alarm alarm) {
if (alarm.daysOfWeek.isRepeating()) {
upcomingInstanceLabel.setVisibility(View.GONE);
} else {
upcomingInstanceLabel.setVisibility(View.VISIBLE);
final String labelText = Alarm.isTomorrow(alarm, Calendar.getInstance()) ?
context.getString(R.string.alarm_tomorrow) :
context.getString(R.string.alarm_today);
upcomingInstanceLabel.setText(labelText);
}
}
@Override
public Animator onAnimateChange(List<Object> payloads, int fromLeft, int fromTop, int fromRight,
int fromBottom, long duration) {
/* There are no possible partial animations for collapsed view holders. */
return null;
}
@Override
public Animator onAnimateChange(final ViewHolder oldHolder, ViewHolder newHolder,
long duration) {
if (!(oldHolder instanceof AlarmItemViewHolder)
|| !(newHolder instanceof AlarmItemViewHolder)) {
return null;
}
final boolean isCollapsing = this == newHolder;
setChangingViewsAlpha(isCollapsing ? 0f : 1f);
final Animator changeAnimatorSet = isCollapsing
? createCollapsingAnimator((AlarmItemViewHolder) oldHolder, duration)
: createExpandingAnimator((AlarmItemViewHolder) newHolder, duration);
changeAnimatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
clock.setVisibility(View.VISIBLE);
onOff.setVisibility(View.VISIBLE);
arrow.setVisibility(View.VISIBLE);
arrow.setTranslationY(0f);
setChangingViewsAlpha(1f);
arrow.jumpDrawablesToCurrentState();
}
});
return changeAnimatorSet;
}
private Animator createExpandingAnimator(AlarmItemViewHolder newHolder, long duration) {
clock.setVisibility(View.INVISIBLE);
onOff.setVisibility(View.INVISIBLE);
arrow.setVisibility(View.INVISIBLE);
final AnimatorSet alphaAnimatorSet = new AnimatorSet();
alphaAnimatorSet.playTogether(
ObjectAnimator.ofFloat(alarmLabel, View.ALPHA, 0f),
ObjectAnimator.ofFloat(daysOfWeek, View.ALPHA, 0f),
ObjectAnimator.ofFloat(upcomingInstanceLabel, View.ALPHA, 0f),
ObjectAnimator.ofFloat(preemptiveDismissButton, View.ALPHA, 0f),
ObjectAnimator.ofFloat(hairLine, View.ALPHA, 0f));
alphaAnimatorSet.setDuration((long) (duration * ANIM_SHORT_DURATION_MULTIPLIER));
final View oldView = itemView;
final View newView = newHolder.itemView;
final Animator boundsAnimator = AnimatorUtils.getBoundsAnimator(oldView, oldView, newView)
.setDuration(duration);
boundsAnimator.setInterpolator(AnimatorUtils.INTERPOLATOR_FAST_OUT_SLOW_IN);
final AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(alphaAnimatorSet, boundsAnimator);
return animatorSet;
}
private Animator createCollapsingAnimator(AlarmItemViewHolder oldHolder, long duration) {
final AnimatorSet alphaAnimatorSet = new AnimatorSet();
alphaAnimatorSet.playTogether(
ObjectAnimator.ofFloat(alarmLabel, View.ALPHA, 1f),
ObjectAnimator.ofFloat(daysOfWeek, View.ALPHA, 1f),
ObjectAnimator.ofFloat(upcomingInstanceLabel, View.ALPHA, 1f),
ObjectAnimator.ofFloat(preemptiveDismissButton, View.ALPHA, 1f),
ObjectAnimator.ofFloat(hairLine, View.ALPHA, 1f));
final long standardDelay = (long) (duration * ANIM_STANDARD_DELAY_MULTIPLIER);
alphaAnimatorSet.setDuration(standardDelay);
alphaAnimatorSet.setStartDelay(duration - standardDelay);
final View oldView = oldHolder.itemView;
final View newView = itemView;
final Animator boundsAnimator = AnimatorUtils.getBoundsAnimator(newView, oldView, newView)
.setDuration(duration);
boundsAnimator.setInterpolator(AnimatorUtils.INTERPOLATOR_FAST_OUT_SLOW_IN);
final View oldArrow = oldHolder.arrow;
final Rect oldArrowRect = new Rect(0, 0, oldArrow.getWidth(), oldArrow.getHeight());
final Rect newArrowRect = new Rect(0, 0, arrow.getWidth(), arrow.getHeight());
((ViewGroup) newView).offsetDescendantRectToMyCoords(arrow, newArrowRect);
((ViewGroup) oldView).offsetDescendantRectToMyCoords(oldArrow, oldArrowRect);
final float arrowTranslationY = oldArrowRect.bottom - newArrowRect.bottom;
arrow.setTranslationY(arrowTranslationY);
arrow.setVisibility(View.VISIBLE);
clock.setVisibility(View.VISIBLE);
onOff.setVisibility(View.VISIBLE);
final Animator arrowAnimation = ObjectAnimator.ofFloat(arrow, View.TRANSLATION_Y, 0f)
.setDuration(duration);
arrowAnimation.setInterpolator(AnimatorUtils.INTERPOLATOR_FAST_OUT_SLOW_IN);
final AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(alphaAnimatorSet, boundsAnimator, arrowAnimation);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
AnimatorUtils.startDrawableAnimation(arrow);
}
});
return animatorSet;
}
private void setChangingViewsAlpha(float alpha) {
alarmLabel.setAlpha(alpha);
daysOfWeek.setAlpha(alpha);
upcomingInstanceLabel.setAlpha(alpha);
hairLine.setAlpha(alpha);
preemptiveDismissButton.setAlpha(alpha);
}
public static class Factory implements ItemAdapter.ItemViewHolder.Factory {
private final LayoutInflater mLayoutInflater;
public Factory(LayoutInflater layoutInflater) {
mLayoutInflater = layoutInflater;
}
@Override
public ItemAdapter.ItemViewHolder<?> createViewHolder(ViewGroup parent, int viewType) {
return new CollapsedAlarmViewHolder(mLayoutInflater.inflate(
viewType, parent, false /* attachToRoot */));
}
}
}