From 5c4d135a8391ffb2000f94905ffb475dad6674c8 Mon Sep 17 00:00:00 2001 From: Chee Kit Date: Mon, 3 Oct 2022 11:18:11 +0800 Subject: [PATCH] feat(labels): support positive and negative button texts --- README.md | 32 +++++++++-------- .../RNMaterialDatePickerModule.kt | 6 +++- .../RNMaterialTimePickerModule.kt | 2 ++ .../model/MDPArguments.kt | 4 ++- .../util/MDPConstants.kt | 8 +++-- .../util/MDPExtensions.kt | 14 ++++++-- example/src/App.tsx | 34 ++++++++++++------- src/datepicker.android.ts | 6 ++-- src/datepicker.ts | 2 +- src/datetimepicker.android.ts | 2 +- src/index.tsx | 28 --------------- src/picker.ts | 8 ++--- src/timepicker.android.ts | 2 +- src/timepicker.ts | 2 +- src/types.ts | 18 +++++----- .../MaterialDateTimePickerAndroid.android.ts | 19 ++++++----- src/utils/MaterialDateTimePickerAndroid.ts | 4 +-- 17 files changed, 98 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 2d2f1f7..45c562f 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ export const App = () => { const showTimePicker = () => { MaterialDatetimePickerAndroid.show({ value: time, - title: 'Select flight time', + titleText: 'Select flight time', mode: AndroidPickerMode.TIME, is24Hours: true, inputMode: AndroidTimeInputMode.CLOCK, @@ -104,10 +104,10 @@ export const App = () => { const showTimePicker = () => { MaterialDatetimePickerAndroid.show({ value: date, - title: 'Select booking date', + titleText: 'Select booking date', mode: AndroidPickerMode.DATE, - minDate: subWeeks(today, 3), - maxDate: addWeeks(today, 4), + minimumDate: subWeeks(today, 3), + maximumDate: addWeeks(today, 4), inputMode: AndroidDateInputMode.CALENDAR, type: AndroidDatePickerType.DEFAULT, onChange: (date) => { @@ -143,8 +143,8 @@ export const App = () => { { setCurrentDate(date); setIsVisible(false); @@ -160,20 +160,22 @@ export const App = () => { #### Common Options -| Name | Type | Default | Required | Description | -| ---------- | -------------------------- | ------------------------ | -------- | ---------------------------------------------------------------------- | -| `mode` | `AndroidPickerMode` | `AndroidPickerMode.DATE` | ❌ | The mode of picker to show | -| `value` | `Date` | | ✅ | The current value of the picker | -| `title` | `string` | | ❌ | The title to be shown on the top left | -| `onChange` | `(date: Date) => string` | | ❌ | The callback invoked when a new date or time is selected | -| `onError` | `(error: unknown) => void` | | ❌ | The callback invoked when an error occured while selecting a new value | +| Name | Type | Default | Required | Description | +| -------------------- | -------------------------- | ------------------------ | -------- | ---------------------------------------------------------------------- | +| `mode` | `AndroidPickerMode` | `AndroidPickerMode.DATE` | ❌ | The mode of picker to show | +| `value` | `Date` | | ✅ | The current value of the picker | +| `titleText` | `string` | | ❌ | The title to be shown on the top left | +| `positiveButtonText` | `string` | | ❌ | The text used in the positive action button | +| `negativeButtonText` | `string` | | ❌ | The text used in the negative action button | +| `onChange` | `(date: Date) => string` | | ❌ | The callback invoked when a new date or time is selected | +| `onError` | `(error: unknown) => void` | | ❌ | The callback invoked when an error occured while selecting a new value | #### Date Picker Options | Name | Type | Default | Required | Description | | ------------------- | ------------------------------------------ | ------- | -------- | -------------------------------------------------- | -| `minDate` | `Date` | | ❌ | The minimum date allowed to be selected | -| `maxDate` | `Date` | | ❌ | The maximum date allowed to be selected | +| `minimumDate` | `Date` | | ❌ | The minimum date allowed to be selected | +| `maximumDate` | `Date` | | ❌ | The maximum date allowed to be selected | | `startDate` | `Date` | | ❌ | The start date when using a date range picker | | `endDate` | `Date` | | ❌ | The end date when using a date range picker | | `inputMode` | `AndroidDateInputMode` | | ❌ | The input mode to launch the date picker in | diff --git a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/RNMaterialDatePickerModule.kt b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/RNMaterialDatePickerModule.kt index f4ec894..e145128 100644 --- a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/RNMaterialDatePickerModule.kt +++ b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/RNMaterialDatePickerModule.kt @@ -32,10 +32,10 @@ import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstan import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_START_MONTH import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_START_YEAR import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_YEAR -import com.thespacemanatee.react_native_material_datetime_picker.util.fixDate import com.thespacemanatee.react_native_material_datetime_picker.util.createCalendarConstraints import com.thespacemanatee.react_native_material_datetime_picker.util.createDialogArguments import com.thespacemanatee.react_native_material_datetime_picker.util.dismissDialog +import com.thespacemanatee.react_native_material_datetime_picker.util.fixDate class RNMaterialDatePickerModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), BaseRNMaterialPicker { @@ -137,6 +137,8 @@ class RNMaterialDatePickerModule(reactContext: ReactApplicationContext) : .setSelection(Pair(startDate.timeInMillis, endDate.timeInMillis)) .setCalendarConstraints(args.createCalendarConstraints()) .setTitleText(args.title) + .setPositiveButtonText(args.positiveButtonText) + .setNegativeButtonText(args.negativeButtonText) .setInputMode(inputMode) .build() .apply { @@ -149,6 +151,8 @@ class RNMaterialDatePickerModule(reactContext: ReactApplicationContext) : .setSelection(date.timeInMillis) .setCalendarConstraints(args.createCalendarConstraints()) .setTitleText(args.title) + .setPositiveButtonText(args.positiveButtonText) + .setNegativeButtonText(args.negativeButtonText) .setInputMode(inputMode) .build() .apply { diff --git a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/RNMaterialTimePickerModule.kt b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/RNMaterialTimePickerModule.kt index 92f0c74..a28af47 100644 --- a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/RNMaterialTimePickerModule.kt +++ b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/RNMaterialTimePickerModule.kt @@ -106,6 +106,8 @@ class RNMaterialTimePickerModule(reactContext: ReactApplicationContext) : .setHour(date.hour) .setMinute(date.minute) .setTitleText(args.title) + .setPositiveButtonText(args.positiveButtonText) + .setNegativeButtonText(args.negativeButtonText) .setInputMode(inputMode) .build().apply { addOnPositiveButtonClickListener(OnPositiveButtonClickListener(this, promise)) diff --git a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/model/MDPArguments.kt b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/model/MDPArguments.kt index df93e2b..98751d7 100644 --- a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/model/MDPArguments.kt +++ b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/model/MDPArguments.kt @@ -3,12 +3,14 @@ package com.thespacemanatee.react_native_material_datetime_picker.model data class MDPArguments( var value: Long? = null, + var title: String? = null, var minDate: Long? = null, var maxDate: Long? = null, var startDate: Long? = null, var endDate: Long? = null, - var title: String? = null, var is24Hour: Boolean? = null, + var positiveButtonText: String? = null, + var negativeButtonText: String? = null, var inputMode: String? = null, var type: String? = null ) diff --git a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/util/MDPConstants.kt b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/util/MDPConstants.kt index a238665..5527157 100644 --- a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/util/MDPConstants.kt +++ b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/util/MDPConstants.kt @@ -5,12 +5,14 @@ object MDPConstants { // arguments const val KEY_VALUE = "value" - const val KEY_TITLE = "title" - const val KEY_MIN_DATE = "minDate" - const val KEY_MAX_DATE = "maxDate" + const val KEY_TITLE_TEXT = "titleText" + const val KEY_MIN_DATE = "minimumDate" + const val KEY_MAX_DATE = "maximumDate" const val KEY_START_DATE = "startDate" const val KEY_END_DATE = "endDate" const val KEY_IS_24_HOUR = "is24Hour" + const val KEY_POS_BUTTON_TEXT = "positiveButtonText" + const val KEY_NEG_BUTTON_TEXT = "negativeButtonText" const val KEY_INPUT_MODE = "inputMode" const val KEY_TYPE = "type" diff --git a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/util/MDPExtensions.kt b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/util/MDPExtensions.kt index a6c2fc6..a0a4fee 100644 --- a/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/util/MDPExtensions.kt +++ b/android/src/main/java/com/thespacemanatee/react_native_material_datetime_picker/util/MDPExtensions.kt @@ -15,8 +15,10 @@ import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstan import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_IS_24_HOUR import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_MAX_DATE import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_MIN_DATE +import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_NEG_BUTTON_TEXT +import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_POS_BUTTON_TEXT import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_START_DATE -import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_TITLE +import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_TITLE_TEXT import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_TYPE import com.thespacemanatee.react_native_material_datetime_picker.util.MDPConstants.KEY_VALUE @@ -24,8 +26,8 @@ fun ReadableMap.createDialogArguments() = MDPArguments().apply { if (hasKey(KEY_VALUE) && !isNull(KEY_VALUE)) { value = getDouble(KEY_VALUE).toLong() } - if (hasKey(KEY_TITLE) && !isNull(KEY_TITLE)) { - title = getString(KEY_TITLE) + if (hasKey(KEY_TITLE_TEXT) && !isNull(KEY_TITLE_TEXT)) { + title = getString(KEY_TITLE_TEXT) } if (hasKey(KEY_MIN_DATE) && !isNull(KEY_MIN_DATE)) { minDate = getDouble(KEY_MIN_DATE).toLong() @@ -42,6 +44,12 @@ fun ReadableMap.createDialogArguments() = MDPArguments().apply { if (hasKey(KEY_IS_24_HOUR) && !isNull(KEY_IS_24_HOUR)) { is24Hour = getBoolean(KEY_IS_24_HOUR) } + if (hasKey(KEY_POS_BUTTON_TEXT) && !isNull(KEY_POS_BUTTON_TEXT)) { + positiveButtonText = getString(KEY_POS_BUTTON_TEXT) + } + if (hasKey(KEY_NEG_BUTTON_TEXT) && !isNull(KEY_NEG_BUTTON_TEXT)) { + negativeButtonText = getString(KEY_NEG_BUTTON_TEXT) + } if (hasKey(KEY_INPUT_MODE) && !isNull(KEY_INPUT_MODE)) { inputMode = getString(KEY_INPUT_MODE) } diff --git a/example/src/App.tsx b/example/src/App.tsx index 2631c29..b295e72 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -24,11 +24,13 @@ const App: FunctionComponent = () => { const handleShowTimePicker = () => { MaterialDatetimePickerAndroid.show({ value: currentTime, - title: 'Select flight time', + titleText: 'Select flight time', mode: AndroidPickerMode.TIME, is24Hour: true, + positiveButtonText: 'Sounds good!', + negativeButtonText: 'Maybe not', inputMode: AndroidTimeInputMode.CLOCK, - onChange: (date) => { + onConfirm: (date) => { setCurrentTime(date); }, }); @@ -37,13 +39,15 @@ const App: FunctionComponent = () => { const handleShowDatePicker = () => { MaterialDatetimePickerAndroid.show({ value: currentDate, - title: 'Select booking date', + titleText: 'Select booking date', mode: AndroidPickerMode.DATE, - minDate: subWeeks(today, 3), - maxDate: addWeeks(today, 4), + minimumDate: subWeeks(today, 3), + maximumDate: addWeeks(today, 4), + positiveButtonText: 'Sounds good!', + negativeButtonText: 'Maybe not', inputMode: AndroidDateInputMode.CALENDAR, type: AndroidDatePickerType.DEFAULT, - onChange: (date) => { + onConfirm: (date) => { setCurrentDate(date); }, }); @@ -52,15 +56,17 @@ const App: FunctionComponent = () => { const handleShowDateRangePicker = () => { MaterialDatetimePickerAndroid.show({ value: currentDate, - title: 'Select duration of trip', + titleText: 'Select duration of trip', mode: AndroidPickerMode.DATE, - minDate: subDays(currentDate, 1), - maxDate: addWeeks(today, 4), + minimumDate: subDays(currentDate, 1), + maximumDate: addWeeks(today, 4), startDate: currentStartDate, endDate: currentEndDate, + positiveButtonText: 'Sounds good!', + negativeButtonText: 'Maybe not', inputMode: AndroidDateInputMode.CALENDAR, type: AndroidDatePickerType.RANGE, - onDateRangeChange: (startDate, endDate) => { + onConfirmDateRange: (startDate, endDate) => { setCurrentStartDate(startDate); setCurrentEndDate(endDate); }, @@ -73,9 +79,11 @@ const App: FunctionComponent = () => { { + minimumDate={subWeeks(today, 3)} + maximumDate={addWeeks(today, 4)} + positiveButtonText="Sounds good!" + negativeButtonText="Maybe not" + onConfirm={(date) => { setCurrentDate(date); setIsVisible(false); }} diff --git a/src/datepicker.android.ts b/src/datepicker.android.ts index cc64467..28f4179 100644 --- a/src/datepicker.android.ts +++ b/src/datepicker.android.ts @@ -14,7 +14,7 @@ const RNMaterialDatePicker = NativeModules.RNMaterialTimePicker } ); -export default class DatePickerAndroid { +export default class DatePicker { /** * Shows the Android Material Design time picker dialog. */ @@ -22,8 +22,8 @@ export default class DatePickerAndroid { return RNMaterialDatePicker.show({ ...options, value: options.value.getTime(), - minDate: options.minDate?.getTime(), - maxDate: options.maxDate?.getTime(), + minimumDate: options.minimumDate?.getTime(), + maximumDate: options.maximumDate?.getTime(), startDate: options.startDate?.getTime(), endDate: options.endDate?.getTime(), }); diff --git a/src/datepicker.ts b/src/datepicker.ts index a87b004..1698783 100644 --- a/src/datepicker.ts +++ b/src/datepicker.ts @@ -2,7 +2,7 @@ import { Platform } from 'react-native'; import type { DateTimePickerResult, DatePickerOptions } from './types'; -export default class DatePickerAndroid { +export default class DatePicker { static async show(options: DatePickerOptions): Promise { options; throw new Error(`DatePicker is not supported on: ${Platform.OS}`); diff --git a/src/datetimepicker.android.ts b/src/datetimepicker.android.ts index 9618113..885a35c 100644 --- a/src/datetimepicker.android.ts +++ b/src/datetimepicker.android.ts @@ -8,7 +8,7 @@ const RNMaterialDatetimePicker = (props: AndroidPickerProps) => { useEffect(() => { return () => { - MaterialDatetimePickerAndroid.dismiss(mode); + MaterialDatetimePickerAndroid.dismiss(); }; }, [mode]); diff --git a/src/index.tsx b/src/index.tsx index a54bef7..1b3b7f4 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,31 +8,3 @@ export { } from './types'; export default RNMaterialDatetimePicker; -// import { NativeModules, Platform } from 'react-native'; - -// const LINKING_ERROR = -// `The package 'react-native-material-datetime-picker' doesn't seem to be linked. Make sure: \n\n` + -// Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) + -// '- You rebuilt the app after installing the package\n' + -// '- You are not using Expo managed workflow\n'; - -// const RNMaterialTimePicker = NativeModules.RNMaterialTimePicker -// ? NativeModules.RNMaterialTimePicker -// : new Proxy( -// {}, -// { -// get() { -// throw new Error(LINKING_ERROR); -// }, -// } -// ); - -// export function show(options: { -// value: Date; -// minDate: Date; -// maxDate: Date; -// is24Hour: boolean; -// inputMode: 'clock' | 'keyboard'; -// }): Promise { -// return RNMaterialTimePicker.show(options); -// } diff --git a/src/picker.ts b/src/picker.ts index bdbe4f7..428fd2b 100644 --- a/src/picker.ts +++ b/src/picker.ts @@ -1,10 +1,10 @@ -import DatePickerAndroid from './datepicker'; -import TimePickerAndroid from './timepicker'; +import DatePicker from './datepicker'; +import TimePicker from './timepicker'; import { AndroidPickerMode } from './types'; const pickers = { - [AndroidPickerMode.DATE]: DatePickerAndroid, - [AndroidPickerMode.TIME]: TimePickerAndroid, + [AndroidPickerMode.DATE]: DatePicker, + [AndroidPickerMode.TIME]: TimePicker, }; export default pickers; diff --git a/src/timepicker.android.ts b/src/timepicker.android.ts index bba0a1d..8f9af40 100644 --- a/src/timepicker.android.ts +++ b/src/timepicker.android.ts @@ -14,7 +14,7 @@ const RNMaterialTimePicker = NativeModules.RNMaterialTimePicker } ); -export default class TimePickerAndroid { +export default class TimePicker { /** * Shows the Android Material Design time picker dialog. */ diff --git a/src/timepicker.ts b/src/timepicker.ts index bf930a4..cf1f7da 100644 --- a/src/timepicker.ts +++ b/src/timepicker.ts @@ -2,7 +2,7 @@ import { Platform } from 'react-native'; import type { DateTimePickerResult, TimePickerOptions } from './types'; -export default class TimePickerAndroid { +export default class TimePicker { static async show(options: TimePickerOptions): Promise { options; throw new Error(`DatePicker is not supported on: ${Platform.OS}`); diff --git a/src/types.ts b/src/types.ts index 3c35b97..3b8232f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -32,34 +32,36 @@ export enum ActionType { type BaseProps = Readonly< ViewProps & { value: Date; - title?: string; - onChange?: (date: Date) => void; + titleText?: string; + positiveButtonText?: string; + negativeButtonText?: string; + onConfirm?: (date: Date) => void; onError?: (error: unknown) => void; } >; export interface DatePickerOptions extends BaseProps { mode?: AndroidPickerMode.DATE; - minDate?: Date; - maxDate?: Date; + minimumDate?: Date; + maximumDate?: Date; startDate?: Date; endDate?: Date; is24Hours?: never; inputMode?: AndroidDateInputMode; type?: AndroidDatePickerType; - onDateRangeChange?: (startDate: Date, endDate: Date) => void; + onConfirmDateRange?: (startDate: Date, endDate: Date) => void; } export interface TimePickerOptions extends BaseProps { mode?: AndroidPickerMode.TIME; - minDate?: never; - maxDate?: never; + minimumDate?: never; + maximumDate?: never; startDate?: never; endDate?: never; is24Hour?: boolean; inputMode?: AndroidTimeInputMode; type?: never; - onDateRangeChange?: never; + onConfirmDateRange?: never; } export type AndroidPickerProps = DatePickerOptions | TimePickerOptions; diff --git a/src/utils/MaterialDateTimePickerAndroid.android.ts b/src/utils/MaterialDateTimePickerAndroid.android.ts index 08fdd47..3b129e3 100644 --- a/src/utils/MaterialDateTimePickerAndroid.android.ts +++ b/src/utils/MaterialDateTimePickerAndroid.android.ts @@ -6,8 +6,8 @@ const show = (props: AndroidPickerProps) => { const { mode = AndroidPickerMode.DATE, value, - onChange, - onDateRangeChange, + onConfirm, + onConfirmDateRange, onError, } = props; const picker = getPicker(mode); @@ -32,7 +32,7 @@ const show = (props: AndroidPickerProps) => { case ActionType.SET_DATE: { const date = new Date(value); date.setFullYear(year, month, day); - onChange?.(date); + onConfirm?.(date); break; } case ActionType.SET_DATE_RANGE: { @@ -40,18 +40,18 @@ const show = (props: AndroidPickerProps) => { const endDate = new Date(value); startDate.setFullYear(startYear, startMonth, startDay); endDate.setFullYear(endYear, endMonth, endDay); - onDateRangeChange?.(startDate, endDate); + onConfirmDateRange?.(startDate, endDate); break; } case ActionType.SET_TIME: { const time = new Date(value); time.setHours(hour, minute); - onChange?.(time); + onConfirm?.(time); break; } case ActionType.DISMISSED: default: { - onChange?.(new Date(value)); + onConfirm?.(new Date(value)); } } } catch (err) { @@ -60,8 +60,11 @@ const show = (props: AndroidPickerProps) => { })(); }; -const dismiss = (mode: AndroidPickerMode): Promise => { - return pickers[mode].dismiss(); +const dismiss = (mode?: AndroidPickerMode): Promise => { + if (mode) { + return pickers[mode].dismiss(); + } + return pickers.date.dismiss() || pickers.time.dismiss(); }; export const MaterialDatetimePickerAndroid = { show, dismiss }; diff --git a/src/utils/MaterialDateTimePickerAndroid.ts b/src/utils/MaterialDateTimePickerAndroid.ts index bb4cedf..4e54d88 100644 --- a/src/utils/MaterialDateTimePickerAndroid.ts +++ b/src/utils/MaterialDateTimePickerAndroid.ts @@ -3,12 +3,12 @@ import { Platform } from 'react-native'; import type { AndroidPickerMode, AndroidPickerProps } from '../types'; const warn = () => { - console.warn( + throw new Error( `MaterialDatetimePickerAndroid is not supported on: ${Platform.OS}` ); }; export const MaterialDatetimePickerAndroid: { show: (props: AndroidPickerProps) => void; - dismiss: (mode: AndroidPickerMode) => void; + dismiss: (mode?: AndroidPickerMode) => Promise; } = { show: warn, dismiss: warn };