diff --git a/library/build.gradle b/library/build.gradle
index d7bfb225..a1c8328d 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -16,11 +16,15 @@ android {
minifyEnabled false
}
}
+ productFlavors {
+ }
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-v4:23.1.1'
+ compile 'com.android.support:recyclerview-v7:23.2.1'
+ compile 'com.android.support:design:23.2.1'
}
-apply from: 'gradle-mvn-push.gradle'
\ No newline at end of file
+apply from: 'gradle-mvn-push.gradle'
diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml
index c2ef964e..6b7f225a 100644
--- a/library/src/main/AndroidManifest.xml
+++ b/library/src/main/AndroidManifest.xml
@@ -18,5 +18,10 @@
+
+
+
+
+
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/Badge.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/Badge.java
new file mode 100644
index 00000000..64da696b
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/Badge.java
@@ -0,0 +1,72 @@
+package com.wdullaer.materialdatetimepicker.date;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class Badge implements Parcelable {
+ public static final int TOP_RIGHT = 1;
+ public static final int TOP_LEFT = 2;
+ public static final int BOTTOM_RIGHT = 3;
+ public static final int BOTTOM_LEFT = 4;
+
+ private int location = TOP_LEFT;
+ private int color = -1;
+ private int displayInt = 0;
+
+ public Badge(int displayInt){
+ this.displayInt = displayInt;
+ }
+
+ public int getLocation() {
+ return location;
+ }
+
+ public void setLocation(int location) {
+ this.location = location;
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public void setColor(int color) {
+ this.color = color;
+ }
+
+ public int getDisplayInt() {
+ return displayInt;
+ }
+
+ public void setDisplayInt(int displayInt) {
+ this.displayInt = displayInt;
+ }
+
+ //parcelling part
+ public Badge(Parcel in){
+ location = in.readInt();
+ color = in.readInt();
+ displayInt = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(location);
+ dest.writeInt(color);
+ dest.writeInt(displayInt);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public Badge createFromParcel(Parcel in) {
+ return new Badge(in);
+ }
+
+ public Badge[] newArray(int size) {
+ return new Badge[size];
+ }
+ };
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/CalendarwBadge.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/CalendarwBadge.java
new file mode 100644
index 00000000..69fcee92
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/CalendarwBadge.java
@@ -0,0 +1,65 @@
+package com.wdullaer.materialdatetimepicker.date;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+
+public class CalendarwBadge extends MonthAdapter.CalendarDay implements Parcelable{
+ private ArrayList badgeArrayList;
+
+ public CalendarwBadge() {super();}
+
+ public CalendarwBadge(long timeInMillis) {super(timeInMillis);}
+
+ public CalendarwBadge(Calendar calendar) {super(calendar);}
+
+ public CalendarwBadge(int year, int month, int day) {
+ super(year, month, day);
+ }
+
+ public ArrayList getBadgeArrayList() {
+ return badgeArrayList;
+ }
+
+ /**
+ * Set list of badges to be displayed.
+ *
+ * @param badgeArrayList List of badges. Maximum number of badges are 4.
+ */
+ public void setBadgeArrayList(ArrayList badgeArrayList) {
+ this.badgeArrayList = badgeArrayList;
+ }
+
+ //parcelling part
+ public CalendarwBadge(Parcel in){
+ year = in.readInt();
+ month = in.readInt();
+ day = in.readInt();
+ in.readTypedList(badgeArrayList, Badge.CREATOR);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(year);
+ dest.writeInt(month);
+ dest.writeInt(day);
+ dest.writeTypedList(badgeArrayList);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public CalendarwBadge createFromParcel(Parcel in) {
+ return new CalendarwBadge(in);
+ }
+
+ public CalendarwBadge[] newArray(int size) {
+ return new CalendarwBadge[size];
+ }
+ };
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePicker.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePicker.java
new file mode 100644
index 00000000..dc0f73ef
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePicker.java
@@ -0,0 +1,39 @@
+package com.wdullaer.materialdatetimepicker.date;
+
+import android.app.FragmentManager;
+import android.os.Build;
+
+import java.util.Calendar;
+
+public class DatePicker {
+
+ /**
+ * Determine appropriate picker dialog to be shown
+ * Option for horizontal scroll only available for Android API >=7
+ *
+ * @param manager Fragment manager of activity where picker dialog will be shown.
+ * @param events Contain details of events to be / not displayed on picker dialog.
+ * Pass null if there is no events to be displayed.
+ * @param tag Picker dialog's tag.
+ * @param scrollDirection Determine picker dialog scroll direction,
+ * use LinearLayoutManager.VERTICAL or LinearLayoutManager.HORIZONTAL,
+ * by default, it is LinearLayoutManager.VERTICAL.
+ */
+ public static void displayDialog(FragmentManager manager, String tag, DatePickerDialog.OnDateSetListener listener,
+ Events events, int scrollDirection){
+
+ Calendar cal = Calendar.getInstance();
+ DatePickerDialog datePickerFragment;
+
+ if(Build.VERSION.SDK_INT >= 7){
+ datePickerFragment = DatePickerDialog.newInstance(listener, cal.get(Calendar.YEAR),
+ cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), events, scrollDirection);
+ }else{
+ if (events!=null) datePickerFragment = DatePickerDialog.newInstance (listener,cal.get(Calendar.YEAR),
+ cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH),events);
+ else datePickerFragment = DatePickerDialog.newInstance (listener,cal.get(Calendar.YEAR),
+ cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
+ }
+ datePickerFragment.show(manager, tag);
+ }
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java
index 3ac4291a..682d8b42 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java
@@ -54,4 +54,12 @@ public interface DatePickerController {
boolean isOutOfRange(int year, int month, int day);
void tryVibrate();
+
+ //EVENTS
+ //---------------------------------------------------------------------
+ boolean isEvent(int year, int month, int day);
+ int getEventColor();
+ boolean isEventClickable();
+ CalendarwBadge getCalendarwBadge();
+ //---------------------------------------------------------------------
}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java
index 19b90d69..6cc72196 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java
@@ -23,11 +23,13 @@
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Color;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.LinearLayoutManager;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -48,11 +50,13 @@
import com.wdullaer.materialdatetimepicker.Utils;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Locale;
+
/**
* Dialog allowing users to select a date.
*/
@@ -114,7 +118,7 @@ public class DatePickerDialog extends DialogFragment implements
private TextView mSelectedMonthTextView;
private TextView mSelectedDayTextView;
private TextView mYearView;
- private DayPickerView mDayPickerView;
+ //private DayPickerView mDayPickerView;
private YearPickerView mYearPickerView;
private int mCurrentView = UNINITIALIZED;
@@ -149,6 +153,14 @@ public class DatePickerDialog extends DialogFragment implements
private String mYearPickerDescription;
private String mSelectYear;
+ private static final String KEY_SCROLL_DIRECTION = "scroll_direction";
+ private static final String KEY_EVENTS = "events";
+
+ private Events mEvents;
+ private DayPickerViewInterface mDayPickerView;
+ private int mScrollDirection = -1;
+ private CalendarwBadge mCalendarwBadge;
+
/**
* The callback used to indicate the user is done filling in the date.
*/
@@ -172,12 +184,13 @@ public interface OnDateChangedListener {
void onDateChanged();
}
-
public DatePickerDialog() {
// Empty constructor required for dialog fragment.
}
/**
+ * Initializer for dialog without displaying events.
+ *
* @param callBack How the parent is notified that the date is set.
* @param year The initial year of the dialog.
* @param monthOfYear The initial month of the dialog.
@@ -198,6 +211,43 @@ public void initialize(OnDateSetListener callBack, int year, int monthOfYear, in
mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
}
+ /**
+ * Initializer for dialog with option to display events.
+ *
+ * @param events Contain details of events to be / not displayed on picker dialog.
+ */
+ public static DatePickerDialog newInstance(OnDateSetListener callBack, int year,
+ int monthOfYear,
+ int dayOfMonth, Events events) {
+ DatePickerDialog ret = new DatePickerDialog();
+ ret.initialize(callBack, year, monthOfYear, dayOfMonth);
+ ret.initialize(events, -1);
+ return ret;
+ }
+
+ /**
+ * Only available for Android API >=7.
+ * Initializer for dialog with option to display events
+ * and scroll orientation.
+ *
+ * @param events Contain details of events to be / not displayed on picker dialog.
+ * @param scrollDirection scrollDirection Determine picker dialog scroll direction,
+ * use LinearLayoutManager.VERTICAL or LinearLayoutManager.HORIZONTAL,
+ * by default, it is LinearLayoutManager.VERTICAL.
+ */
+ public static DatePickerDialog newInstance(OnDateSetListener callBack, int year, int monthOfYear,
+ int dayOfMonth,Events events, int scrollDirection) {
+ DatePickerDialog ret = new DatePickerDialog();
+ ret.initialize(callBack, year, monthOfYear, dayOfMonth);
+ ret.initialize(events, scrollDirection);
+ return ret;
+ }
+
+ public void initialize(Events events, int scrollDirection){
+ this.mEvents = events;
+ this.mScrollDirection = scrollDirection;
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -247,6 +297,8 @@ public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putString(KEY_OK_STRING, mOkString);
outState.putInt(KEY_CANCEL_RESID, mCancelResid);
outState.putString(KEY_CANCEL_STRING, mCancelString);
+ outState.putInt(KEY_SCROLL_DIRECTION, mScrollDirection);
+ outState.putParcelable(KEY_EVENTS, mEvents);
}
@Override
@@ -292,10 +344,14 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
mOkString = savedInstanceState.getString(KEY_OK_STRING);
mCancelResid = savedInstanceState.getInt(KEY_CANCEL_RESID);
mCancelString = savedInstanceState.getString(KEY_CANCEL_STRING);
+ mScrollDirection = savedInstanceState.getInt(KEY_SCROLL_DIRECTION);
+ mEvents = savedInstanceState.getParcelable(KEY_EVENTS);
}
final Activity activity = getActivity();
- mDayPickerView = new SimpleDayPickerView(activity, this);
+ if(Build.VERSION.SDK_INT >= 7)
+ mDayPickerView = new DayPickerRecyclerView(activity, this, mScrollDirection);
+ else mDayPickerView = new SimpleDayPickerView(activity, this);
mYearPickerView = new YearPickerView(activity, this);
// if theme mode has not been set by java code, check if it is specified in Style.xml
@@ -313,8 +369,11 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
view.setBackgroundColor(ContextCompat.getColor(activity, bgColorResource));
mAnimator = (AccessibleDateAnimator) view.findViewById(R.id.animator);
- mAnimator.addView(mDayPickerView);
+ if(Build.VERSION.SDK_INT >= 7)
+ mAnimator.addView((DayPickerRecyclerView)mDayPickerView);
+ else mAnimator.addView((DayPickerView)mDayPickerView);
mAnimator.addView(mYearPickerView);
+
mAnimator.setDateMillis(mCalendar.getTimeInMillis());
// TODO: Replace with animation decided upon by the design team.
Animation animation = new AlphaAnimation(0.0f, 1.0f);
@@ -547,7 +606,7 @@ public void setAccentColor(String color) {
* @param color the accent color you want
*/
public void setAccentColor(@ColorInt int color) {
- mAccentColor = Color.argb(255, Color.red(color), Color.green(color), Color.blue(color));;
+ mAccentColor = Color.argb(255, Color.red(color), Color.green(color), Color.blue(color));
}
/**
@@ -987,4 +1046,48 @@ public void notifyOnDateListener() {
mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH));
}
}
+
+ /**
+ * Check if the specified date (input parameters - year, month, day) is
+ * a date for an event.
+ */
+ @Override
+ public boolean isEvent(int year, int month, int day) {
+ boolean hol = false;
+
+ if (mEvents!=null){
+ ArrayList calList = mEvents.getCalList();
+ for(CalendarwBadge calendar:calList){
+ if(calendar.getYear()==year){
+ if(calendar.getMonth()== month){
+ if(calendar.getDay()== day) {
+ hol = true;
+ mCalendarwBadge = calendar;
+ }
+ }
+ }
+ }
+ }
+
+ return hol;
+ }
+
+ @Override
+ public CalendarwBadge getCalendarwBadge() {
+ return mCalendarwBadge;
+ }
+
+ @Override
+ public int getEventColor() {
+ if (mEvents!=null)
+ return mEvents.getEventColor();
+ else return -1;
+ }
+
+ @Override
+ public boolean isEventClickable() {
+ if (mEvents!=null)
+ return mEvents.isClickable();
+ else return false;
+ }
}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerRecyclerView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerRecyclerView.java
new file mode 100644
index 00000000..3ae9e63f
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerRecyclerView.java
@@ -0,0 +1,337 @@
+package com.wdullaer.materialdatetimepicker.date;
+
+import android.content.Context;
+import android.os.Handler;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+import com.wdullaer.materialdatetimepicker.date.DatePickerDialog.OnDateChangedListener;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+public class DayPickerRecyclerView extends RecyclerView implements DayPickerViewInterface, OnDateChangedListener{
+
+ private static final String TAG = "MonthFragment";
+
+ protected static final int SCROLL_HYST_WEEKS = 2; // Affects when the month selection will change while scrolling up
+ protected static final int GOTO_SCROLL_DURATION = 250; // How long the GoTo fling animation should las
+ protected static final int SCROLL_CHANGE_DELAY = 40; // How long to wait after receiving an onScrollStateChanged notification before acting on it
+ public static final int DAYS_PER_WEEK = 7; // The number of days to display in each week
+ public static int LIST_TOP_OFFSET = -1; // so that the top line will be under the separator
+
+ // You can override these numbers to get a different appearance
+ protected int mNumWeeks = 6;
+ protected boolean mShowWeekNumber = false;
+ protected int mDaysPerWeek = 7;
+ private static SimpleDateFormat YEAR_FORMAT = new SimpleDateFormat("yyyy", Locale.getDefault());
+ protected float mFriction = 1.0f; // These affect the scroll speed and feel
+
+ protected Context mContext;
+ protected Handler mHandler;
+
+ // highlighted time
+ protected MonthAdapter.CalendarDay mSelectedDay = new MonthAdapter.CalendarDay();
+ protected MonthRecyclerViewAdapter mAdapter;
+ protected MonthAdapter.CalendarDay mTempDay = new MonthAdapter.CalendarDay();
+
+ protected int mFirstDayOfWeek; // When the week starts; numbered like Time. (e.g. SUNDAY=0).
+ protected CharSequence mPrevMonthName; // The last name announced by accessibility
+ protected int mCurrentMonthDisplayed; // which month should be displayed/highlighted [0-11]
+ protected long mPreviousScrollPosition; // used for tracking during a scroll
+ protected int mPreviousScrollState = RecyclerView.SCROLL_STATE_IDLE; // used for tracking what state listview is in
+ protected int mCurrentScrollState = RecyclerView.SCROLL_STATE_IDLE; // used for tracking what state listview is in
+
+ private DatePickerController mController;
+ private boolean mPerformingScroll;
+ protected int mScrollDirection;
+
+ public DayPickerRecyclerView(Context context, DatePickerController controller, int scrollDirection) {
+ super(context);
+ mController = controller;
+ mScrollDirection = scrollDirection;
+ setUpRecyclerView();
+ }
+
+ public DayPickerRecyclerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public DayPickerRecyclerView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /*
+ * Sets all the required fields for the recyclerview. Override this method to
+ * set a different recyclerview behavior.
+ */
+ protected void setUpRecyclerView() {
+ setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.MATCH_PARENT));
+
+ setHasFixedSize(true);
+ setVerticalScrollBarEnabled(false);
+ setFadingEdgeLength(0);
+
+ LinearLayoutManager layoutManager;
+ if(mScrollDirection == LinearLayoutManager.VERTICAL || mScrollDirection == LinearLayoutManager.HORIZONTAL)
+ layoutManager = new LinearLayoutManager(getContext(), mScrollDirection, false);
+ else layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
+ setLayoutManager(layoutManager);
+
+ refreshAdapter();
+ onDateChanged();
+ }
+
+ /**
+ * Creates a new adapter if necessary and sets up its parameters. Override
+ * this method to provide a custom adapter.
+ */
+ protected void refreshAdapter() {
+ if (mAdapter == null) {
+ mAdapter = new MonthRecyclerViewAdapter(getContext(),mController);
+ } else {
+ mAdapter.setSelectedDay(mSelectedDay);
+ }
+ // refresh the view with the new parameters
+ setAdapter(mAdapter);
+ }
+
+ /**
+ * Gets the position of the view that is most prominently displayed within the list view.
+ */
+ public int getMostVisiblePosition() {
+ final int firstPosition = ((LinearLayoutManager)getLayoutManager()).findFirstVisibleItemPosition();
+ final int height = getHeight();
+
+ int maxDisplayedHeight = 0;
+ int mostVisibleIndex = 0;
+ int i=0;
+ int bottom = 0;
+ while (bottom < height) {
+ View child = getChildAt(i);
+ if (child == null) {
+ break;
+ }
+ bottom = child.getBottom();
+ int displayedHeight = Math.min(bottom, height) - Math.max(0, child.getTop());
+ if (displayedHeight > maxDisplayedHeight) {
+ mostVisibleIndex = i;
+ maxDisplayedHeight = displayedHeight;
+ }
+ i++;
+ }
+ return firstPosition + mostVisibleIndex;
+ }
+
+ public void onChange(){
+ refreshAdapter();
+ }
+
+ private static String getMonthAndYearString(MonthAdapter.CalendarDay day) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(day.year, day.month, day.day);
+
+ String sbuf = "";
+ sbuf += cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
+ sbuf += " ";
+ sbuf += YEAR_FORMAT.format(cal.getTime());
+ return sbuf;
+ }
+
+ @Override
+ public void onDateChanged(){
+ goTo(mController.getSelectedDay(), false, true, true);
+ }
+
+ @Override
+ public void onScrolled(int dx, int dy) {
+ //mPreviousScrollState = mCurrentScrollState;
+ }
+
+ @Override
+ public void onScrollStateChanged(int state) {
+ // use a post to prevent re-entering onScrollStateChanged before it exits
+ mScrollStateChangedRunnable.doScrollStateChange(state);
+ }
+
+ /**
+ * This moves to the specified time in the view. If the time is not already
+ * in range it will move the list so that the first of the month containing
+ * the time is at the top of the view. If the new time is already in view
+ * the list will not be scrolled unless forceScroll is true. This time may
+ * optionally be highlighted as selected as well.
+ *
+ * @param day The day to move to
+ * @param animate Whether to scroll to the given time or just redraw at the
+ * new location
+ * @param setSelected Whether to set the given time as selected
+ * @param forceScroll Whether to recenter even if the time is already
+ * visible
+ * @return Whether or not the view animated to the new location
+ */
+ public boolean goTo(MonthAdapter.CalendarDay day, boolean animate, boolean setSelected, boolean forceScroll) {
+
+ // Set the selected day
+ if (setSelected) {
+ mSelectedDay.set(day);
+ }
+
+ mTempDay.set(day);
+ int minMonth = mController.getStartDate().get(Calendar.MONTH);
+ final int position = (day.year - mController.getMinYear())
+ * MonthAdapter.MONTHS_IN_YEAR + day.month - minMonth;
+
+ View child;
+ int i = 0;
+ int toporleft;
+ // Find a child that's completely in the view
+ do {
+ child = getChildAt(i++);
+ if (child == null) {
+ break;
+ }
+ toporleft = mScrollDirection == LinearLayoutManager.VERTICAL ? child.getTop() : child.getLeft();
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "child at " + (i - 1) + " has top " + toporleft);
+ }
+ } while (toporleft < 0);
+
+ // Compute the first and last position visible
+ int selectedPosition;
+ if (child != null) {
+ selectedPosition = getLayoutManager().getPosition(child);
+ } else {
+ selectedPosition = 0;
+ }
+
+ if (setSelected) {
+ mAdapter.setSelectedDay(mSelectedDay);
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "GoTo position " + position);
+ }
+ // Check if the selected day is now outside of our visible range
+ // and if so scroll to the month that contains it
+ if (position != selectedPosition || forceScroll) {
+ setMonthDisplayed(mTempDay);
+ mPreviousScrollState = RecyclerView.SCROLL_STATE_SETTLING;
+ if (animate) {
+ smoothScrollToPosition(position);
+ return true;
+ } else {
+ postSetSelection(position);
+ }
+ } else if (setSelected) {
+ setMonthDisplayed(mSelectedDay);
+ }
+ return false;
+ }
+
+ public void postSetSelection(final int position) {
+ clearFocus();
+ post(new Runnable() {
+
+ @Override
+ public void run() {
+ scrollToPosition(position);
+ onScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE);
+ }
+ });
+ }
+
+ /**
+ * Sets the month displayed at the top of this view based on time. Override
+ * to add custom events when the title is changed.
+ */
+ protected void setMonthDisplayed(MonthAdapter.CalendarDay date) {
+ mCurrentMonthDisplayed = date.month;
+ invalidate();
+ }
+
+ protected ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable();
+
+ protected class ScrollStateRunnable implements Runnable {
+ private int mNewState;
+
+ /**
+ * Sets up the runnable with a short delay in case the scroll state
+ * immediately changes again.
+ *
+ * @param scrollState The new state it changed to
+ */
+ public void doScrollStateChange(int scrollState) {
+ mHandler = new Handler();
+ mHandler.removeCallbacks(this);
+ mNewState = scrollState;
+ mHandler.postDelayed(this, SCROLL_CHANGE_DELAY);
+ }
+
+ @Override
+ public void run() {
+ mCurrentScrollState = mNewState;
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG,
+ "new scroll state: " + mNewState + " old state: " + mPreviousScrollState);
+ }
+ // Fix the position after a scroll or a fling ends
+ if (mNewState == RecyclerView.SCROLL_STATE_IDLE
+ && mPreviousScrollState != RecyclerView.SCROLL_STATE_IDLE
+ && mPreviousScrollState != RecyclerView.SCROLL_STATE_DRAGGING) {
+ mPreviousScrollState = mNewState;
+
+ int firstPosition = ((LinearLayoutManager)getLayoutManager()).findFirstVisibleItemPosition();
+ int lastPosition = ((LinearLayoutManager)getLayoutManager()).findLastVisibleItemPosition();
+ boolean scroll = firstPosition != 0 && lastPosition != getLayoutManager().getChildCount() - 1;
+ final int midpoint = getHeight() / 2;
+ int toporleft;
+ int bottomorright;
+
+ int i = 0;
+ View child = getChildAt(i);
+ if(mScrollDirection == LinearLayoutManager.VERTICAL){
+ while (child != null && child.getBottom() <= 0) {
+ child = getChildAt(++i);
+ }
+ if (child == null) {return;} // The view is no longer visible, just return
+
+ toporleft = child.getTop();
+ bottomorright = child.getBottom();
+
+ if (scroll && toporleft < LIST_TOP_OFFSET) {
+ if (bottomorright > midpoint) {
+ smoothScrollBy(0, toporleft);
+ } else {
+ smoothScrollBy(0, bottomorright);
+ }
+ }
+
+ }else{
+ while (child != null && child.getRight() <= 0) {
+ child = getChildAt(++i);
+ }
+ if (child == null) {return;} // The view is no longer visible, just return
+
+ toporleft = child.getLeft();
+ bottomorright = child.getRight();
+
+ if (scroll && toporleft < LIST_TOP_OFFSET) {
+ if (bottomorright > midpoint) {
+ smoothScrollBy(toporleft, 0);
+ } else {
+ smoothScrollBy(bottomorright, 0);
+ }
+ }
+ }
+
+ } else {
+ mPreviousScrollState = mNewState;
+ }
+ }
+ }
+
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java
index 303488f3..75f9b78b 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java
@@ -42,7 +42,7 @@
/**
* This displays a list of months in a calendar format with selectable days.
*/
-public abstract class DayPickerView extends ListView implements OnScrollListener,
+public abstract class DayPickerView extends ListView implements DayPickerViewInterface, OnScrollListener,
OnDateChangedListener {
private static final String TAG = "MonthFragment";
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerViewInterface.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerViewInterface.java
new file mode 100644
index 00000000..9b31d466
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerViewInterface.java
@@ -0,0 +1,11 @@
+package com.wdullaer.materialdatetimepicker.date;
+
+/**
+ * Created by DroidGreen on 4/6/16.
+ */
+public interface DayPickerViewInterface {
+ int getMostVisiblePosition();
+ void postSetSelection(final int position);
+ void onDateChanged();
+ void onChange();
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/Events.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/Events.java
new file mode 100644
index 00000000..fb33130c
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/Events.java
@@ -0,0 +1,63 @@
+package com.wdullaer.materialdatetimepicker.date;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+
+public class Events implements Parcelable{
+ private int eventColor = -1;
+ private boolean clickable;
+ private ArrayList calList = null;
+
+ public Events(boolean clickable){this.clickable = clickable;}
+
+ public boolean isClickable() {return clickable;}
+
+ /**
+ * @param clickable Set true if user can select an event date. Set false, otherwise.
+ */
+ public void setClickable(boolean clickable) {this.clickable = clickable;}
+
+ public ArrayList getCalList() {
+ return calList;
+ }
+
+ /**
+ * @param calList List of event details including dates and badges (if any).
+ */
+ public void setCalList(ArrayList calList) {
+ this.calList = calList;
+ }
+
+ public int getEventColor(){return eventColor;}
+
+ public void setEventColor(int eventColor){this.eventColor = eventColor;}
+
+ //parcelling part
+ public Events(Parcel in){
+ eventColor = in.readInt();
+ clickable = (Boolean) in.readValue( null );
+ in.readTypedList(calList, CalendarwBadge.CREATOR);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(eventColor);
+ dest.writeValue(clickable);
+ dest.writeTypedList(calList);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public Events createFromParcel(Parcel in) {
+ return new Events(in);
+ }
+
+ public Events[] newArray(int size) {return new Events[size];}
+ };
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthAdapter.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthAdapter.java
index bc03198a..f5835e09 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthAdapter.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthAdapter.java
@@ -106,7 +106,7 @@ public int getDay() {
}
public MonthAdapter(Context context,
- DatePickerController controller) {
+ DatePickerController controller) {
mContext = context;
mController = controller;
init();
@@ -229,4 +229,4 @@ protected void onDayTapped(CalendarDay day) {
mController.onDayOfMonthSelected(day.year, day.month, day.day);
setSelectedDay(day);
}
-}
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthRecyclerViewAdapter.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthRecyclerViewAdapter.java
new file mode 100644
index 00000000..ef6607ed
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthRecyclerViewAdapter.java
@@ -0,0 +1,125 @@
+package com.wdullaer.materialdatetimepicker.date;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.TextView;
+
+import com.wdullaer.materialdatetimepicker.R;
+
+import java.util.Calendar;
+import java.util.HashMap;
+
+public class MonthRecyclerViewAdapter extends RecyclerView.Adapter{
+ private static final String TAG = "SimpleMonthAdapter";
+
+ private final Context mContext;
+ protected final DatePickerController mController;
+
+ private MonthAdapter.CalendarDay mSelectedDay;
+
+ protected static int WEEK_7_OVERHANG_HEIGHT = 7;
+ protected static final int MONTHS_IN_YEAR = 12;
+
+
+ public MonthRecyclerViewAdapter(Context context, DatePickerController controller) {
+ mContext = context;
+ mController = controller;
+ mSelectedDay = new MonthAdapter.CalendarDay(System.currentTimeMillis());
+ setSelectedDay(mController.getSelectedDay());
+ }
+
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ public HashMap drawingParams = null;
+
+ public ViewHolder(SimpleMonthView v) {
+ super(v);
+
+ if (drawingParams == null) {
+ drawingParams = new HashMap<>();
+ }
+ drawingParams.clear();
+ }
+ }
+ @Override
+ public MonthRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+
+ SimpleMonthView v = new SimpleMonthView(mContext, null, mController);
+ RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(
+ RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.MATCH_PARENT);
+ v.setLayoutParams(params);
+ v.setClickable(true);
+ v.setOnDayClickListener(new MonthView.OnDayClickListener() {
+ @Override
+ public void onDayClick(MonthView view, MonthAdapter.CalendarDay day) {
+ if (day != null) {
+ onDayTapped(day);
+ }
+ }
+ });
+
+ return new ViewHolder(v);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+
+ final int month = (position + mController.getStartDate().get(Calendar.MONTH)) % MONTHS_IN_YEAR;
+ final int year = (position + mController.getStartDate().get(Calendar.MONTH)) / MONTHS_IN_YEAR + mController.getMinYear();
+
+ int selectedDay = -1;
+ if (isSelectedDayInMonth(year, month)) {
+ selectedDay = mSelectedDay.day;
+ }
+
+ // Invokes requestLayout() to ensure that the recycled view is set with the appropriate
+ // height/number of weeks before being displayed.
+ //((SimpleMonthView)holder.itemView).reuse();
+
+ holder.drawingParams.put(SimpleMonthView.VIEW_PARAMS_SELECTED_DAY, selectedDay);
+ holder.drawingParams.put(SimpleMonthView.VIEW_PARAMS_YEAR, year);
+ holder.drawingParams.put(SimpleMonthView.VIEW_PARAMS_MONTH, month);
+ holder.drawingParams.put(SimpleMonthView.VIEW_PARAMS_WEEK_START, mController.getFirstDayOfWeek());
+ ((SimpleMonthView)holder.itemView).setMonthParams(holder.drawingParams);
+ holder.itemView.invalidate();
+ }
+
+ @Override
+ public int getItemCount() {
+ Calendar endDate = mController.getEndDate();
+ Calendar startDate = mController.getStartDate();
+ int endMonth = endDate.get(Calendar.YEAR) * MONTHS_IN_YEAR + endDate.get(Calendar.MONTH);
+ int startMonth = startDate.get(Calendar.YEAR) * MONTHS_IN_YEAR + startDate.get(Calendar.MONTH);
+ return endMonth - startMonth + 1;
+ //return ((mController.getMaxYear() - mController.getMinYear()) + 1) * MONTHS_IN_YEAR;
+ }
+
+ private boolean isSelectedDayInMonth(int year, int month) {
+ return mSelectedDay.year == year && mSelectedDay.month == month;
+ }
+
+ /**
+ * Updates the selected day and related parameters.
+ *
+ * @param day The day to highlight
+ */
+ public void setSelectedDay(MonthAdapter.CalendarDay day) {
+ mSelectedDay = day;
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Maintains the same hour/min/sec but moves the day to the tapped day.
+ *
+ * @param day The day that was tapped
+ */
+ protected void onDayTapped(MonthAdapter.CalendarDay day) {
+ mController.tryVibrate();
+ mController.onDayOfMonthSelected(day.year, day.month, day.day);
+ setSelectedDay(day);
+ }
+
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java
index ae184b88..410b6b52 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java
@@ -117,6 +117,8 @@ public abstract class MonthView extends View {
protected static int MONTH_DAY_LABEL_TEXT_SIZE;
protected static int MONTH_HEADER_SIZE;
protected static int DAY_SELECTED_CIRCLE_SIZE;
+ protected static int BADGE_CIRCLE_SIZE;
+ protected static int BADGE_NUMBER_TEXT_SIZE;
// used for scaling to the device density
protected static float mScale = 0;
@@ -133,6 +135,8 @@ public abstract class MonthView extends View {
protected Paint mMonthTitlePaint;
protected Paint mSelectedCirclePaint;
protected Paint mMonthDayLabelPaint;
+ protected Paint mBadgePaint;
+ protected Paint mBadgeNumPaint;
private final Formatter mFormatter;
private final StringBuilder mStringBuilder;
@@ -229,6 +233,9 @@ public MonthView(Context context, AttributeSet attr, DatePickerController contro
MONTH_HEADER_SIZE = res.getDimensionPixelOffset(R.dimen.mdtp_month_list_item_header_height);
DAY_SELECTED_CIRCLE_SIZE = res
.getDimensionPixelSize(R.dimen.mdtp_day_number_select_circle_radius);
+ BADGE_CIRCLE_SIZE = res
+ .getDimensionPixelSize(R.dimen.mdtp_badge_circle_radius);
+ BADGE_NUMBER_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.mdtp_badge_num_size);
mRowHeight = (res.getDimensionPixelOffset(R.dimen.mdtp_date_picker_view_animator_height)
- getMonthHeaderSize()) / MAX_NUM_ROWS;
@@ -312,7 +319,7 @@ protected void initView() {
mMonthDayLabelPaint.setAntiAlias(true);
mMonthDayLabelPaint.setTextSize(MONTH_DAY_LABEL_TEXT_SIZE);
mMonthDayLabelPaint.setColor(mMonthDayTextColor);
- mMonthDayLabelPaint.setTypeface(TypefaceHelper.get(getContext(),"Roboto-Medium"));
+ mMonthDayLabelPaint.setTypeface(TypefaceHelper.get(getContext(), "Roboto-Medium"));
mMonthDayLabelPaint.setStyle(Style.FILL);
mMonthDayLabelPaint.setTextAlign(Align.CENTER);
mMonthDayLabelPaint.setFakeBoldText(true);
@@ -323,6 +330,21 @@ protected void initView() {
mMonthNumPaint.setStyle(Style.FILL);
mMonthNumPaint.setTextAlign(Align.CENTER);
mMonthNumPaint.setFakeBoldText(false);
+
+ mBadgePaint = new Paint();
+ mBadgePaint.setAntiAlias(true);
+ mBadgePaint.setColor(mTodayNumberColor);
+ mBadgePaint.setTextAlign(Align.CENTER);
+ mBadgePaint.setStyle(Style.FILL);
+ mBadgePaint.setAlpha(SELECTED_CIRCLE_ALPHA);
+
+ mBadgeNumPaint = new Paint();
+ mBadgeNumPaint.setAntiAlias(true);
+ mBadgeNumPaint.setTextSize(BADGE_NUMBER_TEXT_SIZE);
+ mBadgeNumPaint.setColor(mSelectedDayTextColor);
+ mBadgeNumPaint.setStyle(Style.FILL);
+ mBadgeNumPaint.setTextAlign(Align.CENTER);
+ mBadgeNumPaint.setFakeBoldText(false);
}
@Override
@@ -585,6 +607,9 @@ private void onDayClick(int day) {
return;
}
+ if(!mController.isEventClickable()&&mController.isEvent(mYear, mMonth, day)){
+ return;
+ }
if (mOnDayClickListener != null) {
mOnDayClickListener.onDayClick(this, new CalendarDay(mYear, mMonth, day));
@@ -820,4 +845,39 @@ protected CharSequence getItemDescription(int day) {
public interface OnDayClickListener {
void onDayClick(MonthView view, CalendarDay day);
}
+
+ /**
+ * Draw events & badges based on settings.
+ */
+ protected void drawEvent(Canvas canvas, int x, int y){
+ int eventColor = mController.getEventColor();
+ mMonthNumPaint.setColor(eventColor==-1?mTodayNumberColor:eventColor);
+
+ CalendarwBadge calendar = mController.getCalendarwBadge();
+ if(calendar.getBadgeArrayList()!=null){
+ for(Badge badge:calendar.getBadgeArrayList()){
+ // default - TOP_LEFT
+ int xp = x - MINI_DAY_NUMBER_TEXT_SIZE;
+ int yp = y - (MINI_DAY_NUMBER_TEXT_SIZE / 3) - MINI_DAY_NUMBER_TEXT_SIZE;
+ switch (badge.getLocation()){
+ case Badge.BOTTOM_RIGHT:
+ xp = x + MINI_DAY_NUMBER_TEXT_SIZE;
+ yp = y - (MINI_DAY_NUMBER_TEXT_SIZE / 3) + MINI_DAY_NUMBER_TEXT_SIZE;
+ break;
+ case Badge.BOTTOM_LEFT:
+ xp = x - MINI_DAY_NUMBER_TEXT_SIZE;
+ yp = y - (MINI_DAY_NUMBER_TEXT_SIZE / 3) + MINI_DAY_NUMBER_TEXT_SIZE;
+ break;
+ case Badge.TOP_RIGHT:
+ xp = x + MINI_DAY_NUMBER_TEXT_SIZE;
+ yp = y - (MINI_DAY_NUMBER_TEXT_SIZE / 3) - MINI_DAY_NUMBER_TEXT_SIZE;
+ break;
+ }
+
+ int badgeColor = badge.getColor(); if(badgeColor!=-1)mBadgePaint.setColor(badgeColor);
+ canvas.drawCircle(xp, yp, BADGE_CIRCLE_SIZE, mBadgePaint);
+ canvas.drawText(String.format("%d", badge.getDisplayInt()), xp, yp + (MINI_DAY_NUMBER_TEXT_SIZE / 4), mBadgeNumPaint);
+ }
+ }
+ }
}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java
index 3533a411..1c5f2af2 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java
@@ -21,6 +21,8 @@
import android.graphics.Typeface;
import android.util.AttributeSet;
+import java.util.ArrayList;
+
public class SimpleMonthView extends MonthView {
public SimpleMonthView(Context context, AttributeSet attr, DatePickerController controller) {
@@ -51,6 +53,9 @@ else if (mSelectedDay == day) {
mMonthNumPaint.setColor(mSelectedDayTextColor);
} else if (mHasToday && mToday == day) {
mMonthNumPaint.setColor(mTodayNumberColor);
+ if (mController.isEvent(year, month, day)){drawEvent(canvas,x,y);}
+ } else if (mController.isEvent(year, month, day)){
+ drawEvent(canvas,x,y);
} else {
mMonthNumPaint.setColor(isHighlighted(year, month, day) ? mHighlightedDayTextColor : mDayTextColor);
}
diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml
index 4edd9ada..13d06e40 100644
--- a/library/src/main/res/values/dimens.xml
+++ b/library/src/main/res/values/dimens.xml
@@ -63,6 +63,8 @@
12sp
64dp
22dp
+ 6dp
+ 8sp
48dp
14sp