blob: 57090a59d9a15c3ac7f7ea82527b897df0e205be [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
Alan Viverette60b674e2015-03-25 13:00:42 -070019import android.annotation.IdRes;
20import android.annotation.LayoutRes;
21import android.annotation.NonNull;
22import android.annotation.Nullable;
Alan Viverette0ef59ac2015-03-23 13:13:25 -070023import android.content.Context;
24import android.content.res.ColorStateList;
25import android.content.res.TypedArray;
Aurimas Liutikas99441c52016-10-11 16:48:32 -070026import android.graphics.Rect;
Alan Viverette68763be2016-05-25 11:42:42 -040027import android.icu.util.Calendar;
Alan Viverette0ef59ac2015-03-23 13:13:25 -070028import 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
Aurimas Liutikas99441c52016-10-11 16:48:32 -070034import com.android.internal.widget.PagerAdapter;
35
Alan Viverette0ef59ac2015-03-23 13:13:25 -070036/**
37 * An adapter for a list of {@link android.widget.SimpleMonthView} items.
38 */
Alan Viverette78bf1d32015-04-17 10:39:22 -070039class DayPickerPagerAdapter extends PagerAdapter {
Alan Viverette0ef59ac2015-03-23 13:13:25 -070040 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 Viverette78bf1d32015-04-17 10:39:22 -070066 public DayPickerPagerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
Alan Viverette60b674e2015-03-25 13:00:42 -070067 @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
Kirill Grouchnikov698b7512016-04-11 17:16:52 -0400111 public boolean getBoundsForDate(Calendar day, Rect outBounds) {
112 final int position = getPositionForDay(day);
113 final ViewHolder monthView = mItems.get(position, null);
114 if (monthView == null) {
115 return false;
116 } else {
117 final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
118 return monthView.calendar.getBoundsForDay(dayOfMonth, outBounds);
119 }
120 }
121
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700122 /**
123 * Sets the selected day.
124 *
125 * @param day the selected day
126 */
Alan Viverette60b674e2015-03-25 13:00:42 -0700127 public void setSelectedDay(@Nullable Calendar day) {
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700128 final int oldPosition = getPositionForDay(mSelectedDay);
129 final int newPosition = getPositionForDay(day);
130
131 // Clear the old position if necessary.
Alan Viverette60b674e2015-03-25 13:00:42 -0700132 if (oldPosition != newPosition && oldPosition >= 0) {
133 final ViewHolder oldMonthView = mItems.get(oldPosition, null);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700134 if (oldMonthView != null) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700135 oldMonthView.calendar.setSelectedDay(-1);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700136 }
137 }
138
139 // Set the new position.
Alan Viverette60b674e2015-03-25 13:00:42 -0700140 if (newPosition >= 0) {
141 final ViewHolder newMonthView = mItems.get(newPosition, null);
142 if (newMonthView != null) {
143 final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
144 newMonthView.calendar.setSelectedDay(dayOfMonth);
145 }
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700146 }
147
148 mSelectedDay = day;
149 }
150
151 /**
152 * Sets the listener to call when the user selects a day.
153 *
154 * @param listener The listener to call.
155 */
156 public void setOnDaySelectedListener(OnDaySelectedListener listener) {
157 mOnDaySelectedListener = listener;
158 }
159
160 void setCalendarTextColor(ColorStateList calendarTextColor) {
161 mCalendarTextColor = calendarTextColor;
Alan Viveretted6d9a942016-04-06 16:01:00 -0400162 notifyDataSetChanged();
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700163 }
164
165 void setDaySelectorColor(ColorStateList selectorColor) {
166 mDaySelectorColor = selectorColor;
Alan Viveretted6d9a942016-04-06 16:01:00 -0400167 notifyDataSetChanged();
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700168 }
169
170 void setMonthTextAppearance(int resId) {
171 mMonthTextAppearance = resId;
Alan Viveretted6d9a942016-04-06 16:01:00 -0400172 notifyDataSetChanged();
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700173 }
174
175 void setDayOfWeekTextAppearance(int resId) {
176 mDayOfWeekTextAppearance = resId;
Alan Viveretted6d9a942016-04-06 16:01:00 -0400177 notifyDataSetChanged();
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700178 }
179
180 int getDayOfWeekTextAppearance() {
181 return mDayOfWeekTextAppearance;
182 }
183
184 void setDayTextAppearance(int resId) {
185 mDayTextAppearance = resId;
Alan Viveretted6d9a942016-04-06 16:01:00 -0400186 notifyDataSetChanged();
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700187 }
188
189 int getDayTextAppearance() {
190 return mDayTextAppearance;
191 }
192
193 @Override
194 public int getCount() {
Alan Viverette60b674e2015-03-25 13:00:42 -0700195 return mCount;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700196 }
197
198 @Override
199 public boolean isViewFromObject(View view, Object object) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700200 final ViewHolder holder = (ViewHolder) object;
201 return view == holder.container;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700202 }
203
204 private int getMonthForPosition(int position) {
Alan Viverettebd51b4d2015-05-15 14:18:44 -0700205 return (position + mMinDate.get(Calendar.MONTH)) % MONTHS_IN_YEAR;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700206 }
207
208 private int getYearForPosition(int position) {
Alan Viverettebd51b4d2015-05-15 14:18:44 -0700209 final int yearOffset = (position + mMinDate.get(Calendar.MONTH)) / MONTHS_IN_YEAR;
210 return yearOffset + mMinDate.get(Calendar.YEAR);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700211 }
212
Alan Viverette60b674e2015-03-25 13:00:42 -0700213 private int getPositionForDay(@Nullable Calendar day) {
214 if (day == null) {
215 return -1;
216 }
217
Alan Viverettebd51b4d2015-05-15 14:18:44 -0700218 final int yearOffset = day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
219 final int monthOffset = day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
Alan Viverette78bf1d32015-04-17 10:39:22 -0700220 final int position = yearOffset * MONTHS_IN_YEAR + monthOffset;
221 return position;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700222 }
223
224 @Override
225 public Object instantiateItem(ViewGroup container, int position) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700226 final View itemView = mInflater.inflate(mLayoutResId, container, false);
227
Alan Viverette8e1a7292017-02-27 10:57:58 -0500228 final SimpleMonthView v = itemView.findViewById(mCalendarViewId);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700229 v.setOnDayClickListener(mOnDayClickListener);
230 v.setMonthTextAppearance(mMonthTextAppearance);
231 v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
232 v.setDayTextAppearance(mDayTextAppearance);
233
234 if (mDaySelectorColor != null) {
235 v.setDaySelectorColor(mDaySelectorColor);
236 }
237
238 if (mDayHighlightColor != null) {
239 v.setDayHighlightColor(mDayHighlightColor);
240 }
241
242 if (mCalendarTextColor != null) {
243 v.setMonthTextColor(mCalendarTextColor);
244 v.setDayOfWeekTextColor(mCalendarTextColor);
245 v.setDayTextColor(mCalendarTextColor);
246 }
247
248 final int month = getMonthForPosition(position);
249 final int year = getYearForPosition(position);
250
251 final int selectedDay;
David Ogutu2e654f72018-03-21 10:40:43 -0400252 if (mSelectedDay != null && mSelectedDay.get(Calendar.MONTH) == month && mSelectedDay.get(
253 Calendar.YEAR) == year) {
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700254 selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
255 } else {
256 selectedDay = -1;
257 }
258
259 final int enabledDayRangeStart;
260 if (mMinDate.get(Calendar.MONTH) == month && mMinDate.get(Calendar.YEAR) == year) {
261 enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH);
262 } else {
263 enabledDayRangeStart = 1;
264 }
265
266 final int enabledDayRangeEnd;
267 if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) {
268 enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH);
269 } else {
270 enabledDayRangeEnd = 31;
271 }
272
273 v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
274 enabledDayRangeStart, enabledDayRangeEnd);
275
Alan Viverette60b674e2015-03-25 13:00:42 -0700276 final ViewHolder holder = new ViewHolder(position, itemView, v);
277 mItems.put(position, holder);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700278
Alan Viverette60b674e2015-03-25 13:00:42 -0700279 container.addView(itemView);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700280
Alan Viverette60b674e2015-03-25 13:00:42 -0700281 return holder;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700282 }
283
284 @Override
285 public void destroyItem(ViewGroup container, int position, Object object) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700286 final ViewHolder holder = (ViewHolder) object;
287 container.removeView(holder.container);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700288
289 mItems.remove(position);
290 }
291
292 @Override
293 public int getItemPosition(Object object) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700294 final ViewHolder holder = (ViewHolder) object;
295 return holder.position;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700296 }
297
298 @Override
299 public CharSequence getPageTitle(int position) {
Alan Viverette60b674e2015-03-25 13:00:42 -0700300 final SimpleMonthView v = mItems.get(position).calendar;
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700301 if (v != null) {
Alan Viverettee264f952016-03-04 13:18:48 -0500302 return v.getMonthYearLabel();
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700303 }
304 return null;
305 }
306
George Mounte998c3f2015-10-27 08:46:44 -0700307 SimpleMonthView getView(Object object) {
308 if (object == null) {
309 return null;
310 }
311 final ViewHolder holder = (ViewHolder) object;
312 return holder.calendar;
313 }
314
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700315 private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
316 @Override
317 public void onDayClick(SimpleMonthView view, Calendar day) {
Alan Viverette5c339492015-04-28 14:07:36 -0700318 if (day != null) {
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700319 setSelectedDay(day);
320
321 if (mOnDaySelectedListener != null) {
Alan Viverette78bf1d32015-04-17 10:39:22 -0700322 mOnDaySelectedListener.onDaySelected(DayPickerPagerAdapter.this, day);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700323 }
324 }
325 }
326 };
327
Alan Viverette60b674e2015-03-25 13:00:42 -0700328 private static class ViewHolder {
329 public final int position;
330 public final View container;
331 public final SimpleMonthView calendar;
332
333 public ViewHolder(int position, View container, SimpleMonthView calendar) {
334 this.position = position;
335 this.container = container;
336 this.calendar = calendar;
337 }
338 }
339
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700340 public interface OnDaySelectedListener {
Alan Viverette78bf1d32015-04-17 10:39:22 -0700341 public void onDaySelected(DayPickerPagerAdapter view, Calendar day);
Alan Viverette0ef59ac2015-03-23 13:13:25 -0700342 }
343}