Skip to content

Commit 09b9347

Browse files
authored
Some fixes for new events placement (and other things) (#78)
* Adds support for auto-picking event textcolor based on background color * Xml support for auto textcolor * Fixes #29 where adding an event at the end of the day removes all events * Text color picking interface + example New event start time adjusted * Only adjusts the selected position when adding new events * Only adjusts the selected position when adding new events * Cloning selected time to prevent changing it in callback * Adds support for auto-picking event textcolor based on background color * Xml support for auto textcolor * Text color picking interface + example New event start time adjusted * Fix to prevent losing events when adding new event * Only adjusts the selected position when adding new events * Only adjusts the selected position when adding new events * Cloning selected time to prevent changing it in callback * Import fix * Fix for min- and maxTime when adding events * Fix some issues with NewEvent placement * remove unused attribute * reformatting * update documentation
1 parent ac15f19 commit 09b9347

File tree

8 files changed

+110
-22
lines changed

8 files changed

+110
-22
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ You can customize the look of the `WeekView` in xml. Use the following attribute
108108
- `columnGap`
109109
- `dayBackgroundColor`
110110
- `dayNameLength`
111+
- `dropListenerEnabled`: Whether items can be dropped on the weekview
111112
- `eventCornerRadius`
112113
- `eventMarginVertical`
113114
- `eventPadding`
@@ -129,6 +130,7 @@ You can customize the look of the `WeekView` in xml. Use the following attribute
129130
- `maxTime`
130131
- `minHourHeight`
131132
- `minTime`
133+
- `minOverlappingMinutes`: The minimal amount of overlap of 2 events needed to be seen as overlapping events
132134
- `newEventColor`
133135
- `newEventId`
134136
- `newEventIconResource`
@@ -168,6 +170,8 @@ Use the following interfaces according to your need.
168170
- `mWeekView.setDateTimeInterpreter()` to set your own labels for the calendar header row and header column
169171
- `mWeekView.setScrollListener()` to get an event every time the first visible day has changed
170172
- `mWeekView.setAddEventClickListener()` to get the start and end time of an event to add
173+
- `mWeekView.setTextColorPicker()` to change the textcolor of an event, based on the event. You can, for example, set a different text color depending on the color of the event.
174+
171175
Sample
172176
----------
173177

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.alamkanak.weekview;
2+
3+
import android.support.annotation.ColorInt;
4+
5+
public interface TextColorPicker {
6+
7+
@ColorInt
8+
int getTextColor(WeekViewEvent event);
9+
10+
}

library/src/main/java/com/alamkanak/weekview/WeekView.java

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ private enum Direction {
9595
private Paint mNewEventBackgroundPaint;
9696
private float mHeaderColumnWidth;
9797
private List<EventRect> mEventRects;
98+
private List<WeekViewEvent> mEvents;
9899
private TextPaint mEventTextPaint;
99100
private TextPaint mNewEventTextPaint;
100101
private Paint mHeaderColumnBackgroundPaint;
@@ -108,6 +109,7 @@ private enum Direction {
108109
private int mMinimumFlingVelocity = 0;
109110
private int mScaledTouchSlop = 0;
110111
private EventRect mNewEventRect;
112+
private TextColorPicker textColorPicker;
111113

112114
// Attributes and their default values.
113115
private int mHourHeight = 50;
@@ -171,6 +173,7 @@ private enum Direction {
171173
private int mMaxTime = 24;
172174
private boolean mAutoLimitTime = false;
173175
private boolean mEnableDropListener = false;
176+
private int mMinOverlappingMinutes = 0;
174177

175178
// Listeners.
176179
private EventClickListener mEventClickListener;
@@ -318,26 +321,41 @@ public boolean onSingleTapConfirmed(MotionEvent e) {
318321
// If the tap was on an empty space, then trigger the callback.
319322
if ((mEmptyViewClickListener != null || mAddEventClickListener != null) && e.getX() > mHeaderColumnWidth && e.getY() > (mHeaderHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom)) {
320323
Calendar selectedTime = getTimeFromPoint(e.getX(), e.getY());
321-
List<EventRect> tempEventRects = new ArrayList<>(mEventRects);
322-
mEventRects = new ArrayList<EventRect>();
324+
323325
if (selectedTime != null) {
326+
List<WeekViewEvent> tempEvents = new ArrayList<>(mEvents);
324327
if (mNewEventRect != null) {
325-
tempEventRects.remove(mNewEventRect);
328+
tempEvents.remove(mNewEventRect.event);
326329
mNewEventRect = null;
327330
}
328331

329332
playSoundEffect(SoundEffectConstants.CLICK);
333+
330334
if (mEmptyViewClickListener != null)
331-
mEmptyViewClickListener.onEmptyViewClicked(selectedTime);
335+
mEmptyViewClickListener.onEmptyViewClicked((Calendar) selectedTime.clone());
332336

333337
if (mAddEventClickListener != null) {
334338
//round selectedTime to resolution
339+
selectedTime.add(Calendar.MINUTE, -(mNewEventLengthInMinutes / 2));
340+
//Fix selected time if before the minimum hour
341+
if (selectedTime.get(Calendar.HOUR_OF_DAY) < mMinTime) {
342+
selectedTime.set(Calendar.HOUR_OF_DAY, mMinTime);
343+
selectedTime.set(Calendar.MINUTE, 0);
344+
}
335345
int unroundedMinutes = selectedTime.get(Calendar.MINUTE);
336346
int mod = unroundedMinutes % mNewEventTimeResolutionInMinutes;
337347
selectedTime.add(Calendar.MINUTE, mod < Math.ceil(mNewEventTimeResolutionInMinutes / 2) ? -mod : (mNewEventTimeResolutionInMinutes - mod));
338348

339349
Calendar endTime = (Calendar) selectedTime.clone();
340-
endTime.add(Calendar.MINUTE, Math.min(mNewEventLengthInMinutes, (24 - selectedTime.get(Calendar.HOUR_OF_DAY)) * 60 - selectedTime.get(Calendar.MINUTE)));
350+
351+
//Minus one to ensure it is the same day and not midnight (next day)
352+
int maxMinutes = (mMaxTime - selectedTime.get(Calendar.HOUR_OF_DAY)) * 60 - selectedTime.get(Calendar.MINUTE) - 1;
353+
endTime.add(Calendar.MINUTE, Math.min(maxMinutes, mNewEventLengthInMinutes));
354+
//If clicked at end of the day, fix selected startTime
355+
if (maxMinutes < mNewEventLengthInMinutes) {
356+
selectedTime.add(Calendar.MINUTE, maxMinutes - mNewEventLengthInMinutes);
357+
}
358+
341359
WeekViewEvent newEvent = new WeekViewEvent(mNewEventIdentifier, "", null, selectedTime, endTime);
342360

343361
int marginTop = mHourHeight * mMinTime;
@@ -349,7 +367,7 @@ public boolean onSingleTapConfirmed(MotionEvent e) {
349367
// Calculate left and right.
350368
float left = 0;
351369
float right = left + mWidthPerDay;
352-
// Draw the event and the event name on top of it.
370+
// Add the new event if its bounds are valid
353371
if (left < right &&
354372
left < getWidth() &&
355373
top < getHeight() &&
@@ -359,12 +377,16 @@ top < getHeight() &&
359377
RectF dayRectF = new RectF(left, top, right, bottom);
360378
newEvent.setColor(mNewEventColor);
361379
mNewEventRect = new EventRect(newEvent, newEvent, dayRectF);
362-
tempEventRects.add(mNewEventRect);
380+
tempEvents.add(newEvent);
381+
WeekView.this.clearEvents();
382+
cacheAndSortEvents(tempEvents);
383+
computePositionOfEvents(mEventRects);
384+
invalidate();
363385
}
386+
364387
}
365388
}
366-
computePositionOfEvents(tempEventRects);
367-
invalidate();
389+
368390
}
369391
return super.onSingleTapConfirmed(e);
370392
}
@@ -466,8 +488,9 @@ public WeekView(Context context, AttributeSet attrs, int defStyleAttr) {
466488
mAutoLimitTime = a.getBoolean(R.styleable.WeekView_autoLimitTime, mAutoLimitTime);
467489
mMinTime = a.getInt(R.styleable.WeekView_minTime, mMinTime);
468490
mMaxTime = a.getInt(R.styleable.WeekView_maxTime, mMaxTime);
469-
if(a.getBoolean(R.styleable.WeekView_dropListenerEnabled, false))
491+
if (a.getBoolean(R.styleable.WeekView_dropListenerEnabled, false))
470492
this.enableDropListener();
493+
mMinOverlappingMinutes = a.getInt(R.styleable.WeekView_minOverlappingMinutes, 0);
471494
} finally {
472495
a.recycle();
473496
}
@@ -1146,6 +1169,10 @@ private void drawEventTitle(WeekViewEvent event, RectF rect, Canvas canvas, floa
11461169
int availableHeight = (int) (rect.bottom - originalTop - mEventPadding * 2);
11471170
int availableWidth = (int) (rect.right - originalLeft - mEventPadding * 2);
11481171

1172+
// Get text color if necessary
1173+
if (textColorPicker != null) {
1174+
mEventTextPaint.setColor(textColorPicker.getTextColor(event));
1175+
}
11491176
// Get text dimensions.
11501177
StaticLayout textLayout = new StaticLayout(bob, mEventTextPaint, availableWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
11511178
if (textLayout.getLineCount() > 0) {
@@ -1235,13 +1262,17 @@ private void getMoreEvents(Calendar day) {
12351262

12361263
// Get more events if the month is changed.
12371264
if (mEventRects == null)
1238-
mEventRects = new ArrayList<EventRect>();
1265+
mEventRects = new ArrayList<>();
1266+
1267+
if (mEvents == null)
1268+
mEvents = new ArrayList<>();
1269+
12391270
if (mWeekViewLoader == null && !isInEditMode())
12401271
throw new IllegalStateException("You must provide a MonthChangeListener");
12411272

12421273
// If a refresh was requested then reset some variables.
12431274
if (mRefreshEvents) {
1244-
mEventRects.clear();
1275+
this.clearEvents();
12451276
mFetchedPeriod = -1;
12461277
}
12471278

@@ -1251,7 +1282,7 @@ private void getMoreEvents(Calendar day) {
12511282
List<? extends WeekViewEvent> newEvents = mWeekViewLoader.onLoad(periodToFetch);
12521283

12531284
// Clear events.
1254-
mEventRects.clear();
1285+
this.clearEvents();
12551286
cacheAndSortEvents(newEvents);
12561287
calculateHeaderHeight();
12571288

@@ -1261,7 +1292,7 @@ private void getMoreEvents(Calendar day) {
12611292

12621293
// Prepare to calculate positions of each events.
12631294
List<EventRect> tempEvents = mEventRects;
1264-
mEventRects = new ArrayList<EventRect>();
1295+
mEventRects = new ArrayList<>();
12651296

12661297
// Iterate through each day with events to calculate the position of the events.
12671298
while (tempEvents.size() > 0) {
@@ -1286,6 +1317,11 @@ private void getMoreEvents(Calendar day) {
12861317
}
12871318
}
12881319

1320+
private void clearEvents() {
1321+
mEventRects.clear();
1322+
mEvents.clear();
1323+
}
1324+
12891325
/**
12901326
* Cache the event for smooth scrolling functionality.
12911327
*
@@ -1298,6 +1334,7 @@ private void cacheEvent(WeekViewEvent event) {
12981334
for (WeekViewEvent splitedEvent : splitedEvents) {
12991335
mEventRects.add(new EventRect(splitedEvent, event, null));
13001336
}
1337+
mEvents.add(event);
13011338
}
13021339

13031340
/**
@@ -1438,7 +1475,10 @@ private boolean isEventsCollide(WeekViewEvent event1, WeekViewEvent event2) {
14381475
long end1 = event1.getEndTime().getTimeInMillis();
14391476
long start2 = event2.getStartTime().getTimeInMillis();
14401477
long end2 = event2.getEndTime().getTimeInMillis();
1441-
return !((start1 >= end2) || (end1 <= start2));
1478+
1479+
long minOverlappingMillis = mMinOverlappingMinutes * 60 * 1000;
1480+
1481+
return !((start1 + minOverlappingMillis >= end2) || (end1 <= start2 + minOverlappingMillis));
14421482
}
14431483

14441484

@@ -1833,6 +1873,14 @@ public void setEventTextColor(int eventTextColor) {
18331873
invalidate();
18341874
}
18351875

1876+
public void setTextColorPicker(TextColorPicker textColorPicker) {
1877+
this.textColorPicker = textColorPicker;
1878+
}
1879+
1880+
public TextColorPicker getTextColorPicker() {
1881+
return textColorPicker;
1882+
}
1883+
18361884
public int getEventPadding() {
18371885
return mEventPadding;
18381886
}
@@ -2426,26 +2474,34 @@ public void setNewEventIconDrawable(Drawable newEventIconDrawable) {
24262474
this.mNewEventIconDrawable = newEventIconDrawable;
24272475
}
24282476

2429-
public void enableDropListener(){
2477+
public void enableDropListener() {
24302478
this.mEnableDropListener = true;
24312479
//set drag and drop listener, required Honeycomb+ Api level
24322480
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
24332481
setOnDragListener(new DragListener());
24342482
}
24352483
}
24362484

2437-
public void disableDropListener(){
2485+
public void disableDropListener() {
24382486
this.mEnableDropListener = false;
24392487
//set drag and drop listener, required Honeycomb+ Api level
24402488
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
24412489
setOnDragListener(null);
24422490
}
24432491
}
24442492

2445-
public boolean isDropListenerEnabled(){
2493+
public boolean isDropListenerEnabled() {
24462494
return this.mEnableDropListener;
24472495
}
24482496

2497+
public void setMinOverlappingMinutes(int minutes) {
2498+
this.mMinOverlappingMinutes = minutes;
2499+
}
2500+
2501+
public int getMinOverlappingMinutes() {
2502+
return this.mMinOverlappingMinutes;
2503+
}
2504+
24492505
/////////////////////////////////////////////////////////////////
24502506
//
24512507
// Functions related to scrolling.

library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.alamkanak.weekview;
22

33
import android.graphics.Shader;
4+
import android.support.annotation.ColorInt;
45

56
import java.util.ArrayList;
67
import java.util.Calendar;
@@ -18,7 +19,9 @@ public class WeekViewEvent {
1819
private Calendar mEndTime;
1920
private String mName;
2021
private String mLocation;
21-
private int mColor;
22+
private
23+
@ColorInt
24+
int mColor;
2225
private boolean mAllDay;
2326
private Shader mShader;
2427

@@ -233,7 +236,9 @@ public void setLocation(String location) {
233236
this.mLocation = location;
234237
}
235238

236-
public int getColor() {
239+
public
240+
@ColorInt
241+
int getColor() {
237242
return mColor;
238243
}
239244

library/src/main/res/values/attrs.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<attr name="maxTime" format="integer" />
3939
<attr name="minHourHeight" format="dimension" />
4040
<attr name="minTime" format="integer" />
41+
<attr name="minOverlappingMinutes" format="integer" />
4142
<attr name="newEventColor" format="color" />
4243
<attr name="newEventId" format="integer" />
4344
<attr name="newEventIdentifier" format="string" />

sample/src/main/java/com/alamkanak/weekview/sample/BasicActivity.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.alamkanak.weekview.sample;
22

3+
import android.graphics.Color;
34
import android.graphics.Typeface;
45
import android.os.Bundle;
56

7+
import com.alamkanak.weekview.TextColorPicker;
68
import com.alamkanak.weekview.WeekViewEvent;
79

810
import java.util.ArrayList;
@@ -22,6 +24,14 @@ protected void onCreate(Bundle savedInstanceState) {
2224

2325
Typeface customTypeface = Typeface.createFromAsset(this.getAssets(), "fonts/Raleway/Raleway-Medium.ttf");
2426
mWeekView.setTypeface(customTypeface);
27+
mWeekView.setTextColorPicker(new TextColorPicker() {
28+
@Override
29+
public int getTextColor(WeekViewEvent event) {
30+
int color = event.getColor();
31+
double a = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
32+
return a < 0.2 ? Color.BLACK : Color.WHITE;
33+
}
34+
});
2535
}
2636

2737
@Override
@@ -51,7 +61,7 @@ public List<? extends WeekViewEvent> onMonthChange(int newYear, int newMonth) {
5161
endTime.set(Calendar.MINUTE, 30);
5262
endTime.set(Calendar.MONTH, newMonth - 1);
5363
event = new WeekViewEvent("Second", getEventTitle(startTime), startTime, endTime);
54-
event.setColor(getResources().getColor(R.color.event_color_02));
64+
event.setColor(getResources().getColor(R.color.event_color_05));
5565
events.add(event);
5666

5767
startTime = Calendar.getInstance();

sample/src/main/res/layout/activity_base.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
app:todayHeaderTextColor="@color/accent"
2929
app:newEventTimeResolutionInMinutes="15"
3030
app:timeColumnResolution="60"
31-
app:dropListenerEnabled="true"/>
31+
app:dropListenerEnabled="true"
32+
app:minOverlappingMinutes="5" />
3233

3334
<TextView
3435
android:id="@+id/draggable_view"

sample/src/main/res/values/colors.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<color name="event_color_02">#f57f68</color>
55
<color name="event_color_03">#87d288</color>
66
<color name="event_color_04">#f8b552</color>
7+
<color name="event_color_05">#88f6f6</color>
78
<color name="toolbar">#efefef</color>
89
<color name="toolbar_text">#8f000000</color>
910
<color name="accent">#2789e4</color>

0 commit comments

Comments
 (0)