Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 1 | /* |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 2 | * Copyright (C) 2015 The Android Open Source Project |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 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 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 19 | import com.android.internal.R; |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 20 | import com.android.internal.widget.ViewPager; |
| 21 | import com.android.internal.widget.ViewPager.OnPageChangeListener; |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 22 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 23 | import android.annotation.Nullable; |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 24 | import android.content.Context; |
| 25 | import android.content.res.ColorStateList; |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 26 | import android.content.res.TypedArray; |
| 27 | import android.util.AttributeSet; |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 28 | import android.util.MathUtils; |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 29 | import android.view.LayoutInflater; |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 30 | import android.view.View; |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 31 | import android.view.ViewGroup; |
| 32 | import android.view.accessibility.AccessibilityManager; |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 33 | |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 34 | import java.util.Calendar; |
| 35 | import java.util.Locale; |
| 36 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 37 | import libcore.icu.LocaleData; |
| 38 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 39 | class DayPickerView extends ViewGroup { |
| 40 | private static final int DEFAULT_LAYOUT = R.layout.day_picker_content_material; |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 41 | private static final int DEFAULT_START_YEAR = 1900; |
| 42 | private static final int DEFAULT_END_YEAR = 2100; |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 43 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 44 | private static final int[] ATTRS_TEXT_COLOR = new int[] { R.attr.textColor }; |
| 45 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 46 | private final Calendar mSelectedDay = Calendar.getInstance(); |
| 47 | private final Calendar mMinDate = Calendar.getInstance(); |
| 48 | private final Calendar mMaxDate = Calendar.getInstance(); |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 49 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 50 | private final AccessibilityManager mAccessibilityManager; |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 51 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 52 | private final ViewPager mViewPager; |
| 53 | private final ImageButton mPrevButton; |
| 54 | private final ImageButton mNextButton; |
| 55 | |
| 56 | private final DayPickerPagerAdapter mAdapter; |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 57 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 58 | /** Temporary calendar used for date calculations. */ |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 59 | private Calendar mTempCalendar; |
| 60 | |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 61 | private OnDaySelectedListener mOnDaySelectedListener; |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 62 | |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 63 | public DayPickerView(Context context) { |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 64 | this(context, null); |
| 65 | } |
| 66 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 67 | public DayPickerView(Context context, @Nullable AttributeSet attrs) { |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 68 | this(context, attrs, R.attr.calendarViewStyle); |
| 69 | } |
| 70 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 71 | public DayPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 72 | this(context, attrs, defStyleAttr, 0); |
| 73 | } |
| 74 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 75 | public DayPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, |
| 76 | int defStyleRes) { |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 77 | super(context, attrs, defStyleAttr, defStyleRes); |
| 78 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 79 | mAccessibilityManager = (AccessibilityManager) context.getSystemService( |
| 80 | Context.ACCESSIBILITY_SERVICE); |
| 81 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 82 | final TypedArray a = context.obtainStyledAttributes(attrs, |
| 83 | R.styleable.CalendarView, defStyleAttr, defStyleRes); |
| 84 | |
| 85 | final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek, |
| 86 | LocaleData.get(Locale.getDefault()).firstDayOfWeek); |
| 87 | |
| 88 | final String minDate = a.getString(R.styleable.CalendarView_minDate); |
| 89 | final String maxDate = a.getString(R.styleable.CalendarView_maxDate); |
| 90 | |
| 91 | final int monthTextAppearanceResId = a.getResourceId( |
| 92 | R.styleable.CalendarView_monthTextAppearance, |
| 93 | R.style.TextAppearance_Material_Widget_Calendar_Month); |
| 94 | final int dayOfWeekTextAppearanceResId = a.getResourceId( |
| 95 | R.styleable.CalendarView_weekDayTextAppearance, |
| 96 | R.style.TextAppearance_Material_Widget_Calendar_DayOfWeek); |
| 97 | final int dayTextAppearanceResId = a.getResourceId( |
| 98 | R.styleable.CalendarView_dateTextAppearance, |
| 99 | R.style.TextAppearance_Material_Widget_Calendar_Day); |
| 100 | |
| 101 | final ColorStateList daySelectorColor = a.getColorStateList( |
| 102 | R.styleable.CalendarView_daySelectorColor); |
| 103 | |
| 104 | a.recycle(); |
| 105 | |
| 106 | // Set up adapter. |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 107 | mAdapter = new DayPickerPagerAdapter(context, |
Alan Viverette | 60b674e | 2015-03-25 13:00:42 -0700 | [diff] [blame] | 108 | R.layout.date_picker_month_item_material, R.id.month_view); |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 109 | mAdapter.setMonthTextAppearance(monthTextAppearanceResId); |
| 110 | mAdapter.setDayOfWeekTextAppearance(dayOfWeekTextAppearanceResId); |
| 111 | mAdapter.setDayTextAppearance(dayTextAppearanceResId); |
| 112 | mAdapter.setDaySelectorColor(daySelectorColor); |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 113 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 114 | final LayoutInflater inflater = LayoutInflater.from(context); |
| 115 | final ViewGroup content = (ViewGroup) inflater.inflate(DEFAULT_LAYOUT, this, false); |
| 116 | |
| 117 | // Transfer all children from content to here. |
| 118 | while (content.getChildCount() > 0) { |
| 119 | final View child = content.getChildAt(0); |
| 120 | content.removeViewAt(0); |
| 121 | addView(child); |
| 122 | } |
| 123 | |
| 124 | mPrevButton = (ImageButton) findViewById(R.id.prev); |
| 125 | mPrevButton.setOnClickListener(mOnClickListener); |
| 126 | |
| 127 | mNextButton = (ImageButton) findViewById(R.id.next); |
| 128 | mNextButton.setOnClickListener(mOnClickListener); |
| 129 | |
| 130 | mViewPager = (ViewPager) findViewById(R.id.day_picker_view_pager); |
| 131 | mViewPager.setAdapter(mAdapter); |
| 132 | mViewPager.setOnPageChangeListener(mOnPageChangedListener); |
| 133 | |
| 134 | // Proxy the month text color into the previous and next buttons. |
| 135 | if (monthTextAppearanceResId != 0) { |
| 136 | final TypedArray ta = mContext.obtainStyledAttributes(null, |
| 137 | ATTRS_TEXT_COLOR, 0, monthTextAppearanceResId); |
| 138 | final ColorStateList monthColor = ta.getColorStateList(0); |
| 139 | if (monthColor != null) { |
| 140 | mPrevButton.setImageTintList(monthColor); |
| 141 | mNextButton.setImageTintList(monthColor); |
| 142 | } |
| 143 | ta.recycle(); |
| 144 | } |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 145 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 146 | // Set up min and max dates. |
| 147 | final Calendar tempDate = Calendar.getInstance(); |
| 148 | if (!CalendarView.parseDate(minDate, tempDate)) { |
| 149 | tempDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1); |
| 150 | } |
| 151 | final long minDateMillis = tempDate.getTimeInMillis(); |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 152 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 153 | if (!CalendarView.parseDate(maxDate, tempDate)) { |
| 154 | tempDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31); |
| 155 | } |
| 156 | final long maxDateMillis = tempDate.getTimeInMillis(); |
| 157 | |
| 158 | if (maxDateMillis < minDateMillis) { |
| 159 | throw new IllegalArgumentException("maxDate must be >= minDate"); |
| 160 | } |
| 161 | |
| 162 | final long setDateMillis = MathUtils.constrain( |
| 163 | System.currentTimeMillis(), minDateMillis, maxDateMillis); |
| 164 | |
| 165 | setFirstDayOfWeek(firstDayOfWeek); |
| 166 | setMinDate(minDateMillis); |
| 167 | setMaxDate(maxDateMillis); |
| 168 | setDate(setDateMillis, false); |
| 169 | |
| 170 | // Proxy selection callbacks to our own listener. |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 171 | mAdapter.setOnDaySelectedListener(new DayPickerPagerAdapter.OnDaySelectedListener() { |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 172 | @Override |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 173 | public void onDaySelected(DayPickerPagerAdapter adapter, Calendar day) { |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 174 | if (mOnDaySelectedListener != null) { |
| 175 | mOnDaySelectedListener.onDaySelected(DayPickerView.this, day); |
| 176 | } |
| 177 | } |
| 178 | }); |
| 179 | } |
| 180 | |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 181 | @Override |
| 182 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 183 | final ViewPager viewPager = mViewPager; |
| 184 | measureChild(viewPager, widthMeasureSpec, heightMeasureSpec); |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 185 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 186 | final int measuredWidthAndState = viewPager.getMeasuredWidthAndState(); |
| 187 | final int measuredHeightAndState = viewPager.getMeasuredHeightAndState(); |
| 188 | setMeasuredDimension(measuredWidthAndState, measuredHeightAndState); |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 189 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 190 | final int pagerWidth = viewPager.getMeasuredWidth(); |
| 191 | final int pagerHeight = viewPager.getMeasuredHeight(); |
| 192 | final int buttonWidthSpec = MeasureSpec.makeMeasureSpec(pagerWidth, MeasureSpec.AT_MOST); |
| 193 | final int buttonHeightSpec = MeasureSpec.makeMeasureSpec(pagerHeight, MeasureSpec.AT_MOST); |
| 194 | mPrevButton.measure(buttonWidthSpec, buttonHeightSpec); |
| 195 | mNextButton.measure(buttonWidthSpec, buttonHeightSpec); |
| 196 | } |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 197 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 198 | @Override |
| 199 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { |
| 200 | final ImageButton leftButton = mPrevButton; |
| 201 | final ImageButton rightButton = mNextButton; |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 202 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 203 | final int width = right - left; |
| 204 | final int height = bottom - top; |
| 205 | mViewPager.layout(0, 0, width, height); |
| 206 | |
| 207 | if (mViewPager.getChildCount() < 1) { |
| 208 | leftButton.setVisibility(View.INVISIBLE); |
| 209 | rightButton.setVisibility(View.INVISIBLE); |
| 210 | return; |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 211 | } |
| 212 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 213 | final SimpleMonthView monthView = (SimpleMonthView) mViewPager.getChildAt(0); |
| 214 | final int monthHeight = monthView.getMonthHeight(); |
| 215 | final int cellWidth = monthView.getCellWidth(); |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 216 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 217 | // Vertically center the previous/next buttons within the month |
| 218 | // header, horizontally center within the day cell. |
| 219 | final int leftDW = leftButton.getMeasuredWidth(); |
| 220 | final int leftDH = leftButton.getMeasuredHeight(); |
| 221 | final int leftIconTop = monthView.getPaddingTop() + (monthHeight - leftDH) / 2; |
| 222 | final int leftIconLeft = monthView.getPaddingLeft() + (cellWidth - leftDW) / 2; |
| 223 | leftButton.layout(leftIconLeft, leftIconTop, leftIconLeft + leftDW, leftIconTop + leftDH); |
| 224 | leftButton.setVisibility(View.VISIBLE); |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 225 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 226 | final int rightDW = rightButton.getMeasuredWidth(); |
| 227 | final int rightDH = rightButton.getMeasuredHeight(); |
| 228 | final int rightIconTop = monthView.getPaddingTop() + (monthHeight - rightDH) / 2; |
| 229 | final int rightIconRight = width - monthView.getPaddingRight() - (cellWidth - rightDW) / 2; |
| 230 | rightButton.layout(rightIconRight - rightDW, rightIconTop, |
| 231 | rightIconRight, rightIconTop + rightDH); |
| 232 | rightButton.setVisibility(View.VISIBLE); |
Alan Viverette | 816aa14 | 2015-04-10 15:41:10 -0700 | [diff] [blame] | 233 | } |
| 234 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 235 | public void setDayOfWeekTextAppearance(int resId) { |
| 236 | mAdapter.setDayOfWeekTextAppearance(resId); |
| 237 | } |
| 238 | |
| 239 | public int getDayOfWeekTextAppearance() { |
| 240 | return mAdapter.getDayOfWeekTextAppearance(); |
| 241 | } |
| 242 | |
| 243 | public void setDayTextAppearance(int resId) { |
| 244 | mAdapter.setDayTextAppearance(resId); |
| 245 | } |
| 246 | |
| 247 | public int getDayTextAppearance() { |
| 248 | return mAdapter.getDayTextAppearance(); |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 249 | } |
| 250 | |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 251 | /** |
| 252 | * Sets the currently selected date to the specified timestamp. Jumps |
| 253 | * immediately to the new date. To animate to the new date, use |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 254 | * {@link #setDate(long, boolean)}. |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 255 | * |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 256 | * @param timeInMillis the target day in milliseconds |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 257 | */ |
| 258 | public void setDate(long timeInMillis) { |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 259 | setDate(timeInMillis, false); |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 260 | } |
| 261 | |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 262 | /** |
| 263 | * Sets the currently selected date to the specified timestamp. Jumps |
| 264 | * immediately to the new date, optionally animating the transition. |
| 265 | * |
| 266 | * @param timeInMillis the target day in milliseconds |
| 267 | * @param animate whether to smooth scroll to the new position |
| 268 | */ |
| 269 | public void setDate(long timeInMillis, boolean animate) { |
| 270 | setDate(timeInMillis, animate, true); |
| 271 | } |
| 272 | |
| 273 | /** |
| 274 | * Moves to the month containing the specified day, optionally setting the |
| 275 | * day as selected. |
| 276 | * |
| 277 | * @param timeInMillis the target day in milliseconds |
| 278 | * @param animate whether to smooth scroll to the new position |
| 279 | * @param setSelected whether to set the specified day as selected |
| 280 | */ |
| 281 | private void setDate(long timeInMillis, boolean animate, boolean setSelected) { |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 282 | if (setSelected) { |
| 283 | mSelectedDay.setTimeInMillis(timeInMillis); |
| 284 | } |
| 285 | |
| 286 | final int position = getPositionFromDay(timeInMillis); |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 287 | if (position != mViewPager.getCurrentItem()) { |
| 288 | mViewPager.setCurrentItem(position, animate); |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 289 | } |
Alan Viverette | f63757b | 2015-04-01 17:14:45 -0700 | [diff] [blame] | 290 | |
| 291 | mTempCalendar.setTimeInMillis(timeInMillis); |
| 292 | mAdapter.setSelectedDay(mTempCalendar); |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 293 | } |
| 294 | |
| 295 | public long getDate() { |
| 296 | return mSelectedDay.getTimeInMillis(); |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 297 | } |
| 298 | |
| 299 | public void setFirstDayOfWeek(int firstDayOfWeek) { |
| 300 | mAdapter.setFirstDayOfWeek(firstDayOfWeek); |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 301 | } |
| 302 | |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 303 | public int getFirstDayOfWeek() { |
| 304 | return mAdapter.getFirstDayOfWeek(); |
| 305 | } |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 306 | |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 307 | public void setMinDate(long timeInMillis) { |
| 308 | mMinDate.setTimeInMillis(timeInMillis); |
| 309 | onRangeChanged(); |
| 310 | } |
| 311 | |
| 312 | public long getMinDate() { |
| 313 | return mMinDate.getTimeInMillis(); |
| 314 | } |
| 315 | |
| 316 | public void setMaxDate(long timeInMillis) { |
| 317 | mMaxDate.setTimeInMillis(timeInMillis); |
| 318 | onRangeChanged(); |
| 319 | } |
| 320 | |
| 321 | public long getMaxDate() { |
| 322 | return mMaxDate.getTimeInMillis(); |
| 323 | } |
| 324 | |
| 325 | /** |
| 326 | * Handles changes to date range. |
| 327 | */ |
| 328 | public void onRangeChanged() { |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 329 | mAdapter.setRange(mMinDate, mMaxDate); |
| 330 | |
Alan Viverette | 5ecbfeb | 2014-11-03 18:31:36 -0800 | [diff] [blame] | 331 | // Changing the min/max date changes the selection position since we |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 332 | // don't really have stable IDs. Jumps immediately to the new position. |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 333 | setDate(mSelectedDay.getTimeInMillis(), false, false); |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 334 | } |
| 335 | |
| 336 | /** |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 337 | * Sets the listener to call when the user selects a day. |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 338 | * |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 339 | * @param listener The listener to call. |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 340 | */ |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 341 | public void setOnDaySelectedListener(OnDaySelectedListener listener) { |
| 342 | mOnDaySelectedListener = listener; |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 343 | } |
| 344 | |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 345 | private int getDiffMonths(Calendar start, Calendar end) { |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 346 | final int diffYears = end.get(Calendar.YEAR) - start.get(Calendar.YEAR); |
Alan Viverette | 0ef59ac | 2015-03-23 13:13:25 -0700 | [diff] [blame] | 347 | return end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears; |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 348 | } |
| 349 | |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 350 | private int getPositionFromDay(long timeInMillis) { |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 351 | final int diffMonthMax = getDiffMonths(mMinDate, mMaxDate); |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 352 | final int diffMonth = getDiffMonths(mMinDate, getTempCalendarForTime(timeInMillis)); |
Alan Viverette | 50eb025 | 2014-10-24 14:34:26 -0700 | [diff] [blame] | 353 | return MathUtils.constrain(diffMonth, 0, diffMonthMax); |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 354 | } |
| 355 | |
Alan Viverette | 4612740 | 2014-11-13 10:50:37 -0800 | [diff] [blame] | 356 | private Calendar getTempCalendarForTime(long timeInMillis) { |
| 357 | if (mTempCalendar == null) { |
| 358 | mTempCalendar = Calendar.getInstance(); |
| 359 | } |
| 360 | mTempCalendar.setTimeInMillis(timeInMillis); |
| 361 | return mTempCalendar; |
| 362 | } |
| 363 | |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 364 | /** |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 365 | * Gets the position of the view that is most prominently displayed within the list view. |
| 366 | */ |
| 367 | public int getMostVisiblePosition() { |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 368 | return mViewPager.getCurrentItem(); |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 369 | } |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 370 | |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 371 | public void setPosition(int position) { |
| 372 | mViewPager.setCurrentItem(position, false); |
| 373 | } |
| 374 | |
| 375 | private final OnPageChangeListener mOnPageChangedListener = new OnPageChangeListener() { |
| 376 | @Override |
| 377 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { |
| 378 | final float alpha = Math.abs(0.5f - positionOffset) * 2.0f; |
| 379 | mPrevButton.setAlpha(alpha); |
| 380 | mNextButton.setAlpha(alpha); |
| 381 | } |
| 382 | |
| 383 | @Override |
| 384 | public void onPageScrollStateChanged(int state) {} |
| 385 | |
| 386 | @Override |
| 387 | public void onPageSelected(int position) { |
| 388 | mPrevButton.setVisibility( |
| 389 | position > 0 ? View.VISIBLE : View.INVISIBLE); |
| 390 | mNextButton.setVisibility( |
| 391 | position < (mAdapter.getCount() - 1) ? View.VISIBLE : View.INVISIBLE); |
| 392 | } |
| 393 | }; |
| 394 | |
| 395 | private final OnClickListener mOnClickListener = new OnClickListener() { |
| 396 | @Override |
| 397 | public void onClick(View v) { |
| 398 | final int direction; |
| 399 | if (v == mPrevButton) { |
| 400 | direction = -1; |
| 401 | } else if (v == mNextButton) { |
| 402 | direction = 1; |
| 403 | } else { |
| 404 | return; |
| 405 | } |
| 406 | |
| 407 | // Animation is expensive for accessibility services since it sends |
| 408 | // lots of scroll and content change events. |
| 409 | final boolean animate = !mAccessibilityManager.isEnabled(); |
| 410 | |
| 411 | // ViewPager clamps input values, so we don't need to worry |
| 412 | // about passing invalid indices. |
| 413 | final int nextItem = mViewPager.getCurrentItem() + direction; |
| 414 | mViewPager.setCurrentItem(nextItem, animate); |
| 415 | } |
| 416 | }; |
| 417 | |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 418 | public interface OnDaySelectedListener { |
Alan Viverette | 78bf1d3 | 2015-04-17 10:39:22 -0700 | [diff] [blame] | 419 | void onDaySelected(DayPickerView view, Calendar day); |
Alan Viverette | e763c9b | 2014-11-06 15:22:31 -0800 | [diff] [blame] | 420 | } |
Fabrice Di Meglio | bd9152f | 2013-10-01 11:21:31 -0700 | [diff] [blame] | 421 | } |