diff options
Diffstat (limited to 'android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/CalendarView.java')
-rw-r--r-- | android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/CalendarView.java | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/CalendarView.java b/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/CalendarView.java new file mode 100644 index 0000000000..4441869351 --- /dev/null +++ b/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/CalendarView.java @@ -0,0 +1,906 @@ + +package org.holoeverywhere.widget; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Locale; + +import org.holoeverywhere.FontLoader; +import org.holoeverywhere.LayoutInflater; +import org.holoeverywhere.R; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Paint.Style; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build.VERSION; +import android.text.TextUtils; +import android.text.format.DateUtils; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.BaseAdapter; + +public class CalendarView extends FrameLayout { + public interface OnDateChangeListener { + public void onSelectedDayChange(CalendarView view, int year, int month, + int dayOfMonth); + } + + private class ScrollStateRunnable implements Runnable { + private int mNewState; + private AbsListView mView; + + public void doScrollStateChange(AbsListView view, int scrollState) { + mView = view; + mNewState = scrollState; + removeCallbacks(this); + postDelayed(this, CalendarView.SCROLL_CHANGE_DELAY); + } + + @Override + @SuppressLint("NewApi") + public void run() { + mCurrentScrollState = mNewState; + if (mNewState == OnScrollListener.SCROLL_STATE_IDLE + && mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE) { + View child = mView.getChildAt(0); + if (child == null) { + return; + } + int dist = child.getBottom() - mListScrollTopOffset; + if (dist > mListScrollTopOffset) { + int y = dist - (mIsScrollingUp ? child.getHeight() : 0); + if (VERSION.SDK_INT >= 11) { + mView.smoothScrollBy(y, + CalendarView.ADJUSTMENT_SCROLL_DURATION); + } else { + mView.scrollBy(0, y); + } + } + } + mPreviousScrollState = mNewState; + } + } + + private class WeeksAdapter extends BaseAdapter implements OnTouchListener { + class CalendarGestureListener extends + GestureDetector.SimpleOnGestureListener { + @Override + public boolean onSingleTapUp(MotionEvent e) { + return true; + } + } + + private Context context; + private int mFocusedMonth; + private GestureDetector mGestureDetector; + private final Calendar mSelectedDate = Calendar.getInstance(); + private int mSelectedWeek; + private int mTotalWeekCount; + + public WeeksAdapter(Context context) { + this.context = context; + mGestureDetector = new GestureDetector(context, + new CalendarGestureListener()); + init(); + } + + @Override + public int getCount() { + return mTotalWeekCount; + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return position; + } + + public Calendar getSelectedDay() { + return mSelectedDate; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + WeekView weekView = null; + if (convertView != null) { + weekView = (WeekView) convertView; + } else { + weekView = new WeekView(context); + android.widget.AbsListView.LayoutParams params = new android.widget.AbsListView.LayoutParams( + android.view.ViewGroup.LayoutParams.WRAP_CONTENT, + android.view.ViewGroup.LayoutParams.WRAP_CONTENT); + weekView.setLayoutParams(params); + weekView.setClickable(true); + weekView.setOnTouchListener(this); + } + + int selectedWeekDay = mSelectedWeek == position ? mSelectedDate + .get(Calendar.DAY_OF_WEEK) : -1; + weekView.init(position, selectedWeekDay, mFocusedMonth); + + return weekView; + } + + private void init() { + mSelectedWeek = getWeeksSinceMinDate(mSelectedDate); + mTotalWeekCount = getWeeksSinceMinDate(mMaxDate); + if (mMinDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek + || mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) { + mTotalWeekCount++; + } + } + + private void onDateTapped(Calendar day) { + setSelectedDay(day); + setMonthDisplayed(day); + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + if (mListView.isEnabled() && mGestureDetector.onTouchEvent(event)) { + WeekView weekView = (WeekView) v; + if (!weekView.getDayFromLocation(event.getX(), mTempDate)) { + return true; + } + if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) { + return true; + } + onDateTapped(mTempDate); + return true; + } + return false; + } + + public void setFocusMonth(int month) { + if (mFocusedMonth == month) { + return; + } + mFocusedMonth = month; + notifyDataSetChanged(); + } + + public void setSelectedDay(Calendar selectedDay) { + if (selectedDay.get(Calendar.DAY_OF_YEAR) == mSelectedDate + .get(Calendar.DAY_OF_YEAR) + && selectedDay.get(Calendar.YEAR) == mSelectedDate + .get(Calendar.YEAR)) { + return; + } + mSelectedDate.setTimeInMillis(selectedDay.getTimeInMillis()); + mSelectedWeek = getWeeksSinceMinDate(mSelectedDate); + mFocusedMonth = mSelectedDate.get(Calendar.MONTH); + notifyDataSetChanged(); + } + } + + private class WeekView extends View { + private String[] mDayNumbers; + private final Paint mDrawPaint = new Paint(); + private Calendar mFirstDay; + private boolean[] mFocusDay; + private boolean mHasSelectedDay = false; + private int mHeight; + private int mLastWeekDayMonth = -1; + private final Paint mMonthNumDrawPaint = new Paint(); + private int mMonthOfFirstWeekDay = -1; + private int mNumCells; + private int mSelectedDay = -1; + private int mSelectedLeft = -1; + private int mSelectedRight = -1; + private final Rect mTempRect = new Rect(); + private int mWeek = -1; + private int mWidth; + + public WeekView(Context context) { + super(context); + + mHeight = (mListView.getHeight() - mListView.getPaddingTop() - mListView + .getPaddingBottom()) / mShownWeekCount; + setPaintProperties(); + } + + private void drawBackground(Canvas canvas) { + if (!mHasSelectedDay) { + return; + } + mDrawPaint.setColor(mSelectedWeekBackgroundColor); + mTempRect.top = mWeekSeperatorLineWidth; + mTempRect.bottom = mHeight; + mTempRect.left = mShowWeekNumber ? mWidth / mNumCells : 0; + mTempRect.right = mSelectedLeft - 2; + canvas.drawRect(mTempRect, mDrawPaint); + mTempRect.left = mSelectedRight + 3; + mTempRect.right = mWidth; + canvas.drawRect(mTempRect, mDrawPaint); + } + + private void drawSelectedDateVerticalBars(Canvas canvas) { + if (!mHasSelectedDay) { + return; + } + mSelectedDateVerticalBar.setBounds(mSelectedLeft + - mSelectedDateVerticalBarWidth / 2, + mWeekSeperatorLineWidth, mSelectedLeft + + mSelectedDateVerticalBarWidth / 2, mHeight); + mSelectedDateVerticalBar.draw(canvas); + mSelectedDateVerticalBar.setBounds(mSelectedRight + - mSelectedDateVerticalBarWidth / 2, + mWeekSeperatorLineWidth, mSelectedRight + + mSelectedDateVerticalBarWidth / 2, mHeight); + mSelectedDateVerticalBar.draw(canvas); + } + + private void drawWeekNumbers(Canvas canvas) { + float textHeight = mDrawPaint.getTextSize(); + int y = (int) ((mHeight + textHeight) / 2) + - mWeekSeperatorLineWidth; + int nDays = mNumCells; + + mDrawPaint.setTextAlign(Align.CENTER); + int i = 0; + int divisor = 2 * nDays; + if (mShowWeekNumber) { + mDrawPaint.setColor(mWeekNumberColor); + int x = mWidth / divisor; + canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); + i++; + } + for (; i < nDays; i++) { + mMonthNumDrawPaint + .setColor(mFocusDay[i] ? mFocusedMonthDateColor + : mUnfocusedMonthDateColor); + int x = (2 * i + 1) * mWidth / divisor; + canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint); + } + } + + private void drawWeekSeparators(Canvas canvas) { + int firstFullyVisiblePosition = mListView.getFirstVisiblePosition(); + if (mListView.getChildAt(0).getTop() < 0) { + firstFullyVisiblePosition++; + } + if (firstFullyVisiblePosition == mWeek) { + return; + } + mDrawPaint.setColor(mWeekSeparatorLineColor); + mDrawPaint.setStrokeWidth(mWeekSeperatorLineWidth); + float x = mShowWeekNumber ? mWidth / mNumCells : 0; + canvas.drawLine(x, 0, mWidth, 0, mDrawPaint); + } + + public boolean getDayFromLocation(float x, Calendar outCalendar) { + int dayStart = mShowWeekNumber ? mWidth / mNumCells : 0; + if (x < dayStart || x > mWidth) { + outCalendar.clear(); + return false; + } + int dayPosition = (int) ((x - dayStart) * mDaysPerWeek / (mWidth - dayStart)); + outCalendar.setTimeInMillis(mFirstDay.getTimeInMillis()); + outCalendar.add(Calendar.DAY_OF_MONTH, dayPosition); + return true; + } + + public Calendar getFirstDay() { + return mFirstDay; + } + + public int getMonthOfFirstWeekDay() { + return mMonthOfFirstWeekDay; + } + + public int getMonthOfLastWeekDay() { + return mLastWeekDayMonth; + } + + public void init(int weekNumber, int selectedWeekDay, int focusedMonth) { + mSelectedDay = selectedWeekDay; + mHasSelectedDay = mSelectedDay != -1; + mNumCells = mShowWeekNumber ? mDaysPerWeek + 1 : mDaysPerWeek; + mWeek = weekNumber; + mTempDate.setTimeInMillis(mMinDate.getTimeInMillis()); + mTempDate.add(Calendar.WEEK_OF_YEAR, mWeek); + mTempDate.setFirstDayOfWeek(mFirstDayOfWeek); + mDayNumbers = new String[mNumCells]; + mFocusDay = new boolean[mNumCells]; + int i = 0; + if (mShowWeekNumber) { + mDayNumbers[0] = Integer.toString(mTempDate + .get(Calendar.WEEK_OF_YEAR)); + i++; + } + int diff = mFirstDayOfWeek - mTempDate.get(Calendar.DAY_OF_WEEK); + mTempDate.add(Calendar.DAY_OF_MONTH, diff); + mFirstDay = (Calendar) mTempDate.clone(); + mMonthOfFirstWeekDay = mTempDate.get(Calendar.MONTH); + for (; i < mNumCells; i++) { + mFocusDay[i] = mTempDate.get(Calendar.MONTH) == focusedMonth; + if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) { + mDayNumbers[i] = ""; + } else { + mDayNumbers[i] = Integer.toString(mTempDate + .get(Calendar.DAY_OF_MONTH)); + } + mTempDate.add(Calendar.DAY_OF_MONTH, 1); + } + if (mTempDate.get(Calendar.DAY_OF_MONTH) == 1) { + mTempDate.add(Calendar.DAY_OF_MONTH, -1); + } + mLastWeekDayMonth = mTempDate.get(Calendar.MONTH); + updateSelectionPositions(); + } + + @Override + protected void onDraw(Canvas canvas) { + drawBackground(canvas); + drawWeekNumbers(canvas); + drawWeekSeparators(canvas); + drawSelectedDateVerticalBars(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mHeight); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + mWidth = w; + updateSelectionPositions(); + } + + private void setPaintProperties() { + mDrawPaint.setFakeBoldText(false); + mDrawPaint.setAntiAlias(true); + mDrawPaint.setTextSize(mDateTextSize); + mDrawPaint.setStyle(Style.FILL); + + mMonthNumDrawPaint.setFakeBoldText(true); + mMonthNumDrawPaint.setAntiAlias(true); + mMonthNumDrawPaint.setTextSize(mDateTextSize); + mMonthNumDrawPaint.setColor(mFocusedMonthDateColor); + mMonthNumDrawPaint.setStyle(Style.FILL); + mMonthNumDrawPaint.setTextAlign(Align.CENTER); + } + + private void updateSelectionPositions() { + if (mHasSelectedDay) { + int selectedPosition = mSelectedDay - mFirstDayOfWeek; + if (selectedPosition < 0) { + selectedPosition += 7; + } + if (mShowWeekNumber) { + selectedPosition++; + } + mSelectedLeft = selectedPosition * mWidth / mNumCells; + mSelectedRight = (selectedPosition + 1) * mWidth / mNumCells; + } + } + } + + private static final int ADJUSTMENT_SCROLL_DURATION = 500; + private static final String DATE_FORMAT = "MM/dd/yyyy"; + private static final int DAYS_PER_WEEK = 7; + private static final String DEFAULT_MAX_DATE = "01/01/2100"; + private static final String DEFAULT_MIN_DATE = "01/01/1900"; + private static final boolean DEFAULT_SHOW_WEEK_NUMBER = true; + private static final int DEFAULT_SHOWN_WEEK_COUNT = 6; + private static final int DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID = -1; + private static final int GOTO_SCROLL_DURATION = 1000; + private static final String LOG_TAG = CalendarView.class.getSimpleName(); + private static final long MILLIS_IN_DAY = 86400000L; + private static final long MILLIS_IN_WEEK = CalendarView.DAYS_PER_WEEK + * CalendarView.MILLIS_IN_DAY; + private static final int SCROLL_CHANGE_DELAY = 40; + private static final int SCROLL_HYST_WEEKS = 2; + private static final int UNSCALED_BOTTOM_BUFFER = 20; + private static final int UNSCALED_LIST_SCROLL_TOP_OFFSET = 2; + private static final int UNSCALED_SELECTED_DATE_VERTICAL_BAR_WIDTH = 6; + private static final int UNSCALED_WEEK_MIN_VISIBLE_HEIGHT = 12; + private static final int UNSCALED_WEEK_SEPARATOR_LINE_WIDTH = 1; + private WeeksAdapter mAdapter; + private int mBottomBuffer = 20; + private Locale mCurrentLocale; + private int mCurrentMonthDisplayed; + private int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE; + private int mCurrentYearDisplayed; + private final java.text.DateFormat mDateFormat = new SimpleDateFormat( + CalendarView.DATE_FORMAT); + private final int mDateTextSize; + private String[] mDayLabels; + private ViewGroup mDayNamesHeader; + private int mDaysPerWeek = 7; + private Calendar mFirstDayOfMonth; + private int mFirstDayOfWeek; + private final int mFocusedMonthDateColor; + private float mFriction = .05f; + private boolean mIsScrollingUp = false; + private int mListScrollTopOffset = 2; + private ListView mListView; + private Calendar mMaxDate; + private Calendar mMinDate; + private TextView mMonthName; + private OnDateChangeListener mOnDateChangeListener; + private long mPreviousScrollPosition; + private int mPreviousScrollState = OnScrollListener.SCROLL_STATE_IDLE; + private ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(); + private final Drawable mSelectedDateVerticalBar; + private final int mSelectedDateVerticalBarWidth; + private final int mSelectedWeekBackgroundColor; + private int mShownWeekCount; + private boolean mShowWeekNumber; + private Calendar mTempDate; + private final int mUnfocusedMonthDateColor; + private float mVelocityScale = 0.333f; + private int mWeekMinVisibleHeight = 12; + private final int mWeekNumberColor; + private final int mWeekSeparatorLineColor; + private final int mWeekSeperatorLineWidth; + + public CalendarView(Context context) { + this(context, null); + } + + public CalendarView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.calendarViewStyle); + } + + public CalendarView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setCurrentLocale(Locale.getDefault()); + TypedArray attributesArray = context.obtainStyledAttributes(attrs, + R.styleable.CalendarView, defStyle, R.style.Holo_CalendarView); + mShowWeekNumber = attributesArray.getBoolean( + R.styleable.CalendarView_showWeekNumber, + CalendarView.DEFAULT_SHOW_WEEK_NUMBER); + mFirstDayOfWeek = attributesArray.getInt( + R.styleable.CalendarView_firstDayOfWeek, 1); + String minDate = attributesArray + .getString(R.styleable.CalendarView_minDate); + if (TextUtils.isEmpty(minDate) || !parseDate(minDate, mMinDate)) { + parseDate(CalendarView.DEFAULT_MIN_DATE, mMinDate); + } + String maxDate = attributesArray + .getString(R.styleable.CalendarView_maxDate); + if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, mMaxDate)) { + parseDate(CalendarView.DEFAULT_MAX_DATE, mMaxDate); + } + if (mMaxDate.before(mMinDate)) { + throw new IllegalArgumentException( + "Max date cannot be before min date."); + } + mShownWeekCount = attributesArray.getInt( + R.styleable.CalendarView_shownWeekCount, + CalendarView.DEFAULT_SHOWN_WEEK_COUNT); + mSelectedWeekBackgroundColor = attributesArray.getColor( + R.styleable.CalendarView_selectedWeekBackgroundColor, 0); + mFocusedMonthDateColor = attributesArray.getColor( + R.styleable.CalendarView_focusedMonthDateColor, 0); + mUnfocusedMonthDateColor = attributesArray.getColor( + R.styleable.CalendarView_unfocusedMonthDateColor, 0); + mWeekSeparatorLineColor = attributesArray.getColor( + R.styleable.CalendarView_weekSeparatorLineColor, 0); + mWeekNumberColor = attributesArray.getColor( + R.styleable.CalendarView_weekNumberColor, 0); + mSelectedDateVerticalBar = attributesArray + .getDrawable(R.styleable.CalendarView_selectedDateVerticalBar); + attributesArray.getResourceId( + R.styleable.CalendarView_dateTextAppearance, + android.R.style.TextAppearance_Small); + mDateTextSize = (int) (12 * getContext().getResources() + .getDisplayMetrics().density); + int weekDayTextAppearanceResId = attributesArray.getResourceId( + R.styleable.CalendarView_weekDayTextAppearance, + CalendarView.DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID); + attributesArray.recycle(); + DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); + mWeekMinVisibleHeight = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + CalendarView.UNSCALED_WEEK_MIN_VISIBLE_HEIGHT, displayMetrics); + mListScrollTopOffset = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + CalendarView.UNSCALED_LIST_SCROLL_TOP_OFFSET, displayMetrics); + mBottomBuffer = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + CalendarView.UNSCALED_BOTTOM_BUFFER, displayMetrics); + mSelectedDateVerticalBarWidth = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + CalendarView.UNSCALED_SELECTED_DATE_VERTICAL_BAR_WIDTH, + displayMetrics); + mWeekSeperatorLineWidth = (int) TypedValue + .applyDimension(TypedValue.COMPLEX_UNIT_DIP, + CalendarView.UNSCALED_WEEK_SEPARATOR_LINE_WIDTH, + displayMetrics); + LayoutInflater.inflate(context, R.layout.calendar_view, this, true); + FontLoader.apply(this); + mListView = (ListView) findViewById(R.id.list); + mDayNamesHeader = (ViewGroup) findViewById(R.id.day_names); + mMonthName = (TextView) findViewById(R.id.month_name); + setUpHeader(weekDayTextAppearanceResId); + setUpListView(); + setUpAdapter(); + mTempDate.setTimeInMillis(System.currentTimeMillis()); + if (mTempDate.before(mMinDate)) { + goTo(mMinDate, false, true, true); + } else if (mMaxDate.before(mTempDate)) { + goTo(mMaxDate, false, true, true); + } else { + goTo(mTempDate, false, true, true); + } + invalidate(); + } + + private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) { + if (oldCalendar == null) { + return Calendar.getInstance(locale); + } else { + final long currentTimeMillis = oldCalendar.getTimeInMillis(); + Calendar newCalendar = Calendar.getInstance(locale); + newCalendar.setTimeInMillis(currentTimeMillis); + return newCalendar; + } + } + + public long getDate() { + return mAdapter.mSelectedDate.getTimeInMillis(); + } + + public int getFirstDayOfWeek() { + return mFirstDayOfWeek; + } + + public long getMaxDate() { + return mMaxDate.getTimeInMillis(); + } + + public long getMinDate() { + return mMinDate.getTimeInMillis(); + } + + public boolean getShowWeekNumber() { + return mShowWeekNumber; + } + + private int getWeeksSinceMinDate(Calendar date) { + if (date.before(mMinDate)) { + throw new IllegalArgumentException("fromDate: " + + mMinDate.getTime() + " does not precede toDate: " + + date.getTime()); + } + long endTimeMillis = date.getTimeInMillis() + + date.getTimeZone().getOffset(date.getTimeInMillis()); + long startTimeMillis = mMinDate.getTimeInMillis() + + mMinDate.getTimeZone().getOffset(mMinDate.getTimeInMillis()); + long dayOffsetMillis = (mMinDate.get(Calendar.DAY_OF_WEEK) - mFirstDayOfWeek) + * CalendarView.MILLIS_IN_DAY; + return (int) ((endTimeMillis - startTimeMillis + dayOffsetMillis) / CalendarView.MILLIS_IN_WEEK); + } + + @SuppressLint("NewApi") + private void goTo(Calendar date, boolean animate, boolean setSelected, + boolean forceScroll) { + if (date.before(mMinDate) || date.after(mMaxDate)) { + throw new IllegalArgumentException("Time not between " + + mMinDate.getTime() + " and " + mMaxDate.getTime()); + } + int firstFullyVisiblePosition = mListView.getFirstVisiblePosition(); + View firstChild = mListView.getChildAt(0); + if (firstChild != null && firstChild.getTop() < 0) { + firstFullyVisiblePosition++; + } + int lastFullyVisiblePosition = firstFullyVisiblePosition + + mShownWeekCount - 1; + if (firstChild != null && firstChild.getTop() > mBottomBuffer) { + lastFullyVisiblePosition--; + } + if (setSelected) { + mAdapter.setSelectedDay(date); + } + int position = getWeeksSinceMinDate(date); + if (position < firstFullyVisiblePosition + || position > lastFullyVisiblePosition || forceScroll) { + mFirstDayOfMonth.setTimeInMillis(date.getTimeInMillis()); + mFirstDayOfMonth.set(Calendar.DAY_OF_MONTH, 1); + setMonthDisplayed(mFirstDayOfMonth); + if (mFirstDayOfMonth.before(mMinDate)) { + position = 0; + } else { + position = getWeeksSinceMinDate(mFirstDayOfMonth); + } + mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING; + if (animate && VERSION.SDK_INT >= 11) { + mListView + .smoothScrollToPositionFromTop(position, + mListScrollTopOffset, + CalendarView.GOTO_SCROLL_DURATION); + } else { + mListView.setSelectionFromTop(position, mListScrollTopOffset); + onScrollStateChanged(mListView, + OnScrollListener.SCROLL_STATE_IDLE); + } + } else if (setSelected) { + setMonthDisplayed(date); + } + } + + @Override + public boolean isEnabled() { + return mListView.isEnabled(); + } + + private boolean isSameDate(Calendar firstDate, Calendar secondDate) { + return firstDate.get(Calendar.DAY_OF_YEAR) == secondDate + .get(Calendar.DAY_OF_YEAR) + && firstDate.get(Calendar.YEAR) == secondDate + .get(Calendar.YEAR); + } + + @SuppressLint("NewApi") + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + setCurrentLocale(newConfig.locale); + } + + private void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { + WeekView child = (WeekView) view.getChildAt(0); + if (child == null) { + return; + } + long currScroll = view.getFirstVisiblePosition() * child.getHeight() + - child.getBottom(); + if (currScroll < mPreviousScrollPosition) { + mIsScrollingUp = true; + } else if (currScroll > mPreviousScrollPosition) { + mIsScrollingUp = false; + } else { + return; + } + int offset = child.getBottom() < mWeekMinVisibleHeight ? 1 : 0; + if (mIsScrollingUp) { + child = (WeekView) view.getChildAt(CalendarView.SCROLL_HYST_WEEKS + + offset); + } else if (offset != 0) { + child = (WeekView) view.getChildAt(offset); + } + int month; + if (mIsScrollingUp) { + month = child.getMonthOfFirstWeekDay(); + } else { + month = child.getMonthOfLastWeekDay(); + } + int monthDiff; + if (mCurrentMonthDisplayed == 11 && month == 0) { + monthDiff = 1; + } else if (mCurrentMonthDisplayed == 0 && month == 11) { + monthDiff = -1; + } else { + monthDiff = month - mCurrentMonthDisplayed; + } + if (!mIsScrollingUp && monthDiff > 0 || mIsScrollingUp && monthDiff < 0) { + Calendar firstDay = child.getFirstDay(); + if (mIsScrollingUp) { + firstDay.add(Calendar.DAY_OF_MONTH, -CalendarView.DAYS_PER_WEEK); + } else { + firstDay.add(Calendar.DAY_OF_MONTH, CalendarView.DAYS_PER_WEEK); + } + setMonthDisplayed(firstDay); + } + mPreviousScrollPosition = currScroll; + mPreviousScrollState = mCurrentScrollState; + } + + private void onScrollStateChanged(AbsListView view, int scrollState) { + mScrollStateChangedRunnable.doScrollStateChange(view, scrollState); + } + + private boolean parseDate(String date, Calendar outDate) { + try { + outDate.setTime(mDateFormat.parse(date)); + return true; + } catch (ParseException e) { + Log.w(CalendarView.LOG_TAG, "Date: " + date + " not in format: " + + CalendarView.DATE_FORMAT); + return false; + } + } + + private void setCurrentLocale(Locale locale) { + if (locale.equals(mCurrentLocale)) { + return; + } + + mCurrentLocale = locale; + mTempDate = getCalendarForLocale(mTempDate, locale); + mFirstDayOfMonth = getCalendarForLocale(mFirstDayOfMonth, locale); + mMinDate = getCalendarForLocale(mMinDate, locale); + mMaxDate = getCalendarForLocale(mMaxDate, locale); + } + + public void setDate(long date) { + setDate(date, false, false); + } + + public void setDate(long date, boolean animate, boolean center) { + mTempDate.setTimeInMillis(date); + if (isSameDate(mTempDate, mAdapter.mSelectedDate)) { + return; + } + goTo(mTempDate, animate, true, center); + } + + @Override + public void setEnabled(boolean enabled) { + mListView.setEnabled(enabled); + } + + public void setFirstDayOfWeek(int firstDayOfWeek) { + if (mFirstDayOfWeek == firstDayOfWeek) { + return; + } + mFirstDayOfWeek = firstDayOfWeek; + mAdapter.init(); + mAdapter.notifyDataSetChanged(); + setUpHeader(CalendarView.DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID); + } + + public void setMaxDate(long maxDate) { + mTempDate.setTimeInMillis(maxDate); + if (isSameDate(mTempDate, mMaxDate)) { + return; + } + mMaxDate.setTimeInMillis(maxDate); + mAdapter.init(); + Calendar date = mAdapter.mSelectedDate; + if (date.after(mMaxDate)) { + setDate(mMaxDate.getTimeInMillis()); + } else { + goTo(date, false, true, false); + } + } + + public void setMinDate(long minDate) { + mTempDate.setTimeInMillis(minDate); + if (isSameDate(mTempDate, mMinDate)) { + return; + } + mMinDate.setTimeInMillis(minDate); + Calendar date = mAdapter.mSelectedDate; + if (date.before(mMinDate)) { + mAdapter.setSelectedDay(mMinDate); + } + mAdapter.init(); + if (date.before(mMinDate)) { + setDate(mTempDate.getTimeInMillis()); + } else { + goTo(date, false, true, false); + } + } + + private void setMonthDisplayed(Calendar calendar) { + final int newMonthDisplayed = calendar.get(Calendar.MONTH); + final int newYearDisplayed = calendar.get(Calendar.YEAR); + if (mCurrentMonthDisplayed != newMonthDisplayed + || mCurrentYearDisplayed != newYearDisplayed) { + mCurrentMonthDisplayed = newMonthDisplayed; + mCurrentYearDisplayed = newYearDisplayed; + mAdapter.setFocusMonth(mCurrentMonthDisplayed); + final int flags = DateUtils.FORMAT_SHOW_DATE + | DateUtils.FORMAT_NO_MONTH_DAY + | DateUtils.FORMAT_SHOW_YEAR; + final long millis = calendar.getTimeInMillis(); + String newMonthName = DateUtils.formatDateRange(getContext(), + millis, millis, flags); + mMonthName.setText(newMonthName); + mMonthName.invalidate(); + } + } + + public void setOnDateChangeListener(OnDateChangeListener listener) { + mOnDateChangeListener = listener; + } + + public void setShowWeekNumber(boolean showWeekNumber) { + if (mShowWeekNumber == showWeekNumber) { + return; + } + mShowWeekNumber = showWeekNumber; + mAdapter.notifyDataSetChanged(); + setUpHeader(CalendarView.DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID); + } + + private void setUpAdapter() { + if (mAdapter == null) { + mAdapter = new WeeksAdapter(getContext()); + mAdapter.registerDataSetObserver(new DataSetObserver() { + @Override + public void onChanged() { + if (mOnDateChangeListener != null) { + Calendar selectedDay = mAdapter.getSelectedDay(); + mOnDateChangeListener.onSelectedDayChange( + CalendarView.this, + selectedDay.get(Calendar.YEAR), + selectedDay.get(Calendar.MONTH), + selectedDay.get(Calendar.DAY_OF_MONTH)); + } + } + }); + mListView.setAdapter(mAdapter); + } + mAdapter.notifyDataSetChanged(); + } + + private void setUpHeader(int weekDayTextAppearanceResId) { + mDayLabels = new String[mDaysPerWeek]; + for (int i = mFirstDayOfWeek, count = mFirstDayOfWeek + mDaysPerWeek; i < count; i++) { + int calendarDay = i > Calendar.SATURDAY ? i - Calendar.SATURDAY : i; + mDayLabels[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString( + calendarDay, DateUtils.LENGTH_SHORTEST); + } + TextView label = (TextView) mDayNamesHeader.getChildAt(0); + if (mShowWeekNumber) { + label.setVisibility(View.VISIBLE); + } else { + label.setVisibility(View.GONE); + } + for (int i = 1, count = mDayNamesHeader.getChildCount(); i < count; i++) { + label = (TextView) mDayNamesHeader.getChildAt(i); + if (weekDayTextAppearanceResId > -1) { + label.setTextAppearance(getContext(), + weekDayTextAppearanceResId); + } + if (i < mDaysPerWeek + 1) { + label.setText(mDayLabels[i - 1]); + label.setVisibility(View.VISIBLE); + } else { + label.setVisibility(View.GONE); + } + } + mDayNamesHeader.invalidate(); + } + + @SuppressLint("NewApi") + private void setUpListView() { + mListView.setDivider(null); + mListView.setItemsCanFocus(true); + mListView.setVerticalScrollBarEnabled(false); + mListView.setOnScrollListener(new OnScrollListener() { + @Override + public void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { + CalendarView.this.onScroll(view, firstVisibleItem, + visibleItemCount, totalItemCount); + } + + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + CalendarView.this.onScrollStateChanged(view, scrollState); + } + }); + if (VERSION.SDK_INT >= 11) { + mListView.setFriction(mFriction); + mListView.setVelocityScale(mVelocityScale); + } + } +} |