diff --git a/library/src/main/java/com/alamkanak/weekview/WeekView.java b/library/src/main/java/com/alamkanak/weekview/WeekView.java index 5a9281b32..1342e8a94 100644 --- a/library/src/main/java/com/alamkanak/weekview/WeekView.java +++ b/library/src/main/java/com/alamkanak/weekview/WeekView.java @@ -16,12 +16,14 @@ import android.text.TextPaint; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.GestureDetector; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.SoundEffectConstants; import android.view.View; +import android.view.WindowManager; import android.widget.OverScroller; import android.widget.Scroller; @@ -62,9 +64,11 @@ public class WeekView extends View { private Paint mTodayBackgroundPaint; private Paint mTodayHeaderTextPaint; private Paint mEventBackgroundPaint; + private Paint mEmptyEventBackgroundPaint; private float mHeaderColumnWidth; private List mEventRects; private TextPaint mEventTextPaint; + private TextPaint mEmptyEventTextPaint; private Paint mHeaderColumnBackgroundPaint; private Scroller mStickyScroller; private int mFetchedMonths[] = new int[3]; @@ -72,6 +76,7 @@ public class WeekView extends View { private float mDistanceY = 0; private float mDistanceX = 0; private Direction mCurrentFlingDirection = Direction.NONE; + float mEmptyEventX; // Attributes and their default values. private int mHourHeight = 50; @@ -90,18 +95,22 @@ public class WeekView extends View { private int mTodayHeaderTextColor = Color.rgb(39, 137, 228); private int mEventTextSize = 12; private int mEventTextColor = Color.BLACK; + private int mEmptyEventTextColor = Color.WHITE; private int mEventPadding = 8; private int mHeaderColumnBackgroundColor = Color.WHITE; private int mDefaultEventColor; + private int mDefaultEmptyEventColor; private boolean mIsFirstDraw = true; private boolean mAreDimensionsInvalid = true; - @Deprecated private int mDayNameLength = LENGTH_LONG; + @Deprecated + private int mDayNameLength = LENGTH_LONG; private int mOverlappingEventGap = 0; private int mEventMarginVertical = 0; private float mXScrollingSpeed = 1f; private Calendar mFirstVisibleDay; private Calendar mLastVisibleDay; private Calendar mScrollToDay = null; + private Calendar mCacheEmptyEventDay; private double mScrollToHour = -1; // Listeners. @@ -177,7 +186,10 @@ public boolean onSingleTapConfirmed(MotionEvent e) { Calendar selectedTime = getTimeFromPoint(e.getX(), e.getY()); if (selectedTime != null) { playSoundEffect(SoundEffectConstants.CLICK); - mEmptyViewClickListener.onEmptyViewClicked(selectedTime); + mEmptyEventX = e.getX(); + mEmptyViewClickListener.onEmptyViewClicked(selectedTime, mCacheEmptyEventDay, isSameDayAndHour(selectedTime, mCacheEmptyEventDay)); + mCacheEmptyEventDay = selectedTime; + invalidate(); } } @@ -248,6 +260,7 @@ public WeekView(Context context, AttributeSet attrs, int defStyleAttr) { mTodayHeaderTextColor = a.getColor(R.styleable.WeekView_todayHeaderTextColor, mTodayHeaderTextColor); mEventTextSize = a.getDimensionPixelSize(R.styleable.WeekView_eventTextSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mEventTextSize, context.getResources().getDisplayMetrics())); mEventTextColor = a.getColor(R.styleable.WeekView_eventTextColor, mEventTextColor); + mEmptyEventTextColor = a.getColor(R.styleable.WeekView_emptyEventTextColor, mEmptyEventTextColor); mEventPadding = a.getDimensionPixelSize(R.styleable.WeekView_hourSeparatorHeight, mEventPadding); mHeaderColumnBackgroundColor = a.getColor(R.styleable.WeekView_headerColumnBackground, mHeaderColumnBackgroundColor); mDayNameLength = a.getInteger(R.styleable.WeekView_dayNameLength, mDayNameLength); @@ -321,6 +334,9 @@ private void init() { // Prepare event background color. mEventBackgroundPaint = new Paint(); mEventBackgroundPaint.setColor(Color.rgb(174, 208, 238)); + // Prepare empty event background color. + mEmptyEventBackgroundPaint = new Paint(); + mEmptyEventBackgroundPaint.setColor(Color.rgb(60, 147, 217)); // Prepare header column background color. mHeaderColumnBackgroundPaint = new Paint(); @@ -331,22 +347,33 @@ private void init() { mEventTextPaint.setStyle(Paint.Style.FILL); mEventTextPaint.setColor(mEventTextColor); mEventTextPaint.setTextSize(mEventTextSize); + // Prepare empty event text size and color. + mEmptyEventTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG); + mEmptyEventTextPaint.setStyle(Paint.Style.FILL); + mEmptyEventTextPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); + mEmptyEventTextPaint.setColor(mEmptyEventTextColor); mStartDate = (Calendar) mToday.clone(); // Set default event color. mDefaultEventColor = Color.parseColor("#9fc6e7"); + // Set default empty event color. + mDefaultEmptyEventColor = Color.parseColor("#3c93d9"); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - // Draw the header row. - drawHeaderRowAndEvents(canvas); - // Draw the time column and all the axes/separators. drawTimeColumnAndAxes(canvas); + //Draw empty event + if (mCurrentScrollDirection != Direction.HORIZONTAL) { + if (mCacheEmptyEventDay != null) drawEmptyEvent(mCacheEmptyEventDay, canvas); + } else mCacheEmptyEventDay = null; + + // Draw the header row. + drawHeaderRowAndEvents(canvas); // Hide everything in the first cell (top left corner). canvas.drawRect(0, 0, mTimeTextWidth + mHeaderColumnPadding * 2, mHeaderTextHeight + mHeaderRowPadding * 2, mHeaderBackgroundPaint); @@ -586,6 +613,57 @@ eventRectF.top < getHeight() && } } + /** + * Draw empty event + * + * @param mCacheEmptyEventDay The day. + * @param canvas The canvas to draw upon. + */ + private void drawEmptyEvent(Calendar mCacheEmptyEventDay, Canvas canvas) { + // Prepare to iterate for each day. + Calendar day = (Calendar) mToday.clone(); + day.add(Calendar.HOUR, 6); + int leftDaysWithGaps = (int) -(Math.ceil(mCurrentOrigin.x / (mWidthPerDay + mColumnGap))); + //iterate thru days + for (int dayNumber = leftDaysWithGaps + 1; + dayNumber <= leftDaysWithGaps + mNumberOfVisibleDays + 1; + dayNumber++) { + // Check if the day is today. + day = (Calendar) mToday.clone(); + day.add(Calendar.DATE, dayNumber - 1); + boolean sameDay = isSameDay(day, mCacheEmptyEventDay); + if (sameDay) { + //calculate bottom and top + float cal_bottom = (mCacheEmptyEventDay.get(Calendar.HOUR_OF_DAY) + 1) * 60; + float bottom = mHourHeight * 24 * cal_bottom / 1440 + mCurrentOrigin.y + mHeaderTextHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight / 2 - mEventMarginVertical; + float originalBottom = bottom - mTimeTextHeight - mHeaderTextHeight; + float cal_top = mCacheEmptyEventDay.get(Calendar.HOUR_OF_DAY) * 60; + float top = mHourHeight * 24 * cal_top / 1440 + mCurrentOrigin.y + mHeaderTextHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight / 2 + mEventMarginVertical; + mEmptyEventBackgroundPaint.setColor(mDefaultEmptyEventColor); + // Calculate left and right. + float left = 0; + for (int i = 0; i < mNumberOfVisibleDays + 1; i++) { + int j = i + 1; + float h_wpd = mHeaderColumnWidth + (mWidthPerDay * j); + if (i != 0) h_wpd += (mColumnGap * j); + if (mEmptyEventX <= h_wpd) { + left = mHeaderColumnWidth; + if (i != 0) left += (mWidthPerDay * i) + (mColumnGap * i); + break; + } + } + float right = left + mWidthPerDay; + + // Draw the empty event and the text on top of it. + RectF dayRectF = new RectF(left, top, right, bottom); + canvas.drawRect(dayRectF, mEmptyEventBackgroundPaint); + drawEmptyText("+", canvas, (((originalBottom - top) / 2) + top), left, (int) dayRectF.width()); + break; + + } + + } + } /** * Draw the name of the event on top of the event rectangle. @@ -622,6 +700,48 @@ else if (lineHeight >= availableHeight) { canvas.restore(); } + /** + * Draw the text on top of the rectangle in the empty event. + * + * @param text The empty text to draw. + * @param canvas The canvas to draw upon. + * @param originalTop The original top position of the rectangle. The rectangle may have some of its portion outside of the visible area. + * @param originalLeft The original left position of the rectangle. The rectangle may have some of its portion outside of the visible area. + */ + private void drawEmptyText(String text, Canvas canvas, float originalTop, float originalLeft, int textWidth) { + + // Get text dimensions + DisplayMetrics metrics = new DisplayMetrics(); + WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getMetrics(metrics); + float textSize = 18f; + switch (metrics.densityDpi) { + case DisplayMetrics.DENSITY_LOW: + textSize = textSize * 0.75f; + break; + case DisplayMetrics.DENSITY_MEDIUM: + textSize = textSize * 1f; + break; + case DisplayMetrics.DENSITY_HIGH: + textSize = textSize * 1.5f; + break; + case DisplayMetrics.DENSITY_XHIGH: + textSize = textSize * 2.0f; + break; + case DisplayMetrics.DENSITY_XXHIGH: + textSize = textSize * 2.5f; + break; + } + + mEmptyEventTextPaint.setTextSize(textSize); + mEmptyEventTextPaint.setColor(mEmptyEventTextColor); + StaticLayout textLayout = new StaticLayout(text, mEmptyEventTextPaint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + // Draw text + canvas.save(); + canvas.translate(originalLeft, originalTop); + textLayout.draw(canvas); + canvas.restore(); + } /** * A class to hold reference to the events and their visual representation. An EventRect is @@ -1202,6 +1322,15 @@ public void setEventTextColor(int eventTextColor) { invalidate(); } + public int getEmptyEventTextColor() { + return mEmptyEventTextColor; + } + + public void setEmptyEventTextColor(int emptyEventTextColor) { + mEmptyEventTextColor = emptyEventTextColor; + invalidate(); + } + public int getEventPadding() { return mEventPadding; } @@ -1229,6 +1358,15 @@ public void setDefaultEventColor(int defaultEventColor) { invalidate(); } + public int getDefaultEmptyEventColor() { + return mDefaultEmptyEventColor; + } + + public void setDefaultEmptyEventColor(int DefaultEmptyEventColor) { + mDefaultEmptyEventColor = DefaultEmptyEventColor; + invalidate(); + } + /** * Note: Use {@link #setDateTimeInterpreter(DateTimeInterpreter)} and * {@link #getDateTimeInterpreter()} instead. @@ -1376,6 +1514,7 @@ public void computeScroll() { public void goToToday() { Calendar today = Calendar.getInstance(); goToDate(today); + mCacheEmptyEventDay = null; } /** @@ -1469,7 +1608,7 @@ public interface EventLongPressListener { } public interface EmptyViewClickListener { - public void onEmptyViewClicked(Calendar time); + public void onEmptyViewClicked(Calendar time, Calendar tempTime, boolean clickedTwice); } public interface EmptyViewLongPressListener { @@ -1518,4 +1657,19 @@ private boolean isSameDay(Calendar dayOne, Calendar dayTwo) { return dayOne.get(Calendar.YEAR) == dayTwo.get(Calendar.YEAR) && dayOne.get(Calendar.DAY_OF_YEAR) == dayTwo.get(Calendar.DAY_OF_YEAR); } + /** + * Checks if two times are on the same day and hour. + * + * @param dayOne The first day. + * @param dayTwo The second day. + * @return Whether the times are on the same day and hour. + */ + private boolean isSameDayAndHour(Calendar dayOne, Calendar dayTwo) { + + if (dayTwo != null) { + return dayOne.get(Calendar.YEAR) == dayTwo.get(Calendar.YEAR) && dayOne.get(Calendar.DAY_OF_YEAR) == dayTwo.get(Calendar.DAY_OF_YEAR) && dayOne.get(Calendar.HOUR_OF_DAY) == dayTwo.get(Calendar.HOUR_OF_DAY); + } + return false; + } + } diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index b94dd76dd..91c853d94 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -25,6 +25,7 @@ +