From 1cca69a6fffb227d9ca0a4a9c9275e0700e3a1f7 Mon Sep 17 00:00:00 2001 From: Brenden Kromhout Date: Wed, 19 Jun 2013 19:34:11 -0400 Subject: [PATCH] CalendarView.java updated to fix various drawing bugs I've added comments to all of the changed areas to explain why I made the changes and what bugs the changes fix. I've tested the changes extensively. Here's the edge case example I mentioned in my comments: Obviously, the loop in WeekView.init() used to populate the mDayNumbers[] array increments mTempDate by EXACTLY one day each time it executes. This can cause a bug when mTempDate finally increments to be the same day as mMaxDate. To better explain the bug, here's an example. Say the time of day of mMinDate is 5:00pm, and the time of day of mMaxDate is 3:00pm. When mTempDate is finally incremented enough that it is the same DAY as mMaxdate, its time of day is still 2 hours past the time of day of mMaxDate. Due to this, even though the day number of mTempDate SHOULD be drawn, the original code won't draw it, because the boolean expression used in the aforementioned loop only tests to see if mTempDate is after mMaxDate. To fix this, the loop now also tests to see if mTempDate is the same day as mMaxDate (Using the already existing isSameDate() method). This ensures that the day number for mMaxDate is drawn even if the time of day of mTempDate puts mTempDate after mMaxDate, so long as mTempDate and mMaxDate have the same DAY_OF_YEAR and YEAR values. The reason WeeksAdapter.onTouch() was modified was because otherwise even though the number is drawn, we still wouldn't be able to select it for the same reasons given above. Apologies for this explanation being so lengthy. --- .../simonvt/calendarview/CalendarView.java | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/library/src/net/simonvt/calendarview/CalendarView.java b/library/src/net/simonvt/calendarview/CalendarView.java index 72409fe..96748ea 100644 --- a/library/src/net/simonvt/calendarview/CalendarView.java +++ b/library/src/net/simonvt/calendarview/CalendarView.java @@ -1005,6 +1005,17 @@ private boolean isSameDate(Calendar firstDate, Calendar secondDate) { && firstDate.get(Calendar.YEAR) == secondDate.get(Calendar.YEAR)); } + /** + * @return True if the weeks of firstDate and secondDate + * are the same. + * Used in WeeksAdapter.init() + * @author Brenden K. + */ + private boolean isSameWeek(Calendar firstDate, Calendar secondDate) { + return (firstDate.get(Calendar.WEEK_OF_YEAR) == secondDate.get(Calendar.WEEK_OF_YEAR) + && firstDate.get(Calendar.YEAR) == secondDate.get(Calendar.YEAR)); + } + /** * Creates a new adapter if necessary and sets up its parameters. */ @@ -1211,7 +1222,17 @@ private void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCou // the top of the screen when scrolling down. int offset = child.getBottom() < mWeekMinVisibleHeight ? 1 : 0; if (mIsScrollingUp) { - child = (WeekView) view.getChildAt(SCROLL_HYST_WEEKS + offset); + // Fixes crashes that occur if the spanned amount of time between + // the min and max dates is either one or two weeks. If the spanned + // amount of time is over two weeks, the original behavior occurs. + // -Brenden K. + if(mAdapter.getCount() == 1) { + child = (WeekView) view.getChildAt(0); + } else if(mAdapter.getCount() == 2) { + child = (WeekView) view.getChildAt(1); + } else { // Original behavior + child = (WeekView) view.getChildAt(SCROLL_HYST_WEEKS + offset); + } } else if (offset != 0) { child = (WeekView) view.getChildAt(offset); } @@ -1363,8 +1384,20 @@ public WeeksAdapter(Context context) { private void init() { mSelectedWeek = getWeeksSinceMinDate(mSelectedDate); mTotalWeekCount = getWeeksSinceMinDate(mMaxDate); - if (mMinDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek - || mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) { + // Changed to ensure proper number of WeekViews are drawn for circumstances where + // getWeeksSinceMinDate(Calendar date) returns a number that is short by one. + // Otherwise even though the onScroll() method doesn't cause a crash, we still don't + // draw all of the weeks we need. + // -Brenden K. + if (!(mMinDate.get(Calendar.DAY_OF_WEEK) == mFirstDayOfWeek)) { + // Ensures we add a week so long as the min date isn't the first day of the week + mTotalWeekCount++; + } else if (isSameWeek(mMinDate, mMaxDate)) { + // Ensures we add a week if the min and max are in the same week + mTotalWeekCount++; + } else if(mMinDate.get(Calendar.DAY_OF_WEEK) == mFirstDayOfWeek + && mMaxDate.get(Calendar.DAY_OF_WEEK) == mFirstDayOfWeek) { + // Ensures we add a week if both the min and max date are the first day of a week mTotalWeekCount++; } } @@ -1452,7 +1485,12 @@ public boolean onTouch(View v, MotionEvent event) { } // it is possible that the touched day is outside the valid range // we draw whole weeks but range end can fall not on the week end - if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) { + + // Fix so that our edge case can be selected (See WeekView.init() + // for more details about the edge case) + // -Brenden K. + if ((mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) + && !(isSameDate(mTempDate, mMaxDate))) { return true; } onDateTapped(mTempDate); @@ -1599,7 +1637,14 @@ public void init(int weekNumber, int selectedWeekDay, int focusedMonth) { mHasFocusedDay |= isFocusedDay; mHasUnfocusedDay &= !isFocusedDay; // do not draw dates outside the valid range to avoid user confusion - if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) { + + // This is our edge case. See the extended description for this commit + // for an explanation, as it is rather long. The modification made to + // the boolean expression in WeeksAdapter.onTouch() was done so that + // it matched the boolean expression used below. + // -Brenden K. + if ((mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) + && !(isSameDate(mTempDate, mMaxDate))) { mDayNumbers[i] = ""; } else { mDayNumbers[i] = String.format(Locale.getDefault(), "%d",