/* * 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 android.widget; import com.android.internal.widget.PagerAdapter; import android.annotation.IdRes; import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.icu.util.Calendar; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.SimpleMonthView.OnDayClickListener; /** * An adapter for a list of {@link android.widget.SimpleMonthView} items. */ class DayPickerPagerAdapter extends PagerAdapter { private static final int MONTHS_IN_YEAR = 12; private final Calendar mMinDate = Calendar.getInstance(); private final Calendar mMaxDate = Calendar.getInstance(); private final SparseArray mItems = new SparseArray<>(); private final LayoutInflater mInflater; private final int mLayoutResId; private final int mCalendarViewId; private Calendar mSelectedDay = null; private int mMonthTextAppearance; private int mDayOfWeekTextAppearance; private int mDayTextAppearance; private ColorStateList mCalendarTextColor; private ColorStateList mDaySelectorColor; private ColorStateList mDayHighlightColor; private OnDaySelectedListener mOnDaySelectedListener; private int mCount; private int mFirstDayOfWeek; public DayPickerPagerAdapter(@NonNull Context context, @LayoutRes int layoutResId, @IdRes int calendarViewId) { mInflater = LayoutInflater.from(context); mLayoutResId = layoutResId; mCalendarViewId = calendarViewId; final TypedArray ta = context.obtainStyledAttributes(new int[] { com.android.internal.R.attr.colorControlHighlight}); mDayHighlightColor = ta.getColorStateList(0); ta.recycle(); } public void setRange(@NonNull Calendar min, @NonNull Calendar max) { mMinDate.setTimeInMillis(min.getTimeInMillis()); mMaxDate.setTimeInMillis(max.getTimeInMillis()); final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR); final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH); mCount = diffMonth + MONTHS_IN_YEAR * diffYear + 1; // Positions are now invalid, clear everything and start over. notifyDataSetChanged(); } /** * Sets the first day of the week. * * @param weekStart which day the week should start on, valid values are * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY} */ public void setFirstDayOfWeek(int weekStart) { mFirstDayOfWeek = weekStart; // Update displayed views. final int count = mItems.size(); for (int i = 0; i < count; i++) { final SimpleMonthView monthView = mItems.valueAt(i).calendar; monthView.setFirstDayOfWeek(weekStart); } } public int getFirstDayOfWeek() { return mFirstDayOfWeek; } /** * Sets the selected day. * * @param day the selected day */ public void setSelectedDay(@Nullable Calendar day) { final int oldPosition = getPositionForDay(mSelectedDay); final int newPosition = getPositionForDay(day); // Clear the old position if necessary. if (oldPosition != newPosition && oldPosition >= 0) { final ViewHolder oldMonthView = mItems.get(oldPosition, null); if (oldMonthView != null) { oldMonthView.calendar.setSelectedDay(-1); } } // Set the new position. if (newPosition >= 0) { final ViewHolder newMonthView = mItems.get(newPosition, null); if (newMonthView != null) { final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH); newMonthView.calendar.setSelectedDay(dayOfMonth); } } mSelectedDay = day; } /** * Sets the listener to call when the user selects a day. * * @param listener The listener to call. */ public void setOnDaySelectedListener(OnDaySelectedListener listener) { mOnDaySelectedListener = listener; } void setCalendarTextColor(ColorStateList calendarTextColor) { mCalendarTextColor = calendarTextColor; notifyDataSetChanged(); } void setDaySelectorColor(ColorStateList selectorColor) { mDaySelectorColor = selectorColor; notifyDataSetChanged(); } void setMonthTextAppearance(int resId) { mMonthTextAppearance = resId; notifyDataSetChanged(); } void setDayOfWeekTextAppearance(int resId) { mDayOfWeekTextAppearance = resId; notifyDataSetChanged(); } int getDayOfWeekTextAppearance() { return mDayOfWeekTextAppearance; } void setDayTextAppearance(int resId) { mDayTextAppearance = resId; notifyDataSetChanged(); } int getDayTextAppearance() { return mDayTextAppearance; } @Override public int getCount() { return mCount; } @Override public boolean isViewFromObject(View view, Object object) { final ViewHolder holder = (ViewHolder) object; return view == holder.container; } private int getMonthForPosition(int position) { return (position + mMinDate.get(Calendar.MONTH)) % MONTHS_IN_YEAR; } private int getYearForPosition(int position) { final int yearOffset = (position + mMinDate.get(Calendar.MONTH)) / MONTHS_IN_YEAR; return yearOffset + mMinDate.get(Calendar.YEAR); } private int getPositionForDay(@Nullable Calendar day) { if (day == null) { return -1; } final int yearOffset = day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR); final int monthOffset = day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH); final int position = yearOffset * MONTHS_IN_YEAR + monthOffset; return position; } @Override public Object instantiateItem(ViewGroup container, int position) { final View itemView = mInflater.inflate(mLayoutResId, container, false); final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId); v.setOnDayClickListener(mOnDayClickListener); v.setMonthTextAppearance(mMonthTextAppearance); v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance); v.setDayTextAppearance(mDayTextAppearance); if (mDaySelectorColor != null) { v.setDaySelectorColor(mDaySelectorColor); } if (mDayHighlightColor != null) { v.setDayHighlightColor(mDayHighlightColor); } if (mCalendarTextColor != null) { v.setMonthTextColor(mCalendarTextColor); v.setDayOfWeekTextColor(mCalendarTextColor); v.setDayTextColor(mCalendarTextColor); } final int month = getMonthForPosition(position); final int year = getYearForPosition(position); final int selectedDay; if (mSelectedDay != null && mSelectedDay.get(Calendar.MONTH) == month) { selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH); } else { selectedDay = -1; } final int enabledDayRangeStart; if (mMinDate.get(Calendar.MONTH) == month && mMinDate.get(Calendar.YEAR) == year) { enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH); } else { enabledDayRangeStart = 1; } final int enabledDayRangeEnd; if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) { enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH); } else { enabledDayRangeEnd = 31; } v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek, enabledDayRangeStart, enabledDayRangeEnd); final ViewHolder holder = new ViewHolder(position, itemView, v); mItems.put(position, holder); container.addView(itemView); return holder; } @Override public void destroyItem(ViewGroup container, int position, Object object) { final ViewHolder holder = (ViewHolder) object; container.removeView(holder.container); mItems.remove(position); } @Override public int getItemPosition(Object object) { final ViewHolder holder = (ViewHolder) object; return holder.position; } @Override public CharSequence getPageTitle(int position) { final SimpleMonthView v = mItems.get(position).calendar; if (v != null) { return v.getMonthYearLabel(); } return null; } SimpleMonthView getView(Object object) { if (object == null) { return null; } final ViewHolder holder = (ViewHolder) object; return holder.calendar; } private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() { @Override public void onDayClick(SimpleMonthView view, Calendar day) { if (day != null) { setSelectedDay(day); if (mOnDaySelectedListener != null) { mOnDaySelectedListener.onDaySelected(DayPickerPagerAdapter.this, day); } } } }; private static class ViewHolder { public final int position; public final View container; public final SimpleMonthView calendar; public ViewHolder(int position, View container, SimpleMonthView calendar) { this.position = position; this.container = container; this.calendar = calendar; } } public interface OnDaySelectedListener { public void onDaySelected(DayPickerPagerAdapter view, Calendar day); } }