blob: 9a4b6f55f617f88c2d45a829390fe56d9bf93819 [file] [log] [blame]
Alan Viverette0ef59ac2015-03-23 13:13:25 -07001/*
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
17package android.widget;
18
19import com.android.internal.widget.PagerAdapter;
20
Alan Viverette60b674e2015-03-25 13:00:42 -070021import android.annotation.IdRes;
22import android.annotation.LayoutRes;
23import android.annotation.NonNull;
24import android.annotation.Nullable;
Alan Viverette0ef59ac2015-03-23 13:13:25 -070025import android.content.Context;
26import android.content.res.ColorStateList;
27import android.content.res.TypedArray;
28import android.util.SparseArray;
Alan Viverette60b674e2015-03-25 13:00:42 -070029import android.view.LayoutInflater;
Alan Viverette0ef59ac2015-03-23 13:13:25 -070030import android.view.View;
31import android.view.ViewGroup;
32import android.widget.SimpleMonthView.OnDayClickListener;
33
34import java.util.Calendar;
35
36/**
37 * An adapter for a list of {@link android.widget.SimpleMonthView} items.
38 */
39class DayPickerAdapter extends PagerAdapter {
40 private static final int MONTHS_IN_YEAR = 12;
41
42 private final Calendar mMinDate = Calendar.getInstance();
43 private final Calendar mMaxDate = Calendar.getInstance();
44
Alan Viverette60b674e2015-03-25 13:00:42 -070045 private final SparseArray<ViewHolder> mItems = new SparseArray<>();
Alan Viverette0ef59ac2015-03-23 13:13:25 -070046
Alan Viverette60b674e2015-03-25 13:00:42 -070047 private final LayoutInflater mInflater;
48 private final int mLayoutResId;
49 private final int mCalendarViewId;
50
51 private Calendar mSelectedDay = null;
Alan Viverette0ef59ac2015-03-23 13:13:25 -070052
53 private int mMonthTextAppearance;
54 private int mDayOfWeekTextAppearance;
55 private int mDayTextAppearance;
56
57 private ColorStateList mCalendarTextColor;
58 private ColorStateList mDaySelectorColor;
59 private ColorStateList mDayHighlightColor;
60
61 private OnDaySelectedListener mOnDaySelectedListener;
62
Alan Viverette60b674e2015-03-25 13:00:42 -070063 private int mCount;
Alan Viverette0ef59ac2015-03-23 13:13:25 -070064 private int mFirstDayOfWeek;
65
Alan Viverette60b674e2015-03-25 13:00:42 -070066 public DayPickerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
67 @IdRes int calendarViewId) {
68 mInflater = LayoutInflater.from(context);
69 mLayoutResId = layoutResId;
70 mCalendarViewId = calendarViewId;
71
Alan Viverette0ef59ac2015-03-23 13:13:25 -070072 final TypedArray ta = context.obtainStyledAttributes(new int[] {
73 com.android.internal.R.attr.colorControlHighlight});
74 mDayHighlightColor = ta.getColorStateList(0);
75 ta.recycle();
76 }
77
Alan Viverette60b674e2015-03-25 13:00:42 -070078 public void setRange(@NonNull Calendar min, @NonNull Calendar max) {
Alan Viverette0ef59ac2015-03-23 13:13:25 -070079 mMinDate.setTimeInMillis(min.getTimeInMillis());
80 mMaxDate.setTimeInMillis(max.getTimeInMillis());
81
Alan Viverette60b674e2015-03-25 13:00:42 -070082 final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
83 final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
84 mCount = diffMonth + MONTHS_IN_YEAR * diffYear + 1;
85
Alan Viverette0ef59ac2015-03-23 13:13:25 -070086 // Positions are now invalid, clear everything and start over.
87 notifyDataSetChanged();
88 }
89
90 /**
91 * Sets the first day of the week.
92 *
93 * @param weekStart which day the week should start on, valid values are
94 * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY}
95 */
96 public void setFirstDayOfWeek(int weekStart) {
97 mFirstDayOfWeek = weekStart;
98
99 // Update displayed views.
100 final int count = mItems.size();
101 for (int i = 0; i < count; i++) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700102 final SimpleMonthView monthView = mItems.valueAt(i).calendar;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700103 monthView.setFirstDayOfWeek(weekStart);
104 }
105 }
106
107 public int getFirstDayOfWeek() {
108 return mFirstDayOfWeek;
109 }
110
111 /**
112 * Sets the selected day.
113 *
114 * @param day the selected day
115 */
Alan Viverette60b674e2015-03-25 13:00:42 -0700116 public void setSelectedDay(@Nullable Calendar day) {
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700117 final int oldPosition = getPositionForDay(mSelectedDay);
118 final int newPosition = getPositionForDay(day);
119
120 // Clear the old position if necessary.
Alan Viverette60b674e2015-03-25 13:00:42 -0700121 if (oldPosition != newPosition && oldPosition >= 0) {
122 final ViewHolder oldMonthView = mItems.get(oldPosition, null);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700123 if (oldMonthView != null) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700124 oldMonthView.calendar.setSelectedDay(-1);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700125 }
126 }
127
128 // Set the new position.
Alan Viverette60b674e2015-03-25 13:00:42 -0700129 if (newPosition >= 0) {
130 final ViewHolder newMonthView = mItems.get(newPosition, null);
131 if (newMonthView != null) {
132 final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
133 newMonthView.calendar.setSelectedDay(dayOfMonth);
134 }
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700135 }
136
137 mSelectedDay = day;
138 }
139
140 /**
141 * Sets the listener to call when the user selects a day.
142 *
143 * @param listener The listener to call.
144 */
145 public void setOnDaySelectedListener(OnDaySelectedListener listener) {
146 mOnDaySelectedListener = listener;
147 }
148
149 void setCalendarTextColor(ColorStateList calendarTextColor) {
150 mCalendarTextColor = calendarTextColor;
151 }
152
153 void setDaySelectorColor(ColorStateList selectorColor) {
154 mDaySelectorColor = selectorColor;
155 }
156
157 void setMonthTextAppearance(int resId) {
158 mMonthTextAppearance = resId;
159 }
160
161 void setDayOfWeekTextAppearance(int resId) {
162 mDayOfWeekTextAppearance = resId;
163 }
164
165 int getDayOfWeekTextAppearance() {
166 return mDayOfWeekTextAppearance;
167 }
168
169 void setDayTextAppearance(int resId) {
170 mDayTextAppearance = resId;
171 }
172
173 int getDayTextAppearance() {
174 return mDayTextAppearance;
175 }
176
177 @Override
178 public int getCount() {
Alan Viverette60b674e2015-03-25 13:00:42 -0700179 return mCount;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700180 }
181
182 @Override
183 public boolean isViewFromObject(View view, Object object) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700184 final ViewHolder holder = (ViewHolder) object;
185 return view == holder.container;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700186 }
187
188 private int getMonthForPosition(int position) {
189 return position % MONTHS_IN_YEAR + mMinDate.get(Calendar.MONTH);
190 }
191
192 private int getYearForPosition(int position) {
193 return position / MONTHS_IN_YEAR + mMinDate.get(Calendar.YEAR);
194 }
195
Alan Viverette60b674e2015-03-25 13:00:42 -0700196 private int getPositionForDay(@Nullable Calendar day) {
197 if (day == null) {
198 return -1;
199 }
200
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700201 final int yearOffset = (day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR));
202 final int monthOffset = (day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH));
203 return yearOffset * MONTHS_IN_YEAR + monthOffset;
204 }
205
206 @Override
207 public Object instantiateItem(ViewGroup container, int position) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700208 final View itemView = mInflater.inflate(mLayoutResId, container, false);
209
210 final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700211 v.setOnDayClickListener(mOnDayClickListener);
212 v.setMonthTextAppearance(mMonthTextAppearance);
213 v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
214 v.setDayTextAppearance(mDayTextAppearance);
215
216 if (mDaySelectorColor != null) {
217 v.setDaySelectorColor(mDaySelectorColor);
218 }
219
220 if (mDayHighlightColor != null) {
221 v.setDayHighlightColor(mDayHighlightColor);
222 }
223
224 if (mCalendarTextColor != null) {
225 v.setMonthTextColor(mCalendarTextColor);
226 v.setDayOfWeekTextColor(mCalendarTextColor);
227 v.setDayTextColor(mCalendarTextColor);
228 }
229
230 final int month = getMonthForPosition(position);
231 final int year = getYearForPosition(position);
232
233 final int selectedDay;
Alan Viverette60b674e2015-03-25 13:00:42 -0700234 if (mSelectedDay != null && mSelectedDay.get(Calendar.MONTH) == month) {
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700235 selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
236 } else {
237 selectedDay = -1;
238 }
239
240 final int enabledDayRangeStart;
241 if (mMinDate.get(Calendar.MONTH) == month && mMinDate.get(Calendar.YEAR) == year) {
242 enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH);
243 } else {
244 enabledDayRangeStart = 1;
245 }
246
247 final int enabledDayRangeEnd;
248 if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) {
249 enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH);
250 } else {
251 enabledDayRangeEnd = 31;
252 }
253
254 v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
255 enabledDayRangeStart, enabledDayRangeEnd);
Alan Viverette60b674e2015-03-25 13:00:42 -0700256 v.setPrevEnabled(position > 0);
257 v.setNextEnabled(position < mCount - 1);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700258
Alan Viverette60b674e2015-03-25 13:00:42 -0700259 final ViewHolder holder = new ViewHolder(position, itemView, v);
260 mItems.put(position, holder);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700261
Alan Viverette60b674e2015-03-25 13:00:42 -0700262 container.addView(itemView);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700263
Alan Viverette60b674e2015-03-25 13:00:42 -0700264 return holder;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700265 }
266
267 @Override
268 public void destroyItem(ViewGroup container, int position, Object object) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700269 final ViewHolder holder = (ViewHolder) object;
270 container.removeView(holder.container);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700271
272 mItems.remove(position);
273 }
274
275 @Override
276 public int getItemPosition(Object object) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700277 final ViewHolder holder = (ViewHolder) object;
278 return holder.position;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700279 }
280
281 @Override
282 public CharSequence getPageTitle(int position) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700283 final SimpleMonthView v = mItems.get(position).calendar;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700284 if (v != null) {
285 return v.getTitle();
286 }
287 return null;
288 }
289
290 private boolean isCalendarInRange(Calendar value) {
291 return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0;
292 }
293
294 private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
295 @Override
296 public void onDayClick(SimpleMonthView view, Calendar day) {
297 if (day != null && isCalendarInRange(day)) {
298 setSelectedDay(day);
299
300 if (mOnDaySelectedListener != null) {
301 mOnDaySelectedListener.onDaySelected(DayPickerAdapter.this, day);
302 }
303 }
304 }
Alan Viverette60b674e2015-03-25 13:00:42 -0700305
306 @Override
307 public void onNavigationClick(SimpleMonthView view, int direction, boolean animate) {
308 if (mOnDaySelectedListener != null) {
309 mOnDaySelectedListener.onNavigationClick(DayPickerAdapter.this, direction, animate);
310 }
311 }
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700312 };
313
Alan Viverette60b674e2015-03-25 13:00:42 -0700314 private static class ViewHolder {
315 public final int position;
316 public final View container;
317 public final SimpleMonthView calendar;
318
319 public ViewHolder(int position, View container, SimpleMonthView calendar) {
320 this.position = position;
321 this.container = container;
322 this.calendar = calendar;
323 }
324 }
325
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700326 public interface OnDaySelectedListener {
327 public void onDaySelected(DayPickerAdapter view, Calendar day);
Alan Viverette60b674e2015-03-25 13:00:42 -0700328 public void onNavigationClick(DayPickerAdapter view, int direction, boolean animate);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700329 }
330}