| /* |
| * 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 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.graphics.Rect; |
| 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; |
| |
| import com.android.internal.widget.PagerAdapter; |
| |
| /** |
| * 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<ViewHolder> 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; |
| } |
| |
| public boolean getBoundsForDate(Calendar day, Rect outBounds) { |
| final int position = getPositionForDay(day); |
| final ViewHolder monthView = mItems.get(position, null); |
| if (monthView == null) { |
| return false; |
| } else { |
| final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH); |
| return monthView.calendar.getBoundsForDay(dayOfMonth, outBounds); |
| } |
| } |
| |
| /** |
| * 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 = 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); |
| } |
| } |