diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0d224931..00000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: android - -jdk: - - oraclejdk8 - -android: - components: - - tools - - platform-tools - - build-tools-28.0.3 - - android-28 - - extra-android-m2repository - - extra-google-m2repository - -script: - - ./gradlew clean check assemble -Dpre-dex=false - -notifications: - email: false - -sudo: false - -cache: - directories: - - $HOME/.gradle \ No newline at end of file diff --git a/docs/CUSTOMIZATION.md b/docs/CUSTOMIZATION.md deleted file mode 100644 index 04451650..00000000 --- a/docs/CUSTOMIZATION.md +++ /dev/null @@ -1,134 +0,0 @@ -Customization Options -===================== - -```xml - -``` - -## Tile Size - -One of the fundamental concepts in this library is that of `tileSize`. -Even if you don't set one explicitly, one is calculated and is used in sizing the view. - -By default, with no tile size set, the view will scale to fill as much space as it can. -The functionality is similar to ImageView with `adjustViewBounds` set to true. - -If a tileSize is set, that will override the `layout_width` and `layout_height` set. - -The view is 7 tiles wide and 8 tiles high (with the top bar visible). - -### Width and Height - -You also have the possibility to use `tileWidth` and `tileHeight` separately. I would recommend using either `tileSize` or, `tileWidth` and `tileHeight`. - - -## Date Selection - -We support four modes of selection: single, multiple, range or none. The default is single selection. -The mode can be changed by calling `setSelectionMode()` and passing the appropriate constant (`SELECTION_MODE_NONE`, `SELECTION_MODE_SINGLE`, `SELECTION_MODE_RANGE` or `SELECTION_MODE_MULTIPLE`). -If you change to single selection, all selected days except the last selected will be cleared. -If you change to none or range, all selected days will be cleared. - -You can set an `OnDateSelectedListener` to listen for selections, make sure to take into account multiple calls for the same date and state. In case of range selection, use `OnRangeSelectedListener` which returns the list of date from the range including first and last. -You can manually select or deselect dates by calling `setDateSelected()`. -Use `setSelectedDate()` to clear the current selection(s) and select the provided date. - -There are also: `clearSelection()`, `getSelectedDates()`, and `getSelectionMode()`; which should work as you would expect. - - -## Showing Other Dates - -By default, only days of one month, in the min-max range, are shown. -You can customize this by setting `mcv_showOtherDates` in xml, or by calling `setShowOtherDates()`. - -Avaliable flags are: -* `other_months`: Show additional days from the previous and next months - * This flag also enables the `out_of_range` flag, to prevent weird blank areas that nobody wants. -* `out_of_range`: Show dates that are outside of the minimum and maximum date range - * This will only affect dates in the current month. Use the `other_months` flag to show other months. -* `decorated_disabled`: Show dates that are set as disabled by a decorator - * This will only affect dates in the current month and inside the minimum/maximum date range. -* `none`: An alias that sets none of the flags -* `all`: An alias that sets all of the flags -* `defaults`: An alias of flags set by default. Currently this is only `decorated_disabled`. - -There are similar constants on `MaterialCalendarView` such as `MaterialCalendarView.SHOW_DECORATED_DISABLED`. - - -## Selection Color - -The default color of the calendar selector is the one set referenced by `?android:attr/colorAccent` on 5.0+ or `?attr/colorAccent` from the AppCompat library (black as a last resort). -You can provide a custom color by setting `mcv_selectionColor` in xml, or by calling `setSelectionColor()`. - -If you want more control than just color, you can use the [decorator api](DECORATORS.md) to set a [custom selector](CUSTOM_SELECTORS.md). - - -## Topbar Options - -### Visibility - -You can hide or show the topbar (arrow buttons and month label) by calling `setTopbarVisible(boolean)` -The default is visible. - -### Arrows - -If you want to change the color or the drawables, they can be set in xml using `mcv_leftArrow` and `mcv_rightArrow` or by calling `setLeftArrow()` and `setRightArrow()`. - -## Custom Labels - -### Header - -You can customize the label displayed in the header by setting a custom `TitleFormatter` by calling `setTitleFormatter()`. -The formatter's `format()` method will be called with a `CalendarDay` containing the month and year you should format. -The default implementation uses a `SimpleDateFormat` with a format of `"MMMM yyyy"`. -The library provides a `DateFormatTitleFormatter` and `MonthArrayTitleFormatter` for convenience. - -You can also set a string array resource with `mcv_monthLabels` that will use the `MonthArrayTitleFormatter` to format the title with the months provided. - -### WeekDays - -You can supply a custom formatter for weekdays with a `WeekDayFormatter` by calling `setWeekDayFormatter()`. -The default implementation is a `CalendarWeekDayFormatter`, which uses `java.util.Calendar` to get weekday labels. -We also provide `ArrayWeekDayFormatter`, which uses `CharSequence` array as week day labels. -You can set `mcv_weekDayLabels` in xml with a string array resource, which will set an `ArrayWeekDayFormatter`. - -### DayFormatter - -You can set custom day labels by passing a `DayFormatter` to the `setDayFormatter()` method. -The default is a `DateFormatDayFormatter`, which uses a `SimpleDateFormat` with format `"d"`. - -Unlike the formatters for Header or WeekDays, this formatter returns a String. -If you want to use spans on your day labels, you will need to use the [decorator api](DECORATORS.md). - - -## Text Appearances - -There are three different text appearances you can set: - -* Header: `mcv_headerTextAppearance` or `setHeaderTextAppearance()` -* Weekday: `mcv_weekDayTextAppearance` or `setWeekDayTextAppearance()` -* Date: `mcv_dateTextAppearance` or `setDateTextAppearance()` - -The header text appearance is used for the topbar month label. -The weekday is for the row of weekday labels, and date is for the individual days. - -For date text appearance, make sure you respond to presses and states. [Read more here](CUSTOM_SELECTORS.md). diff --git a/docs/CUSTOMIZATION_BUILDER.md b/docs/CUSTOMIZATION_BUILDER.md deleted file mode 100644 index 0b18dbab..00000000 --- a/docs/CUSTOMIZATION_BUILDER.md +++ /dev/null @@ -1,57 +0,0 @@ -State builder -============= - -Certain parameters are only modifiable using the state builder of the `MaterialCalendarView`. -Using the builder prevents from updating the view each time one of the setters is called. The view is updated when calling `Builder#commit()` and that improve performances. -Previously, the fields could be customize using casual setters. - -Here is a concrete example of how to use the builder: - -```java -mcv.state().edit() - .setFirstDayOfWeek(Calendar.WEDNESDAY) - .setMinimumDate(CalendarDay.from(2016, 4, 3)) - .setMaximumDate(CalendarDay.from(2016, 5, 12)) - .setCalendarDisplayMode(CalendarMode.WEEKS) - .setSaveCurrentPosition(true) - .commit(); -``` - -## state.edit() vs newState() - -Using `mcv.state().edit()` will preserve the current state of the `MaterialCalendarView` while `mcv.newState()` will initialize the builder with new parameters. -Only the fields that are modifiable using the builder can be reset or edit. Here is the list of the fields: - -- First Day Of Week -- Minimum Date -- Maximum Date -- Calendar Display Mode - -As an example, if you are setting `firstDayOfWeek` inside your xml, and you want to preserve the field when using the builder, you should use `state.edit()`. -However if you don't want to preserve any current parameters from the list above, use `newState()`. In most cases `state.edit()` should be the right method to use. - -### First Day Of The Week - -The default first day of the week is Sunday. You can set a custom day of the week by setting `mcv_firstDayOfWeek` in xml, or by calling `setFirstDayOfWeek()`. -The xml attribute is an enum of `sunday` through `saturday` and `setFirstDayOfWeek()` accepts values from `java.util.Calendar` such as `Calendar.MONDAY`. - - -### Date Ranges - -By default, the calendar displays months for 200 years before today and 200 years after. -You can specify different minimum and maximum dates by calling `setMinimumDate(CalendarDay)` and `setMaximumDate(CalendarDay)`. -Passing `null` will reset back to the default 200 years. -There are also convenience methods that accept a `Calendar` or a `Date` object and convert them to a `CalendarDay` using the relevant `CalendarDay.from()` factory method. - -### Calendar Display Mode - -`MaterialCalendarView` propose two display modes: weekly and monthly. You can set the display mode in your xml using the attribute `mcv_calendarMode` with `month` for monthly mode, or `week` for weekly mode. -You can also use the builder `setCalendarDisplayMode(CalendarMode)` parameter. - -It is **important** to note that the `CalendarMode.WEEKS` is still experimental. - -### Save current position between week and month mode - -`SaveCurrentPosition` is set to false by default. When switching between week and month mode, the view redirect you to the today's date. - -When `setSaveCurrentPosition` is set to `true`, the calendar will stay on the current position or last selected date. \ No newline at end of file diff --git a/docs/CUSTOM_SELECTORS.md b/docs/CUSTOM_SELECTORS.md deleted file mode 100644 index fd0a1cab..00000000 --- a/docs/CUSTOM_SELECTORS.md +++ /dev/null @@ -1,99 +0,0 @@ -Custom Selectors -================ - -This doc describes how to create custom stateful drawables and colors to be used in the view. - -## Stateful-ness in Material CalendarView - -There are several places in the view where reacting to state would be useful. -The most obvious is the date selection indicator, but state can also be represented with custom -backgrounds set by decorators or text colors. - -The state that is used to represent selected days is `android:checked`. -Days can also be disabled, which is represented with `android:enabled`. - -### Drawables - -If you want to set a custom selector or background, you'll need to make sure your drawable responds to state. -This is most easily done by using a `selector` in your xml or use `StateListDrawable`. - -Here is a basic example of a selector: - -```xml - - - - - - - - -``` - -This is the (truncated) code used to generate the default selector: - - ```java -private static Drawable generateSelector() { - StateListDrawable drawable = new StateListDrawable(); - drawable.setExitFadeDuration(...); - drawable.addState(new int[]{android.R.attr.state_checked}, generateCircleDrawable(...)); - drawable.addState(new int[]{android.R.attr.state_pressed}, generateCircleDrawable(...)); - drawable.addState(new int[]{}, generateCircleDrawable(Color.TRANSPARENT)); - return drawable; -} - ``` - -### Text Color - -In some cases, the default text color isn't the one you want. -In this case, you will need to create a custom text appearance style that sets the text color you need. -You do this by setting `mcv_dateTextAppearance` or calling `setDateTextAppearance()`. -This library provides a text appearance style `TextAppearance.MaterialCalendarWidget.Date`, for you to extend. -And it also has two stateful colors, `mcv_text_date_dark` or `mcv_text_date_light` (which is the default). - -Here's an example for a dark theme and a light selector: - -```xml - -``` - -Here's an example for a dark theme and a dark selector: - -```xml - - -``` -```xml - - - - - - - - - - - - -``` diff --git a/docs/DECORATORS.md b/docs/DECORATORS.md deleted file mode 100644 index 64499ae8..00000000 --- a/docs/DECORATORS.md +++ /dev/null @@ -1,87 +0,0 @@ -DayViewDecorators -================= - -The decorator API is a flexible way to customize individual days. -Specifically, it allows you to: - -* Set custom backgrounds -* Set custom selectors -* Apply spans to the entire day's text - * We provide `DotSpan` which will draw a dot centered below the text -* Set dates as disabled - -This doc will explain how the API works and examples of how to use it. - -## How It Works - -A `DayViewDecorator` is an interface that has only two methods you need to implement, `shouldDecorate(CalendarDay)` and `decorate(DayViewFacade)`. -`shouldDecorate()` is called for every date in the calendar to determine if the decorator should be applied to that date. -`decorate()` is called only one time to gather the customizations used for this decorator. -This is so we can cache the decorations and efficiently apply them to many days. - -The `decorate()` method provides you with a `DayViewFacade` that has four methods to allow decoration: - -1. `setBackgroundDrawable(Drawable)` - * You can set a drawable to draw behind everything else. - * This also responds to state changes. -2. `setSelectionDrawable(Drawable)` - * This customizes the selection indicator. -3. `addSpan(Object)` - * Allows you to set a span on the entire day label. - * We provide a `DotSpan` that draws a dot centered below the label. - * For an introduction to spans, see [this article](http://androidcocktail.blogspot.com/2014/03/android-spannablestring-example.html). - * If you want to learn more about custom spans, check out [this article](http://flavienlaurent.com/blog/2014/01/31/spans/). - * The span is set using `setSpan(yourSpan, 0, label.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);` -4. `setDaysDisabled(boolean)` - * Allows you to disable and re-enable days. - * This will not affect minimum and maximum dates. - * Days decorated as disabled can be re-enabled with other decorators. - -If one of your decorators changes after it has been added to the calendar view, -make sure you call `invalidateDecorators()` to have those changes reflected. -The decorators are automatically invalidated when you add or remove decorators from the view. - -To add a decorator to the calendar, you can call `addDecorator()`. -The order that decorators are added are the order in which they will be applied. -You can remove decorators by calling `removeDecorator()` or `removeDecorators()`. - -When implementing a `DayViewDecorator`, make sure that they are as efficient as possible. -Remember that `shouldDecorate()` needs to be called 42 times for each month view. -An easy way to be more efficient is to convert your data to `CalendarDay`s outside of `shouldDecorate()`. - -## Responding To State - -If you provide custom drawables, make sure they respond to touches and states. -Read more in the [custom selector documentation](CUSTOM_SELECTORS.md). - -## Examples - -This section details some example uses. -You can also check out the sample app's `BasicActivityDecorated` activity for some examples. - -### Events - -Here is a simple example decorator that will draw a dot under a set of dates. - -```java -public class EventDecorator implements DayViewDecorator { - - private final int color; - private final HashSet dates; - - public EventDecorator(int color, Collection dates) { - this.color = color; - this.dates = new HashSet<>(dates); - } - - @Override - public boolean shouldDecorate(CalendarDay day) { - return dates.contains(day); - } - - @Override - public void decorate(DayViewFacade view) { - view.addSpan(new DotSpan(5, color)); - } -} -``` diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index ee4468d5..00000000 --- a/docs/README.md +++ /dev/null @@ -1,35 +0,0 @@ -Documentation -============= - -This is where in depth documentation will be going. - -## Customization Options - -Check out most of the customization options [here](CUSTOMIZATION.md). - -## Customization using state builder - -Some of the customization can be made using a builder. Using a builder for those parameters helps preventing bugs and improves performances. -Those parameters are: - -- [First Day Of Week](CUSTOMIZATION_BUILDER.md#first-day-of-the-week) -- [Minimum Date](CUSTOMIZATION_BUILDER.md#date-ranges) -- [Maximum Date](CUSTOMIZATION_BUILDER.md#date-ranges) -- [Calendar Display Mode](CUSTOMIZATION_BUILDER.md#calendar-display-mode) - -The documentation is available [here](CUSTOMIZATION_BUILDER.md). - -## Events, Highlighting, Custom Selectors, and More! - -All of this and more can be done via the decorator api. Please check out the [decorator documentation](DECORATORS.md). - -## Custom Selectors and Colors - -If you provide custom drawables or colors, you'll want to make sure they respond to state. -Check out the [documentation for custom states](CUSTOM_SELECTORS.md). - -## TODO - -- Write and organize the documentation. Focus on customization with real world scenarios. -- Improve performances. -- Add test cases. \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1b1340d5..64544d28 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ -distributionBase = GRADLE_USER_HOME -distributionPath = wrapper/dists -distributionUrl = https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip -zipStoreBase = GRADLE_USER_HOME -zipStorePath = wrapper/dists +#Tue Apr 07 21:03:41 EET 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/images/hero.png b/images/hero.png deleted file mode 100644 index 1f678e06..00000000 Binary files a/images/hero.png and /dev/null differ diff --git a/images/screencast.gif b/images/screencast.gif deleted file mode 100644 index 94b826fb..00000000 Binary files a/images/screencast.gif and /dev/null differ diff --git a/library/build.gradle b/library/build.gradle index 824727a5..6cc36232 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -3,11 +3,11 @@ apply plugin: 'maven' apply plugin: 'com.github.dcendents.android-maven' android { - compileSdkVersion rootProject.ext.compileSdkVersion + compileSdkVersion 28 defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion + minSdkVersion 16 + targetSdkVersion 27 versionCode Integer.parseInt(project.VERSION_CODE) versionName project.VERSION_NAME @@ -23,6 +23,10 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + buildTypes { + staging { + } + } } group = "com.github.prolificinteractive" @@ -30,13 +34,13 @@ version = android.defaultConfig.versionName archivesBaseName = 'material-calendarview' dependencies { - implementation rootProject.ext.threeTenAbp - implementation rootProject.ext.supportV4 - implementation rootProject.ext.supportAppCompat - implementation rootProject.ext.supportAnnotations + implementation 'com.jakewharton.threetenabp:threetenabp:1.1.1' + implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.annotation:annotation:1.0.0' - rootProject.ext.testDep.each { testImplementation it } - rootProject.ext.androidTestDep.each { androidTestImplementation it } + // SSP / SDP + implementation 'com.intuit.ssp:ssp-android:1.0.6' + implementation 'com.intuit.sdp:sdp-android:1.0.6' } tasks.withType(Javadoc) { diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml index 095af6b0..d1e1a33c 100644 --- a/library/src/main/AndroidManifest.xml +++ b/library/src/main/AndroidManifest.xml @@ -1,14 +1,12 @@ + package="com.prolificinteractive.materialcalendarview"> - - - + + + diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/AnimatorListener.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/AnimatorListener.java index cf9ee34d..d4a793be 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/AnimatorListener.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/AnimatorListener.java @@ -3,19 +3,19 @@ import android.animation.Animator; class AnimatorListener implements Animator.AnimatorListener { - @Override - public void onAnimationStart(Animator animator) { - } + @Override + public void onAnimationStart(Animator animator) { + } - @Override - public void onAnimationEnd(Animator animator) { - } + @Override + public void onAnimationEnd(Animator animator) { + } - @Override - public void onAnimationCancel(Animator animator) { - } + @Override + public void onAnimationCancel(Animator animator) { + } - @Override - public void onAnimationRepeat(Animator animator) { - } + @Override + public void onAnimationRepeat(Animator animator) { + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarDay.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarDay.java index 4a0b073d..1f1a0e13 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarDay.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarDay.java @@ -2,8 +2,9 @@ import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.threeten.bp.LocalDate; /** @@ -11,176 +12,184 @@ */ public final class CalendarDay implements Parcelable { - /** - * Everything is based on this variable for {@link CalendarDay}. - */ - @NonNull private final LocalDate date; - - /** - * @param year new instance's year - * @param month new instance's month as defined by {@linkplain java.util.Calendar} - * @param day new instance's day of month - */ - private CalendarDay(final int year, final int month, final int day) { - date = LocalDate.of(year, month, day); - } - - /** - * @param date {@link LocalDate} instance - */ - private CalendarDay(@NonNull final LocalDate date) { - this.date = date; - } - - /** - * Get a new instance set to today - * - * @return CalendarDay set to today's date - */ - @NonNull public static CalendarDay today() { - return from(LocalDate.now()); - } - - /** - * Get a new instance set to the specified day - * - * @param year new instance's year - * @param month new instance's month as defined by {@linkplain java.util.Calendar} - * @param day new instance's day of month - * @return CalendarDay set to the specified date - */ - @NonNull public static CalendarDay from(int year, int month, int day) { - return new CalendarDay(year, month, day); - } - - /** - * Get a new instance set to the specified day - * - * @param date {@linkplain LocalDate} to pull date information from. Passing null will return null - * @return CalendarDay set to the specified date - */ - public static CalendarDay from(@Nullable LocalDate date) { - if (date == null) { - return null; - } - return new CalendarDay(date); - } - - /** - * Get the year - * - * @return the year for this day - */ - public int getYear() { - return date.getYear(); - } - - /** - * Get the month, represented by values from {@linkplain LocalDate} - * - * @return the month of the year as defined by {@linkplain LocalDate} - */ - public int getMonth() { - return date.getMonthValue(); - } - - /** - * Get the day - * - * @return the day of the month for this day - */ - public int getDay() { - return date.getDayOfMonth(); - } - - /** - * Get this day as a {@linkplain LocalDate} - * - * @return a date with this days information - */ - @NonNull public LocalDate getDate() { - return date; - } - - /** - * Determine if this day is within a specified range - * - * @param minDate the earliest day, may be null - * @param maxDate the latest day, may be null - * @return true if the between (inclusive) the min and max dates. - */ - public boolean isInRange(@Nullable CalendarDay minDate, @Nullable CalendarDay maxDate) { - return !(minDate != null && minDate.isAfter(this)) && - !(maxDate != null && maxDate.isBefore(this)); - } - - /** - * Determine if this day is before the given instance - * - * @param other the other day to test - * @return true if this is before other, false if equal or after - */ - public boolean isBefore(@NonNull final CalendarDay other) { - return date.isBefore(other.getDate()); - } - - /** - * Determine if this day is after the given instance - * - * @param other the other day to test - * @return true if this is after other, false if equal or before - */ - public boolean isAfter(@NonNull final CalendarDay other) { - return date.isAfter(other.getDate()); - } - - @Override public boolean equals(Object o) { - return o instanceof CalendarDay && date.equals(((CalendarDay) o).getDate()); - } - - @Override - public int hashCode() { - return hashCode(date.getYear(), date.getMonthValue(), date.getDayOfMonth()); - } - - private static int hashCode(int year, int month, int day) { - //Should produce hashes like "20150401" - return (year * 10000) + (month * 100) + day; - } - - @Override - public String toString() { - return "CalendarDay{" + date.getYear() + "-" + date.getMonthValue() + "-" - + date.getDayOfMonth() + "}"; - } - - /* - * Parcelable Stuff - */ - - public CalendarDay(Parcel in) { - this(in.readInt(), in.readInt(), in.readInt()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(date.getYear()); - dest.writeInt(date.getMonthValue()); - dest.writeInt(date.getDayOfMonth()); - } - - public static final Creator CREATOR = new Creator() { - public CalendarDay createFromParcel(Parcel in) { - return new CalendarDay(in); - } - - public CalendarDay[] newArray(int size) { - return new CalendarDay[size]; - } - }; + public static final Creator CREATOR = new Creator() { + public CalendarDay createFromParcel(Parcel in) { + return new CalendarDay(in); + } + + public CalendarDay[] newArray(int size) { + return new CalendarDay[size]; + } + }; + /** + * Everything is based on this variable for {@link CalendarDay}. + */ + @NonNull + private final LocalDate date; + + /** + * @param year new instance's year + * @param month new instance's month as defined by {@linkplain java.util.Calendar} + * @param day new instance's day of month + */ + private CalendarDay(final int year, final int month, final int day) { + date = LocalDate.of(year, month, day); + } + + /** + * @param date {@link LocalDate} instance + */ + private CalendarDay(@NonNull final LocalDate date) { + this.date = date; + } + + public CalendarDay(Parcel in) { + this(in.readInt(), in.readInt(), in.readInt()); + } + + /** + * Get a new instance set to today + * + * @return CalendarDay set to today's date + */ + @NonNull + public static CalendarDay today() { + return from(LocalDate.now()); + } + + /** + * Get a new instance set to the specified day + * + * @param year new instance's year + * @param month new instance's month as defined by {@linkplain java.util.Calendar} + * @param day new instance's day of month + * @return CalendarDay set to the specified date + */ + @NonNull + public static CalendarDay from(int year, int month, int day) { + return new CalendarDay(year, month, day); + } + + /** + * Get a new instance set to the specified day + * + * @param date {@linkplain LocalDate} to pull date information from. Passing null will return null + * @return CalendarDay set to the specified date + */ + public static CalendarDay from(@Nullable LocalDate date) { + if (date == null) { + return null; + } + return new CalendarDay(date); + } + + private static int hashCode(int year, int month, int day) { + //Should produce hashes like "20150401" + return (year * 10000) + (month * 100) + day; + } + + /** + * Get the year + * + * @return the year for this day + */ + public int getYear() { + return date.getYear(); + } + + /** + * Get the month, represented by values from {@linkplain LocalDate} + * + * @return the month of the year as defined by {@linkplain LocalDate} + */ + public int getMonth() { + return date.getMonthValue(); + } + + /** + * Get the day + * + * @return the day of the month for this day + */ + public int getDay() { + return date.getDayOfMonth(); + } + + /** + * Get this day as a {@linkplain LocalDate} + * + * @return a date with this days information + */ + @NonNull + public LocalDate getDate() { + return date; + } + + public String getFormattedSelectedDate() { + return date.getDayOfMonth() + "-" + date.getMonthValue() + "-" + date.getYear(); + } + + /** + * Determine if this day is within a specified range + * + * @param minDate the earliest day, may be null + * @param maxDate the latest day, may be null + * @return true if the between (inclusive) the min and max dates. + */ + public boolean isInRange(@Nullable CalendarDay minDate, @Nullable CalendarDay maxDate) { + return !(minDate != null && minDate.isAfter(this)) && + !(maxDate != null && maxDate.isBefore(this)); + } + + /** + * Determine if this day is before the given instance + * + * @param other the other day to test + * @return true if this is before other, false if equal or after + */ + public boolean isBefore(@NonNull final CalendarDay other) { + return date.isBefore(other.getDate()); + } + + /** + * Determine if this day is after the given instance + * + * @param other the other day to test + * @return true if this is after other, false if equal or before + */ + public boolean isAfter(@NonNull final CalendarDay other) { + return date.isAfter(other.getDate()); + } + + @Override + public boolean equals(Object o) { + return o instanceof CalendarDay && date.equals(((CalendarDay) o).getDate()); + } + + /* + * Parcelable Stuff + */ + + @Override + public int hashCode() { + return hashCode(date.getYear(), date.getMonthValue(), date.getDayOfMonth()); + } + + @Override + public String toString() { + return "CalendarDay{" + date.getYear() + "-" + date.getMonthValue() + "-" + + date.getDayOfMonth() + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(date.getYear()); + dest.writeInt(date.getMonthValue()); + dest.writeInt(date.getDayOfMonth()); + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarMode.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarMode.java index 3c704ad8..fa53c8ca 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarMode.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarMode.java @@ -5,21 +5,21 @@ */ public enum CalendarMode { - /** - * Month Mode to display an entire month per page. - */ - MONTHS(6), - /** - * Week mode that shows the calendar week by week. - */ - WEEKS(1); + /** + * Month Mode to display an entire month per page. + */ + MONTHS(6), + /** + * Week mode that shows the calendar week by week. + */ + WEEKS(1); - /** - * Number of visible weeks per calendar mode. - */ - final int visibleWeeksCount; + /** + * Number of visible weeks per calendar mode. + */ + final int visibleWeeksCount; - CalendarMode(int visibleWeeksCount) { - this.visibleWeeksCount = visibleWeeksCount; - } + CalendarMode(int visibleWeeksCount) { + this.visibleWeeksCount = visibleWeeksCount; + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPager.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPager.java index 33562555..60109815 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPager.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPager.java @@ -1,68 +1,68 @@ package com.prolificinteractive.materialcalendarview; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.view.ViewPager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; /** * Custom ViewPager that allows swiping to be disabled. */ -class CalendarPager extends ViewPager { +class CalendarPager extends RtlViewPager { - private boolean pagingEnabled = true; + private boolean pagingEnabled = true; - public CalendarPager(@NonNull final Context context) { - super(context); - } + public CalendarPager(@NonNull final Context context) { + super(context); + } - public CalendarPager(@NonNull final Context context, @Nullable final AttributeSet attrs) { - super(context, attrs); - } + public CalendarPager(@NonNull final Context context, @Nullable final AttributeSet attrs) { + super(context, attrs); + } - /** - * enable disable viewpager scroll - * - * @param pagingEnabled false to disable paging, true for paging (default) - */ - public void setPagingEnabled(boolean pagingEnabled) { - this.pagingEnabled = pagingEnabled; - } - - /** - * @return is this viewpager allowed to page - */ - public boolean isPagingEnabled() { - return pagingEnabled; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - return pagingEnabled && super.onInterceptTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - return pagingEnabled && super.onTouchEvent(ev); - } - - @Override - public boolean canScrollVertically(int direction) { /** - * disables scrolling vertically when paging disabled, fixes scrolling - * for nested {@link android.support.v4.view.ViewPager} + * @return is this viewpager allowed to page */ - return pagingEnabled && super.canScrollVertically(direction); - } + public boolean isPagingEnabled() { + return pagingEnabled; + } - @Override - public boolean canScrollHorizontally(int direction) { /** - * disables scrolling horizontally when paging disabled, fixes scrolling - * for nested {@link android.support.v4.view.ViewPager} + * enable disable viewpager scroll + * + * @param pagingEnabled false to disable paging, true for paging (default) */ - return pagingEnabled && super.canScrollHorizontally(direction); - } + public void setPagingEnabled(boolean pagingEnabled) { + this.pagingEnabled = pagingEnabled; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return pagingEnabled && super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + return pagingEnabled && super.onTouchEvent(ev); + } + + @Override + public boolean canScrollVertically(int direction) { + /** + * disables scrolling vertically when paging disabled, fixes scrolling + * for nested {@link ViewPager} + */ + return pagingEnabled && super.canScrollVertically(direction); + } + + @Override + public boolean canScrollHorizontally(int direction) { + /** + * disables scrolling horizontally when paging disabled, fixes scrolling + * for nested {@link ViewPager} + */ + return pagingEnabled && super.canScrollHorizontally(direction); + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPagerAdapter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPagerAdapter.java index d4c68eae..17a68954 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPagerAdapter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPagerAdapter.java @@ -1,18 +1,22 @@ package com.prolificinteractive.materialcalendarview; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.view.PagerAdapter; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.PagerAdapter; import android.view.View; import android.view.ViewGroup; + +import com.prolificinteractive.materialcalendarview.format.DateFormatDayFormatter; import com.prolificinteractive.materialcalendarview.MaterialCalendarView.ShowOtherDates; import com.prolificinteractive.materialcalendarview.format.DayFormatter; import com.prolificinteractive.materialcalendarview.format.TitleFormatter; import com.prolificinteractive.materialcalendarview.format.WeekDayFormatter; + import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.List; + import org.threeten.bp.LocalDate; /** @@ -20,359 +24,358 @@ */ abstract class CalendarPagerAdapter extends PagerAdapter { - private final ArrayDeque currentViews; - - protected final MaterialCalendarView mcv; - private final CalendarDay today; - - @NonNull private TitleFormatter titleFormatter = TitleFormatter.DEFAULT; - private Integer color = null; - private Integer dateTextAppearance = null; - private Integer weekDayTextAppearance = null; - @ShowOtherDates - private int showOtherDates = MaterialCalendarView.SHOW_DEFAULTS; - private CalendarDay minDate = null; - private CalendarDay maxDate = null; - private DateRangeIndex rangeIndex; - private List selectedDates = new ArrayList<>(); - private WeekDayFormatter weekDayFormatter = WeekDayFormatter.DEFAULT; - private DayFormatter dayFormatter = DayFormatter.DEFAULT; - private DayFormatter dayFormatterContentDescription = dayFormatter; - private List decorators = new ArrayList<>(); - private List decoratorResults = null; - private boolean selectionEnabled = true; - boolean showWeekDays; - - CalendarPagerAdapter(MaterialCalendarView mcv) { - this.mcv = mcv; - this.today = CalendarDay.today(); - currentViews = new ArrayDeque<>(); - currentViews.iterator(); - setRangeDates(null, null); - } - - public void setDecorators(List decorators) { - this.decorators = decorators; - invalidateDecorators(); - } - - public void invalidateDecorators() { - decoratorResults = new ArrayList<>(); - for (DayViewDecorator decorator : decorators) { - DayViewFacade facade = new DayViewFacade(); - decorator.decorate(facade); - if (facade.isDecorated()) { - decoratorResults.add(new DecoratorResult(decorator, facade)); - } - } - for (V pagerView : currentViews) { - pagerView.setDayViewDecorators(decoratorResults); - } - } - - @Override - public int getCount() { - return rangeIndex.getCount(); - } - - @Override - public CharSequence getPageTitle(int position) { - return titleFormatter.format(getItem(position)); - } - - public CalendarPagerAdapter migrateStateAndReturn(CalendarPagerAdapter newAdapter) { - newAdapter.titleFormatter = titleFormatter; - newAdapter.color = color; - newAdapter.dateTextAppearance = dateTextAppearance; - newAdapter.weekDayTextAppearance = weekDayTextAppearance; - newAdapter.showOtherDates = showOtherDates; - newAdapter.minDate = minDate; - newAdapter.maxDate = maxDate; - newAdapter.selectedDates = selectedDates; - newAdapter.weekDayFormatter = weekDayFormatter; - newAdapter.dayFormatter = dayFormatter; - newAdapter.dayFormatterContentDescription = dayFormatterContentDescription; - newAdapter.decorators = decorators; - newAdapter.decoratorResults = decoratorResults; - newAdapter.selectionEnabled = selectionEnabled; - return newAdapter; - } - - public int getIndexForDay(CalendarDay day) { - if (day == null) { - return getCount() / 2; - } - if (minDate != null && day.isBefore(minDate)) { - return 0; - } - if (maxDate != null && day.isAfter(maxDate)) { - return getCount() - 1; - } - return rangeIndex.indexOf(day); - } - - protected abstract V createView(int position); - - protected abstract int indexOf(V view); - - protected abstract boolean isInstanceOfView(Object object); - - protected abstract DateRangeIndex createRangeIndex(CalendarDay min, CalendarDay max); - - @Override - public int getItemPosition(@NonNull Object object) { - if (!(isInstanceOfView(object))) { - return POSITION_NONE; - } - CalendarPagerView pagerView = (CalendarPagerView) object; - CalendarDay firstViewDay = pagerView.getFirstViewDay(); - if (firstViewDay == null) { - return POSITION_NONE; - } - int index = indexOf((V) object); - if (index < 0) { - return POSITION_NONE; - } - return index; - } - - @NonNull - @Override - public Object instantiateItem(@NonNull ViewGroup container, int position) { - V pagerView = createView(position); - pagerView.setContentDescription(mcv.getCalendarContentDescription()); - pagerView.setAlpha(0); - pagerView.setSelectionEnabled(selectionEnabled); - - pagerView.setWeekDayFormatter(weekDayFormatter); - pagerView.setDayFormatter(dayFormatter); - pagerView.setDayFormatterContentDescription(dayFormatterContentDescription); - if (color != null) { - pagerView.setSelectionColor(color); - } - if (dateTextAppearance != null) { - pagerView.setDateTextAppearance(dateTextAppearance); - } - if (weekDayTextAppearance != null) { - pagerView.setWeekDayTextAppearance(weekDayTextAppearance); - } - pagerView.setShowOtherDates(showOtherDates); - pagerView.setMinimumDate(minDate); - pagerView.setMaximumDate(maxDate); - pagerView.setSelectedDates(selectedDates); - - container.addView(pagerView); - currentViews.add(pagerView); + protected final MaterialCalendarView mcv; + private final ArrayDeque currentViews; + private final CalendarDay today; + boolean showWeekDays; + @NonNull + private TitleFormatter titleFormatter = TitleFormatter.DEFAULT; + private Integer color = null; + private Integer dateTextAppearance = null; + private Integer weekDayTextAppearance = null; + @ShowOtherDates + private int showOtherDates = MaterialCalendarView.SHOW_DEFAULTS; + private CalendarDay minDate = null; + private CalendarDay maxDate = null; + private DateRangeIndex rangeIndex; + private List selectedDates = new ArrayList<>(); + private WeekDayFormatter weekDayFormatter = WeekDayFormatter.DEFAULT; + private DayFormatter dayFormatter = DateFormatDayFormatter.getInstance(); + private DayFormatter dayFormatterContentDescription = dayFormatter; + private List decorators = new ArrayList<>(); + private List decoratorResults = null; + private boolean selectionEnabled = true; + + CalendarPagerAdapter(MaterialCalendarView mcv) { + this.mcv = mcv; + this.today = CalendarDay.today(); + currentViews = new ArrayDeque<>(); + currentViews.iterator(); + setRangeDates(null, null); + } - pagerView.setDayViewDecorators(decoratorResults); - - return pagerView; - } - - public void setShowWeekDays(boolean showWeekDays) { - this.showWeekDays = showWeekDays; - } + public void setDecorators(List decorators) { + this.decorators = decorators; + invalidateDecorators(); + } + + public void invalidateDecorators() { + decoratorResults = new ArrayList<>(); + for (DayViewDecorator decorator : decorators) { + DayViewFacade facade = new DayViewFacade(); + decorator.decorate(facade); + if (facade.isDecorated()) { + decoratorResults.add(new DecoratorResult(decorator, facade)); + } + } + for (V pagerView : currentViews) { + pagerView.setDayViewDecorators(decoratorResults); + } + } - public boolean isShowWeekDays() { - return showWeekDays; - } + @Override + public int getCount() { + return rangeIndex.getCount(); + } - public void setSelectionEnabled(boolean enabled) { - selectionEnabled = enabled; - for (V pagerView : currentViews) { - pagerView.setSelectionEnabled(selectionEnabled); + @Override + public CharSequence getPageTitle(int position) { + return titleFormatter.format(getItem(position)); } - } - @Override - public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { - V pagerView = (V) object; - currentViews.remove(pagerView); - container.removeView(pagerView); - } + public CalendarPagerAdapter migrateStateAndReturn(CalendarPagerAdapter newAdapter) { + newAdapter.titleFormatter = titleFormatter; + newAdapter.color = color; + newAdapter.dateTextAppearance = dateTextAppearance; + newAdapter.weekDayTextAppearance = weekDayTextAppearance; + newAdapter.showOtherDates = showOtherDates; + newAdapter.minDate = minDate; + newAdapter.maxDate = maxDate; + newAdapter.selectedDates = selectedDates; + newAdapter.weekDayFormatter = weekDayFormatter; + newAdapter.dayFormatter = dayFormatter; + newAdapter.dayFormatterContentDescription = dayFormatterContentDescription; + newAdapter.decorators = decorators; + newAdapter.decoratorResults = decoratorResults; + newAdapter.selectionEnabled = selectionEnabled; + return newAdapter; + } - @Override - public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { - return view == object; - } + public int getIndexForDay(CalendarDay day) { + if (day == null) { + return getCount() / 2; + } + if (minDate != null && day.isBefore(minDate)) { + return 0; + } + if (maxDate != null && day.isAfter(maxDate)) { + return getCount() - 1; + } + return rangeIndex.indexOf(day); + } - public void setTitleFormatter(@Nullable TitleFormatter titleFormatter) { - this.titleFormatter = titleFormatter == null ? TitleFormatter.DEFAULT : titleFormatter; - } + protected abstract V createView(int position); + + protected abstract int indexOf(V view); + + protected abstract boolean isInstanceOfView(Object object); + + protected abstract DateRangeIndex createRangeIndex(CalendarDay min, CalendarDay max); + + @Override + public int getItemPosition(@NonNull Object object) { + if (!(isInstanceOfView(object))) { + return POSITION_NONE; + } + CalendarPagerView pagerView = (CalendarPagerView) object; + CalendarDay firstViewDay = pagerView.getFirstViewDay(); + if (firstViewDay == null) { + return POSITION_NONE; + } + int index = indexOf((V) object); + if (index < 0) { + return POSITION_NONE; + } + return index; + } - public void setSelectionColor(int color) { - this.color = color; - for (V pagerView : currentViews) { - pagerView.setSelectionColor(color); + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, int position) { + V pagerView = createView(position); + pagerView.setContentDescription(mcv.getCalendarContentDescription()); + pagerView.setAlpha(0); + pagerView.setSelectionEnabled(selectionEnabled); + + pagerView.setWeekDayFormatter(weekDayFormatter); + pagerView.setDayFormatter(dayFormatter); + pagerView.setDayFormatterContentDescription(dayFormatterContentDescription); + if (color != null) { + pagerView.setSelectionColor(color); + } + if (dateTextAppearance != null) { + pagerView.setDateTextAppearance(dateTextAppearance); + } + if (weekDayTextAppearance != null) { + pagerView.setWeekDayTextAppearance(weekDayTextAppearance); + } + pagerView.setShowOtherDates(showOtherDates); + pagerView.setMinimumDate(minDate); + pagerView.setMaximumDate(maxDate); + pagerView.setSelectedDates(selectedDates); + + container.addView(pagerView); + currentViews.add(pagerView); + + pagerView.setDayViewDecorators(decoratorResults); + + return pagerView; } - } - public void setDateTextAppearance(int taId) { - if (taId == 0) { - return; + public boolean isShowWeekDays() { + return showWeekDays; } - this.dateTextAppearance = taId; - for (V pagerView : currentViews) { - pagerView.setDateTextAppearance(taId); + + public void setShowWeekDays(boolean showWeekDays) { + this.showWeekDays = showWeekDays; } - } - public void setShowOtherDates(@ShowOtherDates int showFlags) { - this.showOtherDates = showFlags; - for (V pagerView : currentViews) { - pagerView.setShowOtherDates(showFlags); + public void setSelectionEnabled(boolean enabled) { + selectionEnabled = enabled; + for (V pagerView : currentViews) { + pagerView.setSelectionEnabled(selectionEnabled); + } } - } - public void setWeekDayFormatter(WeekDayFormatter formatter) { - this.weekDayFormatter = formatter; - for (V pagerView : currentViews) { - pagerView.setWeekDayFormatter(formatter); + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + V pagerView = (V) object; + currentViews.remove(pagerView); + container.removeView(pagerView); } - } - public void setDayFormatter(DayFormatter formatter) { - dayFormatterContentDescription = dayFormatterContentDescription == dayFormatter ? - formatter : dayFormatterContentDescription; - this.dayFormatter = formatter; - for (V pagerView : currentViews) { - pagerView.setDayFormatter(formatter); + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return view == object; } - } - public void setDayFormatterContentDescription(DayFormatter formatter) { - dayFormatterContentDescription = formatter; - for (V pagerView : currentViews) { - pagerView.setDayFormatterContentDescription(formatter); + public void setTitleFormatter(@Nullable TitleFormatter titleFormatter) { + this.titleFormatter = titleFormatter == null ? TitleFormatter.DEFAULT : titleFormatter; } - } - @ShowOtherDates - public int getShowOtherDates() { - return showOtherDates; - } + public void setSelectionColor(int color) { + this.color = color; + for (V pagerView : currentViews) { + pagerView.setSelectionColor(color); + } + } - public void setWeekDayTextAppearance(int taId) { - if (taId == 0) { - return; + public void setWeekDayFormatter(WeekDayFormatter formatter) { + this.weekDayFormatter = formatter; + for (V pagerView : currentViews) { + pagerView.setWeekDayFormatter(formatter); + } } - this.weekDayTextAppearance = taId; - for (V pagerView : currentViews) { - pagerView.setWeekDayTextAppearance(taId); + + public void setDayFormatter(DayFormatter formatter) { + dayFormatterContentDescription = dayFormatterContentDescription == dayFormatter ? + formatter : dayFormatterContentDescription; + this.dayFormatter = formatter; + for (V pagerView : currentViews) { + pagerView.setDayFormatter(formatter); + } } - } - public void setRangeDates(CalendarDay min, CalendarDay max) { - this.minDate = min; - this.maxDate = max; - for (V pagerView : currentViews) { - pagerView.setMinimumDate(min); - pagerView.setMaximumDate(max); + public void setDayFormatterContentDescription(DayFormatter formatter) { + dayFormatterContentDescription = formatter; + for (V pagerView : currentViews) { + pagerView.setDayFormatterContentDescription(formatter); + } } - if (min == null) { - min = CalendarDay.from(today.getYear() - 200, today.getMonth(), today.getDay()); + @ShowOtherDates + public int getShowOtherDates() { + return showOtherDates; } - if (max == null) { - max = CalendarDay.from(today.getYear() + 200, today.getMonth(), today.getDay()); + public void setShowOtherDates(@ShowOtherDates int showFlags) { + this.showOtherDates = showFlags; + for (V pagerView : currentViews) { + pagerView.setShowOtherDates(showFlags); + } } - rangeIndex = createRangeIndex(min, max); + public void setRangeDates(CalendarDay min, CalendarDay max) { + this.minDate = min; + this.maxDate = max; + for (V pagerView : currentViews) { + pagerView.setMinimumDate(min); + pagerView.setMaximumDate(max); + } - notifyDataSetChanged(); - invalidateSelectedDates(); - } + if (min == null) { + min = CalendarDay.from(today.getYear() - 200, today.getMonth(), today.getDay()); + } - public DateRangeIndex getRangeIndex() { - return rangeIndex; - } + if (max == null) { + max = CalendarDay.from(today.getYear() + 200, today.getMonth(), today.getDay()); + } - public void clearSelections() { - selectedDates.clear(); - invalidateSelectedDates(); - } + rangeIndex = createRangeIndex(min, max); - /** - * Select or un-select a day. - * - * @param day Day to select or un-select - * @param selected Whether to select or un-select the day from the list. - * @see CalendarPagerAdapter#selectRange(CalendarDay, CalendarDay) - */ - public void setDateSelected(CalendarDay day, boolean selected) { - if (selected) { - if (!selectedDates.contains(day)) { - selectedDates.add(day); + notifyDataSetChanged(); invalidateSelectedDates(); - } - } else { - if (selectedDates.contains(day)) { - selectedDates.remove(day); + } + + public DateRangeIndex getRangeIndex() { + return rangeIndex; + } + + public void clearSelections() { + selectedDates.clear(); invalidateSelectedDates(); - } } - } - /** - * Clear the previous selection, select the range of days from first to last, and finally - * invalidate. First day should be before last day, otherwise the selection won't happen. - * - * @param first The first day of the range. - * @param last The last day in the range. - * @see CalendarPagerAdapter#setDateSelected(CalendarDay, boolean) - */ - public void selectRange(final CalendarDay first, final CalendarDay last) { - selectedDates.clear(); + /** + * Select or un-select a day. + * + * @param day Day to select or un-select + * @param selected Whether to select or un-select the day from the list. + * @see CalendarPagerAdapter#selectRange(CalendarDay, CalendarDay) + */ + public void setDateSelected(CalendarDay day, boolean selected) { + if (selected) { + if (!selectedDates.contains(day)) { + selectedDates.add(day); + invalidateSelectedDates(); + } + } else { + if (selectedDates.contains(day)) { + selectedDates.remove(day); + invalidateSelectedDates(); + } + } + } + + /** + * Clear the previous selection, select the range of days from first to last, and finally + * invalidate. First day should be before last day, otherwise the selection won't happen. + * + * @param first The first day of the range. + * @param last The last day in the range. + * @see CalendarPagerAdapter#setDateSelected(CalendarDay, boolean) + */ + public void selectRange(final CalendarDay first, final CalendarDay last) { + selectedDates.clear(); + + // Copy to start from the first day and increment + LocalDate temp = LocalDate.of(first.getYear(), first.getMonth(), first.getDay()); - // Copy to start from the first day and increment - LocalDate temp = LocalDate.of(first.getYear(), first.getMonth(), first.getDay()); + // for comparison + final LocalDate end = last.getDate(); - // for comparison - final LocalDate end = last.getDate(); + while (temp.isBefore(end) || temp.equals(end)) { + selectedDates.add(CalendarDay.from(temp)); + temp = temp.plusDays(1); + } - while( temp.isBefore(end) || temp.equals(end) ) { - selectedDates.add(CalendarDay.from(temp)); - temp = temp.plusDays(1); + invalidateSelectedDates(); } - invalidateSelectedDates(); - } + private void invalidateSelectedDates() { + validateSelectedDates(); + for (V pagerView : currentViews) { + pagerView.setSelectedDates(selectedDates); + } + } - private void invalidateSelectedDates() { - validateSelectedDates(); - for (V pagerView : currentViews) { - pagerView.setSelectedDates(selectedDates); + private void validateSelectedDates() { + for (int i = 0; i < selectedDates.size(); i++) { + CalendarDay date = selectedDates.get(i); + + if ((minDate != null && minDate.isAfter(date)) || (maxDate != null + && maxDate.isBefore(date))) { + selectedDates.remove(i); + mcv.onDateUnselected(date); + i -= 1; + } + } } - } - private void validateSelectedDates() { - for (int i = 0; i < selectedDates.size(); i++) { - CalendarDay date = selectedDates.get(i); + public CalendarDay getItem(int position) { + return rangeIndex.getItem(position); + } - if ((minDate != null && minDate.isAfter(date)) || (maxDate != null - && maxDate.isBefore(date))) { - selectedDates.remove(i); - mcv.onDateUnselected(date); - i -= 1; - } + @NonNull + public List getSelectedDates() { + return Collections.unmodifiableList(selectedDates); } - } - public CalendarDay getItem(int position) { - return rangeIndex.getItem(position); - } + protected int getDateTextAppearance() { + return dateTextAppearance == null ? 0 : dateTextAppearance; + } - @NonNull - public List getSelectedDates() { - return Collections.unmodifiableList(selectedDates); - } + public void setDateTextAppearance(int taId) { + if (taId == 0) { + return; + } + this.dateTextAppearance = taId; + for (V pagerView : currentViews) { + pagerView.setDateTextAppearance(taId); + } + } - protected int getDateTextAppearance() { - return dateTextAppearance == null ? 0 : dateTextAppearance; - } + protected int getWeekDayTextAppearance() { + return weekDayTextAppearance == null ? 0 : weekDayTextAppearance; + } - protected int getWeekDayTextAppearance() { - return weekDayTextAppearance == null ? 0 : weekDayTextAppearance; - } + public void setWeekDayTextAppearance(int taId) { + if (taId == 0) { + return; + } + this.weekDayTextAppearance = taId; + for (V pagerView : currentViews) { + pagerView.setWeekDayTextAppearance(taId); + } + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPagerView.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPagerView.java index f3a4fa9a..909137f1 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPagerView.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/CalendarPagerView.java @@ -1,18 +1,21 @@ package com.prolificinteractive.materialcalendarview; import android.os.Build; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; + import com.prolificinteractive.materialcalendarview.MaterialCalendarView.ShowOtherDates; import com.prolificinteractive.materialcalendarview.format.DayFormatter; import com.prolificinteractive.materialcalendarview.format.WeekDayFormatter; + import java.util.ArrayList; import java.util.Collection; import java.util.List; + import org.threeten.bp.DayOfWeek; import org.threeten.bp.LocalDate; import org.threeten.bp.temporal.TemporalField; @@ -22,348 +25,348 @@ import static com.prolificinteractive.materialcalendarview.MaterialCalendarView.showOtherMonths; abstract class CalendarPagerView extends ViewGroup - implements View.OnClickListener, View.OnLongClickListener { - - protected static final int DEFAULT_DAYS_IN_WEEK = 7; - protected static final int DEFAULT_MAX_WEEKS = 6; - protected static final int DAY_NAMES_ROW = 1; - - private final ArrayList weekDayViews = new ArrayList<>(); - private final ArrayList decoratorResults = new ArrayList<>(); - private final DayOfWeek firstDayOfWeek; - @ShowOtherDates protected int showOtherDates = SHOW_DEFAULTS; - private MaterialCalendarView mcv; - private CalendarDay firstViewDay; - private CalendarDay minDate = null; - private CalendarDay maxDate = null; - protected boolean showWeekDays; - - private final Collection dayViews = new ArrayList<>(); - - public CalendarPagerView( - @NonNull MaterialCalendarView view, - CalendarDay firstViewDay, - DayOfWeek firstDayOfWeek, - boolean showWeekDays) { - super(view.getContext()); - - this.mcv = view; - this.firstViewDay = firstViewDay; - this.firstDayOfWeek = firstDayOfWeek; - this.showWeekDays = showWeekDays; - - setClipChildren(false); - setClipToPadding(false); - - if (showWeekDays) { - buildWeekDays(resetAndGetWorkingCalendar()); - } - buildDayViews(dayViews, resetAndGetWorkingCalendar()); - } + implements View.OnClickListener, View.OnLongClickListener { + + protected static final int DEFAULT_DAYS_IN_WEEK = 7; + protected static final int DEFAULT_MAX_WEEKS = 6; + protected static final int DAY_NAMES_ROW = 1; + + private final ArrayList weekDayViews = new ArrayList<>(); + private final ArrayList decoratorResults = new ArrayList<>(); + private final DayOfWeek firstDayOfWeek; + private final Collection dayViews = new ArrayList<>(); + @ShowOtherDates + protected int showOtherDates = SHOW_DEFAULTS; + protected boolean showWeekDays; + private MaterialCalendarView mcv; + private CalendarDay firstViewDay; + private CalendarDay minDate = null; + private CalendarDay maxDate = null; + + public CalendarPagerView( + @NonNull MaterialCalendarView view, + CalendarDay firstViewDay, + DayOfWeek firstDayOfWeek, + boolean showWeekDays) { + super(view.getContext()); + + this.mcv = view; + this.firstViewDay = firstViewDay; + this.firstDayOfWeek = firstDayOfWeek; + this.showWeekDays = showWeekDays; + + setClipChildren(false); + setClipToPadding(false); + + if (showWeekDays) { + buildWeekDays(resetAndGetWorkingCalendar()); + } + buildDayViews(dayViews, resetAndGetWorkingCalendar()); + } + + private void buildWeekDays(LocalDate calendar) { + LocalDate local = calendar; + for (int i = 0; i < DEFAULT_DAYS_IN_WEEK; i++) { + WeekDayView weekDayView = new WeekDayView(getContext(), local.getDayOfWeek()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + weekDayView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + } + weekDayViews.add(weekDayView); + addView(weekDayView); + local = local.plusDays(1); + } + } - private void buildWeekDays(LocalDate calendar) { - LocalDate local = calendar; - for (int i = 0; i < DEFAULT_DAYS_IN_WEEK; i++) { - WeekDayView weekDayView = new WeekDayView(getContext(), local.getDayOfWeek()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - weekDayView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - } - weekDayViews.add(weekDayView); - addView(weekDayView); - local = local.plusDays(1); - } - } - - protected void addDayView(Collection dayViews, LocalDate temp) { - CalendarDay day = CalendarDay.from(temp); - DayView dayView = new DayView(getContext(), day); - dayView.setOnClickListener(this); - dayView.setOnLongClickListener(this); - dayViews.add(dayView); - addView(dayView, new LayoutParams()); - } - - protected LocalDate resetAndGetWorkingCalendar() { - final TemporalField firstDayOfWeek = WeekFields.of(this.firstDayOfWeek, 1).dayOfWeek(); - final LocalDate temp = getFirstViewDay().getDate().with(firstDayOfWeek, 1); - int dow = temp.getDayOfWeek().getValue(); - int delta = getFirstDayOfWeek().getValue() - dow; - //If the delta is positive, we want to remove a week - boolean removeRow = showOtherMonths(showOtherDates) ? delta >= 0 : delta > 0; - if (removeRow) { - delta -= DEFAULT_DAYS_IN_WEEK; - } - return temp.plusDays(delta); - } - - protected DayOfWeek getFirstDayOfWeek() { - return firstDayOfWeek; - } - - protected abstract void buildDayViews(Collection dayViews, LocalDate calendar); - - protected abstract boolean isDayEnabled(CalendarDay day); - - void setDayViewDecorators(List results) { - this.decoratorResults.clear(); - if (results != null) { - this.decoratorResults.addAll(results); - } - invalidateDecorators(); - } - - public void setWeekDayTextAppearance(int taId) { - for (WeekDayView weekDayView : weekDayViews) { - weekDayView.setTextAppearance(getContext(), taId); - } - } - - public void setDateTextAppearance(int taId) { - for (DayView dayView : dayViews) { - dayView.setTextAppearance(getContext(), taId); - } - } - - public void setShowOtherDates(@ShowOtherDates int showFlags) { - this.showOtherDates = showFlags; - updateUi(); - } - - public void setSelectionEnabled(boolean selectionEnabled) { - for (DayView dayView : dayViews) { - dayView.setOnClickListener(selectionEnabled ? this : null); - dayView.setClickable(selectionEnabled); - } - } - - public void setSelectionColor(int color) { - for (DayView dayView : dayViews) { - dayView.setSelectionColor(color); - } - } - - public void setWeekDayFormatter(WeekDayFormatter formatter) { - for (WeekDayView dayView : weekDayViews) { - dayView.setWeekDayFormatter(formatter); - } - } - - public void setDayFormatter(DayFormatter formatter) { - for (DayView dayView : dayViews) { - dayView.setDayFormatter(formatter); + protected void addDayView(Collection dayViews, LocalDate temp) { + CalendarDay day = CalendarDay.from(temp); + DayView dayView = new DayView(getContext(), day); + dayView.setOnClickListener(this); + dayView.setOnLongClickListener(this); + dayViews.add(dayView); + addView(dayView, new LayoutParams()); } - } - - public void setDayFormatterContentDescription(DayFormatter formatter) { - for (DayView dayView : dayViews) { - dayView.setDayFormatterContentDescription(formatter); - } - } - - public void setMinimumDate(CalendarDay minDate) { - this.minDate = minDate; - updateUi(); - } - - public void setMaximumDate(CalendarDay maxDate) { - this.maxDate = maxDate; - updateUi(); - } - public void setSelectedDates(Collection dates) { - for (DayView dayView : dayViews) { - CalendarDay day = dayView.getDate(); - dayView.setChecked(dates != null && dates.contains(day)); + protected LocalDate resetAndGetWorkingCalendar() { + final TemporalField firstDayOfWeek = WeekFields.of(this.firstDayOfWeek, 1).dayOfWeek(); + final LocalDate temp = getFirstViewDay().getDate().with(firstDayOfWeek, 1); + int dow = temp.getDayOfWeek().getValue(); + int delta = getFirstDayOfWeek().getValue() - dow; + //If the delta is positive, we want to remove a week + boolean removeRow = showOtherMonths(showOtherDates) ? delta >= 0 : delta > 0; + if (removeRow) { + delta -= DEFAULT_DAYS_IN_WEEK; + } + return temp.plusDays(delta); } - postInvalidate(); - } - protected void updateUi() { - for (DayView dayView : dayViews) { - CalendarDay day = dayView.getDate(); - dayView.setupSelection(showOtherDates, day.isInRange(minDate, maxDate), isDayEnabled(day)); + protected DayOfWeek getFirstDayOfWeek() { + return firstDayOfWeek; } - postInvalidate(); - } - protected void invalidateDecorators() { - final DayViewFacade facadeAccumulator = new DayViewFacade(); - for (DayView dayView : dayViews) { - facadeAccumulator.reset(); - for (DecoratorResult result : decoratorResults) { - if (result.decorator.shouldDecorate(dayView.getDate())) { - result.result.applyTo(facadeAccumulator); + protected abstract void buildDayViews(Collection dayViews, LocalDate calendar); + + protected abstract boolean isDayEnabled(CalendarDay day); + + void setDayViewDecorators(List results) { + this.decoratorResults.clear(); + if (results != null) { + this.decoratorResults.addAll(results); } - } - dayView.applyFacade(facadeAccumulator); - } - } - - @Override - public void onClick(final View v) { - if (v instanceof DayView) { - final DayView dayView = (DayView) v; - mcv.onDateClicked(dayView); - } - } - - @Override - public boolean onLongClick(final View v) { - if (v instanceof DayView) { - final DayView dayView = (DayView) v; - mcv.onDateLongClicked(dayView); - return true; - } - return false; - } - - /* - * Custom ViewGroup Code - */ - - /** - * {@inheritDoc} - */ - @Override - protected LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(); - } - - /** - * {@inheritDoc} - */ - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - final int specWidthSize = MeasureSpec.getSize(widthMeasureSpec); - final int specWidthMode = MeasureSpec.getMode(widthMeasureSpec); - final int specHeightSize = MeasureSpec.getSize(heightMeasureSpec); - final int specHeightMode = MeasureSpec.getMode(heightMeasureSpec); - - //We expect to be somewhere inside a MaterialCalendarView, which should measure EXACTLY - if (specHeightMode == MeasureSpec.UNSPECIFIED || specWidthMode == MeasureSpec.UNSPECIFIED) { - throw new IllegalStateException("CalendarPagerView should never be left to decide it's size"); - } - - //The spec width should be a correct multiple - final int measureTileWidth = specWidthSize / DEFAULT_DAYS_IN_WEEK; - final int measureTileHeight = specHeightSize / getRows(); - - //Just use the spec sizes - setMeasuredDimension(specWidthSize, specHeightSize); - - int count = getChildCount(); - - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - - int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( - measureTileWidth, - MeasureSpec.EXACTLY - ); - - int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( - measureTileHeight, - MeasureSpec.EXACTLY - ); - - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - } - } - - /** - * Return the number of rows to display per page - */ - protected abstract int getRows(); - - /** - * {@inheritDoc} - */ - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - final int parentWidth = getWidth(); - final int count = getChildCount(); - final int parentLeft = 0; - final int parentRight = parentWidth; - - int childTop = 0; - int childLeft = parentLeft; - int childRight = parentRight; - - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - - final int width = child.getMeasuredWidth(); - final int height = child.getMeasuredHeight(); - - if (LocalUtils.isRTL()) { - child.layout(childRight - width, childTop, childRight, childTop + height); - childRight -= width; - } else { - child.layout(childLeft, childTop, childLeft + width, childTop + height); - childLeft += width; - } - - //We should warp every so many children - if (i % DEFAULT_DAYS_IN_WEEK == (DEFAULT_DAYS_IN_WEEK - 1)) { - childLeft = parentLeft; - childRight = parentRight; - childTop += height; - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public LayoutParams generateLayoutParams(AttributeSet attrs) { - return new LayoutParams(); - } - - @Override - public boolean shouldDelayChildPressedState() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams; - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return new LayoutParams(); - } - - @Override - public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); - event.setClassName(CalendarPagerView.class.getName()); - } - - @Override - public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); - info.setClassName(CalendarPagerView.class.getName()); - } - - protected CalendarDay getFirstViewDay() { - return firstViewDay; - } - - /** - * Simple layout params class for MonthView, since every child is the same size - */ - protected static class LayoutParams extends MarginLayoutParams { + invalidateDecorators(); + } + + public void setWeekDayTextAppearance(int taId) { + for (WeekDayView weekDayView : weekDayViews) { + weekDayView.setTextAppearance(getContext(), taId); + } + } + + public void setDateTextAppearance(int taId) { + for (DayView dayView : dayViews) { + dayView.setTextAppearance(getContext(), taId); + } + } + + public void setShowOtherDates(@ShowOtherDates int showFlags) { + this.showOtherDates = showFlags; + updateUi(); + } + + public void setSelectionEnabled(boolean selectionEnabled) { + for (DayView dayView : dayViews) { + dayView.setOnClickListener(selectionEnabled ? this : null); + dayView.setClickable(selectionEnabled); + } + } + + public void setSelectionColor(int color) { + for (DayView dayView : dayViews) { + dayView.setSelectionColor(color); + } + } + + public void setWeekDayFormatter(WeekDayFormatter formatter) { + for (WeekDayView dayView : weekDayViews) { + dayView.setWeekDayFormatter(formatter); + } + } + + public void setDayFormatter(DayFormatter formatter) { + for (DayView dayView : dayViews) { + dayView.setDayFormatter(formatter); + } + } + + public void setDayFormatterContentDescription(DayFormatter formatter) { + for (DayView dayView : dayViews) { + dayView.setDayFormatterContentDescription(formatter); + } + } + + public void setMinimumDate(CalendarDay minDate) { + this.minDate = minDate; + updateUi(); + } + + public void setMaximumDate(CalendarDay maxDate) { + this.maxDate = maxDate; + updateUi(); + } + + public void setSelectedDates(Collection dates) { + for (DayView dayView : dayViews) { + CalendarDay day = dayView.getDate(); + dayView.setChecked(dates != null && dates.contains(day)); + } + postInvalidate(); + } + + protected void updateUi() { + for (DayView dayView : dayViews) { + CalendarDay day = dayView.getDate(); + dayView.setupSelection(showOtherDates, day.isInRange(minDate, maxDate), isDayEnabled(day)); + } + postInvalidate(); + } + + protected void invalidateDecorators() { + final DayViewFacade facadeAccumulator = new DayViewFacade(); + for (DayView dayView : dayViews) { + facadeAccumulator.reset(); + for (DecoratorResult result : decoratorResults) { + if (result.decorator.shouldDecorate(dayView.getDate())) { + result.result.applyTo(facadeAccumulator); + } + } + dayView.applyFacade(facadeAccumulator); + } + } + + @Override + public void onClick(final View v) { + if (v instanceof DayView) { + final DayView dayView = (DayView) v; + mcv.onDateClicked(dayView); + } + } + + @Override + public boolean onLongClick(final View v) { + if (v instanceof DayView) { + final DayView dayView = (DayView) v; + mcv.onDateLongClicked(dayView); + return true; + } + return false; + } + + /* + * Custom ViewGroup Code + */ + + /** + * {@inheritDoc} + */ + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { + final int specWidthSize = MeasureSpec.getSize(widthMeasureSpec); + final int specWidthMode = MeasureSpec.getMode(widthMeasureSpec); + final int specHeightSize = MeasureSpec.getSize(heightMeasureSpec); + final int specHeightMode = MeasureSpec.getMode(heightMeasureSpec); + + //We expect to be somewhere inside a MaterialCalendarView, which should measure EXACTLY + if (specHeightMode == MeasureSpec.UNSPECIFIED || specWidthMode == MeasureSpec.UNSPECIFIED) { + throw new IllegalStateException("CalendarPagerView should never be left to decide it's size"); + } + + //The spec width should be a correct multiple + final int measureTileWidth = specWidthSize / DEFAULT_DAYS_IN_WEEK; + final int measureTileHeight = specHeightSize / getRows(); + + //Just use the spec sizes + setMeasuredDimension(specWidthSize, specHeightSize); + + int count = getChildCount(); + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + + int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( + measureTileWidth, + MeasureSpec.EXACTLY + ); + + int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + measureTileHeight, + MeasureSpec.EXACTLY + ); + + child.measure(childWidthMeasureSpec, childHeightMeasureSpec); + } + } + + /** + * Return the number of rows to display per page + */ + protected abstract int getRows(); + + /** + * {@inheritDoc} + */ + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int parentWidth = getWidth(); + final int count = getChildCount(); + final int parentLeft = 0; + final int parentRight = parentWidth; + + int childTop = 0; + int childLeft = parentLeft; + int childRight = parentRight; + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + + final int width = child.getMeasuredWidth(); + final int height = child.getMeasuredHeight(); + + if (LocalUtils.isRTL()) { + child.layout(childRight - width, childTop, childRight, childTop + height); + childRight -= width; + } else { + child.layout(childLeft, childTop, childLeft + width, childTop + height); + childLeft += width; + } + + //We should warp every so many children + if (i % DEFAULT_DAYS_IN_WEEK == (DEFAULT_DAYS_IN_WEEK - 1)) { + childLeft = parentLeft; + childRight = parentRight; + childTop += height; + } + } + } /** * {@inheritDoc} */ - public LayoutParams() { - super(WRAP_CONTENT, WRAP_CONTENT); + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(); + } + + @Override + public boolean shouldDelayChildPressedState() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams; + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(); + } + + @Override + public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setClassName(CalendarPagerView.class.getName()); + } + + @Override + public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(CalendarPagerView.class.getName()); + } + + protected CalendarDay getFirstViewDay() { + return firstViewDay; + } + + /** + * Simple layout params class for MonthView, since every child is the same size + */ + protected static class LayoutParams extends MarginLayoutParams { + + /** + * {@inheritDoc} + */ + public LayoutParams() { + super(WRAP_CONTENT, WRAP_CONTENT); + } } - } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/CurrentDayDecorator.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/CurrentDayDecorator.java new file mode 100644 index 00000000..64ec68d6 --- /dev/null +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/CurrentDayDecorator.java @@ -0,0 +1,41 @@ +package com.prolificinteractive.materialcalendarview; + +import android.app.Activity; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.text.style.ForegroundColorSpan; + +import androidx.core.content.ContextCompat; + +public class CurrentDayDecorator implements DayViewDecorator { + + private final Drawable selectionDrawable; + private Drawable drawable; + private boolean flag; + + private CalendarDay currentDay = CalendarDay.today(); + + public CurrentDayDecorator(Activity context, boolean flag) { + drawable = ContextCompat.getDrawable(context, R.drawable.gray_circle); + selectionDrawable = ContextCompat.getDrawable(context, R.drawable.calendar_selector); + this.flag = flag; + } + + @Override + public boolean shouldDecorate(CalendarDay day) { + return day.equals(currentDay); + } + + @Override + public void decorate(DayViewFacade view) { + if (flag) { + view.addSpan(new ForegroundColorSpan(Color.WHITE)); + view.setSelectionDrawable(selectionDrawable); + + } else { + view.addSpan(new ForegroundColorSpan(Color.BLACK)); + view.setSelectionDrawable(drawable); + + } + } +} diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/CustomMultipleDotSpan.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/CustomMultipleDotSpan.java new file mode 100644 index 00000000..bb91102d --- /dev/null +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/CustomMultipleDotSpan.java @@ -0,0 +1,61 @@ +package com.prolificinteractive.materialcalendarview; + +import android.app.Activity; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.style.LineBackgroundSpan; + +public class CustomMultipleDotSpan implements LineBackgroundSpan { + + private final float radius; + private int[] color = new int[0]; + private Activity context; + + + public CustomMultipleDotSpan() { + this.radius = 5; + this.color[0] = 5; + } + + + public CustomMultipleDotSpan(int color) { + this.radius = 5; + this.color[0] = 0; + } + + + public CustomMultipleDotSpan(float radius) { + this.radius = radius; + this.color[0] = 0; + } + + + public CustomMultipleDotSpan(Activity context, float radius, int[] color) { + this.radius = radius; + this.color = color; + this.context = context; + } + + @Override + public void drawBackground( + Canvas canvas, Paint paint, + int left, int right, int top, int baseline, int bottom, + CharSequence charSequence, + int start, int end, int lineNum + ) { + + int total = color.length > 5 ? 5 : color.length; + int leftMost = (total - 1) * -10; + + for (int i = 0; i < total; i++) { + int oldColor = paint.getColor(); + if (color[i] != 0) { + paint.setColor(color[i]); + } + int extraMarginDots = context.getResources().getDimensionPixelSize(R.dimen._5sdp) + 3; + canvas.drawCircle((left + right) / 2 - leftMost, bottom + extraMarginDots, radius - 2, paint); + paint.setColor(oldColor); + leftMost = leftMost + 20; + } + } +} diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/DateRangeIndex.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/DateRangeIndex.java index ff1c3811..ca2f888a 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/DateRangeIndex.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/DateRangeIndex.java @@ -6,18 +6,18 @@ */ interface DateRangeIndex { - /** - * Count of pages displayed between 2 dates. - */ - int getCount(); + /** + * Count of pages displayed between 2 dates. + */ + int getCount(); - /** - * Index of the page where the date is displayed. - */ - int indexOf(CalendarDay day); + /** + * Index of the page where the date is displayed. + */ + int indexOf(CalendarDay day); - /** - * Get the first date at the position within the index. - */ - CalendarDay getItem(int position); + /** + * Get the first date at the position within the index. + */ + CalendarDay getItem(int position); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/DayView.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/DayView.java index 675e5f94..ca12fae4 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/DayView.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/DayView.java @@ -6,6 +6,9 @@ import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.Color; + +import com.prolificinteractive.materialcalendarview.format.DateFormatDayFormatter; + import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; @@ -13,14 +16,16 @@ import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.shapes.OvalShape; import android.os.Build; -import android.support.annotation.NonNull; -import android.support.v7.widget.AppCompatCheckedTextView; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatCheckedTextView; import android.text.SpannableString; import android.text.Spanned; import android.view.Gravity; import android.view.View; + import com.prolificinteractive.materialcalendarview.MaterialCalendarView.ShowOtherDates; import com.prolificinteractive.materialcalendarview.format.DayFormatter; + import java.util.List; import static com.prolificinteractive.materialcalendarview.MaterialCalendarView.showDecoratedDisabled; @@ -30,276 +35,274 @@ /** * Display one day of a {@linkplain MaterialCalendarView} */ -@SuppressLint("ViewConstructor") class DayView extends AppCompatCheckedTextView { +@SuppressLint("ViewConstructor") +class DayView extends AppCompatCheckedTextView { + + private final int fadeTime; + private final Rect tempRect = new Rect(); + private final Rect circleDrawableRect = new Rect(); + private CalendarDay date; + private int selectionColor = Color.GRAY; + private Drawable customBackground = null; + private Drawable selectionDrawable; + private Drawable mCircleDrawable; + private DayFormatter formatter = DateFormatDayFormatter.getInstance(); + private DayFormatter contentDescriptionFormatter = formatter; + private boolean isInRange = true; + private boolean isInMonth = true; + private boolean isDecoratedDisabled = false; + @ShowOtherDates + private int showOtherDates = MaterialCalendarView.SHOW_DEFAULTS; + + public DayView(Context context, CalendarDay day) { + super(context); + + fadeTime = getResources().getInteger(android.R.integer.config_shortAnimTime); + + setSelectionColor(this.selectionColor); + + setGravity(Gravity.CENTER); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + setTextAlignment(TEXT_ALIGNMENT_CENTER); + } + + setDay(day); + } - private CalendarDay date; - private int selectionColor = Color.GRAY; + private static Drawable generateBackground(int color, int fadeTime, Rect bounds) { + StateListDrawable drawable = new StateListDrawable(); + drawable.setExitFadeDuration(fadeTime); + drawable.addState(new int[]{android.R.attr.state_checked}, generateCircleDrawable(color)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + drawable.addState( + new int[]{android.R.attr.state_pressed}, + generateRippleDrawable(color, bounds) + ); + } else { + drawable.addState(new int[]{android.R.attr.state_pressed}, generateCircleDrawable(color)); + } + + drawable.addState(new int[]{}, generateCircleDrawable(Color.TRANSPARENT)); + + return drawable; + } - private final int fadeTime; - private Drawable customBackground = null; - private Drawable selectionDrawable; - private Drawable mCircleDrawable; - private DayFormatter formatter = DayFormatter.DEFAULT; - private DayFormatter contentDescriptionFormatter = formatter; + private static Drawable generateCircleDrawable(final int color) { + ShapeDrawable drawable = new ShapeDrawable(new OvalShape()); + drawable.getPaint().setColor(color); + return drawable; + } - private boolean isInRange = true; - private boolean isInMonth = true; - private boolean isDecoratedDisabled = false; - @ShowOtherDates - private int showOtherDates = MaterialCalendarView.SHOW_DEFAULTS; + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private static Drawable generateRippleDrawable(final int color, Rect bounds) { + ColorStateList list = ColorStateList.valueOf(color); + Drawable mask = generateCircleDrawable(Color.WHITE); + RippleDrawable rippleDrawable = new RippleDrawable(list, null, mask); + // API 21 + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) { + rippleDrawable.setBounds(bounds); + } + + // API 22. Technically harmless to leave on for API 21 and 23, but not worth risking for 23+ + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1) { + int center = (bounds.left + bounds.right) / 2; + rippleDrawable.setHotspotBounds(center, bounds.top, center, bounds.bottom); + } + + return rippleDrawable; + } - public DayView(Context context, CalendarDay day) { - super(context); + public void setDay(CalendarDay date) { + this.date = date; + setText(getLabel()); + } - fadeTime = getResources().getInteger(android.R.integer.config_shortAnimTime); + /** + * Set the new label formatter and reformat the current label. This preserves current spans. + * + * @param formatter new label formatter + */ + public void setDayFormatter(DayFormatter formatter) { + this.contentDescriptionFormatter = contentDescriptionFormatter == this.formatter ? + formatter : contentDescriptionFormatter; + this.formatter = formatter == null ? DateFormatDayFormatter.getInstance() : formatter; + CharSequence currentLabel = getText(); + Object[] spans = null; + if (currentLabel instanceof Spanned) { + spans = ((Spanned) currentLabel).getSpans(0, currentLabel.length(), Object.class); + } + SpannableString newLabel = new SpannableString(getLabel()); + if (spans != null) { + for (Object span : spans) { + newLabel.setSpan(span, 0, newLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + setText(newLabel); + } - setSelectionColor(this.selectionColor); + /** + * Set the new content description formatter and reformat the current content description. + * + * @param formatter new content description formatter + */ + public void setDayFormatterContentDescription(DayFormatter formatter) { + this.contentDescriptionFormatter = formatter == null ? this.formatter : formatter; + setContentDescription(getContentDescriptionLabel()); + } - setGravity(Gravity.CENTER); + @NonNull + public String getLabel() { + return formatter.format(date); + } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - setTextAlignment(TEXT_ALIGNMENT_CENTER); + @NonNull + public String getContentDescriptionLabel() { + return contentDescriptionFormatter == null ? formatter.format(date) + : contentDescriptionFormatter.format(date); } - setDay(day); - } - - public void setDay(CalendarDay date) { - this.date = date; - setText(getLabel()); - } - - /** - * Set the new label formatter and reformat the current label. This preserves current spans. - * - * @param formatter new label formatter - */ - public void setDayFormatter(DayFormatter formatter) { - this.contentDescriptionFormatter = contentDescriptionFormatter == this.formatter ? - formatter : contentDescriptionFormatter; - this.formatter = formatter == null ? DayFormatter.DEFAULT : formatter; - CharSequence currentLabel = getText(); - Object[] spans = null; - if (currentLabel instanceof Spanned) { - spans = ((Spanned) currentLabel).getSpans(0, currentLabel.length(), Object.class); + public void setSelectionColor(int color) { + this.selectionColor = color; + regenerateBackground(); } - SpannableString newLabel = new SpannableString(getLabel()); - if (spans != null) { - for (Object span : spans) { - newLabel.setSpan(span, 0, newLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } + + /** + * @param drawable custom selection drawable + */ + public void setSelectionDrawable(Drawable drawable) { + if (drawable == null) { + this.selectionDrawable = null; + } else { + this.selectionDrawable = drawable.getConstantState().newDrawable(getResources()); + } + regenerateBackground(); } - setText(newLabel); - } - - /** - * Set the new content description formatter and reformat the current content description. - * - * @param formatter new content description formatter - */ - public void setDayFormatterContentDescription(DayFormatter formatter) { - this.contentDescriptionFormatter = formatter == null ? this.formatter : formatter; - setContentDescription(getContentDescriptionLabel()); - } - - @NonNull - public String getLabel() { - return formatter.format(date); - } - - @NonNull - public String getContentDescriptionLabel() { - return contentDescriptionFormatter == null ? formatter.format(date) - : contentDescriptionFormatter.format(date); - } - - public void setSelectionColor(int color) { - this.selectionColor = color; - regenerateBackground(); - } - - /** - * @param drawable custom selection drawable - */ - public void setSelectionDrawable(Drawable drawable) { - if (drawable == null) { - this.selectionDrawable = null; - } else { - this.selectionDrawable = drawable.getConstantState().newDrawable(getResources()); + + /** + * @param drawable background to draw behind everything else + */ + public void setCustomBackground(Drawable drawable) { + if (drawable == null) { + this.customBackground = null; + } else { + this.customBackground = drawable.getConstantState().newDrawable(getResources()); + } + invalidate(); } - regenerateBackground(); - } - - /** - * @param drawable background to draw behind everything else - */ - public void setCustomBackground(Drawable drawable) { - if (drawable == null) { - this.customBackground = null; - } else { - this.customBackground = drawable.getConstantState().newDrawable(getResources()); + + public CalendarDay getDate() { + return date; } - invalidate(); - } - public CalendarDay getDate() { - return date; - } + private void setEnabled() { + boolean enabled = isInMonth && isInRange && !isDecoratedDisabled; + super.setEnabled(isInRange && !isDecoratedDisabled); - private void setEnabled() { - boolean enabled = isInMonth && isInRange && !isDecoratedDisabled; - super.setEnabled(isInRange && !isDecoratedDisabled); + boolean showOtherMonths = showOtherMonths(showOtherDates); + boolean showOutOfRange = showOutOfRange(showOtherDates) || showOtherMonths; + boolean showDecoratedDisabled = showDecoratedDisabled(showOtherDates); - boolean showOtherMonths = showOtherMonths(showOtherDates); - boolean showOutOfRange = showOutOfRange(showOtherDates) || showOtherMonths; - boolean showDecoratedDisabled = showDecoratedDisabled(showOtherDates); + boolean shouldBeVisible = enabled; - boolean shouldBeVisible = enabled; + if (!isInMonth && showOtherMonths) { + shouldBeVisible = true; + } - if (!isInMonth && showOtherMonths) { - shouldBeVisible = true; - } + if (!isInRange && showOutOfRange) { + shouldBeVisible |= isInMonth; + } - if (!isInRange && showOutOfRange) { - shouldBeVisible |= isInMonth; - } + if (isDecoratedDisabled && showDecoratedDisabled) { + shouldBeVisible |= isInMonth && isInRange; + } - if (isDecoratedDisabled && showDecoratedDisabled) { - shouldBeVisible |= isInMonth && isInRange; + if (!isInMonth && shouldBeVisible) { + setTextColor(getTextColors().getColorForState( + new int[]{-android.R.attr.state_enabled}, Color.GRAY)); + } + setVisibility(shouldBeVisible ? View.VISIBLE : View.INVISIBLE); } - if (!isInMonth && shouldBeVisible) { - setTextColor(getTextColors().getColorForState( - new int[] { -android.R.attr.state_enabled }, Color.GRAY)); - } - setVisibility(shouldBeVisible ? View.VISIBLE : View.INVISIBLE); - } - - protected void setupSelection( - @ShowOtherDates int showOtherDates, - boolean inRange, - boolean inMonth) { - this.showOtherDates = showOtherDates; - this.isInMonth = inMonth; - this.isInRange = inRange; - setEnabled(); - } - - private final Rect tempRect = new Rect(); - private final Rect circleDrawableRect = new Rect(); - - @Override - protected void onDraw(@NonNull Canvas canvas) { - if (customBackground != null) { - customBackground.setBounds(tempRect); - customBackground.setState(getDrawableState()); - customBackground.draw(canvas); + protected void setupSelection( + @ShowOtherDates int showOtherDates, + boolean inRange, + boolean inMonth) { + this.showOtherDates = showOtherDates; + this.isInMonth = inMonth; + this.isInRange = inRange; + setEnabled(); } - mCircleDrawable.setBounds(circleDrawableRect); + @Override + protected void onDraw(@NonNull Canvas canvas) { + if (customBackground != null) { + customBackground.setBounds(tempRect); + customBackground.setState(getDrawableState()); + customBackground.draw(canvas); + } - super.onDraw(canvas); - } + mCircleDrawable.setBounds(circleDrawableRect); - private void regenerateBackground() { - if (selectionDrawable != null) { - setBackgroundDrawable(selectionDrawable); - } else { - mCircleDrawable = generateBackground(selectionColor, fadeTime, circleDrawableRect); - setBackgroundDrawable(mCircleDrawable); - } - } - - private static Drawable generateBackground(int color, int fadeTime, Rect bounds) { - StateListDrawable drawable = new StateListDrawable(); - drawable.setExitFadeDuration(fadeTime); - drawable.addState(new int[] { android.R.attr.state_checked }, generateCircleDrawable(color)); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - drawable.addState( - new int[] { android.R.attr.state_pressed }, - generateRippleDrawable(color, bounds) - ); - } else { - drawable.addState(new int[] { android.R.attr.state_pressed }, generateCircleDrawable(color)); + super.onDraw(canvas); } - drawable.addState(new int[] { }, generateCircleDrawable(Color.TRANSPARENT)); - - return drawable; - } - - private static Drawable generateCircleDrawable(final int color) { - ShapeDrawable drawable = new ShapeDrawable(new OvalShape()); - drawable.getPaint().setColor(color); - return drawable; - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private static Drawable generateRippleDrawable(final int color, Rect bounds) { - ColorStateList list = ColorStateList.valueOf(color); - Drawable mask = generateCircleDrawable(Color.WHITE); - RippleDrawable rippleDrawable = new RippleDrawable(list, null, mask); - // API 21 - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) { - rippleDrawable.setBounds(bounds); + private void regenerateBackground() { + if (selectionDrawable != null) { + setBackgroundDrawable(selectionDrawable); + } else { + mCircleDrawable = generateBackground(selectionColor, fadeTime, circleDrawableRect); + setBackgroundDrawable(mCircleDrawable); + } } - // API 22. Technically harmless to leave on for API 21 and 23, but not worth risking for 23+ - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1) { - int center = (bounds.left + bounds.right) / 2; - rippleDrawable.setHotspotBounds(center, bounds.top, center, bounds.bottom); + /** + * @param facade apply the facade to us + */ + void applyFacade(DayViewFacade facade) { + this.isDecoratedDisabled = facade.areDaysDisabled(); + setEnabled(); + + setCustomBackground(facade.getBackgroundDrawable()); + setSelectionDrawable(facade.getSelectionDrawable()); + + // Facade has spans + List spans = facade.getSpans(); + if (!spans.isEmpty()) { + String label = getLabel(); + SpannableString formattedLabel = new SpannableString(getLabel()); + for (DayViewFacade.Span span : spans) { + formattedLabel.setSpan(span.span, 0, label.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + setText(formattedLabel); + } + // Reset in case it was customized previously + else { + setText(getLabel()); + } } - return rippleDrawable; - } - - /** - * @param facade apply the facade to us - */ - void applyFacade(DayViewFacade facade) { - this.isDecoratedDisabled = facade.areDaysDisabled(); - setEnabled(); - - setCustomBackground(facade.getBackgroundDrawable()); - setSelectionDrawable(facade.getSelectionDrawable()); - - // Facade has spans - List spans = facade.getSpans(); - if (!spans.isEmpty()) { - String label = getLabel(); - SpannableString formattedLabel = new SpannableString(getLabel()); - for (DayViewFacade.Span span : spans) { - formattedLabel.setSpan(span.span, 0, label.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - setText(formattedLabel); + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + calculateBounds(right - left, bottom - top); + regenerateBackground(); } - // Reset in case it was customized previously - else { - setText(getLabel()); - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - calculateBounds(right - left, bottom - top); - regenerateBackground(); - } - - private void calculateBounds(int width, int height) { - final int radius = Math.min(height, width); - final int offset = Math.abs(height - width) / 2; - - // Lollipop platform bug. Circle drawable offset needs to be half of normal offset - final int circleOffset = - Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP ? offset / 2 : offset; - - if (width >= height) { - tempRect.set(offset, 0, radius + offset, height); - circleDrawableRect.set(circleOffset, 0, radius + circleOffset, height); - } else { - tempRect.set(0, offset, width, radius + offset); - circleDrawableRect.set(0, circleOffset, width, radius + circleOffset); + + private void calculateBounds(int width, int height) { + final int radius = Math.min(height, width); + final int offset = Math.abs(height - width) / 2; + + // Lollipop platform bug. Circle drawable offset needs to be half of normal offset + final int circleOffset = + Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP ? offset / 2 : offset; + + if (width >= height) { + tempRect.set(offset, 0, radius + offset, height); + circleDrawableRect.set(circleOffset, 0, radius + circleOffset, height); + } else { + tempRect.set(0, offset, width, radius + offset); + circleDrawableRect.set(0, circleOffset, width, radius + circleOffset); + } } - } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/DayViewDecorator.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/DayViewDecorator.java index 4b7585c1..e6657816 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/DayViewDecorator.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/DayViewDecorator.java @@ -5,18 +5,18 @@ */ public interface DayViewDecorator { - /** - * Determine if a specific day should be decorated - * - * @param day {@linkplain CalendarDay} to possibly decorate - * @return true if this decorator should be applied to the provided day - */ - boolean shouldDecorate(CalendarDay day); + /** + * Determine if a specific day should be decorated + * + * @param day {@linkplain CalendarDay} to possibly decorate + * @return true if this decorator should be applied to the provided day + */ + boolean shouldDecorate(CalendarDay day); - /** - * Set decoration options onto a facade to be applied to all relevant days - * - * @param view View to decorate - */ - void decorate(DayViewFacade view); + /** + * Set decoration options onto a facade to be applied to all relevant days + * + * @param view View to decorate + */ + void decorate(DayViewFacade view); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/DayViewFacade.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/DayViewFacade.java index cbffdfec..53df2a21 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/DayViewFacade.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/DayViewFacade.java @@ -1,7 +1,8 @@ package com.prolificinteractive.materialcalendarview; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; + import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -11,124 +12,123 @@ */ public class DayViewFacade { - private boolean isDecorated; - - private Drawable backgroundDrawable = null; - private Drawable selectionDrawable = null; - private final LinkedList spans = new LinkedList<>(); - private boolean daysDisabled = false; - - DayViewFacade() { - isDecorated = false; - } - - /** - * Set a drawable to draw behind everything else - * - * @param drawable Drawable to draw behind everything - */ - public void setBackgroundDrawable(@NonNull Drawable drawable) { - if (drawable == null) { - throw new IllegalArgumentException("Cannot be null"); + private final LinkedList spans = new LinkedList<>(); + private boolean isDecorated; + private Drawable backgroundDrawable = null; + private Drawable selectionDrawable = null; + private boolean daysDisabled = false; + + DayViewFacade() { + isDecorated = false; + } + + /** + * Add a span to the entire text of a day + * + * @param span text span instance + */ + public void addSpan(@NonNull Object span) { + if (spans != null) { + this.spans.add(new Span(span)); + isDecorated = true; + } + } + + /** + *

Set days to be in a disabled state, or re-enabled.

+ *

Note, passing true here will not override minimum and maximum dates, if set. + * This will only re-enable disabled dates.

+ * + * @param daysDisabled true to disable days, false to re-enable days + */ + public void setDaysDisabled(boolean daysDisabled) { + this.daysDisabled = daysDisabled; + this.isDecorated = true; } - this.backgroundDrawable = drawable; - isDecorated = true; - } - - /** - * Set a custom selection drawable - * TODO: define states that can/should be used in StateListDrawables - * - * @param drawable the drawable for selection - */ - public void setSelectionDrawable(@NonNull Drawable drawable) { - if (drawable == null) { - throw new IllegalArgumentException("Cannot be null"); + + void reset() { + backgroundDrawable = null; + selectionDrawable = null; + spans.clear(); + isDecorated = false; + daysDisabled = false; + } + + /** + * Apply things set this to other + * + * @param other facade to apply our data to + */ + void applyTo(DayViewFacade other) { + if (selectionDrawable != null) { + other.setSelectionDrawable(selectionDrawable); + } + if (backgroundDrawable != null) { + other.setBackgroundDrawable(backgroundDrawable); + } + other.spans.addAll(spans); + other.isDecorated |= this.isDecorated; + other.daysDisabled = daysDisabled; } - selectionDrawable = drawable; - isDecorated = true; - } - - /** - * Add a span to the entire text of a day - * - * @param span text span instance - */ - public void addSpan(@NonNull Object span) { - if (spans != null) { - this.spans.add(new Span(span)); - isDecorated = true; + + boolean isDecorated() { + return isDecorated; } - } - - /** - *

Set days to be in a disabled state, or re-enabled.

- *

Note, passing true here will not override minimum and maximum dates, if set. - * This will only re-enable disabled dates.

- * - * @param daysDisabled true to disable days, false to re-enable days - */ - public void setDaysDisabled(boolean daysDisabled) { - this.daysDisabled = daysDisabled; - this.isDecorated = true; - } - - void reset() { - backgroundDrawable = null; - selectionDrawable = null; - spans.clear(); - isDecorated = false; - daysDisabled = false; - } - - /** - * Apply things set this to other - * - * @param other facade to apply our data to - */ - void applyTo(DayViewFacade other) { - if (selectionDrawable != null) { - other.setSelectionDrawable(selectionDrawable); + + Drawable getSelectionDrawable() { + return selectionDrawable; } - if (backgroundDrawable != null) { - other.setBackgroundDrawable(backgroundDrawable); + + /** + * Set a custom selection drawable + * TODO: define states that can/should be used in StateListDrawables + * + * @param drawable the drawable for selection + */ + public void setSelectionDrawable(@NonNull Drawable drawable) { + if (drawable == null) { + throw new IllegalArgumentException("Cannot be null"); + } + selectionDrawable = drawable; + isDecorated = true; } - other.spans.addAll(spans); - other.isDecorated |= this.isDecorated; - other.daysDisabled = daysDisabled; - } - - boolean isDecorated() { - return isDecorated; - } - - Drawable getSelectionDrawable() { - return selectionDrawable; - } - - Drawable getBackgroundDrawable() { - return backgroundDrawable; - } - - List getSpans() { - return Collections.unmodifiableList(spans); - } - - /** - * Are days from this facade disabled - * - * @return true if disabled, false if not re-enabled - */ - public boolean areDaysDisabled() { - return daysDisabled; - } - - static class Span { - - final Object span; - - public Span(Object span) { - this.span = span; + + Drawable getBackgroundDrawable() { + return backgroundDrawable; + } + + /** + * Set a drawable to draw behind everything else + * + * @param drawable Drawable to draw behind everything + */ + public void setBackgroundDrawable(@NonNull Drawable drawable) { + if (drawable == null) { + throw new IllegalArgumentException("Cannot be null"); + } + this.backgroundDrawable = drawable; + isDecorated = true; + } + + List getSpans() { + return Collections.unmodifiableList(spans); + } + + /** + * Are days from this facade disabled + * + * @return true if disabled, false if not re-enabled + */ + public boolean areDaysDisabled() { + return daysDisabled; + } + + static class Span { + + final Object span; + + public Span(Object span) { + this.span = span; + } } - } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/DecoratorResult.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/DecoratorResult.java index 392897f3..d491a955 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/DecoratorResult.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/DecoratorResult.java @@ -1,11 +1,11 @@ package com.prolificinteractive.materialcalendarview; class DecoratorResult { - public final DayViewDecorator decorator; - public final DayViewFacade result; + public final DayViewDecorator decorator; + public final DayViewFacade result; - DecoratorResult(DayViewDecorator decorator, DayViewFacade result) { - this.decorator = decorator; - this.result = result; - } + DecoratorResult(DayViewDecorator decorator, DayViewFacade result) { + this.decorator = decorator; + this.result = result; + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/LocalUtils.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/LocalUtils.java index 19870623..bb995e8f 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/LocalUtils.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/LocalUtils.java @@ -1,15 +1,17 @@ package com.prolificinteractive.materialcalendarview; -import android.support.v4.text.TextUtilsCompat; -import android.support.v4.view.ViewCompat; +import androidx.core.text.TextUtilsCompat; +import androidx.core.view.ViewCompat; + import java.util.Locale; class LocalUtils { - private LocalUtils() { } + private LocalUtils() { + } - static boolean isRTL() { - return TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) - == ViewCompat.LAYOUT_DIRECTION_RTL; - } + static boolean isRTL() { + return TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) + == ViewCompat.LAYOUT_DIRECTION_RTL; + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/MaterialCalendarView.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/MaterialCalendarView.java index 623b4a69..65a65af6 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/MaterialCalendarView.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/MaterialCalendarView.java @@ -9,12 +9,6 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.ArrayRes; -import android.support.annotation.DrawableRes; -import android.support.annotation.IntDef; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.util.SparseArray; import android.util.TypedValue; @@ -27,11 +21,25 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; + +import androidx.annotation.ArrayRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; + import com.prolificinteractive.materialcalendarview.format.ArrayWeekDayFormatter; +import com.prolificinteractive.materialcalendarview.format.DateFormatDayFormatter; import com.prolificinteractive.materialcalendarview.format.DayFormatter; import com.prolificinteractive.materialcalendarview.format.MonthArrayTitleFormatter; import com.prolificinteractive.materialcalendarview.format.TitleFormatter; import com.prolificinteractive.materialcalendarview.format.WeekDayFormatter; + +import org.threeten.bp.DayOfWeek; +import org.threeten.bp.LocalDate; +import org.threeten.bp.temporal.WeekFields; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -40,9 +48,6 @@ import java.util.Collection; import java.util.List; import java.util.Locale; -import org.threeten.bp.DayOfWeek; -import org.threeten.bp.LocalDate; -import org.threeten.bp.temporal.WeekFields; /** *

@@ -68,1951 +73,1930 @@ */ public class MaterialCalendarView extends ViewGroup { - public static final int INVALID_TILE_DIMENSION = -10; - - /** - * {@linkplain IntDef} annotation for selection mode. - * - * @see #setSelectionMode(int) - * @see #getSelectionMode() - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef( - { SELECTION_MODE_NONE, SELECTION_MODE_SINGLE, SELECTION_MODE_MULTIPLE, SELECTION_MODE_RANGE }) - public @interface SelectionMode { - } - - /** - * Selection mode that disallows all selection. - * When changing to this mode, current selection will be cleared. - */ - public static final int SELECTION_MODE_NONE = 0; - - /** - * Selection mode that allows one selected date at one time. This is the default mode. - * When switching from {@linkplain #SELECTION_MODE_MULTIPLE}, this will select the same date - * as from {@linkplain #getSelectedDate()}, which should be the last selected date - */ - public static final int SELECTION_MODE_SINGLE = 1; - - /** - * Selection mode which allows more than one selected date at one time. - */ - public static final int SELECTION_MODE_MULTIPLE = 2; - - /** - * Selection mode which allows selection of a range between two dates - */ - public static final int SELECTION_MODE_RANGE = 3; - - /** - * {@linkplain IntDef} annotation for showOtherDates. - * - * @see #setShowOtherDates(int) - * @see #getShowOtherDates() - */ - @SuppressLint("UniqueConstants") - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, value = { - SHOW_NONE, SHOW_ALL, SHOW_DEFAULTS, - SHOW_OUT_OF_RANGE, SHOW_OTHER_MONTHS, SHOW_DECORATED_DISABLED - }) - public @interface ShowOtherDates { - } - - /** - * Do not show any non-enabled dates - */ - public static final int SHOW_NONE = 0; - - /** - * Show dates from the proceeding and successive months, in a disabled state. - * This flag also enables the {@link #SHOW_OUT_OF_RANGE} flag to prevent odd blank areas. - */ - public static final int SHOW_OTHER_MONTHS = 1; - - /** - * Show dates that are outside of the min-max range. - * This will only show days from the current month unless {@link #SHOW_OTHER_MONTHS} is enabled. - */ - public static final int SHOW_OUT_OF_RANGE = 1 << 1; - - /** - * Show days that are individually disabled with decorators. - * This will only show dates in the current month and inside the minimum and maximum date range. - */ - public static final int SHOW_DECORATED_DISABLED = 1 << 2; - - /** - * The default flags for showing non-enabled dates. Currently only shows {@link - * #SHOW_DECORATED_DISABLED} - */ - public static final int SHOW_DEFAULTS = SHOW_DECORATED_DISABLED; - - /** - * Show all the days - */ - public static final int SHOW_ALL = - SHOW_OTHER_MONTHS | SHOW_OUT_OF_RANGE | SHOW_DECORATED_DISABLED; - - /** - * Use this orientation to animate the title vertically - */ - public static final int VERTICAL = 0; - - /** - * Use this orientation to animate the title horizontally - */ - public static final int HORIZONTAL = 1; - - /** - * Default tile size in DIPs. This is used in cases where there is no tile size specificed and the - * view is set to {@linkplain ViewGroup.LayoutParams#WRAP_CONTENT WRAP_CONTENT} - */ - public static final int DEFAULT_TILE_SIZE_DP = 44; - private static final int DEFAULT_DAYS_IN_WEEK = 7; - private static final int DEFAULT_MAX_WEEKS = 6; - private static final int DAY_NAMES_ROW = 1; - - private final TitleChanger titleChanger; - - private final TextView title; - private final ImageView buttonPast; - private final ImageView buttonFuture; - private final CalendarPager pager; - private CalendarPagerAdapter adapter; - private CalendarDay currentMonth; - private LinearLayout topbar; - private CalendarMode calendarMode; - /** - * Used for the dynamic calendar height. - */ - private boolean mDynamicHeightEnabled; - - private final ArrayList dayViewDecorators = new ArrayList<>(); - - private final OnClickListener onClickListener = new OnClickListener() { - @Override - public void onClick(View v) { - if (v == buttonFuture) { - pager.setCurrentItem(pager.getCurrentItem() + 1, true); - } else if (v == buttonPast) { - pager.setCurrentItem(pager.getCurrentItem() - 1, true); - } + public static final int INVALID_TILE_DIMENSION = -10; + /** + * Selection mode that disallows all selection. + * When changing to this mode, current selection will be cleared. + */ + public static final int SELECTION_MODE_NONE = 0; + /** + * Selection mode that allows one selected date at one time. This is the default mode. + * When switching from {@linkplain #SELECTION_MODE_MULTIPLE}, this will select the same date + * as from {@linkplain #getSelectedDate()}, which should be the last selected date + */ + public static final int SELECTION_MODE_SINGLE = 1; + /** + * Selection mode which allows more than one selected date at one time. + */ + public static final int SELECTION_MODE_MULTIPLE = 2; + /** + * Selection mode which allows selection of a range between two dates + */ + public static final int SELECTION_MODE_RANGE = 3; + /** + * Do not show any non-enabled dates + */ + public static final int SHOW_NONE = 0; + /** + * Show dates from the proceeding and successive months, in a disabled state. + * This flag also enables the {@link #SHOW_OUT_OF_RANGE} flag to prevent odd blank areas. + */ + public static final int SHOW_OTHER_MONTHS = 1; + /** + * Show dates that are outside of the min-max range. + * This will only show days from the current month unless {@link #SHOW_OTHER_MONTHS} is enabled. + */ + public static final int SHOW_OUT_OF_RANGE = 1 << 1; + /** + * Show days that are individually disabled with decorators. + * This will only show dates in the current month and inside the minimum and maximum date range. + */ + public static final int SHOW_DECORATED_DISABLED = 1 << 2; + /** + * The default flags for showing non-enabled dates. Currently only shows {@link + * #SHOW_DECORATED_DISABLED} + */ + public static final int SHOW_DEFAULTS = SHOW_DECORATED_DISABLED; + /** + * Show all the days + */ + public static final int SHOW_ALL = + SHOW_OTHER_MONTHS | SHOW_OUT_OF_RANGE | SHOW_DECORATED_DISABLED; + /** + * Use this orientation to animate the title vertically + */ + public static final int VERTICAL = 0; + /** + * Use this orientation to animate the title horizontally + */ + public static final int HORIZONTAL = 1; + /** + * Default tile size in DIPs. This is used in cases where there is no tile size specificed and the + * view is set to {@linkplain ViewGroup.LayoutParams#WRAP_CONTENT WRAP_CONTENT} + */ + public static final int DEFAULT_TILE_SIZE_DP = 44; + private static final int DEFAULT_DAYS_IN_WEEK = 7; + private static final int DEFAULT_MAX_WEEKS = 6; + private static final int DAY_NAMES_ROW = 1; + private final TitleChanger titleChanger; + private final TextView title; + private final ImageView backArrowButton; + private final ImageView ForwardArrowButton; + private final CalendarPager pager; + private final ArrayList dayViewDecorators = new ArrayList<>(); + private final OnClickListener onClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + if (v == ForwardArrowButton) { + pager.setCurrentItem(pager.getCurrentItem() + 1, true); + } else if (v == backArrowButton) { + pager.setCurrentItem(pager.getCurrentItem() - 1, true); + } + } + }; + CharSequence calendarContentDescription; + private CalendarPagerAdapter adapter; + private CalendarDay currentMonth; + private LinearLayout topbar; + private CalendarMode calendarMode; + /** + * Used for the dynamic calendar height. + */ + private boolean mDynamicHeightEnabled; + private CalendarDay minDate = null; + private CalendarDay maxDate = null; + private OnDateSelectedListener listener; + private OnDateLongClickListener longClickListener; + private OnMonthChangedListener monthListener; + private OnRangeSelectedListener rangeListener; + private int accentColor = 0; + private int tileHeight = INVALID_TILE_DIMENSION; + private int tileWidth = INVALID_TILE_DIMENSION; + @SelectionMode + private int selectionMode = SELECTION_MODE_SINGLE; + private boolean allowClickDaysOutsideCurrentMonth = true; + private DayOfWeek firstDayOfWeek; + private boolean showWeekDays; + private State state; + + public MaterialCalendarView(Context context) { + this(context, null); } - }; - private final ViewPager.OnPageChangeListener pageChangeListener = - new ViewPager.OnPageChangeListener() { - @Override - public void onPageSelected(int position) { - titleChanger.setPreviousMonth(currentMonth); - currentMonth = adapter.getItem(position); - updateUi(); + public MaterialCalendarView(Context context, AttributeSet attrs) { + super(context, attrs); - dispatchOnMonthChanged(currentMonth); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + //If we're on good Android versions, turn off clipping for cool effects + setClipToPadding(false); + setClipChildren(false); + } else { + //Old Android does not like _not_ clipping view pagers, we need to clip + setClipChildren(true); + setClipToPadding(true); } - @Override - public void onPageScrollStateChanged(int state) { + final LayoutInflater inflater = + (LayoutInflater) getContext().getSystemService(Service.LAYOUT_INFLATER_SERVICE); + final View content = inflater.inflate(R.layout.calendar_view, null, false); + + topbar = content.findViewById(R.id.header); + backArrowButton = content.findViewById(R.id.previous); + title = content.findViewById(R.id.month_name); + ForwardArrowButton = content.findViewById(R.id.next); + pager = new CalendarPager(getContext()); + + backArrowButton.setOnClickListener(onClickListener); + ForwardArrowButton.setOnClickListener(onClickListener); + + titleChanger = new TitleChanger(title); + setOnChangeViewPagerListener(); + pager.setPageTransformer(false, new ViewPager.PageTransformer() { + @Override + public void transformPage(View page, float position) { + position = (float) Math.sqrt(1 - Math.abs(position)); + page.setAlpha(position); + } + }); + + TypedArray a = context.getTheme() + .obtainStyledAttributes(attrs, R.styleable.MaterialCalendarView, 0, 0); + try { + int calendarModeIndex = a.getInteger( + R.styleable.MaterialCalendarView_mcv_calendarMode, + 0 + ); + int firstDayOfWeekInt = a.getInteger( + R.styleable.MaterialCalendarView_mcv_firstDayOfWeek, + -1 + ); + + titleChanger.setOrientation( + a.getInteger( + R.styleable.MaterialCalendarView_mcv_titleAnimationOrientation, + VERTICAL + )); + + if (firstDayOfWeekInt >= 1 && firstDayOfWeekInt <= 7) { + firstDayOfWeek = DayOfWeek.of(firstDayOfWeekInt); + } else { + firstDayOfWeek = WeekFields.of(Locale.getDefault()).getFirstDayOfWeek(); + } + + showWeekDays = a.getBoolean(R.styleable.MaterialCalendarView_mcv_showWeekDays, true); + + newState() + .setFirstDayOfWeek(firstDayOfWeek) + .setCalendarDisplayMode(CalendarMode.values()[calendarModeIndex]) + .setShowWeekDays(showWeekDays) + .commit(); + + setSelectionMode(a.getInteger( + R.styleable.MaterialCalendarView_mcv_selectionMode, + SELECTION_MODE_SINGLE + )); + + final int tileSize = a.getLayoutDimension( + R.styleable.MaterialCalendarView_mcv_tileSize, + INVALID_TILE_DIMENSION + ); + if (tileSize > INVALID_TILE_DIMENSION) { + setTileSize(tileSize); + } + + final int tileWidth = a.getLayoutDimension( + R.styleable.MaterialCalendarView_mcv_tileWidth, + INVALID_TILE_DIMENSION + ); + if (tileWidth > INVALID_TILE_DIMENSION) { + setTileWidth(tileWidth); + } + + final int tileHeight = a.getLayoutDimension( + R.styleable.MaterialCalendarView_mcv_tileHeight, + INVALID_TILE_DIMENSION + ); + if (tileHeight > INVALID_TILE_DIMENSION) { + setTileHeight(tileHeight); + } + + setLeftArrow( + a.getResourceId( + R.styleable.MaterialCalendarView_mcv_leftArrow, + R.drawable.mcv_action_previous + ) + ); + setRightArrow( + a.getResourceId( + R.styleable.MaterialCalendarView_mcv_rightArrow, + R.drawable.mcv_action_next + ) + ); + + setSelectionColor( + a.getColor( + R.styleable.MaterialCalendarView_mcv_selectionColor, + getThemeAccentColor(context) + ) + ); + + CharSequence[] array = a.getTextArray(R.styleable.MaterialCalendarView_mcv_weekDayLabels); + if (array != null) { + setWeekDayFormatter(new ArrayWeekDayFormatter(array)); + } + + array = a.getTextArray(R.styleable.MaterialCalendarView_mcv_monthLabels); + if (array != null) { + setTitleFormatter(new MonthArrayTitleFormatter(array)); + } + + setHeaderTextAppearance(a.getResourceId( + R.styleable.MaterialCalendarView_mcv_headerTextAppearance, + R.style.TextAppearance_MaterialCalendarWidget_Header + )); + setWeekDayTextAppearance(a.getResourceId( + R.styleable.MaterialCalendarView_mcv_weekDayTextAppearance, + R.style.TextAppearance_MaterialCalendarWidget_WeekDay + )); + setDateTextAppearance(a.getResourceId( + R.styleable.MaterialCalendarView_mcv_dateTextAppearance, + R.style.TextAppearance_MaterialCalendarWidget_Date + )); + //noinspection ResourceType + setShowOtherDates(a.getInteger( + R.styleable.MaterialCalendarView_mcv_showOtherDates, + SHOW_DEFAULTS + )); + + setAllowClickDaysOutsideCurrentMonth(a.getBoolean( + R.styleable.MaterialCalendarView_mcv_allowClickDaysOutsideCurrentMonth, + true + )); + } catch (Exception e) { + e.printStackTrace(); + } finally { + a.recycle(); } - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + // Adapter is created while parsing the TypedArray attrs, so setup has to happen after + setupChildren(); + + currentMonth = CalendarDay.today(); + setCurrentDate(currentMonth); + + if (isInEditMode()) { + removeView(pager); + MonthView monthView = new MonthView(this, currentMonth, getFirstDayOfWeek(), true); + monthView.setSelectionColor(getSelectionColor()); + monthView.setDateTextAppearance(adapter.getDateTextAppearance()); + monthView.setWeekDayTextAppearance(adapter.getWeekDayTextAppearance()); + monthView.setShowOtherDates(getShowOtherDates()); + addView(monthView, new LayoutParams(calendarMode.visibleWeeksCount + DAY_NAMES_ROW)); } - }; - - private CalendarDay minDate = null; - private CalendarDay maxDate = null; - - private OnDateSelectedListener listener; - private OnDateLongClickListener longClickListener; - private OnMonthChangedListener monthListener; - private OnRangeSelectedListener rangeListener; - - CharSequence calendarContentDescription; - private int accentColor = 0; - private int tileHeight = INVALID_TILE_DIMENSION; - private int tileWidth = INVALID_TILE_DIMENSION; - @SelectionMode - private int selectionMode = SELECTION_MODE_SINGLE; - private boolean allowClickDaysOutsideCurrentMonth = true; - private DayOfWeek firstDayOfWeek; - private boolean showWeekDays; - - private State state; - - public MaterialCalendarView(Context context) { - this(context, null); - } - - public MaterialCalendarView(Context context, AttributeSet attrs) { - super(context, attrs); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - //If we're on good Android versions, turn off clipping for cool effects - setClipToPadding(false); - setClipChildren(false); - } else { - //Old Android does not like _not_ clipping view pagers, we need to clip - setClipChildren(true); - setClipToPadding(true); - } - - final LayoutInflater inflater = - (LayoutInflater) getContext().getSystemService(Service.LAYOUT_INFLATER_SERVICE); - final View content = inflater.inflate(R.layout.calendar_view, null, false); - - topbar = content.findViewById(R.id.header); - buttonPast = content.findViewById(R.id.previous); - title = content.findViewById(R.id.month_name); - buttonFuture = content.findViewById(R.id.next); - pager = new CalendarPager(getContext()); - - buttonPast.setOnClickListener(onClickListener); - buttonFuture.setOnClickListener(onClickListener); - - titleChanger = new TitleChanger(title); - - pager.setOnPageChangeListener(pageChangeListener); - pager.setPageTransformer(false, new ViewPager.PageTransformer() { - @Override - public void transformPage(View page, float position) { - position = (float) Math.sqrt(1 - Math.abs(position)); - page.setAlpha(position); - } - }); - - TypedArray a = context.getTheme() - .obtainStyledAttributes(attrs, R.styleable.MaterialCalendarView, 0, 0); - try { - int calendarModeIndex = a.getInteger( - R.styleable.MaterialCalendarView_mcv_calendarMode, - 0 - ); - int firstDayOfWeekInt = a.getInteger( - R.styleable.MaterialCalendarView_mcv_firstDayOfWeek, - -1 - ); - - titleChanger.setOrientation( - a.getInteger( - R.styleable.MaterialCalendarView_mcv_titleAnimationOrientation, - VERTICAL - )); - - if (firstDayOfWeekInt >= 1 && firstDayOfWeekInt <= 7) { - firstDayOfWeek = DayOfWeek.of(firstDayOfWeekInt); - } else { - firstDayOfWeek = WeekFields.of(Locale.getDefault()).getFirstDayOfWeek(); - } - - showWeekDays = a.getBoolean(R.styleable.MaterialCalendarView_mcv_showWeekDays, true); - - newState() - .setFirstDayOfWeek(firstDayOfWeek) - .setCalendarDisplayMode(CalendarMode.values()[calendarModeIndex]) - .setShowWeekDays(showWeekDays) - .commit(); - - setSelectionMode(a.getInteger( - R.styleable.MaterialCalendarView_mcv_selectionMode, - SELECTION_MODE_SINGLE - )); - - final int tileSize = a.getLayoutDimension( - R.styleable.MaterialCalendarView_mcv_tileSize, - INVALID_TILE_DIMENSION - ); - if (tileSize > INVALID_TILE_DIMENSION) { - setTileSize(tileSize); - } - - final int tileWidth = a.getLayoutDimension( - R.styleable.MaterialCalendarView_mcv_tileWidth, - INVALID_TILE_DIMENSION - ); - if (tileWidth > INVALID_TILE_DIMENSION) { - setTileWidth(tileWidth); - } - - final int tileHeight = a.getLayoutDimension( - R.styleable.MaterialCalendarView_mcv_tileHeight, - INVALID_TILE_DIMENSION - ); - if (tileHeight > INVALID_TILE_DIMENSION) { - setTileHeight(tileHeight); - } - - setLeftArrow( - a.getResourceId( - R.styleable.MaterialCalendarView_mcv_leftArrow, - R.drawable.mcv_action_previous - ) - ); - setRightArrow( - a.getResourceId( - R.styleable.MaterialCalendarView_mcv_rightArrow, - R.drawable.mcv_action_next - ) - ); - - setSelectionColor( - a.getColor( - R.styleable.MaterialCalendarView_mcv_selectionColor, - getThemeAccentColor(context) - ) - ); - - CharSequence[] array = a.getTextArray(R.styleable.MaterialCalendarView_mcv_weekDayLabels); - if (array != null) { - setWeekDayFormatter(new ArrayWeekDayFormatter(array)); - } - - array = a.getTextArray(R.styleable.MaterialCalendarView_mcv_monthLabels); - if (array != null) { - setTitleFormatter(new MonthArrayTitleFormatter(array)); - } - - setHeaderTextAppearance(a.getResourceId( - R.styleable.MaterialCalendarView_mcv_headerTextAppearance, - R.style.TextAppearance_MaterialCalendarWidget_Header - )); - setWeekDayTextAppearance(a.getResourceId( - R.styleable.MaterialCalendarView_mcv_weekDayTextAppearance, - R.style.TextAppearance_MaterialCalendarWidget_WeekDay - )); - setDateTextAppearance(a.getResourceId( - R.styleable.MaterialCalendarView_mcv_dateTextAppearance, - R.style.TextAppearance_MaterialCalendarWidget_Date - )); - //noinspection ResourceType - setShowOtherDates(a.getInteger( - R.styleable.MaterialCalendarView_mcv_showOtherDates, - SHOW_DEFAULTS - )); - - setAllowClickDaysOutsideCurrentMonth(a.getBoolean( - R.styleable.MaterialCalendarView_mcv_allowClickDaysOutsideCurrentMonth, - true - )); - } catch (Exception e) { - e.printStackTrace(); - } finally { - a.recycle(); - } - - // Adapter is created while parsing the TypedArray attrs, so setup has to happen after - setupChildren(); - - currentMonth = CalendarDay.today(); - setCurrentDate(currentMonth); - - if (isInEditMode()) { - removeView(pager); - MonthView monthView = new MonthView(this, currentMonth, getFirstDayOfWeek(), true); - monthView.setSelectionColor(getSelectionColor()); - monthView.setDateTextAppearance(adapter.getDateTextAppearance()); - monthView.setWeekDayTextAppearance(adapter.getWeekDayTextAppearance()); - monthView.setShowOtherDates(getShowOtherDates()); - addView(monthView, new LayoutParams(calendarMode.visibleWeeksCount + DAY_NAMES_ROW)); - } - } - - private void setupChildren() { - addView(topbar); - - pager.setId(R.id.mcv_pager); - pager.setOffscreenPageLimit(1); - int tileHeight = showWeekDays ? calendarMode.visibleWeeksCount + DAY_NAMES_ROW - : calendarMode.visibleWeeksCount; - addView(pager, new LayoutParams(tileHeight)); - } - - private void updateUi() { - titleChanger.change(currentMonth); - enableView(buttonPast, canGoBack()); - enableView(buttonFuture, canGoForward()); - } - - /** - * Change the selection mode of the calendar. The default mode is {@linkplain - * #SELECTION_MODE_SINGLE} - * - * @param mode the selection mode to change to. This must be one of - * {@linkplain #SELECTION_MODE_NONE}, {@linkplain #SELECTION_MODE_SINGLE}, - * {@linkplain #SELECTION_MODE_RANGE} or {@linkplain #SELECTION_MODE_MULTIPLE}. - * Unknown values will act as {@linkplain #SELECTION_MODE_SINGLE} - * @see #getSelectionMode() - * @see #SELECTION_MODE_NONE - * @see #SELECTION_MODE_SINGLE - * @see #SELECTION_MODE_MULTIPLE - * @see #SELECTION_MODE_RANGE - */ - public void setSelectionMode(final @SelectionMode int mode) { - final @SelectionMode int oldMode = this.selectionMode; - this.selectionMode = mode; - switch (mode) { - case SELECTION_MODE_RANGE: - clearSelection(); - break; - case SELECTION_MODE_MULTIPLE: - break; - case SELECTION_MODE_SINGLE: - if (oldMode == SELECTION_MODE_MULTIPLE || oldMode == SELECTION_MODE_RANGE) { - //We should only have one selection now, so we should pick one - List dates = getSelectedDates(); - if (!dates.isEmpty()) { - setSelectedDate(getSelectedDate()); - } + } + + private static int getThemeAccentColor(Context context) { + int colorAttr; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + colorAttr = android.R.attr.colorAccent; + } else { + //Get colorAccent defined for AppCompat + colorAttr = + context.getResources().getIdentifier("colorAccent", "attr", context.getPackageName()); + } + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(colorAttr, outValue, true); + return outValue.data; + } + + /** + * @param showOtherDates int flag for show other dates + * @return true if the other months flag is set + */ + public static boolean showOtherMonths(@ShowOtherDates int showOtherDates) { + return (showOtherDates & SHOW_OTHER_MONTHS) != 0; + } + + /** + * @param showOtherDates int flag for show other dates + * @return true if the out of range flag is set + */ + public static boolean showOutOfRange(@ShowOtherDates int showOtherDates) { + return (showOtherDates & SHOW_OUT_OF_RANGE) != 0; + } + + /** + * @param showOtherDates int flag for show other dates + * @return true if the decorated disabled flag is set + */ + public static boolean showDecoratedDisabled(@ShowOtherDates int showOtherDates) { + return (showOtherDates & SHOW_DECORATED_DISABLED) != 0; + } + + /** + * Clamp the size to the measure spec. + * + * @param size Size we want to be + * @param spec Measure spec to clamp against + * @return the appropriate size to pass to {@linkplain View#setMeasuredDimension(int, int)} + */ + private static int clampSize(int size, int spec) { + int specMode = MeasureSpec.getMode(spec); + int specSize = MeasureSpec.getSize(spec); + switch (specMode) { + case MeasureSpec.EXACTLY: { + return specSize; + } + case MeasureSpec.AT_MOST: { + return Math.min(size, specSize); + } + case MeasureSpec.UNSPECIFIED: + default: { + return size; + } + } + } + + /** + * Used for enabling or disabling views, while also changing the alpha. + * + * @param view The view to enable or disable. + * @param enable Whether to enable or disable the view. + */ + private static void enableView(final View view, final boolean enable) { + view.setEnabled(enable); + view.setAlpha(enable ? 1f : 0.1f); + } + + private void setOnChangeViewPagerListener() { + pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + @Override + public void onPageSelected(int position) { + titleChanger.setPreviousMonth(currentMonth); + currentMonth = adapter.getItem(pager.getCurrentItem()); + updateUi(); + dispatchOnMonthChanged(currentMonth); + } + + @Override + public void onPageScrollStateChanged(int state) { + } + }); + } + + private void setupChildren() { + addView(topbar); + + pager.setId(R.id.mcv_pager); + pager.setOffscreenPageLimit(1); + int tileHeight = showWeekDays ? calendarMode.visibleWeeksCount + DAY_NAMES_ROW + : calendarMode.visibleWeeksCount; + addView(pager, new LayoutParams(tileHeight)); + } + + private void updateUi() { + titleChanger.change(currentMonth); + enableView(backArrowButton, canGoBack()); + enableView(ForwardArrowButton, canGoForward()); + } + + /** + * Go to previous month or week without using the button {@link #backArrowButton}. Should only go to + * previous if {@link #canGoBack()} is true, meaning it's possible to go to the previous month + * or week. + */ + public void goToPrevious() { + if (canGoBack()) { + pager.setCurrentItem(pager.getCurrentItem() - 1, true); + } + } + + /** + * Go to next month or week without using the button {@link #ForwardArrowButton}. Should only go to + * next if {@link #canGoForward()} is enabled, meaning it's possible to go to the next month or + * week. + */ + public void goToNext() { + if (canGoForward()) { + pager.setCurrentItem(pager.getCurrentItem() + 1, true); } - break; - default: - case SELECTION_MODE_NONE: - this.selectionMode = SELECTION_MODE_NONE; - if (oldMode != SELECTION_MODE_NONE) { - //No selection! Clear out! - clearSelection(); + } + + /** + * Get the current selection mode. The default mode is {@linkplain #SELECTION_MODE_SINGLE} + * + * @return the current selection mode + * @see #setSelectionMode(int) + * @see #SELECTION_MODE_NONE + * @see #SELECTION_MODE_SINGLE + * @see #SELECTION_MODE_MULTIPLE + * @see #SELECTION_MODE_RANGE + */ + @SelectionMode + public int getSelectionMode() { + return selectionMode; + } + + /** + * Change the selection mode of the calendar. The default mode is {@linkplain + * #SELECTION_MODE_SINGLE} + * + * @param mode the selection mode to change to. This must be one of + * {@linkplain #SELECTION_MODE_NONE}, {@linkplain #SELECTION_MODE_SINGLE}, + * {@linkplain #SELECTION_MODE_RANGE} or {@linkplain #SELECTION_MODE_MULTIPLE}. + * Unknown values will act as {@linkplain #SELECTION_MODE_SINGLE} + * @see #getSelectionMode() + * @see #SELECTION_MODE_NONE + * @see #SELECTION_MODE_SINGLE + * @see #SELECTION_MODE_MULTIPLE + * @see #SELECTION_MODE_RANGE + */ + public void setSelectionMode(final @SelectionMode int mode) { + final @SelectionMode int oldMode = this.selectionMode; + this.selectionMode = mode; + switch (mode) { + case SELECTION_MODE_RANGE: + clearSelection(); + break; + case SELECTION_MODE_MULTIPLE: + break; + case SELECTION_MODE_SINGLE: + if (oldMode == SELECTION_MODE_MULTIPLE || oldMode == SELECTION_MODE_RANGE) { + //We should only have one selection now, so we should pick one + List dates = getSelectedDates(); + if (!dates.isEmpty()) { + setSelectedDate(getSelectedDate()); + } + } + break; + default: + case SELECTION_MODE_NONE: + this.selectionMode = SELECTION_MODE_NONE; + if (oldMode != SELECTION_MODE_NONE) { + //No selection! Clear out! + clearSelection(); + } + break; } - break; - } - - adapter.setSelectionEnabled(selectionMode != SELECTION_MODE_NONE); - } - - /** - * Go to previous month or week without using the button {@link #buttonPast}. Should only go to - * previous if {@link #canGoBack()} is true, meaning it's possible to go to the previous month - * or week. - */ - public void goToPrevious() { - if (canGoBack()) { - pager.setCurrentItem(pager.getCurrentItem() - 1, true); - } - } - - /** - * Go to next month or week without using the button {@link #buttonFuture}. Should only go to - * next if {@link #canGoForward()} is enabled, meaning it's possible to go to the next month or - * week. - */ - public void goToNext() { - if (canGoForward()) { - pager.setCurrentItem(pager.getCurrentItem() + 1, true); - } - } - - /** - * Get the current selection mode. The default mode is {@linkplain #SELECTION_MODE_SINGLE} - * - * @return the current selection mode - * @see #setSelectionMode(int) - * @see #SELECTION_MODE_NONE - * @see #SELECTION_MODE_SINGLE - * @see #SELECTION_MODE_MULTIPLE - * @see #SELECTION_MODE_RANGE - */ - @SelectionMode - public int getSelectionMode() { - return selectionMode; - } - - /** - * Use {@link #getTileWidth()} or {@link #getTileHeight()} instead. This method is deprecated - * and will just return the largest of the two sizes. - * - * @return tile height or width, whichever is larger - */ - @Deprecated - public int getTileSize() { - return Math.max(tileHeight, tileWidth); - } - - /** - * Set the size of each tile that makes up the calendar. - * Each day is 1 tile, so the widget is 7 tiles wide and 7 or 8 tiles tall - * depending on the visibility of the {@link #topbar}. - * - * @param size the new size for each tile in pixels - */ - public void setTileSize(int size) { - this.tileWidth = size; - this.tileHeight = size; - requestLayout(); - } - - /** - * @param tileSizeDp the new size for each tile in dips - * @see #setTileSize(int) - */ - public void setTileSizeDp(int tileSizeDp) { - setTileSize(dpToPx(tileSizeDp)); - } - - /** - * @return the height of tiles in pixels - */ - public int getTileHeight() { - return tileHeight; - } - - /** - * Set the height of each tile that makes up the calendar. - * - * @param height the new height for each tile in pixels - */ - public void setTileHeight(int height) { - this.tileHeight = height; - requestLayout(); - } - - /** - * @param tileHeightDp the new height for each tile in dips - * @see #setTileHeight(int) - */ - public void setTileHeightDp(int tileHeightDp) { - setTileHeight(dpToPx(tileHeightDp)); - } - - /** - * @return the width of tiles in pixels - */ - public int getTileWidth() { - return tileWidth; - } - - /** - * Set the width of each tile that makes up the calendar. - * - * @param width the new width for each tile in pixels - */ - public void setTileWidth(int width) { - this.tileWidth = width; - requestLayout(); - } - - /** - * @param tileWidthDp the new width for each tile in dips - * @see #setTileWidth(int) - */ - public void setTileWidthDp(int tileWidthDp) { - setTileWidth(dpToPx(tileWidthDp)); - } - - private int dpToPx(int dp) { - return (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics() - ); - } - - /** - * Whether the pager can page forward, meaning the future month is enabled. - * - * @return true if there is a future month that can be shown - */ - public boolean canGoForward() { - return pager.getCurrentItem() < (adapter.getCount() - 1); - } - - /** - * Whether the pager can page backward, meaning the previous month is enabled. - * - * @return true if there is a previous month that can be shown - */ - public boolean canGoBack() { - return pager.getCurrentItem() > 0; - } - - /** - * Pass all touch events to the pager so scrolling works on the edges of the calendar view. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - return pager.dispatchTouchEvent(event); - } - - /** - * @return the color used for the selection - */ - public int getSelectionColor() { - return accentColor; - } - - /** - * @param color The selection color - */ - public void setSelectionColor(int color) { - if (color == 0) { - if (!isInEditMode()) { - return; - } else { - color = Color.GRAY; - } - } - accentColor = color; - adapter.setSelectionColor(color); - invalidate(); - } - - /** - * Set content description for button past - * - * @param description String to use as content description - */ - public void setContentDescriptionArrowPast(final CharSequence description) { - buttonPast.setContentDescription(description); - } - - /** - * Set content description for button future - * - * @param description String to use as content description - */ - public void setContentDescriptionArrowFuture(final CharSequence description) { - buttonFuture.setContentDescription(description); - } - - /** - * Set content description for calendar - * - * @param description String to use as content description - */ - public void setContentDescriptionCalendar(final CharSequence description) { - calendarContentDescription = description; - } - - /** - * Get content description for calendar - * - * @return calendar's content description - */ - public CharSequence getCalendarContentDescription() { - return calendarContentDescription != null - ? calendarContentDescription - : getContext().getString(R.string.calendar); - } - - /** - * Set a formatter for day content description. - * - * @param formatter the new formatter, null for default - */ - public void setDayFormatterContentDescription(DayFormatter formatter) { - adapter.setDayFormatterContentDescription(formatter); - } - - /** - * @return icon used for the left arrow - */ - public Drawable getLeftArrow() { - return buttonPast.getDrawable(); - } - - /** - * @param icon the new icon to use for the left paging arrow - */ - public void setLeftArrow(@DrawableRes final int icon) { - buttonPast.setImageResource(icon); - } - - /** - * @return icon used for the right arrow - */ - public Drawable getRightArrow() { - return buttonFuture.getDrawable(); - } - - /** - * @param icon the new icon to use for the right paging arrow - */ - public void setRightArrow(@DrawableRes final int icon) { - buttonFuture.setImageResource(icon); - } - - /** - * @param resourceId The text appearance resource id. - */ - public void setHeaderTextAppearance(int resourceId) { - title.setTextAppearance(getContext(), resourceId); - } - - /** - * @param resourceId The text appearance resource id. - */ - public void setDateTextAppearance(int resourceId) { - adapter.setDateTextAppearance(resourceId); - } - - /** - * @param resourceId The text appearance resource id. - */ - public void setWeekDayTextAppearance(int resourceId) { - adapter.setWeekDayTextAppearance(resourceId); - } - - /** - * Get the currently selected date, or null if no selection. Depending on the selection mode, - * you might get different results. - * - *

For {@link #SELECTION_MODE_SINGLE}, returns the selected date.

- *

For {@link #SELECTION_MODE_MULTIPLE}, returns the last date selected.

- *

For {@link #SELECTION_MODE_RANGE}, returns the last date of the range. In most cases, you - * should probably be using {@link #getSelectedDates()}.

- *

For {@link #SELECTION_MODE_NONE}, returns null.

- * - * @return The selected day, or null if no selection. If in multiple selection mode, this - * will return the last date of the list of selected dates. - * @see MaterialCalendarView#getSelectedDates() - */ - @Nullable public CalendarDay getSelectedDate() { - List dates = adapter.getSelectedDates(); - if (dates.isEmpty()) { - return null; - } else { - return dates.get(dates.size() - 1); - } - } - - /** - * Return the list of currently selected dates. Mostly useful for {@link #SELECTION_MODE_MULTIPLE} - * and {@link #SELECTION_MODE_RANGE}. For the other modes, check {@link #getSelectedDate()}. - * - *

For {@link #SELECTION_MODE_MULTIPLE}, returns the list in the order of selection.

- *

For {@link #SELECTION_MODE_RANGE}, returns the range of dates ordered chronologically.

- * - * @return All of the currently selected dates. - * @see MaterialCalendarView#getSelectedDate() - */ - @NonNull public List getSelectedDates() { - return adapter.getSelectedDates(); - } - - /** - * Clear the currently selected date(s) - */ - public void clearSelection() { - List dates = getSelectedDates(); - adapter.clearSelections(); - for (CalendarDay day : dates) { - dispatchOnDateSelected(day, false); - } - } - - /** - * @param date a Date set to a day to select. Null to clear selection - */ - public void setSelectedDate(@Nullable LocalDate date) { - setSelectedDate(CalendarDay.from(date)); - } - - /** - * @param date a Date to set as selected. Null to clear selection - */ - public void setSelectedDate(@Nullable CalendarDay date) { - clearSelection(); - if (date != null) { - setDateSelected(date, true); - } - } - - /** - * @param day a CalendarDay to change. Passing null does nothing - * @param selected true if day should be selected, false to deselect - */ - public void setDateSelected(@Nullable CalendarDay day, boolean selected) { - if (day == null) { - return; - } - adapter.setDateSelected(day, selected); - } - - /** - * Get the current first day of the month in month mode, or the first visible day of the - * currently visible week. - * - * For example, in week mode, if the week is July 29th, 2018 to August 4th, 2018, - * this will return July 29th, 2018. If in month mode and the month is august, then this method - * will return August 1st, 2018. - * - * @return The current month or week shown, will be set to first day of the month in month mode, - * or the first visible day for a week. - */ - public CalendarDay getCurrentDate() { - return adapter.getItem(pager.getCurrentItem()); - } - - /** - * Set the calendar to a specific month or week based on a date. - * - * In month mode, the calendar will be set to the corresponding month. - * - * In week mode, the calendar will be set to the corresponding week. - * - * @param calendar a Calendar set to a day to focus the calendar on. Null will do nothing - */ - public void setCurrentDate(@Nullable LocalDate calendar) { - setCurrentDate(CalendarDay.from(calendar)); - } - - /** - * Set the calendar to a specific month or week based on a date. - * - * In month mode, the calendar will be set to the corresponding month. - * - * In week mode, the calendar will be set to the corresponding week. - * - * @param day a CalendarDay to focus the calendar on. Null will do nothing - */ - public void setCurrentDate(@Nullable CalendarDay day) { - setCurrentDate(day, true); - } - - /** - * Set the calendar to a specific month or week based on a date. - * - * In month mode, the calendar will be set to the corresponding month. - * - * In week mode, the calendar will be set to the corresponding week. - * - * @param day a CalendarDay to focus the calendar on. Null will do nothing - * @param useSmoothScroll use smooth scroll when changing months. - */ - public void setCurrentDate(@Nullable CalendarDay day, boolean useSmoothScroll) { - if (day == null) { - return; - } - int index = adapter.getIndexForDay(day); - pager.setCurrentItem(index, useSmoothScroll); - updateUi(); - } - - /** - * @return the minimum selectable date for the calendar, if any - */ - public CalendarDay getMinimumDate() { - return minDate; - } - - /** - * @return the maximum selectable date for the calendar, if any - */ - public CalendarDay getMaximumDate() { - return maxDate; - } - - /** - * The default value is {@link #SHOW_DEFAULTS}, which currently is just {@link - * #SHOW_DECORATED_DISABLED}. - * This means that the default visible days are of the current month, in the min-max range. - * - * @param showOtherDates flags for showing non-enabled dates - * @see #SHOW_ALL - * @see #SHOW_NONE - * @see #SHOW_DEFAULTS - * @see #SHOW_OTHER_MONTHS - * @see #SHOW_OUT_OF_RANGE - * @see #SHOW_DECORATED_DISABLED - */ - public void setShowOtherDates(@ShowOtherDates int showOtherDates) { - adapter.setShowOtherDates(showOtherDates); - } - - /** - * Allow the user to click on dates from other months that are not out of range. Go to next or - * previous month if a day outside the current month is clicked. The day still need to be - * enabled to be selected. - * Default value is true. Should be used with {@link #SHOW_OTHER_MONTHS}. - * - * @param enabled True to allow the user to click on a day outside current month displayed - */ - public void setAllowClickDaysOutsideCurrentMonth(final boolean enabled) { - this.allowClickDaysOutsideCurrentMonth = enabled; - } - - /** - * Set a formatter for weekday labels. - * - * @param formatter the new formatter, null for default - */ - public void setWeekDayFormatter(WeekDayFormatter formatter) { - adapter.setWeekDayFormatter(formatter == null ? WeekDayFormatter.DEFAULT : formatter); - } - - /** - * Set a formatter for day labels. - * - * @param formatter the new formatter, null for default - */ - public void setDayFormatter(DayFormatter formatter) { - adapter.setDayFormatter(formatter == null ? DayFormatter.DEFAULT : formatter); - } - - /** - * Set a {@linkplain com.prolificinteractive.materialcalendarview.format.WeekDayFormatter} - * with the provided week day labels - * - * @param weekDayLabels Labels to use for the days of the week - * @see com.prolificinteractive.materialcalendarview.format.ArrayWeekDayFormatter - * @see #setWeekDayFormatter(com.prolificinteractive.materialcalendarview.format.WeekDayFormatter) - */ - public void setWeekDayLabels(CharSequence[] weekDayLabels) { - setWeekDayFormatter(new ArrayWeekDayFormatter(weekDayLabels)); - } - - /** - * Set a {@linkplain com.prolificinteractive.materialcalendarview.format.WeekDayFormatter} - * with the provided week day labels - * - * @param arrayRes String array resource of week day labels - * @see com.prolificinteractive.materialcalendarview.format.ArrayWeekDayFormatter - * @see #setWeekDayFormatter(com.prolificinteractive.materialcalendarview.format.WeekDayFormatter) - */ - public void setWeekDayLabels(@ArrayRes int arrayRes) { - setWeekDayLabels(getResources().getTextArray(arrayRes)); - } - - /** - * @return int of flags used for showing non-enabled dates - * @see #SHOW_ALL - * @see #SHOW_NONE - * @see #SHOW_DEFAULTS - * @see #SHOW_OTHER_MONTHS - * @see #SHOW_OUT_OF_RANGE - * @see #SHOW_DECORATED_DISABLED - */ - @ShowOtherDates - public int getShowOtherDates() { - return adapter.getShowOtherDates(); - } - - /** - * @return true if allow click on days outside current month displayed - */ - public boolean allowClickDaysOutsideCurrentMonth() { - return allowClickDaysOutsideCurrentMonth; - } - - /** - * @return true if the week days names are shown - */ - public boolean isShowWeekDays() { - return showWeekDays; - } - - /** - * Set a custom formatter for the month/year title - * - * @param titleFormatter new formatter to use, null to use default formatter - */ - public void setTitleFormatter(@Nullable TitleFormatter titleFormatter) { - titleChanger.setTitleFormatter(titleFormatter); - adapter.setTitleFormatter(titleFormatter); - updateUi(); - } - - /** - * Set a {@linkplain com.prolificinteractive.materialcalendarview.format.TitleFormatter} - * using the provided month labels - * - * @param monthLabels month labels to use - * @see com.prolificinteractive.materialcalendarview.format.MonthArrayTitleFormatter - * @see #setTitleFormatter(com.prolificinteractive.materialcalendarview.format.TitleFormatter) - */ - public void setTitleMonths(CharSequence[] monthLabels) { - setTitleFormatter(new MonthArrayTitleFormatter(monthLabels)); - } - - /** - * Set a {@linkplain com.prolificinteractive.materialcalendarview.format.TitleFormatter} - * using the provided month labels - * - * @param arrayRes String array resource of month labels to use - * @see com.prolificinteractive.materialcalendarview.format.MonthArrayTitleFormatter - * @see #setTitleFormatter(com.prolificinteractive.materialcalendarview.format.TitleFormatter) - */ - public void setTitleMonths(@ArrayRes int arrayRes) { - setTitleMonths(getResources().getTextArray(arrayRes)); - } - - /** - * Change the title animation orientation to have a different look and feel. - * - * @param orientation {@link MaterialCalendarView#VERTICAL} or {@link - * MaterialCalendarView#HORIZONTAL} - */ - public void setTitleAnimationOrientation(final int orientation) { - titleChanger.setOrientation(orientation); - } - - /** - * Get the orientation of the animation of the title. - * - * @return Title animation orientation {@link MaterialCalendarView#VERTICAL} or {@link - * MaterialCalendarView#HORIZONTAL} - */ - public int getTitleAnimationOrientation() { - return titleChanger.getOrientation(); - } - - /** - * Sets the visibility {@link #topbar}, which contains - * the previous month button {@link #buttonPast}, next month button {@link #buttonFuture}, - * and the month title {@link #title}. - * - * @param visible Boolean indicating if the topbar is visible - */ - public void setTopbarVisible(boolean visible) { - topbar.setVisibility(visible ? View.VISIBLE : View.GONE); - requestLayout(); - } - - /** - * @return true if the topbar is visible - */ - public boolean getTopbarVisible() { - return topbar.getVisibility() == View.VISIBLE; - } - - /** - * Get the current {@link CalendarMode} set of the Calendar. - * - * @return Whichever mode the calendar is currently in. - */ - public CalendarMode getCalendarMode() { - return calendarMode; - } - - @Override - protected Parcelable onSaveInstanceState() { - SavedState ss = new SavedState(super.onSaveInstanceState()); - ss.showOtherDates = getShowOtherDates(); - ss.allowClickDaysOutsideCurrentMonth = allowClickDaysOutsideCurrentMonth(); - ss.minDate = getMinimumDate(); - ss.maxDate = getMaximumDate(); - ss.selectedDates = getSelectedDates(); - ss.selectionMode = getSelectionMode(); - ss.topbarVisible = getTopbarVisible(); - ss.dynamicHeightEnabled = mDynamicHeightEnabled; - ss.currentMonth = currentMonth; - ss.cacheCurrentPosition = state.cacheCurrentPosition; - return ss; - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - SavedState ss = (SavedState) state; - super.onRestoreInstanceState(ss.getSuperState()); - state().edit() - .setMinimumDate(ss.minDate) - .setMaximumDate(ss.maxDate) - .isCacheCalendarPositionEnabled(ss.cacheCurrentPosition) - .commit(); - - setShowOtherDates(ss.showOtherDates); - setAllowClickDaysOutsideCurrentMonth(ss.allowClickDaysOutsideCurrentMonth); - clearSelection(); - for (CalendarDay calendarDay : ss.selectedDates) { - setDateSelected(calendarDay, true); - } - setTopbarVisible(ss.topbarVisible); - setSelectionMode(ss.selectionMode); - setDynamicHeightEnabled(ss.dynamicHeightEnabled); - setCurrentDate(ss.currentMonth); - } - - @Override - protected void dispatchSaveInstanceState(@NonNull SparseArray container) { - dispatchFreezeSelfOnly(container); - } - - @Override - protected void dispatchRestoreInstanceState(@NonNull SparseArray container) { - dispatchThawSelfOnly(container); - } - - private void setRangeDates(CalendarDay min, CalendarDay max) { - CalendarDay c = currentMonth; - adapter.setRangeDates(min, max); - currentMonth = c; - if (min != null) { - currentMonth = min.isAfter(currentMonth) ? min : currentMonth; - } - int position = adapter.getIndexForDay(c); - pager.setCurrentItem(position, false); - updateUi(); - } - - public static class SavedState extends BaseSavedState { - - int showOtherDates = SHOW_DEFAULTS; - boolean allowClickDaysOutsideCurrentMonth = true; - CalendarDay minDate = null; - CalendarDay maxDate = null; - List selectedDates = new ArrayList<>(); - boolean topbarVisible = true; - int selectionMode = SELECTION_MODE_SINGLE; - boolean dynamicHeightEnabled = false; - CalendarDay currentMonth = null; - boolean cacheCurrentPosition; - - SavedState(Parcelable superState) { - super(superState); + + adapter.setSelectionEnabled(selectionMode != SELECTION_MODE_NONE); + } + + /** + * Use {@link #getTileWidth()} or {@link #getTileHeight()} instead. This method is deprecated + * and will just return the largest of the two sizes. + * + * @return tile height or width, whichever is larger + */ + @Deprecated + public int getTileSize() { + return Math.max(tileHeight, tileWidth); + } + + /** + * Set the size of each tile that makes up the calendar. + * Each day is 1 tile, so the widget is 7 tiles wide and 7 or 8 tiles tall + * depending on the visibility of the {@link #topbar}. + * + * @param size the new size for each tile in pixels + */ + public void setTileSize(int size) { + this.tileWidth = size; + this.tileHeight = size; + requestLayout(); + } + + /** + * @param tileSizeDp the new size for each tile in dips + * @see #setTileSize(int) + */ + public void setTileSizeDp(int tileSizeDp) { + setTileSize(dpToPx(tileSizeDp)); + } + + /** + * @return the height of tiles in pixels + */ + public int getTileHeight() { + return tileHeight; + } + + /** + * Set the height of each tile that makes up the calendar. + * + * @param height the new height for each tile in pixels + */ + public void setTileHeight(int height) { + this.tileHeight = height; + requestLayout(); + } + + /** + * @param tileHeightDp the new height for each tile in dips + * @see #setTileHeight(int) + */ + public void setTileHeightDp(int tileHeightDp) { + setTileHeight(dpToPx(tileHeightDp)); + } + + /** + * @return the width of tiles in pixels + */ + public int getTileWidth() { + return tileWidth; + } + + /** + * Set the width of each tile that makes up the calendar. + * + * @param width the new width for each tile in pixels + */ + public void setTileWidth(int width) { + this.tileWidth = width; + requestLayout(); + } + + /** + * @param tileWidthDp the new width for each tile in dips + * @see #setTileWidth(int) + */ + public void setTileWidthDp(int tileWidthDp) { + setTileWidth(dpToPx(tileWidthDp)); + } + + private int dpToPx(int dp) { + return (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics() + ); + } + + /** + * Whether the pager can page forward, meaning the future month is enabled. + * + * @return true if there is a future month that can be shown + */ + public boolean canGoForward() { + return pager.getCurrentItem() < (adapter.getCount() - 1); + } + + /** + * Whether the pager can page backward, meaning the previous month is enabled. + * + * @return true if there is a previous month that can be shown + */ + public boolean canGoBack() { + return pager.getCurrentItem() > 0; } + /** + * Pass all touch events to the pager so scrolling works on the edges of the calendar view. + */ @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeInt(showOtherDates); - out.writeByte((byte) (allowClickDaysOutsideCurrentMonth ? 1 : 0)); - out.writeParcelable(minDate, 0); - out.writeParcelable(maxDate, 0); - out.writeTypedList(selectedDates); - out.writeInt(topbarVisible ? 1 : 0); - out.writeInt(selectionMode); - out.writeInt(dynamicHeightEnabled ? 1 : 0); - out.writeParcelable(currentMonth, 0); - out.writeByte((byte) (cacheCurrentPosition ? 1 : 0)); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; + public boolean onTouchEvent(MotionEvent event) { + return pager.dispatchTouchEvent(event); + } - private SavedState(Parcel in) { - super(in); - showOtherDates = in.readInt(); - allowClickDaysOutsideCurrentMonth = in.readByte() != 0; - ClassLoader loader = CalendarDay.class.getClassLoader(); - minDate = in.readParcelable(loader); - maxDate = in.readParcelable(loader); - in.readTypedList(selectedDates, CalendarDay.CREATOR); - topbarVisible = in.readInt() == 1; - selectionMode = in.readInt(); - dynamicHeightEnabled = in.readInt() == 1; - currentMonth = in.readParcelable(loader); - cacheCurrentPosition = in.readByte() != 0; - } - } - - private static int getThemeAccentColor(Context context) { - int colorAttr; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - colorAttr = android.R.attr.colorAccent; - } else { - //Get colorAccent defined for AppCompat - colorAttr = - context.getResources().getIdentifier("colorAccent", "attr", context.getPackageName()); - } - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(colorAttr, outValue, true); - return outValue.data; - } - - /** - * @return The first day of the week as a {@linkplain Calendar} day constant. - */ - public DayOfWeek getFirstDayOfWeek() { - return firstDayOfWeek; - } - - /** - * By default, the calendar will take up all the space needed to show any month (6 rows). - * By enabling dynamic height, the view will change height dependant on the visible month. - *

- * This means months that only need 5 or 4 rows to show the entire month will only take up - * that many rows, and will grow and shrink as necessary. - * - * @param useDynamicHeight true to have the view different heights based on the visible month - */ - public void setDynamicHeightEnabled(boolean useDynamicHeight) { - this.mDynamicHeightEnabled = useDynamicHeight; - } - - /** - * @return the dynamic height state - true if enabled. - */ - public boolean isDynamicHeightEnabled() { - return mDynamicHeightEnabled; - } - - /** - * Add a collection of day decorators - * - * @param decorators decorators to add - */ - public void addDecorators(Collection decorators) { - if (decorators == null) { - return; - } - - dayViewDecorators.addAll(decorators); - adapter.setDecorators(dayViewDecorators); - } - - /** - * Add several day decorators - * - * @param decorators decorators to add - */ - public void addDecorators(DayViewDecorator... decorators) { - addDecorators(Arrays.asList(decorators)); - } - - /** - * Add a day decorator - * - * @param decorator decorator to add - */ - public void addDecorator(DayViewDecorator decorator) { - if (decorator == null) { - return; - } - dayViewDecorators.add(decorator); - adapter.setDecorators(dayViewDecorators); - } - - /** - * Remove all decorators - */ - public void removeDecorators() { - dayViewDecorators.clear(); - adapter.setDecorators(dayViewDecorators); - } - - /** - * Remove a specific decorator instance. Same rules as {@linkplain List#remove(Object)} - * - * @param decorator decorator to remove - */ - public void removeDecorator(DayViewDecorator decorator) { - dayViewDecorators.remove(decorator); - adapter.setDecorators(dayViewDecorators); - } - - /** - * Invalidate decorators after one has changed internally. That is, if a decorator mutates, you - * should call this method to update the widget. - */ - public void invalidateDecorators() { - adapter.invalidateDecorators(); - } - - /* - * Listener/Callback Code - */ - - /** - * Sets the listener to be notified upon selected date changes. - * - * @param listener thing to be notified - */ - public void setOnDateChangedListener(OnDateSelectedListener listener) { - this.listener = listener; - } - - /** - * Sets the listener to be notified upon long clicks on dates. - * - * @param longClickListener thing to be notified - */ - public void setOnDateLongClickListener(OnDateLongClickListener longClickListener) { - this.longClickListener = longClickListener; - } - - /** - * Sets the listener to be notified upon month changes. - * - * @param listener thing to be notified - */ - public void setOnMonthChangedListener(OnMonthChangedListener listener) { - this.monthListener = listener; - } - - /** - * Sets the listener to be notified upon a range has been selected. - * - * @param listener thing to be notified - */ - public void setOnRangeSelectedListener(OnRangeSelectedListener listener) { - this.rangeListener = listener; - } - - /** - * Add listener to the title or null to remove it. - * - * @param listener Listener to be notified. - */ - public void setOnTitleClickListener(final OnClickListener listener) { - title.setOnClickListener(listener); - } - - /** - * Dispatch date change events to a listener, if set - * - * @param day the day that was selected - * @param selected true if the day is now currently selected, false otherwise - */ - protected void dispatchOnDateSelected(final CalendarDay day, final boolean selected) { - if (listener != null) { - listener.onDateSelected(MaterialCalendarView.this, day, selected); - } - } - - /** - * Dispatch a range of days to a range listener, if set, ordered chronologically. - * - * @param days Enclosing days ordered from first to last day. - */ - protected void dispatchOnRangeSelected(@NonNull final List days) { - if (rangeListener != null) { - rangeListener.onRangeSelected(MaterialCalendarView.this, days); - } - } - - /** - * Dispatch date change events to a listener, if set - * - * @param day first day of the new month - */ - protected void dispatchOnMonthChanged(final CalendarDay day) { - if (monthListener != null) { - monthListener.onMonthChanged(MaterialCalendarView.this, day); - } - } - - /** - * Call by {@link CalendarPagerView} to indicate that a day was clicked and we should handle it. - * This method will always process the click to the selected date. - * - * @param date date of the day that was clicked - * @param nowSelected true if the date is now selected, false otherwise - */ - protected void onDateClicked(@NonNull CalendarDay date, boolean nowSelected) { - switch (selectionMode) { - case SELECTION_MODE_MULTIPLE: { - adapter.setDateSelected(date, nowSelected); - dispatchOnDateSelected(date, nowSelected); - } - break; - case SELECTION_MODE_RANGE: { - final List currentSelection = adapter.getSelectedDates(); - - if (currentSelection.size() == 0) { - // Selecting the first date of a range - adapter.setDateSelected(date, nowSelected); - dispatchOnDateSelected(date, nowSelected); - } else if (currentSelection.size() == 1) { - // Selecting the second date of a range - final CalendarDay firstDaySelected = currentSelection.get(0); - if (firstDaySelected.equals(date)) { - // Right now, we are not supporting a range of one day, so we are removing the day instead. - adapter.setDateSelected(date, nowSelected); - dispatchOnDateSelected(date, nowSelected); - } else if (firstDaySelected.isAfter(date)) { - // Selecting a range, dispatching in reverse order... - adapter.selectRange(date, firstDaySelected); - dispatchOnRangeSelected(adapter.getSelectedDates()); - } else { - // Selecting a range, dispatching in order... - adapter.selectRange(firstDaySelected, date); - dispatchOnRangeSelected(adapter.getSelectedDates()); - } - } else { - // Clearing selection and making a selection of the new date. - adapter.clearSelections(); - adapter.setDateSelected(date, nowSelected); - dispatchOnDateSelected(date, nowSelected); + /** + * @return the color used for the selection + */ + public int getSelectionColor() { + return accentColor; + } + + /** + * @param color The selection color + */ + public void setSelectionColor(int color) { + if (color == 0) { + if (!isInEditMode()) { + return; + } else { + color = Color.GRAY; + } } - } - break; - default: - case SELECTION_MODE_SINGLE: { - adapter.clearSelections(); - adapter.setDateSelected(date, true); - dispatchOnDateSelected(date, true); - } - break; - } - } - - /** - * Select a fresh range of date including first day and last day. - * - * @param firstDay first day of the range to select - * @param lastDay last day of the range to select - */ - public void selectRange(final CalendarDay firstDay, final CalendarDay lastDay) { - if (firstDay == null || lastDay == null) { - return; - } else if (firstDay.isAfter(lastDay)) { - adapter.selectRange(lastDay, firstDay); - dispatchOnRangeSelected(adapter.getSelectedDates()); - } else { - adapter.selectRange(firstDay, lastDay); - dispatchOnRangeSelected(adapter.getSelectedDates()); - } - } - - /** - * Call by {@link CalendarPagerView} to indicate that a day was clicked and we should handle it - */ - protected void onDateClicked(final DayView dayView) { - final CalendarDay currentDate = getCurrentDate(); - final CalendarDay selectedDate = dayView.getDate(); - final int currentMonth = currentDate.getMonth(); - final int selectedMonth = selectedDate.getMonth(); - - if (calendarMode == CalendarMode.MONTHS - && allowClickDaysOutsideCurrentMonth - && currentMonth != selectedMonth) { - if (currentDate.isAfter(selectedDate)) { - goToPrevious(); - } else if (currentDate.isBefore(selectedDate)) { - goToNext(); - } - } - onDateClicked(dayView.getDate(), !dayView.isChecked()); - } - - /** - * Call by {@link CalendarPagerView} to indicate that a day was long clicked and we should handle - * it - */ - protected void onDateLongClicked(final DayView dayView) { - if (longClickListener != null) { - longClickListener.onDateLongClick(MaterialCalendarView.this, dayView.getDate()); - } - } - - /** - * Called by the adapter for cases when changes in state result in dates being unselected - * - * @param date date that should be de-selected - */ - protected void onDateUnselected(CalendarDay date) { - dispatchOnDateSelected(date, false); - } - - /* - * Show Other Dates Utils - */ - - /** - * @param showOtherDates int flag for show other dates - * @return true if the other months flag is set - */ - public static boolean showOtherMonths(@ShowOtherDates int showOtherDates) { - return (showOtherDates & SHOW_OTHER_MONTHS) != 0; - } - - /** - * @param showOtherDates int flag for show other dates - * @return true if the out of range flag is set - */ - public static boolean showOutOfRange(@ShowOtherDates int showOtherDates) { - return (showOtherDates & SHOW_OUT_OF_RANGE) != 0; - } - - /** - * @param showOtherDates int flag for show other dates - * @return true if the decorated disabled flag is set - */ - public static boolean showDecoratedDisabled(@ShowOtherDates int showOtherDates) { - return (showOtherDates & SHOW_DECORATED_DISABLED) != 0; - } - - /* - * Custom ViewGroup Code - */ - - /** - * {@inheritDoc} - */ - @Override - protected LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(1); - } - - /** - * {@inheritDoc} - */ - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - final int specWidthSize = MeasureSpec.getSize(widthMeasureSpec); - final int specWidthMode = MeasureSpec.getMode(widthMeasureSpec); - final int specHeightSize = MeasureSpec.getSize(heightMeasureSpec); - final int specHeightMode = MeasureSpec.getMode(heightMeasureSpec); - - //We need to disregard padding for a while. This will be added back later - final int desiredWidth = specWidthSize - getPaddingLeft() - getPaddingRight(); - final int desiredHeight = specHeightSize - getPaddingTop() - getPaddingBottom(); - - final int weekCount = getWeekCountBasedOnMode(); - - final int viewTileHeight = getTopbarVisible() ? (weekCount + 1) : weekCount; - - //Calculate independent tile sizes for later - int desiredTileWidth = desiredWidth / DEFAULT_DAYS_IN_WEEK; - int desiredTileHeight = desiredHeight / viewTileHeight; - - int measureTileSize = -1; - int measureTileWidth = -1; - int measureTileHeight = -1; - - if (this.tileWidth != INVALID_TILE_DIMENSION || this.tileHeight != INVALID_TILE_DIMENSION) { - if (this.tileWidth > 0) { - //We have a tileWidth set, we should use that - measureTileWidth = this.tileWidth; - } else { - measureTileWidth = desiredTileWidth; - } - if (this.tileHeight > 0) { - //We have a tileHeight set, we should use that - measureTileHeight = this.tileHeight; - } else { - measureTileHeight = desiredTileHeight; - } - } else if (specWidthMode == MeasureSpec.EXACTLY || specWidthMode == MeasureSpec.AT_MOST) { - if (specHeightMode == MeasureSpec.EXACTLY) { - //Pick the smaller of the two explicit sizes - measureTileSize = Math.min(desiredTileWidth, desiredTileHeight); - } else { - //Be the width size the user wants - measureTileSize = desiredTileWidth; - } - } else if (specHeightMode == MeasureSpec.EXACTLY || specHeightMode == MeasureSpec.AT_MOST) { - //Be the height size the user wants - measureTileSize = desiredTileHeight; - } - - if (measureTileSize > 0) { - //Use measureTileSize if set - measureTileHeight = measureTileSize; - measureTileWidth = measureTileSize; - } else if (measureTileSize <= 0) { - if (measureTileWidth <= 0) { - //Set width to default if no value were set - measureTileWidth = dpToPx(DEFAULT_TILE_SIZE_DP); - } - if (measureTileHeight <= 0) { - //Set height to default if no value were set - measureTileHeight = dpToPx(DEFAULT_TILE_SIZE_DP); - } - } - - //Calculate our size based off our measured tile size - int measuredWidth = measureTileWidth * DEFAULT_DAYS_IN_WEEK; - int measuredHeight = measureTileHeight * viewTileHeight; - - //Put padding back in from when we took it away - measuredWidth += getPaddingLeft() + getPaddingRight(); - measuredHeight += getPaddingTop() + getPaddingBottom(); - - //Contract fulfilled, setting out measurements - setMeasuredDimension( - //We clamp inline because we want to use un-clamped versions on the children - clampSize(measuredWidth, widthMeasureSpec), - clampSize(measuredHeight, heightMeasureSpec) - ); - - int count = getChildCount(); - - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - - LayoutParams p = (LayoutParams) child.getLayoutParams(); - - int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( - DEFAULT_DAYS_IN_WEEK * measureTileWidth, - MeasureSpec.EXACTLY - ); - - int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( - p.height * measureTileHeight, - MeasureSpec.EXACTLY - ); - - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - } - } - - private int getWeekCountBasedOnMode() { - int weekCount = calendarMode.visibleWeeksCount; - final boolean isInMonthsMode = calendarMode.equals(CalendarMode.MONTHS); - if (isInMonthsMode && mDynamicHeightEnabled && adapter != null && pager != null) { - final LocalDate cal = adapter.getItem(pager.getCurrentItem()).getDate(); - final LocalDate tempLastDay = cal.withDayOfMonth(cal.lengthOfMonth()); - weekCount = tempLastDay.get(WeekFields.of(firstDayOfWeek, 1).weekOfMonth()); - } - return showWeekDays ? weekCount + DAY_NAMES_ROW : weekCount; - } - - /** - * Clamp the size to the measure spec. - * - * @param size Size we want to be - * @param spec Measure spec to clamp against - * @return the appropriate size to pass to {@linkplain View#setMeasuredDimension(int, int)} - */ - private static int clampSize(int size, int spec) { - int specMode = MeasureSpec.getMode(spec); - int specSize = MeasureSpec.getSize(spec); - switch (specMode) { - case MeasureSpec.EXACTLY: { - return specSize; - } - case MeasureSpec.AT_MOST: { - return Math.min(size, specSize); - } - case MeasureSpec.UNSPECIFIED: - default: { - return size; - } - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - final int count = getChildCount(); - - final int parentLeft = getPaddingLeft(); - final int parentWidth = right - left - parentLeft - getPaddingRight(); - - int childTop = getPaddingTop(); - - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == View.GONE) { - continue; - } - - final int width = child.getMeasuredWidth(); - final int height = child.getMeasuredHeight(); - - int delta = (parentWidth - width) / 2; - int childLeft = parentLeft + delta; - - child.layout(childLeft, childTop, childLeft + width, childTop + height); - - childTop += height; - } - } - - /** - * {@inheritDoc} - */ - @Override - public LayoutParams generateLayoutParams(AttributeSet attrs) { - return new LayoutParams(1); - } - - @Override - public boolean shouldDelayChildPressedState() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams; - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return new LayoutParams(1); - } - - @Override - public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); - event.setClassName(MaterialCalendarView.class.getName()); - } - - @Override - public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); - info.setClassName(MaterialCalendarView.class.getName()); - } - - /** - * Simple layout params for MaterialCalendarView. The only variation for layout is height. - */ - protected static class LayoutParams extends MarginLayoutParams { - - /** - * Create a layout that matches parent width, and is X number of tiles high + accentColor = color; + adapter.setSelectionColor(color); + invalidate(); + } + + /** + * Set content description for button past * - * @param tileHeight view height in number of tiles - */ - public LayoutParams(int tileHeight) { - super(MATCH_PARENT, tileHeight); - } - } - - /** - * Enable or disable the ability to swipe between months. - * - * @param pagingEnabled pass false to disable paging, true to enable (default) - */ - public void setPagingEnabled(boolean pagingEnabled) { - pager.setPagingEnabled(pagingEnabled); - updateUi(); - } - - /** - * @return true if swiping months is enabled, false if disabled. Default is true. - */ - public boolean isPagingEnabled() { - return pager.isPagingEnabled(); - } - - /** - * Preserve the current parameters of the Material Calendar View. - */ - public State state() { - return state; - } - - /** - * Initialize the parameters from scratch. - */ - public StateBuilder newState() { - return new StateBuilder(); - } - - public class State { - private final CalendarMode calendarMode; - private final DayOfWeek firstDayOfWeek; - private final CalendarDay minDate; - private final CalendarDay maxDate; - private final boolean cacheCurrentPosition; - private final boolean showWeekDays; - - private State(final StateBuilder builder) { - calendarMode = builder.calendarMode; - firstDayOfWeek = builder.firstDayOfWeek; - minDate = builder.minDate; - maxDate = builder.maxDate; - cacheCurrentPosition = builder.cacheCurrentPosition; - showWeekDays = builder.showWeekDays; - } - - /** - * Modify parameters from current state. - */ - public StateBuilder edit() { - return new StateBuilder(this); - } - } - - public class StateBuilder { - private CalendarMode calendarMode; - private DayOfWeek firstDayOfWeek; - private boolean cacheCurrentPosition = false; - private CalendarDay minDate = null; - private CalendarDay maxDate = null; - private boolean showWeekDays; + * @param description String to use as content description + */ + public void setContentDescriptionArrowPast(final CharSequence description) { + backArrowButton.setContentDescription(description); + } - public StateBuilder() { - calendarMode = CalendarMode.MONTHS; - firstDayOfWeek = - LocalDate.now().with(WeekFields.of(Locale.getDefault()).dayOfWeek(), 1).getDayOfWeek(); + /** + * Set content description for button future + * + * @param description String to use as content description + */ + public void setContentDescriptionArrowFuture(final CharSequence description) { + ForwardArrowButton.setContentDescription(description); } - private StateBuilder(final State state) { - calendarMode = state.calendarMode; - firstDayOfWeek = state.firstDayOfWeek; - minDate = state.minDate; - maxDate = state.maxDate; - cacheCurrentPosition = state.cacheCurrentPosition; - showWeekDays = state.showWeekDays; + /** + * Set content description for calendar + * + * @param description String to use as content description + */ + public void setContentDescriptionCalendar(final CharSequence description) { + calendarContentDescription = description; } /** - * Sets the first day of the week. - *

- * Uses the {@link DayOfWeek} day constants. + * Get content description for calendar * - * @param day The first day of the week as a {@link DayOfWeek} enum. - * @see java.util.Calendar + * @return calendar's content description */ - public StateBuilder setFirstDayOfWeek(DayOfWeek day) { - this.firstDayOfWeek = day; - return this; + public CharSequence getCalendarContentDescription() { + return calendarContentDescription != null + ? calendarContentDescription + : getContext().getString(R.string.calendar); } /** - * Set calendar display mode. The default mode is Months. - * When switching between modes will select todays date, or the selected date, - * if selection mode is single. + * Set a formatter for day content description. * - * @param mode - calendar mode + * @param formatter the new formatter, null for default */ - public StateBuilder setCalendarDisplayMode(CalendarMode mode) { - this.calendarMode = mode; - return this; + public void setDayFormatterContentDescription(DayFormatter formatter) { + adapter.setDayFormatterContentDescription(formatter); } /** - * @param date set the minimum selectable date, null for no minimum + * @return icon used for the left arrow */ - public StateBuilder setMinimumDate(@Nullable LocalDate date) { - setMinimumDate(CalendarDay.from(date)); - return this; + public Drawable getLeftArrow() { + return backArrowButton.getDrawable(); } /** - * @param calendar set the minimum selectable date, null for no minimum + * @param icon the new icon to use for the left paging arrow */ - public StateBuilder setMinimumDate(@Nullable CalendarDay calendar) { - minDate = calendar; - return this; + public void setLeftArrow(@DrawableRes final int icon) { + backArrowButton.setImageResource(icon); } /** - * @param date set the maximum selectable date, null for no maximum + * @return icon used for the right arrow */ - public StateBuilder setMaximumDate(@Nullable LocalDate date) { - setMaximumDate(CalendarDay.from(date)); - return this; + public Drawable getRightArrow() { + return ForwardArrowButton.getDrawable(); } /** - * @param calendar set the maximum selectable date, null for no maximum + * @param icon the new icon to use for the right paging arrow */ - public StateBuilder setMaximumDate(@Nullable CalendarDay calendar) { - maxDate = calendar; - return this; + public void setRightArrow(@DrawableRes final int icon) { + ForwardArrowButton.setImageResource(icon); } /** - * @param showWeekDays true to show week days names + * @param resourceId The text appearance resource id. */ - public StateBuilder setShowWeekDays(boolean showWeekDays) { - this.showWeekDays = showWeekDays; - return this; + public void setHeaderTextAppearance(int resourceId) { + title.setTextAppearance(getContext(), resourceId); } /** - * Use this method to enable saving the current position when switching - * between week and month mode. By default, the calendar update to the latest selected date - * or the current date. When set to true, the view will used the month that the calendar is - * currently on. + * @param resourceId The text appearance resource id. + */ + public void setDateTextAppearance(int resourceId) { + adapter.setDateTextAppearance(resourceId); + } + + /** + * @param resourceId The text appearance resource id. + */ + public void setWeekDayTextAppearance(int resourceId) { + adapter.setWeekDayTextAppearance(resourceId); + } + + /** + * Get the currently selected date, or null if no selection. Depending on the selection mode, + * you might get different results. + * + *

For {@link #SELECTION_MODE_SINGLE}, returns the selected date.

+ *

For {@link #SELECTION_MODE_MULTIPLE}, returns the last date selected.

+ *

For {@link #SELECTION_MODE_RANGE}, returns the last date of the range. In most cases, you + * should probably be using {@link #getSelectedDates()}.

+ *

For {@link #SELECTION_MODE_NONE}, returns null.

+ * + * @return The selected day, or null if no selection. If in multiple selection mode, this + * will return the last date of the list of selected dates. + * @see MaterialCalendarView#getSelectedDates() + */ + @Nullable + public CalendarDay getSelectedDate() { + List dates = adapter.getSelectedDates(); + if (dates.isEmpty()) { + return null; + } else { + return dates.get(dates.size() - 1); + } + } + + /** + * @param date a Date set to a day to select. Null to clear selection + */ + public void setSelectedDate(@Nullable LocalDate date) { + setSelectedDate(CalendarDay.from(date)); + } + + /** + * @param date a Date to set as selected. Null to clear selection + */ + public void setSelectedDate(@Nullable CalendarDay date) { + clearSelection(); + if (date != null) { + setDateSelected(date, true); + } + } + + /** + * Return the list of currently selected dates. Mostly useful for {@link #SELECTION_MODE_MULTIPLE} + * and {@link #SELECTION_MODE_RANGE}. For the other modes, check {@link #getSelectedDate()}. * - * @param cacheCurrentPosition Set to true to cache the current position, false otherwise. - */ - public StateBuilder isCacheCalendarPositionEnabled(final boolean cacheCurrentPosition) { - this.cacheCurrentPosition = cacheCurrentPosition; - return this; - } - - public void commit() { - MaterialCalendarView.this.commit(new State(this)); - } - } - - private void commit(State state) { - // Use the calendarDayToShow to determine which date to focus on for the case of switching between month and week views - CalendarDay calendarDayToShow = null; - if (adapter != null && state.cacheCurrentPosition) { - calendarDayToShow = adapter.getItem(pager.getCurrentItem()); - if (calendarMode != state.calendarMode) { - CalendarDay currentlySelectedDate = getSelectedDate(); - if (calendarMode == CalendarMode.MONTHS && currentlySelectedDate != null) { - // Going from months to weeks - LocalDate lastVisibleCalendar = calendarDayToShow.getDate(); - CalendarDay lastVisibleCalendarDay = CalendarDay.from(lastVisibleCalendar.plusDays(1)); - if (currentlySelectedDate.equals(calendarDayToShow) || - (currentlySelectedDate.isAfter(calendarDayToShow) && currentlySelectedDate.isBefore( - lastVisibleCalendarDay))) { - // Currently selected date is within view, so center on that - calendarDayToShow = currentlySelectedDate; - } - } else if (calendarMode == CalendarMode.WEEKS) { - // Going from weeks to months - LocalDate lastVisibleCalendar = calendarDayToShow.getDate(); - CalendarDay lastVisibleCalendarDay = CalendarDay.from(lastVisibleCalendar.plusDays(6)); - if (currentlySelectedDate != null && - (currentlySelectedDate.equals(calendarDayToShow) || currentlySelectedDate.equals( - lastVisibleCalendarDay) || - (currentlySelectedDate.isAfter(calendarDayToShow) - && currentlySelectedDate.isBefore(lastVisibleCalendarDay)))) { - // Currently selected date is within view, so center on that - calendarDayToShow = currentlySelectedDate; - } else { - calendarDayToShow = lastVisibleCalendarDay; - } + *

For {@link #SELECTION_MODE_MULTIPLE}, returns the list in the order of selection.

+ *

For {@link #SELECTION_MODE_RANGE}, returns the range of dates ordered chronologically.

+ * + * @return All of the currently selected dates. + * @see MaterialCalendarView#getSelectedDate() + */ + @NonNull + public List getSelectedDates() { + return adapter.getSelectedDates(); + } + + /** + * Clear the currently selected date(s) + */ + public void clearSelection() { + List dates = getSelectedDates(); + adapter.clearSelections(); + for (CalendarDay day : dates) { + dispatchOnDateSelected(day, false); + } + } + + /** + * @param day a CalendarDay to change. Passing null does nothing + * @param selected true if day should be selected, false to deselect + */ + public void setDateSelected(@Nullable CalendarDay day, boolean selected) { + if (day == null) { + return; } - } - } - - this.state = state; - // Save states parameters - calendarMode = state.calendarMode; - firstDayOfWeek = state.firstDayOfWeek; - minDate = state.minDate; - maxDate = state.maxDate; - showWeekDays = state.showWeekDays; - - // Recreate adapter - final CalendarPagerAdapter newAdapter; - switch (calendarMode) { - case MONTHS: - newAdapter = new MonthPagerAdapter(this); - break; - case WEEKS: - newAdapter = new WeekPagerAdapter(this); - break; - default: - throw new IllegalArgumentException("Provided display mode which is not yet implemented"); - } - if (adapter == null) { - adapter = newAdapter; - } else { - adapter = adapter.migrateStateAndReturn(newAdapter); - } - adapter.setShowWeekDays(showWeekDays); - pager.setAdapter(adapter); - setRangeDates(minDate, maxDate); - - // Reset height params after mode change - int tileHeight = showWeekDays ? calendarMode.visibleWeeksCount + DAY_NAMES_ROW - : calendarMode.visibleWeeksCount; - pager.setLayoutParams(new LayoutParams(tileHeight)); - - setCurrentDate( - selectionMode == SELECTION_MODE_SINGLE && !adapter.getSelectedDates().isEmpty() - ? adapter.getSelectedDates().get(0) - : CalendarDay.today()); - - if (calendarDayToShow != null) { - pager.setCurrentItem(adapter.getIndexForDay(calendarDayToShow)); - } - - invalidateDecorators(); - updateUi(); - } - - /** - * Used for enabling or disabling views, while also changing the alpha. - * - * @param view The view to enable or disable. - * @param enable Whether to enable or disable the view. - */ - private static void enableView(final View view, final boolean enable) { - view.setEnabled(enable); - view.setAlpha(enable ? 1f : 0.1f); - } + adapter.setDateSelected(day, selected); + } + + /** + * Get the current first day of the month in month mode, or the first visible day of the + * currently visible week. + *

+ * For example, in week mode, if the week is July 29th, 2018 to August 4th, 2018, + * this will return July 29th, 2018. If in month mode and the month is august, then this method + * will return August 1st, 2018. + * + * @return The current month or week shown, will be set to first day of the month in month mode, + * or the first visible day for a week. + */ + public CalendarDay getCurrentDate() { + return adapter.getItem(pager.getCurrentItem()); + } + + /** + * Set the calendar to a specific month or week based on a date. + *

+ * In month mode, the calendar will be set to the corresponding month. + *

+ * In week mode, the calendar will be set to the corresponding week. + * + * @param calendar a Calendar set to a day to focus the calendar on. Null will do nothing + */ + public void setCurrentDate(@Nullable LocalDate calendar) { + setCurrentDate(CalendarDay.from(calendar)); + } + + /** + * Set the calendar to a specific month or week based on a date. + *

+ * In month mode, the calendar will be set to the corresponding month. + *

+ * In week mode, the calendar will be set to the corresponding week. + * + * @param day a CalendarDay to focus the calendar on. Null will do nothing + */ + public void setCurrentDate(@Nullable CalendarDay day) { + setCurrentDate(day, true); + } + + /** + * Set the calendar to a specific month or week based on a date. + *

+ * In month mode, the calendar will be set to the corresponding month. + *

+ * In week mode, the calendar will be set to the corresponding week. + * + * @param day a CalendarDay to focus the calendar on. Null will do nothing + * @param useSmoothScroll use smooth scroll when changing months. + */ + public void setCurrentDate(@Nullable CalendarDay day, boolean useSmoothScroll) { + if (day == null) { + return; + } + int index = adapter.getIndexForDay(day); + pager.setCurrentItem(index, useSmoothScroll); + updateUi(); + } + + /** + * @return the minimum selectable date for the calendar, if any + */ + public CalendarDay getMinimumDate() { + return minDate; + } + + /** + * @return the maximum selectable date for the calendar, if any + */ + public CalendarDay getMaximumDate() { + return maxDate; + } + + /** + * Allow the user to click on dates from other months that are not out of range. Go to next or + * previous month if a day outside the current month is clicked. The day still need to be + * enabled to be selected. + * Default value is true. Should be used with {@link #SHOW_OTHER_MONTHS}. + * + * @param enabled True to allow the user to click on a day outside current month displayed + */ + public void setAllowClickDaysOutsideCurrentMonth(final boolean enabled) { + this.allowClickDaysOutsideCurrentMonth = enabled; + } + + /** + * Set a formatter for weekday labels. + * + * @param formatter the new formatter, null for default + */ + public void setWeekDayFormatter(WeekDayFormatter formatter) { + adapter.setWeekDayFormatter(formatter == null ? WeekDayFormatter.DEFAULT : formatter); + } + + /** + * Set a formatter for day labels. + * + * @param formatter the new formatter, null for default + */ + public void setDayFormatter(DayFormatter formatter) { + adapter.setDayFormatter(formatter == null ? DateFormatDayFormatter.getInstance() : formatter); + } + + /** + * Set a {@linkplain com.prolificinteractive.materialcalendarview.format.WeekDayFormatter} + * with the provided week day labels + * + * @param weekDayLabels Labels to use for the days of the week + * @see com.prolificinteractive.materialcalendarview.format.ArrayWeekDayFormatter + * @see #setWeekDayFormatter(com.prolificinteractive.materialcalendarview.format.WeekDayFormatter) + */ + public void setWeekDayLabels(CharSequence[] weekDayLabels) { + setWeekDayFormatter(new ArrayWeekDayFormatter(weekDayLabels)); + } + + /** + * Set a {@linkplain com.prolificinteractive.materialcalendarview.format.WeekDayFormatter} + * with the provided week day labels + * + * @param arrayRes String array resource of week day labels + * @see com.prolificinteractive.materialcalendarview.format.ArrayWeekDayFormatter + * @see #setWeekDayFormatter(com.prolificinteractive.materialcalendarview.format.WeekDayFormatter) + */ + public void setWeekDayLabels(@ArrayRes int arrayRes) { + setWeekDayLabels(getResources().getTextArray(arrayRes)); + } + + /** + * @return int of flags used for showing non-enabled dates + * @see #SHOW_ALL + * @see #SHOW_NONE + * @see #SHOW_DEFAULTS + * @see #SHOW_OTHER_MONTHS + * @see #SHOW_OUT_OF_RANGE + * @see #SHOW_DECORATED_DISABLED + */ + @ShowOtherDates + public int getShowOtherDates() { + return adapter.getShowOtherDates(); + } + + /** + * The default value is {@link #SHOW_DEFAULTS}, which currently is just {@link + * #SHOW_DECORATED_DISABLED}. + * This means that the default visible days are of the current month, in the min-max range. + * + * @param showOtherDates flags for showing non-enabled dates + * @see #SHOW_ALL + * @see #SHOW_NONE + * @see #SHOW_DEFAULTS + * @see #SHOW_OTHER_MONTHS + * @see #SHOW_OUT_OF_RANGE + * @see #SHOW_DECORATED_DISABLED + */ + public void setShowOtherDates(@ShowOtherDates int showOtherDates) { + adapter.setShowOtherDates(showOtherDates); + } + + /** + * @return true if allow click on days outside current month displayed + */ + public boolean allowClickDaysOutsideCurrentMonth() { + return allowClickDaysOutsideCurrentMonth; + } + + /** + * @return true if the week days names are shown + */ + public boolean isShowWeekDays() { + return showWeekDays; + } + + /** + * Set a custom formatter for the month/year title + * + * @param titleFormatter new formatter to use, null to use default formatter + */ + public void setTitleFormatter(@Nullable TitleFormatter titleFormatter) { + titleChanger.setTitleFormatter(titleFormatter); + adapter.setTitleFormatter(titleFormatter); + updateUi(); + } + + /** + * Set a {@linkplain com.prolificinteractive.materialcalendarview.format.TitleFormatter} + * using the provided month labels + * + * @param monthLabels month labels to use + * @see com.prolificinteractive.materialcalendarview.format.MonthArrayTitleFormatter + * @see #setTitleFormatter(com.prolificinteractive.materialcalendarview.format.TitleFormatter) + */ + public void setTitleMonths(CharSequence[] monthLabels) { + setTitleFormatter(new MonthArrayTitleFormatter(monthLabels)); + } + + /** + * Set a {@linkplain com.prolificinteractive.materialcalendarview.format.TitleFormatter} + * using the provided month labels + * + * @param arrayRes String array resource of month labels to use + * @see com.prolificinteractive.materialcalendarview.format.MonthArrayTitleFormatter + * @see #setTitleFormatter(com.prolificinteractive.materialcalendarview.format.TitleFormatter) + */ + public void setTitleMonths(@ArrayRes int arrayRes) { + setTitleMonths(getResources().getTextArray(arrayRes)); + } + + /** + * Get the orientation of the animation of the title. + * + * @return Title animation orientation {@link MaterialCalendarView#VERTICAL} or {@link + * MaterialCalendarView#HORIZONTAL} + */ + public int getTitleAnimationOrientation() { + return titleChanger.getOrientation(); + } + + /** + * Change the title animation orientation to have a different look and feel. + * + * @param orientation {@link MaterialCalendarView#VERTICAL} or {@link + * MaterialCalendarView#HORIZONTAL} + */ + public void setTitleAnimationOrientation(final int orientation) { + titleChanger.setOrientation(orientation); + } + + /** + * @return true if the topbar is visible + */ + public boolean getTopbarVisible() { + return topbar.getVisibility() == View.VISIBLE; + } + + /** + * Sets the visibility {@link #topbar}, which contains + * the previous month button {@link #backArrowButton}, next month button {@link #ForwardArrowButton}, + * and the month title {@link #title}. + * + * @param visible Boolean indicating if the topbar is visible + */ + public void setTopbarVisible(boolean visible) { + topbar.setVisibility(visible ? View.VISIBLE : View.GONE); + requestLayout(); + } + + /** + * Get the current {@link CalendarMode} set of the Calendar. + * + * @return Whichever mode the calendar is currently in. + */ + public CalendarMode getCalendarMode() { + return calendarMode; + } + + @Override + protected Parcelable onSaveInstanceState() { + SavedState ss = new SavedState(super.onSaveInstanceState()); + ss.showOtherDates = getShowOtherDates(); + ss.allowClickDaysOutsideCurrentMonth = allowClickDaysOutsideCurrentMonth(); + ss.minDate = getMinimumDate(); + ss.maxDate = getMaximumDate(); + ss.selectedDates = getSelectedDates(); + ss.selectionMode = getSelectionMode(); + ss.topbarVisible = getTopbarVisible(); + ss.dynamicHeightEnabled = mDynamicHeightEnabled; + ss.currentMonth = currentMonth; + ss.cacheCurrentPosition = state.cacheCurrentPosition; + return ss; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + state().edit() + .setMinimumDate(ss.minDate) + .setMaximumDate(ss.maxDate) + .isCacheCalendarPositionEnabled(ss.cacheCurrentPosition) + .commit(); + + setShowOtherDates(ss.showOtherDates); + setAllowClickDaysOutsideCurrentMonth(ss.allowClickDaysOutsideCurrentMonth); + clearSelection(); + for (CalendarDay calendarDay : ss.selectedDates) { + setDateSelected(calendarDay, true); + } + setTopbarVisible(ss.topbarVisible); + setSelectionMode(ss.selectionMode); + setDynamicHeightEnabled(ss.dynamicHeightEnabled); + setCurrentDate(ss.currentMonth); + } + + @Override + protected void dispatchSaveInstanceState(@NonNull SparseArray container) { + dispatchFreezeSelfOnly(container); + } + + @Override + protected void dispatchRestoreInstanceState(@NonNull SparseArray container) { + dispatchThawSelfOnly(container); + } + + private void setRangeDates(CalendarDay min, CalendarDay max) { + CalendarDay c = currentMonth; + adapter.setRangeDates(min, max); + currentMonth = c; + if (min != null) { + currentMonth = min.isAfter(currentMonth) ? min : currentMonth; + } + int position = adapter.getIndexForDay(c); + pager.setCurrentItem(position, false); + updateUi(); + } + + /** + * @return The first day of the week as a {@linkplain Calendar} day constant. + */ + public DayOfWeek getFirstDayOfWeek() { + return firstDayOfWeek; + } + + /** + * @return the dynamic height state - true if enabled. + */ + public boolean isDynamicHeightEnabled() { + return mDynamicHeightEnabled; + } + + /** + * By default, the calendar will take up all the space needed to show any month (6 rows). + * By enabling dynamic height, the view will change height dependant on the visible month. + *

+ * This means months that only need 5 or 4 rows to show the entire month will only take up + * that many rows, and will grow and shrink as necessary. + * + * @param useDynamicHeight true to have the view different heights based on the visible month + */ + public void setDynamicHeightEnabled(boolean useDynamicHeight) { + this.mDynamicHeightEnabled = useDynamicHeight; + } + + /** + * Add a collection of day decorators + * + * @param decorators decorators to add + */ + public void addDecorators(Collection decorators) { + if (decorators == null) { + return; + } + + dayViewDecorators.addAll(decorators); + adapter.setDecorators(dayViewDecorators); + } + + /** + * Add several day decorators + * + * @param decorators decorators to add + */ + public void addDecorators(DayViewDecorator... decorators) { + addDecorators(Arrays.asList(decorators)); + } + + /** + * Add a day decorator + * + * @param decorator decorator to add + */ + public void addDecorator(DayViewDecorator decorator) { + if (decorator == null) { + return; + } + dayViewDecorators.add(decorator); + adapter.setDecorators(dayViewDecorators); + } + + /** + * Remove all decorators + */ + public void removeDecorators() { + dayViewDecorators.clear(); + adapter.setDecorators(dayViewDecorators); + } + + /* + * Listener/Callback Code + */ + + /** + * Remove a specific decorator instance. Same rules as {@linkplain List#remove(Object)} + * + * @param decorator decorator to remove + */ + public void removeDecorator(DayViewDecorator decorator) { + dayViewDecorators.remove(decorator); + adapter.setDecorators(dayViewDecorators); + } + + /** + * Invalidate decorators after one has changed internally. That is, if a decorator mutates, you + * should call this method to update the widget. + */ + public void invalidateDecorators() { + adapter.invalidateDecorators(); + } + + /** + * Sets the listener to be notified upon selected date changes. + * + * @param listener thing to be notified + */ + public void setOnDateChangedListener(OnDateSelectedListener listener) { + this.listener = listener; + } + + /** + * Sets the listener to be notified upon long clicks on dates. + * + * @param longClickListener thing to be notified + */ + public void setOnDateLongClickListener(OnDateLongClickListener longClickListener) { + this.longClickListener = longClickListener; + } + + /** + * Sets the listener to be notified upon month changes. + * + * @param listener thing to be notified + */ + public void setOnMonthChangedListener(OnMonthChangedListener listener) { + this.monthListener = listener; + } + + /** + * Sets the listener to be notified upon a range has been selected. + * + * @param listener thing to be notified + */ + public void setOnRangeSelectedListener(OnRangeSelectedListener listener) { + this.rangeListener = listener; + } + + /** + * Add listener to the title or null to remove it. + * + * @param listener Listener to be notified. + */ + public void setOnTitleClickListener(final OnClickListener listener) { + title.setOnClickListener(listener); + } + + /** + * Dispatch date change events to a listener, if set + * + * @param day the day that was selected + * @param selected true if the day is now currently selected, false otherwise + */ + protected void dispatchOnDateSelected(final CalendarDay day, final boolean selected) { + if (listener != null) { + listener.onDateSelected(MaterialCalendarView.this, day, selected); + } + } + + /** + * Dispatch a range of days to a range listener, if set, ordered chronologically. + * + * @param days Enclosing days ordered from first to last day. + */ + protected void dispatchOnRangeSelected(@NonNull final List days) { + if (rangeListener != null) { + rangeListener.onRangeSelected(MaterialCalendarView.this, days); + } + } + + /** + * Dispatch date change events to a listener, if set + * + * @param day first day of the new month + */ + protected void dispatchOnMonthChanged(final CalendarDay day) { + if (monthListener != null) { + monthListener.onMonthChanged(MaterialCalendarView.this, day); + } + } + + /** + * Call by {@link CalendarPagerView} to indicate that a day was clicked and we should handle it. + * This method will always process the click to the selected date. + * + * @param date date of the day that was clicked + * @param nowSelected true if the date is now selected, false otherwise + */ + protected void onDateClicked(@NonNull CalendarDay date, boolean nowSelected) { + switch (selectionMode) { + case SELECTION_MODE_MULTIPLE: { + adapter.setDateSelected(date, nowSelected); + dispatchOnDateSelected(date, nowSelected); + } + break; + case SELECTION_MODE_RANGE: { + final List currentSelection = adapter.getSelectedDates(); + + if (currentSelection.size() == 0) { + // Selecting the first date of a range + adapter.setDateSelected(date, nowSelected); + dispatchOnDateSelected(date, nowSelected); + } else if (currentSelection.size() == 1) { + // Selecting the second date of a range + final CalendarDay firstDaySelected = currentSelection.get(0); + if (firstDaySelected.equals(date)) { + // Right now, we are not supporting a range of one day, so we are removing the day instead. + adapter.setDateSelected(date, nowSelected); + dispatchOnDateSelected(date, nowSelected); + } else if (firstDaySelected.isAfter(date)) { + // Selecting a range, dispatching in reverse order... + adapter.selectRange(date, firstDaySelected); + dispatchOnRangeSelected(adapter.getSelectedDates()); + } else { + // Selecting a range, dispatching in order... + adapter.selectRange(firstDaySelected, date); + dispatchOnRangeSelected(adapter.getSelectedDates()); + } + } else { + // Clearing selection and making a selection of the new date. + adapter.clearSelections(); + adapter.setDateSelected(date, nowSelected); + dispatchOnDateSelected(date, nowSelected); + } + } + break; + default: + case SELECTION_MODE_SINGLE: { + adapter.clearSelections(); + adapter.setDateSelected(date, true); + dispatchOnDateSelected(date, true); + } + break; + } + } + + /** + * Select a fresh range of date including first day and last day. + * + * @param firstDay first day of the range to select + * @param lastDay last day of the range to select + */ + public void selectRange(final CalendarDay firstDay, final CalendarDay lastDay) { + if (firstDay == null || lastDay == null) { + return; + } else if (firstDay.isAfter(lastDay)) { + adapter.selectRange(lastDay, firstDay); + dispatchOnRangeSelected(adapter.getSelectedDates()); + } else { + adapter.selectRange(firstDay, lastDay); + dispatchOnRangeSelected(adapter.getSelectedDates()); + } + } + + /** + * Call by {@link CalendarPagerView} to indicate that a day was clicked and we should handle it + */ + protected void onDateClicked(final DayView dayView) { + final CalendarDay currentDate = getCurrentDate(); + final CalendarDay selectedDate = dayView.getDate(); + final int currentMonth = currentDate.getMonth(); + final int selectedMonth = selectedDate.getMonth(); + + if (calendarMode == CalendarMode.MONTHS + && allowClickDaysOutsideCurrentMonth + && currentMonth != selectedMonth) { + if (currentDate.isAfter(selectedDate)) { + goToPrevious(); + } else if (currentDate.isBefore(selectedDate)) { + goToNext(); + } + } + onDateClicked(dayView.getDate(), !dayView.isChecked()); + } + + /* + * Show Other Dates Utils + */ + + /** + * Call by {@link CalendarPagerView} to indicate that a day was long clicked and we should handle + * it + */ + protected void onDateLongClicked(final DayView dayView) { + if (longClickListener != null) { + longClickListener.onDateLongClick(MaterialCalendarView.this, dayView.getDate()); + } + } + + /** + * Called by the adapter for cases when changes in state result in dates being unselected + * + * @param date date that should be de-selected + */ + protected void onDateUnselected(CalendarDay date) { + dispatchOnDateSelected(date, false); + } + + /** + * {@inheritDoc} + */ + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(1); + } + + /* + * Custom ViewGroup Code + */ + + /** + * {@inheritDoc} + */ + @Override + protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { + final int specWidthSize = MeasureSpec.getSize(widthMeasureSpec); + final int specWidthMode = MeasureSpec.getMode(widthMeasureSpec); + final int specHeightSize = MeasureSpec.getSize(heightMeasureSpec); + final int specHeightMode = MeasureSpec.getMode(heightMeasureSpec); + + //We need to disregard padding for a while. This will be added back later + final int desiredWidth = specWidthSize - getPaddingLeft() - getPaddingRight(); + final int desiredHeight = specHeightSize - getPaddingTop() - getPaddingBottom(); + + final int weekCount = getWeekCountBasedOnMode(); + + final int viewTileHeight = getTopbarVisible() ? (weekCount + 1) : weekCount; + + //Calculate independent tile sizes for later + int desiredTileWidth = desiredWidth / DEFAULT_DAYS_IN_WEEK; + int desiredTileHeight = desiredHeight / viewTileHeight; + + int measureTileSize = -1; + int measureTileWidth = -1; + int measureTileHeight = -1; + + if (this.tileWidth != INVALID_TILE_DIMENSION || this.tileHeight != INVALID_TILE_DIMENSION) { + if (this.tileWidth > 0) { + //We have a tileWidth set, we should use that + measureTileWidth = this.tileWidth; + } else { + measureTileWidth = desiredTileWidth; + } + if (this.tileHeight > 0) { + //We have a tileHeight set, we should use that + measureTileHeight = this.tileHeight; + } else { + measureTileHeight = desiredTileHeight; + } + } else if (specWidthMode == MeasureSpec.EXACTLY || specWidthMode == MeasureSpec.AT_MOST) { + if (specHeightMode == MeasureSpec.EXACTLY) { + //Pick the smaller of the two explicit sizes + measureTileSize = Math.min(desiredTileWidth, desiredTileHeight); + } else { + //Be the width size the user wants + measureTileSize = desiredTileWidth; + } + } else if (specHeightMode == MeasureSpec.EXACTLY || specHeightMode == MeasureSpec.AT_MOST) { + //Be the height size the user wants + measureTileSize = desiredTileHeight; + } + + if (measureTileSize > 0) { + //Use measureTileSize if set + measureTileHeight = measureTileSize; + measureTileWidth = measureTileSize; + } else if (measureTileSize <= 0) { + if (measureTileWidth <= 0) { + //Set width to default if no value were set + measureTileWidth = dpToPx(DEFAULT_TILE_SIZE_DP); + } + if (measureTileHeight <= 0) { + //Set height to default if no value were set + measureTileHeight = dpToPx(DEFAULT_TILE_SIZE_DP); + } + } + + //Calculate our size based off our measured tile size + int measuredWidth = measureTileWidth * DEFAULT_DAYS_IN_WEEK; + int measuredHeight = measureTileHeight * viewTileHeight; + + //Put padding back in from when we took it away + measuredWidth += getPaddingLeft() + getPaddingRight(); + measuredHeight += getPaddingTop() + getPaddingBottom(); + + //Contract fulfilled, setting out measurements + setMeasuredDimension( + //We clamp inline because we want to use un-clamped versions on the children + clampSize(measuredWidth, widthMeasureSpec), + clampSize(measuredHeight, heightMeasureSpec) + ); + + int count = getChildCount(); + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + + LayoutParams p = (LayoutParams) child.getLayoutParams(); + + int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( + DEFAULT_DAYS_IN_WEEK * measureTileWidth, + MeasureSpec.EXACTLY + ); + + int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + p.height * measureTileHeight, + MeasureSpec.EXACTLY + ); + + child.measure(childWidthMeasureSpec, childHeightMeasureSpec); + } + } + + private int getWeekCountBasedOnMode() { + int weekCount = calendarMode.visibleWeeksCount; + final boolean isInMonthsMode = calendarMode.equals(CalendarMode.MONTHS); + if (isInMonthsMode && mDynamicHeightEnabled && adapter != null && pager != null) { + final LocalDate cal = adapter.getItem(pager.getCurrentItem()).getDate(); + final LocalDate tempLastDay = cal.withDayOfMonth(cal.lengthOfMonth()); + weekCount = tempLastDay.get(WeekFields.of(firstDayOfWeek, 1).weekOfMonth()); + } + return showWeekDays ? weekCount + DAY_NAMES_ROW : weekCount; + } + + /** + * {@inheritDoc} + */ + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int count = getChildCount(); + + final int parentLeft = getPaddingLeft(); + final int parentWidth = right - left - parentLeft - getPaddingRight(); + + int childTop = getPaddingTop(); + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == View.GONE) { + continue; + } + + final int width = child.getMeasuredWidth(); + final int height = child.getMeasuredHeight(); + + int delta = (parentWidth - width) / 2; + int childLeft = parentLeft + delta; + + child.layout(childLeft, childTop, childLeft + width, childTop + height); + + childTop += height; + } + } + + /** + * {@inheritDoc} + */ + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(1); + } + + @Override + public boolean shouldDelayChildPressedState() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams; + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(1); + } + + @Override + public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setClassName(MaterialCalendarView.class.getName()); + } + + @Override + public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(MaterialCalendarView.class.getName()); + } + + /** + * @return true if swiping months is enabled, false if disabled. Default is true. + */ + public boolean isPagingEnabled() { + return pager.isPagingEnabled(); + } + + /** + * Enable or disable the ability to swipe between months. + * + * @param pagingEnabled pass false to disable paging, true to enable (default) + */ + public void setPagingEnabled(boolean pagingEnabled) { + pager.setPagingEnabled(pagingEnabled); + updateUi(); + } + + /** + * Preserve the current parameters of the Material Calendar View. + */ + public State state() { + return state; + } + + /** + * Initialize the parameters from scratch. + */ + public StateBuilder newState() { + return new StateBuilder(); + } + + private void commit(State state) { + // Use the calendarDayToShow to determine which date to focus on for the case of switching between month and week views + CalendarDay calendarDayToShow = null; + if (adapter != null && state.cacheCurrentPosition) { + calendarDayToShow = adapter.getItem(pager.getCurrentItem()); + if (calendarMode != state.calendarMode) { + CalendarDay currentlySelectedDate = getSelectedDate(); + if (calendarMode == CalendarMode.MONTHS && currentlySelectedDate != null) { + // Going from months to weeks + LocalDate lastVisibleCalendar = calendarDayToShow.getDate(); + CalendarDay lastVisibleCalendarDay = CalendarDay.from(lastVisibleCalendar.plusDays(1)); + if (currentlySelectedDate.equals(calendarDayToShow) || + (currentlySelectedDate.isAfter(calendarDayToShow) && currentlySelectedDate.isBefore( + lastVisibleCalendarDay))) { + // Currently selected date is within view, so center on that + calendarDayToShow = currentlySelectedDate; + } + } else if (calendarMode == CalendarMode.WEEKS) { + // Going from weeks to months + LocalDate lastVisibleCalendar = calendarDayToShow.getDate(); + CalendarDay lastVisibleCalendarDay = CalendarDay.from(lastVisibleCalendar.plusDays(6)); + if (currentlySelectedDate != null && + (currentlySelectedDate.equals(calendarDayToShow) || currentlySelectedDate.equals( + lastVisibleCalendarDay) || + (currentlySelectedDate.isAfter(calendarDayToShow) + && currentlySelectedDate.isBefore(lastVisibleCalendarDay)))) { + // Currently selected date is within view, so center on that + calendarDayToShow = currentlySelectedDate; + } else { + calendarDayToShow = lastVisibleCalendarDay; + } + } + } + } + + this.state = state; + // Save states parameters + calendarMode = state.calendarMode; + firstDayOfWeek = state.firstDayOfWeek; + minDate = state.minDate; + maxDate = state.maxDate; + showWeekDays = state.showWeekDays; + + // Recreate adapter + final CalendarPagerAdapter newAdapter; + switch (calendarMode) { + case MONTHS: + newAdapter = new MonthPagerAdapter(this); + break; + case WEEKS: + newAdapter = new WeekPagerAdapter(this); + break; + default: + throw new IllegalArgumentException("Provided display mode which is not yet implemented"); + } + if (adapter == null) { + adapter = newAdapter; + } else { + adapter = adapter.migrateStateAndReturn(newAdapter); + } + adapter.setShowWeekDays(showWeekDays); + pager.setAdapter(adapter); + setRangeDates(minDate, maxDate); + + // Reset height params after mode change + int tileHeight = showWeekDays ? calendarMode.visibleWeeksCount + DAY_NAMES_ROW + : calendarMode.visibleWeeksCount; + pager.setLayoutParams(new LayoutParams(tileHeight)); + + setCurrentDate( + selectionMode == SELECTION_MODE_SINGLE && !adapter.getSelectedDates().isEmpty() + ? adapter.getSelectedDates().get(0) + : CalendarDay.today()); + + if (calendarDayToShow != null) { + pager.setCurrentItem(adapter.getIndexForDay(calendarDayToShow)); + } + + invalidateDecorators(); + updateUi(); + } + + /** + * {@linkplain IntDef} annotation for selection mode. + * + * @see #setSelectionMode(int) + * @see #getSelectionMode() + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + {SELECTION_MODE_NONE, SELECTION_MODE_SINGLE, SELECTION_MODE_MULTIPLE, SELECTION_MODE_RANGE}) + public @interface SelectionMode { + } + + /** + * {@linkplain IntDef} annotation for showOtherDates. + * + * @see #setShowOtherDates(int) + * @see #getShowOtherDates() + */ + @SuppressLint("UniqueConstants") + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = { + SHOW_NONE, SHOW_ALL, SHOW_DEFAULTS, + SHOW_OUT_OF_RANGE, SHOW_OTHER_MONTHS, SHOW_DECORATED_DISABLED + }) + public @interface ShowOtherDates { + } + + public static class SavedState extends BaseSavedState { + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + int showOtherDates = SHOW_DEFAULTS; + boolean allowClickDaysOutsideCurrentMonth = true; + CalendarDay minDate = null; + CalendarDay maxDate = null; + List selectedDates = new ArrayList<>(); + boolean topbarVisible = true; + int selectionMode = SELECTION_MODE_SINGLE; + boolean dynamicHeightEnabled = false; + CalendarDay currentMonth = null; + boolean cacheCurrentPosition; + + SavedState(Parcelable superState) { + super(superState); + } + + private SavedState(Parcel in) { + super(in); + showOtherDates = in.readInt(); + allowClickDaysOutsideCurrentMonth = in.readByte() != 0; + ClassLoader loader = CalendarDay.class.getClassLoader(); + minDate = in.readParcelable(loader); + maxDate = in.readParcelable(loader); + in.readTypedList(selectedDates, CalendarDay.CREATOR); + topbarVisible = in.readInt() == 1; + selectionMode = in.readInt(); + dynamicHeightEnabled = in.readInt() == 1; + currentMonth = in.readParcelable(loader); + cacheCurrentPosition = in.readByte() != 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(showOtherDates); + out.writeByte((byte) (allowClickDaysOutsideCurrentMonth ? 1 : 0)); + out.writeParcelable(minDate, 0); + out.writeParcelable(maxDate, 0); + out.writeTypedList(selectedDates); + out.writeInt(topbarVisible ? 1 : 0); + out.writeInt(selectionMode); + out.writeInt(dynamicHeightEnabled ? 1 : 0); + out.writeParcelable(currentMonth, 0); + out.writeByte((byte) (cacheCurrentPosition ? 1 : 0)); + } + } + + /** + * Simple layout params for MaterialCalendarView. The only variation for layout is height. + */ + protected static class LayoutParams extends MarginLayoutParams { + + /** + * Create a layout that matches parent width, and is X number of tiles high + * + * @param tileHeight view height in number of tiles + */ + public LayoutParams(int tileHeight) { + super(MATCH_PARENT, tileHeight); + } + } + + public class State { + private final CalendarMode calendarMode; + private final DayOfWeek firstDayOfWeek; + private final CalendarDay minDate; + private final CalendarDay maxDate; + private final boolean cacheCurrentPosition; + private final boolean showWeekDays; + + private State(final StateBuilder builder) { + calendarMode = builder.calendarMode; + firstDayOfWeek = builder.firstDayOfWeek; + minDate = builder.minDate; + maxDate = builder.maxDate; + cacheCurrentPosition = builder.cacheCurrentPosition; + showWeekDays = builder.showWeekDays; + } + + /** + * Modify parameters from current state. + */ + public StateBuilder edit() { + return new StateBuilder(this); + } + } + + public class StateBuilder { + private CalendarMode calendarMode; + private DayOfWeek firstDayOfWeek; + private boolean cacheCurrentPosition = false; + private CalendarDay minDate = null; + private CalendarDay maxDate = null; + private boolean showWeekDays; + + public StateBuilder() { + calendarMode = CalendarMode.MONTHS; + firstDayOfWeek = + LocalDate.now().with(WeekFields.of(Locale.getDefault()).dayOfWeek(), 1).getDayOfWeek(); + } + + private StateBuilder(final State state) { + calendarMode = state.calendarMode; + firstDayOfWeek = state.firstDayOfWeek; + minDate = state.minDate; + maxDate = state.maxDate; + cacheCurrentPosition = state.cacheCurrentPosition; + showWeekDays = state.showWeekDays; + } + + /** + * Sets the first day of the week. + *

+ * Uses the {@link DayOfWeek} day constants. + * + * @param day The first day of the week as a {@link DayOfWeek} enum. + * @see java.util.Calendar + */ + public StateBuilder setFirstDayOfWeek(DayOfWeek day) { + this.firstDayOfWeek = day; + return this; + } + + /** + * Set calendar display mode. The default mode is Months. + * When switching between modes will select todays date, or the selected date, + * if selection mode is single. + * + * @param mode - calendar mode + */ + public StateBuilder setCalendarDisplayMode(CalendarMode mode) { + this.calendarMode = mode; + return this; + } + + /** + * @param date set the minimum selectable date, null for no minimum + */ + public StateBuilder setMinimumDate(@Nullable LocalDate date) { + setMinimumDate(CalendarDay.from(date)); + return this; + } + + /** + * @param calendar set the minimum selectable date, null for no minimum + */ + public StateBuilder setMinimumDate(@Nullable CalendarDay calendar) { + minDate = calendar; + return this; + } + + /** + * @param date set the maximum selectable date, null for no maximum + */ + public StateBuilder setMaximumDate(@Nullable LocalDate date) { + setMaximumDate(CalendarDay.from(date)); + return this; + } + + /** + * @param calendar set the maximum selectable date, null for no maximum + */ + public StateBuilder setMaximumDate(@Nullable CalendarDay calendar) { + maxDate = calendar; + return this; + } + + /** + * @param showWeekDays true to show week days names + */ + public StateBuilder setShowWeekDays(boolean showWeekDays) { + this.showWeekDays = showWeekDays; + return this; + } + + /** + * Use this method to enable saving the current position when switching + * between week and month mode. By default, the calendar update to the latest selected date + * or the current date. When set to true, the view will used the month that the calendar is + * currently on. + * + * @param cacheCurrentPosition Set to true to cache the current position, false otherwise. + */ + public StateBuilder isCacheCalendarPositionEnabled(final boolean cacheCurrentPosition) { + this.cacheCurrentPosition = cacheCurrentPosition; + return this; + } + + public void commit() { + MaterialCalendarView.this.commit(new State(this)); + } + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/MaterialCalendarViewInitProvider.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/MaterialCalendarViewInitProvider.java index cc7f2d4a..3516cb79 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/MaterialCalendarViewInitProvider.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/MaterialCalendarViewInitProvider.java @@ -6,8 +6,9 @@ import android.content.pm.ProviderInfo; import android.database.Cursor; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.jakewharton.threetenabp.AndroidThreeTen; /** @@ -15,61 +16,72 @@ */ public final class MaterialCalendarViewInitProvider extends ContentProvider { - private static final String MCV_AUTHORITY = - "com.prolificinteractive.materialcalendarview.materialcalendarviewinitprovider"; - - public MaterialCalendarViewInitProvider() { } + private static final String MCV_AUTHORITY = + "com.prolificinteractive.materialcalendarview.materialcalendarviewinitprovider"; - @Override public boolean onCreate() { - // The interesting piece here. - AndroidThreeTen.init(getContext()); - return true; - } + public MaterialCalendarViewInitProvider() { + } - @Override public void attachInfo(final Context context, final ProviderInfo providerInfo) { - if (providerInfo == null) { - throw new NullPointerException("MaterialCalendarViewInitProvider ProviderInfo cannot be null."); + @Override + public boolean onCreate() { + // The interesting piece here. + AndroidThreeTen.init(getContext()); + return true; } - // So if the authorities equal the library internal ones, the developer forgot to set his applicationId - if (MCV_AUTHORITY.equals(providerInfo.authority)) { - throw new IllegalStateException( - "Incorrect provider authority in manifest. Most likely due to a " - + "missing applicationId variable in application\'s build.gradle."); + + @Override + public void attachInfo(final Context context, final ProviderInfo providerInfo) { + if (providerInfo == null) { + throw new NullPointerException("MaterialCalendarViewInitProvider ProviderInfo cannot be null."); + } + // So if the authorities equal the library internal ones, the developer forgot to set his applicationId + if (MCV_AUTHORITY.equals(providerInfo.authority)) { + throw new IllegalStateException( + "Incorrect provider authority in manifest. Most likely due to a " + + "missing applicationId variable in application\'s build.gradle."); + } + super.attachInfo(context, providerInfo); } - super.attachInfo(context, providerInfo); - } - @Nullable @Override public Cursor query( - @NonNull final Uri uri, - @Nullable final String[] projection, - @Nullable final String selection, - @Nullable final String[] selectionArgs, - @Nullable final String sortOrder) { - return null; - } + @Nullable + @Override + public Cursor query( + @NonNull final Uri uri, + @Nullable final String[] projection, + @Nullable final String selection, + @Nullable final String[] selectionArgs, + @Nullable final String sortOrder) { + return null; + } - @Nullable @Override public String getType(@NonNull final Uri uri) { - return null; - } + @Nullable + @Override + public String getType(@NonNull final Uri uri) { + return null; + } - @Nullable @Override public Uri insert( - @NonNull final Uri uri, - @Nullable final ContentValues values) { - return null; - } + @Nullable + @Override + public Uri insert( + @NonNull final Uri uri, + @Nullable final ContentValues values) { + return null; + } - @Override public int delete( - @NonNull final Uri uri, - @Nullable final String selection, - @Nullable final String[] selectionArgs) { - return 0; - } + @Override + public int delete( + @NonNull final Uri uri, + @Nullable final String selection, + @Nullable final String[] selectionArgs) { + return 0; + } - @Override public int update( - @NonNull final Uri uri, - @Nullable final ContentValues values, - @Nullable final String selection, - @Nullable final String[] selectionArgs) { - return 0; - } + @Override + public int update( + @NonNull final Uri uri, + @Nullable final ContentValues values, + @Nullable final String selection, + @Nullable final String[] selectionArgs) { + return 0; + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/MonthPagerAdapter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/MonthPagerAdapter.java index 1e205310..b557cfdf 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/MonthPagerAdapter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/MonthPagerAdapter.java @@ -1,6 +1,7 @@ package com.prolificinteractive.materialcalendarview; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; + import org.threeten.bp.Period; /** @@ -8,56 +9,63 @@ */ class MonthPagerAdapter extends CalendarPagerAdapter { - MonthPagerAdapter(MaterialCalendarView mcv) { - super(mcv); - } + MonthPagerAdapter(MaterialCalendarView mcv) { + super(mcv); + } - @Override protected MonthView createView(int position) { - return new MonthView(mcv, getItem(position), mcv.getFirstDayOfWeek(), showWeekDays); - } + @Override + protected MonthView createView(int position) { + return new MonthView(mcv, getItem(position), mcv.getFirstDayOfWeek(), showWeekDays); + } - @Override protected int indexOf(MonthView view) { - CalendarDay month = view.getMonth(); - return getRangeIndex().indexOf(month); - } + @Override + protected int indexOf(MonthView view) { + CalendarDay month = view.getMonth(); + return getRangeIndex().indexOf(month); + } - @Override protected boolean isInstanceOfView(Object object) { - return object instanceof MonthView; - } + @Override + protected boolean isInstanceOfView(Object object) { + return object instanceof MonthView; + } - @Override protected DateRangeIndex createRangeIndex(CalendarDay min, CalendarDay max) { - return new Monthly(min, max); - } + @Override + protected DateRangeIndex createRangeIndex(CalendarDay min, CalendarDay max) { + return new Monthly(min, max); + } - public static class Monthly implements DateRangeIndex { + public static class Monthly implements DateRangeIndex { - /** - * Minimum date with the first month to display. - */ - private final CalendarDay min; + /** + * Minimum date with the first month to display. + */ + private final CalendarDay min; - /** - * Number of months to display. - */ - private final int count; + /** + * Number of months to display. + */ + private final int count; - public Monthly(@NonNull final CalendarDay min, @NonNull final CalendarDay max) { - this.min = CalendarDay.from(min.getYear(), min.getMonth(), 1); - this.count = indexOf(max) + 1; - } + public Monthly(@NonNull final CalendarDay min, @NonNull final CalendarDay max) { + this.min = CalendarDay.from(min.getYear(), min.getMonth(), 1); + this.count = indexOf(max) + 1; + } - @Override public int getCount() { - return count; - } + @Override + public int getCount() { + return count; + } - @Override public int indexOf(final CalendarDay day) { - return (int) Period - .between(min.getDate().withDayOfMonth(1), day.getDate().withDayOfMonth(1)) - .toTotalMonths(); - } + @Override + public int indexOf(final CalendarDay day) { + return (int) Period + .between(min.getDate().withDayOfMonth(1), day.getDate().withDayOfMonth(1)) + .toTotalMonths(); + } - @Override public CalendarDay getItem(final int position) { - return CalendarDay.from(min.getDate().plusMonths(position)); + @Override + public CalendarDay getItem(final int position) { + return CalendarDay.from(min.getDate().plusMonths(position)); + } } - } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/MonthView.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/MonthView.java index 1fae0818..0ab195f4 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/MonthView.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/MonthView.java @@ -1,46 +1,52 @@ package com.prolificinteractive.materialcalendarview; import android.annotation.SuppressLint; -import android.support.annotation.NonNull; -import java.util.Collection; +import androidx.annotation.NonNull; + import org.threeten.bp.DayOfWeek; import org.threeten.bp.LocalDate; +import java.util.Collection; + /** * Display a month of {@linkplain DayView}s and * seven {@linkplain WeekDayView}s. */ -@SuppressLint("ViewConstructor") class MonthView extends CalendarPagerView { - - public MonthView( - @NonNull final MaterialCalendarView view, - final CalendarDay month, - final DayOfWeek firstDayOfWeek, - final boolean showWeekDays) { - super(view, month, firstDayOfWeek, showWeekDays); - } - - @Override protected void buildDayViews( - final Collection dayViews, - final LocalDate calendar) { - LocalDate temp = calendar; - for (int r = 0; r < DEFAULT_MAX_WEEKS; r++) { - for (int i = 0; i < DEFAULT_DAYS_IN_WEEK; i++) { - addDayView(dayViews, temp); - temp = temp.plusDays(1); - } +@SuppressLint("ViewConstructor") +class MonthView extends CalendarPagerView { + + public MonthView( + @NonNull final MaterialCalendarView view, + final CalendarDay month, + final DayOfWeek firstDayOfWeek, + final boolean showWeekDays) { + super(view, month, firstDayOfWeek, showWeekDays); } - } - public CalendarDay getMonth() { - return getFirstViewDay(); - } + @Override + protected void buildDayViews( + final Collection dayViews, + final LocalDate calendar) { + LocalDate temp = calendar; + for (int r = 0; r < DEFAULT_MAX_WEEKS; r++) { + for (int i = 0; i < DEFAULT_DAYS_IN_WEEK; i++) { + addDayView(dayViews, temp); + temp = temp.plusDays(1); + } + } + } - @Override protected boolean isDayEnabled(final CalendarDay day) { - return day.getMonth() == getFirstViewDay().getMonth(); - } + public CalendarDay getMonth() { + return getFirstViewDay(); + } - @Override protected int getRows() { - return showWeekDays ? DEFAULT_MAX_WEEKS + DAY_NAMES_ROW : DEFAULT_MAX_WEEKS; - } + @Override + protected boolean isDayEnabled(final CalendarDay day) { + return day.getMonth() == getFirstViewDay().getMonth(); + } + + @Override + protected int getRows() { + return showWeekDays ? DEFAULT_MAX_WEEKS + DAY_NAMES_ROW : DEFAULT_MAX_WEEKS; + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/MySelectorDecorator.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/MySelectorDecorator.java new file mode 100644 index 00000000..1c6510de --- /dev/null +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/MySelectorDecorator.java @@ -0,0 +1,41 @@ +package com.prolificinteractive.materialcalendarview; + +import android.app.Activity; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.text.style.ForegroundColorSpan; + +import java.util.Collection; +import java.util.HashSet; + +public class MySelectorDecorator implements DayViewDecorator { + + private final Drawable drawable; + private HashSet dates; + + + public MySelectorDecorator(Activity context, Collection dates, int Drawable) { + drawable = context.getResources().getDrawable(Drawable); + this.dates = new HashSet<>(dates); + } + + public MySelectorDecorator(Activity context, int Drawable) { + drawable = context.getResources().getDrawable(Drawable); + } + + @Override + public boolean shouldDecorate(CalendarDay day) { + return dates == null || dates.contains(day); + } + + @Override + public void decorate(DayViewFacade view) { + view.setSelectionDrawable(drawable); + if (dates != null) { + view.addSpan(new ForegroundColorSpan(Color.WHITE)); + } + } +} + + + diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/NoSelectionDecorator.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/NoSelectionDecorator.java new file mode 100644 index 00000000..18ee0679 --- /dev/null +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/NoSelectionDecorator.java @@ -0,0 +1,21 @@ +package com.prolificinteractive.materialcalendarview; + +import android.graphics.Color; +import android.text.style.ForegroundColorSpan; + +public class NoSelectionDecorator implements DayViewDecorator { + + public NoSelectionDecorator() { + } + + @Override + public boolean shouldDecorate(CalendarDay day) { + return true; + } + + @Override + public void decorate(DayViewFacade view) { + view.addSpan(new ForegroundColorSpan(Color.BLACK)); + + } +} diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/OnDateLongClickListener.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/OnDateLongClickListener.java index e1fbc208..61201b81 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/OnDateLongClickListener.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/OnDateLongClickListener.java @@ -1,18 +1,18 @@ package com.prolificinteractive.materialcalendarview; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * The callback used to indicate a date has been long clicked. */ public interface OnDateLongClickListener { - /** - * Called when a user long clicks on a day. - * There is no logic to prevent multiple calls for the same date and state. - * - * @param widget the view associated with this listener - * @param date the date that was long clicked. - */ - void onDateLongClick(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date); + /** + * Called when a user long clicks on a day. + * There is no logic to prevent multiple calls for the same date and state. + * + * @param widget the view associated with this listener + * @param date the date that was long clicked. + */ + void onDateLongClick(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/OnDateSelectedListener.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/OnDateSelectedListener.java index e4ea640c..f2dba380 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/OnDateSelectedListener.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/OnDateSelectedListener.java @@ -1,22 +1,22 @@ package com.prolificinteractive.materialcalendarview; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * The callback used to indicate a date has been selected or deselected */ public interface OnDateSelectedListener { - /** - * Called when a user clicks on a day. - * There is no logic to prevent multiple calls for the same date and state. - * - * @param widget the view associated with this listener - * @param date the date that was selected or unselected - * @param selected true if the day is now selected, false otherwise - */ - void onDateSelected( - @NonNull MaterialCalendarView widget, - @NonNull CalendarDay date, - boolean selected); + /** + * Called when a user clicks on a day. + * There is no logic to prevent multiple calls for the same date and state. + * + * @param widget the view associated with this listener + * @param date the date that was selected or unselected + * @param selected true if the day is now selected, false otherwise + */ + void onDateSelected( + @NonNull MaterialCalendarView widget, + @NonNull CalendarDay date, + boolean selected); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/OnMonthChangedListener.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/OnMonthChangedListener.java index 16f4b576..8b20de65 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/OnMonthChangedListener.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/OnMonthChangedListener.java @@ -5,11 +5,11 @@ */ public interface OnMonthChangedListener { - /** - * Called upon change of the selected day - * - * @param widget the view associated with this listener - * @param date the month picked, as the first day of the month - */ - void onMonthChanged(MaterialCalendarView widget, CalendarDay date); + /** + * Called upon change of the selected day + * + * @param widget the view associated with this listener + * @param date the month picked, as the first day of the month + */ + void onMonthChanged(MaterialCalendarView widget, CalendarDay date); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/OnRangeSelectedListener.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/OnRangeSelectedListener.java index 97c41715..3982c78a 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/OnRangeSelectedListener.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/OnRangeSelectedListener.java @@ -1,6 +1,7 @@ package com.prolificinteractive.materialcalendarview; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; + import java.util.List; /** @@ -8,12 +9,12 @@ */ public interface OnRangeSelectedListener { - /** - * Called when a user selects a range of days. - * There is no logic to prevent multiple calls for the same date and state. - * - * @param widget the view associated with this listener - * @param dates the dates in the range, in ascending order - */ - void onRangeSelected(@NonNull MaterialCalendarView widget, @NonNull List dates); + /** + * Called when a user selects a range of days. + * There is no logic to prevent multiple calls for the same date and state. + * + * @param widget the view associated with this listener + * @param dates the dates in the range, in ascending order + */ + void onRangeSelected(@NonNull MaterialCalendarView widget, @NonNull List dates); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/RtlViewPager.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/RtlViewPager.java new file mode 100644 index 00000000..02f1dc7e --- /dev/null +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/RtlViewPager.java @@ -0,0 +1,422 @@ +package com.prolificinteractive.materialcalendarview; + +import android.content.Context; +import android.database.DataSetObserver; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import java.util.HashMap; + +public class RtlViewPager extends ViewPager { + + private final HashMap mPageChangeListeners = new HashMap<>(); + private int mLayoutDirection = ViewCompat.LAYOUT_DIRECTION_LTR; + + public RtlViewPager(Context context) { + super(context); + } + + public RtlViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void onRtlPropertiesChanged(int layoutDirection) { + super.onRtlPropertiesChanged(layoutDirection); + int viewCompatLayoutDirection = layoutDirection == View.LAYOUT_DIRECTION_RTL ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR; + if (viewCompatLayoutDirection != mLayoutDirection) { + PagerAdapter adapter = super.getAdapter(); + int position = 0; + if (adapter != null) { + position = getCurrentItem(); + } + mLayoutDirection = viewCompatLayoutDirection; + if (adapter != null) { + adapter.notifyDataSetChanged(); + setCurrentItem(position); + } + } + } + + @Override + public PagerAdapter getAdapter() { + ReversingAdapter adapter = (ReversingAdapter) super.getAdapter(); + return adapter == null ? null : adapter.getDelegate(); + } + + @Override + public void setAdapter(PagerAdapter adapter) { + if (adapter != null) { + adapter = new ReversingAdapter(adapter); + } + super.setAdapter(adapter); + setCurrentItem(0); + } + + private boolean isRtl() { + return mLayoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL; + } + + @Override + public int getCurrentItem() { + int item = super.getCurrentItem(); + PagerAdapter adapter = super.getAdapter(); + if (adapter != null && isRtl()) { + item = adapter.getCount() - item - 1; + } + return item; + } + + @Override + public void setCurrentItem(int position) { + PagerAdapter adapter = super.getAdapter(); + if (adapter != null && isRtl()) { + position = adapter.getCount() - position - 1; + } + super.setCurrentItem(position); + } + + @Override + public void setCurrentItem(int position, boolean smoothScroll) { + PagerAdapter adapter = super.getAdapter(); + if (adapter != null && isRtl()) { + position = adapter.getCount() - position - 1; + } + super.setCurrentItem(position, smoothScroll); + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + return new SavedState(superState, mLayoutDirection); + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + + SavedState ss = (SavedState) state; + mLayoutDirection = ss.mLayoutDirection; + super.onRestoreInstanceState(ss.mViewPagerSavedState); + } + + @Override + public void addOnPageChangeListener(@NonNull OnPageChangeListener listener) { + ReversingOnPageChangeListener reversingListener = new ReversingOnPageChangeListener(listener); + mPageChangeListeners.put(listener, reversingListener); + super.addOnPageChangeListener(reversingListener); + } + + @Override + public void removeOnPageChangeListener(@NonNull OnPageChangeListener listener) { + ReversingOnPageChangeListener reverseListener = mPageChangeListeners.remove(listener); + if (reverseListener != null) { + super.removeOnPageChangeListener(reverseListener); + } + } + + @Override + public void clearOnPageChangeListeners() { + super.clearOnPageChangeListeners(); + mPageChangeListeners.clear(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) { + int height = 0; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + int h = child.getMeasuredHeight(); + if (h > height) { + height = h; + } + } + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + public static class SavedState implements Parcelable { + + // The `CREATOR` field is used to create the parcelable from a parcel, even though it is never referenced directly. + public static final Parcelable.ClassLoaderCreator CREATOR + = new Parcelable.ClassLoaderCreator() { + + @Override + public SavedState createFromParcel(Parcel source) { + return createFromParcel(source, null); + } + + @Override + public SavedState createFromParcel(Parcel source, ClassLoader loader) { + return new SavedState(source, loader); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + private final Parcelable mViewPagerSavedState; + private final int mLayoutDirection; + + private SavedState(Parcelable viewPagerSavedState, int layoutDirection) { + mViewPagerSavedState = viewPagerSavedState; + mLayoutDirection = layoutDirection; + } + + private SavedState(Parcel in, ClassLoader loader) { + if (loader == null) { + loader = getClass().getClassLoader(); + } + mViewPagerSavedState = in.readParcelable(loader); + mLayoutDirection = in.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeParcelable(mViewPagerSavedState, flags); + out.writeInt(mLayoutDirection); + } + } + + public static class DelegatingPagerAdapter extends PagerAdapter { + + private final PagerAdapter mDelegate; + + DelegatingPagerAdapter(@NonNull final PagerAdapter delegate) { + this.mDelegate = delegate; + delegate.registerDataSetObserver(new MyDataSetObserver(this)); + } + + PagerAdapter getDelegate() { + return mDelegate; + } + + @Override + public int getCount() { + return mDelegate.getCount(); + } + + @Override + public void startUpdate(@NonNull ViewGroup container) { + mDelegate.startUpdate(container); + } + + @Override + public @NonNull + Object instantiateItem(@NonNull ViewGroup container, int position) { + return mDelegate.instantiateItem(container, position); + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + mDelegate.destroyItem(container, position, object); + } + + @Override + public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + mDelegate.setPrimaryItem(container, position, object); + } + + @Override + public void finishUpdate(@NonNull ViewGroup container) { + mDelegate.finishUpdate(container); + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return mDelegate.isViewFromObject(view, object); + } + + @Override + public Parcelable saveState() { + return mDelegate.saveState(); + } + + @Override + public void restoreState(Parcelable state, ClassLoader loader) { + mDelegate.restoreState(state, loader); + } + + @Override + public int getItemPosition(@NonNull Object object) { + return mDelegate.getItemPosition(object); + } + + @Override + public void notifyDataSetChanged() { + mDelegate.notifyDataSetChanged(); + } + + @Override + public void registerDataSetObserver(@NonNull DataSetObserver observer) { + mDelegate.registerDataSetObserver(observer); + } + + @Override + public void unregisterDataSetObserver(@NonNull DataSetObserver observer) { + mDelegate.unregisterDataSetObserver(observer); + } + + @Override + public CharSequence getPageTitle(int position) { + return mDelegate.getPageTitle(position); + } + + @Override + public float getPageWidth(int position) { + return mDelegate.getPageWidth(position); + } + + private void superNotifyDataSetChanged() { + super.notifyDataSetChanged(); + } + + private static class MyDataSetObserver extends DataSetObserver { + + final DelegatingPagerAdapter mParent; + + private MyDataSetObserver(DelegatingPagerAdapter mParent) { + this.mParent = mParent; + } + + @Override + public void onChanged() { + if (mParent != null) { + mParent.superNotifyDataSetChanged(); + } + } + + @Override + public void onInvalidated() { + onChanged(); + } + } + } + + private class ReversingOnPageChangeListener implements OnPageChangeListener { + + private final OnPageChangeListener mListener; + + ReversingOnPageChangeListener(OnPageChangeListener listener) { + mListener = listener; + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + // The documentation says that `getPageWidth(...)` returns the fraction of the _measured_ width that that page takes up. However, the code seems to + // use the width so we will here too. + final int width = getWidth(); + PagerAdapter adapter = RtlViewPager.super.getAdapter(); + if (isRtl() && adapter != null) { + int count = adapter.getCount(); + int remainingWidth = (int) (width * (1 - adapter.getPageWidth(position))) + positionOffsetPixels; + while (position < count && remainingWidth > 0) { + position += 1; + remainingWidth -= (int) (width * adapter.getPageWidth(position)); + } + position = count - position - 1; + positionOffsetPixels = -remainingWidth; + positionOffset = positionOffsetPixels / (width * adapter.getPageWidth(position)); + } + mListener.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + + @Override + public void onPageSelected(int position) { + PagerAdapter adapter = RtlViewPager.super.getAdapter(); + if (isRtl() && adapter != null) { + position = adapter.getCount() - position - 1; + } + mListener.onPageSelected(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + mListener.onPageScrollStateChanged(state); + } + } + + private class ReversingAdapter extends DelegatingPagerAdapter { + + ReversingAdapter(@NonNull PagerAdapter adapter) { + super(adapter); + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + if (isRtl()) { + position = getCount() - position - 1; + } + super.destroyItem(container, position, object); + } + + @Override + public int getItemPosition(@NonNull Object object) { + int position = super.getItemPosition(object); + if (isRtl()) { + if (position == POSITION_UNCHANGED || position == POSITION_NONE) { + // We can't accept POSITION_UNCHANGED when in RTL mode because adding items to the end of the collection adds them to the beginning of the + // ViewPager. Items whose positions do not change from the perspective of the wrapped adapter actually do change from the perspective of + // the ViewPager. + position = POSITION_NONE; + } else { + position = getCount() - position - 1; + } + } + return position; + } + + @Override + public CharSequence getPageTitle(int position) { + if (isRtl()) { + position = getCount() - position - 1; + } + return super.getPageTitle(position); + } + + @Override + public float getPageWidth(int position) { + if (isRtl()) { + position = getCount() - position - 1; + } + return super.getPageWidth(position); + } + + @Override + public @NonNull + Object instantiateItem(@NonNull ViewGroup container, int position) { + if (isRtl()) { + position = getCount() - position - 1; + } + return super.instantiateItem(container, position); + } + + @Override + public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + if (isRtl()) { + position = getCount() - position - 1; + } + super.setPrimaryItem(container, position, object); + } + } +} diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/TitleChanger.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/TitleChanger.java index 31cef265..0b29cda2 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/TitleChanger.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/TitleChanger.java @@ -2,148 +2,148 @@ import android.animation.Animator; import android.content.res.Resources; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.text.TextUtils; import android.util.TypedValue; import android.view.ViewPropertyAnimator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.widget.TextView; + import com.prolificinteractive.materialcalendarview.format.TitleFormatter; class TitleChanger { - public static final int DEFAULT_ANIMATION_DELAY = 400; - public static final int DEFAULT_Y_TRANSLATION_DP = 20; - - private final TextView title; - @NonNull private TitleFormatter titleFormatter = TitleFormatter.DEFAULT; - - private final int animDelay; - private final int animDuration; - private final int translate; - private final Interpolator interpolator = new DecelerateInterpolator(2f); - - private int orientation = MaterialCalendarView.VERTICAL; + public static final int DEFAULT_ANIMATION_DELAY = 400; + public static final int DEFAULT_Y_TRANSLATION_DP = 20; - private long lastAnimTime = 0; - private CalendarDay previousMonth = null; + private final TextView title; + private final int animDelay; + private final int animDuration; + private final int translate; + private final Interpolator interpolator = new DecelerateInterpolator(2f); + @NonNull + private TitleFormatter titleFormatter = TitleFormatter.DEFAULT; + private int orientation = MaterialCalendarView.VERTICAL; - public TitleChanger(TextView title) { - this.title = title; + private long lastAnimTime = 0; + private CalendarDay previousMonth = null; - Resources res = title.getResources(); + public TitleChanger(TextView title) { + this.title = title; - animDelay = DEFAULT_ANIMATION_DELAY; + Resources res = title.getResources(); - animDuration = res.getInteger(android.R.integer.config_shortAnimTime) / 2; + animDelay = DEFAULT_ANIMATION_DELAY; - translate = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, DEFAULT_Y_TRANSLATION_DP, res.getDisplayMetrics() - ); - } + animDuration = res.getInteger(android.R.integer.config_shortAnimTime) / 2; - public void change(final CalendarDay currentMonth) { - long currentTime = System.currentTimeMillis(); - - if (currentMonth == null) { - return; + translate = (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, DEFAULT_Y_TRANSLATION_DP, res.getDisplayMetrics() + ); } - if (TextUtils.isEmpty(title.getText()) || (currentTime - lastAnimTime) < animDelay) { - doChange(currentTime, currentMonth, false); - } + public void change(final CalendarDay currentMonth) { + long currentTime = System.currentTimeMillis(); - if (currentMonth.equals(previousMonth) || - (currentMonth.getMonth() == previousMonth.getMonth() - && currentMonth.getYear() == previousMonth.getYear())) { - return; - } + if (currentMonth == null) { + return; + } - doChange(currentTime, currentMonth, true); - } + if (TextUtils.isEmpty(title.getText()) || (currentTime - lastAnimTime) < animDelay) { + doChange(currentTime, currentMonth, false); + } - private void doChange(final long now, final CalendarDay currentMonth, boolean animate) { + if (currentMonth.equals(previousMonth) || + (currentMonth.getMonth() == previousMonth.getMonth() + && currentMonth.getYear() == previousMonth.getYear())) { + return; + } - title.animate().cancel(); - doTranslation(title, 0); + doChange(currentTime, currentMonth, true); + } - title.setAlpha(1); - lastAnimTime = now; + private void doChange(final long now, final CalendarDay currentMonth, boolean animate) { - final CharSequence newTitle = titleFormatter.format(currentMonth); + title.animate().cancel(); + doTranslation(title, 0); - if (!animate) { - title.setText(newTitle); - } else { - final int translation = translate * (previousMonth.isBefore(currentMonth) ? 1 : -1); - final ViewPropertyAnimator viewPropertyAnimator = title.animate(); + title.setAlpha(1); + lastAnimTime = now; - if (orientation == MaterialCalendarView.HORIZONTAL) { - viewPropertyAnimator.translationX(translation * -1); - } else { - viewPropertyAnimator.translationY(translation * -1); - } + final CharSequence newTitle = titleFormatter.format(currentMonth); - viewPropertyAnimator - .alpha(0) - .setDuration(animDuration) - .setInterpolator(interpolator) - .setListener(new AnimatorListener() { + if (!animate) { + title.setText(newTitle); + } else { + final int translation = translate * (previousMonth.isBefore(currentMonth) ? 1 : -1); + final ViewPropertyAnimator viewPropertyAnimator = title.animate(); - @Override - public void onAnimationCancel(Animator animator) { - doTranslation(title, 0); - title.setAlpha(1); + if (orientation == MaterialCalendarView.HORIZONTAL) { + viewPropertyAnimator.translationX(translation * -1); + } else { + viewPropertyAnimator.translationY(translation * -1); } - @Override - public void onAnimationEnd(Animator animator) { - title.setText(newTitle); - doTranslation(title, translation); - - final ViewPropertyAnimator viewPropertyAnimator = title.animate(); - if (orientation == MaterialCalendarView.HORIZONTAL) { - viewPropertyAnimator.translationX(0); - } else { - viewPropertyAnimator.translationY(0); - } - - viewPropertyAnimator - .alpha(1) - .setDuration(animDuration) - .setInterpolator(interpolator) - .setListener(new AnimatorListener()) - .start(); - } - }).start(); + viewPropertyAnimator + .alpha(0) + .setDuration(animDuration) + .setInterpolator(interpolator) + .setListener(new AnimatorListener() { + + @Override + public void onAnimationCancel(Animator animator) { + doTranslation(title, 0); + title.setAlpha(1); + } + + @Override + public void onAnimationEnd(Animator animator) { + title.setText(newTitle); + doTranslation(title, translation); + + final ViewPropertyAnimator viewPropertyAnimator = title.animate(); + if (orientation == MaterialCalendarView.HORIZONTAL) { + viewPropertyAnimator.translationX(0); + } else { + viewPropertyAnimator.translationY(0); + } + + viewPropertyAnimator + .alpha(1) + .setDuration(animDuration) + .setInterpolator(interpolator) + .setListener(new AnimatorListener()) + .start(); + } + }).start(); + } + + previousMonth = currentMonth; } - previousMonth = currentMonth; - } - - private void doTranslation(final TextView title, final int translate) { - if (orientation == MaterialCalendarView.HORIZONTAL) { - title.setTranslationX(translate); - } else { - title.setTranslationY(translate); + private void doTranslation(final TextView title, final int translate) { + if (orientation == MaterialCalendarView.HORIZONTAL) { + title.setTranslationX(translate); + } else { + title.setTranslationY(translate); + } } - } - public void setTitleFormatter(@Nullable final TitleFormatter titleFormatter) { - this.titleFormatter = titleFormatter == null ? TitleFormatter.DEFAULT : titleFormatter; - } + public void setTitleFormatter(@Nullable final TitleFormatter titleFormatter) { + this.titleFormatter = titleFormatter == null ? TitleFormatter.DEFAULT : titleFormatter; + } - public void setOrientation(int orientation) { - this.orientation = orientation; - } + public int getOrientation() { + return orientation; + } - public int getOrientation() { - return orientation; - } + public void setOrientation(int orientation) { + this.orientation = orientation; + } - public void setPreviousMonth(CalendarDay previousMonth) { - this.previousMonth = previousMonth; - } + public void setPreviousMonth(CalendarDay previousMonth) { + this.previousMonth = previousMonth; + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/ViolationsDecorator.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/ViolationsDecorator.java new file mode 100644 index 00000000..ab3ba239 --- /dev/null +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/ViolationsDecorator.java @@ -0,0 +1,29 @@ +package com.prolificinteractive.materialcalendarview; + +import android.app.Activity; + +import java.util.Collection; +import java.util.HashSet; + +public class ViolationsDecorator implements DayViewDecorator { + + private int[] color; + private HashSet dates; + private Activity context; + + public ViolationsDecorator(Activity context, int[] color, Collection dates) { + this.color = color; + this.dates = new HashSet<>(dates); + this.context = context; + } + + @Override + public boolean shouldDecorate(CalendarDay day) { + return dates.contains(day); + } + + @Override + public void decorate(DayViewFacade view) { + view.addSpan(new CustomMultipleDotSpan(context, 6, color)); + } +} diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekDayView.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekDayView.java index 9d635b52..e2df64a2 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekDayView.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekDayView.java @@ -3,39 +3,42 @@ import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; -import android.support.annotation.Nullable; -import android.support.v7.widget.AppCompatTextView; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; import android.view.Gravity; + import com.prolificinteractive.materialcalendarview.format.WeekDayFormatter; + import org.threeten.bp.DayOfWeek; /** * Display a day of the week */ -@SuppressLint("ViewConstructor") class WeekDayView extends AppCompatTextView { +@SuppressLint("ViewConstructor") +class WeekDayView extends AppCompatTextView { - private WeekDayFormatter formatter = WeekDayFormatter.DEFAULT; - private DayOfWeek dayOfWeek; + private WeekDayFormatter formatter = WeekDayFormatter.DEFAULT; + private DayOfWeek dayOfWeek; - public WeekDayView(final Context context, final DayOfWeek dayOfWeek) { - super(context); + public WeekDayView(final Context context, final DayOfWeek dayOfWeek) { + super(context); - setGravity(Gravity.CENTER); + setGravity(Gravity.CENTER); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - setTextAlignment(TEXT_ALIGNMENT_CENTER); - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + setTextAlignment(TEXT_ALIGNMENT_CENTER); + } - setDayOfWeek(dayOfWeek); - } + setDayOfWeek(dayOfWeek); + } - public void setWeekDayFormatter(@Nullable final WeekDayFormatter formatter) { - this.formatter = formatter == null ? WeekDayFormatter.DEFAULT : formatter; - setDayOfWeek(dayOfWeek); - } + public void setWeekDayFormatter(@Nullable final WeekDayFormatter formatter) { + this.formatter = formatter == null ? WeekDayFormatter.DEFAULT : formatter; + setDayOfWeek(dayOfWeek); + } - public void setDayOfWeek(final DayOfWeek dayOfWeek) { - this.dayOfWeek = dayOfWeek; - setText(formatter.format(dayOfWeek)); - } + public void setDayOfWeek(final DayOfWeek dayOfWeek) { + this.dayOfWeek = dayOfWeek; + setText(formatter.format(dayOfWeek)); + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekPagerAdapter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekPagerAdapter.java index 413038da..227bfe17 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekPagerAdapter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekPagerAdapter.java @@ -1,6 +1,7 @@ package com.prolificinteractive.materialcalendarview; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; + import org.threeten.bp.DayOfWeek; import org.threeten.bp.LocalDate; import org.threeten.bp.temporal.ChronoUnit; @@ -8,78 +9,81 @@ public class WeekPagerAdapter extends CalendarPagerAdapter { - public WeekPagerAdapter(MaterialCalendarView mcv) { - super(mcv); - } - - @Override - protected WeekView createView(int position) { - return new WeekView(mcv, getItem(position), mcv.getFirstDayOfWeek(), showWeekDays); - } - - @Override - protected int indexOf(WeekView view) { - CalendarDay week = view.getFirstViewDay(); - return getRangeIndex().indexOf(week); - } - - @Override - protected boolean isInstanceOfView(Object object) { - return object instanceof WeekView; - } - - @Override - protected DateRangeIndex createRangeIndex(CalendarDay min, CalendarDay max) { - return new Weekly(min, max, mcv.getFirstDayOfWeek()); - } - - public static class Weekly implements DateRangeIndex { - - /** - * Minimum day of the first week to display. - */ - private final CalendarDay min; - - /** - * Number of weeks to show. - */ - private final int count; - - /** - * First day of the week to base the weeks on. - */ - private final DayOfWeek firstDayOfWeek; - - public Weekly( - @NonNull final CalendarDay min, - @NonNull final CalendarDay max, - final DayOfWeek firstDayOfWeek) { - this.firstDayOfWeek = firstDayOfWeek; - this.min = getFirstDayOfWeek(min); - this.count = indexOf(max) + 1; + public WeekPagerAdapter(MaterialCalendarView mcv) { + super(mcv); + } + + @Override + protected WeekView createView(int position) { + return new WeekView(mcv, getItem(position), mcv.getFirstDayOfWeek(), showWeekDays); } - @Override public int getCount() { - return count; + @Override + protected int indexOf(WeekView view) { + CalendarDay week = view.getFirstViewDay(); + return getRangeIndex().indexOf(week); } - @Override public int indexOf(final CalendarDay day) { - final WeekFields weekFields = WeekFields.of(firstDayOfWeek, 1); - final LocalDate temp = day.getDate().with(weekFields.dayOfWeek(), 1L); - return (int) ChronoUnit.WEEKS.between(min.getDate(), temp); + @Override + protected boolean isInstanceOfView(Object object) { + return object instanceof WeekView; } - @Override public CalendarDay getItem(final int position) { - return CalendarDay.from(min.getDate().plusWeeks(position)); + @Override + protected DateRangeIndex createRangeIndex(CalendarDay min, CalendarDay max) { + return new Weekly(min, max, mcv.getFirstDayOfWeek()); } - /** - * Getting the first day of a week for a specific date based on a specific week day as first - * day. - */ - private CalendarDay getFirstDayOfWeek(@NonNull final CalendarDay day) { - final LocalDate temp = day.getDate().with(WeekFields.of(firstDayOfWeek, 1).dayOfWeek(), 1L); - return CalendarDay.from(temp); + public static class Weekly implements DateRangeIndex { + + /** + * Minimum day of the first week to display. + */ + private final CalendarDay min; + + /** + * Number of weeks to show. + */ + private final int count; + + /** + * First day of the week to base the weeks on. + */ + private final DayOfWeek firstDayOfWeek; + + public Weekly( + @NonNull final CalendarDay min, + @NonNull final CalendarDay max, + final DayOfWeek firstDayOfWeek) { + this.firstDayOfWeek = firstDayOfWeek; + this.min = getFirstDayOfWeek(min); + this.count = indexOf(max) + 1; + } + + @Override + public int getCount() { + return count; + } + + @Override + public int indexOf(final CalendarDay day) { + final WeekFields weekFields = WeekFields.of(firstDayOfWeek, 1); + final LocalDate temp = day.getDate().with(weekFields.dayOfWeek(), 1L); + return (int) ChronoUnit.WEEKS.between(min.getDate(), temp); + } + + @Override + public CalendarDay getItem(final int position) { + return CalendarDay.from(min.getDate().plusWeeks(position)); + } + + /** + * Getting the first day of a week for a specific date based on a specific week day as first + * day. + */ + private CalendarDay getFirstDayOfWeek(@NonNull final CalendarDay day) { + final LocalDate temp = day.getDate().with(WeekFields.of(firstDayOfWeek, 1).dayOfWeek(), 1L); + return CalendarDay.from(temp); + } } - } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekView.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekView.java index b9b87adb..d76a8dd8 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekView.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/WeekView.java @@ -1,8 +1,10 @@ package com.prolificinteractive.materialcalendarview; import android.annotation.SuppressLint; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; + import java.util.Collection; + import org.threeten.bp.DayOfWeek; import org.threeten.bp.LocalDate; @@ -10,31 +12,35 @@ * Display a week of {@linkplain DayView}s and * seven {@linkplain WeekDayView}s. */ -@SuppressLint("ViewConstructor") class WeekView extends CalendarPagerView { - - public WeekView( - @NonNull final MaterialCalendarView view, - final CalendarDay firstViewDay, - final DayOfWeek firstDayOfWeek, - final boolean showWeekDays) { - super(view, firstViewDay, firstDayOfWeek, showWeekDays); - } - - @Override protected void buildDayViews( - final Collection dayViews, - final LocalDate calendar) { - LocalDate temp = calendar; - for (int i = 0; i < DEFAULT_DAYS_IN_WEEK; i++) { - addDayView(dayViews, temp); - temp = temp.plusDays(1); +@SuppressLint("ViewConstructor") +class WeekView extends CalendarPagerView { + + public WeekView( + @NonNull final MaterialCalendarView view, + final CalendarDay firstViewDay, + final DayOfWeek firstDayOfWeek, + final boolean showWeekDays) { + super(view, firstViewDay, firstDayOfWeek, showWeekDays); } - } - @Override protected boolean isDayEnabled(CalendarDay day) { - return true; - } + @Override + protected void buildDayViews( + final Collection dayViews, + final LocalDate calendar) { + LocalDate temp = calendar; + for (int i = 0; i < DEFAULT_DAYS_IN_WEEK; i++) { + addDayView(dayViews, temp); + temp = temp.plusDays(1); + } + } - @Override protected int getRows() { - return showWeekDays ? DAY_NAMES_ROW + 1 : 1; - } + @Override + protected boolean isDayEnabled(CalendarDay day) { + return true; + } + + @Override + protected int getRows() { + return showWeekDays ? DAY_NAMES_ROW + 1 : 1; + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/ArrayWeekDayFormatter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/ArrayWeekDayFormatter.java index f3e052cd..71edc04a 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/ArrayWeekDayFormatter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/ArrayWeekDayFormatter.java @@ -7,25 +7,26 @@ */ public class ArrayWeekDayFormatter implements WeekDayFormatter { - private final CharSequence[] weekDayLabels; + private final CharSequence[] weekDayLabels; - /** - * @param weekDayLabels an array of 7 labels, starting with Sunday - */ - public ArrayWeekDayFormatter(final CharSequence[] weekDayLabels) { - if (weekDayLabels == null) { - throw new IllegalArgumentException("Cannot be null"); + /** + * @param weekDayLabels an array of 7 labels, starting with Sunday + */ + public ArrayWeekDayFormatter(final CharSequence[] weekDayLabels) { + if (weekDayLabels == null) { + throw new IllegalArgumentException("Cannot be null"); + } + if (weekDayLabels.length != 7) { + throw new IllegalArgumentException("Array must contain exactly 7 elements"); + } + this.weekDayLabels = weekDayLabels; } - if (weekDayLabels.length != 7) { - throw new IllegalArgumentException("Array must contain exactly 7 elements"); - } - this.weekDayLabels = weekDayLabels; - } - /** - * {@inheritDoc} - */ - @Override public CharSequence format(final DayOfWeek dayOfWeek) { - return weekDayLabels[dayOfWeek.getValue() - 1]; - } + /** + * {@inheritDoc} + */ + @Override + public CharSequence format(final DayOfWeek dayOfWeek) { + return weekDayLabels[dayOfWeek.getValue() - 1]; + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/CalendarWeekDayFormatter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/CalendarWeekDayFormatter.java index 246964ae..5378b6ac 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/CalendarWeekDayFormatter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/CalendarWeekDayFormatter.java @@ -1,6 +1,7 @@ package com.prolificinteractive.materialcalendarview.format; import java.util.Locale; + import org.threeten.bp.DayOfWeek; import org.threeten.bp.format.TextStyle; @@ -10,10 +11,11 @@ * @see java.time.DayOfWeek#getDisplayName(java.time.format.TextStyle, Locale) */ public final class CalendarWeekDayFormatter implements WeekDayFormatter { - /** - * {@inheritDoc} - */ - @Override public CharSequence format(final DayOfWeek dayOfWeek) { - return dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.getDefault()); - } + /** + * {@inheritDoc} + */ + @Override + public CharSequence format(final DayOfWeek dayOfWeek) { + return dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.getDefault()); + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DateFormatDayFormatter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DateFormatDayFormatter.java index cd8e1d37..dd0dcfa2 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DateFormatDayFormatter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DateFormatDayFormatter.java @@ -1,38 +1,83 @@ package com.prolificinteractive.materialcalendarview.format; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; + import com.prolificinteractive.materialcalendarview.CalendarDay; + import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Locale; -import org.threeten.bp.format.DateTimeFormatter; /** * Format using a {@linkplain DateFormat} instance. */ public class DateFormatDayFormatter implements DayFormatter { - private final DateTimeFormatter dateFormat; - - /** - * Format using a default format - */ - public DateFormatDayFormatter() { - this(DateTimeFormatter.ofPattern(DEFAULT_FORMAT, Locale.getDefault())); - } - - /** - * Format using a specific {@linkplain DateFormat} - * - * @param format the format to use - */ - public DateFormatDayFormatter(@NonNull final DateTimeFormatter format) { - this.dateFormat = format; - } - - /** - * {@inheritDoc} - */ - @Override @NonNull public String format(@NonNull final CalendarDay day) { - return dateFormat.format(day.getDate()); - } + //create singleton instance from DateFormatDayFormatter to avoid creating redundant instance for each DayView. + private static DateFormatDayFormatter dateFormatDayFormatter; + private DateFormat dateFormat; + private Locale lastKnownLocal; + + + /** + * Format using a default format + */ + private DateFormatDayFormatter() { + this.dateFormat = new SimpleDateFormat("d", Locale.getDefault()); + this.lastKnownLocal = Locale.getDefault(); + } + + /** + * Format using a specific {@linkplain DateFormat} + * + * @param format the format to use + */ + private DateFormatDayFormatter(@NonNull final DateFormat format) { + this.dateFormat = format; + } + + public static DateFormatDayFormatter getInstance() { + if (dateFormatDayFormatter == null) + dateFormatDayFormatter = new DateFormatDayFormatter(); + else { + //if user change local and resume the activity the calender now will draw DayView text with the new Local. + Locale currentLocal = Locale.getDefault(); + if (!dateFormatDayFormatter.getLastKnownLocal().equals(currentLocal)) { + dateFormatDayFormatter.setLastKnownLocal(currentLocal); + dateFormatDayFormatter.setDateFormat(new SimpleDateFormat("d", currentLocal)); + } + } + return dateFormatDayFormatter; + } + + /** + * {@inheritDoc} + */ + public Locale getLastKnownLocal() { + return lastKnownLocal; + } + + public void setLastKnownLocal(Locale lastKnownLocal) { + this.lastKnownLocal = lastKnownLocal; + } + + public DateFormat getDateFormat() { + return dateFormat; + } + + public void setDateFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + + @Override + @NonNull + public String format(@NonNull final CalendarDay day) { + try { + return dateFormat.format(new SimpleDateFormat("yyyy-MM-dd").parse(day.getDate().toString())); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DateFormatTitleFormatter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DateFormatTitleFormatter.java index 3ba646c2..78901cfa 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DateFormatTitleFormatter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DateFormatTitleFormatter.java @@ -1,6 +1,7 @@ package com.prolificinteractive.materialcalendarview.format; import com.prolificinteractive.materialcalendarview.CalendarDay; + import org.threeten.bp.format.DateTimeFormatter; /** @@ -8,28 +9,29 @@ */ public class DateFormatTitleFormatter implements TitleFormatter { - private final DateTimeFormatter dateFormat; + private final DateTimeFormatter dateFormat; - /** - * Format using {@link TitleFormatter#DEFAULT_FORMAT} for formatting. - */ - public DateFormatTitleFormatter() { - this(DateTimeFormatter.ofPattern(DEFAULT_FORMAT)); - } + /** + * Format using {@link TitleFormatter#DEFAULT_FORMAT} for formatting. + */ + public DateFormatTitleFormatter() { + this(DateTimeFormatter.ofPattern(DEFAULT_FORMAT)); + } - /** - * Format using a specified {@linkplain DateTimeFormatter} - * - * @param format the format to use - */ - public DateFormatTitleFormatter(final DateTimeFormatter format) { - this.dateFormat = format; - } + /** + * Format using a specified {@linkplain DateTimeFormatter} + * + * @param format the format to use + */ + public DateFormatTitleFormatter(final DateTimeFormatter format) { + this.dateFormat = format; + } - /** - * {@inheritDoc} - */ - @Override public CharSequence format(final CalendarDay day) { - return dateFormat.format(day.getDate()); - } + /** + * {@inheritDoc} + */ + @Override + public CharSequence format(final CalendarDay day) { + return dateFormat.format(day.getDate()); + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DayFormatter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DayFormatter.java index 69fc11b8..b5950443 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DayFormatter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/DayFormatter.java @@ -1,7 +1,9 @@ package com.prolificinteractive.materialcalendarview.format; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; + import com.prolificinteractive.materialcalendarview.CalendarDay; + import java.text.SimpleDateFormat; /** @@ -9,21 +11,21 @@ */ public interface DayFormatter { - /** - * Default format for displaying the day. - */ - String DEFAULT_FORMAT = "d"; + /** + * Default format for displaying the day. + */ + String DEFAULT_FORMAT = "d"; - /** - * Default implementation used by {@linkplain com.prolificinteractive.materialcalendarview.MaterialCalendarView} - */ - DayFormatter DEFAULT = new DateFormatDayFormatter(); + /** + * Default implementation used by {@linkplain com.prolificinteractive.materialcalendarview.MaterialCalendarView} + */ - /** - * Format a given day into a string - * - * @param day the day - * @return a label for the day - */ - @NonNull String format(@NonNull CalendarDay day); + /** + * Format a given day into a string + * + * @param day the day + * @return a label for the day + */ + @NonNull + String format(@NonNull CalendarDay day); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/MonthArrayTitleFormatter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/MonthArrayTitleFormatter.java index dfd58600..c1641bb7 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/MonthArrayTitleFormatter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/MonthArrayTitleFormatter.java @@ -1,6 +1,7 @@ package com.prolificinteractive.materialcalendarview.format; import android.text.SpannableStringBuilder; + import com.prolificinteractive.materialcalendarview.CalendarDay; /** @@ -8,31 +9,31 @@ */ public class MonthArrayTitleFormatter implements TitleFormatter { - private final CharSequence[] monthLabels; + private final CharSequence[] monthLabels; - /** - * Format using an array of month labels - * - * @param monthLabels an array of 12 labels to use for months, starting with January - */ - public MonthArrayTitleFormatter(CharSequence[] monthLabels) { - if (monthLabels == null) { - throw new IllegalArgumentException("Label array cannot be null"); - } - if (monthLabels.length < 12) { - throw new IllegalArgumentException("Label array is too short"); + /** + * Format using an array of month labels + * + * @param monthLabels an array of 12 labels to use for months, starting with January + */ + public MonthArrayTitleFormatter(CharSequence[] monthLabels) { + if (monthLabels == null) { + throw new IllegalArgumentException("Label array cannot be null"); + } + if (monthLabels.length < 12) { + throw new IllegalArgumentException("Label array is too short"); + } + this.monthLabels = monthLabels; } - this.monthLabels = monthLabels; - } - /** - * {@inheritDoc} - */ - @Override - public CharSequence format(CalendarDay day) { - return new SpannableStringBuilder() - .append(monthLabels[day.getMonth() - 1]) - .append(" ") - .append(String.valueOf(day.getYear())); - } + /** + * {@inheritDoc} + */ + @Override + public CharSequence format(CalendarDay day) { + return new SpannableStringBuilder() + .append(monthLabels[day.getMonth() - 1]) + .append(" ") + .append(String.valueOf(day.getYear())); + } } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/TitleFormatter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/TitleFormatter.java index 9f2d0d9c..ba8cc6a0 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/TitleFormatter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/TitleFormatter.java @@ -7,15 +7,15 @@ */ public interface TitleFormatter { - String DEFAULT_FORMAT = "LLLL yyyy"; + String DEFAULT_FORMAT = "LLLL yyyy"; - TitleFormatter DEFAULT = new DateFormatTitleFormatter(); + TitleFormatter DEFAULT = new DateFormatTitleFormatter(); - /** - * Converts the supplied day to a suitable month/year title - * - * @param day the day containing relevant month and year information - * @return a label to display for the given month/year - */ - CharSequence format(CalendarDay day); + /** + * Converts the supplied day to a suitable month/year title + * + * @param day the day containing relevant month and year information + * @return a label to display for the given month/year + */ + CharSequence format(CalendarDay day); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/WeekDayFormatter.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/WeekDayFormatter.java index 0546ed3b..229bec71 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/format/WeekDayFormatter.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/format/WeekDayFormatter.java @@ -6,16 +6,16 @@ * Supply labels for a given day of the week. */ public interface WeekDayFormatter { - /** - * Convert a given day of the week into a label. - * - * @param dayOfWeek the day of the week as returned by {@linkplain DayOfWeek#getValue()}. - * @return a label for the day of week. - */ - CharSequence format(DayOfWeek dayOfWeek); + /** + * Default implementation used by {@linkplain com.prolificinteractive.materialcalendarview.MaterialCalendarView} + */ + WeekDayFormatter DEFAULT = new CalendarWeekDayFormatter(); - /** - * Default implementation used by {@linkplain com.prolificinteractive.materialcalendarview.MaterialCalendarView} - */ - WeekDayFormatter DEFAULT = new CalendarWeekDayFormatter(); + /** + * Convert a given day of the week into a label. + * + * @param dayOfWeek the day of the week as returned by {@linkplain DayOfWeek#getValue()}. + * @return a label for the day of week. + */ + CharSequence format(DayOfWeek dayOfWeek); } diff --git a/library/src/main/java/com/prolificinteractive/materialcalendarview/spans/DotSpan.java b/library/src/main/java/com/prolificinteractive/materialcalendarview/spans/DotSpan.java index f1a78d50..421f10f5 100644 --- a/library/src/main/java/com/prolificinteractive/materialcalendarview/spans/DotSpan.java +++ b/library/src/main/java/com/prolificinteractive/materialcalendarview/spans/DotSpan.java @@ -9,71 +9,71 @@ */ public class DotSpan implements LineBackgroundSpan { - /** - * Default radius used - */ - public static final float DEFAULT_RADIUS = 3; + /** + * Default radius used + */ + public static final float DEFAULT_RADIUS = 3; - private final float radius; - private final int color; + private final float radius; + private final int color; - /** - * Create a span to draw a dot using default radius and color - * - * @see #DotSpan(float, int) - * @see #DEFAULT_RADIUS - */ - public DotSpan() { - this.radius = DEFAULT_RADIUS; - this.color = 0; - } + /** + * Create a span to draw a dot using default radius and color + * + * @see #DotSpan(float, int) + * @see #DEFAULT_RADIUS + */ + public DotSpan() { + this.radius = DEFAULT_RADIUS; + this.color = 0; + } - /** - * Create a span to draw a dot using a specified color - * - * @param color color of the dot - * @see #DotSpan(float, int) - * @see #DEFAULT_RADIUS - */ - public DotSpan(int color) { - this.radius = DEFAULT_RADIUS; - this.color = color; - } + /** + * Create a span to draw a dot using a specified color + * + * @param color color of the dot + * @see #DotSpan(float, int) + * @see #DEFAULT_RADIUS + */ + public DotSpan(int color) { + this.radius = DEFAULT_RADIUS; + this.color = color; + } - /** - * Create a span to draw a dot using a specified radius - * - * @param radius radius for the dot - * @see #DotSpan(float, int) - */ - public DotSpan(float radius) { - this.radius = radius; - this.color = 0; - } + /** + * Create a span to draw a dot using a specified radius + * + * @param radius radius for the dot + * @see #DotSpan(float, int) + */ + public DotSpan(float radius) { + this.radius = radius; + this.color = 0; + } - /** - * Create a span to draw a dot using a specified radius and color - * - * @param radius radius for the dot - * @param color color of the dot - */ - public DotSpan(float radius, int color) { - this.radius = radius; - this.color = color; - } + /** + * Create a span to draw a dot using a specified radius and color + * + * @param radius radius for the dot + * @param color color of the dot + */ + public DotSpan(float radius, int color) { + this.radius = radius; + this.color = color; + } - @Override - public void drawBackground( - Canvas canvas, Paint paint, - int left, int right, int top, int baseline, int bottom, - CharSequence charSequence, - int start, int end, int lineNum - ) { - int oldColor = paint.getColor(); - if (color != 0) { - paint.setColor(color); + @Override + public void drawBackground( + Canvas canvas, Paint paint, + int left, int right, int top, int baseline, int bottom, + CharSequence charSequence, + int start, int end, int lineNum + ) { + int oldColor = paint.getColor(); + if (color != 0) { + paint.setColor(color); + } + canvas.drawCircle((left + right) / 2, bottom + radius, radius, paint); + paint.setColor(oldColor); } - canvas.drawCircle((left + right) / 2, bottom + radius, radius, paint); - paint.setColor(oldColor); - } } diff --git a/library/src/main/res/color/mcv_text_date_dark.xml b/library/src/main/res/color/mcv_text_date_dark.xml index a7d96ea0..7450bd47 100644 --- a/library/src/main/res/color/mcv_text_date_dark.xml +++ b/library/src/main/res/color/mcv_text_date_dark.xml @@ -1,15 +1,13 @@ - + - + - + - + - + diff --git a/library/src/main/res/color/mcv_text_date_light.xml b/library/src/main/res/color/mcv_text_date_light.xml index 48c42272..1190744b 100644 --- a/library/src/main/res/color/mcv_text_date_light.xml +++ b/library/src/main/res/color/mcv_text_date_light.xml @@ -1,15 +1,13 @@ - + - + - + - + - + diff --git a/library/src/main/res/drawable-ldrtl/mcv_action_next.xml b/library/src/main/res/drawable-ldrtl/mcv_action_next.xml index 0b624e03..318f41f3 100644 --- a/library/src/main/res/drawable-ldrtl/mcv_action_next.xml +++ b/library/src/main/res/drawable-ldrtl/mcv_action_next.xml @@ -1,11 +1,9 @@ - + android:viewportHeight="24.0"> + diff --git a/library/src/main/res/drawable-ldrtl/mcv_action_previous.xml b/library/src/main/res/drawable-ldrtl/mcv_action_previous.xml index 9080087f..d441199c 100644 --- a/library/src/main/res/drawable-ldrtl/mcv_action_previous.xml +++ b/library/src/main/res/drawable-ldrtl/mcv_action_previous.xml @@ -1,11 +1,9 @@ - + android:viewportHeight="24.0"> + diff --git a/library/src/main/res/drawable/blue_circle.xml b/library/src/main/res/drawable/blue_circle.xml new file mode 100644 index 00000000..38d8c968 --- /dev/null +++ b/library/src/main/res/drawable/blue_circle.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/library/src/main/res/drawable/calendar_selector.xml b/library/src/main/res/drawable/calendar_selector.xml new file mode 100644 index 00000000..a9997e9a --- /dev/null +++ b/library/src/main/res/drawable/calendar_selector.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/library/src/main/res/drawable/gray_circle.xml b/library/src/main/res/drawable/gray_circle.xml new file mode 100644 index 00000000..8f8a51cf --- /dev/null +++ b/library/src/main/res/drawable/gray_circle.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/library/src/main/res/drawable/mcv_action_next.xml b/library/src/main/res/drawable/mcv_action_next.xml index 9080087f..d441199c 100644 --- a/library/src/main/res/drawable/mcv_action_next.xml +++ b/library/src/main/res/drawable/mcv_action_next.xml @@ -1,11 +1,9 @@ - + android:viewportHeight="24.0"> + diff --git a/library/src/main/res/drawable/mcv_action_previous.xml b/library/src/main/res/drawable/mcv_action_previous.xml index 0b624e03..318f41f3 100644 --- a/library/src/main/res/drawable/mcv_action_previous.xml +++ b/library/src/main/res/drawable/mcv_action_previous.xml @@ -1,11 +1,9 @@ - + android:viewportHeight="24.0"> + diff --git a/library/src/main/res/layout/calendar_view.xml b/library/src/main/res/layout/calendar_view.xml index 4d8a2420..73300de9 100644 --- a/library/src/main/res/layout/calendar_view.xml +++ b/library/src/main/res/layout/calendar_view.xml @@ -6,40 +6,36 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" - android:orientation="horizontal" - > + android:orientation="horizontal"> - + - + - + \ No newline at end of file diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index 7cf664ba..87eb3441 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -1,70 +1,70 @@ - + - - - + + + - - - + + + - - - - - - - - + + + + + + + + - - + + - - + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - + + + + - - - - - - + + + + + + - - - - - + + + + + diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml index 69a44add..18715a9f 100644 --- a/library/src/main/res/values/dimens.xml +++ b/library/src/main/res/values/dimens.xml @@ -1,5 +1,5 @@ - 4dp - 4dp + 4dp + 4dp diff --git a/library/src/main/res/values/ids.xml b/library/src/main/res/values/ids.xml index cb6dcb22..e730c3de 100644 --- a/library/src/main/res/values/ids.xml +++ b/library/src/main/res/values/ids.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml index 05a93ca3..549c67f7 100644 --- a/library/src/main/res/values/strings.xml +++ b/library/src/main/res/values/strings.xml @@ -1,6 +1,6 @@ - Go to previous - Go to next - Calendar + Go to previous + Go to next + Calendar diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index 70c5be03..4087ee2a 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -1,20 +1,17 @@ - + - + - + \ No newline at end of file diff --git a/library/src/test/java/com/prolificinteractive/materialcalendarview/MonthlyRangeIndexTest.java b/library/src/test/java/com/prolificinteractive/materialcalendarview/MonthlyRangeIndexTest.java index ceb160ff..4d00b893 100644 --- a/library/src/test/java/com/prolificinteractive/materialcalendarview/MonthlyRangeIndexTest.java +++ b/library/src/test/java/com/prolificinteractive/materialcalendarview/MonthlyRangeIndexTest.java @@ -16,119 +16,126 @@ public class MonthlyRangeIndexTest { - @Test public void test400Years() { - final CalendarDay january1816 = CalendarDay.from(1816, JANUARY.getValue(), 15); - final CalendarDay january2216 = CalendarDay.from(2216, JANUARY.getValue(), 15); - final CalendarDay april2018 = CalendarDay.from(2018, APRIL.getValue(), 1); - final CalendarDay february1816 = CalendarDay.from(1816, FEBRUARY.getValue(), 1); + @Test + public void test400Years() { + final CalendarDay january1816 = CalendarDay.from(1816, JANUARY.getValue(), 15); + final CalendarDay january2216 = CalendarDay.from(2216, JANUARY.getValue(), 15); + final CalendarDay april2018 = CalendarDay.from(2018, APRIL.getValue(), 1); + final CalendarDay february1816 = CalendarDay.from(1816, FEBRUARY.getValue(), 1); - final MonthPagerAdapter.Monthly monthly = - new MonthPagerAdapter.Monthly(january1816, january2216); + final MonthPagerAdapter.Monthly monthly = + new MonthPagerAdapter.Monthly(january1816, january2216); - assertThat(monthly.getCount(), equalTo((2216 - 1816) * 12 + 1)); + assertThat(monthly.getCount(), equalTo((2216 - 1816) * 12 + 1)); - assertThat(monthly.getItem((2018 - 1816) * 12 + 3), equalTo(april2018)); - assertThat(monthly.getItem(1), equalTo(february1816)); + assertThat(monthly.getItem((2018 - 1816) * 12 + 3), equalTo(april2018)); + assertThat(monthly.getItem(1), equalTo(february1816)); - assertThat(monthly.indexOf(january1816), equalTo(0)); - assertThat(monthly.indexOf(february1816), equalTo(1)); - assertThat(monthly.indexOf(april2018), equalTo((2018 - 1816) * 12 + 3)); - assertThat(monthly.indexOf(january2216), equalTo((2216 - 1816) * 12)); - } + assertThat(monthly.indexOf(january1816), equalTo(0)); + assertThat(monthly.indexOf(february1816), equalTo(1)); + assertThat(monthly.indexOf(april2018), equalTo((2018 - 1816) * 12 + 3)); + assertThat(monthly.indexOf(january2216), equalTo((2216 - 1816) * 12)); + } - @Test public void test3Years() { - final CalendarDay may2016 = CalendarDay.from(2016, MAY.getValue(), 6); - final CalendarDay april2017 = CalendarDay.from(2017, MAY.getValue(), 1); - final CalendarDay june2019 = CalendarDay.from(2019, JUNE.getValue(), 1); - final CalendarDay july2019 = CalendarDay.from(2019, JULY.getValue(), 21); + @Test + public void test3Years() { + final CalendarDay may2016 = CalendarDay.from(2016, MAY.getValue(), 6); + final CalendarDay april2017 = CalendarDay.from(2017, MAY.getValue(), 1); + final CalendarDay june2019 = CalendarDay.from(2019, JUNE.getValue(), 1); + final CalendarDay july2019 = CalendarDay.from(2019, JULY.getValue(), 21); - final MonthPagerAdapter.Monthly monthly = new MonthPagerAdapter.Monthly(may2016, july2019); + final MonthPagerAdapter.Monthly monthly = new MonthPagerAdapter.Monthly(may2016, july2019); - assertThat(monthly.getCount(), equalTo((2019 - 2016) * 12 + 3)); + assertThat(monthly.getCount(), equalTo((2019 - 2016) * 12 + 3)); - assertThat(monthly.getItem(12), equalTo(april2017)); - assertThat(monthly.getItem((2019 - 2016) * 12 + 1), equalTo(june2019)); + assertThat(monthly.getItem(12), equalTo(april2017)); + assertThat(monthly.getItem((2019 - 2016) * 12 + 1), equalTo(june2019)); - assertThat(monthly.indexOf(may2016), equalTo(0)); - assertThat(monthly.indexOf(april2017), equalTo(12)); - assertThat(monthly.indexOf(june2019), equalTo((2019 - 2016) * 12 + 1)); - assertThat(monthly.indexOf(july2019), equalTo((2019 - 2016) * 12 + 2)); - } + assertThat(monthly.indexOf(may2016), equalTo(0)); + assertThat(monthly.indexOf(april2017), equalTo(12)); + assertThat(monthly.indexOf(june2019), equalTo((2019 - 2016) * 12 + 1)); + assertThat(monthly.indexOf(july2019), equalTo((2019 - 2016) * 12 + 2)); + } - @Test public void test2Years() { - final CalendarDay may2016 = CalendarDay.from(2016, MAY.getValue(), 31); - final CalendarDay may2018 = CalendarDay.from(2018, MAY.getValue(), 1); + @Test + public void test2Years() { + final CalendarDay may2016 = CalendarDay.from(2016, MAY.getValue(), 31); + final CalendarDay may2018 = CalendarDay.from(2018, MAY.getValue(), 1); - final MonthPagerAdapter.Monthly monthly = new MonthPagerAdapter.Monthly(may2016, may2018); + final MonthPagerAdapter.Monthly monthly = new MonthPagerAdapter.Monthly(may2016, may2018); - assertThat(monthly.getCount(), equalTo(25)); + assertThat(monthly.getCount(), equalTo(25)); - assertThat(monthly.getItem(25), equalTo(CalendarDay.from(2018, JUNE.getValue(), 1))); + assertThat(monthly.getItem(25), equalTo(CalendarDay.from(2018, JUNE.getValue(), 1))); - assertThat(monthly.indexOf(may2016), equalTo(0)); - assertThat(monthly.indexOf(may2018), equalTo((2018 - 2016) * 12)); - } + assertThat(monthly.indexOf(may2016), equalTo(0)); + assertThat(monthly.indexOf(may2018), equalTo((2018 - 2016) * 12)); + } - @Test public void test1Year() { - final CalendarDay january2018 = CalendarDay.from(2018, JANUARY.getValue(), 1); - final CalendarDay december2018 = CalendarDay.from(2018, DECEMBER.getValue(), 31); - final CalendarDay last = CalendarDay.from(2018, DECEMBER.getValue(), 1); + @Test + public void test1Year() { + final CalendarDay january2018 = CalendarDay.from(2018, JANUARY.getValue(), 1); + final CalendarDay december2018 = CalendarDay.from(2018, DECEMBER.getValue(), 31); + final CalendarDay last = CalendarDay.from(2018, DECEMBER.getValue(), 1); - final MonthPagerAdapter.Monthly monthly = - new MonthPagerAdapter.Monthly(january2018, december2018); + final MonthPagerAdapter.Monthly monthly = + new MonthPagerAdapter.Monthly(january2018, december2018); - assertThat(monthly.getCount(), equalTo(12)); + assertThat(monthly.getCount(), equalTo(12)); - assertThat(monthly.getItem(0), equalTo(january2018)); - assertThat(monthly.getItem(11), equalTo(last)); + assertThat(monthly.getItem(0), equalTo(january2018)); + assertThat(monthly.getItem(11), equalTo(last)); - assertThat(monthly.indexOf(january2018), equalTo(0)); - assertThat(monthly.indexOf(last), equalTo(11)); - assertThat(monthly.indexOf(december2018), equalTo(11)); - } + assertThat(monthly.indexOf(january2018), equalTo(0)); + assertThat(monthly.indexOf(last), equalTo(11)); + assertThat(monthly.indexOf(december2018), equalTo(11)); + } - @Test public void test3Months() { - final CalendarDay may2018 = CalendarDay.from(2018, MAY.getValue(), 25); - final CalendarDay june2018 = CalendarDay.from(2018, JUNE.getValue(), 1); - final CalendarDay july2018 = CalendarDay.from(2018, JULY.getValue(), 5); + @Test + public void test3Months() { + final CalendarDay may2018 = CalendarDay.from(2018, MAY.getValue(), 25); + final CalendarDay june2018 = CalendarDay.from(2018, JUNE.getValue(), 1); + final CalendarDay july2018 = CalendarDay.from(2018, JULY.getValue(), 5); - final MonthPagerAdapter.Monthly monthly = new MonthPagerAdapter.Monthly(may2018, july2018); + final MonthPagerAdapter.Monthly monthly = new MonthPagerAdapter.Monthly(may2018, july2018); - assertThat(monthly.getCount(), equalTo(3)); + assertThat(monthly.getCount(), equalTo(3)); - assertThat(monthly.getItem(1), equalTo(june2018)); + assertThat(monthly.getItem(1), equalTo(june2018)); - assertThat(monthly.indexOf(may2018), equalTo(0)); - assertThat(monthly.indexOf(june2018), equalTo(1)); - assertThat(monthly.indexOf(july2018), equalTo(2)); - } + assertThat(monthly.indexOf(may2018), equalTo(0)); + assertThat(monthly.indexOf(june2018), equalTo(1)); + assertThat(monthly.indexOf(july2018), equalTo(2)); + } - @Test public void test2Months() { - final CalendarDay october2018 = CalendarDay.from(2018, OCTOBER.getValue(), 31); - final CalendarDay november2018 = CalendarDay.from(2018, NOVEMBER.getValue(), 1); + @Test + public void test2Months() { + final CalendarDay october2018 = CalendarDay.from(2018, OCTOBER.getValue(), 31); + final CalendarDay november2018 = CalendarDay.from(2018, NOVEMBER.getValue(), 1); - final MonthPagerAdapter.Monthly monthly = - new MonthPagerAdapter.Monthly(october2018, november2018); + final MonthPagerAdapter.Monthly monthly = + new MonthPagerAdapter.Monthly(october2018, november2018); - assertThat(monthly.getCount(), equalTo(2)); + assertThat(monthly.getCount(), equalTo(2)); - assertThat(monthly.getItem(0), equalTo(CalendarDay.from(2018, OCTOBER.getValue(), 1))); - assertThat(monthly.getItem(1), equalTo(CalendarDay.from(2018, NOVEMBER.getValue(), 1))); + assertThat(monthly.getItem(0), equalTo(CalendarDay.from(2018, OCTOBER.getValue(), 1))); + assertThat(monthly.getItem(1), equalTo(CalendarDay.from(2018, NOVEMBER.getValue(), 1))); - assertThat(monthly.indexOf(october2018), equalTo(0)); - assertThat(monthly.indexOf(november2018), equalTo(1)); - } + assertThat(monthly.indexOf(october2018), equalTo(0)); + assertThat(monthly.indexOf(november2018), equalTo(1)); + } - @Test public void test1Month() { - final CalendarDay startOctober2018 = CalendarDay.from(2018, OCTOBER.getValue(), 5); - final CalendarDay endOctober2018 = CalendarDay.from(2018, OCTOBER.getValue(), 25); + @Test + public void test1Month() { + final CalendarDay startOctober2018 = CalendarDay.from(2018, OCTOBER.getValue(), 5); + final CalendarDay endOctober2018 = CalendarDay.from(2018, OCTOBER.getValue(), 25); - final MonthPagerAdapter.Monthly monthly = - new MonthPagerAdapter.Monthly(endOctober2018, endOctober2018); + final MonthPagerAdapter.Monthly monthly = + new MonthPagerAdapter.Monthly(endOctober2018, endOctober2018); - assertThat(monthly.getCount(), equalTo(1)); - assertThat(monthly.getItem(0), equalTo(CalendarDay.from(2018, OCTOBER.getValue(), 1))); - assertThat(monthly.indexOf(startOctober2018), equalTo(0)); - assertThat(monthly.indexOf(endOctober2018), equalTo(0)); - } + assertThat(monthly.getCount(), equalTo(1)); + assertThat(monthly.getItem(0), equalTo(CalendarDay.from(2018, OCTOBER.getValue(), 1))); + assertThat(monthly.indexOf(startOctober2018), equalTo(0)); + assertThat(monthly.indexOf(endOctober2018), equalTo(0)); + } } \ No newline at end of file diff --git a/library/src/test/java/com/prolificinteractive/materialcalendarview/WeeklyRangeIndexTest.java b/library/src/test/java/com/prolificinteractive/materialcalendarview/WeeklyRangeIndexTest.java index 2afdc5fd..763bb970 100644 --- a/library/src/test/java/com/prolificinteractive/materialcalendarview/WeeklyRangeIndexTest.java +++ b/library/src/test/java/com/prolificinteractive/materialcalendarview/WeeklyRangeIndexTest.java @@ -17,139 +17,147 @@ import static org.threeten.bp.Month.MARCH; public class WeeklyRangeIndexTest { - private static final int _2018 = 2018; + private static final int _2018 = 2018; - @Test public void test1week() { - final CalendarDay startJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 7); - final CalendarDay endJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 13); + @Test + public void test1week() { + final CalendarDay startJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 7); + final CalendarDay endJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 13); - final DateRangeIndex weekly = - new WeekPagerAdapter.Weekly(startJanuary2018, endJanuary2018, SUNDAY); + final DateRangeIndex weekly = + new WeekPagerAdapter.Weekly(startJanuary2018, endJanuary2018, SUNDAY); - assertThat(weekly.getCount(), equalTo(1)); + assertThat(weekly.getCount(), equalTo(1)); - assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); + assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); - assertThat(weekly.indexOf(startJanuary2018), equalTo(0)); - assertThat(weekly.indexOf(endJanuary2018), equalTo(0)); - } + assertThat(weekly.indexOf(startJanuary2018), equalTo(0)); + assertThat(weekly.indexOf(endJanuary2018), equalTo(0)); + } - @Test public void test2weeksWith2Days() { - final CalendarDay startJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 13); - final CalendarDay endJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 14); + @Test + public void test2weeksWith2Days() { + final CalendarDay startJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 13); + final CalendarDay endJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 14); - final DateRangeIndex weekly = - new WeekPagerAdapter.Weekly(startJanuary2018, endJanuary2018, SUNDAY); + final DateRangeIndex weekly = + new WeekPagerAdapter.Weekly(startJanuary2018, endJanuary2018, SUNDAY); - assertThat(weekly.getCount(), equalTo(2)); + assertThat(weekly.getCount(), equalTo(2)); - assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); + assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); - assertThat(weekly.indexOf(startJanuary2018), equalTo(0)); - assertThat(weekly.indexOf(endJanuary2018), equalTo(1)); - } + assertThat(weekly.indexOf(startJanuary2018), equalTo(0)); + assertThat(weekly.indexOf(endJanuary2018), equalTo(1)); + } - @Test public void test2weeksWith2DaysWithDifferentFirstDay() { - final CalendarDay startJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 10); - final CalendarDay endJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 11); + @Test + public void test2weeksWith2DaysWithDifferentFirstDay() { + final CalendarDay startJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 10); + final CalendarDay endJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 11); - final DateRangeIndex weekly = - new WeekPagerAdapter.Weekly(startJanuary2018, endJanuary2018, THURSDAY); + final DateRangeIndex weekly = + new WeekPagerAdapter.Weekly(startJanuary2018, endJanuary2018, THURSDAY); - assertThat(weekly.getCount(), equalTo(2)); + assertThat(weekly.getCount(), equalTo(2)); - assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 4))); + assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 4))); - assertThat(weekly.indexOf(startJanuary2018), equalTo(0)); - assertThat(weekly.indexOf(endJanuary2018), equalTo(1)); - } + assertThat(weekly.indexOf(startJanuary2018), equalTo(0)); + assertThat(weekly.indexOf(endJanuary2018), equalTo(1)); + } - @Test public void test1weekStartingDifferentDays() { - final CalendarDay startFebruary2018 = CalendarDay.from(_2018, FEBRUARY.getValue(), 7); - final CalendarDay endFebruary2018 = CalendarDay.from(_2018, FEBRUARY.getValue(), 11); + @Test + public void test1weekStartingDifferentDays() { + final CalendarDay startFebruary2018 = CalendarDay.from(_2018, FEBRUARY.getValue(), 7); + final CalendarDay endFebruary2018 = CalendarDay.from(_2018, FEBRUARY.getValue(), 11); - final DateRangeIndex monday = - new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, MONDAY); - final DateRangeIndex tuesday = - new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, TUESDAY); - final DateRangeIndex wednesday = - new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, WEDNESDAY); - final DateRangeIndex thursday = - new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, THURSDAY); - final DateRangeIndex friday = - new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, FRIDAY); - final DateRangeIndex saturday = - new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, SATURDAY); - final DateRangeIndex sunday = - new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, SUNDAY); + final DateRangeIndex monday = + new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, MONDAY); + final DateRangeIndex tuesday = + new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, TUESDAY); + final DateRangeIndex wednesday = + new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, WEDNESDAY); + final DateRangeIndex thursday = + new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, THURSDAY); + final DateRangeIndex friday = + new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, FRIDAY); + final DateRangeIndex saturday = + new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, SATURDAY); + final DateRangeIndex sunday = + new WeekPagerAdapter.Weekly(startFebruary2018, endFebruary2018, SUNDAY); - assertThat(monday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 5))); - assertThat(tuesday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 6))); - assertThat(wednesday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 7))); - assertThat(thursday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 1))); - assertThat(friday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 2))); - assertThat(saturday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 3))); - assertThat(sunday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 4))); - } + assertThat(monday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 5))); + assertThat(tuesday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 6))); + assertThat(wednesday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 7))); + assertThat(thursday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 1))); + assertThat(friday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 2))); + assertThat(saturday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 3))); + assertThat(sunday.getItem(0), equalTo(CalendarDay.from(_2018, FEBRUARY.getValue(), 4))); + } - @Test public void test2weeks() { - final CalendarDay startJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 9); - final CalendarDay endJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 18); + @Test + public void test2weeks() { + final CalendarDay startJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 9); + final CalendarDay endJanuary2018 = CalendarDay.from(_2018, JANUARY.getValue(), 18); - final DateRangeIndex weekly = - new WeekPagerAdapter.Weekly(startJanuary2018, endJanuary2018, SUNDAY); + final DateRangeIndex weekly = + new WeekPagerAdapter.Weekly(startJanuary2018, endJanuary2018, SUNDAY); - assertThat(weekly.getCount(), equalTo(2)); + assertThat(weekly.getCount(), equalTo(2)); - assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); - assertThat(weekly.getItem(1), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 14))); + assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); + assertThat(weekly.getItem(1), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 14))); - assertThat(weekly.indexOf(startJanuary2018), equalTo(0)); - assertThat(weekly.indexOf(endJanuary2018), equalTo(1)); - } + assertThat(weekly.indexOf(startJanuary2018), equalTo(0)); + assertThat(weekly.indexOf(endJanuary2018), equalTo(1)); + } - @Test public void test10weeks() { - final CalendarDay january2018 = CalendarDay.from(_2018, JANUARY.getValue(), 9); - final CalendarDay march2018 = CalendarDay.from(_2018, MARCH.getValue(), 12); + @Test + public void test10weeks() { + final CalendarDay january2018 = CalendarDay.from(_2018, JANUARY.getValue(), 9); + final CalendarDay march2018 = CalendarDay.from(_2018, MARCH.getValue(), 12); - final DateRangeIndex weekly = new WeekPagerAdapter.Weekly(january2018, march2018, SUNDAY); + final DateRangeIndex weekly = new WeekPagerAdapter.Weekly(january2018, march2018, SUNDAY); - assertThat(weekly.getCount(), equalTo(10)); + assertThat(weekly.getCount(), equalTo(10)); - assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); - assertThat(weekly.getItem(9), equalTo(CalendarDay.from(_2018, MARCH.getValue(), 11))); + assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); + assertThat(weekly.getItem(9), equalTo(CalendarDay.from(_2018, MARCH.getValue(), 11))); - assertThat(weekly.indexOf(january2018), equalTo(0)); - assertThat(weekly.indexOf(march2018), equalTo(9)); - } + assertThat(weekly.indexOf(january2018), equalTo(0)); + assertThat(weekly.indexOf(march2018), equalTo(9)); + } - @Test public void test52weeks() { - final CalendarDay january2018 = CalendarDay.from(_2018, JANUARY.getValue(), 9); - final CalendarDay january2019 = CalendarDay.from(2019, JANUARY.getValue(), 3); + @Test + public void test52weeks() { + final CalendarDay january2018 = CalendarDay.from(_2018, JANUARY.getValue(), 9); + final CalendarDay january2019 = CalendarDay.from(2019, JANUARY.getValue(), 3); - final DateRangeIndex weekly = new WeekPagerAdapter.Weekly(january2018, january2019, SUNDAY); + final DateRangeIndex weekly = new WeekPagerAdapter.Weekly(january2018, january2019, SUNDAY); - assertThat(weekly.getCount(), equalTo(52)); + assertThat(weekly.getCount(), equalTo(52)); - assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); - assertThat(weekly.getItem(51), equalTo(CalendarDay.from(2018, DECEMBER.getValue(), 30))); + assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); + assertThat(weekly.getItem(51), equalTo(CalendarDay.from(2018, DECEMBER.getValue(), 30))); - assertThat(weekly.indexOf(january2018), equalTo(0)); - assertThat(weekly.indexOf(january2019), equalTo(51)); - } + assertThat(weekly.indexOf(january2018), equalTo(0)); + assertThat(weekly.indexOf(january2019), equalTo(51)); + } - @Test public void test1000weeks() { - final CalendarDay january2018 = CalendarDay.from(_2018, JANUARY.getValue(), 11); - final CalendarDay march2037 = CalendarDay.from(2037, MARCH.getValue(), 1); + @Test + public void test1000weeks() { + final CalendarDay january2018 = CalendarDay.from(_2018, JANUARY.getValue(), 11); + final CalendarDay march2037 = CalendarDay.from(2037, MARCH.getValue(), 1); - final DateRangeIndex weekly = new WeekPagerAdapter.Weekly(january2018, march2037, SUNDAY); + final DateRangeIndex weekly = new WeekPagerAdapter.Weekly(january2018, march2037, SUNDAY); - assertThat(weekly.getCount(), equalTo(1000)); + assertThat(weekly.getCount(), equalTo(1000)); - assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); - assertThat(weekly.getItem(999), equalTo(CalendarDay.from(2037, MARCH.getValue(), 1))); + assertThat(weekly.getItem(0), equalTo(CalendarDay.from(_2018, JANUARY.getValue(), 7))); + assertThat(weekly.getItem(999), equalTo(CalendarDay.from(2037, MARCH.getValue(), 1))); - assertThat(weekly.indexOf(january2018), equalTo(0)); - assertThat(weekly.indexOf(march2037), equalTo(999)); - } + assertThat(weekly.indexOf(january2018), equalTo(0)); + assertThat(weekly.indexOf(march2037), equalTo(999)); + } } \ No newline at end of file diff --git a/library/src/test/java/com/prolificinteractive/materialcalendarview/format/CalendarWeekDayFormatterTest.java b/library/src/test/java/com/prolificinteractive/materialcalendarview/format/CalendarWeekDayFormatterTest.java index 132db575..27c2173f 100644 --- a/library/src/test/java/com/prolificinteractive/materialcalendarview/format/CalendarWeekDayFormatterTest.java +++ b/library/src/test/java/com/prolificinteractive/materialcalendarview/format/CalendarWeekDayFormatterTest.java @@ -1,6 +1,7 @@ package com.prolificinteractive.materialcalendarview.format; import java.util.Locale; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -11,44 +12,53 @@ public class CalendarWeekDayFormatterTest { - public CalendarWeekDayFormatter formatter; - public Locale defaultLocaleOriginal; + public CalendarWeekDayFormatter formatter; + public Locale defaultLocaleOriginal; - @Before public void setUp() { - defaultLocaleOriginal = Locale.getDefault(); - Locale.setDefault(Locale.ENGLISH); - formatter = new CalendarWeekDayFormatter(); - } + @Before + public void setUp() { + defaultLocaleOriginal = Locale.getDefault(); + Locale.setDefault(Locale.ENGLISH); + formatter = new CalendarWeekDayFormatter(); + } - @After public void tearDown() { - Locale.setDefault(defaultLocaleOriginal); - } + @After + public void tearDown() { + Locale.setDefault(defaultLocaleOriginal); + } - @Test public void testFormattedDayOfWeek_Sunday() { - assertThat(formatter.format(DayOfWeek.SUNDAY).toString(), is("Sun")); - } + @Test + public void testFormattedDayOfWeek_Sunday() { + assertThat(formatter.format(DayOfWeek.SUNDAY).toString(), is("Sun")); + } - @Test public void testFormattedDayOfWeek_Monday() { - assertThat(formatter.format(DayOfWeek.MONDAY).toString(), is("Mon")); - } + @Test + public void testFormattedDayOfWeek_Monday() { + assertThat(formatter.format(DayOfWeek.MONDAY).toString(), is("Mon")); + } - @Test public void testFormattedDayOfWeek_Tuesday() { - assertThat(formatter.format(DayOfWeek.TUESDAY).toString(), is("Tue")); - } + @Test + public void testFormattedDayOfWeek_Tuesday() { + assertThat(formatter.format(DayOfWeek.TUESDAY).toString(), is("Tue")); + } - @Test public void testFormattedDayOfWeek_Wednesday() { - assertThat(formatter.format(DayOfWeek.WEDNESDAY).toString(), is("Wed")); - } + @Test + public void testFormattedDayOfWeek_Wednesday() { + assertThat(formatter.format(DayOfWeek.WEDNESDAY).toString(), is("Wed")); + } - @Test public void testFormattedDayOfWeek_Thursday() { - assertThat(formatter.format(DayOfWeek.THURSDAY).toString(), is("Thu")); - } + @Test + public void testFormattedDayOfWeek_Thursday() { + assertThat(formatter.format(DayOfWeek.THURSDAY).toString(), is("Thu")); + } - @Test public void testFormattedDayOfWeek_Friday() { - assertThat(formatter.format(DayOfWeek.FRIDAY).toString(), is("Fri")); - } + @Test + public void testFormattedDayOfWeek_Friday() { + assertThat(formatter.format(DayOfWeek.FRIDAY).toString(), is("Fri")); + } - @Test public void shouldReturnCorrectFormattedEnglishTextOfSaturday() { - assertThat(formatter.format(DayOfWeek.SATURDAY).toString(), is("Sat")); - } + @Test + public void shouldReturnCorrectFormattedEnglishTextOfSaturday() { + assertThat(formatter.format(DayOfWeek.SATURDAY).toString(), is("Sat")); + } } \ No newline at end of file diff --git a/sample/.gitignore b/sample/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/sample/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/sample/README.md b/sample/README.md deleted file mode 100644 index fb08c91e..00000000 --- a/sample/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Material CalendarView Sample App -================================ - -The sample app contains a mixture of implementations to help test and debug during development, -and to help new users understand how to implement some functionality. \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle deleted file mode 100644 index 01c0408f..00000000 --- a/sample/build.gradle +++ /dev/null @@ -1,37 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - - defaultConfig { - applicationId "com.prolificinteractive.materialcalendarview.sample" - - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - - versionCode 1 - versionName "1.0" - } - - lintOptions { - abortOnError false - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -dependencies { - // You should use the commented out line below in you're application. - // We depend on the source directly here so that development is easier. - implementation project(':library') - //compile 'com.prolificinteractive:material-calendarview:1.4.3' - - implementation rootProject.ext.threeTenAbp - implementation rootProject.ext.supportAppCompat - implementation rootProject.ext.recyclerviewV7 - implementation rootProject.ext.butterknife - annotationProcessor rootProject.ext.butterknifeCompiler -} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml deleted file mode 100644 index db4839bb..00000000 --- a/sample/src/main/AndroidManifest.xml +++ /dev/null @@ -1,294 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/BasicActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/BasicActivity.java deleted file mode 100644 index e3168c13..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/BasicActivity.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.widget.TextView; -import android.widget.Toast; -import butterknife.BindView; -import butterknife.ButterKnife; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.OnDateLongClickListener; -import com.prolificinteractive.materialcalendarview.OnDateSelectedListener; -import com.prolificinteractive.materialcalendarview.OnMonthChangedListener; -import org.threeten.bp.format.DateTimeFormatter; - -/** - * Shows off the most basic usage - */ -public class BasicActivity extends AppCompatActivity - implements OnDateSelectedListener, OnMonthChangedListener, OnDateLongClickListener { - - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, d MMM yyyy"); - - @BindView(R.id.calendarView) - MaterialCalendarView widget; - - @BindView(R.id.textView) - TextView textView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_basic); - ButterKnife.bind(this); - - widget.setOnDateChangedListener(this); - widget.setOnDateLongClickListener(this); - widget.setOnMonthChangedListener(this); - - //Setup initial text - textView.setText("No Selection"); - } - - @Override - public void onDateSelected( - @NonNull MaterialCalendarView widget, - @NonNull CalendarDay date, - boolean selected) { - textView.setText(selected ? FORMATTER.format(date.getDate()) : "No Selection"); - } - - @Override - public void onDateLongClick(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date) { - final String text = String.format("%s is available", FORMATTER.format(date.getDate())); - Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onMonthChanged(MaterialCalendarView widget, CalendarDay date) { - //noinspection ConstantConditions - getSupportActionBar().setTitle(FORMATTER.format(date.getDate())); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/BasicActivityDecorated.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/BasicActivityDecorated.java deleted file mode 100644 index d67a5b8b..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/BasicActivityDecorated.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.graphics.Color; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import butterknife.BindView; -import butterknife.ButterKnife; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.OnDateSelectedListener; -import com.prolificinteractive.materialcalendarview.sample.decorators.EventDecorator; -import com.prolificinteractive.materialcalendarview.sample.decorators.HighlightWeekendsDecorator; -import com.prolificinteractive.materialcalendarview.sample.decorators.MySelectorDecorator; -import com.prolificinteractive.materialcalendarview.sample.decorators.OneDayDecorator; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import org.threeten.bp.LocalDate; -import org.threeten.bp.Month; - -/** - * Shows off the most basic usage - */ -public class BasicActivityDecorated extends AppCompatActivity implements OnDateSelectedListener { - - private final OneDayDecorator oneDayDecorator = new OneDayDecorator(); - - @BindView(R.id.calendarView) - MaterialCalendarView widget; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_basic); - ButterKnife.bind(this); - - widget.setOnDateChangedListener(this); - widget.setShowOtherDates(MaterialCalendarView.SHOW_ALL); - - final LocalDate instance = LocalDate.now(); - widget.setSelectedDate(instance); - - final LocalDate min = LocalDate.of(instance.getYear(), Month.JANUARY, 1); - final LocalDate max = LocalDate.of(instance.getYear(), Month.DECEMBER, 31); - - widget.state().edit().setMinimumDate(min).setMaximumDate(max).commit(); - - widget.addDecorators( - new MySelectorDecorator(this), - new HighlightWeekendsDecorator(), - oneDayDecorator - ); - - new ApiSimulator().executeOnExecutor(Executors.newSingleThreadExecutor()); - } - - @Override - public void onDateSelected( - @NonNull MaterialCalendarView widget, - @NonNull CalendarDay date, - boolean selected) { - //If you change a decorate, you need to invalidate decorators - oneDayDecorator.setDate(date.getDate()); - widget.invalidateDecorators(); - } - - /** - * Simulate an API call to show how to add decorators - */ - private class ApiSimulator extends AsyncTask> { - - @Override - protected List doInBackground(@NonNull Void... voids) { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - LocalDate temp = LocalDate.now().minusMonths(2); - final ArrayList dates = new ArrayList<>(); - for (int i = 0; i < 30; i++) { - final CalendarDay day = CalendarDay.from(temp); - dates.add(day); - temp = temp.plusDays(5); - } - - return dates; - } - - @Override - protected void onPostExecute(@NonNull List calendarDays) { - super.onPostExecute(calendarDays); - - if (isFinishing()) { - return; - } - - widget.addDecorator(new EventDecorator(Color.RED, calendarDays)); - } - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomTileDimensions.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomTileDimensions.java deleted file mode 100644 index 8d60de5e..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomTileDimensions.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.content.DialogInterface; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.widget.LinearLayout; -import android.widget.NumberPicker; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.DayViewDecorator; -import com.prolificinteractive.materialcalendarview.DayViewFacade; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; - -/** - * Created by maragues on 17/06/16. - */ -public class CustomTileDimensions extends AppCompatActivity { - - @BindView(R.id.calendarView) - MaterialCalendarView widget; - - private int currentTileWidth; - private int currentTileHeight; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_custom_tile); - ButterKnife.bind(this); - - currentTileWidth = MaterialCalendarView.DEFAULT_TILE_SIZE_DP; - currentTileHeight = MaterialCalendarView.DEFAULT_TILE_SIZE_DP; - - widget.addDecorator(new TodayDecorator()); - } - - @OnClick(R.id.custom_tile_match_parent) - public void onMatchParentClick() { - widget.setTileSize(LinearLayout.LayoutParams.MATCH_PARENT); - } - - @OnClick(R.id.custom_tile_width_match_parent) - public void onWidthMatchParentClick() { - widget.setTileWidth(LinearLayout.LayoutParams.MATCH_PARENT); - } - - @OnClick(R.id.custom_tile_height_match_parent) - public void onHeightMatchParentClick() { - widget.setTileHeight(LinearLayout.LayoutParams.MATCH_PARENT); - } - - @OnClick(R.id.custom_tile_width_size) - public void onWidthClick() { - final NumberPicker view = new NumberPicker(this); - view.setMinValue(24); - view.setMaxValue(64); - view.setWrapSelectorWheel(false); - view.setValue(currentTileWidth); - new AlertDialog.Builder(this) - .setView(view) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(@NonNull DialogInterface dialog, int which) { - currentTileWidth = view.getValue(); - widget.setTileWidthDp(currentTileWidth); - } - }) - .show(); - } - - @OnClick(R.id.custom_tile_height_size) - public void onHeightClick() { - final NumberPicker view = new NumberPicker(this); - view.setMinValue(24); - view.setMaxValue(64); - view.setWrapSelectorWheel(false); - view.setValue(currentTileHeight); - new AlertDialog.Builder(this) - .setView(view) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(@NonNull DialogInterface dialog, int which) { - currentTileHeight = view.getValue(); - widget.setTileHeightDp(currentTileHeight); - } - }) - .show(); - } - - private class TodayDecorator implements DayViewDecorator { - - private final CalendarDay today; - private final Drawable backgroundDrawable; - - public TodayDecorator() { - today = CalendarDay.today(); - backgroundDrawable = getResources().getDrawable(R.drawable.today_circle_background); - } - - @Override - public boolean shouldDecorate(CalendarDay day) { - return today.equals(day); - } - - @Override - public void decorate(DayViewFacade view) { - view.setBackgroundDrawable(backgroundDrawable); - } - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomizeCodeActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomizeCodeActivity.java deleted file mode 100644 index 2cdbda24..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomizeCodeActivity.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.util.TypedValue; -import butterknife.BindView; -import butterknife.ButterKnife; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.CalendarMode; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.format.ArrayWeekDayFormatter; -import com.prolificinteractive.materialcalendarview.format.MonthArrayTitleFormatter; -import org.threeten.bp.DayOfWeek; - -public class CustomizeCodeActivity extends AppCompatActivity { - - @BindView(R.id.calendarView) - MaterialCalendarView widget; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_basic); - ButterKnife.bind(this); - - widget.setShowOtherDates(MaterialCalendarView.SHOW_ALL); - widget.setLeftArrow(R.drawable.ic_arrow_back); - widget.setRightArrow(R.drawable.ic_arrow_forward); - widget.setSelectionColor(getResources().getColor(R.color.sample_primary)); - widget.setWeekDayTextAppearance(R.style.CustomTextAppearance); - widget.setHeaderTextAppearance(R.style.CustomTextAppearance); - widget.setDateTextAppearance(R.style.CustomTextAppearance); - widget.setTitleFormatter(new MonthArrayTitleFormatter(getResources().getTextArray(R.array.custom_months))); - widget.setWeekDayFormatter(new ArrayWeekDayFormatter(getResources().getTextArray(R.array.custom_weekdays))); - widget.setTileSize((int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, - 36, - getResources().getDisplayMetrics() - )); - widget.setTitleAnimationOrientation(MaterialCalendarView.VERTICAL); - - CalendarDay today = CalendarDay.from(2016, 5, 2); - widget.setCurrentDate(today); - widget.setSelectedDate(today); - - widget.state().edit() - .setFirstDayOfWeek(DayOfWeek.WEDNESDAY) - .setMinimumDate(CalendarDay.from(2016, 4, 3)) - .setMaximumDate(CalendarDay.from(2016, 5, 12)) - .setCalendarDisplayMode(CalendarMode.WEEKS) - .commit(); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomizeXmlActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomizeXmlActivity.java deleted file mode 100644 index baf33683..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/CustomizeXmlActivity.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import butterknife.BindView; -import butterknife.ButterKnife; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; - -public class CustomizeXmlActivity extends AppCompatActivity { - - @BindView(R.id.calendarView) - MaterialCalendarView widget; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_customization); - ButterKnife.bind(this); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DialogsActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DialogsActivity.java deleted file mode 100644 index befb6ef9..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DialogsActivity.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.app.AppCompatDialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.OnDateSelectedListener; -import org.threeten.bp.format.DateTimeFormatter; - -/** - * Shows off the most basic usage - */ -public class DialogsActivity extends AppCompatActivity { - - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, d MMM yyyy"); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_dialogs); - ButterKnife.bind(this); - } - - @OnClick(R.id.button_normal_dialog) - void onNormalDialogClick() { - new SimpleDialogFragment().show(getSupportFragmentManager(), "test-normal"); - } - - @OnClick(R.id.button_simple_dialog) - void onSimpleCalendarDialogClick() { - new SimpleCalendarDialogFragment().show(getSupportFragmentManager(), "test-simple-calendar"); - } - - public static class SimpleDialogFragment extends AppCompatDialogFragment { - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.title_activity_dialogs) - .setMessage("Test Dialog") - .setPositiveButton(android.R.string.ok, null) - .create(); - } - } - - public static class SimpleCalendarDialogFragment extends AppCompatDialogFragment - implements OnDateSelectedListener { - - private TextView textView; - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - LayoutInflater inflater = getActivity().getLayoutInflater(); - - //inflate custom layout and get views - //pass null as parent view because will be in dialog layout - View view = inflater.inflate(R.layout.dialog_basic, null); - - textView = view.findViewById(R.id.textView); - - MaterialCalendarView widget = view.findViewById(R.id.calendarView); - - widget.setOnDateChangedListener(this); - - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.title_activity_dialogs) - .setView(view) - .setPositiveButton(android.R.string.ok, null) - .create(); - } - - @Override - public void onDateSelected( - @NonNull MaterialCalendarView widget, - @NonNull CalendarDay date, - boolean selected) { - textView.setText(FORMATTER.format(date.getDate())); - } - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DisableDaysActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DisableDaysActivity.java deleted file mode 100644 index d164553b..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DisableDaysActivity.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import butterknife.BindView; -import butterknife.ButterKnife; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.DayViewDecorator; -import com.prolificinteractive.materialcalendarview.DayViewFacade; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import org.threeten.bp.LocalDate; -import org.threeten.bp.Month; - -/** - * Show off setting min and max dates and disabling individual days - */ -public class DisableDaysActivity extends AppCompatActivity { - - @BindView(R.id.calendarView) MaterialCalendarView widget; - - @Override protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_basic); - ButterKnife.bind(this); - - // Add a decorator to disable prime numbered days - widget.addDecorator(new PrimeDayDisableDecorator()); - // Add a second decorator that explicitly enables days <= 10. This will work because - // decorators are applied in order, and the system allows re-enabling - widget.addDecorator(new EnableOneToTenDecorator()); - - final LocalDate calendar = LocalDate.now(); - widget.setSelectedDate(calendar); - - final LocalDate min = LocalDate.of(calendar.getYear(), Month.JANUARY, 1); - final LocalDate max = LocalDate.of(calendar.getYear() + 1, Month.OCTOBER, 31); - - widget.state().edit() - .setMinimumDate(min) - .setMaximumDate(max) - .commit(); - } - - private static class PrimeDayDisableDecorator implements DayViewDecorator { - - @Override public boolean shouldDecorate(final CalendarDay day) { - return PRIME_TABLE[day.getDay()]; - } - - @Override public void decorate(final DayViewFacade view) { - view.setDaysDisabled(true); - } - - private static boolean[] PRIME_TABLE = { - false, // 0? - false, - true, // 2 - true, // 3 - false, - true, // 5 - false, - true, // 7 - false, - false, - false, - true, // 11 - false, - true, // 13 - false, - false, - false, - true, // 17 - false, - true, // 19 - false, - false, - false, - true, // 23 - false, - false, - false, - false, - false, - true, // 29 - false, - true, // 31 - false, - false, - false, //PADDING - }; - } - - private static class EnableOneToTenDecorator implements DayViewDecorator { - - @Override - public boolean shouldDecorate(CalendarDay day) { - return day.getDay() <= 10; - } - - @Override - public void decorate(DayViewFacade view) { - view.setDaysDisabled(false); - } - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DynamicSettersActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DynamicSettersActivity.java deleted file mode 100644 index 516cdd37..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/DynamicSettersActivity.java +++ /dev/null @@ -1,345 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.app.DatePickerDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.graphics.Color; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.transition.TransitionManager; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.LinearLayout; -import android.widget.NumberPicker; -import android.widget.Toast; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnCheckedChanged; -import butterknife.OnClick; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.CalendarMode; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.OnDateLongClickListener; -import java.util.Random; -import org.threeten.bp.DayOfWeek; -import org.threeten.bp.format.DateTimeFormatter; - -public class DynamicSettersActivity extends AppCompatActivity implements OnDateLongClickListener { - - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, d MMM yyyy"); - - @BindView(R.id.calendarView) MaterialCalendarView widget; - @BindView(R.id.animate_mode_transition) CheckBox animateModeTransition; - @BindView(R.id.parent) ViewGroup parent; - - private int currentTileSize; - private int currentTileWidth; - private int currentTileHeight; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_dynamic_setters); - ButterKnife.bind(this); - - currentTileSize = MaterialCalendarView.DEFAULT_TILE_SIZE_DP; - currentTileWidth = MaterialCalendarView.DEFAULT_TILE_SIZE_DP; - currentTileHeight = MaterialCalendarView.DEFAULT_TILE_SIZE_DP; - - widget.setOnTitleClickListener(new View.OnClickListener() { - @Override - public void onClick(final View view) { - Toast.makeText(DynamicSettersActivity.this, R.string.today, Toast.LENGTH_SHORT).show(); - } - }); - - widget.setOnDateLongClickListener(this); - } - - @OnClick(R.id.button_other_dates) - void onOtherDatesClicked() { - CharSequence[] items = { - "Other Months", - "Out Of Range", - "Decorated Disabled", - "Select days outside month" - }; - final int[] itemValues = { - MaterialCalendarView.SHOW_OTHER_MONTHS, - MaterialCalendarView.SHOW_OUT_OF_RANGE, - MaterialCalendarView.SHOW_DECORATED_DISABLED, - }; - int showOtherDates = widget.getShowOtherDates(); - - boolean[] initSelections = { - MaterialCalendarView.showOtherMonths(showOtherDates), - MaterialCalendarView.showOutOfRange(showOtherDates), - MaterialCalendarView.showDecoratedDisabled(showOtherDates), - widget.allowClickDaysOutsideCurrentMonth() - }; - new AlertDialog.Builder(this) - .setTitle("Show Other Dates") - .setMultiChoiceItems( - items, - initSelections, - new DialogInterface.OnMultiChoiceClickListener() { - @Override - public void onClick(DialogInterface dialog, int which, boolean isChecked) { - if (which < 3) { - int showOtherDates = widget.getShowOtherDates(); - if (isChecked) { - //Set flag - showOtherDates |= itemValues[which]; - } else { - //Unset flag - showOtherDates &= ~itemValues[which]; - } - widget.setShowOtherDates(showOtherDates); - } else if (which == 3) { - widget.setAllowClickDaysOutsideCurrentMonth(isChecked); - } - } - } - ) - .setPositiveButton(android.R.string.ok, null) - .show(); - } - - @OnCheckedChanged(R.id.enable_save_current_position) - void onSaveCurrentPositionChecked(boolean checked) { - widget.state().edit().isCacheCalendarPositionEnabled(checked).commit(); - } - - @OnCheckedChanged(R.id.show_week_days) - void onShowWeekDaysChecked(boolean checked) { - widget.state().edit().setShowWeekDays(checked).commit(); - } - - @OnCheckedChanged(R.id.check_text_appearance) - void onTextAppearanceChecked(boolean checked) { - if (checked) { - widget.setHeaderTextAppearance(R.style.TextAppearance_AppCompat_Large); - widget.setDateTextAppearance(R.style.TextAppearance_AppCompat_Medium); - widget.setWeekDayTextAppearance(R.style.TextAppearance_AppCompat_Medium); - } else { - widget.setHeaderTextAppearance(R.style.TextAppearance_MaterialCalendarWidget_Header); - widget.setDateTextAppearance(R.style.TextAppearance_MaterialCalendarWidget_Date); - widget.setWeekDayTextAppearance(R.style.TextAppearance_MaterialCalendarWidget_WeekDay); - } - widget.setShowOtherDates( - checked ? MaterialCalendarView.SHOW_ALL : MaterialCalendarView.SHOW_NONE); - } - - @OnCheckedChanged(R.id.check_page_enabled) - void onPageEnabledChecked(boolean checked) { - widget.setPagingEnabled(checked); - } - - @OnCheckedChanged(R.id.dynamic_height_enabled) - void onDynamicHeightChecked(boolean checked) { - widget.setDynamicHeightEnabled(checked); - } - - @OnClick(R.id.button_previous) - void onPreviousClicked() { - widget.goToPrevious(); - } - - @OnClick(R.id.button_next) - void onNextClicked() { - widget.goToNext(); - } - - @OnClick(R.id.button_min_date) - void onMinClicked() { - showDatePickerDialog(this, widget.getMinimumDate(), - (view, year, monthOfYear, dayOfMonth) -> - widget.state().edit() - .setMinimumDate(CalendarDay.from(year, monthOfYear + 1, dayOfMonth)) - .commit() - ); - } - - @OnClick(R.id.button_max_date) - void onMaxClicked() { - showDatePickerDialog(this, widget.getMaximumDate(), - (view, year, monthOfYear, dayOfMonth) -> - widget.state().edit() - .setMaximumDate(CalendarDay.from(year, monthOfYear + 1, dayOfMonth)) - .commit() - ); - } - - @OnClick(R.id.button_selected_date) - void onSelectedClicked() { - showDatePickerDialog(this, widget.getSelectedDate(), - (view, year, monthOfYear, dayOfMonth) -> - widget.setSelectedDate(CalendarDay.from(year, monthOfYear + 1, dayOfMonth)) - ); - } - - @OnClick(R.id.button_toggle_topbar) - void onToggleTopBarClicked() { - widget.setTopbarVisible(!widget.getTopbarVisible()); - } - - Random random = new Random(); - - @OnClick(R.id.button_set_colors) - void onColorsClicked() { - int color = Color.HSVToColor(new float[] { - random.nextFloat() * 360, - 1f, - 0.75f - }); - widget.setSelectionColor(color); - } - - @OnClick(R.id.button_set_tile_size) - void onTileSizeClicked() { - final NumberPicker view = new NumberPicker(this); - view.setMinValue(24); - view.setMaxValue(64); - view.setWrapSelectorWheel(false); - view.setValue(currentTileSize); - new AlertDialog.Builder(this) - .setView(view) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(@NonNull DialogInterface dialog, int which) { - currentTileSize = view.getValue(); - widget.setTileSizeDp(currentTileSize); - } - }) - .show(); - } - - @OnClick(R.id.button_set_width_height) - void onTileWidthHeightClicked() { - final LinearLayout layout = new LinearLayout(this); - layout.setOrientation(LinearLayout.HORIZONTAL); - final NumberPicker pickerWidth = new NumberPicker(this); - pickerWidth.setMinValue(24); - pickerWidth.setMaxValue(64); - pickerWidth.setWrapSelectorWheel(false); - pickerWidth.setValue(currentTileWidth); - final NumberPicker pickerHeight = new NumberPicker(this); - pickerHeight.setMinValue(24); - pickerHeight.setMaxValue(64); - pickerHeight.setWrapSelectorWheel(false); - pickerHeight.setValue(currentTileHeight); - layout.addView(pickerWidth); - layout.addView(pickerHeight); - new AlertDialog.Builder(this) - .setView(layout) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(@NonNull DialogInterface dialog, int which) { - currentTileWidth = pickerWidth.getValue(); - currentTileHeight = pickerHeight.getValue(); - widget.setTileSize(-1); - widget.setTileWidthDp(currentTileWidth); - widget.setTileHeightDp(currentTileHeight); - } - }) - .show(); - } - - @OnClick(R.id.button_clear_selection) - void onClearSelection() { - widget.clearSelection(); - } - - @OnClick(R.id.button_selection_mode) - void onChangeSelectionMode() { - CharSequence[] items = { - "No Selection", - "Single Date", - "Multiple Dates", - "Range of Dates" - }; - new AlertDialog.Builder(this) - .setTitle("Selection Mode") - .setSingleChoiceItems( - items, - widget.getSelectionMode(), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - widget.setSelectionMode(which); - dialog.dismiss(); - } - } - ) - .show(); - } - - @OnClick(R.id.button_change_orientation) - void onButtonChangeOrientation() { - widget.setTitleAnimationOrientation( - widget.getTitleAnimationOrientation() == MaterialCalendarView.VERTICAL - ? MaterialCalendarView.HORIZONTAL - : MaterialCalendarView.VERTICAL); - - Toast.makeText( - this, - widget.getTitleAnimationOrientation() == MaterialCalendarView.VERTICAL - ? "Vertical" - : "Horizontal", - Toast.LENGTH_SHORT - ).show(); - } - - private static final DayOfWeek[] DAYS_OF_WEEK = { - DayOfWeek.SUNDAY, - DayOfWeek.MONDAY, - DayOfWeek.TUESDAY, - DayOfWeek.WEDNESDAY, - DayOfWeek.THURSDAY, - DayOfWeek.FRIDAY, - DayOfWeek.SATURDAY, - }; - - @OnClick(R.id.button_set_first_day) - void onFirstDayOfWeekClicked() { - int index = random.nextInt(DAYS_OF_WEEK.length); - widget.state().edit().setFirstDayOfWeek(DAYS_OF_WEEK[index]).commit(); - } - - @OnClick(R.id.button_weeks) - public void onSetWeekMode() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && animateModeTransition.isChecked()) { - TransitionManager.beginDelayedTransition(parent); - } - widget.state().edit().setCalendarDisplayMode(CalendarMode.WEEKS).commit(); - } - - @OnClick(R.id.button_months) - public void onSetMonthMode() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && animateModeTransition.isChecked()) { - TransitionManager.beginDelayedTransition(parent); - } - widget.state().edit().setCalendarDisplayMode(CalendarMode.MONTHS).commit(); - } - - public static void showDatePickerDialog( - Context context, CalendarDay day, - DatePickerDialog.OnDateSetListener callback) { - if (day == null) { - day = CalendarDay.today(); - } - DatePickerDialog dialog = new DatePickerDialog( - context, 0, callback, day.getYear(), day.getMonth() - 1, day.getDay() - ); - dialog.show(); - } - - @Override - public void onDateLongClick(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date) { - Toast.makeText(this, FORMATTER.format(date.getDate()), Toast.LENGTH_SHORT).show(); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/GettersActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/GettersActivity.java deleted file mode 100644 index 42d9bd96..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/GettersActivity.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.view.View; -import android.widget.Toast; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnCheckedChanged; -import butterknife.OnClick; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.CalendarMode; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import java.util.List; - -/** - * Because the calendar has a lot of getters method, this activity is here to demonstrate what each - * getter is returning. For more information, make sure to check the documentation. - */ -public class GettersActivity extends AppCompatActivity { - public static final CharSequence[] ITEMS = - new CharSequence[] { "NONE", "SINGLE", "MULTIPLE", "RANGE" }; - - @BindView(R.id.calendarView) MaterialCalendarView widget; - - @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_getters); - ButterKnife.bind(this); - } - - @OnCheckedChanged(R.id.calendar_mode) - void onCalendarModeChanged(boolean checked) { - final CalendarMode mode = checked ? CalendarMode.WEEKS : CalendarMode.MONTHS; - widget.state().edit().setCalendarDisplayMode(mode).commit(); - } - - @OnClick(R.id.button_selection_mode) void onChangeSelectionMode() { - new AlertDialog.Builder(this) - .setTitle("Selection Mode") - .setSingleChoiceItems(ITEMS, widget.getSelectionMode(), (dialog, which) -> { - widget.setSelectionMode(which); - dialog.dismiss(); - }) - .show(); - } - - @OnClick(R.id.get_current_date) public void getCurrentDatesClick(final View v) { - Toast.makeText(this, widget.getCurrentDate().toString(), Toast.LENGTH_SHORT).show(); - Log.e("GettersActivity", widget.getCurrentDate().toString()); - } - - @OnClick(R.id.get_selected_date) public void getSelectedDatesClick(final View v) { - final CalendarDay selectedDate = widget.getSelectedDate(); - if (selectedDate != null) { - Toast.makeText(this, selectedDate.toString(), Toast.LENGTH_SHORT).show(); - Log.e("GettersActivity", selectedDate.toString()); - } else { - Toast.makeText(this, "No Selection", Toast.LENGTH_SHORT).show(); - } - } - - @OnClick(R.id.get_selected_dates) public void getSelectedDateClick(final View v) { - final List selectedDates = widget.getSelectedDates(); - if (!selectedDates.isEmpty()) { - Toast.makeText(this, selectedDates.toString(), Toast.LENGTH_SHORT).show(); - Log.e("GettersActivity", selectedDates.toString()); - } else { - Toast.makeText(this, "No Selection", Toast.LENGTH_SHORT).show(); - } - } - - @OnClick(R.id.get_selection_mode) public void getSelectionModeClick(final View v) { - Toast.makeText(this, ITEMS[widget.getSelectionMode()], Toast.LENGTH_SHORT).show(); - Log.e("GettersActivity", ITEMS[widget.getSelectionMode()].toString()); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MainActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MainActivity.java deleted file mode 100644 index 4e8ecbd8..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MainActivity.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import java.util.List; - -/** - * Routing Activity for other samples - */ -public class MainActivity extends AppCompatActivity { - - private static final String CATEGORY_SAMPLE = - "com.prolificinteractive.materialcalendarview.sample.SAMPLE"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - RecyclerView list = findViewById(R.id.list); - list.setLayoutManager(new LinearLayoutManager(this)); - list.setAdapter(new ResolveInfoAdapter(this, getAllSampleActivities())); - } - - private List getAllSampleActivities() { - Intent filter = new Intent(); - filter.setAction(Intent.ACTION_RUN); - filter.addCategory(CATEGORY_SAMPLE); - return getPackageManager().queryIntentActivities(filter, 0); - } - - private void onRouteClicked(ResolveInfo route) { - ActivityInfo activity = route.activityInfo; - ComponentName name = new ComponentName(activity.applicationInfo.packageName, activity.name); - startActivity(new Intent(Intent.ACTION_VIEW).setComponent(name)); - } - - class ResolveInfoAdapter extends RecyclerView.Adapter { - - private final PackageManager pm; - private final LayoutInflater inflater; - private final List samples; - - private ResolveInfoAdapter(Context context, List resolveInfos) { - this.samples = resolveInfos; - this.inflater = LayoutInflater.from(context); - this.pm = context.getPackageManager(); - } - - @Override - public ResolveInfoViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { - View view = inflater.inflate(R.layout.item_route, viewGroup, false); - return new ResolveInfoViewHolder(view); - } - - @Override - public void onBindViewHolder(ResolveInfoViewHolder viewHolder, int i) { - ResolveInfo item = samples.get(i); - viewHolder.textView.setText(item.loadLabel(pm)); - } - - @Override - public int getItemCount() { - return samples.size(); - } - - class ResolveInfoViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { - - public final TextView textView; - - public ResolveInfoViewHolder(View view) { - super(view); - this.textView = view.findViewById(android.R.id.text1); - view.setOnClickListener(this); - } - - @Override - public void onClick(@NonNull View v) { - onRouteClicked(samples.get(getAdapterPosition())); - } - } - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MultipleSizeActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MultipleSizeActivity.java deleted file mode 100644 index 10cc9360..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MultipleSizeActivity.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; - -/** - * Displays various ways of sizing CalendarView - */ -public class MultipleSizeActivity extends AppCompatActivity { - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_multiple_size); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MultipleViewActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MultipleViewActivity.java deleted file mode 100644 index a0066ffe..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/MultipleViewActivity.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.content.Context; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import butterknife.BindView; -import butterknife.ButterKnife; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import org.threeten.bp.LocalDate; - -/** - * In response to the issue comment at - * https://github.com/prolificinteractive/material-calendarview/issues/8#issuecomment-241205704 - * , test activity with multiple MaterialCalendarViews - */ -public class MultipleViewActivity extends AppCompatActivity { - //number of MaterialCalendarViews to display in list - static final int NUM_ENTRIES = 3; - - @BindView(R.id.calendar_list) - RecyclerView calendarList; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_multiple); - ButterKnife.bind(this); - - //setup RecyclerView - calendarList.setLayoutManager(new LinearLayoutManager(this)); - calendarList.setAdapter(new MultipleViewAdapter(this)); - } - - /** - * Adapter for RecyclerView - */ - class MultipleViewAdapter extends RecyclerView.Adapter { - final LayoutInflater inflater; - - MultipleViewAdapter(final Context context) { - inflater = LayoutInflater.from(context); - } - - @Override - public EntryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - final View view = inflater.inflate(R.layout.calendar_list_entry, parent, false); - return new EntryViewHolder(view); - } - - @Override - public int getItemCount() { - return NUM_ENTRIES; - } - - @Override - public void onBindViewHolder(EntryViewHolder holder, int position) { - //set selected date to today - holder.calendarView.setSelectedDate(LocalDate.now()); - } - - /** - * View holder for list entry - */ - class EntryViewHolder extends RecyclerView.ViewHolder { - final MaterialCalendarView calendarView; - - EntryViewHolder(final View itemView) { - super(itemView); - calendarView = itemView.findViewById(R.id.list_entry); - } - } - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/OldCalendarViewActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/OldCalendarViewActivity.java deleted file mode 100644 index aabd146d..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/OldCalendarViewActivity.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.widget.CalendarView; -import android.widget.TextView; -import butterknife.BindView; -import butterknife.ButterKnife; -import java.text.DateFormat; -import java.text.SimpleDateFormat; - -/** - * Shows off the most basic usage - */ -public class OldCalendarViewActivity extends AppCompatActivity - implements CalendarView.OnDateChangeListener { - - private static final DateFormat FORMATTER = SimpleDateFormat.getDateInstance(); - - @BindView(R.id.calendarView) - CalendarView widget; - - @BindView(R.id.textView) - TextView textView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_old_calendarview); - ButterKnife.bind(this); - - widget.setOnDateChangeListener(this); - } - - @Override - public void onSelectedDayChange( - CalendarView view, int year, int month, - int dayOfMonth) { - textView.setText(FORMATTER.format(view.getDate())); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/RotationActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/RotationActivity.java deleted file mode 100644 index 1db75395..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/RotationActivity.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.widget.Toast; -import butterknife.BindView; -import butterknife.ButterKnife; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.OnDateLongClickListener; -import com.prolificinteractive.materialcalendarview.OnMonthChangedListener; -import org.threeten.bp.format.DateTimeFormatter; - -/** - * Shows off the most basic usage - */ -public class RotationActivity extends AppCompatActivity - implements OnMonthChangedListener, OnDateLongClickListener { - - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, d MMM yyyy"); - - @BindView(R.id.calendarView) - MaterialCalendarView widget; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_rotation); - ButterKnife.bind(this); - - widget.setOnDateLongClickListener(this); - widget.setOnMonthChangedListener(this); - } - - @Override - public void onDateLongClick(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date) { - final String text = String.format("%s is available", FORMATTER.format(date.getDate())); - Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onMonthChanged(MaterialCalendarView widget, CalendarDay date) { - //noinspection ConstantConditions - getSupportActionBar().setTitle(FORMATTER.format(date.getDate())); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/SelectionModesActivity.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/SelectionModesActivity.java deleted file mode 100644 index 45135558..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/SelectionModesActivity.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.transition.TransitionManager; -import android.view.ViewGroup; -import android.widget.Toast; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnCheckedChanged; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.CalendarMode; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.OnDateSelectedListener; -import com.prolificinteractive.materialcalendarview.OnRangeSelectedListener; -import com.prolificinteractive.materialcalendarview.sample.decorators.RangeDayDecorator; -import java.util.List; -import org.threeten.bp.format.DateTimeFormatter; - -/** - * An activity that demonstrate the multiple selection mode that the calendar offers. - * The mode can be set through xml or in java. - * - * @see MaterialCalendarView.SelectionMode - */ -public class SelectionModesActivity extends AppCompatActivity - implements OnDateSelectedListener, OnRangeSelectedListener { - - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, d MMM yyyy"); - - @BindView(R.id.parent) ViewGroup parent; - @BindView(R.id.calendar_view_single) MaterialCalendarView single; - @BindView(R.id.calendar_view_multi) MaterialCalendarView multi; - @BindView(R.id.calendar_view_range) MaterialCalendarView range; - @BindView(R.id.calendar_view_none) MaterialCalendarView none; - - private RangeDayDecorator decorator; - - @Override protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_selection_modes); - ButterKnife.bind(this); - - decorator = new RangeDayDecorator(this); - - single.setOnDateChangedListener(this); - multi.setOnDateChangedListener(this); - range.setOnDateChangedListener(this); - range.setOnRangeSelectedListener(this); - range.addDecorator(decorator); - none.setOnDateChangedListener(this); - } - - @Override public void onDateSelected( - @NonNull final MaterialCalendarView widget, - @NonNull final CalendarDay date, - final boolean selected) { - final String text = selected ? FORMATTER.format(date.getDate()) : "No Selection"; - Toast.makeText(SelectionModesActivity.this, text, Toast.LENGTH_SHORT).show(); - } - - @Override public void onRangeSelected( - @NonNull final MaterialCalendarView widget, - @NonNull final List dates) { - if (dates.size() > 0) { - decorator.addFirstAndLast(dates.get(0), dates.get(dates.size() - 1)); - range.invalidateDecorators(); - } - } - - @OnCheckedChanged(R.id.calendar_mode) - void onCalendarModeChanged(boolean checked) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - TransitionManager.beginDelayedTransition(parent); - } - final CalendarMode mode = checked ? CalendarMode.WEEKS : CalendarMode.MONTHS; - single.state().edit().setCalendarDisplayMode(mode).commit(); - multi.state().edit().setCalendarDisplayMode(mode).commit(); - range.state().edit().setCalendarDisplayMode(mode).commit(); - none.state().edit().setCalendarDisplayMode(mode).commit(); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/SwappableBasicActivityDecorated.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/SwappableBasicActivityDecorated.java deleted file mode 100644 index aaa5ba6f..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/SwappableBasicActivityDecorated.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample; - -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.CalendarMode; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.OnDateSelectedListener; -import com.prolificinteractive.materialcalendarview.sample.decorators.HighlightWeekendsDecorator; -import com.prolificinteractive.materialcalendarview.sample.decorators.MySelectorDecorator; -import com.prolificinteractive.materialcalendarview.sample.decorators.OneDayDecorator; -import org.threeten.bp.LocalDate; -import org.threeten.bp.Month; - -/** - * Shows off the most basic usage - */ -public class SwappableBasicActivityDecorated extends AppCompatActivity - implements OnDateSelectedListener { - - private final OneDayDecorator oneDayDecorator = new OneDayDecorator(); - - @BindView(R.id.calendarView) MaterialCalendarView widget; - - @Override protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_basic_modes); - ButterKnife.bind(this); - - widget.setOnDateChangedListener(this); - widget.setShowOtherDates(MaterialCalendarView.SHOW_ALL); - - final LocalDate instance = LocalDate.now(); - widget.setSelectedDate(instance); - - final LocalDate min = LocalDate.of(instance.getYear(), Month.JANUARY, 1); - final LocalDate max = LocalDate.of(instance.getYear(), Month.DECEMBER, 31); - - widget.state().edit().setMinimumDate(min).setMaximumDate(max).commit(); - - widget.addDecorators( - new MySelectorDecorator(this), - new HighlightWeekendsDecorator(), - oneDayDecorator - ); - } - - @Override - public void onDateSelected( - @NonNull MaterialCalendarView widget, - @NonNull CalendarDay date, - boolean selected) { - //If you change a decorate, you need to invalidate decorators - oneDayDecorator.setDate(date.getDate()); - widget.invalidateDecorators(); - } - - @OnClick(R.id.button_weeks) - public void onSetWeekMode() { - widget.state().edit() - .setCalendarDisplayMode(CalendarMode.WEEKS) - .commit(); - } - - @OnClick(R.id.button_months) - public void onSetMonthMode() { - widget.state().edit() - .setCalendarDisplayMode(CalendarMode.MONTHS) - .commit(); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/EventDecorator.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/EventDecorator.java deleted file mode 100644 index 95079557..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/EventDecorator.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample.decorators; - -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.DayViewDecorator; -import com.prolificinteractive.materialcalendarview.DayViewFacade; -import com.prolificinteractive.materialcalendarview.spans.DotSpan; -import java.util.Collection; -import java.util.HashSet; - -/** - * Decorate several days with a dot - */ -public class EventDecorator implements DayViewDecorator { - - private int color; - private HashSet dates; - - public EventDecorator(int color, Collection dates) { - this.color = color; - this.dates = new HashSet<>(dates); - } - - @Override - public boolean shouldDecorate(CalendarDay day) { - return dates.contains(day); - } - - @Override - public void decorate(DayViewFacade view) { - view.addSpan(new DotSpan(5, color)); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/HighlightWeekendsDecorator.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/HighlightWeekendsDecorator.java deleted file mode 100644 index 22e5b500..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/HighlightWeekendsDecorator.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample.decorators; - -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.DayViewDecorator; -import com.prolificinteractive.materialcalendarview.DayViewFacade; -import org.threeten.bp.DayOfWeek; - -/** - * Highlight Saturdays and Sundays with a background - */ -public class HighlightWeekendsDecorator implements DayViewDecorator { - - private final Drawable highlightDrawable; - private static final int color = Color.parseColor("#228BC34A"); - - public HighlightWeekendsDecorator() { - highlightDrawable = new ColorDrawable(color); - } - - @Override public boolean shouldDecorate(final CalendarDay day) { - final DayOfWeek weekDay = day.getDate().getDayOfWeek(); - return weekDay == DayOfWeek.SATURDAY || weekDay == DayOfWeek.SUNDAY; - } - - @Override public void decorate(final DayViewFacade view) { - view.setBackgroundDrawable(highlightDrawable); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/MySelectorDecorator.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/MySelectorDecorator.java deleted file mode 100644 index f35b3bcc..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/MySelectorDecorator.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample.decorators; - -import android.app.Activity; -import android.graphics.drawable.Drawable; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.DayViewDecorator; -import com.prolificinteractive.materialcalendarview.DayViewFacade; -import com.prolificinteractive.materialcalendarview.sample.R; - -/** - * Use a custom selector - */ -public class MySelectorDecorator implements DayViewDecorator { - - private final Drawable drawable; - - public MySelectorDecorator(Activity context) { - drawable = context.getResources().getDrawable(R.drawable.my_selector); - } - - @Override - public boolean shouldDecorate(CalendarDay day) { - return true; - } - - @Override - public void decorate(DayViewFacade view) { - view.setSelectionDrawable(drawable); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/OneDayDecorator.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/OneDayDecorator.java deleted file mode 100644 index e6735f4b..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/OneDayDecorator.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample.decorators; - -import android.graphics.Typeface; -import android.text.style.RelativeSizeSpan; -import android.text.style.StyleSpan; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.DayViewDecorator; -import com.prolificinteractive.materialcalendarview.DayViewFacade; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import org.threeten.bp.LocalDate; - -/** - * Decorate a day by making the text big and bold - */ -public class OneDayDecorator implements DayViewDecorator { - - private CalendarDay date; - - public OneDayDecorator() { - date = CalendarDay.today(); - } - - @Override - public boolean shouldDecorate(CalendarDay day) { - return date != null && day.equals(date); - } - - @Override - public void decorate(DayViewFacade view) { - view.addSpan(new StyleSpan(Typeface.BOLD)); - view.addSpan(new RelativeSizeSpan(1.4f)); - } - - /** - * We're changing the internals, so make sure to call {@linkplain MaterialCalendarView#invalidateDecorators()} - */ - public void setDate(LocalDate date) { - this.date = CalendarDay.from(date); - } -} diff --git a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/RangeDayDecorator.java b/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/RangeDayDecorator.java deleted file mode 100644 index dfe3dd7f..00000000 --- a/sample/src/main/java/com/prolificinteractive/materialcalendarview/sample/decorators/RangeDayDecorator.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.prolificinteractive.materialcalendarview.sample.decorators; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import com.prolificinteractive.materialcalendarview.CalendarDay; -import com.prolificinteractive.materialcalendarview.DayViewDecorator; -import com.prolificinteractive.materialcalendarview.DayViewFacade; -import com.prolificinteractive.materialcalendarview.MaterialCalendarView; -import com.prolificinteractive.materialcalendarview.sample.R; -import java.util.HashSet; - -/** - * Decorate 2 days. - */ -public class RangeDayDecorator implements DayViewDecorator { - - private final HashSet list = new HashSet<>(); - private final Drawable drawable; - - public RangeDayDecorator(final Context context) { - drawable = context.getResources().getDrawable(R.drawable.my_selector); - } - - @Override - public boolean shouldDecorate(CalendarDay day) { - return list.contains(day); - } - - @Override - public void decorate(DayViewFacade view) { - view.setSelectionDrawable(drawable); - } - - /** - * We're changing the dates, so make sure to call {@linkplain MaterialCalendarView#invalidateDecorators()} - */ - public void addFirstAndLast(final CalendarDay first, final CalendarDay last) { - list.clear(); - list.add(first); - list.add(last); - } -} diff --git a/sample/src/main/res/drawable-hdpi/ic_my_selector.png b/sample/src/main/res/drawable-hdpi/ic_my_selector.png deleted file mode 100644 index 46ceaba6..00000000 Binary files a/sample/src/main/res/drawable-hdpi/ic_my_selector.png and /dev/null differ diff --git a/sample/src/main/res/drawable-mdpi/ic_my_selector.png b/sample/src/main/res/drawable-mdpi/ic_my_selector.png deleted file mode 100644 index 3b48334b..00000000 Binary files a/sample/src/main/res/drawable-mdpi/ic_my_selector.png and /dev/null differ diff --git a/sample/src/main/res/drawable-xhdpi/ic_my_selector.png b/sample/src/main/res/drawable-xhdpi/ic_my_selector.png deleted file mode 100644 index 4010b796..00000000 Binary files a/sample/src/main/res/drawable-xhdpi/ic_my_selector.png and /dev/null differ diff --git a/sample/src/main/res/drawable-xxhdpi/ic_my_selector.png b/sample/src/main/res/drawable-xxhdpi/ic_my_selector.png deleted file mode 100644 index 3b531e9c..00000000 Binary files a/sample/src/main/res/drawable-xxhdpi/ic_my_selector.png and /dev/null differ diff --git a/sample/src/main/res/drawable/ic_arrow_back.xml b/sample/src/main/res/drawable/ic_arrow_back.xml deleted file mode 100644 index 031f901d..00000000 --- a/sample/src/main/res/drawable/ic_arrow_back.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/sample/src/main/res/drawable/ic_arrow_forward.xml b/sample/src/main/res/drawable/ic_arrow_forward.xml deleted file mode 100644 index 60f93ad7..00000000 --- a/sample/src/main/res/drawable/ic_arrow_forward.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/sample/src/main/res/drawable/my_selector.xml b/sample/src/main/res/drawable/my_selector.xml deleted file mode 100644 index 8d839141..00000000 --- a/sample/src/main/res/drawable/my_selector.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/sample/src/main/res/drawable/today_circle_background.xml b/sample/src/main/res/drawable/today_circle_background.xml deleted file mode 100644 index 953e4714..00000000 --- a/sample/src/main/res/drawable/today_circle_background.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/sample/src/main/res/font/shirkhand.xml b/sample/src/main/res/font/shirkhand.xml deleted file mode 100644 index a1dc4760..00000000 --- a/sample/src/main/res/font/shirkhand.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/sample/src/main/res/font/shrikhand_regular.ttf b/sample/src/main/res/font/shrikhand_regular.ttf deleted file mode 100755 index e52b55e4..00000000 Binary files a/sample/src/main/res/font/shrikhand_regular.ttf and /dev/null differ diff --git a/sample/src/main/res/layout-land/activity_rotation.xml b/sample/src/main/res/layout-land/activity_rotation.xml deleted file mode 100644 index f55f2495..00000000 --- a/sample/src/main/res/layout-land/activity_rotation.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_basic.xml b/sample/src/main/res/layout/activity_basic.xml deleted file mode 100644 index c71b8736..00000000 --- a/sample/src/main/res/layout/activity_basic.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_basic_modes.xml b/sample/src/main/res/layout/activity_basic_modes.xml deleted file mode 100644 index 43b86338..00000000 --- a/sample/src/main/res/layout/activity_basic_modes.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - -