├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── android ├── .project ├── .settings │ └── org.eclipse.buildship.core.prefs ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── reactlibrary │ ├── DatePickerFragment.java │ ├── RNNavybitsDateTimePickerModule.java │ ├── RNNavybitsDateTimePickerPackage.java │ └── TimePickerFragment.java ├── datePicker.js ├── example.js ├── img ├── NBPicker.gif └── nbPicker_android.gif ├── index.js ├── ios ├── RNNavybitsDateTimePicker.h ├── RNNavybitsDateTimePicker.m ├── RNNavybitsDateTimePicker.podspec ├── RNNavybitsDateTimePicker.xcodeproj │ └── project.pbxproj └── RNNavybitsDateTimePicker.xcworkspace │ └── contents.xcworkspacedata ├── package.json └── styles.js /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | # node.js 7 | # 8 | node_modules/ 9 | npm-debug.log 10 | yarn-error.log 11 | 12 | 13 | # Xcode 14 | # 15 | build/ 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata 25 | *.xccheckout 26 | *.moved-aside 27 | DerivedData 28 | *.hmap 29 | *.ipa 30 | *.xcuserstate 31 | project.xcworkspace 32 | 33 | 34 | # Android/IntelliJ 35 | # 36 | build/ 37 | .idea 38 | .gradle 39 | local.properties 40 | *.iml 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Hanane 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # react-native-navybits-date-time-picker 3 | This project is a modified version of [react-native-datePicker](https://github.com/xgfe/react-native-datepicker). 4 | It solves the need to set a *MinuteInterval* on android using the native picker [`MaterialDateTimePicker`](https://github.com/wdullaer/MaterialDateTimePicker) 5 | 6 | 7 | ## Getting started 8 | 9 | `$ npm install react-native-navybits-date-time-picker --save` 10 | 11 | ### Manual installation 12 | #### iOS 13 | you don't need to do anything 14 | #### Android 15 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java` 16 | - Add `import com.reactlibrary.RNNavybitsDateTimePickerPackage;` to the imports at the top of the file 17 | - Add `new RNNavybitsDateTimePickerPackage()` to the list returned by the `getPackages()` method 18 | 2. Append the following lines to `android/settings.gradle`: 19 | ``` 20 | include ':react-native-navybits-date-time-picker' 21 | project(':react-native-navybits-date-time-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navybits-date-time-picker/android') 22 | ``` 23 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`: 24 | ``` 25 | compile project(':react-native-navybits-date-time-picker') 26 | ``` 27 | 28 | ## Example 29 | Please refer to example.js 30 | ![android!150x300, 20%](https://github.com/Navybits/react-native-navybits-date-time-picker/blob/master/img/nbPicker_android.gif) 31 | ![ios!150x300, 20%](https://github.com/Navybits/react-native-navybits-date-time-picker/blob/master/img/NBPicker.gif) 32 | 33 | 34 | 35 | ## Properties 36 | 37 | | Prop | Default | Type | Description | 38 | | :------------ |:---------------:| :---------------:| :-----| 39 | | style | - | `object` | Specify the style of the DatePicker button, eg. width, height... | 40 | | date | - | string | date | Moment instance | Specify the display date of DatePicker. `string` type value must match the specified format | 41 | | mode | 'date' | `enum` | The `enum` of `date` and `time` for android and ios, , `datetime` for ios only| 42 | | format | 'YYYY-MM-DD' | `string` | Specify the display format of the date, which using [moment.js](http://momentjs.com/). The default value change according to the mode. | 43 | | okText | 'ok' | `string` | Specify the confirm text | 44 | | cancelText | 'cancel' | `string` | Specify cancel text | 45 | | minDate | - | string | date | Restricts the range of possible date values. | 46 | | maxDate | - | string | date | Restricts the range of possible date values. | 47 | | minTime | - | string | date | Restricts the range of possible date values. | 48 | | maxTime | - | string | date | Restricts the range of possible date values. | 49 | | duration | 300 | `number` | Specify the animation duration of datepicker on ios.| 50 | | hourInterval | 1 | `number` | Controls hours interval on android time picker.| 51 | | minuteInterval | 10 | `number` | Controls minutes interval on time picker.(ios and android)| 52 | | secondInterval | 10 | `number` | Controls seconds interval on android time picker.| 53 | | okColor | 'green' | `string` | Controls ok Text color.| 54 | | cancelColor | 'red' | `string` | Controls cancel Text color.| 55 | | accentColor | 'blue' | `string` | Controls date/Time header color.| 56 | | darkTheme | false | `boolean` | Controls date/Time body color.(light or dark)| 57 | | vibrate | false | `boolean` | Set whether the dialogs should vibrate the device when a selection is made. (android only)| 58 | | dismissOnPause | false | `boolean` | Set whether the picker dismisses itself when the parent Activity is paused or whether it recreates itself when the Activity is resumed.(android only)| 59 | | enableSeconds | false | `boolean` | Allows you to enable or disable a seconds and minutes picker on the TimepickerDialog. Enabling the seconds picker, implies enabling the minutes picker. Disabling the minute picker will disable the seconds picker. The last applied setting will be used. By default enableSeconds = false and enableMinutes = true..(android only)| 60 | | enableMinutes | true | `boolean` | Allows you to enable or disable a minutes on the TimepickerDialog. (android only)| 61 | | showYearPickerFirst | false | `boolean` | Show the year picker first, rather than the month and day picker.. (android only)| 62 | | scrollOrientation | 'horizontal' | `string` | Determines whether months scroll Horizontal or Vertical. Defaults to Horizontal for the v2 layout and Vertical for the v1 layout (android only)| 63 | | disabledTimes | - | `array` | You can pass in an array of objects, each object contains hour limiter minute and or seconds limiter. These values will not be available for selection. (android only)| 64 | | customStyles | - | `object` | The hook of customize datepicker style, same as the native style. `dateTouchBody`, `dateInput`...| 65 | | hideText | false | `boolean` | hides the displayed date/Time | 66 | | disabled | false | `boolean` | Disable date/Time picker button | 67 | | is24Hour | - | `boolean` | Set the TimePicker is24Hour flag. The default value depend on `format`. | 68 | | allowFontScaling | true | `boolean` | Set to false to disable font scaling for every text component. | 69 | | placeholder | '' | `string` | The placeholder show when this.props.date is falsy | 70 | | onDateChange | - | `function` | This is called when the user confirm the picked date or time in the UI. The first and only argument is a date or time string representing the new date and time formatted by [moment.js](http://momentjs.com/) with the given format property. | 71 | | onOpenModal | - | `function` | This is called when the DatePicker Modal opens. (ios only) | 72 | | onCloseModal | - | `function` | This is called when the DatePicker Modal closes. (ios only) | 73 | | onPressMask | - | `function` | This is called when clicking the ios modal mask. (ios only) | 74 | | TouchableComponent | `TouchableHighlight` | `Component` | Replace the `TouchableHighlight` with a custom `Component`. For example : `TouchableOpacity` | 75 | | getDateStr | - | Function | A function to override how to format the date into a `String` for display, receives a `Date` instance 76 | 77 | ### Property `customStyles` available keys 78 | 79 | * appearance: `dateInput`, `disabled`, `dateTouchBody`, `placeholderText`, `dateText` 80 | * ios select panel: `datePickerCon`, `datePicker`, `btnConfirm`, `btnTextConfirm`, `btnCancel`, `btnTextCancel` 81 | 82 | 83 | ## Instance Methods 84 | 85 | | Method | Params | Description | 86 | | :------------ |:---------------:| :---------------:| 87 | | onConfirm | - | Manually open the date picker panel | 88 | | onCancel | - | Manually close the date picker panel like, similarly pressing cancel btn | 89 | 90 | 91 | 92 | ## Usage 93 | ```javascript 94 | import TimePicker from "react-native-navybits-date-time-picker"; 95 | 96 | 110 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(5.4)) 5 | connection.project.dir= 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home= 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | } 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | 14 | android { 15 | compileSdkVersion 26 16 | buildToolsVersion "26.0.1" 17 | 18 | defaultConfig { 19 | minSdkVersion 16 20 | targetSdkVersion 26 21 | versionCode 1 22 | versionName "1.0" 23 | } 24 | lintOptions { 25 | abortOnError false 26 | } 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | } 32 | 33 | dependencies { 34 | compile 'com.wdullaer:materialdatetimepicker:3.6.2' 35 | compile 'com.facebook.react:react-native:+' 36 | } 37 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Navybits/react-native-navybits-date-time-picker/5e35496b71a8f920d1af675bd8f254bc38b84e85/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Dec 20 13:58:56 EET 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/DatePickerFragment.java: -------------------------------------------------------------------------------- 1 | package com.reactlibrary; 2 | 3 | import android.app.DialogFragment; 4 | import android.content.DialogInterface; 5 | import android.os.Bundle; 6 | 7 | import java.lang.reflect.Array; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Arrays; 10 | import java.util.Calendar; 11 | import java.util.Date; 12 | import java.util.TimeZone; 13 | 14 | import com.facebook.react.bridge.Callback; 15 | import com.facebook.react.bridge.ReadableArray; 16 | import com.facebook.react.bridge.ReadableMap; 17 | 18 | import android.graphics.Color; 19 | import android.util.Log; 20 | import android.view.LayoutInflater; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.view.WindowManager; 24 | 25 | import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; 26 | import com.wdullaer.materialdatetimepicker.date.DateRangeLimiter; 27 | import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; 28 | import com.wdullaer.materialdatetimepicker.time.Timepoint; 29 | 30 | public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener { 31 | 32 | DatePickerDialog dpd; 33 | private Callback callback; 34 | private boolean dismissOnPause, vibrate, darkTheme, autoDismiss, showYearPickerFirst; 35 | private int year, month, day; 36 | private String okText, title, cancelText, accentColor, okColor, cancelColor, scrollOrientation; 37 | private String minDate, maxDate; 38 | 39 | public DatePickerFragment() { 40 | } 41 | 42 | 43 | public DatePickerFragment(ReadableMap options, Callback callback) { 44 | 45 | this.callback = callback; 46 | final Calendar c = Calendar.getInstance(); 47 | 48 | title = options.hasKey("title") ? options.getString("title") : ""; 49 | okText = options.hasKey("okText") ? options.getString("okText") : "OK"; 50 | cancelText = options.hasKey("cancelText") ? options.getString("cancelText") : "CANCEL"; 51 | scrollOrientation = options.hasKey("scrollOrientation") ? options.getString("scrollOrientation") : "horizontal"; 52 | 53 | year = options.hasKey("year") ? options.getInt("year") : c.get(Calendar.YEAR); 54 | month = options.hasKey("month") ? options.getInt("month") : c.get(Calendar.MONTH); 55 | day = options.hasKey("day") ? options.getInt("day") : c.get(Calendar.DAY_OF_YEAR); 56 | 57 | dismissOnPause = options.hasKey("dismissOnPause") ? options.getBoolean("dismissOnPause") : false; 58 | vibrate = options.hasKey("vibrate") ? options.getBoolean("vibrate") : false; 59 | darkTheme = options.hasKey("darkTheme") ? options.getBoolean("darkTheme") : false; 60 | autoDismiss = options.hasKey("autoDismiss") ? options.getBoolean("autoDismiss") : false; 61 | showYearPickerFirst = options.hasKey("showYearPickerFirst") ? options.getBoolean("showYearPickerFirst") : false; 62 | 63 | accentColor = options.hasKey("accentColor") ? options.getString("accentColor") : "#ffffff"; 64 | okColor = options.hasKey("okColor") ? options.getString("okColor") : "#ffffff"; 65 | cancelColor = options.hasKey("cancelColor") ? options.getString("cancelColor") : "#ffffff"; 66 | 67 | if( options.hasKey("minDate") ) 68 | minDate = options.getString("minDate") ; 69 | if( options.hasKey("maxDate") ) 70 | maxDate = options.getString("maxDate") ; 71 | 72 | 73 | 74 | } 75 | 76 | @Override 77 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 78 | getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); 79 | 80 | dpd = DatePickerDialog.newInstance(DatePickerFragment.this, year, month, day); 81 | 82 | dpd.setTitle(title); 83 | dpd.setOkText(okText); 84 | dpd.setCancelText(cancelText); 85 | 86 | 87 | dpd.vibrate(vibrate); 88 | dpd.dismissOnPause(dismissOnPause); 89 | dpd.autoDismiss(autoDismiss); 90 | dpd.showYearPickerFirst(showYearPickerFirst); 91 | 92 | dpd.setAccentColor(Color.parseColor(accentColor)); 93 | dpd.setThemeDark(darkTheme); 94 | dpd.setOkColor(Color.parseColor(okColor)); 95 | dpd.setCancelColor(Color.parseColor(cancelColor)); 96 | 97 | 98 | if(minDate!=null){ 99 | Calendar cal1 = Calendar.getInstance(); 100 | 101 | SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); 102 | try { 103 | cal1.setTime(sdf.parse(minDate)); 104 | } 105 | catch (Exception e) { 106 | //The handling for the code 107 | } 108 | 109 | dpd.setMinDate(cal1); 110 | 111 | } 112 | if(maxDate!=null) { 113 | Calendar cal1 = Calendar.getInstance(); 114 | 115 | SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); 116 | try { 117 | cal1.setTime(sdf.parse(maxDate)); 118 | } 119 | catch (Exception e) { 120 | //The handling for the code 121 | } 122 | dpd.setMaxDate(cal1); 123 | 124 | } 125 | Log.d("scrollOrientation", scrollOrientation); 126 | if (scrollOrientation.equals("horizontal")) 127 | dpd.setScrollOrientation(DatePickerDialog.ScrollOrientation.HORIZONTAL); 128 | else if (scrollOrientation.equals("vertical")) 129 | dpd.setScrollOrientation(DatePickerDialog.ScrollOrientation.VERTICAL); 130 | 131 | 132 | 133 | dpd.setOnCancelListener(new DialogInterface.OnCancelListener() { 134 | @Override 135 | public void onCancel(DialogInterface dialogInterface) { 136 | getActivity().getFragmentManager().popBackStackImmediate(); 137 | getDialog().dismiss(); 138 | } 139 | }); 140 | dpd.show(getFragmentManager(), "Timepickerdialog"); 141 | 142 | return null; 143 | } 144 | @Override 145 | public void onDismiss(DialogInterface dialog) { 146 | super.onDismiss(dialog); 147 | } 148 | @Override 149 | public void onResume() { 150 | super.onResume(); 151 | TimePickerDialog tpd = (TimePickerDialog) getFragmentManager().findFragmentByTag("Timepickerdialog"); 152 | if (dpd != null) 153 | dpd.setOnDateSetListener(this); 154 | } 155 | 156 | @Override 157 | public void onDateSet(DatePickerDialog datePickerDialog, int i, int i1, int i2) { 158 | int dayString = i2; 159 | //hourOfDay < 10 ? "0" + hourOfDay : "" + hourOfDay; 160 | int yearString = i; 161 | //minute < 10 ? "0" + minute : "" + minute; 162 | int monthString = i1+1; 163 | //second < 10 ? "0" + second : "" + second; 164 | String date = "You picked the following date: " + yearString + "h" + monthString + "m" + dayString + "s"; 165 | callback.invoke(yearString, monthString,dayString); 166 | getActivity().getFragmentManager().popBackStackImmediate(); 167 | getDialog().dismiss(); 168 | // getActivity().finish(); 169 | } 170 | 171 | 172 | } 173 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNNavybitsDateTimePickerModule.java: -------------------------------------------------------------------------------- 1 | 2 | package com.reactlibrary; 3 | 4 | import android.app.Activity; 5 | import android.app.DialogFragment; 6 | 7 | import com.facebook.react.bridge.ReactApplicationContext; 8 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 9 | import com.facebook.react.bridge.ReactMethod; 10 | import com.facebook.react.bridge.Callback; 11 | import com.facebook.react.bridge.ReadableMap; 12 | 13 | public class RNNavybitsDateTimePickerModule extends ReactContextBaseJavaModule { 14 | private Activity activity; 15 | 16 | public RNNavybitsDateTimePickerModule(ReactApplicationContext reactContext) { 17 | super(reactContext); 18 | this.activity = getCurrentActivity(); 19 | } 20 | 21 | 22 | @Override 23 | public String getName() { 24 | return "DateTimePicker"; 25 | } 26 | 27 | 28 | @ReactMethod 29 | public void showTimePicker(ReadableMap options, Callback callback) { 30 | String mode = options.hasKey("mode") ? options.getString("mode") : "time"; 31 | 32 | if(mode.equals("time")) { 33 | DialogFragment timePicker = new TimePickerFragment(options, callback); 34 | 35 | timePicker.show(getCurrentActivity().getFragmentManager(), "timePicker"); 36 | }else{ 37 | DialogFragment datePicker = new DatePickerFragment(options, callback); 38 | 39 | datePicker.show(getCurrentActivity().getFragmentManager(), "datePicker"); 40 | 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNNavybitsDateTimePickerPackage.java: -------------------------------------------------------------------------------- 1 | 2 | package com.reactlibrary; 3 | 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.bridge.NativeModule; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.uimanager.ViewManager; 12 | import com.facebook.react.bridge.JavaScriptModule; 13 | public class RNNavybitsDateTimePickerPackage implements ReactPackage { 14 | @Override 15 | public List createNativeModules(ReactApplicationContext reactContext) { 16 | return Arrays.asList(new RNNavybitsDateTimePickerModule(reactContext)); 17 | } 18 | 19 | // Deprecated from RN 0.47 20 | public List> createJSModules() { 21 | return Collections.emptyList(); 22 | } 23 | 24 | @Override 25 | public List createViewManagers(ReactApplicationContext reactContext) { 26 | return Collections.emptyList(); 27 | } 28 | } -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/TimePickerFragment.java: -------------------------------------------------------------------------------- 1 | package com.reactlibrary; 2 | 3 | import android.app.DialogFragment; 4 | import android.content.DialogInterface; 5 | import android.os.Bundle; 6 | 7 | import java.lang.reflect.Array; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Arrays; 10 | import java.util.Calendar; 11 | import java.util.Date; 12 | import java.util.Locale; 13 | 14 | import com.facebook.react.bridge.Callback; 15 | import com.facebook.react.bridge.ReadableArray; 16 | import com.facebook.react.bridge.ReadableMap; 17 | 18 | import android.graphics.Color; 19 | import android.util.Log; 20 | import android.view.LayoutInflater; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.view.WindowManager; 24 | 25 | import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; 26 | import com.wdullaer.materialdatetimepicker.time.Timepoint; 27 | import com.facebook.react.uimanager.annotations.ReactProp; 28 | 29 | public class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener { 30 | 31 | TimePickerDialog tpd; 32 | private Callback callback; 33 | private boolean enableSeconds, enableMinutes, dismissOnPause, vibrate, darkTheme, is24Hour; 34 | private int hour, minute, second, minutesInterval, hoursInterval, secondsInterval; 35 | private String okText, title, cancelText, accentColor, okColor, cancelColor; 36 | private ReadableArray disabledTimes; 37 | private String minTime, maxTime; 38 | 39 | 40 | public TimePickerFragment() { 41 | } 42 | 43 | public TimePickerFragment(ReadableMap options, Callback callback) { 44 | 45 | this.callback = callback; 46 | final Calendar c = Calendar.getInstance(); 47 | 48 | title = options.hasKey("title") ? options.getString("title") : ""; 49 | okText = options.hasKey("okText") ? options.getString("okText") : "OK"; 50 | cancelText = options.hasKey("cancelText") ? options.getString("cancelText") : "CANCEL"; 51 | 52 | hour = options.hasKey("hour") ? options.getInt("hour") : c.get(Calendar.HOUR_OF_DAY); 53 | minute = options.hasKey("minute") ? options.getInt("minute") : c.get(Calendar.MINUTE); 54 | second = options.hasKey("second") ? options.getInt("second") : c.get(Calendar.SECOND); 55 | 56 | minutesInterval = options.hasKey("minuteInterval") ? options.getInt("minuteInterval") : 15; 57 | hoursInterval = options.hasKey("hourInterval") ? options.getInt("hourInterval") : 1; 58 | secondsInterval = options.hasKey("secondInterval") ? options.getInt("secondInterval") : 10; 59 | 60 | enableMinutes = options.hasKey("enableMinutes") ? options.getBoolean("enableMinutes") : true; 61 | enableSeconds = options.hasKey("enableSeconds") ? options.getBoolean("enableSeconds") : false; 62 | dismissOnPause = options.hasKey("dismissOnPause") ? options.getBoolean("dismissOnPause") : false; 63 | vibrate = options.hasKey("vibrate") ? options.getBoolean("vibrate") : false; 64 | darkTheme = options.hasKey("darkTheme") ? options.getBoolean("darkTheme") : false; 65 | is24Hour = options.hasKey("is24Hour") ? options.getBoolean("is24Hour") : false; 66 | 67 | accentColor = options.hasKey("accentColor") ? options.getString("accentColor") : "#ffffff"; 68 | okColor = options.hasKey("okColor") ? options.getString("okColor") : "#ffffff"; 69 | cancelColor = options.hasKey("cancelColor") ? options.getString("cancelColor") : "#ffffff"; 70 | 71 | if (options.hasKey("minTime")) 72 | minTime = options.getString("minTime"); 73 | if (options.hasKey("maxTime")) 74 | maxTime = options.getString("maxTime"); 75 | 76 | if (options.hasKey("disabledTimes")) 77 | disabledTimes = options.getArray("disabledTimes"); 78 | } 79 | 80 | @ReactProp(name = "title") 81 | public void setTitle(String title) { 82 | tpd.setTitle(title); 83 | } 84 | 85 | @ReactProp(name = "okText") 86 | public void setOkText(String okText) { 87 | tpd.setOkText(okText); 88 | } 89 | 90 | @ReactProp(name = "cancelText") 91 | public void setCancelText(String cancelText) { 92 | tpd.setCancelText(title); 93 | } 94 | 95 | @ReactProp(name = "accentColor") 96 | public void setAccentColor(String accentColor) { 97 | tpd.setAccentColor(Color.parseColor(accentColor)); 98 | } 99 | 100 | @ReactProp(name = "okColor") 101 | public void setOkColor(String okColor) { 102 | tpd.setOkColor(Color.parseColor(okColor)); 103 | } 104 | 105 | @ReactProp(name = "cancelColor") 106 | public void setCancelColor(String cancelColor) { 107 | tpd.setCancelColor(Color.parseColor(cancelColor)); 108 | } 109 | 110 | @ReactProp(name = "vibrate") 111 | public void setVibrate(Boolean vibrate) { 112 | tpd.vibrate(vibrate); 113 | } 114 | 115 | @ReactProp(name = "enableSeconds") 116 | public void setEnableSeconds(Boolean enableSeconds) { 117 | tpd.enableSeconds(enableSeconds); 118 | } 119 | 120 | @ReactProp(name = "dismissOnPause") 121 | public void setDismissOnPause(Boolean dismissOnPause) { 122 | tpd.dismissOnPause(dismissOnPause); 123 | } 124 | 125 | @ReactProp(name = "themeDark") 126 | public void setThemeDark(Boolean themeDark) { 127 | tpd.setThemeDark(themeDark); 128 | } 129 | 130 | @ReactProp(name = "timeInterval") 131 | public void setTimeInterval(int hoursInterval, int minutesInterval, int secondsInterval) { 132 | tpd.setTimeInterval(hoursInterval, minutesInterval, secondsInterval); 133 | } 134 | 135 | @Override 136 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 137 | getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); 138 | 139 | if (enableMinutes == true && enableSeconds == true) 140 | tpd = TimePickerDialog.newInstance(TimePickerFragment.this, hour, minute, second, is24Hour); 141 | else 142 | tpd = TimePickerDialog.newInstance(TimePickerFragment.this, hour, minute, is24Hour); 143 | 144 | tpd.setTitle(title); 145 | tpd.setOkText(okText); 146 | tpd.setCancelText(cancelText); 147 | 148 | tpd.vibrate(vibrate); 149 | tpd.setThemeDark(darkTheme); 150 | tpd.dismissOnPause(dismissOnPause); 151 | tpd.enableMinutes(enableMinutes); 152 | tpd.enableSeconds(enableSeconds); 153 | tpd.setTimeInterval(hoursInterval, minutesInterval, secondsInterval); 154 | 155 | tpd.setAccentColor(Color.parseColor(accentColor)); 156 | tpd.setOkColor(Color.parseColor(okColor)); 157 | tpd.setCancelColor(Color.parseColor(cancelColor)); 158 | 159 | if (minTime != null) { 160 | Calendar cal1 = Calendar.getInstance(); 161 | 162 | SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); 163 | try { 164 | cal1.setTime(sdf.parse(minTime)); 165 | } catch (Exception e) { 166 | // The handling for the code 167 | } 168 | tpd.setMinTime(new Timepoint(cal1.get(Calendar.HOUR_OF_DAY), cal1.get(Calendar.MINUTE), 169 | cal1.get(Calendar.SECOND))); 170 | } 171 | if (maxTime != null) { 172 | Calendar cal1 = Calendar.getInstance(); 173 | 174 | SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); 175 | try { 176 | cal1.setTime(sdf.parse(maxTime)); 177 | } catch (Exception e) { 178 | // The handling for the code 179 | } 180 | tpd.setMaxTime(new Timepoint(cal1.get(Calendar.HOUR_OF_DAY), cal1.get(Calendar.MINUTE), 181 | cal1.get(Calendar.SECOND))); 182 | } 183 | if (disabledTimes != null) { 184 | int size = disabledTimes.size(); 185 | Timepoint[] disabledTimesPicker = new Timepoint[size]; 186 | 187 | Log.d("size", Integer.toString(size)); 188 | for (int i = 0; i < size; i++) { 189 | if (disabledTimes.getMap(i).hasKey("second")) 190 | disabledTimesPicker[i] = new Timepoint(disabledTimes.getMap(i).getInt("hour"), 191 | disabledTimes.getMap(i).getInt("minute"), disabledTimes.getMap(i).getInt("second")); 192 | else if (disabledTimes.getMap(i).hasKey("minute")) 193 | disabledTimesPicker[i] = new Timepoint(disabledTimes.getMap(i).getInt("hour"), 194 | disabledTimes.getMap(i).getInt("minute")); 195 | else 196 | disabledTimesPicker[i] = new Timepoint(disabledTimes.getMap(i).getInt("hour")); 197 | 198 | } 199 | 200 | Log.d("disabledTimesPicker", Arrays.toString(disabledTimesPicker)); 201 | tpd.setDisabledTimes(disabledTimesPicker); 202 | } 203 | 204 | tpd.setOnCancelListener(new DialogInterface.OnCancelListener() { 205 | @Override 206 | public void onCancel(DialogInterface dialogInterface) { 207 | getActivity().getFragmentManager().popBackStackImmediate(); 208 | getDialog().dismiss(); 209 | } 210 | }); 211 | tpd.show(getFragmentManager(), "Timepickerdialog"); 212 | 213 | return null; 214 | } 215 | 216 | @Override 217 | public void onDismiss(DialogInterface dialog) { 218 | super.onDismiss(dialog); 219 | } 220 | 221 | @Override 222 | public void onResume() { 223 | super.onResume(); 224 | TimePickerDialog tpd = (TimePickerDialog) getFragmentManager().findFragmentByTag("Timepickerdialog"); 225 | if (tpd != null) 226 | tpd.setOnTimeSetListener(this); 227 | } 228 | 229 | @Override 230 | public void onTimeSet(TimePickerDialog view, int hourOfDay, int minute, int second) { 231 | String hourString = hourOfDay < 10 ? "0" + hourOfDay : "" + hourOfDay; 232 | String minuteString = minute < 10 ? "0" + minute : "" + minute; 233 | String secondString = second < 10 ? "0" + second : "" + second; 234 | String time = "You picked the following time: " + hourString + "h" + minuteString + "m" + secondString + "s"; 235 | callback.invoke(hourString, minuteString, secondString); 236 | getActivity().getFragmentManager().popBackStackImmediate(); 237 | getDialog().dismiss(); 238 | // getActivity().finish(); 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /datePicker.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import moment from "moment"; 3 | import PropTypes from "prop-types"; 4 | import React, { Component } from "react"; 5 | import { 6 | Animated, 7 | DatePickerIOS, 8 | Keyboard, 9 | Modal, 10 | NativeModules, 11 | Platform, 12 | Text, 13 | TouchableHighlight, 14 | View 15 | } from "react-native"; 16 | import styles from "./styles"; 17 | var RCTDateTimePicker = NativeModules.DateTimePicker; 18 | 19 | const FORMATS = { 20 | date: "YYYY-MM-DD", 21 | datetime: "YYYY-MM-DD HH:mm", 22 | time24: "HH:mm", 23 | time: "hh:mm a" 24 | }; 25 | const SUPPORTED_ORIENTATIONS = [ 26 | "portrait", 27 | "portrait-upside-down", 28 | "landscape", 29 | "landscape-left", 30 | "landscape-right" 31 | ]; 32 | 33 | class DatePicker extends Component { 34 | constructor(props) { 35 | super(props); 36 | 37 | this.state = { 38 | date: this.getDate(), 39 | modalVisible: false, 40 | animatedHeight: new Animated.Value(0), 41 | allowPointerEvents: true 42 | }; 43 | this._hideDateTimePicker = this._hideDateTimePicker.bind(this); 44 | this._handleDatePicked = this._handleDatePicked.bind(this); 45 | 46 | this.getDate = this.getDate.bind(this); 47 | this.getDateStr = this.getDateStr.bind(this); 48 | this.datePicked = this.datePicked.bind(this); 49 | this.onPressDate = this.onPressDate.bind(this); 50 | this.onPressCancel = this.onPressCancel.bind(this); 51 | this.onPressConfirm = this.onPressConfirm.bind(this); 52 | this.onDateChange = this.onDateChange.bind(this); 53 | this.onPressMask = this.onPressMask.bind(this); 54 | this.setModalVisible = this.setModalVisible.bind(this); 55 | } 56 | 57 | componentWillReceiveProps(nextProps) { 58 | if (nextProps.date !== this.props.date) { 59 | this.setState({ date: this.getDate(nextProps.date) }); 60 | } 61 | } 62 | 63 | setModalVisible(visible) { 64 | const { height, duration } = this.props; 65 | 66 | // slide animation 67 | if (visible) { 68 | this.setState({ modalVisible: visible }); 69 | return Animated.timing(this.state.animatedHeight, { 70 | toValue: height, 71 | duration: duration 72 | }).start(); 73 | } else { 74 | return Animated.timing(this.state.animatedHeight, { 75 | toValue: 0, 76 | duration: duration 77 | }).start(() => { 78 | this.setState({ modalVisible: visible }); 79 | }); 80 | } 81 | } 82 | 83 | onStartShouldSetResponder(e) { 84 | return true; 85 | } 86 | 87 | onMoveShouldSetResponder(e) { 88 | return true; 89 | } 90 | 91 | onPressMask() { 92 | if (typeof this.props.onPressMask === "function") { 93 | this.props.onPressMask(); 94 | } else { 95 | this.onPressCancel(); 96 | } 97 | } 98 | 99 | onPressCancel() { 100 | this.setModalVisible(false); 101 | 102 | if (typeof this.props.onCancel === "function") { 103 | this.props.onCancel(); 104 | } 105 | if (typeof this.props.onCloseModal === "function") { 106 | this.props.onCloseModal(); 107 | } 108 | } 109 | 110 | onPressConfirm() { 111 | this.datePicked(); 112 | this.setModalVisible(false); 113 | 114 | if (typeof this.props.onConfirm === "function") { 115 | this.props.onConfirm(this.state.date); 116 | } 117 | if (typeof this.props.onCloseModal === "function") { 118 | this.props.onCloseModal(); 119 | } 120 | } 121 | 122 | getDate(date = this.props.date) { 123 | const { mode, minDate, maxDate, is24Hour } = this.props; 124 | let format = FORMATS[mode]; 125 | if (mode == "time" && is24Hour) format = FORMATS["time24"]; 126 | 127 | if (!date) { 128 | let now = new Date(); 129 | if (minDate) { 130 | let _minDate = this.getDate(minDate); 131 | 132 | if (now < _minDate) { 133 | return _minDate; 134 | } 135 | } 136 | 137 | if (maxDate) { 138 | let _maxDate = this.getDate(maxDate); 139 | 140 | if (now > _maxDate) { 141 | return _maxDate; 142 | } 143 | } 144 | 145 | return now; 146 | } 147 | 148 | if (date instanceof Date) { 149 | return date; 150 | } 151 | 152 | return moment(date, format).toDate(); 153 | } 154 | 155 | getDateStr(date = this.props.date) { 156 | const { mode, is24Hour } = this.props; 157 | let format = FORMATS[mode]; 158 | if (mode == "time" && is24Hour) format = FORMATS["time24"]; 159 | 160 | const dateInstance = date instanceof Date ? date : this.getDate(date); 161 | 162 | if (typeof this.props.getDateStr === "function") { 163 | return this.props.getDateStr(dateInstance); 164 | } 165 | 166 | return moment(dateInstance).format(format); 167 | } 168 | 169 | datePicked() { 170 | if (typeof this.props.onDateChange === "function") { 171 | this.props.onDateChange( 172 | this.getDateStr(this.state.date), 173 | this.state.date 174 | ); 175 | } 176 | } 177 | 178 | getTitleElement() { 179 | const { date, placeholder, customStyles, allowFontScaling } = this.props; 180 | 181 | if (!date && placeholder) { 182 | return ( 183 | 187 | {placeholder} 188 | 189 | ); 190 | } 191 | return ( 192 | 196 | {this.getDateStr()} 197 | 198 | ); 199 | } 200 | showTimePicker() { 201 | //date = date || new Date(); 202 | let _this = this; 203 | let options = _.clone(this.props); 204 | let date = this.state.date; 205 | // console.log({ date: moment(date) }); 206 | if (options.mode == "time") { 207 | options.hour = moment(date).hour(); 208 | options.minute = moment(date).minute(); 209 | options.second = moment(date).second(); 210 | 211 | if (options.minTime) { 212 | options = { 213 | ...options, 214 | minTime: moment(options.minTime).format("HH:mm:ss") 215 | }; 216 | } 217 | 218 | if (options.maxTime) { 219 | options = { 220 | ...options, 221 | maxTime: moment(options.maxTime).format("HH:mm:ss") 222 | }; 223 | } 224 | } else { 225 | options.year = moment(date).get("year"); 226 | options.month = moment(date).get("month"); 227 | options.day = moment(date).get("date"); 228 | 229 | if (options.minDate) { 230 | options = { 231 | ...options, 232 | minDate: moment(options.minDate).format("DD-MM-YYYY") 233 | }; 234 | } 235 | 236 | if (options.maxDate) { 237 | options = { 238 | ...options, 239 | maxDate: moment(options.maxDate).format("DD-MM-YYYY") 240 | }; 241 | } 242 | } 243 | // console.log({ options }); 244 | if (options.mode == "time") 245 | RCTDateTimePicker.showTimePicker(options, function(hour, minute, second) { 246 | //ƒconsole.log({ hour, minute, second }); 247 | let newDate = new Date(); 248 | newDate.setHours(hour); 249 | newDate.setMinutes(minute); 250 | newDate.setSeconds(second); 251 | //console.log({ newDate }); 252 | if (hour && minute) _this._handleDatePicked(newDate); 253 | else _this._handleDatePicked(null); 254 | }); 255 | else 256 | RCTDateTimePicker.showTimePicker(options, function(year, month, day) { 257 | // console.log({ year, month, day }); 258 | let newDate = new Date(year, month - 1, day); 259 | // console.log({ newDate }); 260 | if (year && month) _this._handleDatePicked(newDate); 261 | else _this._handleDatePicked(null); 262 | }); 263 | } 264 | 265 | _handleDatePicked = date => { 266 | let { onConfirm, onCancel } = this.props; 267 | if (date) { 268 | let displayedDate = this.getDate(date); 269 | this.setState({ 270 | originalDate: date, 271 | date: displayedDate 272 | }); 273 | onConfirm && onConfirm(date); 274 | } else { 275 | onCancel && onCancel(); 276 | } 277 | this._hideDateTimePicker(); 278 | }; 279 | _hideDateTimePicker = () => this.setState({ isDateTimePickerVisible: false }); 280 | 281 | onDateChange(date) { 282 | this.setState({ 283 | allowPointerEvents: false, 284 | date: date 285 | }); 286 | const timeoutId = setTimeout(() => { 287 | this.setState({ 288 | allowPointerEvents: true 289 | }); 290 | clearTimeout(timeoutId); 291 | }, 200); 292 | } 293 | 294 | onPressDate() { 295 | if (this.props.disabled) { 296 | return true; 297 | } 298 | 299 | Keyboard.dismiss(); 300 | 301 | // reset state 302 | this.setState({ 303 | date: this.getDate() 304 | }); 305 | 306 | if (Platform.OS == "ios") { 307 | this.setModalVisible(true); 308 | 309 | if (typeof this.props.onOpenModal === "function") { 310 | this.props.onOpenModal(); 311 | } 312 | } else { 313 | this.showTimePicker(this.state.date); 314 | } 315 | } 316 | 317 | render() { 318 | const { 319 | mode, 320 | style, 321 | customStyles, 322 | disabled, 323 | minDate, 324 | maxDate, 325 | minuteInterval, 326 | timeZoneOffsetInMinutes, 327 | cancelText, 328 | title, 329 | okText, 330 | cancelColor, 331 | okColor, 332 | TouchableComponent, 333 | testID, 334 | is24Hour, 335 | accentColor, 336 | cancelBtnTestID, 337 | confirmBtnTestID, 338 | allowFontScaling, 339 | locale, 340 | darkTheme 341 | } = this.props; 342 | 343 | const dateInputStyle = [ 344 | styles.dateInput, 345 | customStyles.dateInput, 346 | disabled && styles.disabled, 347 | disabled && customStyles.disabled 348 | ]; 349 | 350 | return ( 351 | 358 | 359 | {this.props.renderDate ? ( 360 | this.props.renderDate(this.props.date) 361 | ) : !this.props.hideText ? ( 362 | {this.getTitleElement()} 363 | ) : ( 364 | 365 | )} 366 | { 372 | this.setModalVisible(false); 373 | }} 374 | > 375 | 376 | 382 | 383 | 391 | 397 | 407 | 416 | {cancelText} 417 | 418 | 419 | {title ? ( 420 | 421 | 422 | {title} 423 | 424 | 425 | ) : null} 426 | 436 | 444 | {okText} 445 | 446 | 447 | 448 | 457 | { 461 | this._picker = picker; 462 | }} 463 | minimumDate={minDate && this.getDate(minDate)} 464 | maximumDate={maxDate && this.getDate(maxDate)} 465 | onDateChange={this.onDateChange} 466 | itemStyle={styles.itemStyle} 467 | minuteInterval={minuteInterval} 468 | timeZoneOffsetInMinutes={ 469 | timeZoneOffsetInMinutes 470 | ? timeZoneOffsetInMinutes 471 | : null 472 | } 473 | style={[styles.datePickerIOS, customStyles.datePicker]} 474 | locale={locale || (is24Hour ? "en_GB" : "en_us")} 475 | /> 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | ); 485 | } 486 | } 487 | 488 | DatePicker.defaultProps = { 489 | mode: "date", 490 | date: new Date(), 491 | // component height: 216(DatePickerIOS) + 1(borderTop) + 42(marginTop), IOS only 492 | height: 259, 493 | 494 | // slide animation duration time, default to 300ms, IOS only 495 | duration: 300, 496 | okText: "ok", 497 | cancelText: "cancel", 498 | // iconSource: require("./date_icon.png"), 499 | customStyles: {}, 500 | 501 | // whether or not show the icon 502 | showIcon: true, 503 | disabled: false, 504 | allowFontScaling: true, 505 | hideText: false, 506 | placeholder: "", 507 | TouchableComponent: TouchableHighlight, 508 | 509 | hourInterval: 1, 510 | minuteInterval: 10, 511 | secondInterval: 10, 512 | 513 | is24Hour: false, 514 | vibrate: false, 515 | darkTheme: false, 516 | enableSeconds: false, 517 | 518 | cancelColor: "red", 519 | okColor: "green", 520 | accentColor: "blue" 521 | }; 522 | 523 | DatePicker.propTypes = { 524 | mode: PropTypes.oneOf(["date", "datetime", "time"]), 525 | date: PropTypes.oneOfType([ 526 | PropTypes.string, 527 | PropTypes.instanceOf(Date), 528 | PropTypes.object 529 | ]), 530 | minDate: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]), //ios 531 | maxDate: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]), //ios 532 | minTime: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]), //ios 533 | maxTime: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]), //ios 534 | 535 | customStyles: PropTypes.object, 536 | 537 | height: PropTypes.number, //ios 538 | duration: PropTypes.number, //ios 539 | hourInterval: PropTypes.number, //android time picker 540 | minuteInterval: PropTypes.number, //android time picker 541 | secondInterval: PropTypes.number, //android time picker 542 | 543 | is24Hour: PropTypes.bool, 544 | disabled: PropTypes.bool, 545 | allowFontScaling: PropTypes.bool, //ios 546 | 547 | locale: PropTypes.string, //ios 548 | placeholder: PropTypes.string, 549 | title: PropTypes.string, 550 | format: PropTypes.string, 551 | okText: PropTypes.string, 552 | cancelText: PropTypes.string, 553 | okColor: PropTypes.string, 554 | cancelColor: PropTypes.string, 555 | accentColor: PropTypes.string, //all 556 | 557 | onConfirm: PropTypes.func, 558 | onCancel: PropTypes.func, 559 | getDateStr: PropTypes.func, 560 | onDateChange: PropTypes.func, //ios 561 | onOpenModal: PropTypes.func, //ios 562 | onCloseModal: PropTypes.func, //ios 563 | onPressMask: PropTypes.func, //ios 564 | renderDate: PropTypes.func, //all 565 | 566 | dismissOnPause: PropTypes.bool, //android 567 | vibrate: PropTypes.bool, //android 568 | darkTheme: PropTypes.bool, //android 569 | enableSeconds: PropTypes.bool, // time picker 570 | enableMinutes: PropTypes.bool, // time picker 571 | 572 | showYearPickerFirst: PropTypes.bool, //android date picker 573 | 574 | scrollOrientation: PropTypes.oneOf(["vertical", "horizontal"]), //android date picker 575 | disabledTimes: PropTypes.array //android time picker 576 | }; 577 | 578 | export default DatePicker; 579 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | * @flow 7 | */ 8 | 9 | import React, { Component } from "react"; 10 | import { 11 | Platform, 12 | TouchableOpacity, 13 | StyleSheet, 14 | Text, 15 | Switch, 16 | Slider, 17 | View, 18 | Dimensions 19 | } from "react-native"; 20 | import TimePicker from "./datePicker"; 21 | import moment from "moment"; 22 | let { width, height } = Dimensions.get("window"); 23 | export default class App extends Component { 24 | constructor(props) { 25 | super(props); 26 | let selectedDate = moment(); 27 | this.state = { 28 | mode: "date", 29 | is24Hour: true, 30 | accentColor: "blue", 31 | minuteInterval: 5, 32 | disabled: false, 33 | okColor: "green", 34 | cancelColor: "red", 35 | darkTheme: false, 36 | showYearPickerFirst: false, 37 | enableSeconds: false, 38 | scrollOrientation: "horizontal", 39 | selectedDate 40 | }; 41 | this._handleDatePicked = this._handleDatePicked.bind(this); 42 | this._hideDateTimePicker = this._hideDateTimePicker.bind(this); 43 | } 44 | renderDate(date) { 45 | let year = moment(date).format("YYYY"); 46 | let month = moment(date).format("MMM"); 47 | let day = moment(date).format("DD"); 48 | return ( 49 | 50 | 58 | {month} 59 | 60 | 68 | {day} 69 | 70 | 71 | {year} 72 | 73 | 74 | ); 75 | } 76 | _handleDatePicked(date) { 77 | console.log("selectedDate", date); 78 | this.setState({ selectedDate: date }); 79 | } 80 | _hideDateTimePicker() { 81 | console.log("canceled"); 82 | } 83 | getRandomColor() { 84 | var letters = "0123456789ABCDEF"; 85 | var color = "#"; 86 | for (var i = 0; i < 6; i++) { 87 | color += letters[Math.floor(Math.random() * 16)]; 88 | } 89 | return color; 90 | } 91 | setAccentColor() { 92 | this.setState({ accentColor: this.getRandomColor() }); 93 | } 94 | setOkColor() { 95 | this.setState({ okColor: this.getRandomColor() }); 96 | } 97 | setCancelColor() { 98 | this.setState({ cancelColor: this.getRandomColor() }); 99 | } 100 | render() { 101 | return ( 102 | 103 | this.renderDate(date)} 105 | accentColor={this.state.accentColor} 106 | okColor={this.state.okColor} 107 | cancelColor={this.state.cancelColor} 108 | okText={"OK"} 109 | cancelText={"CANCEL"} 110 | showYearPickerFirst={this.state.showYearPickerFirst} 111 | minuteInterval={this.state.minuteInterval} 112 | enableSeconds={this.state.enableSeconds} 113 | mode={this.state.mode} 114 | darkTheme={this.state.darkTheme} 115 | is24Hour={this.state.is24Hour} 116 | disabled={this.state.disabled} 117 | onConfirm={this._handleDatePicked} 118 | onCancel={this._hideDateTimePicker} 119 | date={this.state.selectedDate} 120 | placeholder={this.state.mode == "date" ? "YY/DD/MM" : "HH:MM"} 121 | title={`Navybits ${ 122 | this.state.mode == "date" ? "Date Picker" : "Time Picker" 123 | }`} 124 | height={300} 125 | disabledTimes={[ 126 | { hour: 22, minute: 10 }, 127 | { hour: 13, minute: 20 } 128 | // { hour: 10, minute: 10, second: 20 } 129 | ]} 130 | minTime={new Date()} 131 | minDate={new Date()} 132 | scrollOrientation={this.state.scrollOrientation} 133 | ref="TimePicker" 134 | /> 135 | 136 | Not disabled 137 | 138 | { 140 | this.setState({ disabled: val }); 141 | }} 142 | value={this.state.disabled} 143 | /> 144 | 145 | Disabled 146 | 147 | 148 | Time 149 | 150 | { 152 | this.setState({ mode: val ? "date" : "time" }); 153 | }} 154 | value={this.state.mode == "date" ? true : false} 155 | /> 156 | 157 | Date 158 | 159 | 160 | light theme 161 | 162 | { 164 | this.setState({ darkTheme: val }); 165 | }} 166 | value={this.state.darkTheme} 167 | /> 168 | 169 | dark theme 170 | 171 | {this.state.mode == "time" ? ( 172 | 173 | not is24Hour 174 | 175 | { 177 | this.setState({ is24Hour: val }); 178 | }} 179 | value={this.state.is24Hour} 180 | /> 181 | 182 | is24Hour 183 | 184 | ) : null} 185 | {Platform.OS == "android" && this.state.mode == "date" ? ( 186 | 187 | Vertical 188 | 189 | { 191 | this.setState({ 192 | scrollOrientation: val ? "horizontal" : "vertical" 193 | }); 194 | }} 195 | value={ 196 | this.state.scrollOrientation == "horizontal" ? true : false 197 | } 198 | /> 199 | 200 | Horizontal 201 | 202 | ) : null} 203 | {Platform.OS == "android" && this.state.mode == "time" ? ( 204 | 205 | do not enableSeconds 206 | 207 | { 209 | this.setState({ 210 | enableSeconds: val 211 | }); 212 | }} 213 | value={this.state.enableSeconds} 214 | /> 215 | 216 | enableSeconds 217 | 218 | ) : null} 219 | {Platform.OS == "android" && this.state.mode == "date" ? ( 220 | 221 | do not showYearPickerFirst 222 | 223 | { 225 | this.setState({ 226 | showYearPickerFirst: val 227 | }); 228 | }} 229 | value={this.state.showYearPickerFirst} 230 | /> 231 | 232 | showYearPickerFirst 233 | 234 | ) : null} 235 | {this.state.mode == "time" ? ( 236 | 237 | {"Minute Interval"} 238 | 239 | { 245 | this.setState({ 246 | minuteInterval: val 247 | }); 248 | }} 249 | step={5} 250 | value={this.state.minuteInterval} 251 | /> 252 | 253 | {this.state.minuteInterval} 254 | 255 | ) : null} 256 | this.setAccentColor()} 259 | > 260 | Set Accent Color to random 261 | 262 | this.setOkColor()} 265 | > 266 | Set Ok Color to random 267 | 268 | this.setCancelColor()} 271 | > 272 | Set Cancel Color to random 273 | 274 | 275 | ); 276 | } 277 | } 278 | 279 | const styles = StyleSheet.create({ 280 | container: { 281 | flex: 1, 282 | justifyContent: "center", 283 | alignItems: "center", 284 | backgroundColor: "#F5FCFF" 285 | }, 286 | welcome: { 287 | fontSize: 20, 288 | textAlign: "center", 289 | margin: 10 290 | }, 291 | instructions: { 292 | textAlign: "center", 293 | color: "#333333", 294 | marginBottom: 5 295 | }, 296 | row: { 297 | flexDirection: "row", 298 | alignItems: "center", 299 | justifyContent: "space-between", 300 | padding: 5, 301 | alignSelf: "stretch", 302 | margin: 5 303 | }, 304 | button: { 305 | padding: 10, 306 | margin: 5, 307 | borderWidth: 1, 308 | backgroundColor: "lightgray" 309 | }, 310 | switchText: { 311 | flex: 1, 312 | textAlign: "center" 313 | }, 314 | centerView: { 315 | flex: 1, 316 | alignItems: "center" 317 | }, 318 | dateElementView: { 319 | flex: 1, 320 | height: 50, 321 | alignItems: "flex-start", 322 | paddingLeft: 15, 323 | paddingRight: 15, 324 | justifyContent: "center", 325 | backgroundColor: "#f2f2f2", 326 | borderWidth: 1, 327 | borderColor: "lightgrey" 328 | }, 329 | dateElement: { 330 | color: "navy" 331 | }, 332 | dateWrapper: { 333 | flexDirection: "row", 334 | alignSelf: "stretch", 335 | alignItems: "center", 336 | width: width - 40, 337 | height: 50, 338 | justifyContent: "space-between" 339 | } 340 | }); 341 | -------------------------------------------------------------------------------- /img/NBPicker.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Navybits/react-native-navybits-date-time-picker/5e35496b71a8f920d1af675bd8f254bc38b84e85/img/NBPicker.gif -------------------------------------------------------------------------------- /img/nbPicker_android.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Navybits/react-native-navybits-date-time-picker/5e35496b71a8f920d1af675bd8f254bc38b84e85/img/nbPicker_android.gif -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import React, { Component } from "react"; 3 | 4 | import DatePicker from "./datePicker"; 5 | 6 | export default class TimePicker extends Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = {}; 10 | } 11 | shouldComponentUpdate(nextProps, nextState) { 12 | return ( 13 | !_.isEqual(nextProps, this.props) || !_.isEqual(nextState, this.state) 14 | ); 15 | } 16 | 17 | render() { 18 | return ; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ios/RNNavybitsDateTimePicker.h: -------------------------------------------------------------------------------- 1 | 2 | #if __has_include("RCTBridgeModule.h") 3 | #import "RCTBridgeModule.h" 4 | #else 5 | #import 6 | #endif 7 | 8 | @interface RNNavybitsDateTimePicker : NSObject 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /ios/RNNavybitsDateTimePicker.m: -------------------------------------------------------------------------------- 1 | 2 | #import "RNNavybitsDateTimePicker.h" 3 | 4 | @implementation RNNavybitsDateTimePicker 5 | 6 | - (dispatch_queue_t)methodQueue 7 | { 8 | return dispatch_get_main_queue(); 9 | } 10 | RCT_EXPORT_MODULE() 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /ios/RNNavybitsDateTimePicker.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = "RNNavybitsDateTimePicker" 4 | s.version = "1.0.0" 5 | s.summary = "RNNavybitsDateTimePicker" 6 | s.description = <<-DESC 7 | This project is a modified version of react-native-datePicker. It solves the need to set a MinuteInterval on android using the native picker MaterialDateTimePicker 8 | DESC 9 | s.homepage = "https://github.com/Navybits/react-native-navybits-date-time-picker/tree/master/ios" 10 | s.license = "MIT" 11 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 12 | s.author = { "Hanane" => "hanane.alsamrout@navybits.com" } 13 | s.platform = :ios, "7.0" 14 | s.source = { :git => "https://github.com/Navybits/react-native-navybits-date-time-picker.git", :tag => "master" } 15 | s.source_files = "RNNavybitsDateTimePicker/**/*.{h,m}" 16 | s.requires_arc = true 17 | 18 | 19 | 20 | s.dependency "React" 21 | #s.dependency "others" 22 | 23 | end 24 | 25 | -------------------------------------------------------------------------------- /ios/RNNavybitsDateTimePicker.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B3E7B58A1CC2AC0600A0062D /* RNNavybitsDateTimePicker.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNNavybitsDateTimePicker.m */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = "include/$(PRODUCT_NAME)"; 18 | dstSubfolderSpec = 16; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 0; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 134814201AA4EA6300B7C361 /* libRNNavybitsDateTimePicker.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNNavybitsDateTimePicker.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | B3E7B5881CC2AC0600A0062D /* RNNavybitsDateTimePicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNavybitsDateTimePicker.h; sourceTree = ""; }; 28 | B3E7B5891CC2AC0600A0062D /* RNNavybitsDateTimePicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNavybitsDateTimePicker.m; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 134814211AA4EA7D00B7C361 /* Products */ = { 43 | isa = PBXGroup; 44 | children = ( 45 | 134814201AA4EA6300B7C361 /* libRNNavybitsDateTimePicker.a */, 46 | ); 47 | name = Products; 48 | sourceTree = ""; 49 | }; 50 | 58B511D21A9E6C8500147676 = { 51 | isa = PBXGroup; 52 | children = ( 53 | B3E7B5881CC2AC0600A0062D /* RNNavybitsDateTimePicker.h */, 54 | B3E7B5891CC2AC0600A0062D /* RNNavybitsDateTimePicker.m */, 55 | 134814211AA4EA7D00B7C361 /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | /* End PBXGroup section */ 60 | 61 | /* Begin PBXNativeTarget section */ 62 | 58B511DA1A9E6C8500147676 /* RNNavybitsDateTimePicker */ = { 63 | isa = PBXNativeTarget; 64 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNNavybitsDateTimePicker" */; 65 | buildPhases = ( 66 | 58B511D71A9E6C8500147676 /* Sources */, 67 | 58B511D81A9E6C8500147676 /* Frameworks */, 68 | 58B511D91A9E6C8500147676 /* CopyFiles */, 69 | ); 70 | buildRules = ( 71 | ); 72 | dependencies = ( 73 | ); 74 | name = RNNavybitsDateTimePicker; 75 | productName = RCTDataManager; 76 | productReference = 134814201AA4EA6300B7C361 /* libRNNavybitsDateTimePicker.a */; 77 | productType = "com.apple.product-type.library.static"; 78 | }; 79 | /* End PBXNativeTarget section */ 80 | 81 | /* Begin PBXProject section */ 82 | 58B511D31A9E6C8500147676 /* Project object */ = { 83 | isa = PBXProject; 84 | attributes = { 85 | LastUpgradeCheck = 0830; 86 | ORGANIZATIONNAME = Facebook; 87 | TargetAttributes = { 88 | 58B511DA1A9E6C8500147676 = { 89 | CreatedOnToolsVersion = 6.1.1; 90 | }; 91 | }; 92 | }; 93 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNNavybitsDateTimePicker" */; 94 | compatibilityVersion = "Xcode 3.2"; 95 | developmentRegion = English; 96 | hasScannedForEncodings = 0; 97 | knownRegions = ( 98 | en, 99 | ); 100 | mainGroup = 58B511D21A9E6C8500147676; 101 | productRefGroup = 58B511D21A9E6C8500147676; 102 | projectDirPath = ""; 103 | projectRoot = ""; 104 | targets = ( 105 | 58B511DA1A9E6C8500147676 /* RNNavybitsDateTimePicker */, 106 | ); 107 | }; 108 | /* End PBXProject section */ 109 | 110 | /* Begin PBXSourcesBuildPhase section */ 111 | 58B511D71A9E6C8500147676 /* Sources */ = { 112 | isa = PBXSourcesBuildPhase; 113 | buildActionMask = 2147483647; 114 | files = ( 115 | B3E7B58A1CC2AC0600A0062D /* RNNavybitsDateTimePicker.m in Sources */, 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | /* End PBXSourcesBuildPhase section */ 120 | 121 | /* Begin XCBuildConfiguration section */ 122 | 58B511ED1A9E6C8500147676 /* Debug */ = { 123 | isa = XCBuildConfiguration; 124 | buildSettings = { 125 | ALWAYS_SEARCH_USER_PATHS = NO; 126 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 127 | CLANG_CXX_LIBRARY = "libc++"; 128 | CLANG_ENABLE_MODULES = YES; 129 | CLANG_ENABLE_OBJC_ARC = YES; 130 | CLANG_WARN_BOOL_CONVERSION = YES; 131 | CLANG_WARN_CONSTANT_CONVERSION = YES; 132 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 133 | CLANG_WARN_EMPTY_BODY = YES; 134 | CLANG_WARN_ENUM_CONVERSION = YES; 135 | CLANG_WARN_INFINITE_RECURSION = YES; 136 | CLANG_WARN_INT_CONVERSION = YES; 137 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 138 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 139 | CLANG_WARN_UNREACHABLE_CODE = YES; 140 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 141 | COPY_PHASE_STRIP = NO; 142 | ENABLE_STRICT_OBJC_MSGSEND = YES; 143 | ENABLE_TESTABILITY = YES; 144 | GCC_C_LANGUAGE_STANDARD = gnu99; 145 | GCC_DYNAMIC_NO_PIC = NO; 146 | GCC_NO_COMMON_BLOCKS = YES; 147 | GCC_OPTIMIZATION_LEVEL = 0; 148 | GCC_PREPROCESSOR_DEFINITIONS = ( 149 | "DEBUG=1", 150 | "$(inherited)", 151 | ); 152 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 153 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 154 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 155 | GCC_WARN_UNDECLARED_SELECTOR = YES; 156 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 157 | GCC_WARN_UNUSED_FUNCTION = YES; 158 | GCC_WARN_UNUSED_VARIABLE = YES; 159 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 160 | MTL_ENABLE_DEBUG_INFO = YES; 161 | ONLY_ACTIVE_ARCH = YES; 162 | SDKROOT = iphoneos; 163 | }; 164 | name = Debug; 165 | }; 166 | 58B511EE1A9E6C8500147676 /* Release */ = { 167 | isa = XCBuildConfiguration; 168 | buildSettings = { 169 | ALWAYS_SEARCH_USER_PATHS = NO; 170 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 171 | CLANG_CXX_LIBRARY = "libc++"; 172 | CLANG_ENABLE_MODULES = YES; 173 | CLANG_ENABLE_OBJC_ARC = YES; 174 | CLANG_WARN_BOOL_CONVERSION = YES; 175 | CLANG_WARN_CONSTANT_CONVERSION = YES; 176 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 177 | CLANG_WARN_EMPTY_BODY = YES; 178 | CLANG_WARN_ENUM_CONVERSION = YES; 179 | CLANG_WARN_INFINITE_RECURSION = YES; 180 | CLANG_WARN_INT_CONVERSION = YES; 181 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 182 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 183 | CLANG_WARN_UNREACHABLE_CODE = YES; 184 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 185 | COPY_PHASE_STRIP = YES; 186 | ENABLE_NS_ASSERTIONS = NO; 187 | ENABLE_STRICT_OBJC_MSGSEND = YES; 188 | GCC_C_LANGUAGE_STANDARD = gnu99; 189 | GCC_NO_COMMON_BLOCKS = YES; 190 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 191 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 192 | GCC_WARN_UNDECLARED_SELECTOR = YES; 193 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 194 | GCC_WARN_UNUSED_FUNCTION = YES; 195 | GCC_WARN_UNUSED_VARIABLE = YES; 196 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 197 | MTL_ENABLE_DEBUG_INFO = NO; 198 | SDKROOT = iphoneos; 199 | VALIDATE_PRODUCT = YES; 200 | }; 201 | name = Release; 202 | }; 203 | 58B511F01A9E6C8500147676 /* Debug */ = { 204 | isa = XCBuildConfiguration; 205 | buildSettings = { 206 | HEADER_SEARCH_PATHS = ( 207 | "$(inherited)", 208 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 209 | "$(SRCROOT)/../../../React/**", 210 | "$(SRCROOT)/../../react-native/React/**", 211 | ); 212 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 213 | OTHER_LDFLAGS = "-ObjC"; 214 | PRODUCT_NAME = RNNavybitsDateTimePicker; 215 | SKIP_INSTALL = YES; 216 | }; 217 | name = Debug; 218 | }; 219 | 58B511F11A9E6C8500147676 /* Release */ = { 220 | isa = XCBuildConfiguration; 221 | buildSettings = { 222 | HEADER_SEARCH_PATHS = ( 223 | "$(inherited)", 224 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 225 | "$(SRCROOT)/../../../React/**", 226 | "$(SRCROOT)/../../react-native/React/**", 227 | ); 228 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 229 | OTHER_LDFLAGS = "-ObjC"; 230 | PRODUCT_NAME = RNNavybitsDateTimePicker; 231 | SKIP_INSTALL = YES; 232 | }; 233 | name = Release; 234 | }; 235 | /* End XCBuildConfiguration section */ 236 | 237 | /* Begin XCConfigurationList section */ 238 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNNavybitsDateTimePicker" */ = { 239 | isa = XCConfigurationList; 240 | buildConfigurations = ( 241 | 58B511ED1A9E6C8500147676 /* Debug */, 242 | 58B511EE1A9E6C8500147676 /* Release */, 243 | ); 244 | defaultConfigurationIsVisible = 0; 245 | defaultConfigurationName = Release; 246 | }; 247 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNNavybitsDateTimePicker" */ = { 248 | isa = XCConfigurationList; 249 | buildConfigurations = ( 250 | 58B511F01A9E6C8500147676 /* Debug */, 251 | 58B511F11A9E6C8500147676 /* Release */, 252 | ); 253 | defaultConfigurationIsVisible = 0; 254 | defaultConfigurationName = Release; 255 | }; 256 | /* End XCConfigurationList section */ 257 | }; 258 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 259 | } 260 | -------------------------------------------------------------------------------- /ios/RNNavybitsDateTimePicker.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | 3 | 5 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "react-native-navybits-date-time-picker", 4 | "version": "1.2.3", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "react-native" 12 | ], 13 | "homepage": "https://github.com/HananeAlSamrout/react-native-navybits-date-time-picker", 14 | "author": "Hanane AL SAMROUT", 15 | "license": "MIT", 16 | "peerDependencies": { 17 | "react-native": "^0.41.2", 18 | "react-native-windows": "0.41.0-rc.1" 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /styles.js: -------------------------------------------------------------------------------- 1 | import { Dimensions, StyleSheet } from "react-native"; 2 | let screenHeight = Dimensions.get("window").height; 3 | let screenWidth = Dimensions.get("window").width; 4 | 5 | module.exports = StyleSheet.create({ 6 | title: { 7 | textAlign: "center", 8 | marginTop: 20 9 | }, 10 | itemStyle: { 11 | color: "red" 12 | }, 13 | datePickerIOS: { 14 | height: 216 15 | }, 16 | datePickerMask: { 17 | flex: 1, 18 | alignItems: "center", 19 | flexDirection: "row", 20 | backgroundColor: "rgba(0,0,0,0.5)", 21 | justifyContent: "center" 22 | }, 23 | containerModal: { 24 | backgroundColor: "transparent", 25 | borderRadius: 10, 26 | alignSelf: "center", 27 | flex: 1 28 | }, 29 | closeGallery: { 30 | position: "absolute", 31 | top: 20, 32 | right: 10, 33 | padding: 10, 34 | zIndex: 5, 35 | backgroundColor: "transparent" 36 | }, 37 | dateTouch: { 38 | width: 142 39 | }, 40 | dateTouchBody: { 41 | flexDirection: "row", 42 | height: 40, 43 | alignItems: "center", 44 | justifyContent: "center" 45 | }, 46 | dateIcon: { 47 | width: 32, 48 | height: 32, 49 | marginLeft: 5, 50 | marginRight: 5 51 | }, 52 | dateInput: { 53 | flex: 1, 54 | height: 40, 55 | borderWidth: 1, 56 | borderColor: "#aaa", 57 | alignItems: "center", 58 | justifyContent: "center" 59 | }, 60 | dateText: { 61 | color: "#333" 62 | }, 63 | placeholderText: { 64 | color: "#c9c9c9" 65 | }, 66 | datePickerMask: { 67 | flex: 1, 68 | alignItems: "flex-end", 69 | flexDirection: "row", 70 | backgroundColor: "#00000077" 71 | }, 72 | datePickerCon: { 73 | backgroundColor: "#fff", 74 | height: 0, 75 | overflow: "hidden" 76 | }, 77 | btnsView: { 78 | height: 42, 79 | // backgroundColor:'red', 80 | flexDirection: "row", 81 | justifyContent: "space-between", 82 | padding: 10 83 | }, 84 | titleWrapper: { 85 | // position: "absolute" 86 | //flex: 1, 87 | alignItems: "center", 88 | justifyContent: "center", 89 | alignSelf: "center" 90 | }, 91 | title: { 92 | fontSize: 16, 93 | fontWeight: "bold" 94 | }, 95 | btnText: { 96 | position: "absolute", 97 | top: 0, 98 | height: 42, 99 | paddingHorizontal: 20, 100 | flexDirection: "row", 101 | alignItems: "center", 102 | justifyContent: "center" 103 | }, 104 | btnTextText: { 105 | fontSize: 16, 106 | color: "green" 107 | }, 108 | btnTextCancel: { 109 | color: "red" 110 | }, 111 | btnCancel: { 112 | flex: 1, 113 | alignItems:'flex-start' 114 | }, 115 | btnConfirm: { 116 | flex:1, 117 | alignItems:'flex-end' 118 | }, 119 | datePicker: { 120 | // marginTop: 42, 121 | borderTopColor: "#ccc", 122 | borderTopWidth: 1 123 | }, 124 | disabled: { 125 | backgroundColor: "#eee" 126 | } 127 | }); 128 | --------------------------------------------------------------------------------