diff --git a/gradle.properties b/gradle.properties
index ec9ff61b..d3081ef8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -16,8 +16,8 @@ org.gradle.jvmargs=-Xmx1536m
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
-VERSION_NAME=4.2.3
-VERSION_CODE=54
+VERSION_NAME=5.0.0
+VERSION_CODE=55
GROUP=com.wdullaer
ANDROID_BUILD_MIN_SDK_VERSION=16
diff --git a/library/build.gradle b/library/build.gradle
index 1418273d..8d6c2347 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -34,12 +34,12 @@ dependencies {
implementation 'androidx.recyclerview:recyclerview:1.0.0'
testImplementation 'junit:junit:4.12'
- testImplementation 'com.pholser:junit-quickcheck-core:0.7'
- testImplementation 'com.pholser:junit-quickcheck-generators:0.7'
+ testImplementation 'com.pholser:junit-quickcheck-core:0.9'
+ testImplementation 'com.pholser:junit-quickcheck-generators:0.9'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:runner:1.2.0'
- androidTestImplementation 'androidx.test:rules:1.2.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
}
apply from: 'gradle-mvn-push.gradle'
diff --git a/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterTest.java b/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterTest.java
index 63464d83..1ffa965e 100644
--- a/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterTest.java
+++ b/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterTest.java
@@ -1,6 +1,7 @@
package com.wdullaer.materialdatetimepicker.date;
import android.os.Parcel;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
@@ -8,7 +9,8 @@
import java.util.Calendar;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
/**
* Unit tests for DefaultDateRangeLimiter which need to run on an android device
diff --git a/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiterTest.java b/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiterTest.java
index 7daed2a4..1df51f15 100644
--- a/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiterTest.java
+++ b/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiterTest.java
@@ -1,12 +1,14 @@
package com.wdullaer.materialdatetimepicker.time;
import android.os.Parcel;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
/**
* Unit tests for DefaultTimepointLimiter which need to run on an android device
diff --git a/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/time/TimepointTest.java b/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/time/TimepointTest.java
index 43cc7d8d..181423d9 100644
--- a/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/time/TimepointTest.java
+++ b/library/src/androidTest/java/com/wdullaer/materialdatetimepicker/time/TimepointTest.java
@@ -1,12 +1,14 @@
package com.wdullaer.materialdatetimepicker.time;
import android.os.Parcel;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
+import static org.junit.Assert.assertEquals;
+
/**
* Test for Timepoint which need to run on an actual device
* Created by wdullaer on 1/11/17.
diff --git a/library/src/main/assets/fonts/Roboto-Medium.ttf b/library/src/main/assets/fonts/Roboto-Medium.ttf
new file mode 100644
index 00000000..39c63d74
Binary files /dev/null and b/library/src/main/assets/fonts/Roboto-Medium.ttf differ
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/GravitySnapHelper.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/GravitySnapHelper.java
index 8da8ef78..9507ec1c 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/GravitySnapHelper.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/GravitySnapHelper.java
@@ -18,15 +18,15 @@
package com.wdullaer.materialdatetimepicker;
import android.os.Build;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.LinearSnapHelper;
+import android.view.Gravity;
+import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.LinearSnapHelper;
import androidx.recyclerview.widget.OrientationHelper;
import androidx.recyclerview.widget.RecyclerView;
-import android.view.Gravity;
-import android.view.View;
/**
* Enables snapping better snapping in a RecyclerView
@@ -101,8 +101,6 @@ public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager la
} else { // END
out[0] = distanceToEnd(targetView, getHorizontalHelper(layoutManager), false);
}
- } else {
- out[0] = 0;
}
if (layoutManager.canScrollVertically()) {
@@ -111,8 +109,6 @@ public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager la
} else { // BOTTOM
out[1] = distanceToEnd(targetView, getVerticalHelper(layoutManager), false);
}
- } else {
- out[1] = 0;
}
return out;
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/HapticFeedbackController.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/HapticFeedbackController.java
index 01ef461e..5b41b4e8 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/HapticFeedbackController.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/HapticFeedbackController.java
@@ -54,8 +54,9 @@ public void start() {
/**
* Method to verify that vibrate permission has been granted.
- *
+ *
* Allows users of the library to disabled vibrate support if desired.
+ *
* @return true if Vibrate permission has been granted
*/
private boolean hasVibratePermission(Context context) {
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/JalaliCalendar.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/JalaliCalendar.java
new file mode 100644
index 00000000..9501483b
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/JalaliCalendar.java
@@ -0,0 +1,854 @@
+package com.wdullaer.materialdatetimepicker;
+
+import android.annotation.SuppressLint;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class JalaliCalendar extends Calendar {
+ private static int[] gregorianDaysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ private static int[] jalaliDaysInMonth = {31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29};
+
+ private final static int FARVARDIN = 0;
+ private final static int ORDIBEHESHT = 1;
+ private final static int KHORDAD = 2;
+ private final static int TIR = 3;
+ private final static int MORDAD = 4;
+ private final static int SHAHRIVAR = 5;
+ private final static int MEHR = 6;
+ private final static int ABAN = 7;
+ private final static int AZAR = 8;
+ private final static int DEY = 9;
+ private final static int BAHMAN = 10;
+ private final static int ESFAND = 11;
+
+ private final static String[] monthNames = {"فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند"};
+ private final static String[] monthENLocaleNames = {"Farvardin", "Ordibehesht", "Khordad", "Tir", "Mordad", "Shahrivar", "Mehr", "Aban", "Azar", "Dey", "Bahman", "Esfand"};
+ private final static String[] weekDayNames = {"یکشنبه", "دوشنبه", "سه شنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه"};
+ private final static String[] weekDayENLocaleNames = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
+
+ private static TimeZone timeZone = TimeZone.getDefault();
+ private static Locale locale = Locale.getDefault();
+ private static boolean isTimeSeted = false;
+
+ private static final int ONE_SECOND = 1000;
+ private static final int ONE_MINUTE = 60 * ONE_SECOND;
+ private static final int ONE_HOUR = 60 * ONE_MINUTE;
+ private static final long ONE_DAY = 24 * ONE_HOUR;
+ private static final int BCE = 0;
+ private static final int CE = 1;
+ public static final int AD = 1;
+ private GregorianCalendar cal;
+
+ private static final int[] MIN_VALUES = {
+ BCE, // ERA
+ 1, // YEAR
+ FARVARDIN, // MONTH
+ 1, // WEEK_OF_YEAR
+ 0, // WEEK_OF_MONTH
+ 1, // DAY_OF_MONTH
+ 1, // DAY_OF_YEAR
+ SATURDAY, // DAY_OF_WEEK
+ 1, // DAY_OF_WEEK_IN_MONTH
+ AM, // AM_PM
+ 0, // HOUR
+ 0, // HOUR_OF_DAY
+ 0, // MINUTE
+ 0, // SECOND
+ 0, // MILLISECOND
+ -13 * ONE_HOUR, // ZONE_OFFSET (UNIX compatibility)
+ 0 // DST_OFFSET
+ };
+
+ private static final int[] LEAST_MAX_VALUES = {
+ CE, // ERA
+ 292269054, // YEAR
+ ESFAND, // MONTH
+ 52, // WEEK_OF_YEAR
+ 4, // WEEK_OF_MONTH
+ 28, // DAY_OF_MONTH
+ 365, // DAY_OF_YEAR
+ FRIDAY, // DAY_OF_WEEK
+ 4, // DAY_OF_WEEK_IN
+ PM, // AM_PM
+ 11, // HOUR
+ 23, // HOUR_OF_DAY
+ 59, // MINUTE
+ 59, // SECOND
+ 999, // MILLISECOND
+ 14 * ONE_HOUR, // ZONE_OFFSET
+ 20 * ONE_MINUTE // DST_OFFSET (historical least maximum)
+ };
+
+ private static final int[] MAX_VALUES = {
+ CE, // ERA
+ 292278994, // YEAR
+ ESFAND, // MONTH
+ 53, // WEEK_OF_YEAR
+ 6, // WEEK_OF_MONTH
+ 31, // DAY_OF_MONTH
+ 366, // DAY_OF_YEAR
+ FRIDAY, // DAY_OF_WEEK
+ 6, // DAY_OF_WEEK_IN
+ PM, // AM_PM
+ 11, // HOUR
+ 23, // HOUR_OF_DAY
+ 59, // MINUTE
+ 59, // SECOND
+ 999, // MILLISECOND
+ 14 * ONE_HOUR, // ZONE_OFFSET
+ 2 * ONE_HOUR // DST_OFFSET (double summer time)
+ };
+
+ public JalaliCalendar() {
+ this(TimeZone.getDefault(), Locale.getDefault());
+ }
+
+ public JalaliCalendar(TimeZone zone) {
+ this(zone, Locale.getDefault());
+ }
+
+ public JalaliCalendar(Locale aLocale) {
+ this(TimeZone.getDefault(), aLocale);
+ }
+
+ public JalaliCalendar(TimeZone zone, Locale aLocale) {
+
+ super(zone, aLocale);
+ timeZone = zone;
+ locale = aLocale;
+ Calendar calendar = Calendar.getInstance(zone, aLocale);
+
+ YearMonthDate yearMonthDate = new YearMonthDate(calendar.get(YEAR), calendar.get(MONTH), calendar.get(DATE));
+ yearMonthDate = gregorianToJalali(yearMonthDate);
+ set(yearMonthDate.getYear(), yearMonthDate.getMonth(), yearMonthDate.getDate());
+ complete();
+
+ }
+
+ public JalaliCalendar(int year, int month, int dayOfMonth) {
+ this(year, month, dayOfMonth, 0, 0, 0, 0);
+ }
+
+ public JalaliCalendar(int year, int month, int dayOfMonth, int hourOfDay,
+ int minute) {
+ this(year, month, dayOfMonth, hourOfDay, minute, 0, 0);
+ }
+
+ public JalaliCalendar(int year, int month, int dayOfMonth, int hourOfDay,
+ int minute, int second) {
+ this(year, month, dayOfMonth, hourOfDay, minute, second, 0);
+ }
+
+ public JalaliCalendar(int year, int month, int dayOfMonth,
+ int hourOfDay, int minute, int second, int millis) {
+ super();
+
+ this.set(YEAR, year);
+ this.set(MONTH, month);
+ this.set(DAY_OF_MONTH, dayOfMonth);
+
+ if (hourOfDay >= 12 && hourOfDay <= 23) {
+
+ this.set(AM_PM, PM);
+ this.set(HOUR, hourOfDay - 12);
+ } else {
+ this.set(HOUR, hourOfDay);
+ this.set(AM_PM, AM);
+ }
+
+ this.set(HOUR_OF_DAY, hourOfDay);
+ this.set(MINUTE, minute);
+ this.set(SECOND, second);
+
+ this.set(MILLISECOND, millis);
+
+ YearMonthDate yearMonthDate = jalaliToGregorian(new YearMonthDate(fields[1], fields[2], fields[5]));
+ cal = new GregorianCalendar(yearMonthDate.getYear(), yearMonthDate.getMonth(), yearMonthDate.getDate(), hourOfDay,
+ minute, second);
+ time = cal.getTimeInMillis();
+
+ isTimeSeted = true;
+ }
+
+ public static JalaliCalendar getInstance() {
+ return new JalaliCalendar();
+ }
+
+ public static JalaliCalendar getInstance(TimeZone zone) {
+ return new JalaliCalendar(zone);
+ }
+
+ public static JalaliCalendar getInstance(TimeZone zone, Locale locale) {
+ return new JalaliCalendar(zone, locale);
+ }
+
+ public String getMonthName() {
+ return locale.getLanguage().equals("fa") ? monthNames[get(MONTH)] : monthENLocaleNames[get(MONTH)];
+ }
+
+ public String getWeekDayName() {
+ return locale.getLanguage().equals("fa") ? weekDayNames[get(DAY_OF_WEEK) - 1] : weekDayENLocaleNames[get(DAY_OF_WEEK) - 1];
+ }
+
+ public static String getWeekDayName(int dayNum) {
+ return locale.getLanguage().equals("fa") ? weekDayNames[dayNum - 1] : weekDayENLocaleNames[dayNum - 1];
+ }
+
+ public static YearMonthDate gregorianToJalali(YearMonthDate gregorian) {
+
+ if (gregorian.getMonth() > 11 || gregorian.getMonth() < -11) {
+ throw new IllegalArgumentException();
+ }
+ int jalaliYear;
+ int jalaliMonth;
+ int jalaliDay;
+
+ int gregorianDayNo, jalaliDayNo;
+ int jalaliNP;
+ int i;
+
+ gregorian.setYear(gregorian.getYear() - 1600);
+ gregorian.setDate(gregorian.getDate() - 1);
+
+ gregorianDayNo = 365 * gregorian.getYear() + (int) Math.floor((gregorian.getYear() + 3) / 4)
+ - (int) Math.floor((gregorian.getYear() + 99) / 100)
+ + (int) Math.floor((gregorian.getYear() + 399) / 400);
+ for (i = 0; i < gregorian.getMonth(); ++i) {
+ gregorianDayNo += gregorianDaysInMonth[i];
+ }
+
+ if (gregorian.getMonth() > 1 && ((gregorian.getYear() % 4 == 0 && gregorian.getYear() % 100 != 0)
+ || (gregorian.getYear() % 400 == 0))) {
+ ++gregorianDayNo;
+ }
+
+ gregorianDayNo += gregorian.getDate();
+
+ jalaliDayNo = gregorianDayNo - 79;
+
+ jalaliNP = (int) Math.floor(jalaliDayNo / 12053);
+ jalaliDayNo = jalaliDayNo % 12053;
+
+ jalaliYear = 979 + 33 * jalaliNP + 4 * (int) (jalaliDayNo / 1461);
+ jalaliDayNo = jalaliDayNo % 1461;
+
+ if (jalaliDayNo >= 366) {
+ jalaliYear += (int) Math.floor((jalaliDayNo - 1) / 365);
+ jalaliDayNo = (jalaliDayNo - 1) % 365;
+ }
+
+ for (i = 0; i < 11 && jalaliDayNo >= jalaliDaysInMonth[i]; ++i) {
+ jalaliDayNo -= jalaliDaysInMonth[i];
+ }
+ jalaliMonth = i;
+ jalaliDay = jalaliDayNo + 1;
+
+ return new YearMonthDate(jalaliYear, jalaliMonth, jalaliDay);
+ }
+
+ public static YearMonthDate jalaliToGregorian(YearMonthDate jalali) {
+ if (jalali.getMonth() > 11 || jalali.getMonth() < -11) {
+ throw new IllegalArgumentException();
+ }
+
+ int gregorianYear;
+ int gregorianMonth;
+ int gregorianDay;
+
+ int gregorianDayNo, jalaliDayNo;
+ int leap;
+
+ int i;
+ jalali.setYear(jalali.getYear() - 979);
+ jalali.setDate(jalali.getDate() - 1);
+
+ jalaliDayNo = 365 * jalali.getYear() + (int) (jalali.getYear() / 33) * 8
+ + (int) Math.floor(((jalali.getYear() % 33) + 3) / 4);
+ for (i = 0; i < jalali.getMonth(); ++i) {
+ jalaliDayNo += jalaliDaysInMonth[i];
+ }
+
+ jalaliDayNo += jalali.getDate();
+
+ gregorianDayNo = jalaliDayNo + 79;
+
+ gregorianYear = 1600 + 400 * (int) Math.floor(gregorianDayNo / 146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
+ gregorianDayNo = gregorianDayNo % 146097;
+
+ leap = 1;
+ if (gregorianDayNo >= 36525) /* 36525 = 365*100 + 100/4 */ {
+ gregorianDayNo--;
+ gregorianYear += 100 * (int) Math.floor(gregorianDayNo / 36524); /* 36524 = 365*100 + 100/4 - 100/100 */
+ gregorianDayNo = gregorianDayNo % 36524;
+
+ if (gregorianDayNo >= 365) {
+ gregorianDayNo++;
+ } else {
+ leap = 0;
+ }
+ }
+
+ gregorianYear += 4 * (int) Math.floor(gregorianDayNo / 1461); /* 1461 = 365*4 + 4/4 */
+ gregorianDayNo = gregorianDayNo % 1461;
+
+ if (gregorianDayNo >= 366) {
+ leap = 0;
+
+ gregorianDayNo--;
+ gregorianYear += (int) Math.floor(gregorianDayNo / 365);
+ gregorianDayNo = gregorianDayNo % 365;
+ }
+
+ for (i = 0; gregorianDayNo >= gregorianDaysInMonth[i] + ((i == 1 && leap == 1) ? i : 0); i++) {
+ gregorianDayNo -= gregorianDaysInMonth[i] + ((i == 1 && leap == 1) ? i : 0);
+ }
+ gregorianMonth = i;
+ gregorianDay = gregorianDayNo + 1;
+
+ return new YearMonthDate(gregorianYear, gregorianMonth, gregorianDay);
+
+ }
+
+ public static int weekOfYear(int dayOfYear, int year) {
+ switch (dayOfWeek(JalaliCalendar.jalaliToGregorian(new YearMonthDate(year, 0, 1)))) {
+ case 2:
+ dayOfYear++;
+ break;
+ case 3:
+ dayOfYear += 2;
+ break;
+ case 4:
+ dayOfYear += 3;
+ break;
+ case 5:
+ dayOfYear += 4;
+ break;
+ case 6:
+ dayOfYear += 5;
+ break;
+ case 7:
+ dayOfYear--;
+ break;
+ }
+ ;
+ dayOfYear = (int) Math.floor(dayOfYear / 7);
+ return dayOfYear + 1;
+ }
+
+ public static int dayOfWeek(YearMonthDate yearMonthDate) {
+
+ Calendar cal = new GregorianCalendar(yearMonthDate.getYear(), yearMonthDate.getMonth(), yearMonthDate.getDate());
+ return cal.get(DAY_OF_WEEK);
+
+ }
+
+ public static boolean isLeepYear(int year) {
+ //Algorithm from www.wikipedia.com
+ return (year % 33 == 1 || year % 33 == 5 || year % 33 == 9 || year % 33 == 13 ||
+ year % 33 == 17 || year % 33 == 22 || year % 33 == 26 || year % 33 == 30);
+ }
+
+ @Override
+ protected void computeTime() {
+ if (!isTimeSet && !isTimeSeted) {
+ Calendar cal = GregorianCalendar.getInstance(timeZone);
+ if (!isSet(HOUR_OF_DAY)) {
+ super.set(HOUR_OF_DAY, cal.get(HOUR_OF_DAY));
+ }
+ if (!isSet(HOUR)) {
+ super.set(HOUR, cal.get(HOUR));
+ }
+ if (!isSet(MINUTE)) {
+ super.set(MINUTE, cal.get(MINUTE));
+ }
+ if (!isSet(SECOND)) {
+ super.set(SECOND, cal.get(SECOND));
+ }
+ if (!isSet(MILLISECOND)) {
+ super.set(MILLISECOND, cal.get(MILLISECOND));
+ }
+ if (!isSet(ZONE_OFFSET)) {
+ super.set(ZONE_OFFSET, cal.get(ZONE_OFFSET));
+ }
+ if (!isSet(DST_OFFSET)) {
+ super.set(DST_OFFSET, cal.get(DST_OFFSET));
+ }
+ if (!isSet(AM_PM)) {
+ super.set(AM_PM, cal.get(AM_PM));
+ }
+
+ if (internalGet(HOUR_OF_DAY) >= 12 && internalGet(HOUR_OF_DAY) <= 23) {
+ super.set(AM_PM, PM);
+ super.set(HOUR, internalGet(HOUR_OF_DAY) - 12);
+ } else {
+ super.set(HOUR, internalGet(HOUR_OF_DAY));
+ super.set(AM_PM, AM);
+ }
+
+ YearMonthDate yearMonthDate = jalaliToGregorian(new YearMonthDate(internalGet(YEAR), internalGet(MONTH), internalGet(DAY_OF_MONTH)));
+ cal.set(yearMonthDate.getYear(), yearMonthDate.getMonth(), yearMonthDate.getDate()
+ , internalGet(HOUR_OF_DAY), internalGet(MINUTE), internalGet(SECOND));
+ time = cal.getTimeInMillis();
+
+ } else if (!isTimeSet && isTimeSeted) {
+ if (internalGet(HOUR_OF_DAY) >= 12 && internalGet(HOUR_OF_DAY) <= 23) {
+ super.set(AM_PM, PM);
+ super.set(HOUR, internalGet(HOUR_OF_DAY) - 12);
+ } else {
+ super.set(HOUR, internalGet(HOUR_OF_DAY));
+ super.set(AM_PM, AM);
+ }
+ cal = new GregorianCalendar();
+ super.set(ZONE_OFFSET, timeZone.getRawOffset());
+ super.set(DST_OFFSET, timeZone.getDSTSavings());
+ YearMonthDate yearMonthDate = jalaliToGregorian(new YearMonthDate(internalGet(YEAR), internalGet(MONTH), internalGet(DAY_OF_MONTH)));
+ cal.set(yearMonthDate.getYear(), yearMonthDate.getMonth(), yearMonthDate.getDate(), internalGet(HOUR_OF_DAY),
+ internalGet(MINUTE), internalGet(SECOND));
+ time = cal.getTimeInMillis();
+ }
+ }
+
+ public void set(int field, int value) {
+ switch (field) {
+ case DATE: {
+ super.set(field, 0);
+ add(field, value);
+ break;
+ }
+ case MONTH: {
+ if (value > 11) {
+ super.set(field, 11);
+ add(field, value - 11);
+ } else if (value < 0) {
+ super.set(field, 0);
+ add(field, value);
+ } else {
+ super.set(field, value);
+ }
+ break;
+ }
+ case DAY_OF_YEAR: {
+ if (isSet(YEAR) && isSet(MONTH) && isSet(DAY_OF_MONTH)) {
+ super.set(YEAR, internalGet(YEAR));
+ super.set(MONTH, 0);
+ super.set(DATE, 0);
+ add(field, value);
+ } else {
+ super.set(field, value);
+ }
+ break;
+ }
+ case WEEK_OF_YEAR: {
+ if (isSet(YEAR) && isSet(MONTH) && isSet(DAY_OF_MONTH)) {
+ add(field, value - get(WEEK_OF_YEAR));
+ } else {
+ super.set(field, value);
+ }
+ break;
+ }
+ case WEEK_OF_MONTH: {
+ if (isSet(YEAR) && isSet(MONTH) && isSet(DAY_OF_MONTH)) {
+ add(field, value - get(WEEK_OF_MONTH));
+ } else {
+ super.set(field, value);
+ }
+ break;
+ }
+ case DAY_OF_WEEK: {
+ if (isSet(YEAR) && isSet(MONTH) && isSet(DAY_OF_MONTH)) {
+ add(DAY_OF_WEEK, value % 7 - get(DAY_OF_WEEK));
+ } else {
+ super.set(field, value);
+ }
+ break;
+ }
+ case HOUR_OF_DAY:
+ case HOUR:
+ case MINUTE:
+ case SECOND:
+ case MILLISECOND:
+ case ZONE_OFFSET:
+ case DST_OFFSET: {
+ if (isSet(YEAR) && isSet(MONTH) && isSet(DATE) && isSet(HOUR) && isSet(HOUR_OF_DAY) &&
+ isSet(MINUTE) && isSet(SECOND) && isSet(MILLISECOND)) {
+ cal = new GregorianCalendar();
+ YearMonthDate yearMonthDate = jalaliToGregorian(new YearMonthDate(internalGet(YEAR), internalGet(MONTH), internalGet(DATE)));
+ cal.set(yearMonthDate.getYear(), yearMonthDate.getMonth(), yearMonthDate.getDate(), internalGet(HOUR_OF_DAY), internalGet(MINUTE),
+ internalGet(SECOND));
+ cal.set(field, value);
+ yearMonthDate = gregorianToJalali(new YearMonthDate(cal.get(YEAR), cal.get(MONTH), cal.get(DATE)));
+ super.set(YEAR, yearMonthDate.getYear());
+ super.set(MONTH, yearMonthDate.getMonth());
+ super.set(DATE, yearMonthDate.getDate());
+ super.set(HOUR_OF_DAY, cal.get(HOUR_OF_DAY));
+ super.set(MINUTE, cal.get(MINUTE));
+ super.set(SECOND, cal.get(SECOND));
+
+ } else {
+ super.set(field, value);
+ }
+ break;
+ }
+
+
+ default: {
+ super.set(field, value);
+ }
+ }
+ }
+
+ @SuppressLint("WrongConstant")
+ @Override
+ protected void computeFields() {
+ boolean temp = isTimeSet;
+ if (!areFieldsSet) {
+ setMinimalDaysInFirstWeek(1);
+ setFirstDayOfWeek(7);
+
+ //Day_Of_Year
+ int dayOfYear = 0;
+ int index = 0;
+
+ while (index < fields[2]) {
+ dayOfYear += jalaliDaysInMonth[index++];
+ }
+ dayOfYear += fields[5];
+ super.set(DAY_OF_YEAR, dayOfYear);
+ //***
+
+ //Day_of_Week
+ super.set(DAY_OF_WEEK, dayOfWeek(jalaliToGregorian(new YearMonthDate(fields[1], fields[2], fields[5]))));
+ //***
+
+ //Day_Of_Week_In_Month
+ if (0 < fields[5] && fields[5] < 8) {
+ super.set(DAY_OF_WEEK_IN_MONTH, 1);
+ }
+
+ if (7 < fields[5] && fields[5] < 15) {
+ super.set(DAY_OF_WEEK_IN_MONTH, 2);
+ }
+
+ if (14 < fields[5] && fields[5] < 22) {
+ super.set(DAY_OF_WEEK_IN_MONTH, 3);
+ }
+
+ if (21 < fields[5] && fields[5] < 29) {
+ super.set(DAY_OF_WEEK_IN_MONTH, 4);
+ }
+
+ if (28 < fields[5] && fields[5] < 32) {
+ super.set(DAY_OF_WEEK_IN_MONTH, 5);
+ }
+ //***
+
+ //Week_Of_Year
+ super.set(WEEK_OF_YEAR, weekOfYear(fields[6], fields[1]));
+ //***
+
+ //Week_Of_Month
+ super.set(WEEK_OF_MONTH, weekOfYear(fields[6], fields[1]) - weekOfYear(fields[6] - fields[5], fields[1]) + 1);
+ //
+
+ isTimeSet = temp;
+ }
+ }
+
+ @Override
+ public void add(int field, int amount) {
+
+ if (field == MONTH) {
+ amount += get(MONTH);
+ add(YEAR, amount / 12);
+ super.set(MONTH, amount % 12);
+ if (get(DAY_OF_MONTH) > jalaliDaysInMonth[amount % 12]) {
+ super.set(DAY_OF_MONTH, jalaliDaysInMonth[amount % 12]);
+ if (get(MONTH) == 11 && isLeepYear(get(YEAR))) {
+ super.set(DAY_OF_MONTH, 30);
+ }
+ }
+ complete();
+
+ } else if (field == YEAR) {
+
+ super.set(YEAR, get(YEAR) + amount);
+ if (get(DAY_OF_MONTH) == 30 && get(MONTH) == 11 && !isLeepYear(get(YEAR))) {
+ super.set(DAY_OF_MONTH, 29);
+ }
+
+ complete();
+ } else {
+ YearMonthDate yearMonthDate = jalaliToGregorian(new YearMonthDate(get(YEAR), get(MONTH), get(DATE)));
+ Calendar gc = new GregorianCalendar(yearMonthDate.getYear(), yearMonthDate.getMonth(), yearMonthDate.getDate(),
+ get(HOUR_OF_DAY), get(MINUTE), get(SECOND));
+ gc.add(field, amount);
+ yearMonthDate = gregorianToJalali(new YearMonthDate(gc.get(YEAR), gc.get(MONTH), gc.get(DATE)));
+ super.set(YEAR, yearMonthDate.getYear());
+ super.set(MONTH, yearMonthDate.getMonth());
+ super.set(DATE, yearMonthDate.getDate());
+ super.set(HOUR_OF_DAY, gc.get(HOUR_OF_DAY));
+ super.set(MINUTE, gc.get(MINUTE));
+ super.set(SECOND, gc.get(SECOND));
+ complete();
+ }
+
+ }
+
+ @Override
+ public void roll(int field, boolean up) {
+ roll(field, up ? +1 : -1);
+ }
+
+ @Override
+ public void roll(int field, int amount) {
+ if (amount == 0) {
+ return;
+ }
+
+ if (field < 0 || field >= ZONE_OFFSET) {
+ throw new IllegalArgumentException();
+ }
+
+ complete();
+
+ switch (field) {
+ case AM_PM: {
+ if (amount % 2 != 0) {
+ if (internalGet(AM_PM) == AM) {
+ fields[AM_PM] = PM;
+ } else {
+ fields[AM_PM] = AM;
+ }
+ if (get(AM_PM) == AM) {
+ super.set(HOUR_OF_DAY, get(HOUR));
+ } else {
+ super.set(HOUR_OF_DAY, get(HOUR) + 12);
+ }
+ }
+ break;
+ }
+ case YEAR: {
+ super.set(YEAR, internalGet(YEAR) + amount);
+ if (internalGet(MONTH) == 11 && internalGet(DAY_OF_MONTH) == 30 && !isLeepYear(internalGet(YEAR))) {
+ super.set(DAY_OF_MONTH, 29);
+ }
+ break;
+ }
+ case MINUTE: {
+ int unit = 60;
+ int m = (internalGet(MINUTE) + amount) % unit;
+ if (m < 0) {
+ m += unit;
+ }
+ super.set(MINUTE, m);
+ break;
+ }
+ case SECOND: {
+ int unit = 60;
+ int s = (internalGet(SECOND) + amount) % unit;
+ if (s < 0) {
+ s += unit;
+ }
+ super.set(SECOND, s);
+ break;
+ }
+ case MILLISECOND: {
+ int unit = 1000;
+ int ms = (internalGet(MILLISECOND) + amount) % unit;
+ if (ms < 0) {
+ ms += unit;
+ }
+ super.set(MILLISECOND, ms);
+ break;
+ }
+
+ case HOUR: {
+ super.set(HOUR, (internalGet(HOUR) + amount) % 12);
+ if (internalGet(HOUR) < 0) {
+ fields[HOUR] += 12;
+ }
+ if (internalGet(AM_PM) == AM) {
+ super.set(HOUR_OF_DAY, internalGet(HOUR));
+ } else {
+ super.set(HOUR_OF_DAY, internalGet(HOUR) + 12);
+ }
+
+ break;
+ }
+ case HOUR_OF_DAY: {
+ fields[HOUR_OF_DAY] = (internalGet(HOUR_OF_DAY) + amount) % 24;
+ if (internalGet(HOUR_OF_DAY) < 0) {
+ fields[HOUR_OF_DAY] += 24;
+ }
+ if (internalGet(HOUR_OF_DAY) < 12) {
+ fields[AM_PM] = AM;
+ fields[HOUR] = internalGet(HOUR_OF_DAY);
+ } else {
+ fields[AM_PM] = PM;
+ fields[HOUR] = internalGet(HOUR_OF_DAY) - 12;
+ }
+
+ }
+ case MONTH: {
+ int mon = (internalGet(MONTH) + amount) % 12;
+ if (mon < 0) {
+ mon += 12;
+ }
+ super.set(MONTH, mon);
+
+ int monthLen = jalaliDaysInMonth[mon];
+ if (internalGet(MONTH) == 11 && isLeepYear(internalGet(YEAR))) {
+ monthLen = 30;
+ }
+ if (internalGet(DAY_OF_MONTH) > monthLen) {
+ super.set(DAY_OF_MONTH, monthLen);
+ }
+ break;
+ }
+ case DAY_OF_MONTH: {
+ int unit = 0;
+ if (0 <= get(MONTH) && get(MONTH) <= 5) {
+ unit = 31;
+ }
+ if (6 <= get(MONTH) && get(MONTH) <= 10) {
+ unit = 30;
+ }
+ if (get(MONTH) == 11) {
+ if (isLeepYear(get(YEAR))) {
+ unit = 30;
+ } else {
+ unit = 29;
+ }
+ }
+ int d = (get(DAY_OF_MONTH) + amount) % unit;
+ if (d < 0) {
+ d += unit;
+ }
+ super.set(DAY_OF_MONTH, d);
+ break;
+
+ }
+ case WEEK_OF_YEAR: {
+ break;
+ }
+ case DAY_OF_YEAR: {
+ int unit = (isLeepYear(internalGet(YEAR)) ? 366 : 365);
+ int dayOfYear = (internalGet(DAY_OF_YEAR) + amount) % unit;
+ dayOfYear = (dayOfYear > 0) ? dayOfYear : dayOfYear + unit;
+ int month = 0, temp = 0;
+ while (dayOfYear > temp) {
+ temp += jalaliDaysInMonth[month++];
+ }
+ super.set(MONTH, --month);
+ super.set(DAY_OF_MONTH, jalaliDaysInMonth[internalGet(MONTH)] - (temp - dayOfYear));
+ break;
+ }
+ case DAY_OF_WEEK: {
+ int index = amount % 7;
+ if (index < 0) {
+ index += 7;
+ }
+ int i = 0;
+ while (i != index) {
+ if (internalGet(DAY_OF_WEEK) == FRIDAY) {
+ add(DAY_OF_MONTH, -6);
+ } else {
+ add(DAY_OF_MONTH, +1);
+ }
+ i++;
+ }
+ break;
+ }
+
+ default:
+ throw new IllegalArgumentException();
+ }
+
+ }
+
+ @Override
+ public int getMinimum(int field) {
+ return MIN_VALUES[field];
+ }
+
+ @Override
+ public int getMaximum(int field) {
+ return MAX_VALUES[field];
+ }
+
+ @Override
+ public int getGreatestMinimum(int field) {
+ return MIN_VALUES[field];
+ }
+
+ @Override
+ public int getLeastMaximum(int field) {
+ return LEAST_MAX_VALUES[field];
+ }
+
+ public static class YearMonthDate {
+
+ YearMonthDate(int year, int month, int date) {
+ this.year = year;
+ this.month = month;
+ this.date = date;
+ }
+
+ private int year;
+ private int month;
+ private int date;
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ public void setMonth(int month) {
+ this.month = month;
+ }
+
+ public int getDate() {
+ return date;
+ }
+
+ public void setDate(int date) {
+ this.date = date;
+ }
+
+ public String toString() {
+ return getYear() + "/" + getMonth() + "/" + getDate();
+ }
+ }
+
+ @Override
+ public int getFirstDayOfWeek() {
+ return SATURDAY;
+ }
+
+ @Override
+ public int getActualMaximum(int field) {
+ if (field == Calendar.DAY_OF_MONTH) {
+ return jalaliDaysInMonth[get(MONTH)];
+ }
+ return super.getActualMaximum(field);
+ }
+
+ public static void setLocale(Locale locale) {
+ JalaliCalendar.locale = locale;
+ }
+
+ public static Locale getLocale() {
+ return locale;
+ }
+}
+
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/Utils.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/Utils.java
index 6fc4d1cc..2ad3ce87 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/Utils.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/Utils.java
@@ -23,12 +23,14 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Typeface;
import android.os.Build;
-import androidx.annotation.AttrRes;
-import androidx.core.content.ContextCompat;
import android.util.TypedValue;
import android.view.View;
+import androidx.annotation.AttrRes;
+import androidx.core.content.ContextCompat;
+
import java.util.Calendar;
/**
@@ -46,8 +48,14 @@ public class Utils {
// Alpha level for fully opaque.
public static final int FULL_ALPHA = 255;
+ /**
+ * user custom font used shared among all classes
+ */
+ private static Typeface customFont;
+
/**
* Try to speak the specified text, for accessibility. Only available on JB or later.
+ *
* @param text Text to announce.
*/
public static void tryAccessibilityAnnounce(View view, CharSequence text) {
@@ -58,11 +66,12 @@ public static void tryAccessibilityAnnounce(View view, CharSequence text) {
/**
* Render an animator to pulsate a view in place.
+ *
* @param labelToAnimate the view to pulsate.
* @return The animator object. Use .start() to begin.
*/
public static ObjectAnimator getPulseAnimator(View labelToAnimate, float decreaseRatio,
- float increaseRatio) {
+ float increaseRatio) {
Keyframe k0 = Keyframe.ofFloat(0f, 1f);
Keyframe k1 = Keyframe.ofFloat(0.275f, decreaseRatio);
Keyframe k2 = Keyframe.ofFloat(0.69f, increaseRatio);
@@ -81,7 +90,7 @@ public static ObjectAnimator getPulseAnimator(View labelToAnimate, float decreas
* Convert Dp to Pixel
*/
@SuppressWarnings("unused")
- public static int dpToPx(float dp, Resources resources){
+ public static int dpToPx(float dp, Resources resources) {
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.getDisplayMetrics());
return (int) px;
}
@@ -95,6 +104,7 @@ public static int darkenColor(int color) {
/**
* Gets the colorAccent from the current context, if possible/available
+ *
* @param context The context to use as reference for the color
* @return the accent color of the current context
*/
@@ -116,6 +126,7 @@ public static int getAccentColorFromThemeIfAvailable(Context context) {
/**
* Gets dialog type (Light/Dark) from current theme
+ *
* @param context The context to use as reference for the boolean
* @param current Default value to return if cannot resolve the attribute
* @return true if dark mode, false if light.
@@ -126,8 +137,9 @@ public static boolean isDarkTheme(Context context, boolean current) {
/**
* Gets the required boolean value from the current context, if possible/available
- * @param context The context to use as reference for the boolean
- * @param attr Attribute id to resolve
+ *
+ * @param context The context to use as reference for the boolean
+ * @param attr Attribute id to resolve
* @param fallback Default value to return if no value is specified in theme
* @return the boolean value from current theme
*/
@@ -154,4 +166,12 @@ public static Calendar trimToMidnight(Calendar calendar) {
calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
+
+ synchronized public static void setCustomFont(Typeface customFont) {
+ Utils.customFont = customFont;
+ }
+
+ synchronized public static Typeface getCustomFont() {
+ return customFont;
+ }
}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/VerticalTextView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/VerticalTextView.java
index 6a62b33a..6b40da6d 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/VerticalTextView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/VerticalTextView.java
@@ -14,11 +14,11 @@
public class VerticalTextView extends androidx.appcompat.widget.AppCompatTextView {
final boolean topDown;
- public VerticalTextView(Context context, AttributeSet attrs){
+ public VerticalTextView(Context context, AttributeSet attrs) {
super(context, attrs);
final int gravity = getGravity();
- if (Gravity.isVertical(gravity) && (gravity&Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
- setGravity((gravity&Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP);
+ if (Gravity.isVertical(gravity) && (gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
+ setGravity((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP);
topDown = false;
} else {
topDown = true;
@@ -26,21 +26,21 @@ public VerticalTextView(Context context, AttributeSet attrs){
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//noinspection SuspiciousNameCombination
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
@Override
- protected void onDraw(Canvas canvas){
+ protected void onDraw(Canvas canvas) {
TextPaint textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
textPaint.drawableState = getDrawableState();
canvas.save();
- if (topDown){
+ if (topDown) {
canvas.translate(getWidth(), 0);
canvas.rotate(90);
} else {
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java
index 161f7ba1..b8448e80 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerController.java
@@ -16,6 +16,12 @@
package com.wdullaer.materialdatetimepicker.date;
+import android.graphics.Typeface;
+
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+import com.wdullaer.materialdatetimepicker.enums.ScrollOrientation;
+import com.wdullaer.materialdatetimepicker.enums.Version;
+
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
@@ -39,7 +45,7 @@ public interface DatePickerController {
boolean isThemeDark();
int getAccentColor();
-
+
boolean isHighlighted(int year, int month, int day);
int getFirstDayOfWeek();
@@ -60,7 +66,11 @@ public interface DatePickerController {
Locale getLocale();
- DatePickerDialog.Version getVersion();
+ Version getVersion();
+
+ ScrollOrientation getScrollOrientation();
+
+ CalendarType getCalendarType();
- DatePickerDialog.ScrollOrientation getScrollOrientation();
+ void setFont(Typeface customFont);
}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java
index 040822aa..8a0cef49 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DatePickerDialog.java
@@ -22,10 +22,12 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -36,15 +38,21 @@
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatDialogFragment;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
+
import com.wdullaer.materialdatetimepicker.HapticFeedbackController;
+import com.wdullaer.materialdatetimepicker.JalaliCalendar;
import com.wdullaer.materialdatetimepicker.R;
import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+import com.wdullaer.materialdatetimepicker.enums.ScrollOrientation;
+import com.wdullaer.materialdatetimepicker.enums.Version;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@@ -59,16 +67,6 @@
public class DatePickerDialog extends AppCompatDialogFragment implements
OnClickListener, DatePickerController {
- public enum Version {
- VERSION_1,
- VERSION_2
- }
-
- public enum ScrollOrientation {
- HORIZONTAL,
- VERTICAL
- }
-
private static final int UNINITIALIZED = -1;
private static final int MONTH_AND_DAY_VIEW = 0;
private static final int YEAR_VIEW = 1;
@@ -100,6 +98,7 @@ public enum ScrollOrientation {
private static final String KEY_DATERANGELIMITER = "daterangelimiter";
private static final String KEY_SCROLL_ORIENTATION = "scrollorientation";
private static final String KEY_LOCALE = "locale";
+ private static final String KEY_CALENDAR_TYPE = "calendarType";
private static final int ANIMATION_DURATION = 300;
private static final int ANIMATION_DELAY = 500;
@@ -109,7 +108,8 @@ public enum ScrollOrientation {
private static SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("dd", Locale.getDefault());
private static SimpleDateFormat VERSION_2_FORMAT;
- private Calendar mCalendar = Utils.trimToMidnight(Calendar.getInstance(getTimeZone()));
+ private Calendar mCalendar;
+ private CalendarType mCalendarType;
private OnDateSetListener mCallBack;
private HashSet mListeners = new HashSet<>();
private DialogInterface.OnCancelListener mOnCancelListener;
@@ -117,6 +117,8 @@ public enum ScrollOrientation {
private AccessibleDateAnimator mAnimator;
+ private Button mOkButton;
+ private Button mCancelButton;
private TextView mDatePickerHeaderView;
private LinearLayout mMonthAndDayView;
private TextView mSelectedMonthTextView;
@@ -127,7 +129,7 @@ public enum ScrollOrientation {
private int mCurrentView = UNINITIALIZED;
- private int mWeekStart = mCalendar.getFirstDayOfWeek();
+ private int mWeekStart;
private String mTitle;
private HashSet highlightedDays = new HashSet<>();
private boolean mThemeDark = false;
@@ -182,54 +184,98 @@ protected interface OnDateChangedListener {
void onDateChanged();
}
-
public DatePickerDialog() {
// Empty constructor required for dialog fragment.
}
/**
* Create a new DatePickerDialog instance with a specific initial selection.
- * @param callBack How the parent is notified that the date is set.
- * @param year The initial year of the dialog.
- * @param monthOfYear The initial month of the dialog.
- * @param dayOfMonth The initial day of the dialog.
+ *
+ * @param callBack How the parent is notified that the date is set.
+ * @param calendarType calendarType of calendar
+ * @param year The initial year of the dialog.
+ * @param monthOfYear The initial month of the dialog.
+ * @param dayOfMonth The initial day of the dialog.
* @return a new DatePickerDialog instance.
*/
- public static DatePickerDialog newInstance(OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) {
+ public static DatePickerDialog newInstance(
+ OnDateSetListener callBack,
+ CalendarType calendarType,
+ int year,
+ int monthOfYear,
+ int dayOfMonth
+ ) {
DatePickerDialog ret = new DatePickerDialog();
- ret.initialize(callBack, year, monthOfYear, dayOfMonth);
+ ret.initialize(callBack, calendarType, year, monthOfYear, dayOfMonth);
return ret;
}
/**
* Create a new DatePickerDialog instance initialised to the current system date.
- * @param callback How the parent is notified that the date is set.
+ *
+ * @param callback How the parent is notified that the date is set.
+ * @param calendarType calendarType of calendar
* @return a new DatePickerDialog instance
*/
@SuppressWarnings({"unused", "WeakerAccess"})
- public static DatePickerDialog newInstance(OnDateSetListener callback) {
- Calendar now = Calendar.getInstance();
- return DatePickerDialog.newInstance(callback, now);
+ public static DatePickerDialog newInstance(
+ OnDateSetListener callback,
+ CalendarType calendarType
+ ) {
+ Calendar now;
+ switch (calendarType) {
+ case JALALI:
+ now = JalaliCalendar.getInstance();
+ break;
+ case GREGORIAN:
+ default:
+ now = Calendar.getInstance();
+ break;
+ }
+
+ return DatePickerDialog.newInstance(callback, calendarType, now);
}
/**
* Create a new DatePickerDialog instance with a specific initial selection.
+ *
* @param callback How the parent is notified that the date is set.
+ * @param calendarType calendarType of calendar
* @param initialSelection A Calendar object containing the original selection of the picker.
* (Time is ignored by trimming the Calendar to midnight in the current
* TimeZone of the Calendar object)
* @return a new DatePickerDialog instance
*/
@SuppressWarnings({"unused", "WeakerAccess"})
- public static DatePickerDialog newInstance(OnDateSetListener callback, Calendar initialSelection) {
+ public static DatePickerDialog newInstance(
+ OnDateSetListener callback,
+ CalendarType calendarType,
+ Calendar initialSelection
+ ) {
DatePickerDialog ret = new DatePickerDialog();
- ret.initialize(callback, initialSelection);
+ ret.initialize(callback, calendarType, initialSelection);
return ret;
}
- public void initialize(OnDateSetListener callBack, Calendar initialSelection) {
+ private void initialize(
+ OnDateSetListener callBack,
+ CalendarType calendarType,
+ Calendar initialSelection
+ ) {
mCallBack = callBack;
- mCalendar = Utils.trimToMidnight((Calendar) initialSelection.clone());
+ this.setCalendarType(calendarType);
+ switch (calendarType) {
+ case JALALI:
+ mCalendar = Utils.trimToMidnight((JalaliCalendar) initialSelection.clone());
+ mDefaultLimiter.setYearRange(1300, 1500);
+ break;
+ case GREGORIAN:
+ default:
+ mCalendar = Utils.trimToMidnight((Calendar) initialSelection.clone());
+ mDefaultLimiter.setYearRange(1900, 2100);
+ break;
+ }
+ mWeekStart = mCalendar.getFirstDayOfWeek();
mScrollOrientation = null;
//noinspection deprecation
setTimeZone(mCalendar.getTimeZone());
@@ -237,12 +283,28 @@ public void initialize(OnDateSetListener callBack, Calendar initialSelection) {
mVersion = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? Version.VERSION_1 : Version.VERSION_2;
}
- public void initialize(OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) {
- Calendar cal = Calendar.getInstance(getTimeZone());
+ public void initialize(
+ OnDateSetListener callBack,
+ CalendarType calendarType,
+ int year,
+ int monthOfYear,
+ int dayOfMonth
+ ) {
+ Calendar cal;
+ switch (calendarType) {
+ case JALALI:
+ cal = JalaliCalendar.getInstance(getTimeZone(), getLocale());
+ break;
+ case GREGORIAN:
+ default:
+ cal = Calendar.getInstance(getTimeZone());
+ break;
+ }
+
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, monthOfYear);
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
- this.initialize(callBack, cal);
+ this.initialize(callBack, calendarType, cal);
}
@Override
@@ -253,13 +315,7 @@ public void onCreate(Bundle savedInstanceState) {
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
setStyle(AppCompatDialogFragment.STYLE_NO_TITLE, 0);
mCurrentView = UNINITIALIZED;
- if (savedInstanceState != null) {
- mCalendar.set(Calendar.YEAR, savedInstanceState.getInt(KEY_SELECTED_YEAR));
- mCalendar.set(Calendar.MONTH, savedInstanceState.getInt(KEY_SELECTED_MONTH));
- mCalendar.set(Calendar.DAY_OF_MONTH, savedInstanceState.getInt(KEY_SELECTED_DAY));
- mDefaultView = savedInstanceState.getInt(KEY_DEFAULT_VIEW);
- }
- if (Build.VERSION.SDK_INT < 18) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
VERSION_2_FORMAT = new SimpleDateFormat(activity.getResources().getString(R.string.mdtp_date_v2_daymonthyear), mLocale);
} else {
VERSION_2_FORMAT = new SimpleDateFormat(DateFormat.getBestDateTimePattern(mLocale, "EEEMMMdd"), mLocale);
@@ -270,6 +326,7 @@ public void onCreate(Bundle savedInstanceState) {
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
+ outState.putSerializable(KEY_CALENDAR_TYPE, mCalendarType);
outState.putInt(KEY_SELECTED_YEAR, mCalendar.get(Calendar.YEAR));
outState.putInt(KEY_SELECTED_MONTH, mCalendar.get(Calendar.MONTH));
outState.putInt(KEY_SELECTED_DAY, mCalendar.get(Calendar.DAY_OF_MONTH));
@@ -317,6 +374,20 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
: ScrollOrientation.HORIZONTAL;
}
if (savedInstanceState != null) {
+ this.setCalendarType((CalendarType) savedInstanceState.get(KEY_CALENDAR_TYPE));
+ switch (mCalendarType) {
+ case JALALI:
+ mCalendar = JalaliCalendar.getInstance(getTimeZone(), getLocale());
+ break;
+ case GREGORIAN:
+ default:
+ mCalendar = Calendar.getInstance(getTimeZone());
+ break;
+ }
+ mCalendar.set(Calendar.YEAR, savedInstanceState.getInt(KEY_SELECTED_YEAR));
+ mCalendar.set(Calendar.MONTH, savedInstanceState.getInt(KEY_SELECTED_MONTH));
+ mCalendar.set(Calendar.DAY_OF_MONTH, savedInstanceState.getInt(KEY_SELECTED_DAY));
+ mDefaultView = savedInstanceState.getInt(KEY_DEFAULT_VIEW);
mWeekStart = savedInstanceState.getInt(KEY_WEEK_START);
currentView = savedInstanceState.getInt(KEY_CURRENT_VIEW);
listPosition = savedInstanceState.getInt(KEY_LIST_POSITION);
@@ -325,17 +396,23 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
highlightedDays = (HashSet) savedInstanceState.getSerializable(KEY_HIGHLIGHTED_DAYS);
mThemeDark = savedInstanceState.getBoolean(KEY_THEME_DARK);
mThemeDarkChanged = savedInstanceState.getBoolean(KEY_THEME_DARK_CHANGED);
- if (savedInstanceState.containsKey(KEY_ACCENT)) mAccentColor = savedInstanceState.getInt(KEY_ACCENT);
+ if (savedInstanceState.containsKey(KEY_ACCENT)) {
+ mAccentColor = savedInstanceState.getInt(KEY_ACCENT);
+ }
mVibrate = savedInstanceState.getBoolean(KEY_VIBRATE);
mDismissOnPause = savedInstanceState.getBoolean(KEY_DISMISS);
mAutoDismiss = savedInstanceState.getBoolean(KEY_AUTO_DISMISS);
mTitle = savedInstanceState.getString(KEY_TITLE);
mOkResid = savedInstanceState.getInt(KEY_OK_RESID);
mOkString = savedInstanceState.getString(KEY_OK_STRING);
- if (savedInstanceState.containsKey(KEY_OK_COLOR)) mOkColor = savedInstanceState.getInt(KEY_OK_COLOR);
+ if (savedInstanceState.containsKey(KEY_OK_COLOR)) {
+ mOkColor = savedInstanceState.getInt(KEY_OK_COLOR);
+ }
mCancelResid = savedInstanceState.getInt(KEY_CANCEL_RESID);
mCancelString = savedInstanceState.getString(KEY_CANCEL_STRING);
- if (savedInstanceState.containsKey(KEY_CANCEL_COLOR)) mCancelColor = savedInstanceState.getInt(KEY_CANCEL_COLOR);
+ if (savedInstanceState.containsKey(KEY_CANCEL_COLOR)) {
+ mCancelColor = savedInstanceState.getInt(KEY_CANCEL_COLOR);
+ }
mVersion = (Version) savedInstanceState.getSerializable(KEY_VERSION);
mScrollOrientation = (ScrollOrientation) savedInstanceState.getSerializable(KEY_SCROLL_ORIENTATION);
mTimezone = (TimeZone) savedInstanceState.getSerializable(KEY_TIMEZONE);
@@ -377,6 +454,20 @@ affect the behaviour of the picker (in the unlikely event the user reconfigures
mYearView = view.findViewById(R.id.mdtp_date_picker_year);
mYearView.setOnClickListener(this);
+ if (mVersion == Version.VERSION_2) {
+ switch (mCalendarType) {
+ case JALALI:
+ mYearView.setGravity(Gravity.END);
+ mMonthAndDayView.setGravity(Gravity.END);
+ break;
+ case GREGORIAN:
+ default:
+ mYearView.setGravity(Gravity.START);
+ mMonthAndDayView.setGravity(Gravity.START);
+ break;
+ }
+ }
+
final Activity activity = requireActivity();
mDayPickerView = new DayPickerGroup(activity, this);
mYearPickerView = new YearPickerView(activity, this);
@@ -409,43 +500,43 @@ affect the behaviour of the picker (in the unlikely event the user reconfigures
animation2.setDuration(ANIMATION_DURATION);
mAnimator.setOutAnimation(animation2);
- Button okButton = view.findViewById(R.id.mdtp_ok);
- okButton.setOnClickListener(v -> {
+ mOkButton = view.findViewById(R.id.mdtp_ok);
+ mOkButton.setOnClickListener(v -> {
tryVibrate();
notifyOnDateListener();
dismiss();
});
- okButton.setTypeface(ResourcesCompat.getFont(activity, R.font.robotomedium));
- if (mOkString != null) okButton.setText(mOkString);
- else okButton.setText(mOkResid);
+ if (mOkString != null) mOkButton.setText(mOkString);
+ else mOkButton.setText(mOkResid);
- Button cancelButton = view.findViewById(R.id.mdtp_cancel);
- cancelButton.setOnClickListener(v -> {
+ mCancelButton = view.findViewById(R.id.mdtp_cancel);
+ mCancelButton.setOnClickListener(v -> {
tryVibrate();
if (getDialog() != null) getDialog().cancel();
});
- cancelButton.setTypeface(ResourcesCompat.getFont(activity, R.font.robotomedium));
- if (mCancelString != null) cancelButton.setText(mCancelString);
- else cancelButton.setText(mCancelResid);
- cancelButton.setVisibility(isCancelable() ? View.VISIBLE : View.GONE);
+ if (mCancelString != null) mCancelButton.setText(mCancelString);
+ else mCancelButton.setText(mCancelResid);
+ mCancelButton.setVisibility(isCancelable() ? View.VISIBLE : View.GONE);
// If an accent color has not been set manually, get it from the context
if (mAccentColor == null) {
mAccentColor = Utils.getAccentColorFromThemeIfAvailable(getActivity());
}
- if (mDatePickerHeaderView != null) mDatePickerHeaderView.setBackgroundColor(Utils.darkenColor(mAccentColor));
+ if (mDatePickerHeaderView != null) {
+ mDatePickerHeaderView.setBackgroundColor(Utils.darkenColor(mAccentColor));
+ }
view.findViewById(R.id.mdtp_day_picker_selected_date_layout).setBackgroundColor(mAccentColor);
// Buttons can have a different color
if (mOkColor == null) {
mOkColor = mAccentColor;
}
- okButton.setTextColor(mOkColor);
+ mOkButton.setTextColor(mOkColor);
if (mCancelColor == null) {
mCancelColor = mAccentColor;
}
- cancelButton.setTextColor(mCancelColor);
+ mCancelButton.setTextColor(mCancelColor);
if (getDialog() == null) {
view.findViewById(R.id.mdtp_done_background).setVisibility(View.GONE);
@@ -463,11 +554,31 @@ affect the behaviour of the picker (in the unlikely event the user reconfigures
}
mHapticFeedbackController = new HapticFeedbackController(activity);
+
+ setUiFont();
+
return view;
}
+ private void setUiFont() {
+ final Typeface font = Utils.getCustomFont();
+
+ if (font == null) {
+ final Activity activity = requireActivity();
+ mOkButton.setTypeface(ResourcesCompat.getFont(activity, R.font.robotomedium));
+ mCancelButton.setTypeface(ResourcesCompat.getFont(activity, R.font.robotomedium));
+ } else {
+ if (mOkButton != null) mOkButton.setTypeface(font);
+ if (mCancelButton != null) mCancelButton.setTypeface(font);
+ if (mDatePickerHeaderView != null) mDatePickerHeaderView.setTypeface(font);
+ if (mSelectedMonthTextView != null) mSelectedMonthTextView.setTypeface(font);
+ if (mSelectedDayTextView != null) mSelectedDayTextView.setTypeface(font);
+ if (mYearView != null) mYearView.setTypeface(font);
+ }
+ }
+
@Override
- public void onConfigurationChanged(final Configuration newConfig) {
+ public void onConfigurationChanged(@NonNull final Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ViewGroup viewGroup = (ViewGroup) getView();
if (viewGroup != null) {
@@ -477,6 +588,10 @@ public void onConfigurationChanged(final Configuration newConfig) {
}
}
+ private void setCalendarType(CalendarType calendarType) {
+ this.mCalendarType = calendarType;
+ }
+
@Override
public void onResume() {
super.onResume();
@@ -491,13 +606,13 @@ public void onPause() {
}
@Override
- public void onCancel(DialogInterface dialog) {
+ public void onCancel(@NonNull DialogInterface dialog) {
super.onCancel(dialog);
if (mOnCancelListener != null) mOnCancelListener.onCancel(dialog);
}
@Override
- public void onDismiss(DialogInterface dialog) {
+ public void onDismiss(@NonNull DialogInterface dialog) {
super.onDismiss(dialog);
if (mOnDismissListener != null) mOnDismissListener.onDismiss(dialog);
}
@@ -570,27 +685,69 @@ private void setCurrentView(final int viewIndex) {
}
private void updateDisplay(boolean announce) {
- mYearView.setText(YEAR_FORMAT.format(mCalendar.getTime()));
+ switch (mCalendarType) {
+ case JALALI:
+ mYearView.setText(String.format(getLocale(), "%d", mCalendar.get(Calendar.YEAR)));
+ break;
+ case GREGORIAN:
+ default:
+ mYearView.setText(YEAR_FORMAT.format(mCalendar.getTime()));
+ break;
+ }
if (mVersion == Version.VERSION_1) {
if (mDatePickerHeaderView != null) {
if (mTitle != null)
mDatePickerHeaderView.setText(mTitle);
else {
- mDatePickerHeaderView.setText(mCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG,
- mLocale));
+ switch (mCalendarType) {
+ case JALALI:
+ mDatePickerHeaderView.setText(JalaliCalendar.getWeekDayName((mCalendar).get(Calendar.DAY_OF_WEEK)));
+ break;
+ case GREGORIAN:
+ default:
+ mDatePickerHeaderView.setText(mCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG,
+ mLocale));
+ break;
+ }
}
}
- mSelectedMonthTextView.setText(MONTH_FORMAT.format(mCalendar.getTime()));
- mSelectedDayTextView.setText(DAY_FORMAT.format(mCalendar.getTime()));
+ switch (mCalendarType) {
+ case JALALI:
+ mYearView.setText(String.format(getLocale(), "%d", mCalendar.get(Calendar.YEAR)));
+ mSelectedMonthTextView.setText(((JalaliCalendar) mCalendar).getMonthName());
+ mSelectedDayTextView.setText(String.format(getLocale(), "%02d", mCalendar.get(Calendar.DAY_OF_MONTH)));
+ break;
+ case GREGORIAN:
+ default:
+ mYearView.setText(YEAR_FORMAT.format(mCalendar.getTime()));
+ mSelectedMonthTextView.setText(MONTH_FORMAT.format(mCalendar.getTime()));
+ mSelectedDayTextView.setText(DAY_FORMAT.format(mCalendar.getTime()));
+ break;
+ }
}
if (mVersion == Version.VERSION_2) {
- mSelectedDayTextView.setText(VERSION_2_FORMAT.format(mCalendar.getTime()));
- if (mTitle != null)
- mDatePickerHeaderView.setText(mTitle.toUpperCase(mLocale));
- else
- mDatePickerHeaderView.setVisibility(View.GONE);
+ switch (mCalendarType) {
+ case JALALI:
+ JalaliCalendar cal = ((JalaliCalendar) mCalendar);
+ String dayMonthText = String.format(getLocale(), "%s %d %s",
+ cal.getWeekDayName(), cal.get(Calendar.DAY_OF_MONTH), cal.getMonthName());
+ mSelectedDayTextView.setText(dayMonthText);
+ if (mTitle != null)
+ mDatePickerHeaderView.setText(mTitle);
+ else
+ mDatePickerHeaderView.setVisibility(View.GONE);
+ break;
+ case GREGORIAN:
+ default:
+ mSelectedDayTextView.setText(VERSION_2_FORMAT.format(mCalendar.getTime()));
+ if (mTitle != null)
+ mDatePickerHeaderView.setText(mTitle.toUpperCase(mLocale));
+ else
+ mDatePickerHeaderView.setVisibility(View.GONE);
+ break;
+ }
}
// Accessibility.
@@ -876,6 +1033,7 @@ public Calendar[] getDisabledDays() {
/**
* Provide a DateRangeLimiter for full control over which dates are enabled and disabled in the picker
+ *
* @param dateRangeLimiter An implementation of the DateRangeLimiter interface
*/
@SuppressWarnings("unused")
@@ -954,6 +1112,7 @@ public Version getVersion() {
/**
* Set which way the user needs to swipe to switch months in the MonthView
+ *
* @param orientation The orientation to use
*/
public void setScrollOrientation(ScrollOrientation orientation) {
@@ -962,17 +1121,29 @@ public void setScrollOrientation(ScrollOrientation orientation) {
/**
* Get which way the user needs to swipe to switch months in the MonthView
+ *
* @return SwipeOrientation
*/
public ScrollOrientation getScrollOrientation() {
return mScrollOrientation;
}
+ @Override
+ public CalendarType getCalendarType() {
+ return mCalendarType;
+ }
+
+ @Override
+ public void setFont(Typeface customFont) {
+ Utils.setCustomFont(customFont);
+ }
+
/**
* Set which timezone the picker should use
- *
+ *
* This has been deprecated in favor of setting the TimeZone using the constructor that
* takes a Calendar object
+ *
* @param timeZone The timezone to use
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@@ -987,12 +1158,22 @@ public void setTimeZone(TimeZone timeZone) {
/**
* Set a custom locale to be used when generating various strings in the picker
+ *
* @param locale Locale
*/
@SuppressWarnings("WeakerAccess")
public void setLocale(Locale locale) {
mLocale = locale;
- mWeekStart = Calendar.getInstance(mTimezone, mLocale).getFirstDayOfWeek();
+ switch (mCalendarType) {
+ case JALALI:
+ JalaliCalendar.setLocale(locale);
+ mWeekStart = JalaliCalendar.getInstance(mTimezone, mLocale).getFirstDayOfWeek();
+ break;
+ case GREGORIAN:
+ default:
+ mWeekStart = Calendar.getInstance(mTimezone, mLocale).getFirstDayOfWeek();
+ break;
+ }
YEAR_FORMAT = new SimpleDateFormat("yyyy", locale);
MONTH_FORMAT = new SimpleDateFormat("MMM", locale);
DAY_FORMAT = new SimpleDateFormat("dd", locale);
@@ -1000,6 +1181,7 @@ public void setLocale(Locale locale) {
/**
* Return the current locale (default or other)
+ *
* @return Locale
*/
@Override
@@ -1024,6 +1206,7 @@ public void setOnDismissListener(DialogInterface.OnDismissListener onDismissList
/**
* Get a reference to the callback
+ *
* @return OnDateSetListener the callback
*/
@SuppressWarnings("unused")
@@ -1132,11 +1315,12 @@ public void tryVibrate() {
if (mVibrate) mHapticFeedbackController.tryVibrate();
}
- @Override public TimeZone getTimeZone() {
+ @Override
+ public TimeZone getTimeZone() {
return mTimezone == null ? TimeZone.getDefault() : mTimezone;
}
- public void notifyOnDateListener() {
+ private void notifyOnDateListener() {
if (mCallBack != null) {
mCallBack.onDateSet(DatePickerDialog.this, mCalendar.get(Calendar.YEAR),
mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH));
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DateRangeLimiter.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DateRangeLimiter.java
index 53763e8a..721f3573 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DateRangeLimiter.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DateRangeLimiter.java
@@ -17,6 +17,7 @@
package com.wdullaer.materialdatetimepicker.date;
import android.os.Parcelable;
+
import androidx.annotation.NonNull;
import java.util.Calendar;
@@ -28,6 +29,7 @@ public interface DateRangeLimiter extends Parcelable {
* This method should match getStartDate()
* It is recommended to keep the default implementation
* This method will be removed from this interface at the next semver major
+ *
* @return the minimum selectable year of the picker
*/
default int getMinYear() {
@@ -39,6 +41,7 @@ default int getMinYear() {
* This method should semantically match getEndDate()
* It is recommended to keep the default implementation.
* This method will be removed from this interface at the next semver major
+ *
* @return the maximum selectable year of the picker
*/
default int getMaxYear() {
@@ -49,26 +52,31 @@ default int getMaxYear() {
* getStartDate returns the minimum selectable date of the picker
* It is called in various places, including the hot loop when rendering.
* It is highly recommended to keep this method as simple as possible
+ *
* @return the minimum selectable date of the picker
*/
- @NonNull Calendar getStartDate();
+ @NonNull
+ Calendar getStartDate();
/**
* getEndDate returns the maximum selectable date of the picker
* It is called in various places, including the hot loop when rendering.
* It is highly recommended to keep this method as simple as possible
+ *
* @return the maximum selectable date of the picker
*/
- @NonNull Calendar getEndDate();
+ @NonNull
+ Calendar getEndDate();
/**
* isOutOfRange is called for each date when it is about to be rendered
* Returning true from this function will cause that particular day to be non selectable
* Since this code is called in the inner loop when rendering, it is highly recommended to
* keep the logic as simple as possible
- * @param year the year of the date
+ *
+ * @param year the year of the date
* @param month the month of the date
- * @param day the day of the month of the date
+ * @param day the day of the month of the date
* @return true if the date should be disabled, false otherwise
*/
boolean isOutOfRange(int year, int month, int day);
@@ -79,8 +87,10 @@ default int getMaxYear() {
* valid according to the constraints set by the limiter.
* This method is not called when the user selects a day, since the picker prevents the
* selection of values which satisfy `isOutOfRange`
+ *
* @param day a date with the current user selection
* @return the date after rounding to a selectable value
*/
- @NonNull Calendar setToNearestDate(@NonNull Calendar day);
+ @NonNull
+ Calendar setToNearestDate(@NonNull Calendar day);
}
\ No newline at end of file
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerGroup.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerGroup.java
index ab7e7026..e4a07b31 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerGroup.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerGroup.java
@@ -1,18 +1,21 @@
package com.wdullaer.materialdatetimepicker.date;
import android.content.Context;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
-import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.ViewCompat;
+
import com.wdullaer.materialdatetimepicker.R;
import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.ScrollOrientation;
+import com.wdullaer.materialdatetimepicker.enums.Version;
public class DayPickerGroup extends ViewGroup
implements View.OnClickListener, DayPickerView.OnPageListener {
@@ -59,7 +62,7 @@ private void init() {
prevButton = findViewById(R.id.mdtp_previous_month_arrow);
nextButton = findViewById(R.id.mdtp_next_month_arrow);
- if (controller.getVersion() == DatePickerDialog.Version.VERSION_1) {
+ if (controller.getVersion() == Version.VERSION_1) {
int size = Utils.dpToPx(16f, getResources());
prevButton.setMinimumHeight(size);
prevButton.setMinimumWidth(size);
@@ -80,7 +83,7 @@ private void init() {
}
private void updateButtonVisibility(int position) {
- final boolean isHorizontal = controller.getScrollOrientation() == DatePickerDialog.ScrollOrientation.HORIZONTAL;
+ final boolean isHorizontal = controller.getScrollOrientation() == ScrollOrientation.HORIZONTAL;
final boolean hasPrev = position > 0;
final boolean hasNext = position < (dayPickerView.getCount() - 1);
prevButton.setVisibility(isHorizontal && hasPrev ? View.VISIBLE : View.INVISIBLE);
@@ -131,7 +134,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
rightButton = nextButton;
}
- final int topMargin = controller.getVersion() == DatePickerDialog.Version.VERSION_1
+ final int topMargin = controller.getVersion() == Version.VERSION_1
? 0
: getContext().getResources().getDimensionPixelSize(R.dimen.mdtp_date_picker_view_animator_padding_v2);
final int width = right - left;
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java
index 885b9297..723e38ad 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DayPickerView.java
@@ -24,19 +24,20 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.wdullaer.materialdatetimepicker.GravitySnapHelper;
import com.wdullaer.materialdatetimepicker.Utils;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog.OnDateChangedListener;
+import com.wdullaer.materialdatetimepicker.enums.ScrollOrientation;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
/**
* This displays a list of months in a calendar format with selectable days.
*/
@@ -63,6 +64,7 @@ public abstract class DayPickerView extends RecyclerView implements OnDateChange
public interface OnPageListener {
/**
* Called when the visible page of the DayPickerView has changed
+ *
* @param position the new position visible in the DayPickerView
*/
void onPageChanged(int position);
@@ -70,9 +72,9 @@ public interface OnPageListener {
public DayPickerView(Context context, AttributeSet attrs) {
super(context, attrs);
- DatePickerDialog.ScrollOrientation scrollOrientation = Build.VERSION.SDK_INT < Build.VERSION_CODES.M
- ? DatePickerDialog.ScrollOrientation.VERTICAL
- : DatePickerDialog.ScrollOrientation.HORIZONTAL;
+ ScrollOrientation scrollOrientation = Build.VERSION.SDK_INT < Build.VERSION_CODES.M
+ ? ScrollOrientation.VERTICAL
+ : ScrollOrientation.HORIZONTAL;
init(context, scrollOrientation);
}
@@ -90,9 +92,9 @@ protected void setController(DatePickerController controller) {
refreshAdapter();
}
- public void init(Context context, DatePickerDialog.ScrollOrientation scrollOrientation) {
+ public void init(Context context, ScrollOrientation scrollOrientation) {
@RecyclerView.Orientation
- int layoutOrientation = scrollOrientation == DatePickerDialog.ScrollOrientation.VERTICAL
+ int layoutOrientation = scrollOrientation == ScrollOrientation.VERTICAL
? RecyclerView.VERTICAL
: RecyclerView.HORIZONTAL;
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context, layoutOrientation, false);
@@ -110,10 +112,10 @@ public void init(Context context, DatePickerDialog.ScrollOrientation scrollOrien
* Sets all the required fields for the list view. Override this method to
* set a different list view behavior.
*/
- protected void setUpRecyclerView(DatePickerDialog.ScrollOrientation scrollOrientation) {
+ protected void setUpRecyclerView(ScrollOrientation scrollOrientation) {
setVerticalScrollBarEnabled(false);
setFadingEdgeLength(0);
- int gravity = scrollOrientation == DatePickerDialog.ScrollOrientation.VERTICAL
+ int gravity = scrollOrientation == ScrollOrientation.VERTICAL
? Gravity.TOP
: Gravity.START;
GravitySnapHelper helper = new GravitySnapHelper(gravity, position -> {
@@ -259,8 +261,9 @@ public int getMostVisiblePosition() {
return getChildAdapterPosition(getMostVisibleMonth());
}
- public @Nullable MonthView getMostVisibleMonth() {
- boolean verticalScroll = mController.getScrollOrientation() == DatePickerDialog.ScrollOrientation.VERTICAL;
+ public @Nullable
+ MonthView getMostVisibleMonth() {
+ boolean verticalScroll = mController.getScrollOrientation() == ScrollOrientation.VERTICAL;
final int maxSize = verticalScroll ? getHeight() : getWidth();
int maxDisplayedSize = 0;
int i = 0;
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiter.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiter.java
index 5f4ef466..8d0fcf36 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiter.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiter.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -40,7 +41,8 @@ class DefaultDateRangeLimiter implements DateRangeLimiter {
private TreeSet selectableDays = new TreeSet<>();
private HashSet disabledDays = new HashSet<>();
- DefaultDateRangeLimiter() {}
+ DefaultDateRangeLimiter() {
+ }
@SuppressWarnings({"unchecked", "WeakerAccess"})
public DefaultDateRangeLimiter(Parcel in) {
@@ -112,19 +114,23 @@ void setYearRange(int startYear, int endYear) {
mMaxYear = endYear;
}
- @Nullable Calendar getMinDate() {
+ @Nullable
+ Calendar getMinDate() {
return mMinDate;
}
- @Nullable Calendar getMaxDate() {
+ @Nullable
+ Calendar getMaxDate() {
return mMaxDate;
}
- @Nullable Calendar[] getSelectableDays() {
- return selectableDays.isEmpty() ? null : selectableDays.toArray(new Calendar[0]);
+ @Nullable
+ Calendar[] getSelectableDays() {
+ return selectableDays.isEmpty() ? null : selectableDays.toArray(new Calendar[0]);
}
- @Nullable Calendar[] getDisabledDays() {
+ @Nullable
+ Calendar[] getDisabledDays() {
return disabledDays.isEmpty() ? null : disabledDays.toArray(new Calendar[0]);
}
@@ -143,7 +149,8 @@ public int getMaxYear() {
}
@Override
- public @NonNull Calendar getStartDate() {
+ public @NonNull
+ Calendar getStartDate() {
if (!selectableDays.isEmpty()) return (Calendar) selectableDays.first().clone();
if (mMinDate != null) return (Calendar) mMinDate.clone();
TimeZone timeZone = mController == null ? TimeZone.getDefault() : mController.getTimeZone();
@@ -155,7 +162,8 @@ public int getMaxYear() {
}
@Override
- public @NonNull Calendar getEndDate() {
+ public @NonNull
+ Calendar getEndDate() {
if (!selectableDays.isEmpty()) return (Calendar) selectableDays.last().clone();
if (mMaxDate != null) return (Calendar) mMaxDate.clone();
TimeZone timeZone = mController == null ? TimeZone.getDefault() : mController.getTimeZone();
@@ -203,7 +211,8 @@ private boolean isAfterMax(@NonNull Calendar calendar) {
}
@Override
- public @NonNull Calendar setToNearestDate(@NonNull Calendar calendar) {
+ public @NonNull
+ Calendar setToNearestDate(@NonNull Calendar calendar) {
if (!selectableDays.isEmpty()) {
Calendar newCalendar = null;
Calendar higher = selectableDays.ceiling(calendar);
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthAdapter.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthAdapter.java
index 6d41fa75..b3d1f070 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthAdapter.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthAdapter.java
@@ -17,11 +17,12 @@
package com.wdullaer.materialdatetimepicker.date;
import android.content.Context;
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
import android.view.ViewGroup;
import android.widget.AbsListView.LayoutParams;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.wdullaer.materialdatetimepicker.date.MonthAdapter.MonthViewHolder;
import com.wdullaer.materialdatetimepicker.date.MonthView.OnDayClickListener;
@@ -155,7 +156,8 @@ public MonthViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewTyp
return new MonthViewHolder(v);
}
- @Override public void onBindViewHolder(@NonNull MonthViewHolder holder, int position) {
+ @Override
+ public void onBindViewHolder(@NonNull MonthViewHolder holder, int position) {
holder.bind(position, mController, mSelectedDay);
}
@@ -164,7 +166,8 @@ public long getItemId(int position) {
return position;
}
- @Override public int getItemCount() {
+ @Override
+ public int getItemCount() {
Calendar endDate = mController.getEndDate();
Calendar startDate = mController.getStartDate();
int endMonth = endDate.get(Calendar.YEAR) * MONTHS_IN_YEAR + endDate.get(Calendar.MONTH);
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java
index 70325d9b..10c97a15 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/MonthView.java
@@ -26,11 +26,6 @@
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import androidx.customview.widget.ExploreByTouchHelper;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -38,8 +33,17 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
+
+import com.wdullaer.materialdatetimepicker.JalaliCalendar;
import com.wdullaer.materialdatetimepicker.R;
import com.wdullaer.materialdatetimepicker.date.MonthAdapter.CalendarDay;
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+import com.wdullaer.materialdatetimepicker.enums.Version;
import java.security.InvalidParameterException;
import java.text.SimpleDateFormat;
@@ -138,8 +142,17 @@ public MonthView(Context context, AttributeSet attr, DatePickerController contro
mController = controller;
Resources res = context.getResources();
- mDayLabelCalendar = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
- mCalendar = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
+ switch (controller.getCalendarType()) {
+ case JALALI:
+ mDayLabelCalendar = JalaliCalendar.getInstance(mController.getTimeZone(), mController.getLocale());
+ mCalendar = JalaliCalendar.getInstance(mController.getTimeZone(), mController.getLocale());
+ break;
+ case GREGORIAN:
+ default:
+ mDayLabelCalendar = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
+ mCalendar = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
+ break;
+ }
mDayOfWeekTypeface = res.getString(R.string.mdtp_day_of_week_label_typeface);
mMonthTitleTypeface = res.getString(R.string.mdtp_sans_serif);
@@ -167,7 +180,7 @@ public MonthView(Context context, AttributeSet attr, DatePickerController contro
MONTH_DAY_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.mdtp_month_day_label_text_size);
MONTH_HEADER_SIZE = res.getDimensionPixelOffset(R.dimen.mdtp_month_list_item_header_height);
MONTH_HEADER_SIZE_V2 = res.getDimensionPixelOffset(R.dimen.mdtp_month_list_item_header_height_v2);
- DAY_SELECTED_CIRCLE_SIZE = mController.getVersion() == DatePickerDialog.Version.VERSION_1
+ DAY_SELECTED_CIRCLE_SIZE = mController.getVersion() == Version.VERSION_1
? res.getDimensionPixelSize(R.dimen.mdtp_day_number_select_circle_radius)
: res.getDimensionPixelSize(R.dimen.mdtp_day_number_select_circle_radius_v2);
DAY_HIGHLIGHT_CIRCLE_SIZE = res
@@ -175,7 +188,7 @@ public MonthView(Context context, AttributeSet attr, DatePickerController contro
DAY_HIGHLIGHT_CIRCLE_MARGIN = res
.getDimensionPixelSize(R.dimen.mdtp_day_highlight_circle_margin);
- if (mController.getVersion() == DatePickerDialog.Version.VERSION_1) {
+ if (mController.getVersion() == Version.VERSION_1) {
mRowHeight = (res.getDimensionPixelOffset(R.dimen.mdtp_date_picker_view_animator_height)
- getMonthHeaderSize()) / MAX_NUM_ROWS;
} else {
@@ -183,7 +196,7 @@ public MonthView(Context context, AttributeSet attr, DatePickerController contro
- getMonthHeaderSize() - MONTH_DAY_LABEL_TEXT_SIZE * 2) / MAX_NUM_ROWS;
}
- mEdgePadding = mController.getVersion() == DatePickerDialog.Version.VERSION_1
+ mEdgePadding = mController.getVersion() == Version.VERSION_1
? 0
: context.getResources().getDimensionPixelSize(R.dimen.mdtp_date_picker_view_animator_padding_v2);
@@ -222,13 +235,11 @@ public boolean dispatchHoverEvent(@NonNull MotionEvent event) {
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- final int day = getDayFromLocation(event.getX(), event.getY());
- if (day >= 0) {
- onDayClick(day);
- }
- break;
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ final int day = getDayFromLocation(event.getX(), event.getY());
+ if (day >= 0) {
+ onDayClick(day);
+ }
}
return true;
}
@@ -239,7 +250,7 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
*/
protected void initView() {
mMonthTitlePaint = new Paint();
- if (mController.getVersion() == DatePickerDialog.Version.VERSION_1)
+ if (mController.getVersion() == Version.VERSION_1)
mMonthTitlePaint.setFakeBoldText(true);
mMonthTitlePaint.setAntiAlias(true);
mMonthTitlePaint.setTextSize(MONTH_LABEL_TEXT_SIZE);
@@ -302,7 +313,16 @@ public void setMonthParams(int selectedDay, int year, int month, int weekStart)
// Figure out what day today is
//final Time today = new Time(Time.getCurrentTimezone());
//today.setToNow();
- final Calendar today = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
+ Calendar today;
+ switch (mController.getCalendarType()) {
+ case JALALI:
+ today = JalaliCalendar.getInstance(mController.getTimeZone(), mController.getLocale());
+ break;
+ case GREGORIAN:
+ default:
+ today = Calendar.getInstance(mController.getTimeZone(), mController.getLocale());
+ break;
+ }
mHasToday = false;
mToday = -1;
@@ -374,7 +394,7 @@ public int getYear() {
* @return The height in pixels of a row of day labels
*/
public int getMonthHeight() {
- int scaleFactor = mController.getVersion() == DatePickerDialog.Version.VERSION_1 ? 2 : 3;
+ int scaleFactor = mController.getVersion() == Version.VERSION_1 ? 2 : 3;
return getMonthHeaderSize() - MONTH_DAY_LABEL_TEXT_SIZE * scaleFactor;
}
@@ -396,18 +416,24 @@ public int getEdgePadding() {
* A wrapper to the MonthHeaderSize to allow override it in children
*/
protected int getMonthHeaderSize() {
- return mController.getVersion() == DatePickerDialog.Version.VERSION_1
+ return mController.getVersion() == Version.VERSION_1
? MONTH_HEADER_SIZE
: MONTH_HEADER_SIZE_V2;
}
@NonNull
private String getMonthAndYearString() {
+ if (mController.getCalendarType() == CalendarType.JALALI) {
+ return ((JalaliCalendar) mCalendar).getMonthName() + " " + ((JalaliCalendar) mCalendar).get(Calendar.YEAR);
+ }
Locale locale = mController.getLocale();
String pattern = "MMMM yyyy";
- if (Build.VERSION.SDK_INT < 18) pattern = getContext().getResources().getString(R.string.mdtp_date_v1_monthyear);
- else pattern = DateFormat.getBestDateTimePattern(locale, pattern);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ pattern = getContext().getResources().getString(R.string.mdtp_date_v1_monthyear);
+ } else {
+ pattern = DateFormat.getBestDateTimePattern(locale, pattern);
+ }
SimpleDateFormat formatter = new SimpleDateFormat(pattern, locale);
formatter.setTimeZone(mController.getTimeZone());
@@ -418,7 +444,7 @@ private String getMonthAndYearString() {
protected void drawMonthTitle(Canvas canvas) {
int x = mWidth / 2;
- int y = mController.getVersion() == DatePickerDialog.Version.VERSION_1
+ int y = mController.getVersion() == Version.VERSION_1
? (getMonthHeaderSize() - MONTH_DAY_LABEL_TEXT_SIZE) / 2
: getMonthHeaderSize() / 2 - MONTH_DAY_LABEL_TEXT_SIZE;
canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint);
@@ -433,7 +459,15 @@ protected void drawMonthDayLabels(Canvas canvas) {
int calendarDay = (i + mWeekStart) % mNumDays;
mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
- String weekString = getWeekDayLabel(mDayLabelCalendar);
+ String weekString = "";
+ switch (mController.getCalendarType()) {
+ case GREGORIAN:
+ weekString = getWeekDayLabel(mDayLabelCalendar);
+ break;
+ case JALALI:
+ weekString = JalaliCalendar.getWeekDayName((mDayLabelCalendar).get(Calendar.DAY_OF_WEEK)).substring(0, 1);
+ break;
+ }
canvas.drawText(weekString, x, y, mMonthDayLabelPaint);
}
}
@@ -553,9 +587,9 @@ private void onDayClick(int day) {
}
/**
- * @param year as an int
+ * @param year as an int
* @param month as an int
- * @param day as an int
+ * @param day as an int
* @return true if the given date should be highlighted
*/
protected boolean isHighlighted(int year, int month, int day) {
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java
index cb886a8e..1a31186a 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/SimpleMonthView.java
@@ -18,9 +18,13 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
+import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.Version;
+
public class SimpleMonthView extends MonthView {
public SimpleMonthView(Context context, AttributeSet attr, DatePickerController controller) {
@@ -30,6 +34,7 @@ public SimpleMonthView(Context context, AttributeSet attr, DatePickerController
@Override
public void drawMonthDay(Canvas canvas, int year, int month, int day,
int x, int y, int startX, int stopX, int startY, int stopY) {
+ final Typeface font = Utils.getCustomFont();
if (mSelectedDay == day) {
canvas.drawCircle(x, y - (MINI_DAY_NUMBER_TEXT_SIZE / 3), DAY_SELECTED_CIRCLE_SIZE,
mSelectedCirclePaint);
@@ -38,16 +43,28 @@ public void drawMonthDay(Canvas canvas, int year, int month, int day,
if (isHighlighted(year, month, day) && mSelectedDay != day) {
canvas.drawCircle(x, y + MINI_DAY_NUMBER_TEXT_SIZE - DAY_HIGHLIGHT_CIRCLE_MARGIN,
DAY_HIGHLIGHT_CIRCLE_SIZE, mSelectedCirclePaint);
- mMonthNumPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
+ if (font != null) {
+ mMonthNumPaint.setTypeface(Typeface.create(font, Typeface.BOLD));
+ } else {
+ mMonthNumPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
+ }
} else {
- mMonthNumPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
+ if (font != null) {
+ mMonthNumPaint.setTypeface(Typeface.create(font, Typeface.NORMAL));
+ } else {
+ mMonthNumPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
+ }
}
// gray out the day number if it's outside the range.
if (mController.isOutOfRange(year, month, day)) {
mMonthNumPaint.setColor(mDisabledDayTextColor);
} else if (mSelectedDay == day) {
- mMonthNumPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
+ if (font != null) {
+ mMonthNumPaint.setTypeface(Typeface.create(font, Typeface.BOLD));
+ } else {
+ mMonthNumPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
+ }
mMonthNumPaint.setColor(mSelectedDayTextColor);
} else if (mHasToday && mToday == day) {
mMonthNumPaint.setColor(mTodayNumberColor);
@@ -57,4 +74,51 @@ public void drawMonthDay(Canvas canvas, int year, int month, int day,
canvas.drawText(String.format(mController.getLocale(), "%d", day), x, y, mMonthNumPaint);
}
+
+ @Override
+ protected void initView() {
+
+ final Typeface font = Utils.getCustomFont();
+
+ mMonthTitlePaint = new Paint();
+ if (mController.getVersion() == Version.VERSION_1)
+ mMonthTitlePaint.setFakeBoldText(true);
+ mMonthTitlePaint.setAntiAlias(true);
+ mMonthTitlePaint.setTextSize(MONTH_LABEL_TEXT_SIZE);
+ if (font != null) {
+ mMonthTitlePaint.setTypeface(font);
+ }
+ mMonthTitlePaint.setColor(mDayTextColor);
+ mMonthTitlePaint.setTextAlign(Paint.Align.CENTER);
+ mMonthTitlePaint.setStyle(Paint.Style.FILL);
+
+ mSelectedCirclePaint = new Paint();
+ mSelectedCirclePaint.setFakeBoldText(true);
+ mSelectedCirclePaint.setAntiAlias(true);
+ mSelectedCirclePaint.setColor(mTodayNumberColor);
+ mSelectedCirclePaint.setTextAlign(Paint.Align.CENTER);
+ mSelectedCirclePaint.setStyle(Paint.Style.FILL);
+ mSelectedCirclePaint.setAlpha(255);
+
+ mMonthDayLabelPaint = new Paint();
+ mMonthDayLabelPaint.setAntiAlias(true);
+ mMonthDayLabelPaint.setTextSize(MONTH_DAY_LABEL_TEXT_SIZE);
+ mMonthDayLabelPaint.setColor(mMonthDayTextColor);
+ if (font != null) {
+ mMonthDayLabelPaint.setTypeface(font);
+ }
+ mMonthDayLabelPaint.setStyle(Paint.Style.FILL);
+ mMonthDayLabelPaint.setTextAlign(Paint.Align.CENTER);
+ mMonthDayLabelPaint.setFakeBoldText(true);
+
+ mMonthNumPaint = new Paint();
+ mMonthNumPaint.setAntiAlias(true);
+ mMonthNumPaint.setTextSize(MINI_DAY_NUMBER_TEXT_SIZE);
+ mMonthNumPaint.setStyle(Paint.Style.FILL);
+ mMonthNumPaint.setTextAlign(Paint.Align.CENTER);
+ mMonthNumPaint.setFakeBoldText(false);
+ if (font != null) {
+ mMonthNumPaint.setTypeface(font);
+ }
+ }
}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/TextViewWithCircularIndicator.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/TextViewWithCircularIndicator.java
index 36ca105e..638d6e53 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/TextViewWithCircularIndicator.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/TextViewWithCircularIndicator.java
@@ -24,9 +24,10 @@
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
+import android.util.AttributeSet;
+
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
-import android.util.AttributeSet;
import com.wdullaer.materialdatetimepicker.R;
@@ -69,8 +70,9 @@ public void setAccentColor(int color, boolean darkMode) {
/**
* Programmatically set the color state list (see mdtp_date_picker_year_selector)
+ *
* @param accentColor pressed state text color
- * @param darkMode current theme mode
+ * @param darkMode current theme mode
* @return ColorStateList with pressed state
*/
private ColorStateList createTextColor(int accentColor, boolean darkMode) {
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/YearPickerView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/YearPickerView.java
index 04c7fdca..c6ee9d5a 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/date/YearPickerView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/date/YearPickerView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Typeface;
import android.graphics.drawable.StateListDrawable;
import android.view.LayoutInflater;
import android.view.View;
@@ -30,7 +31,9 @@
import android.widget.TextView;
import com.wdullaer.materialdatetimepicker.R;
+import com.wdullaer.materialdatetimepicker.Utils;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog.OnDateChangedListener;
+import com.wdullaer.materialdatetimepicker.enums.Version;
/**
* Displays a selectable list of years.
@@ -50,9 +53,9 @@ public YearPickerView(Context context, DatePickerController controller) {
LayoutParams.WRAP_CONTENT);
setLayoutParams(frame);
Resources res = context.getResources();
- mViewSize = mController.getVersion() == DatePickerDialog.Version.VERSION_1
- ? res.getDimensionPixelOffset(R.dimen.mdtp_date_picker_view_animator_height)
- : res.getDimensionPixelOffset(R.dimen.mdtp_date_picker_view_animator_height_v2);
+ mViewSize = mController.getVersion() == Version.VERSION_1
+ ? res.getDimensionPixelOffset(R.dimen.mdtp_date_picker_view_animator_height)
+ : res.getDimensionPixelOffset(R.dimen.mdtp_date_picker_view_animator_height_v2);
mChildSize = res.getDimensionPixelOffset(R.dimen.mdtp_year_label_height);
setVerticalFadingEdgeEnabled(true);
setFadingEdgeLength(mChildSize / 3);
@@ -125,12 +128,16 @@ public View getView(int position, View convertView, ViewGroup parent) {
v = (TextViewWithCircularIndicator) convertView;
} else {
v = (TextViewWithCircularIndicator) LayoutInflater.from(parent.getContext())
- .inflate(R.layout.mdtp_year_label_text_view, parent, false);
+ .inflate(R.layout.mdtp_year_label_text_view, parent, false);
v.setAccentColor(mController.getAccentColor(), mController.isThemeDark());
}
+ final Typeface font = Utils.getCustomFont();
+ if (font != null) {
+ v.setTypeface(font);
+ }
int year = mMinYear + position;
boolean selected = mController.getSelectedDay().year == year;
- v.setText(String.format(mController.getLocale(),"%d", year));
+ v.setText(String.format(mController.getLocale(), "%d", year));
v.drawIndicator(selected);
v.requestLayout();
if (selected) {
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/CalendarType.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/CalendarType.java
new file mode 100644
index 00000000..ba725714
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/CalendarType.java
@@ -0,0 +1,6 @@
+package com.wdullaer.materialdatetimepicker.enums;
+
+public enum CalendarType {
+ GREGORIAN,
+ JALALI
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/ScrollOrientation.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/ScrollOrientation.java
new file mode 100644
index 00000000..ca543395
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/ScrollOrientation.java
@@ -0,0 +1,6 @@
+package com.wdullaer.materialdatetimepicker.enums;
+
+public enum ScrollOrientation {
+ HORIZONTAL,
+ VERTICAL
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/Version.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/Version.java
new file mode 100644
index 00000000..177938f9
--- /dev/null
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/enums/Version.java
@@ -0,0 +1,6 @@
+package com.wdullaer.materialdatetimepicker.enums;
+
+public enum Version {
+ VERSION_1,
+ VERSION_2
+}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/AmPmCirclesView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/AmPmCirclesView.java
index f87e1111..908ae5d5 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/AmPmCirclesView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/AmPmCirclesView.java
@@ -20,14 +20,16 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.Typeface;
import android.graphics.Paint.Align;
-import androidx.core.content.ContextCompat;
+import android.graphics.Typeface;
import android.util.Log;
import android.view.View;
+import androidx.core.content.ContextCompat;
+
import com.wdullaer.materialdatetimepicker.R;
import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
import java.text.DateFormatSymbols;
import java.util.Locale;
@@ -74,7 +76,7 @@ public AmPmCirclesView(Context context) {
mIsInitialized = false;
}
- public void initialize(Context context, Locale locale, TimePickerController controller, int amOrPm) {
+ public void initialize(CalendarType type, Context context, Locale locale, TimePickerController controller, int amOrPm) {
if (mIsInitialized) {
Log.e(TAG, "AmPmCirclesView may only be initialized once.");
return;
@@ -100,7 +102,12 @@ public void initialize(Context context, Locale locale, TimePickerController cont
String typefaceFamily = res.getString(R.string.mdtp_sans_serif);
Typeface tf = Typeface.create(typefaceFamily, Typeface.NORMAL);
- mPaint.setTypeface(tf);
+ final Typeface font = Utils.getCustomFont();
+ if (font != null) {
+ mPaint.setTypeface(font);
+ } else {
+ mPaint.setTypeface(tf);
+ }
mPaint.setAntiAlias(true);
mPaint.setTextAlign(Align.CENTER);
@@ -109,8 +116,17 @@ public void initialize(Context context, Locale locale, TimePickerController cont
mAmPmCircleRadiusMultiplier =
Float.parseFloat(res.getString(R.string.mdtp_ampm_circle_radius_multiplier));
String[] amPmTexts = new DateFormatSymbols(locale).getAmPmStrings();
- mAmText = amPmTexts[0];
- mPmText = amPmTexts[1];
+ switch (type) {
+ case JALALI:
+ mAmText = "ق.ظ";
+ mPmText = "ب.ظ";
+ break;
+ case GREGORIAN:
+ default:
+ mAmText = amPmTexts[0];
+ mPmText = amPmTexts[1];
+ break;
+ }
mAmDisabled = controller.isAmDisabled();
mPmDisabled = controller.isPmDisabled();
@@ -137,16 +153,16 @@ public int getIsTouchingAmOrPm(float xCoord, float yCoord) {
return -1;
}
- int squaredYDistance = (int) ((yCoord - mAmPmYCenter)*(yCoord - mAmPmYCenter));
+ int squaredYDistance = (int) ((yCoord - mAmPmYCenter) * (yCoord - mAmPmYCenter));
int distanceToAmCenter =
- (int) Math.sqrt((xCoord - mAmXCenter)*(xCoord - mAmXCenter) + squaredYDistance);
+ (int) Math.sqrt((xCoord - mAmXCenter) * (xCoord - mAmXCenter) + squaredYDistance);
if (distanceToAmCenter <= mAmPmCircleRadius && !mAmDisabled) {
return AM;
}
int distanceToPmCenter =
- (int) Math.sqrt((xCoord - mPmXCenter)*(xCoord - mPmXCenter) + squaredYDistance);
+ (int) Math.sqrt((xCoord - mPmXCenter) * (xCoord - mPmXCenter) + squaredYDistance);
if (distanceToPmCenter <= mAmPmCircleRadius && !mPmDisabled) {
return PM;
}
@@ -168,7 +184,7 @@ public void onDraw(Canvas canvas) {
int circleRadius =
(int) (Math.min(layoutXCenter, layoutYCenter) * mCircleRadiusMultiplier);
mAmPmCircleRadius = (int) (circleRadius * mAmPmCircleRadiusMultiplier);
- layoutYCenter += mAmPmCircleRadius*0.75;
+ layoutYCenter += mAmPmCircleRadius * 0.75;
int textSize = mAmPmCircleRadius * 3 / 4;
mPaint.setTextSize(textSize);
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/CircleView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/CircleView.java
index 46ff501a..f40682bb 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/CircleView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/CircleView.java
@@ -20,11 +20,13 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
-import androidx.core.content.ContextCompat;
import android.util.Log;
import android.view.View;
+import androidx.core.content.ContextCompat;
+
import com.wdullaer.materialdatetimepicker.R;
+import com.wdullaer.materialdatetimepicker.enums.Version;
/**
* Draws a simple white circle on which the numbers will be drawn.
@@ -65,7 +67,7 @@ public void initialize(Context context, TimePickerController controller) {
mPaint.setAntiAlias(true);
mIs24HourMode = controller.is24HourMode();
- if (mIs24HourMode || controller.getVersion() != TimePickerDialog.Version.VERSION_1) {
+ if (mIs24HourMode || controller.getVersion() != Version.VERSION_1) {
mCircleRadiusMultiplier = Float.parseFloat(
res.getString(R.string.mdtp_circle_radius_multiplier_24HourMode));
} else {
@@ -95,7 +97,7 @@ public void onDraw(Canvas canvas) {
// a slightly higher center. To keep the entire view centered vertically, we'll
// have to push it up by half the radius of the AM/PM circles.
int amPmCircleRadius = (int) (mCircleRadius * mAmPmCircleRadiusMultiplier);
- mYCenter -= amPmCircleRadius*0.75;
+ mYCenter -= amPmCircleRadius * 0.75;
}
mDrawValuesReady = true;
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiter.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiter.java
index 39d6cbfa..74b36c6c 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiter.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiter.java
@@ -2,6 +2,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -24,7 +25,8 @@ class DefaultTimepointLimiter implements TimepointLimiter {
private Timepoint mMinTime;
private Timepoint mMaxTime;
- DefaultTimepointLimiter() {}
+ DefaultTimepointLimiter() {
+ }
@SuppressWarnings("WeakerAccess")
public DefaultTimepointLimiter(Parcel in) {
@@ -61,13 +63,13 @@ public DefaultTimepointLimiter[] newArray(int size) {
};
void setMinTime(@NonNull Timepoint minTime) {
- if(mMaxTime != null && minTime.compareTo(mMaxTime) > 0)
+ if (mMaxTime != null && minTime.compareTo(mMaxTime) > 0)
throw new IllegalArgumentException("Minimum time must be smaller than the maximum time");
mMinTime = minTime;
}
void setMaxTime(@NonNull Timepoint maxTime) {
- if(mMinTime != null && maxTime.compareTo(mMinTime) < 0)
+ if (mMinTime != null && maxTime.compareTo(mMinTime) < 0)
throw new IllegalArgumentException("Maximum time must be greater than the minimum time");
mMaxTime = maxTime;
}
@@ -82,23 +84,28 @@ void setDisabledTimes(@NonNull Timepoint[] disabledTimes) {
exclusiveSelectableTimes = getExclusiveSelectableTimes(mSelectableTimes, mDisabledTimes);
}
- @Nullable Timepoint getMinTime() {
+ @Nullable
+ Timepoint getMinTime() {
return mMinTime;
}
- @Nullable Timepoint getMaxTime() {
+ @Nullable
+ Timepoint getMaxTime() {
return mMaxTime;
}
- @NonNull Timepoint[] getSelectableTimes() {
+ @NonNull
+ Timepoint[] getSelectableTimes() {
return mSelectableTimes.toArray(new Timepoint[mSelectableTimes.size()]);
}
- @NonNull Timepoint[] getDisabledTimes() {
+ @NonNull
+ Timepoint[] getDisabledTimes() {
return mDisabledTimes.toArray(new Timepoint[mDisabledTimes.size()]);
}
- @NonNull private TreeSet getExclusiveSelectableTimes(@NonNull TreeSet selectable, @NonNull TreeSet disabled) {
+ @NonNull
+ private TreeSet getExclusiveSelectableTimes(@NonNull TreeSet selectable, @NonNull TreeSet disabled) {
TreeSet output = new TreeSet<>(selectable);
output.removeAll(disabled);
return output;
@@ -111,7 +118,7 @@ public boolean isOutOfRange(@Nullable Timepoint current, int index, @NonNull Tim
if (index == HOUR_INDEX) {
if (mMinTime != null && mMinTime.getHour() > current.getHour()) return true;
- if (mMaxTime != null && mMaxTime.getHour()+1 <= current.getHour()) return true;
+ if (mMaxTime != null && mMaxTime.getHour() + 1 <= current.getHour()) return true;
if (!exclusiveSelectableTimes.isEmpty()) {
Timepoint ceil = exclusiveSelectableTimes.ceiling(current);
@@ -126,8 +133,7 @@ public boolean isOutOfRange(@Nullable Timepoint current, int index, @NonNull Tim
}
return false;
- }
- else if (index == MINUTE_INDEX) {
+ } else if (index == MINUTE_INDEX) {
if (mMinTime != null) {
Timepoint roundedMin = new Timepoint(mMinTime.getHour(), mMinTime.getMinute());
if (roundedMin.compareTo(current) > 0) return true;
@@ -153,8 +159,7 @@ else if (index == MINUTE_INDEX) {
}
return false;
- }
- else return isOutOfRange(current);
+ } else return isOutOfRange(current);
}
public boolean isOutOfRange(@NonNull Timepoint current) {
@@ -174,7 +179,8 @@ public boolean isAmDisabled() {
if (mMinTime != null && mMinTime.compareTo(midday) >= 0) return true;
- if (!exclusiveSelectableTimes.isEmpty()) return exclusiveSelectableTimes.first().compareTo(midday) >= 0;
+ if (!exclusiveSelectableTimes.isEmpty())
+ return exclusiveSelectableTimes.first().compareTo(midday) >= 0;
return false;
}
@@ -186,13 +192,15 @@ public boolean isPmDisabled() {
if (mMaxTime != null && mMaxTime.compareTo(midday) < 0) return true;
- if (!exclusiveSelectableTimes.isEmpty()) return exclusiveSelectableTimes.last().compareTo(midday) < 0;
+ if (!exclusiveSelectableTimes.isEmpty())
+ return exclusiveSelectableTimes.last().compareTo(midday) < 0;
return false;
}
@Override
- public @NonNull Timepoint roundToNearest(@NonNull Timepoint time,@Nullable Timepoint.TYPE type, @NonNull Timepoint.TYPE resolution) {
+ public @NonNull
+ Timepoint roundToNearest(@NonNull Timepoint time, @Nullable Timepoint.TYPE type, @NonNull Timepoint.TYPE resolution) {
if (mMinTime != null && mMinTime.compareTo(time) > 0) return mMinTime;
if (mMaxTime != null && mMaxTime.compareTo(time) < 0) return mMaxTime;
@@ -213,22 +221,29 @@ public boolean isPmDisabled() {
}
if (type == Timepoint.TYPE.HOUR) {
- if (floor.getHour() != time.getHour() && ceil.getHour() == time.getHour()) return ceil;
- if (floor.getHour() == time.getHour() && ceil.getHour() != time.getHour()) return floor;
- if (floor.getHour() != time.getHour() && ceil.getHour() != time.getHour()) return time;
+ if (floor.getHour() != time.getHour() && ceil.getHour() == time.getHour())
+ return ceil;
+ if (floor.getHour() == time.getHour() && ceil.getHour() != time.getHour())
+ return floor;
+ if (floor.getHour() != time.getHour() && ceil.getHour() != time.getHour())
+ return time;
}
if (type == Timepoint.TYPE.MINUTE) {
- if (floor.getHour() != time.getHour() && ceil.getHour() != time.getHour()) return time;
+ if (floor.getHour() != time.getHour() && ceil.getHour() != time.getHour())
+ return time;
if (floor.getHour() != time.getHour() && ceil.getHour() == time.getHour()) {
return ceil.getMinute() == time.getMinute() ? ceil : time;
}
if (floor.getHour() == time.getHour() && ceil.getHour() != time.getHour()) {
return floor.getMinute() == time.getMinute() ? floor : time;
}
- if (floor.getMinute() != time.getMinute() && ceil.getMinute() == time.getMinute()) return ceil;
- if (floor.getMinute() == time.getMinute() && ceil.getMinute() != time.getMinute()) return floor;
- if (floor.getMinute() != time.getMinute() && ceil.getMinute() != time.getMinute()) return time;
+ if (floor.getMinute() != time.getMinute() && ceil.getMinute() == time.getMinute())
+ return ceil;
+ if (floor.getMinute() == time.getMinute() && ceil.getMinute() != time.getMinute())
+ return floor;
+ if (floor.getMinute() != time.getMinute() && ceil.getMinute() != time.getMinute())
+ return time;
}
int floorDist = Math.abs(time.compareTo(floor));
@@ -252,7 +267,8 @@ public boolean isPmDisabled() {
boolean ceilDisabled = time.equals(ceil, Timepoint.TYPE.MINUTE);
boolean floorDisabled = time.equals(floor, Timepoint.TYPE.MINUTE);
- if (ceilDisabled || floorDisabled) return searchValidTimePoint(time, type, resolution);
+ if (ceilDisabled || floorDisabled)
+ return searchValidTimePoint(time, type, resolution);
return time;
}
@@ -262,7 +278,8 @@ public boolean isPmDisabled() {
boolean ceilDisabled = time.equals(ceil, Timepoint.TYPE.HOUR);
boolean floorDisabled = time.equals(floor, Timepoint.TYPE.HOUR);
- if (ceilDisabled || floorDisabled) return searchValidTimePoint(time, type, resolution);
+ if (ceilDisabled || floorDisabled)
+ return searchValidTimePoint(time, type, resolution);
return time;
}
}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialPickerLayout.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialPickerLayout.java
index 6c6dc889..384556fb 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialPickerLayout.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialPickerLayout.java
@@ -22,9 +22,6 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import androidx.annotation.NonNull;
-import androidx.core.content.ContextCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
@@ -38,7 +35,13 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+
import com.wdullaer.materialdatetimepicker.R;
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+import com.wdullaer.materialdatetimepicker.enums.Version;
import java.util.Calendar;
import java.util.Locale;
@@ -98,7 +101,9 @@ public class RadialPickerLayout extends FrameLayout implements OnTouchListener {
public interface OnValueSelectedListener {
void onValueSelected(Timepoint newTime);
+
void enablePicker();
+
void advancePicker(int index);
}
@@ -156,13 +161,21 @@ public void setOnValueSelectedListener(OnValueSelectedListener listener) {
/**
* Initialize the Layout with starting values.
- * @param context A context needed to inflate resources
- * @param locale A Locale to be used when generating strings
- * @param initialTime The initial selection of the Timepicker
+ *
+ * @param calendarType Type of calendar
+ * @param context A context needed to inflate resources
+ * @param locale A Locale to be used when generating strings
+ * @param initialTime The initial selection of the Timepicker
* @param is24HourMode Indicates whether we should render in 24hour mode or with AM/PM selectors
*/
- public void initialize(Context context, Locale locale, TimePickerController timePickerController,
- Timepoint initialTime, boolean is24HourMode) {
+ public void initialize(
+ CalendarType calendarType,
+ Context context,
+ Locale locale,
+ TimePickerController timePickerController,
+ Timepoint initialTime,
+ boolean is24HourMode
+ ) {
if (mTimeInitialized) {
Log.e(TAG, "Time has already been initialized.");
return;
@@ -174,8 +187,8 @@ public void initialize(Context context, Locale locale, TimePickerController time
// Initialize the circle and AM/PM circles if applicable.
mCircleView.initialize(context, mController);
mCircleView.invalidate();
- if (!mIs24HourMode && mController.getVersion() == TimePickerDialog.Version.VERSION_1) {
- mAmPmCirclesView.initialize(context, locale, mController, initialTime.isAM() ? AM : PM);
+ if (!mIs24HourMode && mController.getVersion() == Version.VERSION_1) {
+ mAmPmCirclesView.initialize(calendarType, context, locale, mController, initialTime.isAM() ? AM : PM);
mAmPmCirclesView.invalidate();
}
@@ -190,8 +203,8 @@ public void initialize(Context context, Locale locale, TimePickerController time
};
RadialTextsView.SelectionValidator hourValidator = selection -> {
Timepoint newTime = new Timepoint(selection, mCurrentTime.getMinute(), mCurrentTime.getSecond());
- if(!mIs24HourMode && getIsCurrentlyAmOrPm() == PM) newTime.setPM();
- if(!mIs24HourMode && getIsCurrentlyAmOrPm() == AM) newTime.setAM();
+ if (!mIs24HourMode && getIsCurrentlyAmOrPm() == PM) newTime.setPM();
+ if (!mIs24HourMode && getIsCurrentlyAmOrPm() == AM) newTime.setAM();
return !mController.isOutOfRange(newTime, HOUR_INDEX);
};
@@ -205,7 +218,7 @@ public void initialize(Context context, Locale locale, TimePickerController time
String[] minutesTexts = new String[12];
String[] secondsTexts = new String[12];
for (int i = 0; i < 12; i++) {
- hoursTexts[i] = is24HourMode?
+ hoursTexts[i] = is24HourMode ?
String.format(locale, "%02d", hours_24[i]) : String.format(locale, "%d", hours[i]);
innerHoursTexts[i] = String.format(locale, "%d", hours[i]);
minutesTexts[i] = String.format(locale, "%02d", minutes[i]);
@@ -213,7 +226,7 @@ public void initialize(Context context, Locale locale, TimePickerController time
}
// The version 2 layout has the hours > 12 on the inner circle rather than the outer circle
// Inner circle and outer circle should be swapped (see #411)
- if (mController.getVersion() == TimePickerDialog.Version.VERSION_2) {
+ if (mController.getVersion() == Version.VERSION_2) {
String[] temp = hoursTexts;
hoursTexts = innerHoursTexts;
innerHoursTexts = temp;
@@ -260,13 +273,14 @@ private void setItem(int index, Timepoint time) {
/**
* Check if a given hour appears in the outer circle or the inner circle
+ *
* @return true if the hour is in the inner circle, false if it's in the outer circle.
*/
private boolean isHourInnerCircle(int hourOfDay) {
// We'll have the 00 hours on the outside circle.
boolean isMorning = hourOfDay <= 12 && hourOfDay != 0;
// In the version 2 layout the circles are swapped
- if (mController.getVersion() != TimePickerDialog.Version.VERSION_1) isMorning = !isMorning;
+ if (mController.getVersion() != Version.VERSION_1) isMorning = !isMorning;
return mIs24HourMode && isMorning;
}
@@ -292,7 +306,7 @@ public Timepoint getTime() {
*/
private int getCurrentlyShowingValue() {
int currentIndex = getCurrentItemShowing();
- switch(currentIndex) {
+ switch (currentIndex) {
case HOUR_INDEX:
return mCurrentTime.getHour();
case MINUTE_INDEX:
@@ -315,14 +329,15 @@ public int getIsCurrentlyAmOrPm() {
/**
* Set the internal value as either AM or PM, and update the AM/PM circle displays.
+ *
* @param amOrPm Integer representing AM of PM (use the supplied constants)
*/
public void setAmOrPm(int amOrPm) {
mAmPmCirclesView.setAmOrPm(amOrPm);
mAmPmCirclesView.invalidate();
Timepoint newSelection = new Timepoint(mCurrentTime);
- if(amOrPm == AM) newSelection.setAM();
- else if(amOrPm == PM) newSelection.setPM();
+ if (amOrPm == AM) newSelection.setAM();
+ else if (amOrPm == PM) newSelection.setPM();
newSelection = roundToValidTime(newSelection, HOUR_INDEX);
reselectSelector(newSelection, false, HOUR_INDEX);
mCurrentTime = newSelection;
@@ -402,10 +417,11 @@ private int snapPrefer30s(int degrees) {
/**
* Returns mapping of any input degrees (0 to 360) to one of 12 visible output degrees (all
* multiples of 30), where the input will be "snapped" to the closest visible degrees.
- * @param degrees The input degrees
+ *
+ * @param degrees The input degrees
* @param forceHigherOrLower The output may be forced to either the higher or lower step, or may
- * be allowed to snap to whichever is closer. Use 1 to force strictly higher, -1 to force
- * strictly lower, and 0 to snap to the closer one.
+ * be allowed to snap to whichever is closer. Use 1 to force strictly higher, -1 to force
+ * strictly lower, and 0 to snap to the closer one.
* @return output degrees, will be a multiple of 30
*/
private static int snapOnly30s(int degrees, int forceHigherOrLower) {
@@ -431,12 +447,13 @@ private static int snapOnly30s(int degrees, int forceHigherOrLower) {
/**
* Snap the input to a selectable value
- * @param newSelection Timepoint - Time which should be rounded
+ *
+ * @param newSelection Timepoint - Time which should be rounded
* @param currentItemShowing int - The index of the current view
* @return Timepoint - the rounded value
*/
private Timepoint roundToValidTime(Timepoint newSelection, int currentItemShowing) {
- switch(currentItemShowing) {
+ switch (currentItemShowing) {
case HOUR_INDEX:
return mController.roundToNearest(newSelection, null);
case MINUTE_INDEX:
@@ -450,31 +467,32 @@ private Timepoint roundToValidTime(Timepoint newSelection, int currentItemShowin
* For the currently showing view (either hours, minutes or seconds), re-calculate the position
* for the selector, and redraw it at that position. The text representing the currently
* selected value will be redrawn if required.
+ *
* @param newSelection Timpoint - Time which should be selected.
* @param forceDrawDot The dot in the circle will generally only be shown when the selection
- * @param index The picker to use as a reference. Will be getCurrentItemShow() except when AM/PM is changed
- * is on non-visible values, but use this to force the dot to be shown.
+ * @param index The picker to use as a reference. Will be getCurrentItemShow() except when AM/PM is changed
+ * is on non-visible values, but use this to force the dot to be shown.
*/
private void reselectSelector(Timepoint newSelection, boolean forceDrawDot, int index) {
- switch(index) {
+ switch (index) {
case HOUR_INDEX:
// The selection might have changed, recalculate the degrees and innerCircle values
int hour = newSelection.getHour();
boolean isInnerCircle = isHourInnerCircle(hour);
- int degrees = (hour%12)*360/12;
- if(!mIs24HourMode) hour = hour%12;
- if(!mIs24HourMode && hour == 0) hour += 12;
+ int degrees = (hour % 12) * 360 / 12;
+ if (!mIs24HourMode) hour = hour % 12;
+ if (!mIs24HourMode && hour == 0) hour += 12;
mHourRadialSelectorView.setSelection(degrees, isInnerCircle, forceDrawDot);
mHourRadialTextsView.setSelection(hour);
// If we rounded the minutes, reposition the minuteSelector too.
- if(newSelection.getMinute() != mCurrentTime.getMinute()) {
+ if (newSelection.getMinute() != mCurrentTime.getMinute()) {
int minDegrees = newSelection.getMinute() * (360 / 60);
mMinuteRadialSelectorView.setSelection(minDegrees, isInnerCircle, forceDrawDot);
mMinuteRadialTextsView.setSelection(newSelection.getMinute());
}
// If we rounded the seconds, reposition the secondSelector too.
- if(newSelection.getSecond() != mCurrentTime.getSecond()) {
+ if (newSelection.getSecond() != mCurrentTime.getSecond()) {
int secDegrees = newSelection.getSecond() * (360 / 60);
mSecondRadialSelectorView.setSelection(secDegrees, isInnerCircle, forceDrawDot);
mSecondRadialTextsView.setSelection(newSelection.getSecond());
@@ -487,8 +505,8 @@ private void reselectSelector(Timepoint newSelection, boolean forceDrawDot, int
mMinuteRadialSelectorView.setSelection(degrees, false, forceDrawDot);
mMinuteRadialTextsView.setSelection(newSelection.getMinute());
// If we rounded the seconds, reposition the secondSelector too.
- if(newSelection.getSecond() != mCurrentTime.getSecond()) {
- int secDegrees = newSelection.getSecond()* (360 / 60);
+ if (newSelection.getSecond() != mCurrentTime.getSecond()) {
+ int secDegrees = newSelection.getSecond() * (360 / 60);
mSecondRadialSelectorView.setSelection(secDegrees, false, forceDrawDot);
mSecondRadialTextsView.setSelection(newSelection.getSecond());
}
@@ -501,7 +519,7 @@ private void reselectSelector(Timepoint newSelection, boolean forceDrawDot, int
}
// Invalidate the currently showing picker to force a redraw
- switch(getCurrentItemShowing()) {
+ switch (getCurrentItemShowing()) {
case HOUR_INDEX:
mHourRadialSelectorView.invalidate();
mHourRadialTextsView.invalidate();
@@ -565,17 +583,17 @@ private Timepoint getTimeFromDegrees(int degrees, boolean isInnerCircle, boolean
}
if (currentShowing == HOUR_INDEX
- && mController.getVersion() != TimePickerDialog.Version.VERSION_1
+ && mController.getVersion() != Version.VERSION_1
&& mIs24HourMode) {
value = (value + 12) % 24;
}
Timepoint newSelection;
- switch(currentShowing) {
+ switch (currentShowing) {
case HOUR_INDEX:
int hour = value;
- if(!mIs24HourMode && getIsCurrentlyAmOrPm() == PM && degrees != 360) hour += 12;
- if(!mIs24HourMode && getIsCurrentlyAmOrPm() == AM && degrees == 360) hour = 0;
+ if (!mIs24HourMode && getIsCurrentlyAmOrPm() == PM && degrees != 360) hour += 12;
+ if (!mIs24HourMode && getIsCurrentlyAmOrPm() == AM && degrees == 360) hour = 0;
newSelection = new Timepoint(hour, mCurrentTime.getMinute(), mCurrentTime.getSecond());
break;
case MINUTE_INDEX:
@@ -594,18 +612,19 @@ private Timepoint getTimeFromDegrees(int degrees, boolean isInnerCircle, boolean
/**
* Calculate the degrees within the circle that corresponds to the specified coordinates, if
* the coordinates are within the range that will trigger a selection.
- * @param pointX The x coordinate.
- * @param pointY The y coordinate.
- * @param forceLegal Force the selection to be legal, regardless of how far the coordinates are
- * from the actual numbers.
+ *
+ * @param pointX The x coordinate.
+ * @param pointY The y coordinate.
+ * @param forceLegal Force the selection to be legal, regardless of how far the coordinates are
+ * from the actual numbers.
* @param isInnerCircle If the selection may be in the inner circle, pass in a size-1 boolean
- * array here, inside which the value will be true if the selection is in the inner circle,
- * and false if in the outer circle.
+ * array here, inside which the value will be true if the selection is in the inner circle,
+ * and false if in the outer circle.
* @return Degrees from 0 to 360, if the selection was within the legal range. -1 if not.
*/
private int getDegreesFromCoords(float pointX, float pointY, boolean forceLegal,
- final Boolean[] isInnerCircle) {
- switch(getCurrentItemShowing()) {
+ final Boolean[] isInnerCircle) {
+ switch (getCurrentItemShowing()) {
case HOUR_INDEX:
return mHourRadialSelectorView.getDegreesFromCoords(
pointX, pointY, forceLegal, isInnerCircle);
@@ -633,11 +652,12 @@ public int getCurrentItemShowing() {
/**
* Set either seconds, minutes or hours as showing.
+ *
* @param animate True to animate the transition, false to show with no animation.
*/
public void setCurrentItemShowing(int index, boolean animate) {
if (index != HOUR_INDEX && index != MINUTE_INDEX && index != SECOND_INDEX) {
- Log.e(TAG, "TimePicker does not support view at index "+index);
+ Log.e(TAG, "TimePicker does not support view at index " + index);
return;
}
@@ -652,7 +672,7 @@ public void setCurrentItemShowing(int index, boolean animate) {
anims[1] = mHourRadialSelectorView.getDisappearAnimator();
anims[2] = mMinuteRadialTextsView.getReappearAnimator();
anims[3] = mMinuteRadialSelectorView.getReappearAnimator();
- } else if (index == HOUR_INDEX && lastIndex == MINUTE_INDEX){
+ } else if (index == HOUR_INDEX && lastIndex == MINUTE_INDEX) {
anims[0] = mHourRadialTextsView.getReappearAnimator();
anims[1] = mHourRadialSelectorView.getReappearAnimator();
anims[2] = mMinuteRadialTextsView.getDisappearAnimator();
@@ -680,7 +700,7 @@ public void setCurrentItemShowing(int index, boolean animate) {
}
if (anims[0] != null && anims[1] != null && anims[2] != null &&
- anims[3] != null) {
+ anims[3] != null) {
if (mTransition != null && mTransition.isRunning()) {
mTransition.end();
}
@@ -716,7 +736,7 @@ public boolean onTouch(View v, MotionEvent event) {
final Boolean[] isInnerCircle = new Boolean[1];
isInnerCircle[0] = false;
- switch(event.getAction()) {
+ switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!mInputEnabled) {
return true;
@@ -729,7 +749,7 @@ public boolean onTouch(View v, MotionEvent event) {
mDoingMove = false;
mDoingTouch = true;
// If we're showing the AM/PM, check to see if the user is touching it.
- if (!mIs24HourMode && mController.getVersion() == TimePickerDialog.Version.VERSION_1) {
+ if (!mIs24HourMode && mController.getVersion() == Version.VERSION_1) {
mIsTouchingAmOrPm = mAmPmCirclesView.getIsTouchingAmOrPm(eventX, eventY);
} else {
mIsTouchingAmOrPm = -1;
@@ -750,7 +770,8 @@ public boolean onTouch(View v, MotionEvent event) {
// Calculate the degrees that is currently being touched.
mDownDegrees = getDegreesFromCoords(eventX, eventY, forceLegal, isInnerCircle);
Timepoint selectedTime = getTimeFromDegrees(mDownDegrees, isInnerCircle[0], false);
- if(mController.isOutOfRange(selectedTime, getCurrentItemShowing())) mDownDegrees = -1;
+ if (mController.isOutOfRange(selectedTime, getCurrentItemShowing()))
+ mDownDegrees = -1;
if (mDownDegrees != -1) {
// If it's a legal touch, set that number as "selected" after the
// TAP_TIMEOUT in case the user moves their finger quickly.
@@ -839,8 +860,8 @@ public boolean onTouch(View v, MotionEvent event) {
mAmPmCirclesView.setAmOrPm(isTouchingAmOrPm);
if (getIsCurrentlyAmOrPm() != isTouchingAmOrPm) {
Timepoint newSelection = new Timepoint(mCurrentTime);
- if(mIsTouchingAmOrPm == AM) newSelection.setAM();
- else if(mIsTouchingAmOrPm == PM) newSelection.setPM();
+ if (mIsTouchingAmOrPm == AM) newSelection.setAM();
+ else if (mIsTouchingAmOrPm == PM) newSelection.setPM();
newSelection = roundToValidTime(newSelection, HOUR_INDEX);
reselectSelector(newSelection, false, HOUR_INDEX);
mCurrentTime = newSelection;
@@ -883,7 +904,7 @@ public boolean trySettingInputEnabled(boolean inputEnabled) {
}
mInputEnabled = inputEnabled;
- mGrayBox.setVisibility(inputEnabled? View.INVISIBLE : View.VISIBLE);
+ mGrayBox.setVisibility(inputEnabled ? View.INVISIBLE : View.VISIBLE);
return true;
}
@@ -897,8 +918,7 @@ public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo inf
if (Build.VERSION.SDK_INT >= 21) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
- }
- else {
+ } else {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
@@ -990,7 +1010,7 @@ public boolean performAccessibilityAction(int action, Bundle arguments) {
}
Timepoint newSelection;
- switch(currentItemShowing) {
+ switch (currentItemShowing) {
case HOUR_INDEX:
newSelection = new Timepoint(
value,
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialSelectorView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialSelectorView.java
index bf8866ed..421afa92 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialSelectorView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialSelectorView.java
@@ -30,6 +30,7 @@
import com.wdullaer.materialdatetimepicker.R;
import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.Version;
import java.lang.ref.WeakReference;
@@ -82,19 +83,20 @@ public RadialSelectorView(Context context) {
/**
* Initialize this selector with the state of the picker.
- * @param context Current context.
- * @param controller Structure containing the accentColor and the 24-hour mode, which will tell us
- * whether the circle's center is moved up slightly to make room for the AM/PM circles.
- * @param hasInnerCircle Whether we have both an inner and an outer circle of numbers
- * that may be selected. Should be true for 24-hour mode in the hours circle.
- * @param disappearsOut Whether the numbers' animation will have them disappearing out
- * or disappearing in.
+ *
+ * @param context Current context.
+ * @param controller Structure containing the accentColor and the 24-hour mode, which will tell us
+ * whether the circle's center is moved up slightly to make room for the AM/PM circles.
+ * @param hasInnerCircle Whether we have both an inner and an outer circle of numbers
+ * that may be selected. Should be true for 24-hour mode in the hours circle.
+ * @param disappearsOut Whether the numbers' animation will have them disappearing out
+ * or disappearing in.
* @param selectionDegrees The initial degrees to be selected.
- * @param isInnerCircle Whether the initial selection is in the inner or outer circle.
- * Will be ignored when hasInnerCircle is false.
+ * @param isInnerCircle Whether the initial selection is in the inner or outer circle.
+ * Will be ignored when hasInnerCircle is false.
*/
public void initialize(Context context, TimePickerController controller, boolean hasInnerCircle,
- boolean disappearsOut, int selectionDegrees, boolean isInnerCircle) {
+ boolean disappearsOut, int selectionDegrees, boolean isInnerCircle) {
if (mIsInitialized) {
Log.e(TAG, "This RadialSelectorView may only be initialized once.");
return;
@@ -110,7 +112,7 @@ public void initialize(Context context, TimePickerController controller, boolean
// Calculate values for the circle radius size.
mIs24HourMode = controller.is24HourMode();
- if (mIs24HourMode || controller.getVersion() != TimePickerDialog.Version.VERSION_1) {
+ if (mIs24HourMode || controller.getVersion() != Version.VERSION_1) {
mCircleRadiusMultiplier = Float.parseFloat(
res.getString(R.string.mdtp_circle_radius_multiplier_24HourMode));
} else {
@@ -136,8 +138,8 @@ public void initialize(Context context, TimePickerController controller, boolean
// Calculate values for the transition mid-way states.
mAnimationRadiusMultiplier = 1;
- mTransitionMidRadiusMultiplier = 1f + (0.05f * (disappearsOut? -1 : 1));
- mTransitionEndRadiusMultiplier = 1f + (0.3f * (disappearsOut? 1 : -1));
+ mTransitionMidRadiusMultiplier = 1f + (0.05f * (disappearsOut ? -1 : 1));
+ mTransitionEndRadiusMultiplier = 1f + (0.3f * (disappearsOut ? 1 : -1));
mInvalidateUpdateListener = new InvalidateUpdateListener(this);
setSelection(selectionDegrees, isInnerCircle, false);
@@ -146,12 +148,13 @@ public void initialize(Context context, TimePickerController controller, boolean
/**
* Set the selection.
+ *
* @param selectionDegrees The degrees to be selected.
- * @param isInnerCircle Whether the selection should be in the inner circle or outer. Will be
- * ignored if hasInnerCircle was initialized to false.
- * @param forceDrawDot Whether to force the dot in the center of the selection circle to be
- * drawn. If false, the dot will be drawn only when the degrees is not a multiple of 30, i.e.
- * the selection is not on a visible number.
+ * @param isInnerCircle Whether the selection should be in the inner circle or outer. Will be
+ * ignored if hasInnerCircle was initialized to false.
+ * @param forceDrawDot Whether to force the dot in the center of the selection circle to be
+ * drawn. If false, the dot will be drawn only when the degrees is not a multiple of 30, i.e.
+ * the selection is not on a visible number.
*/
public void setSelection(int selectionDegrees, boolean isInnerCircle, boolean forceDrawDot) {
mSelectionDegrees = selectionDegrees;
@@ -184,14 +187,14 @@ public void setAnimationRadiusMultiplier(float animationRadiusMultiplier) {
}
public int getDegreesFromCoords(float pointX, float pointY, boolean forceLegal,
- final Boolean[] isInnerCircle) {
+ final Boolean[] isInnerCircle) {
if (!mDrawValuesReady) {
return -1;
}
double hypotenuse = Math.sqrt(
- (pointY - mYCenter)*(pointY - mYCenter) +
- (pointX - mXCenter)*(pointX - mXCenter));
+ (pointY - mYCenter) * (pointY - mYCenter) +
+ (pointX - mXCenter) * (pointX - mXCenter));
// Check if we're outside the range
if (mHasInnerCircle) {
if (forceLegal) {
@@ -276,7 +279,7 @@ public void onDraw(Canvas canvas) {
// a slightly higher center. To keep the entire view centered vertically, we'll
// have to push it up by half the radius of the AM/PM circles.
int amPmCircleRadius = (int) (mCircleRadius * mAmPmCircleRadiusMultiplier);
- mYCenter -= amPmCircleRadius *0.75;
+ mYCenter -= amPmCircleRadius * 0.75;
}
mSelectionRadius = (int) (mCircleRadius * mSelectionRadiusMultiplier);
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialTextsView.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialTextsView.java
index 85d1f541..a92f8450 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialTextsView.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/RadialTextsView.java
@@ -25,13 +25,16 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.Typeface;
import android.graphics.Paint.Align;
-import androidx.core.content.ContextCompat;
+import android.graphics.Typeface;
import android.util.Log;
import android.view.View;
+import androidx.core.content.ContextCompat;
+
import com.wdullaer.materialdatetimepicker.R;
+import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.Version;
/**
* A view to show a series of numbers in a circular pattern.
@@ -87,7 +90,7 @@ public RadialTextsView(Context context) {
}
public void initialize(Context context, String[] texts, String[] innerTexts,
- TimePickerController controller, SelectionValidator validator, boolean disappearsOut) {
+ TimePickerController controller, SelectionValidator validator, boolean disappearsOut) {
if (mIsInitialized) {
Log.e(TAG, "This RadialTextsView may only be initialized once.");
return;
@@ -98,9 +101,16 @@ public void initialize(Context context, String[] texts, String[] innerTexts,
int textColorRes = controller.isThemeDark() ? R.color.mdtp_white : R.color.mdtp_numbers_text_color;
mPaint.setColor(ContextCompat.getColor(context, textColorRes));
String typefaceFamily = res.getString(R.string.mdtp_radial_numbers_typeface);
- mTypefaceLight = Typeface.create(typefaceFamily, Typeface.NORMAL);
String typefaceFamilyRegular = res.getString(R.string.mdtp_sans_serif);
- mTypefaceRegular = Typeface.create(typefaceFamilyRegular, Typeface.NORMAL);
+ final Typeface font = Utils.getCustomFont();
+ if (font != null) {
+ mTypefaceLight = Typeface.create(font, Typeface.NORMAL);
+ mTypefaceRegular = Typeface.create(font, Typeface.NORMAL);
+ } else {
+ mTypefaceLight = Typeface.create(typefaceFamily, Typeface.NORMAL);
+ mTypefaceRegular = Typeface.create(typefaceFamilyRegular, Typeface.NORMAL);
+ }
+
mPaint.setAntiAlias(true);
mPaint.setTextAlign(Align.CENTER);
@@ -109,6 +119,7 @@ public void initialize(Context context, String[] texts, String[] innerTexts,
mSelectedPaint.setColor(selectedTextColor);
mSelectedPaint.setAntiAlias(true);
mSelectedPaint.setTextAlign(Align.CENTER);
+ mSelectedPaint.setTypeface(mTypefaceRegular);
// Set up the inactive paint
int inactiveColorRes = controller.isThemeDark() ? R.color.mdtp_date_picker_text_disabled_dark_theme
@@ -116,6 +127,7 @@ public void initialize(Context context, String[] texts, String[] innerTexts,
mInactivePaint.setColor(ContextCompat.getColor(context, inactiveColorRes));
mInactivePaint.setAntiAlias(true);
mInactivePaint.setTextAlign(Align.CENTER);
+ mInactivePaint.setTypeface(mTypefaceRegular);
mTexts = texts;
mInnerTexts = innerTexts;
@@ -123,7 +135,7 @@ public void initialize(Context context, String[] texts, String[] innerTexts,
mHasInnerCircle = (innerTexts != null);
// Calculate the radius for the main circle.
- if (mIs24HourMode || controller.getVersion() != TimePickerDialog.Version.VERSION_1) {
+ if (mIs24HourMode || controller.getVersion() != Version.VERSION_1) {
mCircleRadiusMultiplier = Float.parseFloat(
res.getString(R.string.mdtp_circle_radius_multiplier_24HourMode));
} else {
@@ -143,7 +155,7 @@ public void initialize(Context context, String[] texts, String[] innerTexts,
res.getString(R.string.mdtp_numbers_radius_multiplier_inner));
// Version 2 layout draws outer circle bigger than inner
- if (controller.getVersion() == TimePickerDialog.Version.VERSION_1) {
+ if (controller.getVersion() == Version.VERSION_1) {
mTextSizeMultiplier = Float.parseFloat(
res.getString(R.string.mdtp_text_size_multiplier_outer));
mInnerTextSizeMultiplier = Float.parseFloat(
@@ -165,8 +177,8 @@ public void initialize(Context context, String[] texts, String[] innerTexts,
}
mAnimationRadiusMultiplier = 1;
- mTransitionMidRadiusMultiplier = 1f + (0.05f * (disappearsOut? -1 : 1));
- mTransitionEndRadiusMultiplier = 1f + (0.3f * (disappearsOut? 1 : -1));
+ mTransitionMidRadiusMultiplier = 1f + (0.05f * (disappearsOut ? -1 : 1));
+ mTransitionEndRadiusMultiplier = 1f + (0.3f * (disappearsOut ? 1 : -1));
mInvalidateUpdateListener = new InvalidateUpdateListener();
mValidator = validator;
@@ -177,6 +189,7 @@ public void initialize(Context context, String[] texts, String[] innerTexts,
/**
* Set the value of the selected text. Depending on the theme this will be rendered differently
+ *
* @param selection The text which is currently selected
*/
protected void setSelection(int selection) {
@@ -216,7 +229,7 @@ public void onDraw(Canvas canvas) {
// a slightly higher center. To keep the entire view centered vertically, we'll
// have to push it up by half the radius of the AM/PM circles.
float amPmCircleRadius = mCircleRadius * mAmPmCircleRadiusMultiplier;
- mYCenter -= amPmCircleRadius *0.75;
+ mYCenter -= amPmCircleRadius * 0.75;
}
mTextSize = mCircleRadius * mTextSizeMultiplier;
@@ -263,7 +276,7 @@ public void onDraw(Canvas canvas) {
* textGridWidths parameters.
*/
private void calculateGridSizes(float numbersRadius, float xCenter, float yCenter,
- float textSize, float[] textGridHeights, float[] textGridWidths) {
+ float textSize, float[] textGridHeights, float[] textGridWidths) {
/*
* The numbers need to be drawn in a 7x7 grid, representing the points on the Unit Circle.
*/
@@ -296,10 +309,10 @@ private void calculateGridSizes(float numbersRadius, float xCenter, float yCente
private Paint[] assignTextColors(String[] texts) {
Paint[] paints = new Paint[texts.length];
- for(int i=0;i
* Created by wdullaer on 6/10/15.
*/
interface TimePickerController {
@@ -24,7 +28,7 @@ interface TimePickerController {
/**
* @return Version - The current version to render
*/
- TimePickerDialog.Version getVersion();
+ Version getVersion();
/**
* Request the device to vibrate
@@ -32,7 +36,7 @@ interface TimePickerController {
void tryVibrate();
/**
- * @param time Timepoint - the selected point in time
+ * @param time Timepoint - the selected point in time
* @param index int - The current view to consider when calculating the range
* @return boolean - true if this is not a selectable value
*/
@@ -50,12 +54,15 @@ interface TimePickerController {
/**
* Will round the given Timepoint to the nearest valid Timepoint given the following restrictions:
- * - TYPE.HOUR, it will just round to the next valid point, possible adjusting minutes and seconds
- * - TYPE.MINUTE, it will round to the next valid point, without adjusting the hour, but possibly adjusting the seconds
- * - TYPE.SECOND, it will round to the next valid point, only adjusting the seconds
+ * - TYPE.HOUR, it will just round to the next valid point, possible adjusting minutes and seconds
+ * - TYPE.MINUTE, it will round to the next valid point, without adjusting the hour, but possibly adjusting the seconds
+ * - TYPE.SECOND, it will round to the next valid point, only adjusting the seconds
+ *
* @param time Timepoint - the timepoint to validate
* @param type Timepoint.TYPE - whether we should round the hours, minutes or seconds
* @return timepoint - the nearest valid timepoint
*/
Timepoint roundToNearest(Timepoint time, Timepoint.TYPE type);
+
+ void setFont(Typeface customFont);
}
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/TimePickerDialog.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/TimePickerDialog.java
index ba2786b9..58239029 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/TimePickerDialog.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/TimePickerDialog.java
@@ -18,21 +18,15 @@
import android.animation.ObjectAnimator;
import android.app.ActionBar.LayoutParams;
+import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
-import androidx.annotation.ColorInt;
-import androidx.annotation.IntRange;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-import androidx.appcompat.app.AppCompatDialogFragment;
-import androidx.core.content.ContextCompat;
-import androidx.core.content.res.ResourcesCompat;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -45,9 +39,20 @@
import android.widget.RelativeLayout;
import android.widget.TextView;
+import androidx.annotation.ColorInt;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.appcompat.app.AppCompatDialogFragment;
+import androidx.core.content.ContextCompat;
+import androidx.core.content.res.ResourcesCompat;
+
import com.wdullaer.materialdatetimepicker.HapticFeedbackController;
import com.wdullaer.materialdatetimepicker.R;
import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+import com.wdullaer.materialdatetimepicker.enums.Version;
import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout.OnValueSelectedListener;
import java.text.DateFormatSymbols;
@@ -63,11 +68,6 @@ public class TimePickerDialog extends AppCompatDialogFragment implements
OnValueSelectedListener, TimePickerController {
private static final String TAG = "TimePickerDialog";
- public enum Version {
- VERSION_1,
- VERSION_2
- }
-
private static final String KEY_INITIAL_TIME = "initial_time";
private static final String KEY_IS_24_HOUR_VIEW = "is_24_hour_view";
private static final String KEY_TITLE = "dialog_title";
@@ -90,6 +90,7 @@ public enum Version {
private static final String KEY_VERSION = "version";
private static final String KEY_TIMEPOINTLIMITER = "timepoint_limiter";
private static final String KEY_LOCALE = "locale";
+ private static final String KEY_CALENDAR_TYPE = "mCalendarType";
public static final int HOUR_INDEX = 0;
public static final int MINUTE_INDEX = 1;
@@ -164,6 +165,8 @@ public enum Version {
private String mSecondPickerDescription;
private String mSelectSeconds;
+ private CalendarType mCalendarType;
+
/**
* The callback interface used to indicate the user is done filling in
* the time (they clicked on the 'Set' button).
@@ -171,10 +174,10 @@ public enum Version {
public interface OnTimeSetListener {
/**
- * @param view The view associated with this listener.
+ * @param view The view associated with this listener.
* @param hourOfDay The hour that was set.
- * @param minute The minute that was set.
- * @param second The second that was set
+ * @param minute The minute that was set.
+ * @param second The second that was set
*/
void onTimeSet(TimePickerDialog view, int hourOfDay, int minute, int second);
}
@@ -185,7 +188,9 @@ public TimePickerDialog() {
/**
* Create a new TimePickerDialog instance with a given intial selection
+ *
* @param callback How the parent is notified that the time is set.
+ * @param calendarType mCalendarType of calendar
* @param hourOfDay The initial hour of the dialog.
* @param minute The initial minute of the dialog.
* @param second The initial second of the dialog.
@@ -193,40 +198,79 @@ public TimePickerDialog() {
* @return a new TimePickerDialog instance.
*/
@SuppressWarnings({"SameParameterValue", "WeakerAccess"})
- public static TimePickerDialog newInstance(OnTimeSetListener callback,
- int hourOfDay, int minute, int second, boolean is24HourMode) {
+ public static TimePickerDialog newInstance(
+ OnTimeSetListener callback,
+ CalendarType calendarType,
+ int hourOfDay,
+ int minute,
+ int second,
+ boolean is24HourMode
+ ) {
TimePickerDialog ret = new TimePickerDialog();
- ret.initialize(callback, hourOfDay, minute, second, is24HourMode);
+ ret.initialize(callback, calendarType, hourOfDay, minute, second, is24HourMode);
return ret;
}
/**
* Create a new TimePickerDialog instance with a given initial selection
+ *
* @param callback How the parent is notified that the time is set.
+ * @param calendarType mCalendarType of calendar
* @param hourOfDay The initial hour of the dialog.
* @param minute The initial minute of the dialog.
* @param is24HourMode True to render 24 hour mode, false to render AM / PM selectors.
* @return a new TimePickerDialog instance.
*/
- public static TimePickerDialog newInstance(OnTimeSetListener callback,
- int hourOfDay, int minute, boolean is24HourMode) {
- return TimePickerDialog.newInstance(callback, hourOfDay, minute, 0, is24HourMode);
+ public static TimePickerDialog newInstance(
+ OnTimeSetListener callback,
+ CalendarType calendarType,
+ int hourOfDay,
+ int minute,
+ boolean is24HourMode
+ ) {
+ return TimePickerDialog.newInstance(
+ callback,
+ calendarType,
+ hourOfDay,
+ minute,
+ 0,
+ is24HourMode
+ );
}
/**
* Create a new TimePickerDialog instance initialized to the current system time
+ *
* @param callback How the parent is notified that the time is set.
+ * @param calendarType mCalendarType of calendar
* @param is24HourMode True to render 24 hour mode, false to render AM / PM selectors.
* @return a new TimePickerDialog instance.
*/
@SuppressWarnings({"unused", "SameParameterValue", "WeakerAccess"})
- public static TimePickerDialog newInstance(OnTimeSetListener callback, boolean is24HourMode) {
+ public static TimePickerDialog newInstance(
+ OnTimeSetListener callback,
+ CalendarType calendarType,
+ boolean is24HourMode
+ ) {
Calendar now = Calendar.getInstance();
- return TimePickerDialog.newInstance(callback, now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), is24HourMode);
- }
-
- public void initialize(OnTimeSetListener callback,
- int hourOfDay, int minute, int second, boolean is24HourMode) {
+ return TimePickerDialog.newInstance(
+ callback,
+ calendarType,
+ now.get(Calendar.HOUR_OF_DAY),
+ now.get(Calendar.MINUTE),
+ is24HourMode
+ );
+ }
+
+ public void initialize(
+ OnTimeSetListener callback,
+ CalendarType calendarType,
+ int hourOfDay,
+ int minute,
+ int second,
+ boolean is24HourMode
+ ) {
+ this.setCalendarType(calendarType);
mCallback = callback;
mInitialTime = new Timepoint(hourOfDay, minute, second);
@@ -246,6 +290,10 @@ public void initialize(OnTimeSetListener callback,
mTimePicker = null;
}
+ private void setCalendarType(CalendarType calendarType) {
+ this.mCalendarType = calendarType;
+ }
+
/**
* Set a title. NOTE: this will only take effect with the next onCreateView
*/
@@ -268,6 +316,7 @@ public void setThemeDark(boolean dark) {
/**
* Set the accent color of this dialog
+ *
* @param color the accent color you want
*/
@SuppressWarnings("unused")
@@ -277,6 +326,7 @@ public void setAccentColor(String color) {
/**
* Set the accent color of this dialog
+ *
* @param color the accent color you want
*/
public void setAccentColor(@ColorInt int color) {
@@ -285,6 +335,7 @@ public void setAccentColor(@ColorInt int color) {
/**
* Set the text color of the OK button
+ *
* @param color the color you want
*/
@SuppressWarnings("unused")
@@ -294,6 +345,7 @@ public void setOkColor(String color) {
/**
* Set the text color of the OK button
+ *
* @param color the color you want
*/
@SuppressWarnings("unused")
@@ -303,6 +355,7 @@ public void setOkColor(@ColorInt int color) {
/**
* Set the text color of the Cancel button
+ *
* @param color the color you want
*/
@SuppressWarnings("unused")
@@ -312,11 +365,12 @@ public void setCancelColor(String color) {
/**
* Set the text color of the Cancel button
+ *
* @param color the color you want
*/
@SuppressWarnings("unused")
public void setCancelColor(@ColorInt int color) {
- mCancelColor= Color.argb(255, Color.red(color), Color.green(color), Color.blue(color));
+ mCancelColor = Color.argb(255, Color.red(color), Color.green(color), Color.blue(color));
}
@Override
@@ -336,6 +390,7 @@ public int getAccentColor() {
/**
* Set whether the device should vibrate when touching fields
+ *
* @param vibrate true if the device should vibrate when touching a field
*/
public void vibrate(boolean vibrate) {
@@ -344,6 +399,7 @@ public void vibrate(boolean vibrate) {
/**
* Set whether the picker should dismiss itself when it's pausing or whether it should try to survive an orientation change
+ *
* @param dismissOnPause true if the picker should dismiss itself
*/
public void dismissOnPause(boolean dismissOnPause) {
@@ -353,6 +409,7 @@ public void dismissOnPause(boolean dismissOnPause) {
/**
* Set whether an additional picker for seconds should be shown
* Will enable minutes picker as well if seconds picker should be shown
+ *
* @param enableSeconds true if the seconds picker should be shown
*/
public void enableSeconds(boolean enableSeconds) {
@@ -363,6 +420,7 @@ public void enableSeconds(boolean enableSeconds) {
/**
* Set whether the picker for minutes should be shown
* Will disable seconds if minutes are disbled
+ *
* @param enableMinutes true if minutes picker should be shown
*/
@SuppressWarnings({"unused", "WeakerAccess"})
@@ -370,6 +428,7 @@ public void enableMinutes(boolean enableMinutes) {
if (!enableMinutes) mEnableSeconds = false;
mEnableMinutes = enableMinutes;
}
+
@SuppressWarnings("unused")
public void setMinTime(int hour, int minute, int second) {
setMinTime(new Timepoint(hour, minute, second));
@@ -394,6 +453,7 @@ public void setMaxTime(Timepoint maxTime) {
* Pass in an array of Timepoints which are the only possible selections.
* Try to specify Timepoints only up to the resolution of your picker (i.e. do not add seconds
* if the resolution of the picker is minutes)
+ *
* @param selectableTimes Array of Timepoints which are the only valid selections in the picker
*/
@SuppressWarnings("WeakerAccess")
@@ -408,6 +468,7 @@ public void setSelectableTimes(Timepoint[] selectableTimes) {
* very expensive operation if a lot of consecutive Timepoints are disabled
* Try to specify Timepoints only up to the resolution of your picker (i.e. do not add seconds
* if the resolution of the picker is minutes)
+ *
* @param disabledTimes Array of Timepoints which are disabled in the resulting picker
*/
public void setDisabledTimes(Timepoint[] disabledTimes) {
@@ -420,13 +481,14 @@ public void setDisabledTimes(Timepoint[] disabledTimes) {
* The interval for all three time components can be set independently
* If you are not using the seconds / minutes picker, set the respective item to 60 for
* better performance.
- * @param hourInterval The interval between 2 selectable hours ([1,24])
+ *
+ * @param hourInterval The interval between 2 selectable hours ([1,24])
* @param minuteInterval The interval between 2 selectable minutes ([1,60])
* @param secondInterval The interval between 2 selectable seconds ([1,60])
*/
- public void setTimeInterval(@IntRange(from=1, to=24) int hourInterval,
- @IntRange(from=1, to=60) int minuteInterval,
- @IntRange(from=1, to=60) int secondInterval) {
+ public void setTimeInterval(@IntRange(from = 1, to = 24) int hourInterval,
+ @IntRange(from = 1, to = 60) int minuteInterval,
+ @IntRange(from = 1, to = 60) int secondInterval) {
List timepoints = new ArrayList<>();
int hour = 0;
@@ -451,12 +513,13 @@ public void setTimeInterval(@IntRange(from=1, to=24) int hourInterval,
* The interval for all three time components can be set independently
* If you are not using the seconds / minutes picker, set the respective item to 60 for
* better performance.
- * @param hourInterval The interval between 2 selectable hours ([1,24])
+ *
+ * @param hourInterval The interval between 2 selectable hours ([1,24])
* @param minuteInterval The interval between 2 selectable minutes ([1,60])
*/
@SuppressWarnings({"SameParameterValue", "WeakerAccess"})
- public void setTimeInterval(@IntRange(from=1, to=24) int hourInterval,
- @IntRange(from=1, to=60) int minuteInterval) {
+ public void setTimeInterval(@IntRange(from = 1, to = 24) int hourInterval,
+ @IntRange(from = 1, to = 60) int minuteInterval) {
setTimeInterval(hourInterval, minuteInterval, 60);
}
@@ -466,10 +529,11 @@ public void setTimeInterval(@IntRange(from=1, to=24) int hourInterval,
* The interval for all three time components can be set independently
* If you are not using the seconds / minutes picker, set the respective item to 60 for
* better performance.
+ *
* @param hourInterval The interval between 2 selectable hours ([1,24])
*/
@SuppressWarnings("unused")
- public void setTimeInterval(@IntRange(from=1, to=24) int hourInterval) {
+ public void setTimeInterval(@IntRange(from = 1, to = 24) int hourInterval) {
setTimeInterval(hourInterval, 60);
}
@@ -490,10 +554,10 @@ public void setOnDismissListener(DialogInterface.OnDismissListener onDismissList
* Set the time that will be shown when the picker opens for the first time
* Overrides the value given in newInstance()
*
- * @deprecated in favor of {@link #setInitialSelection(int, int, int)}
* @param hourOfDay the hour of the day
- * @param minute the minute of the hour
- * @param second the second of the minute
+ * @param minute the minute of the hour
+ * @param second the second of the minute
+ * @deprecated in favor of {@link #setInitialSelection(int, int, int)}
*/
@Deprecated
public void setStartTime(int hourOfDay, int minute, int second) {
@@ -505,9 +569,9 @@ public void setStartTime(int hourOfDay, int minute, int second) {
* Set the time that will be shown when the picker opens for the first time
* Overrides the value given in newInstance
*
- * @deprecated in favor of {@link #setInitialSelection(int, int)}
* @param hourOfDay the hour of the day
- * @param minute the minute of the hour
+ * @param minute the minute of the hour
+ * @deprecated in favor of {@link #setInitialSelection(int, int)}
*/
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
@@ -518,9 +582,10 @@ public void setStartTime(int hourOfDay, int minute) {
/**
* Set the time that will be shown when the picker opens for the first time
* Overrides the value given in newInstance()
+ *
* @param hourOfDay the hour of the day
- * @param minute the minute of the hour
- * @param second the second of the minute
+ * @param minute the minute of the hour
+ * @param second the second of the minute
*/
@SuppressWarnings("WeakerAccess")
public void setInitialSelection(int hourOfDay, int minute, int second) {
@@ -530,8 +595,9 @@ public void setInitialSelection(int hourOfDay, int minute, int second) {
/**
* Set the time that will be shown when the picker opens for the first time
* Overrides the value given in newInstance
+ *
* @param hourOfDay the hour of the day
- * @param minute the minute of the hour
+ * @param minute the minute of the hour
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public void setInitialSelection(int hourOfDay, int minute) {
@@ -541,6 +607,7 @@ public void setInitialSelection(int hourOfDay, int minute) {
/**
* Set the time that will be shown when the picker opens for the first time
* Overrides the value given in newInstance()
+ *
* @param time the Timepoint selected when the Dialog opens
*/
@SuppressWarnings("WeakerAccess")
@@ -551,6 +618,7 @@ public void setInitialSelection(Timepoint time) {
/**
* Set the label for the Ok button (max 12 characters)
+ *
* @param okString A literal String to be used as the Ok button label
*/
@SuppressWarnings("unused")
@@ -560,6 +628,7 @@ public void setOkText(String okString) {
/**
* Set the label for the Ok button (max 12 characters)
+ *
* @param okResid A resource ID to be used as the Ok button label
*/
@SuppressWarnings("unused")
@@ -570,6 +639,7 @@ public void setOkText(@StringRes int okResid) {
/**
* Set the label for the Cancel button (max 12 characters)
+ *
* @param cancelString A literal String to be used as the Cancel button label
*/
@SuppressWarnings("unused")
@@ -579,6 +649,7 @@ public void setCancelText(String cancelString) {
/**
* Set the label for the Cancel button (max 12 characters)
+ *
* @param cancelResid A resource ID to be used as the Cancel button label
*/
@SuppressWarnings("unused")
@@ -589,6 +660,7 @@ public void setCancelText(@StringRes int cancelResid) {
/**
* Set which layout version the picker should use
+ *
* @param version The version to use
*/
public void setVersion(Version version) {
@@ -598,6 +670,7 @@ public void setVersion(Version version) {
/**
* Pass in a custom implementation of TimeLimiter
* Disables setSelectableTimes, setDisabledTimes, setTimeInterval, setMinTime and setMaxTime
+ *
* @param limiter A custom implementation of TimeLimiter
*/
@SuppressWarnings("unused")
@@ -612,6 +685,7 @@ public Version getVersion() {
/**
* Get a reference to the OnTimeSetListener callback
+ *
* @return OnTimeSetListener the callback
*/
@SuppressWarnings("unused")
@@ -621,6 +695,7 @@ public OnTimeSetListener getOnTimeSetListener() {
/**
* Set the Locale which will be used to generate various strings throughout the picker
+ *
* @param locale Locale
*/
@SuppressWarnings("unused")
@@ -633,25 +708,32 @@ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(AppCompatDialogFragment.STYLE_NO_TITLE, 0);
if (savedInstanceState != null && savedInstanceState.containsKey(KEY_INITIAL_TIME)
- && savedInstanceState.containsKey(KEY_IS_24_HOUR_VIEW)) {
+ && savedInstanceState.containsKey(KEY_IS_24_HOUR_VIEW)) {
+ this.setCalendarType((CalendarType) savedInstanceState.get(KEY_CALENDAR_TYPE));
mInitialTime = savedInstanceState.getParcelable(KEY_INITIAL_TIME);
mIs24HourMode = savedInstanceState.getBoolean(KEY_IS_24_HOUR_VIEW);
mInKbMode = savedInstanceState.getBoolean(KEY_IN_KB_MODE);
mTitle = savedInstanceState.getString(KEY_TITLE);
mThemeDark = savedInstanceState.getBoolean(KEY_THEME_DARK);
mThemeDarkChanged = savedInstanceState.getBoolean(KEY_THEME_DARK_CHANGED);
- if (savedInstanceState.containsKey(KEY_ACCENT)) mAccentColor = savedInstanceState.getInt(KEY_ACCENT);
+ if (savedInstanceState.containsKey(KEY_ACCENT)) {
+ mAccentColor = savedInstanceState.getInt(KEY_ACCENT);
+ }
mVibrate = savedInstanceState.getBoolean(KEY_VIBRATE);
mDismissOnPause = savedInstanceState.getBoolean(KEY_DISMISS);
mEnableSeconds = savedInstanceState.getBoolean(KEY_ENABLE_SECONDS);
mEnableMinutes = savedInstanceState.getBoolean(KEY_ENABLE_MINUTES);
mOkResid = savedInstanceState.getInt(KEY_OK_RESID);
mOkString = savedInstanceState.getString(KEY_OK_STRING);
- if (savedInstanceState.containsKey(KEY_OK_COLOR)) mOkColor = savedInstanceState.getInt(KEY_OK_COLOR);
+ if (savedInstanceState.containsKey(KEY_OK_COLOR)) {
+ mOkColor = savedInstanceState.getInt(KEY_OK_COLOR);
+ }
if (mOkColor == Integer.MAX_VALUE) mOkColor = null;
mCancelResid = savedInstanceState.getInt(KEY_CANCEL_RESID);
mCancelString = savedInstanceState.getString(KEY_CANCEL_STRING);
- if (savedInstanceState.containsKey(KEY_CANCEL_COLOR)) mCancelColor = savedInstanceState.getInt(KEY_CANCEL_COLOR);
+ if (savedInstanceState.containsKey(KEY_CANCEL_COLOR)) {
+ mCancelColor = savedInstanceState.getInt(KEY_CANCEL_COLOR);
+ }
mVersion = (Version) savedInstanceState.getSerializable(KEY_VERSION);
mLimiter = savedInstanceState.getParcelable(KEY_TIMEPOINTLIMITER);
mLocale = (Locale) savedInstanceState.getSerializable(KEY_LOCALE);
@@ -672,9 +754,9 @@ affect the behaviour of the picker (in the unlikely event the user reconfigures
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ Bundle savedInstanceState) {
int viewRes = mVersion == Version.VERSION_1 ? R.layout.mdtp_time_picker_dialog : R.layout.mdtp_time_picker_dialog_v2;
- View view = inflater.inflate(viewRes, container,false);
+ View view = inflater.inflate(viewRes, container, false);
KeyboardListener keyboardListener = new KeyboardListener();
view.findViewById(R.id.mdtp_time_picker_dialog).setOnKeyListener(keyboardListener);
@@ -713,13 +795,23 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
mPmTextView = view.findViewById(R.id.mdtp_pm_label);
mPmTextView.setOnKeyListener(keyboardListener);
mAmPmLayout = view.findViewById(R.id.mdtp_ampm_layout);
- String[] amPmTexts = new DateFormatSymbols(mLocale).getAmPmStrings();
+ String[] amPmTexts;
+ switch (mCalendarType) {
+ case JALALI:
+ amPmTexts = new String[]{"ق.ظ", "ب.ظ"};
+ break;
+ case GREGORIAN:
+ default:
+ amPmTexts = new DateFormatSymbols(mLocale).getAmPmStrings();
+ break;
+ }
+
mAmText = amPmTexts[0];
mPmText = amPmTexts[1];
mHapticFeedbackController = new HapticFeedbackController(getActivity());
- if(mTimePicker != null) {
+ if (mTimePicker != null) {
mInitialTime = new Timepoint(mTimePicker.getHours(), mTimePicker.getMinutes(), mTimePicker.getSeconds());
}
@@ -728,7 +820,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
mTimePicker = view.findViewById(R.id.mdtp_time_picker);
mTimePicker.setOnValueSelectedListener(this);
mTimePicker.setOnKeyListener(keyboardListener);
- mTimePicker.initialize(getActivity(), mLocale, this, mInitialTime, mIs24HourMode);
+ mTimePicker.initialize(mCalendarType, getActivity(), mLocale, this, mInitialTime, mIs24HourMode);
int currentItemShowing = HOUR_INDEX;
if (savedInstanceState != null &&
@@ -762,8 +854,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
dismiss();
});
mOkButton.setOnKeyListener(keyboardListener);
- mOkButton.setTypeface(ResourcesCompat.getFont(context, R.font.robotomedium));
- if(mOkString != null) mOkButton.setText(mOkString);
+ if (mOkString != null) mOkButton.setText(mOkString);
else mOkButton.setText(mOkResid);
mCancelButton = view.findViewById(R.id.mdtp_cancel);
@@ -771,8 +862,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
tryVibrate();
if (getDialog() != null) getDialog().cancel();
});
- mCancelButton.setTypeface(ResourcesCompat.getFont(context, R.font.robotomedium));
- if(mCancelString != null) mCancelButton.setText(mCancelString);
+ if (mCancelString != null) mCancelButton.setText(mCancelString);
else mCancelButton.setText(mCancelResid);
mCancelButton.setVisibility(isCancelable() ? View.VISIBLE : View.GONE);
@@ -793,7 +883,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
}
mTimePicker.setAmOrPm(amOrPm);
};
- mAmTextView .setVisibility(View.GONE);
+ mAmTextView.setVisibility(View.GONE);
mPmTextView.setVisibility(View.VISIBLE);
mAmPmLayout.setOnClickListener(listener);
if (mVersion == Version.VERSION_2) {
@@ -906,8 +996,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
paramsAmPm.addRule(RelativeLayout.BELOW, R.id.mdtp_seconds_space);
mAmPmLayout.setLayoutParams(paramsAmPm);
}
- }
- else if (mIs24HourMode && !mEnableSeconds && mEnableMinutes) {
+ } else if (mIs24HourMode && !mEnableSeconds && mEnableMinutes) {
// center first separator
RelativeLayout.LayoutParams paramsSeparator = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
@@ -925,7 +1014,7 @@ else if (mIs24HourMode && !mEnableSeconds && mEnableMinutes) {
if (!mIs24HourMode) {
RelativeLayout.LayoutParams paramsAmPm = new RelativeLayout.LayoutParams(
- LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
+ LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
);
paramsAmPm.addRule(RelativeLayout.RIGHT_OF, R.id.mdtp_hour_space);
paramsAmPm.addRule(RelativeLayout.ALIGN_BASELINE, R.id.mdtp_hour_space);
@@ -995,7 +1084,7 @@ else if (mIs24HourMode && !mEnableSeconds && mEnableMinutes) {
if (mCancelColor == null) mCancelColor = mAccentColor;
mCancelButton.setTextColor(mCancelColor);
- if(getDialog() == null) {
+ if (getDialog() == null) {
view.findViewById(R.id.mdtp_done_background).setVisibility(View.GONE);
}
@@ -1004,13 +1093,36 @@ else if (mIs24HourMode && !mEnableSeconds && mEnableMinutes) {
int darkBackgroundColor = ContextCompat.getColor(context, R.color.mdtp_light_gray);
int lightGray = ContextCompat.getColor(context, R.color.mdtp_light_gray);
- mTimePicker.setBackgroundColor(mThemeDark? lightGray : circleBackground);
+ mTimePicker.setBackgroundColor(mThemeDark ? lightGray : circleBackground);
view.findViewById(R.id.mdtp_time_picker_dialog).setBackgroundColor(mThemeDark ? darkBackgroundColor : backgroundColor);
+
+ setUiFont(view);
+
return view;
}
+ private void setUiFont(View view) {
+ final Typeface font = Utils.getCustomFont();
+ if (font == null) {
+ final Activity activity = requireActivity();
+ mOkButton.setTypeface(ResourcesCompat.getFont(activity, R.font.robotomedium));
+ mCancelButton.setTypeface(ResourcesCompat.getFont(activity, R.font.robotomedium));
+ } else {
+ if (mOkButton != null) mOkButton.setTypeface(font);
+ if (mCancelButton != null) mCancelButton.setTypeface(font);
+ if (mAmTextView != null) mAmTextView.setTypeface(font);
+ if (mPmTextView != null) mPmTextView.setTypeface(font);
+ if (mHourView != null) mHourView.setTypeface(font);
+ if (mMinuteView != null) mMinuteView.setTypeface(font);
+ if (mSecondView != null) mSecondView.setTypeface(font);
+ ((TextView) view.findViewById(R.id.mdtp_separator)).setTypeface(font);
+ ((TextView) view.findViewById(R.id.mdtp_separator_seconds)).setTypeface(font);
+ ((TextView) view.findViewById(R.id.mdtp_time_picker_header)).setTypeface(font);
+ }
+ }
+
@Override
- public void onConfigurationChanged(final Configuration newConfig) {
+ public void onConfigurationChanged(@NonNull final Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ViewGroup viewGroup = (ViewGroup) getView();
if (viewGroup != null) {
@@ -1030,24 +1142,24 @@ public void onResume() {
public void onPause() {
super.onPause();
mHapticFeedbackController.stop();
- if(mDismissOnPause) dismiss();
+ if (mDismissOnPause) dismiss();
}
@Override
- public void onCancel(DialogInterface dialog) {
+ public void onCancel(@NonNull DialogInterface dialog) {
super.onCancel(dialog);
- if(mOnCancelListener != null) mOnCancelListener.onCancel(dialog);
+ if (mOnCancelListener != null) mOnCancelListener.onCancel(dialog);
}
@Override
- public void onDismiss(DialogInterface dialog) {
+ public void onDismiss(@NonNull DialogInterface dialog) {
super.onDismiss(dialog);
- if(mOnDismissListener != null) mOnDismissListener.onDismiss(dialog);
+ if (mOnDismissListener != null) mOnDismissListener.onDismiss(dialog);
}
@Override
public void tryVibrate() {
- if(mVibrate) mHapticFeedbackController.tryVibrate();
+ if (mVibrate) mHapticFeedbackController.tryVibrate();
}
private void updateAmPmDisplay(int amOrPm) {
@@ -1066,7 +1178,7 @@ private void updateAmPmDisplay(int amOrPm) {
mPmTextView.setText(mAmText);
Utils.tryAccessibilityAnnounce(mTimePicker, mAmText);
mPmTextView.setContentDescription(mAmText);
- } else if (amOrPm == PM){
+ } else if (amOrPm == PM) {
mPmTextView.setText(mPmText);
Utils.tryAccessibilityAnnounce(mTimePicker, mPmText);
mPmTextView.setContentDescription(mPmText);
@@ -1079,6 +1191,7 @@ private void updateAmPmDisplay(int amOrPm) {
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
if (mTimePicker != null) {
+ outState.putSerializable(KEY_CALENDAR_TYPE, mCalendarType);
outState.putParcelable(KEY_INITIAL_TIME, mTimePicker.getTime());
outState.putBoolean(KEY_IS_24_HOUR_VIEW, mIs24HourMode);
outState.putInt(KEY_CURRENT_ITEM_SHOWING, mTimePicker.getCurrentItemShowing());
@@ -1117,28 +1230,28 @@ public void onValueSelected(Timepoint newValue) {
mTimePicker.setContentDescription(mMinutePickerDescription + ": " + newValue.getMinute());
setSecond(newValue.getSecond());
mTimePicker.setContentDescription(mSecondPickerDescription + ": " + newValue.getSecond());
- if(!mIs24HourMode) updateAmPmDisplay(newValue.isAM() ? AM : PM);
+ if (!mIs24HourMode) updateAmPmDisplay(newValue.isAM() ? AM : PM);
}
@Override
public void advancePicker(int index) {
- if(!mAllowAutoAdvance) return;
- if(index == HOUR_INDEX && mEnableMinutes) {
+ if (!mAllowAutoAdvance) return;
+ if (index == HOUR_INDEX && mEnableMinutes) {
setCurrentItemShowing(MINUTE_INDEX, true, true, false);
String announcement = mSelectHours + ". " + mTimePicker.getMinutes();
Utils.tryAccessibilityAnnounce(mTimePicker, announcement);
- } else if(index == MINUTE_INDEX && mEnableSeconds) {
+ } else if (index == MINUTE_INDEX && mEnableSeconds) {
setCurrentItemShowing(SECOND_INDEX, true, true, false);
- String announcement = mSelectMinutes+". " + mTimePicker.getSeconds();
+ String announcement = mSelectMinutes + ". " + mTimePicker.getSeconds();
Utils.tryAccessibilityAnnounce(mTimePicker, announcement);
}
}
@Override
public void enablePicker() {
- if(!isTypedTimeFullyLegal()) mTypedTimes.clear();
+ if (!isTypedTimeFullyLegal()) mTypedTimes.clear();
finishKbMode(true);
}
@@ -1163,6 +1276,7 @@ public boolean isPmDisabled() {
/**
* Round a given Timepoint to the nearest valid Timepoint
+ *
* @param time Timepoint - The timepoint to round
* @return Timepoint - The nearest valid Timepoint
*/
@@ -1175,11 +1289,18 @@ public Timepoint roundToNearest(@NonNull Timepoint time, @Nullable Timepoint.TYP
return mLimiter.roundToNearest(time, type, getPickerResolution());
}
+ @Override
+ public void setFont(Typeface customFont) {
+ Utils.setCustomFont(customFont);
+ }
+
/**
* Get the configured resolution of the current picker in terms of Timepoint components
+ *
* @return Timepoint.TYPE (hour, minute or second)
*/
- @NonNull Timepoint.TYPE getPickerResolution() {
+ @NonNull
+ Timepoint.TYPE getPickerResolution() {
if (mEnableSeconds) return Timepoint.TYPE.SECOND;
if (mEnableMinutes) return Timepoint.TYPE.MINUTE;
return Timepoint.TYPE.HOUR;
@@ -1216,7 +1337,7 @@ private void setMinute(int value) {
}
private void setSecond(int value) {
- if(value == 60) {
+ if (value == 60) {
value = 0;
}
CharSequence text = String.format(mLocale, "%02d", value);
@@ -1227,11 +1348,11 @@ private void setSecond(int value) {
// Show either Hours or Minutes.
private void setCurrentItemShowing(int index, boolean animateCircle, boolean delayLabelAnimate,
- boolean announce) {
+ boolean announce) {
mTimePicker.setCurrentItemShowing(index, animateCircle);
TextView labelToAnimate;
- switch(index) {
+ switch (index) {
case HOUR_INDEX:
int hours = mTimePicker.getHours();
if (!mIs24HourMode) {
@@ -1276,12 +1397,13 @@ private void setCurrentItemShowing(int index, boolean animateCircle, boolean del
/**
* For keyboard mode, processes key events.
+ *
* @param keyCode the pressed key.
* @return true if the key was successfully processed, false otherwise.
*/
private boolean processKeyUp(int keyCode) {
if (keyCode == KeyEvent.KEYCODE_TAB) {
- if(mInKbMode) {
+ if (mInKbMode) {
if (isTypedTimeFullyLegal()) {
finishKbMode(true);
}
@@ -1323,7 +1445,7 @@ private boolean processKeyUp(int keyCode) {
|| keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7
|| keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9
|| (!mIs24HourMode &&
- (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) {
+ (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) {
if (!mInKbMode) {
if (mTimePicker == null) {
// Something's wrong, because time picker should definitely not be null.
@@ -1346,9 +1468,10 @@ private boolean processKeyUp(int keyCode) {
/**
* Try to start keyboard mode with the specified key, as long as the timepicker is not in the
* middle of a touch-event.
+ *
* @param keyCode The key to use as the first press. Keyboard mode will not be started if the
- * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting
- * key.
+ * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting
+ * key.
*/
private void tryStartingKbMode(int keyCode) {
if (mTimePicker.trySettingInputEnabled(false) &&
@@ -1433,6 +1556,7 @@ private int deleteLastTypedKey() {
/**
* Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time.
+ *
* @param updateDisplays If true, update the displays with the relevant time.
*/
private void finishKbMode(boolean updateDisplays) {
@@ -1456,8 +1580,9 @@ private void finishKbMode(boolean updateDisplays) {
* Update the hours, minutes, seconds and AM/PM displays with the typed times. If the typedTimes
* is empty, either show an empty display (filled with the placeholder text), or update from the
* timepicker's values.
+ *
* @param allowEmptyDisplay if true, then if the typedTimes is empty, use the placeholder text.
- * Otherwise, revert to the timepicker's values.
+ * Otherwise, revert to the timepicker's values.
*/
private void updateDisplay(boolean allowEmptyDisplay) {
if (!allowEmptyDisplay && mTypedTimes.isEmpty()) {
@@ -1468,7 +1593,7 @@ private void updateDisplay(boolean allowEmptyDisplay) {
setMinute(minute);
setSecond(second);
if (!mIs24HourMode) {
- updateAmPmDisplay(hour < 12? AM : PM);
+ updateAmPmDisplay(hour < 12 ? AM : PM);
}
setCurrentItemShowing(mTimePicker.getCurrentItemShowing(), true, true, true);
mOkButton.setEnabled(true);
@@ -1479,9 +1604,9 @@ private void updateDisplay(boolean allowEmptyDisplay) {
String minuteFormat = (enteredZeros[1]) ? "%02d" : "%2d";
String secondFormat = (enteredZeros[1]) ? "%02d" : "%2d";
String hourStr = (values[0] == -1) ? mDoublePlaceholderText :
- String.format(hourFormat, values[0]).replace(' ', mPlaceholderText);
+ String.format(hourFormat, values[0]).replace(' ', mPlaceholderText);
String minuteStr = (values[1] == -1) ? mDoublePlaceholderText :
- String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
+ String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
String secondStr = (values[2] == -1) ? mDoublePlaceholderText :
String.format(secondFormat, values[1]).replace(' ', mPlaceholderText);
mHourView.setText(hourStr);
@@ -1528,9 +1653,10 @@ private static int getValFromKeyCode(int keyCode) {
/**
* Get the currently-entered time, as integer values of the hours, minutes and seconds typed.
+ *
* @param enteredZeros A size-2 boolean array, which the caller should initialize, and which
- * may then be used for the caller to know whether zeros had been explicitly entered as either
- * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's.
+ * may then be used for the caller to know whether zeros had been explicitly entered as either
+ * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's.
* @return A size-3 int array. The first value will be the hours, the second value will be the
* minutes, and the third will be either TimePickerDialog.AM or TimePickerDialog.PM.
*/
@@ -1542,7 +1668,7 @@ private int[] getEnteredTime(@NonNull Boolean[] enteredZeros) {
int keyCode = mTypedTimes.get(mTypedTimes.size() - 1);
if (keyCode == getAmOrPmKeyCode(AM)) {
amOrPm = AM;
- } else if (keyCode == getAmOrPmKeyCode(PM)){
+ } else if (keyCode == getAmOrPmKeyCode(PM)) {
amOrPm = PM;
}
startIndex = 2;
@@ -1557,7 +1683,7 @@ private int[] getEnteredTime(@NonNull Boolean[] enteredZeros) {
if (i == startIndex) {
second = val;
} else if (i == startIndex + 1) {
- second += 10*val;
+ second += 10 * val;
if (val == 0) enteredZeros[2] = true;
}
}
@@ -1583,7 +1709,7 @@ private int[] getEnteredTime(@NonNull Boolean[] enteredZeros) {
}
}
- return new int[] {hour, minute, second, amOrPm};
+ return new int[]{hour, minute, second, amOrPm};
}
/**
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/Timepoint.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/Timepoint.java
index 023da205..6d4019b2 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/Timepoint.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/Timepoint.java
@@ -2,6 +2,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -14,7 +15,7 @@
* The time input is expected to use 24 hour mode.
* Fields are modulo'd into their correct ranges.
* It does not handle timezones.
- *
+ *
* Created by wdullaer on 13/10/15.
*/
@SuppressWarnings("WeakerAccess")
@@ -33,20 +34,20 @@ public Timepoint(Timepoint time) {
this(time.hour, time.minute, time.second);
}
- public Timepoint(@IntRange(from=0, to=23) int hour,
- @IntRange(from=0, to=59) int minute,
- @IntRange(from=0, to=59) int second) {
+ public Timepoint(@IntRange(from = 0, to = 23) int hour,
+ @IntRange(from = 0, to = 59) int minute,
+ @IntRange(from = 0, to = 59) int second) {
this.hour = hour % 24;
this.minute = minute % 60;
this.second = second % 60;
}
- public Timepoint(@IntRange(from=0, to=23) int hour,
- @IntRange(from=0, to=59) int minute) {
+ public Timepoint(@IntRange(from = 0, to = 23) int hour,
+ @IntRange(from = 0, to = 59) int minute) {
this(hour, minute, 0);
}
- public Timepoint(@IntRange(from=0, to=23) int hour) {
+ public Timepoint(@IntRange(from = 0, to = 23) int hour) {
this(hour, 0);
}
@@ -56,17 +57,17 @@ public Timepoint(Parcel in) {
second = in.readInt();
}
- @IntRange(from=0, to=23)
+ @IntRange(from = 0, to = 23)
public int getHour() {
return hour;
}
- @IntRange(from=0, to=59)
+ @IntRange(from = 0, to = 59)
public int getMinute() {
return minute;
}
- @IntRange(from=0, to=59)
+ @IntRange(from = 0, to = 59)
public int getSecond() {
return second;
}
@@ -80,11 +81,11 @@ public boolean isPM() {
}
public void setAM() {
- if(hour >= 12) hour = hour % 12;
+ if (hour >= 12) hour = hour % 12;
}
public void setPM() {
- if(hour < 12) hour = (hour + 12) % 24;
+ if (hour < 12) hour = (hour + 12) % 24;
}
public void add(TYPE type, int value) {
diff --git a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/TimepointLimiter.java b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/TimepointLimiter.java
index 3709fa01..8f8090ba 100644
--- a/library/src/main/java/com/wdullaer/materialdatetimepicker/time/TimepointLimiter.java
+++ b/library/src/main/java/com/wdullaer/materialdatetimepicker/time/TimepointLimiter.java
@@ -1,6 +1,7 @@
package com.wdullaer.materialdatetimepicker.time;
import android.os.Parcelable;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -9,23 +10,23 @@ public interface TimepointLimiter extends Parcelable {
/**
* isOutOfRange indicates whether a particular timepoint is selectable or not
* It is called multiple times in the rendering path, so it should be fast
- *
+ *
* The index parameter indicates which picker is currently visible. This is necessary because
* you typically only want to compare with a resolution up to the visible component. (The
* implementation should ensure that 8 is selectable, if any valid timepoint with 8 as the hour
* is selectable, when the hour picker is showing)
- *
+ *
* Similarly the overall resolution of the picker is passed in, because it can impact the
* comparisons an implementation does (especially when comparing with a disabled list)
- *
+ *
* The scope of this method is most likely too broad, which makes it hard to reason about. It is
* one of the main reasons the DefaultTimeLimiter implementation of this contains extensive
* example and generate tests. The default implementation should cover 90% of use cases, but if
* I ever notice that a substantial amount of people are trying to implement this themselves, it
* might need to be redesigned.
*
- * @param point A timepoint to validate
- * @param index The currently showing picker (hour, minute, second)
+ * @param point A timepoint to validate
+ * @param index The currently showing picker (hour, minute, second)
* @param resolution The overall resolution of the picker
* @return whether the Timepoint is out of range or selectable
*/
@@ -36,6 +37,7 @@ public interface TimepointLimiter extends Parcelable {
* This method is called when the picker is initialized or when the user clicks / taps the AM or
* PM buttons.
* This means that it's result can't be updated when the picker is already being rendered
+ *
* @return true if the AM selector should be disabled
*/
boolean isAmDisabled();
@@ -45,6 +47,7 @@ public interface TimepointLimiter extends Parcelable {
* This method is called when the picker is initialized or when the user clicks / taps the AM or
* PM buttons.
* This means that it's result can't be updated when the picker is already being rendered
+ *
* @return true if the PM selector should be disabled
*/
boolean isPmDisabled();
@@ -53,16 +56,17 @@ public interface TimepointLimiter extends Parcelable {
* roundToNearest returns the nearest selectable timepoint given a particular input
* It is called whenever the user touches the screen, which means it can get called very
* frequently if the user performs a drag operation
- *
+ *
* Both the currently showing picker and the overall resolution are passed in, for similar
* reasons as in isOutOfRange
*
- * @param time the proposed selection
- * @param type the currently showing picker (hour, minute, second)
+ * @param time the proposed selection
+ * @param type the currently showing picker (hour, minute, second)
* @param resolution the overall resolution of the picker
* @return a selectable timepoint
*/
- @NonNull Timepoint roundToNearest(
+ @NonNull
+ Timepoint roundToNearest(
@NonNull Timepoint time,
@Nullable Timepoint.TYPE type,
@NonNull Timepoint.TYPE resolution
diff --git a/library/src/main/res/layout/mdtp_date_picker_selected_date_v2.xml b/library/src/main/res/layout/mdtp_date_picker_selected_date_v2.xml
index 38299d30..cbbbc732 100644
--- a/library/src/main/res/layout/mdtp_date_picker_selected_date_v2.xml
+++ b/library/src/main/res/layout/mdtp_date_picker_selected_date_v2.xml
@@ -44,17 +44,19 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
+ android:gravity="start"
android:clickable="true"
+ android:focusable="true"
android:orientation="horizontal"
android:background="@android:color/transparent"
android:textColor="@color/mdtp_date_picker_selector" >
- {
-
- });
+ DatePickerDialog dpd = DatePickerDialog.newInstance(
+ (view, year, monthOfYear, dayOfMonth) -> {
+ },
+ CalendarType.GREGORIAN
+ );
Assert.assertFalse(dpd.isHighlighted(1990, 1, 1));
}
@Test
public void isHighlightedShouldReturnFalseIfHighlightedDoesNotContainSelection() {
- DatePickerDialog dpd = DatePickerDialog.newInstance((view, year, monthOfYear, dayOfMonth) -> {
-
- });
+ DatePickerDialog dpd = DatePickerDialog.newInstance(
+ (view, year, monthOfYear, dayOfMonth) -> {
+ },
+ CalendarType.GREGORIAN
+ );
Calendar highlighted = Calendar.getInstance();
highlighted.set(Calendar.YEAR, 1990);
highlighted.set(Calendar.MONTH, 1);
@@ -35,9 +41,11 @@ public void isHighlightedShouldReturnFalseIfHighlightedDoesNotContainSelection()
@Test
public void isHighlightedShouldReturnTrueIfHighlightedDoesContainSelection() {
- DatePickerDialog dpd = DatePickerDialog.newInstance((view, year, monthOfYear, dayOfMonth) -> {
-
- });
+ DatePickerDialog dpd = DatePickerDialog.newInstance(
+ (view, year, monthOfYear, dayOfMonth) -> {
+ },
+ CalendarType.GREGORIAN
+ );
int year = 1990;
int month = 1;
int day = 1;
@@ -58,9 +66,12 @@ public void isHighlightedShouldReturnTrueIfHighlightedDoesContainSelection() {
public void isHighlightedShouldBehaveCorrectlyInCustomTimezones() {
String timeZoneString = "Americas/Los_Angeles";
Calendar initial = Calendar.getInstance(TimeZone.getTimeZone(timeZoneString));
- DatePickerDialog dpd = DatePickerDialog.newInstance((view, year, monthOfYear, dayOfMonth) -> {
-
- }, initial);
+ DatePickerDialog dpd = DatePickerDialog.newInstance(
+ (view, year, monthOfYear, dayOfMonth) -> {
+ },
+ CalendarType.GREGORIAN,
+ initial
+ );
int year = 1990;
int month = 1;
int day = 1;
diff --git a/library/src/test/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterPropertyTest.java b/library/src/test/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterPropertyTest.java
index 59e76bf3..d2b732ba 100644
--- a/library/src/test/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterPropertyTest.java
+++ b/library/src/test/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterPropertyTest.java
@@ -1,9 +1,14 @@
package com.wdullaer.materialdatetimepicker.date;
+import android.graphics.Typeface;
+
import com.pholser.junit.quickcheck.Property;
import com.pholser.junit.quickcheck.generator.InRange;
import com.pholser.junit.quickcheck.runner.JUnitQuickcheck;
import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+import com.wdullaer.materialdatetimepicker.enums.ScrollOrientation;
+import com.wdullaer.materialdatetimepicker.enums.Version;
import org.junit.Assert;
import org.junit.runner.RunWith;
@@ -23,16 +28,20 @@
public class DefaultDateRangeLimiterPropertyTest {
final private DatePickerController controller = new DatePickerController() {
@Override
- public void onYearSelected(int year) {}
+ public void onYearSelected(int year) {
+ }
@Override
- public void onDayOfMonthSelected(int year, int month, int day) {}
+ public void onDayOfMonthSelected(int year, int month, int day) {
+ }
@Override
- public void registerOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {}
+ public void registerOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {
+ }
@Override
- public void unregisterOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {}
+ public void unregisterOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {
+ }
@Override
public MonthAdapter.CalendarDay getSelectedDay() {
@@ -85,7 +94,8 @@ public boolean isOutOfRange(int year, int month, int day) {
}
@Override
- public void tryVibrate() {}
+ public void tryVibrate() {
+ }
@Override
public TimeZone getTimeZone() {
@@ -98,13 +108,22 @@ public Locale getLocale() {
}
@Override
- public DatePickerDialog.Version getVersion() {
- return DatePickerDialog.Version.VERSION_2;
+ public Version getVersion() {
+ return Version.VERSION_2;
+ }
+
+ @Override
+ public ScrollOrientation getScrollOrientation() {
+ return ScrollOrientation.HORIZONTAL;
+ }
+
+ @Override
+ public CalendarType getCalendarType() {
+ return CalendarType.GREGORIAN;
}
@Override
- public DatePickerDialog.ScrollOrientation getScrollOrientation() {
- return DatePickerDialog.ScrollOrientation.HORIZONTAL;
+ public void setFont(Typeface customFont) {
}
};
diff --git a/library/src/test/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterTest.java b/library/src/test/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterTest.java
index ef7bbd04..b12467b2 100644
--- a/library/src/test/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterTest.java
+++ b/library/src/test/java/com/wdullaer/materialdatetimepicker/date/DefaultDateRangeLimiterTest.java
@@ -1,9 +1,14 @@
package com.wdullaer.materialdatetimepicker.date;
+import android.graphics.Typeface;
+
import com.wdullaer.materialdatetimepicker.Utils;
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+import com.wdullaer.materialdatetimepicker.enums.ScrollOrientation;
+import com.wdullaer.materialdatetimepicker.enums.Version;
-import org.junit.Test;
import org.junit.Assert;
+import org.junit.Test;
import java.util.Arrays;
import java.util.Calendar;
@@ -13,22 +18,26 @@
/**
* Unit tests for the default DateRangeLimiter implementation
* Primarily used to assert that the rounding logic functions properly
- *
+ *
* Created by wdullaer on 14/04/17.
*/
public class DefaultDateRangeLimiterTest {
final private DatePickerController controller = new DatePickerController() {
@Override
- public void onYearSelected(int year) {}
+ public void onYearSelected(int year) {
+ }
@Override
- public void onDayOfMonthSelected(int year, int month, int day) {}
+ public void onDayOfMonthSelected(int year, int month, int day) {
+ }
@Override
- public void registerOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {}
+ public void registerOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {
+ }
@Override
- public void unregisterOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {}
+ public void unregisterOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {
+ }
@Override
public MonthAdapter.CalendarDay getSelectedDay() {
@@ -81,7 +90,8 @@ public boolean isOutOfRange(int year, int month, int day) {
}
@Override
- public void tryVibrate() {}
+ public void tryVibrate() {
+ }
@Override
public TimeZone getTimeZone() {
@@ -94,13 +104,22 @@ public Locale getLocale() {
}
@Override
- public DatePickerDialog.Version getVersion() {
- return DatePickerDialog.Version.VERSION_2;
+ public Version getVersion() {
+ return Version.VERSION_2;
}
@Override
- public DatePickerDialog.ScrollOrientation getScrollOrientation() {
- return DatePickerDialog.ScrollOrientation.HORIZONTAL;
+ public ScrollOrientation getScrollOrientation() {
+ return ScrollOrientation.HORIZONTAL;
+ }
+
+ @Override
+ public CalendarType getCalendarType() {
+ return CalendarType.GREGORIAN;
+ }
+
+ @Override
+ public void setFont(Typeface customFont) {
}
};
@@ -109,7 +128,7 @@ public DatePickerDialog.ScrollOrientation getScrollOrientation() {
public void getSelectableDaysShouldHaveDatesTrimmedToMidnight() {
DefaultDateRangeLimiter limiter = new DefaultDateRangeLimiter();
Calendar[] days = new Calendar[3];
- for (int i = 0;i < days.length; i++) {
+ for (int i = 0; i < days.length; i++) {
Calendar day = Calendar.getInstance();
day.set(Calendar.YEAR, 1999 + i);
day.set(Calendar.HOUR_OF_DAY, 2);
@@ -136,7 +155,7 @@ public void getSelectableDaysShouldHaveDatesTrimmedToMidnight() {
public void getDisabledDaysShouldHaveDatesTrimmedToMidnight() {
DefaultDateRangeLimiter limiter = new DefaultDateRangeLimiter();
Calendar[] days = new Calendar[3];
- for (int i = 0;i < days.length; i++) {
+ for (int i = 0; i < days.length; i++) {
Calendar day = Calendar.getInstance();
day.set(Calendar.YEAR, 1999 + i);
day.set(Calendar.HOUR_OF_DAY, 2);
@@ -452,16 +471,20 @@ public void isOutOfRangeShouldWorkWithCustomTimeZones() {
days[0] = disabledDay;
DatePickerController controller = new DatePickerController() {
@Override
- public void onYearSelected(int year) {}
+ public void onYearSelected(int year) {
+ }
@Override
- public void onDayOfMonthSelected(int year, int month, int day) {}
+ public void onDayOfMonthSelected(int year, int month, int day) {
+ }
@Override
- public void registerOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {}
+ public void registerOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {
+ }
@Override
- public void unregisterOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {}
+ public void unregisterOnDateChangedListener(DatePickerDialog.OnDateChangedListener listener) {
+ }
@Override
public MonthAdapter.CalendarDay getSelectedDay() {
@@ -529,14 +552,23 @@ public Locale getLocale() {
}
@Override
- public DatePickerDialog.Version getVersion() {
+ public Version getVersion() {
return null;
}
@Override
- public DatePickerDialog.ScrollOrientation getScrollOrientation() {
+ public ScrollOrientation getScrollOrientation() {
return null;
}
+
+ @Override
+ public CalendarType getCalendarType() {
+ return CalendarType.GREGORIAN;
+ }
+
+ @Override
+ public void setFont(Typeface customFont) {
+ }
};
limiter.setDisabledDays(days);
@@ -559,7 +591,7 @@ public void setToNearestShouldReturnTheInputWhenValid() {
public void setToNearestShouldRoundDisabledDates() {
DefaultDateRangeLimiter limiter = new DefaultDateRangeLimiter();
Calendar[] days = new Calendar[3];
- for (int i = 0;i < days.length; i++) {
+ for (int i = 0; i < days.length; i++) {
Calendar day = Calendar.getInstance();
day.set(Calendar.YEAR, 1999 + i);
day.set(Calendar.HOUR_OF_DAY, 2);
@@ -613,7 +645,7 @@ public void setToNearestShouldRoundToMaxDate() {
public void setToNearestShouldRoundToASelectableDay() {
DefaultDateRangeLimiter limiter = new DefaultDateRangeLimiter();
Calendar[] days = new Calendar[3];
- for (int i = 0;i < days.length; i++) {
+ for (int i = 0; i < days.length; i++) {
Calendar day = Calendar.getInstance();
day.set(Calendar.YEAR, 1999 + i);
day.set(Calendar.HOUR_OF_DAY, 2);
@@ -638,7 +670,7 @@ public void setToNearestShouldRoundToASelectableDayWhenAControllerIsSet() {
DefaultDateRangeLimiter limiter = new DefaultDateRangeLimiter();
limiter.setController(controller);
Calendar[] days = new Calendar[3];
- for (int i = 0;i < days.length; i++) {
+ for (int i = 0; i < days.length; i++) {
Calendar day = Calendar.getInstance();
day.set(Calendar.YEAR, 1999 + i);
day.set(Calendar.HOUR_OF_DAY, 2);
diff --git a/library/src/test/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiterTest.java b/library/src/test/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiterTest.java
index 6f21b879..6ea9e3d0 100644
--- a/library/src/test/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiterTest.java
+++ b/library/src/test/java/com/wdullaer/materialdatetimepicker/time/DefaultTimepointLimiterTest.java
@@ -1,15 +1,15 @@
package com.wdullaer.materialdatetimepicker.time;
+import org.junit.Assert;
+import org.junit.Test;
+
import static com.wdullaer.materialdatetimepicker.time.TimePickerDialog.HOUR_INDEX;
import static com.wdullaer.materialdatetimepicker.time.TimePickerDialog.MINUTE_INDEX;
-import org.junit.Test;
-import org.junit.Assert;
-
/**
* Unit tests for the default implementation of TimepointLimiter
* Mostly used to assert that the rounding logic works
- *
+ *
* Created by wdullaer on 22/06/17.
*/
public class DefaultTimepointLimiterTest {
@@ -257,7 +257,7 @@ public void isOutOfRangeShouldReturnTrueIfInputNotSelectable() {
new Timepoint(13),
new Timepoint(14)
};
- DefaultTimepointLimiter limiter = new DefaultTimepointLimiter();
+ DefaultTimepointLimiter limiter = new DefaultTimepointLimiter();
limiter.setSelectableTimes(selectableDays);
diff --git a/library/src/test/java/com/wdullaer/materialdatetimepicker/time/TimePickerDialogTest.java b/library/src/test/java/com/wdullaer/materialdatetimepicker/time/TimePickerDialogTest.java
index 3bad88b4..10a38bfa 100644
--- a/library/src/test/java/com/wdullaer/materialdatetimepicker/time/TimePickerDialogTest.java
+++ b/library/src/test/java/com/wdullaer/materialdatetimepicker/time/TimePickerDialogTest.java
@@ -1,19 +1,21 @@
package com.wdullaer.materialdatetimepicker.time;
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+
import org.junit.Assert;
import org.junit.Test;
public class TimePickerDialogTest {
@Test
public void getPickerResolutionShouldReturnSecondIfSecondsAreEnabled() {
- TimePickerDialog tpd = TimePickerDialog.newInstance(null, false);
+ TimePickerDialog tpd = TimePickerDialog.newInstance(null, CalendarType.GREGORIAN, false);
tpd.enableSeconds(true);
Assert.assertEquals(tpd.getPickerResolution(), Timepoint.TYPE.SECOND);
}
@Test
public void getPickerResolutionShouldReturnMinuteIfMinutesAreEnabled() {
- TimePickerDialog tpd = TimePickerDialog.newInstance(null, false);
+ TimePickerDialog tpd = TimePickerDialog.newInstance(null, CalendarType.GREGORIAN, false);
tpd.enableSeconds(false);
tpd.enableMinutes(true);
Assert.assertEquals(tpd.getPickerResolution(), Timepoint.TYPE.MINUTE);
@@ -21,7 +23,7 @@ public void getPickerResolutionShouldReturnMinuteIfMinutesAreEnabled() {
@Test
public void getPickerResolutionShouldReturnHourIfMinutesAndSecondsAreDisabled() {
- TimePickerDialog tpd = TimePickerDialog.newInstance(null, false);
+ TimePickerDialog tpd = TimePickerDialog.newInstance(null, CalendarType.GREGORIAN, false);
tpd.enableMinutes(false);
Assert.assertEquals(tpd.getPickerResolution(), Timepoint.TYPE.HOUR);
}
diff --git a/library/src/test/java/com/wdullaer/materialdatetimepicker/time/TimepointTest.java b/library/src/test/java/com/wdullaer/materialdatetimepicker/time/TimepointTest.java
index 3c25e83f..dc7b84f6 100644
--- a/library/src/test/java/com/wdullaer/materialdatetimepicker/time/TimepointTest.java
+++ b/library/src/test/java/com/wdullaer/materialdatetimepicker/time/TimepointTest.java
@@ -1,7 +1,7 @@
package com.wdullaer.materialdatetimepicker.time;
-import org.junit.Test;
import org.junit.Assert;
+import org.junit.Test;
import java.util.HashSet;
diff --git a/sample/build.gradle b/sample/build.gradle
index 7f625112..f510f253 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -10,6 +10,7 @@ android {
targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
versionName project.VERSION_NAME
versionCode Integer.parseInt(project.VERSION_CODE)
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@@ -35,4 +36,6 @@ dependencies {
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.viewpager:viewpager:1.0.0'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-1'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
}
diff --git a/sample/src/androidTest/java/com/wdullaer/datetimepickerexample/ApplicationTest.java b/sample/src/androidTest/java/com/wdullaer/datetimepickerexample/ApplicationTest.java
deleted file mode 100644
index 88a7376a..00000000
--- a/sample/src/androidTest/java/com/wdullaer/datetimepickerexample/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.wdullaer.datetimepickerexample;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase {
- public ApplicationTest() {
- super(Application.class);
- }
-}
\ No newline at end of file
diff --git a/sample/src/androidTest/java/com/wdullaer/datetimepickerexample/ExampleInstrumentedTest.java b/sample/src/androidTest/java/com/wdullaer/datetimepickerexample/ExampleInstrumentedTest.java
new file mode 100644
index 00000000..b4eefdee
--- /dev/null
+++ b/sample/src/androidTest/java/com/wdullaer/datetimepickerexample/ExampleInstrumentedTest.java
@@ -0,0 +1,27 @@
+package com.wdullaer.datetimepickerexample;
+
+import android.content.Context;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ assertEquals("com.wdullaer.materialdatetimepicker.sample", appContext.getPackageName());
+ }
+}
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
index a7830ee8..4936c8f5 100644
--- a/sample/src/main/AndroidManifest.xml
+++ b/sample/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
+ android:supportsRtl="true"
android:theme="@style/AppTheme" >
adapter = ArrayAdapter.createFromResource(requireActivity(),
+ R.array.calendar_types_array, android.R.layout.simple_spinner_item);
+ // Specify the layout to use when the list of choices appears
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ // Apply the adapter to the spinner
+ spinner.setAdapter(adapter);
+
+ final Spinner localeSpinner = view.findViewById(R.id.calendar_locale);
+ // Create an ArrayAdapter using the string array and a default spinner layout
+ ArrayAdapter localeAdapter = ArrayAdapter.createFromResource(requireActivity(),
+ R.array.calendar_Locales_array, android.R.layout.simple_spinner_item);
+ // Specify the layout to use when the list of choices appears
+ localeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ // Apply the adapter to the spinner
+ localeSpinner.setAdapter(localeAdapter);
+
+ font = Typeface.createFromAsset(requireActivity().getAssets(), "IRANYekanMobileRegular.ttf");
+
view.findViewById(R.id.original_button).setOnClickListener(v -> {
Calendar now = Calendar.getInstance();
new android.app.DatePickerDialog(
@@ -73,18 +106,29 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
// Show a datepicker when the dateButton is clicked
dateButton.setOnClickListener(v -> {
- Calendar now = Calendar.getInstance();
- if (defaultSelection.isChecked()) {
- now.add(Calendar.DATE, 7);
- }
+ Calendar now;
/*
It is recommended to always create a new instance whenever you need to show a Dialog.
The sample app is reusing them because it is useful when looking for regressions
during testing
*/
+
+ if (spinner.getSelectedItemPosition() == 0) {
+ calendarType = CalendarType.JALALI;
+ now = JalaliCalendar.getInstance();
+ } else {
+ calendarType = CalendarType.GREGORIAN;
+ now = Calendar.getInstance();
+ }
+
+ if (defaultSelection.isChecked()) {
+ now.add(Calendar.DATE, 7);
+ }
+
if (dpd == null) {
dpd = DatePickerDialog.newInstance(
DatePickerFragment.this,
+ calendarType,
now.get(Calendar.YEAR),
now.get(Calendar.MONTH),
now.get(Calendar.DAY_OF_MONTH)
@@ -92,21 +136,47 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
} else {
dpd.initialize(
DatePickerFragment.this,
+ calendarType,
now.get(Calendar.YEAR),
now.get(Calendar.MONTH),
now.get(Calendar.DAY_OF_MONTH)
);
}
+
+ switch (calendarType) {
+ case JALALI:
+ dpd.setFont(font);
+ break;
+ case GREGORIAN:
+ default:
+ dpd.setFont(null);
+ break;
+ }
+
+ if (localeSpinner.getSelectedItemPosition() == 0) {
+ dpd.setLocale(new Locale("fa"));
+ } else {
+ dpd.setLocale(Locale.ENGLISH);
+ }
+
dpd.setThemeDark(modeDarkDate.isChecked());
dpd.vibrate(vibrateDate.isChecked());
dpd.dismissOnPause(dismissDate.isChecked());
dpd.showYearPickerFirst(showYearFirst.isChecked());
- dpd.setVersion(showVersion2.isChecked() ? DatePickerDialog.Version.VERSION_2 : DatePickerDialog.Version.VERSION_1);
+ dpd.setVersion(showVersion2.isChecked() ? Version.VERSION_2 : Version.VERSION_1);
if (modeCustomAccentDate.isChecked()) {
dpd.setAccentColor(Color.parseColor("#9C27B0"));
}
if (titleDate.isChecked()) {
- dpd.setTitle("DatePicker Title");
+ switch (calendarType) {
+ case JALALI:
+ dpd.setTitle("عنوان انتخابگر تاریخ");
+ break;
+ case GREGORIAN:
+ default:
+ dpd.setTitle("DatePicker Title");
+ break;
+ }
}
if (highlightDays.isChecked()) {
Calendar date1 = Calendar.getInstance();
@@ -120,17 +190,26 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
if (limitSelectableDays.isChecked()) {
Calendar[] days = new Calendar[13];
for (int i = -6; i < 7; i++) {
- Calendar day = Calendar.getInstance();
+ Calendar day;
+ switch (calendarType) {
+ case JALALI:
+ day = JalaliCalendar.getInstance();
+ break;
+ case GREGORIAN:
+ default:
+ day = Calendar.getInstance();
+ break;
+ }
day.add(Calendar.DAY_OF_MONTH, i * 2);
days[i + 6] = day;
}
dpd.setSelectableDays(days);
}
if (switchOrientation.isChecked()) {
- if (dpd.getVersion() == DatePickerDialog.Version.VERSION_1) {
- dpd.setScrollOrientation(DatePickerDialog.ScrollOrientation.HORIZONTAL);
+ if (dpd.getVersion() == Version.VERSION_1) {
+ dpd.setScrollOrientation(ScrollOrientation.HORIZONTAL);
} else {
- dpd.setScrollOrientation(DatePickerDialog.ScrollOrientation.VERTICAL);
+ dpd.setScrollOrientation(ScrollOrientation.VERTICAL);
}
}
dpd.setOnCancelListener(dialog -> {
@@ -153,12 +232,12 @@ public void onDestroy() {
public void onResume() {
super.onResume();
DatePickerDialog dpd = (DatePickerDialog) requireFragmentManager().findFragmentByTag("Datepickerdialog");
- if(dpd != null) dpd.setOnDateSetListener(this);
+ if (dpd != null) dpd.setOnDateSetListener(this);
}
@Override
public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
- String date = "You picked the following date: "+dayOfMonth+"/"+(++monthOfYear)+"/"+year;
+ String date = "You picked the following date: " + dayOfMonth + "/" + (++monthOfYear) + "/" + year;
dateTextView.setText(date);
dpd = null;
}
diff --git a/sample/src/main/java/com/wdullaer/datetimepickerexample/MainActivity.java b/sample/src/main/java/com/wdullaer/datetimepickerexample/MainActivity.java
index 556d9df2..d6f05332 100644
--- a/sample/src/main/java/com/wdullaer/datetimepickerexample/MainActivity.java
+++ b/sample/src/main/java/com/wdullaer/datetimepickerexample/MainActivity.java
@@ -1,15 +1,17 @@
package com.wdullaer.datetimepickerexample;
import android.os.Bundle;
-import com.google.android.material.tabs.TabLayout;
+
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
-public class MainActivity extends AppCompatActivity
-{
+import com.google.android.material.tabs.TabLayout;
+
+public class MainActivity extends AppCompatActivity {
ViewPager viewPager;
PickerAdapter adapter;
@@ -25,7 +27,7 @@ protected void onCreate(Bundle savedInstanceState) {
setSupportActionBar(findViewById(R.id.toolbar));
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
- for(int i=0; i < adapter.getCount(); i++) //noinspection ConstantConditions
+ for (int i = 0; i < adapter.getCount(); i++) //noinspection ConstantConditions
tabLayout.getTabAt(i).setText(adapter.getTitle(i));
}
@@ -35,7 +37,7 @@ private class PickerAdapter extends FragmentPagerAdapter {
Fragment datePickerFragment;
PickerAdapter(FragmentManager fm) {
- super(fm);
+ super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
timePickerFragment = new TimePickerFragment();
datePickerFragment = new DatePickerFragment();
}
@@ -45,9 +47,10 @@ public int getCount() {
return NUM_PAGES;
}
+ @NonNull
@Override
public Fragment getItem(int position) {
- switch(position) {
+ switch (position) {
case 0:
return timePickerFragment;
case 1:
@@ -57,7 +60,7 @@ public Fragment getItem(int position) {
}
int getTitle(int position) {
- switch(position) {
+ switch (position) {
case 0:
return R.string.tab_title_time;
case 1:
diff --git a/sample/src/main/java/com/wdullaer/datetimepickerexample/TimePickerFragment.java b/sample/src/main/java/com/wdullaer/datetimepickerexample/TimePickerFragment.java
index 7eab7af2..36d06e2f 100644
--- a/sample/src/main/java/com/wdullaer/datetimepickerexample/TimePickerFragment.java
+++ b/sample/src/main/java/com/wdullaer/datetimepickerexample/TimePickerFragment.java
@@ -1,17 +1,23 @@
package com.wdullaer.datetimepickerexample;
import android.graphics.Color;
+import android.graphics.Typeface;
import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
+import android.widget.Spinner;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.wdullaer.materialdatetimepicker.enums.CalendarType;
+import com.wdullaer.materialdatetimepicker.enums.Version;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import com.wdullaer.materialdatetimepicker.time.Timepoint;
@@ -33,8 +39,12 @@ public class TimePickerFragment extends Fragment implements TimePickerDialog.OnT
private CheckBox limitSelectableTimes;
private CheckBox disableSpecificTimes;
private CheckBox showVersion2;
+
+ private static Typeface font;
private TimePickerDialog tpd;
+ private CalendarType calendarType;
+
public TimePickerFragment() {
// Required empty public constructor
}
@@ -58,6 +68,17 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
disableSpecificTimes = view.findViewById(R.id.disable_times);
showVersion2 = view.findViewById(R.id.show_version_2);
+ final Spinner spinner = view.findViewById(R.id.calendar_type);
+ // Create an ArrayAdapter using the string array and a default spinner layout
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(requireActivity(),
+ R.array.calendar_types_array, android.R.layout.simple_spinner_item);
+ // Specify the layout to use when the list of choices appears
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ // Apply the adapter to the spinner
+ spinner.setAdapter(adapter);
+
+ font = Typeface.createFromAsset(requireActivity().getAssets(), "IRANYekanMobileRegular.ttf");
+
view.findViewById(R.id.original_button).setOnClickListener(view1 -> {
Calendar now = Calendar.getInstance();
new android.app.TimePickerDialog(
@@ -72,6 +93,13 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
// Show a timepicker when the timeButton is clicked
timeButton.setOnClickListener(v -> {
Calendar now = Calendar.getInstance();
+
+ if (spinner.getSelectedItemPosition() == 0) {
+ calendarType = CalendarType.JALALI;
+ } else {
+ calendarType = CalendarType.GREGORIAN;
+ }
+
/*
It is recommended to always create a new instance whenever you need to show a Dialog.
The sample app is reusing them because it is useful when looking for regressions
@@ -80,6 +108,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
if (tpd == null) {
tpd = TimePickerDialog.newInstance(
TimePickerFragment.this,
+ calendarType,
now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE),
mode24Hours.isChecked()
@@ -87,22 +116,41 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
} else {
tpd.initialize(
TimePickerFragment.this,
+ calendarType,
now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE),
now.get(Calendar.SECOND),
mode24Hours.isChecked()
);
}
+
+ switch (calendarType) {
+ case JALALI:
+ tpd.setFont(font);
+ break;
+ case GREGORIAN:
+ default:
+ tpd.setFont(null);
+ break;
+ }
tpd.setThemeDark(modeDarkTime.isChecked());
tpd.vibrate(vibrateTime.isChecked());
tpd.dismissOnPause(dismissTime.isChecked());
tpd.enableSeconds(enableSeconds.isChecked());
- tpd.setVersion(showVersion2.isChecked() ? TimePickerDialog.Version.VERSION_2 : TimePickerDialog.Version.VERSION_1);
+ tpd.setVersion(showVersion2.isChecked() ? Version.VERSION_2 : Version.VERSION_1);
if (modeCustomAccentTime.isChecked()) {
tpd.setAccentColor(Color.parseColor("#9C27B0"));
}
if (titleTime.isChecked()) {
- tpd.setTitle("TimePicker Title");
+ switch (calendarType) {
+ case JALALI:
+ tpd.setTitle("عنوان انتخابگر زمان");
+ break;
+ case GREGORIAN:
+ default:
+ tpd.setTitle("TimePicker Title");
+ break;
+ }
}
if (limitSelectableTimes.isChecked()) {
if (enableSeconds.isChecked()) {
@@ -140,15 +188,15 @@ public void onDestroy() {
public void onResume() {
super.onResume();
TimePickerDialog tpd = (TimePickerDialog) requireFragmentManager().findFragmentByTag("Timepickerdialog");
- if(tpd != null) tpd.setOnTimeSetListener(this);
+ if (tpd != null) tpd.setOnTimeSetListener(this);
}
@Override
public void onTimeSet(TimePickerDialog view, int hourOfDay, int minute, int second) {
- String hourString = hourOfDay < 10 ? "0"+hourOfDay : ""+hourOfDay;
- String minuteString = minute < 10 ? "0"+minute : ""+minute;
- String secondString = second < 10 ? "0"+second : ""+second;
- String time = "You picked the following time: "+hourString+"h"+minuteString+"m"+secondString+"s";
+ String hourString = hourOfDay < 10 ? "0" + hourOfDay : "" + hourOfDay;
+ String minuteString = minute < 10 ? "0" + minute : "" + minute;
+ String secondString = second < 10 ? "0" + second : "" + second;
+ String time = "You picked the following time: " + hourString + "h" + minuteString + "m" + secondString + "s";
timeTextView.setText(time);
tpd = null;
}
diff --git a/sample/src/main/res/layout/datepicker_layout.xml b/sample/src/main/res/layout/datepicker_layout.xml
index 4fd9decf..a1d7cd7f 100644
--- a/sample/src/main/res/layout/datepicker_layout.xml
+++ b/sample/src/main/res/layout/datepicker_layout.xml
@@ -26,6 +26,26 @@
android:layout_height="wrap_content"
android:text="@string/original_button"/>
+
+
+
+
+
+
Date
Date+Time
+
+ - Jalali
+ - Gregorian
+
+
+
+ - Persian
+ - English
+
+