From 22d480584f41f4ee8915ff7289e42e4b91c6beca Mon Sep 17 00:00:00 2001 From: JoshBarnesD Date: Tue, 28 May 2024 14:04:21 +0200 Subject: [PATCH 01/14] Added implementation for firstDayOfWeek for Android --- .../rndatetimepicker/DatePickerModule.java | 370 +++++++++--------- .../rndatetimepicker/RNConstants.java | 1 + .../RNDatePickerDialogFragment.java | 311 +++++++-------- example/App.js | 62 +++ src/DateTimePickerAndroid.android.js | 2 + src/androidUtils.js | 3 + src/datetimepicker.android.js | 2 + src/index.d.ts | 1 + src/types.js | 1 + 9 files changed, 417 insertions(+), 336 deletions(-) diff --git a/android/src/main/java/com/reactcommunity/rndatetimepicker/DatePickerModule.java b/android/src/main/java/com/reactcommunity/rndatetimepicker/DatePickerModule.java index c7272205..46f6a2d0 100644 --- a/android/src/main/java/com/reactcommunity/rndatetimepicker/DatePickerModule.java +++ b/android/src/main/java/com/reactcommunity/rndatetimepicker/DatePickerModule.java @@ -5,185 +5,191 @@ * LICENSE file in the root directory of this source tree. */ -package com.reactcommunity.rndatetimepicker; - -import android.app.DatePickerDialog.OnDateSetListener; -import android.content.DialogInterface; -import android.content.DialogInterface.OnDismissListener; -import android.content.DialogInterface.OnClickListener; -import android.os.Bundle; -import android.widget.DatePicker; -import androidx.annotation.NonNull; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; - -import com.facebook.react.bridge.*; -import com.facebook.react.common.annotations.VisibleForTesting; -import com.facebook.react.module.annotations.ReactModule; - -import static com.reactcommunity.rndatetimepicker.Common.dismissDialog; - -import java.util.Calendar; - -/** - * {@link NativeModule} that allows JS to show a native date picker dialog and get called back when - * the user selects a date. - */ -@ReactModule(name = DatePickerModule.NAME) -public class DatePickerModule extends NativeModuleDatePickerSpec { - - @VisibleForTesting - public static final String NAME = "RNCDatePicker"; - - public DatePickerModule(ReactApplicationContext reactContext) { - super(reactContext); - } - - @NonNull - @Override - public String getName() { - return NAME; - } - - private class DatePickerDialogListener implements OnDateSetListener, OnDismissListener, OnClickListener { - - private final Promise mPromise; - private final Bundle mArgs; - private boolean mPromiseResolved = false; - - public DatePickerDialogListener(final Promise promise, Bundle arguments) { - mPromise = promise; - mArgs = arguments; - } - - @Override - public void onDateSet(DatePicker view, int year, int month, int day) { - if (!mPromiseResolved && getReactApplicationContext().hasActiveReactInstance()) { - final RNDate date = new RNDate(mArgs); - Calendar calendar = Calendar.getInstance(Common.getTimeZone(mArgs)); - calendar.set(year, month, day, date.hour(), date.minute(), 0); - calendar.set(Calendar.MILLISECOND, 0); - - WritableMap result = new WritableNativeMap(); - result.putString("action", RNConstants.ACTION_DATE_SET); - result.putDouble("timestamp", calendar.getTimeInMillis()); - result.putDouble("utcOffset", calendar.getTimeZone().getOffset(calendar.getTimeInMillis()) / 1000 / 60); - - mPromise.resolve(result); - mPromiseResolved = true; - } - } - - @Override - public void onDismiss(DialogInterface dialog) { - if (!mPromiseResolved && getReactApplicationContext().hasActiveReactInstance()) { - WritableMap result = new WritableNativeMap(); - result.putString("action", RNConstants.ACTION_DISMISSED); - mPromise.resolve(result); - mPromiseResolved = true; - } - } - - @Override - public void onClick(DialogInterface dialog, int which) { - if (!mPromiseResolved && getReactApplicationContext().hasActiveReactInstance()) { - WritableMap result = new WritableNativeMap(); - result.putString("action", RNConstants.ACTION_NEUTRAL_BUTTON); - mPromise.resolve(result); - mPromiseResolved = true; - } - } - } - - @ReactMethod - public void dismiss(Promise promise) { - FragmentActivity activity = (FragmentActivity) getCurrentActivity(); - dismissDialog(activity, NAME, promise); - } - /** - * Show a date picker dialog. - * - * @param options a map containing options. Available keys are: - * - * - * - * @param promise This will be invoked with parameters action, year, - * month (0-11), day, where action is {@code dateSetAction} or - * {@code dismissedAction}, depending on what the user did. If the action is - * dismiss, year, month and date are undefined. - */ - @ReactMethod - public void open(final ReadableMap options, final Promise promise) { - FragmentActivity activity = (FragmentActivity) getCurrentActivity(); - if (activity == null) { - promise.reject( - RNConstants.ERROR_NO_ACTIVITY, - "Tried to open a DatePicker dialog while not attached to an Activity"); - return; - } - - final FragmentManager fragmentManager = activity.getSupportFragmentManager(); - - UiThreadUtil.runOnUiThread(() -> { - RNDatePickerDialogFragment oldFragment = - (RNDatePickerDialogFragment) fragmentManager.findFragmentByTag(NAME); - - Bundle arguments = createFragmentArguments(options); - - if (oldFragment != null) { - oldFragment.update(arguments); - return; - } - - RNDatePickerDialogFragment fragment = new RNDatePickerDialogFragment(); - - fragment.setArguments(arguments); - - final DatePickerDialogListener listener = new DatePickerDialogListener(promise, arguments); - fragment.setOnDismissListener(listener); - fragment.setOnDateSetListener(listener); - fragment.setOnNeutralButtonActionListener(listener); - fragment.show(fragmentManager, NAME); - }); - } - - private Bundle createFragmentArguments(ReadableMap options) { - final Bundle args = Common.createFragmentArguments(options); - - if (options.hasKey(RNConstants.ARG_MINDATE) && !options.isNull(RNConstants.ARG_MINDATE)) { - args.putLong(RNConstants.ARG_MINDATE, (long) options.getDouble(RNConstants.ARG_MINDATE)); - } - if (options.hasKey(RNConstants.ARG_MAXDATE) && !options.isNull(RNConstants.ARG_MAXDATE)) { - args.putLong(RNConstants.ARG_MAXDATE, (long) options.getDouble(RNConstants.ARG_MAXDATE)); - } - if (options.hasKey(RNConstants.ARG_DISPLAY) && !options.isNull(RNConstants.ARG_DISPLAY)) { - args.putString(RNConstants.ARG_DISPLAY, options.getString(RNConstants.ARG_DISPLAY)); - } - if (options.hasKey(RNConstants.ARG_DIALOG_BUTTONS) && !options.isNull(RNConstants.ARG_DIALOG_BUTTONS)) { - args.putBundle(RNConstants.ARG_DIALOG_BUTTONS, Arguments.toBundle(options.getMap(RNConstants.ARG_DIALOG_BUTTONS))); - } - if (options.hasKey(RNConstants.ARG_TZOFFSET_MINS) && !options.isNull(RNConstants.ARG_TZOFFSET_MINS)) { - args.putLong(RNConstants.ARG_TZOFFSET_MINS, (long) options.getDouble(RNConstants.ARG_TZOFFSET_MINS)); - } - if (options.hasKey(RNConstants.ARG_TESTID) && !options.isNull(RNConstants.ARG_TESTID)) { - args.putString(RNConstants.ARG_TESTID, options.getString(RNConstants.ARG_TESTID)); - } - return args; - } -} + package com.reactcommunity.rndatetimepicker; + + import android.app.DatePickerDialog.OnDateSetListener; + import android.content.DialogInterface; + import android.content.DialogInterface.OnDismissListener; + import android.content.DialogInterface.OnClickListener; + import android.os.Bundle; + import android.widget.DatePicker; + import androidx.annotation.NonNull; + import androidx.fragment.app.FragmentActivity; + import androidx.fragment.app.FragmentManager; + + import com.facebook.react.bridge.*; + import com.facebook.react.common.annotations.VisibleForTesting; + import com.facebook.react.module.annotations.ReactModule; + + import static com.reactcommunity.rndatetimepicker.Common.dismissDialog; + + import java.util.Calendar; + + /** + * {@link NativeModule} that allows JS to show a native date picker dialog and get called back when + * the user selects a date. + */ + @ReactModule(name = DatePickerModule.NAME) + public class DatePickerModule extends NativeModuleDatePickerSpec { + + @VisibleForTesting + public static final String NAME = "RNCDatePicker"; + + public DatePickerModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @NonNull + @Override + public String getName() { + return NAME; + } + + private class DatePickerDialogListener implements OnDateSetListener, OnDismissListener, OnClickListener { + + private final Promise mPromise; + private final Bundle mArgs; + private boolean mPromiseResolved = false; + + public DatePickerDialogListener(final Promise promise, Bundle arguments) { + mPromise = promise; + mArgs = arguments; + } + + @Override + public void onDateSet(DatePicker view, int year, int month, int day) { + if (!mPromiseResolved && getReactApplicationContext().hasActiveReactInstance()) { + final RNDate date = new RNDate(mArgs); + Calendar calendar = Calendar.getInstance(Common.getTimeZone(mArgs)); + calendar.set(year, month, day, date.hour(), date.minute(), 0); + calendar.set(Calendar.MILLISECOND, 0); + + WritableMap result = new WritableNativeMap(); + result.putString("action", RNConstants.ACTION_DATE_SET); + result.putDouble("timestamp", calendar.getTimeInMillis()); + result.putDouble("utcOffset", calendar.getTimeZone().getOffset(calendar.getTimeInMillis()) / 1000 / 60); + + mPromise.resolve(result); + mPromiseResolved = true; + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + if (!mPromiseResolved && getReactApplicationContext().hasActiveReactInstance()) { + WritableMap result = new WritableNativeMap(); + result.putString("action", RNConstants.ACTION_DISMISSED); + mPromise.resolve(result); + mPromiseResolved = true; + } + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (!mPromiseResolved && getReactApplicationContext().hasActiveReactInstance()) { + WritableMap result = new WritableNativeMap(); + result.putString("action", RNConstants.ACTION_NEUTRAL_BUTTON); + mPromise.resolve(result); + mPromiseResolved = true; + } + } + } + + @ReactMethod + public void dismiss(Promise promise) { + FragmentActivity activity = (FragmentActivity) getCurrentActivity(); + dismissDialog(activity, NAME, promise); + } + /** + * Show a date picker dialog. + * + * @param options a map containing options. Available keys are: + * + * + * + * @param promise This will be invoked with parameters action, year, + * month (0-11), day, where action is {@code dateSetAction} or + * {@code dismissedAction}, depending on what the user did. If the action is + * dismiss, year, month and date are undefined. + */ + @ReactMethod + public void open(final ReadableMap options, final Promise promise) { + FragmentActivity activity = (FragmentActivity) getCurrentActivity(); + if (activity == null) { + promise.reject( + RNConstants.ERROR_NO_ACTIVITY, + "Tried to open a DatePicker dialog while not attached to an Activity"); + return; + } + + final FragmentManager fragmentManager = activity.getSupportFragmentManager(); + + UiThreadUtil.runOnUiThread(() -> { + RNDatePickerDialogFragment oldFragment = + (RNDatePickerDialogFragment) fragmentManager.findFragmentByTag(NAME); + + Bundle arguments = createFragmentArguments(options); + + if (oldFragment != null) { + oldFragment.update(arguments); + return; + } + + RNDatePickerDialogFragment fragment = new RNDatePickerDialogFragment(); + + fragment.setArguments(arguments); + + final DatePickerDialogListener listener = new DatePickerDialogListener(promise, arguments); + fragment.setOnDismissListener(listener); + fragment.setOnDateSetListener(listener); + fragment.setOnNeutralButtonActionListener(listener); + fragment.show(fragmentManager, NAME); + }); + } + + private Bundle createFragmentArguments(ReadableMap options) { + final Bundle args = Common.createFragmentArguments(options); + + if (options.hasKey(RNConstants.ARG_MINDATE) && !options.isNull(RNConstants.ARG_MINDATE)) { + args.putLong(RNConstants.ARG_MINDATE, (long) options.getDouble(RNConstants.ARG_MINDATE)); + } + if (options.hasKey(RNConstants.ARG_MAXDATE) && !options.isNull(RNConstants.ARG_MAXDATE)) { + args.putLong(RNConstants.ARG_MAXDATE, (long) options.getDouble(RNConstants.ARG_MAXDATE)); + } + if (options.hasKey(RNConstants.ARG_DISPLAY) && !options.isNull(RNConstants.ARG_DISPLAY)) { + args.putString(RNConstants.ARG_DISPLAY, options.getString(RNConstants.ARG_DISPLAY)); + } + if (options.hasKey(RNConstants.ARG_DIALOG_BUTTONS) && !options.isNull(RNConstants.ARG_DIALOG_BUTTONS)) { + args.putBundle(RNConstants.ARG_DIALOG_BUTTONS, Arguments.toBundle(options.getMap(RNConstants.ARG_DIALOG_BUTTONS))); + } + if (options.hasKey(RNConstants.ARG_TZOFFSET_MINS) && !options.isNull(RNConstants.ARG_TZOFFSET_MINS)) { + args.putLong(RNConstants.ARG_TZOFFSET_MINS, (long) options.getDouble(RNConstants.ARG_TZOFFSET_MINS)); + } + if (options.hasKey(RNConstants.ARG_TESTID) && !options.isNull(RNConstants.ARG_TESTID)) { + args.putString(RNConstants.ARG_TESTID, options.getString(RNConstants.ARG_TESTID)); + } + if (options.hasKey(RNConstants.FIRST_DAY_OF_WEEK) && !options.isNull(RNConstants.FIRST_DAY_OF_WEEK)) { + // FIRST_DAY_OF_WEEK is 0-indexed, since it uses the same constants DAY_OF_WEEK used in the Windows implementation + // Android DatePicker uses 1-indexed values, SUNDAY being 1 and SATURDAY being 7, so the +1 is necessary in this case + args.putInt(RNConstants.FIRST_DAY_OF_WEEK, options.getInt(RNConstants.FIRST_DAY_OF_WEEK)+1); + } + return args; + } + } + \ No newline at end of file diff --git a/android/src/main/java/com/reactcommunity/rndatetimepicker/RNConstants.java b/android/src/main/java/com/reactcommunity/rndatetimepicker/RNConstants.java index 99530d51..acb56cb9 100644 --- a/android/src/main/java/com/reactcommunity/rndatetimepicker/RNConstants.java +++ b/android/src/main/java/com/reactcommunity/rndatetimepicker/RNConstants.java @@ -18,6 +18,7 @@ public final class RNConstants { public static final String ACTION_TIME_SET = "timeSetAction"; public static final String ACTION_DISMISSED = "dismissedAction"; public static final String ACTION_NEUTRAL_BUTTON = "neutralButtonAction"; + public static final String FIRST_DAY_OF_WEEK = "firstDayOfWeek"; /** * Minimum date supported by {@link TimePickerDialog}, 01 Jan 1900 diff --git a/android/src/main/java/com/reactcommunity/rndatetimepicker/RNDatePickerDialogFragment.java b/android/src/main/java/com/reactcommunity/rndatetimepicker/RNDatePickerDialogFragment.java index 72de7cbb..c35ff32a 100644 --- a/android/src/main/java/com/reactcommunity/rndatetimepicker/RNDatePickerDialogFragment.java +++ b/android/src/main/java/com/reactcommunity/rndatetimepicker/RNDatePickerDialogFragment.java @@ -5,157 +5,160 @@ * LICENSE file in the root directory of this source tree. */ -package com.reactcommunity.rndatetimepicker; - -import static com.reactcommunity.rndatetimepicker.Common.getDisplayDate; -import static com.reactcommunity.rndatetimepicker.Common.setButtonTextColor; -import static com.reactcommunity.rndatetimepicker.Common.setButtonTitles; - -import android.annotation.SuppressLint; -import android.app.DatePickerDialog; -import android.app.DatePickerDialog.OnDateSetListener; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnDismissListener; -import android.content.DialogInterface.OnClickListener; -import android.os.Build; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; - -import android.widget.DatePicker; - -import java.util.Calendar; -import java.util.Locale; - -@SuppressLint("ValidFragment") -public class RNDatePickerDialogFragment extends DialogFragment { - private DatePickerDialog instance; - - @Nullable - private OnDateSetListener mOnDateSetListener; - @Nullable - private OnDismissListener mOnDismissListener; - @Nullable - private OnClickListener mOnNeutralButtonActionListener; - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - Bundle args = getArguments(); - instance = createDialog(args); - return instance; - } - - public void update(Bundle args) { - final RNDate date = new RNDate(args); - instance.updateDate(date.year(), date.month(), date.day()); - } - - static @NonNull - DatePickerDialog getDialog( - Bundle args, - Context activityContext, - @Nullable OnDateSetListener onDateSetListener) { - final RNDate date = new RNDate(args); - final int year = date.year(); - final int month = date.month(); - final int day = date.day(); - - RNDatePickerDisplay display = getDisplayDate(args); - - if (args != null && args.getString(RNConstants.ARG_DISPLAY, null) != null) { - display = RNDatePickerDisplay.valueOf(args.getString(RNConstants.ARG_DISPLAY).toUpperCase(Locale.US)); - } - - if (display == RNDatePickerDisplay.SPINNER) { - return new RNDismissableDatePickerDialog( - activityContext, - R.style.SpinnerDatePickerDialog, - onDateSetListener, - year, - month, - day, - display - ); - } - return new RNDismissableDatePickerDialog( - activityContext, - onDateSetListener, - year, - month, - day, - display - ); - } - - private DatePickerDialog createDialog(Bundle args) { - Context activityContext = getActivity(); - DatePickerDialog dialog = getDialog(args, activityContext, mOnDateSetListener); - - if (args != null) { - setButtonTitles(args, dialog, mOnNeutralButtonActionListener); - if (activityContext != null) { - RNDatePickerDisplay display = getDisplayDate(args); - boolean needsColorOverride = display == RNDatePickerDisplay.SPINNER; - dialog.setOnShowListener(setButtonTextColor(activityContext, dialog, args, needsColorOverride)); - } - } - - final DatePicker datePicker = dialog.getDatePicker(); - final long minDate = Common.minDateWithTimeZone(args); - final long maxDate = Common.maxDateWithTimeZone(args); - - if (args.containsKey(RNConstants.ARG_MINDATE)) { - datePicker.setMinDate(minDate); - } else { - // This is to work around a bug in DatePickerDialog where it doesn't display a title showing - // the date under certain conditions. - datePicker.setMinDate(RNConstants.DEFAULT_MIN_DATE); - } - if (args.containsKey(RNConstants.ARG_MAXDATE)) { - datePicker.setMaxDate(maxDate); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && (args.containsKey(RNConstants.ARG_MAXDATE) || args.containsKey(RNConstants.ARG_MINDATE))) { - datePicker.setOnDateChangedListener((view, year, monthOfYear, dayOfMonth) -> { - Calendar calendar = Calendar.getInstance(Common.getTimeZone(args)); - calendar.set(year, monthOfYear, dayOfMonth, 0, 0, 0); - long timestamp = Math.min(Math.max(calendar.getTimeInMillis(), minDate), maxDate); - calendar.setTimeInMillis(timestamp); - if (datePicker.getYear() != calendar.get(Calendar.YEAR) || datePicker.getMonth() != calendar.get(Calendar.MONTH) || datePicker.getDayOfMonth() != calendar.get(Calendar.DAY_OF_MONTH)) { - datePicker.updateDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); - } - }); - } - - if (args.containsKey(RNConstants.ARG_TESTID)) { - datePicker.setTag(args.getString(RNConstants.ARG_TESTID)); - } - - return dialog; - } - - @Override - public void onDismiss(@NonNull DialogInterface dialog) { - super.onDismiss(dialog); - if (mOnDismissListener != null) { - mOnDismissListener.onDismiss(dialog); - } - } - - /*package*/ void setOnDateSetListener(@Nullable OnDateSetListener onDateSetListener) { - mOnDateSetListener = onDateSetListener; - } - - /*package*/ void setOnDismissListener(@Nullable OnDismissListener onDismissListener) { - mOnDismissListener = onDismissListener; - } - - /*package*/ void setOnNeutralButtonActionListener(@Nullable OnClickListener onNeutralButtonActionListener) { - mOnNeutralButtonActionListener = onNeutralButtonActionListener; - } -} + package com.reactcommunity.rndatetimepicker; + + import static com.reactcommunity.rndatetimepicker.Common.getDisplayDate; + import static com.reactcommunity.rndatetimepicker.Common.setButtonTextColor; + import static com.reactcommunity.rndatetimepicker.Common.setButtonTitles; + + import android.annotation.SuppressLint; + import android.app.DatePickerDialog; + import android.app.DatePickerDialog.OnDateSetListener; + import android.app.Dialog; + import android.content.Context; + import android.content.DialogInterface; + import android.content.DialogInterface.OnDismissListener; + import android.content.DialogInterface.OnClickListener; + import android.os.Build; + import android.os.Bundle; + + import androidx.annotation.NonNull; + import androidx.annotation.Nullable; + import androidx.fragment.app.DialogFragment; + + import android.widget.DatePicker; + + import java.util.Calendar; + import java.util.Locale; + + @SuppressLint("ValidFragment") + public class RNDatePickerDialogFragment extends DialogFragment { + private DatePickerDialog instance; + + @Nullable + private OnDateSetListener mOnDateSetListener; + @Nullable + private OnDismissListener mOnDismissListener; + @Nullable + private OnClickListener mOnNeutralButtonActionListener; + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Bundle args = getArguments(); + instance = createDialog(args); + return instance; + } + + public void update(Bundle args) { + final RNDate date = new RNDate(args); + instance.updateDate(date.year(), date.month(), date.day()); + } + + static @NonNull + DatePickerDialog getDialog( + Bundle args, + Context activityContext, + @Nullable OnDateSetListener onDateSetListener) { + final RNDate date = new RNDate(args); + final int year = date.year(); + final int month = date.month(); + final int day = date.day(); + + RNDatePickerDisplay display = getDisplayDate(args); + + if (args != null && args.getString(RNConstants.ARG_DISPLAY, null) != null) { + display = RNDatePickerDisplay.valueOf(args.getString(RNConstants.ARG_DISPLAY).toUpperCase(Locale.US)); + } + + if (display == RNDatePickerDisplay.SPINNER) { + return new RNDismissableDatePickerDialog( + activityContext, + R.style.SpinnerDatePickerDialog, + onDateSetListener, + year, + month, + day, + display + ); + } + return new RNDismissableDatePickerDialog( + activityContext, + onDateSetListener, + year, + month, + day, + display + ); + } + + private DatePickerDialog createDialog(Bundle args) { + Context activityContext = getActivity(); + DatePickerDialog dialog = getDialog(args, activityContext, mOnDateSetListener); + + if (args != null) { + setButtonTitles(args, dialog, mOnNeutralButtonActionListener); + if (activityContext != null) { + RNDatePickerDisplay display = getDisplayDate(args); + boolean needsColorOverride = display == RNDatePickerDisplay.SPINNER; + dialog.setOnShowListener(setButtonTextColor(activityContext, dialog, args, needsColorOverride)); + } + } + + final DatePicker datePicker = dialog.getDatePicker(); + final long minDate = Common.minDateWithTimeZone(args); + final long maxDate = Common.maxDateWithTimeZone(args); + + if (args.containsKey(RNConstants.ARG_MINDATE)) { + datePicker.setMinDate(minDate); + } else { + // This is to work around a bug in DatePickerDialog where it doesn't display a title showing + // the date under certain conditions. + datePicker.setMinDate(RNConstants.DEFAULT_MIN_DATE); + } + + if (args.containsKey(RNConstants.FIRST_DAY_OF_WEEK)) { + final int firstDayOfWeek = args.getInt(RNConstants.FIRST_DAY_OF_WEEK); + datePicker.setFirstDayOfWeek(firstDayOfWeek); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && (args.containsKey(RNConstants.ARG_MAXDATE) || args.containsKey(RNConstants.ARG_MINDATE))) { + datePicker.setOnDateChangedListener((view, year, monthOfYear, dayOfMonth) -> { + Calendar calendar = Calendar.getInstance(Common.getTimeZone(args)); + calendar.set(year, monthOfYear, dayOfMonth, 0, 0, 0); + long timestamp = Math.min(Math.max(calendar.getTimeInMillis(), minDate), maxDate); + calendar.setTimeInMillis(timestamp); + if (datePicker.getYear() != calendar.get(Calendar.YEAR) || datePicker.getMonth() != calendar.get(Calendar.MONTH) || datePicker.getDayOfMonth() != calendar.get(Calendar.DAY_OF_MONTH)) { + datePicker.updateDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); + } + }); + } + + if (args.containsKey(RNConstants.ARG_TESTID)) { + datePicker.setTag(args.getString(RNConstants.ARG_TESTID)); + } + + return dialog; + } + + @Override + public void onDismiss(@NonNull DialogInterface dialog) { + super.onDismiss(dialog); + if (mOnDismissListener != null) { + mOnDismissListener.onDismiss(dialog); + } + } + + /*package*/ void setOnDateSetListener(@Nullable OnDateSetListener onDateSetListener) { + mOnDateSetListener = onDateSetListener; + } + + /*package*/ void setOnDismissListener(@Nullable OnDismissListener onDismissListener) { + mOnDismissListener = onDismissListener; + } + + /*package*/ void setOnNeutralButtonActionListener(@Nullable OnClickListener onNeutralButtonActionListener) { + mOnNeutralButtonActionListener = onNeutralButtonActionListener; + } + } + \ No newline at end of file diff --git a/example/App.js b/example/App.js index 2190714c..bfbfdf4c 100644 --- a/example/App.js +++ b/example/App.js @@ -253,6 +253,13 @@ export const App = () => { /> )} + DAY_OF_WEEK[key] === firstDayOfWeek, + )}`} + /> { testID="neutralButtonLabelTextInput" /> + + + + firstDayOfWeek (android only) + + +