Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2015 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 android.widget;
     18 
     19 import com.android.internal.widget.PagerAdapter;
     20 
     21 import android.annotation.IdRes;
     22 import android.annotation.LayoutRes;
     23 import android.annotation.NonNull;
     24 import android.annotation.Nullable;
     25 import android.content.Context;
     26 import android.content.res.ColorStateList;
     27 import android.content.res.TypedArray;
     28 import android.icu.util.Calendar;
     29 import android.util.SparseArray;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.SimpleMonthView.OnDayClickListener;
     34 
     35 /**
     36  * An adapter for a list of {@link android.widget.SimpleMonthView} items.
     37  */
     38 class DayPickerPagerAdapter extends PagerAdapter {
     39     private static final int MONTHS_IN_YEAR = 12;
     40 
     41     private final Calendar mMinDate = Calendar.getInstance();
     42     private final Calendar mMaxDate = Calendar.getInstance();
     43 
     44     private final SparseArray<ViewHolder> mItems = new SparseArray<>();
     45 
     46     private final LayoutInflater mInflater;
     47     private final int mLayoutResId;
     48     private final int mCalendarViewId;
     49 
     50     private Calendar mSelectedDay = null;
     51 
     52     private int mMonthTextAppearance;
     53     private int mDayOfWeekTextAppearance;
     54     private int mDayTextAppearance;
     55 
     56     private ColorStateList mCalendarTextColor;
     57     private ColorStateList mDaySelectorColor;
     58     private ColorStateList mDayHighlightColor;
     59 
     60     private OnDaySelectedListener mOnDaySelectedListener;
     61 
     62     private int mCount;
     63     private int mFirstDayOfWeek;
     64 
     65     public DayPickerPagerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
     66             @IdRes int calendarViewId) {
     67         mInflater = LayoutInflater.from(context);
     68         mLayoutResId = layoutResId;
     69         mCalendarViewId = calendarViewId;
     70 
     71         final TypedArray ta = context.obtainStyledAttributes(new int[] {
     72                 com.android.internal.R.attr.colorControlHighlight});
     73         mDayHighlightColor = ta.getColorStateList(0);
     74         ta.recycle();
     75     }
     76 
     77     public void setRange(@NonNull Calendar min, @NonNull Calendar max) {
     78         mMinDate.setTimeInMillis(min.getTimeInMillis());
     79         mMaxDate.setTimeInMillis(max.getTimeInMillis());
     80 
     81         final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
     82         final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
     83         mCount = diffMonth + MONTHS_IN_YEAR * diffYear + 1;
     84 
     85         // Positions are now invalid, clear everything and start over.
     86         notifyDataSetChanged();
     87     }
     88 
     89     /**
     90      * Sets the first day of the week.
     91      *
     92      * @param weekStart which day the week should start on, valid values are
     93      *                  {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY}
     94      */
     95     public void setFirstDayOfWeek(int weekStart) {
     96         mFirstDayOfWeek = weekStart;
     97 
     98         // Update displayed views.
     99         final int count = mItems.size();
    100         for (int i = 0; i < count; i++) {
    101             final SimpleMonthView monthView = mItems.valueAt(i).calendar;
    102             monthView.setFirstDayOfWeek(weekStart);
    103         }
    104     }
    105 
    106     public int getFirstDayOfWeek() {
    107         return mFirstDayOfWeek;
    108     }
    109 
    110     /**
    111      * Sets the selected day.
    112      *
    113      * @param day the selected day
    114      */
    115     public void setSelectedDay(@Nullable Calendar day) {
    116         final int oldPosition = getPositionForDay(mSelectedDay);
    117         final int newPosition = getPositionForDay(day);
    118 
    119         // Clear the old position if necessary.
    120         if (oldPosition != newPosition && oldPosition >= 0) {
    121             final ViewHolder oldMonthView = mItems.get(oldPosition, null);
    122             if (oldMonthView != null) {
    123                 oldMonthView.calendar.setSelectedDay(-1);
    124             }
    125         }
    126 
    127         // Set the new position.
    128         if (newPosition >= 0) {
    129             final ViewHolder newMonthView = mItems.get(newPosition, null);
    130             if (newMonthView != null) {
    131                 final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
    132                 newMonthView.calendar.setSelectedDay(dayOfMonth);
    133             }
    134         }
    135 
    136         mSelectedDay = day;
    137     }
    138 
    139     /**
    140      * Sets the listener to call when the user selects a day.
    141      *
    142      * @param listener The listener to call.
    143      */
    144     public void setOnDaySelectedListener(OnDaySelectedListener listener) {
    145         mOnDaySelectedListener = listener;
    146     }
    147 
    148     void setCalendarTextColor(ColorStateList calendarTextColor) {
    149         mCalendarTextColor = calendarTextColor;
    150         notifyDataSetChanged();
    151     }
    152 
    153     void setDaySelectorColor(ColorStateList selectorColor) {
    154         mDaySelectorColor = selectorColor;
    155         notifyDataSetChanged();
    156     }
    157 
    158     void setMonthTextAppearance(int resId) {
    159         mMonthTextAppearance = resId;
    160         notifyDataSetChanged();
    161     }
    162 
    163     void setDayOfWeekTextAppearance(int resId) {
    164         mDayOfWeekTextAppearance = resId;
    165         notifyDataSetChanged();
    166     }
    167 
    168     int getDayOfWeekTextAppearance() {
    169         return mDayOfWeekTextAppearance;
    170     }
    171 
    172     void setDayTextAppearance(int resId) {
    173         mDayTextAppearance = resId;
    174         notifyDataSetChanged();
    175     }
    176 
    177     int getDayTextAppearance() {
    178         return mDayTextAppearance;
    179     }
    180 
    181     @Override
    182     public int getCount() {
    183         return mCount;
    184     }
    185 
    186     @Override
    187     public boolean isViewFromObject(View view, Object object) {
    188         final ViewHolder holder = (ViewHolder) object;
    189         return view == holder.container;
    190     }
    191 
    192     private int getMonthForPosition(int position) {
    193         return (position + mMinDate.get(Calendar.MONTH)) % MONTHS_IN_YEAR;
    194     }
    195 
    196     private int getYearForPosition(int position) {
    197         final int yearOffset = (position + mMinDate.get(Calendar.MONTH)) / MONTHS_IN_YEAR;
    198         return yearOffset + mMinDate.get(Calendar.YEAR);
    199     }
    200 
    201     private int getPositionForDay(@Nullable Calendar day) {
    202         if (day == null) {
    203             return -1;
    204         }
    205 
    206         final int yearOffset = day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
    207         final int monthOffset = day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
    208         final int position = yearOffset * MONTHS_IN_YEAR + monthOffset;
    209         return position;
    210     }
    211 
    212     @Override
    213     public Object instantiateItem(ViewGroup container, int position) {
    214         final View itemView = mInflater.inflate(mLayoutResId, container, false);
    215 
    216         final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId);
    217         v.setOnDayClickListener(mOnDayClickListener);
    218         v.setMonthTextAppearance(mMonthTextAppearance);
    219         v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
    220         v.setDayTextAppearance(mDayTextAppearance);
    221 
    222         if (mDaySelectorColor != null) {
    223             v.setDaySelectorColor(mDaySelectorColor);
    224         }
    225 
    226         if (mDayHighlightColor != null) {
    227             v.setDayHighlightColor(mDayHighlightColor);
    228         }
    229 
    230         if (mCalendarTextColor != null) {
    231             v.setMonthTextColor(mCalendarTextColor);
    232             v.setDayOfWeekTextColor(mCalendarTextColor);
    233             v.setDayTextColor(mCalendarTextColor);
    234         }
    235 
    236         final int month = getMonthForPosition(position);
    237         final int year = getYearForPosition(position);
    238 
    239         final int selectedDay;
    240         if (mSelectedDay != null && mSelectedDay.get(Calendar.MONTH) == month) {
    241             selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
    242         } else {
    243             selectedDay = -1;
    244         }
    245 
    246         final int enabledDayRangeStart;
    247         if (mMinDate.get(Calendar.MONTH) == month && mMinDate.get(Calendar.YEAR) == year) {
    248             enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH);
    249         } else {
    250             enabledDayRangeStart = 1;
    251         }
    252 
    253         final int enabledDayRangeEnd;
    254         if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) {
    255             enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH);
    256         } else {
    257             enabledDayRangeEnd = 31;
    258         }
    259 
    260         v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
    261                 enabledDayRangeStart, enabledDayRangeEnd);
    262 
    263         final ViewHolder holder = new ViewHolder(position, itemView, v);
    264         mItems.put(position, holder);
    265 
    266         container.addView(itemView);
    267 
    268         return holder;
    269     }
    270 
    271     @Override
    272     public void destroyItem(ViewGroup container, int position, Object object) {
    273         final ViewHolder holder = (ViewHolder) object;
    274         container.removeView(holder.container);
    275 
    276         mItems.remove(position);
    277     }
    278 
    279     @Override
    280     public int getItemPosition(Object object) {
    281         final ViewHolder holder = (ViewHolder) object;
    282         return holder.position;
    283     }
    284 
    285     @Override
    286     public CharSequence getPageTitle(int position) {
    287         final SimpleMonthView v = mItems.get(position).calendar;
    288         if (v != null) {
    289             return v.getMonthYearLabel();
    290         }
    291         return null;
    292     }
    293 
    294     SimpleMonthView getView(Object object) {
    295         if (object == null) {
    296             return null;
    297         }
    298         final ViewHolder holder = (ViewHolder) object;
    299         return holder.calendar;
    300     }
    301 
    302     private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
    303         @Override
    304         public void onDayClick(SimpleMonthView view, Calendar day) {
    305             if (day != null) {
    306                 setSelectedDay(day);
    307 
    308                 if (mOnDaySelectedListener != null) {
    309                     mOnDaySelectedListener.onDaySelected(DayPickerPagerAdapter.this, day);
    310                 }
    311             }
    312         }
    313     };
    314 
    315     private static class ViewHolder {
    316         public final int position;
    317         public final View container;
    318         public final SimpleMonthView calendar;
    319 
    320         public ViewHolder(int position, View container, SimpleMonthView calendar) {
    321             this.position = position;
    322             this.container = container;
    323             this.calendar = calendar;
    324         }
    325     }
    326 
    327     public interface OnDaySelectedListener {
    328         public void onDaySelected(DayPickerPagerAdapter view, Calendar day);
    329     }
    330 }
    331