├── README.md
├── android
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── hijridatepicker
│ │ ├── HijriDatePickerAndroidModule.java
│ │ ├── HijriDatePickerDialogFragment.java
│ │ ├── HijriDialogViewManagerPackage.java
│ │ └── SupportHijriDatePickerDialogFragment.java
│ └── res
│ ├── layout
│ └── dialog_basic.xml
│ ├── values-ar
│ └── strings.xml
│ └── values
│ └── strings.xml
├── index.android.js
├── index.ios.js
└── package.json
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # react-native-hijri-date-picker-android
3 | [](http://www.codelabsys.com/)
4 |
5 |
6 | #This Module version is experimental, if you found any issues, kindly submit.
7 |
8 | ## Getting started
9 | ### Versions
10 | For React Native >= 0.47.0 use v2.+
11 | For React Native < 0.47.0 use v1.0.8
12 |
13 | ### Installing
14 | [](https://nodei.co/npm/react-native-hijri-date-picker-android/)
15 |
16 | `$ npm install react-native-hijri-date-picker-android --save`
17 |
18 | ### Mostly automatic installation
19 |
20 | `$ react-native link react-native-hijri-date-picker-android`
21 |
22 | ### Manual installation
23 |
24 | #### Android
25 |
26 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java`
27 | - Add `import com.reactlibrary.HijriDatePickerAndroidPackage;` to the imports at the top of the file
28 | - Add `new HijriDatePickerAndroidPackage()` to the list returned by the `getPackages()` method
29 | 2. Append the following lines to `android/settings.gradle`:
30 | ```
31 | include ':react-native-hijri-date-picker-android'
32 | project(':react-native-hijri-date-picker-android').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-hijri-date-picker-android/android')
33 | ```
34 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
35 | ```
36 | compile project(':react-native-hijri-date-picker-android')
37 | ```
38 |
39 |
40 | ## Usage
41 | ```javascript
42 | //first include HijriDatePickerAndroid
43 | import HijriDatePickerAndroid from "react-native-hijri-date-picker-android";
44 |
45 |
46 | let options = { date: new Date(), minDate: new Date(new Date().getTime() - (1 * 30 * 24 * 60 * 60 * 1000)), maxDate: new Date(new Date().getTime() + (1 * 30 * 24 * 60 * 60 * 1000)) };
47 | let stringOptions = { date: "27-7-1438", minDate: "25-6-1438", maxDate: "29-8-1438" };
48 | //mode:"no_arrows" hide the arrows at the bar of the calendar
49 | //weekDayLabels, override the default day labels at the calendar
50 | let moreOptions = { date: "27-7-1438", minDate: "25-6-1438", maxDate: "29-8-1438", mode:"no_arrows", weekDayLabels:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]};
51 | //accepts option dates with date objects or strings in the following format ['dd-MM-yyyy']
52 | HijriDatePickerAndroid.open(stringOptions).then(function (result) {
53 | if (result.action == HijriDatePickerAndroid.dismissedAction) {
54 | console.warn("Dismissed");
55 | } else {
56 | let { year, day, month } = result;
57 | console.warn("Hijri Date: " + day + "/" +( month + 1) + "/" + year + "/");
58 | }
59 | });
60 |
61 | //convert string Hijri date ['dd-MM-yyyy'] to a gregorian timestamp
62 | HijriDatePickerAndroid.convertHijriDateToGregorianDate("12-7-1438").then(function (result) {
63 | console.warn("Gregorian Timestamp" + JSON.stringify(result));
64 |
65 | });
66 |
67 |
68 | //convert gregorian date object to hijri {year,month,day}
69 | HijriDatePickerAndroid.convertGregorianDateToHijriDate(new Date()).then(function ({ year, day, month }) {
70 | console.warn("Hijri Date: " + day + "/" + month + 1 + "/" + year + "/");
71 |
72 | ```
73 |
74 | ## For IOS
75 |
76 | Check out our IOS project [react-native-universal-datepicker-ios](https://github.com/Codelabsys/react-native-universal-datepicker-ios)
77 |
78 |
79 | ## Credits
80 |
81 | This project was made by the help of [Assem-Hafez](https://github.com/Assem-Hafez) and [Mohamed-Abbas](https://github.com/Mohamed-Abbas)
82 | for the company we're working at [Codelabsys](http://www.codelabsys.com/)
83 |
84 | And is based on the following projects, [material-hijri-calendarview](https://github.com/eltohamy/material-hijri-calendarview) and [ummalqura-calendar](https://github.com/msarhan/ummalqura-calendar)
85 |
--------------------------------------------------------------------------------
/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 23
16 | buildToolsVersion "23.0.1"
17 |
18 | defaultConfig {
19 | minSdkVersion 16
20 | targetSdkVersion 22
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.facebook.react:react-native:+'
35 | compile 'com.github.eltohamy:material-hijri-calendarview:1.1.0@aar'
36 | compile group: 'com.github.msarhan', name: 'ummalqura-calendar', version:'1.1.7'
37 | }
38 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/src/main/java/com/hijridatepicker/HijriDatePickerAndroidModule.java:
--------------------------------------------------------------------------------
1 | package com.hijridatepicker;
2 |
3 |
4 | import android.app.Activity;
5 | import android.app.DatePickerDialog;
6 | import android.app.DialogFragment;
7 | import android.app.FragmentManager;
8 | import android.content.DialogInterface;
9 | import android.os.Bundle;
10 | import android.support.annotation.Nullable;
11 | import android.widget.DatePicker;
12 |
13 | import com.facebook.react.bridge.Promise;
14 | import com.facebook.react.bridge.ReactApplicationContext;
15 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
16 | import com.facebook.react.bridge.ReactMethod;
17 | import com.facebook.react.bridge.ReadableArray;
18 | import com.facebook.react.bridge.ReadableMap;
19 | import com.facebook.react.bridge.ReadableType;
20 | import com.facebook.react.bridge.WritableMap;
21 | import com.facebook.react.bridge.WritableNativeMap;
22 | import com.github.msarhan.ummalqura.calendar.UmmalquraCalendar;
23 |
24 | import java.util.ArrayList;
25 | import java.util.Calendar;
26 | import java.util.HashMap;
27 | import java.util.Map;
28 | import java.util.regex.PatternSyntaxException;
29 |
30 | public class HijriDatePickerAndroidModule extends ReactContextBaseJavaModule {
31 | private static final String REACT_CLASS = "HijriDatePickerAndroid";
32 |
33 | public static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
34 | public static final String ERROR_OPEN = "E_OPEN";
35 | public static final String ERROR_PARSING_OPTIONS = "E_PARSING_OPTIONS";
36 | private static final String ERROR_CONVERT = "E_CONVERT";
37 |
38 | private static final String ACTION_DATE_SET = "dateSetAction";
39 | private static final String ACTION_DISMISSED = "dismissedAction";
40 |
41 | private static final String FRAGMENT_TAG = "DatePickerAndroid";
42 | static final String ARG_DATE = "date";
43 | static final String ARG_MINDATE = "minDate";
44 | static final String ARG_MAXDATE = "maxDate";
45 | static final String ARG_WEEK_DAY_LABELS = "weekDayLabels";
46 | public static final String ARG_MODE = "mode";
47 |
48 |
49 | public HijriDatePickerAndroidModule(final ReactApplicationContext reactContext) {
50 | super(reactContext);
51 | }
52 |
53 | @Override
54 | public String getName() {
55 | return REACT_CLASS;
56 | }
57 |
58 | @Nullable
59 | @Override
60 | public Map getConstants() {
61 | Map constants = new HashMap<>();
62 | constants.put(ACTION_DATE_SET, ACTION_DATE_SET);
63 | constants.put(ACTION_DISMISSED, ACTION_DISMISSED);
64 | constants.put(ERROR_NO_ACTIVITY, ERROR_NO_ACTIVITY);
65 | constants.put(ERROR_OPEN, ERROR_OPEN);
66 | constants.put(ERROR_CONVERT, ERROR_CONVERT);
67 | constants.put(ERROR_PARSING_OPTIONS, ERROR_PARSING_OPTIONS);
68 | return constants;
69 | }
70 |
71 | /**
72 | * Copyright (c) 2015-present, Facebook, Inc.
73 | * All rights reserved.
74 | *
75 | * This source code is licensed under the BSD-style license found in the
76 | * LICENSE file in the root directory of this source tree. An additional grant
77 | * of patent rights can be found in the PATENTS file in the same directory.
78 | * Show a date picker dialog.
79 | *
80 | * @param options a map containing options. Available keys are:
81 | *
82 | *
83 | *
{@code date} (timestamp in milliseconds) the date to show by default
84 | *
85 | * {@code minDate} (timestamp in milliseconds) the minimum date the user should be allowed
86 | * to select
87 | *
88 | *
89 | * {@code maxDate} (timestamp in milliseconds) the maximum date the user should be allowed
90 | * to select
91 | *
92 | *
93 | * {@code mode} To set the date picker mode to ' no_arrows/default' ,
94 | * currently there's only one mode for HijriDatePicker, so this field works only with mode no_arrows/default
95 | *
96 | *
97 | * {@code weekDayLabels} (array of strings) the day labels that appears on the calendar
98 | *
99 | *
100 | * @param promise This will be invoked with parameters action, year,
101 | * month (0-11), day, where action is {@code dateSetAction} or
102 | * {@code dismissedAction}, depending on what the user did. If the action is
103 | * dismiss, year, month and date are undefined.
104 | */
105 | @ReactMethod
106 | public void open(@Nullable final ReadableMap options, Promise promise) {
107 | try {
108 | Activity activity = getCurrentActivity();
109 | if (activity == null) {
110 | promise.reject(ERROR_NO_ACTIVITY, "Tried to open a DatePicker dialog while not attached to an Activity");
111 | return;
112 | }
113 | // We want to support both android.app.Activity and the pre-Honeycomb FragmentActivity
114 | // (for apps that use it for legacy reasons). This unfortunately leads to some code duplication.
115 | if (activity instanceof android.support.v4.app.FragmentActivity) {
116 | android.support.v4.app.FragmentManager fragmentManager = ((android.support.v4.app.FragmentActivity) activity).getSupportFragmentManager();
117 | android.support.v4.app.DialogFragment oldFragment = (android.support.v4.app.DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
118 | if (oldFragment != null) {
119 | oldFragment.dismiss();
120 | }
121 | SupportHijriDatePickerDialogFragment fragment = new SupportHijriDatePickerDialogFragment();
122 | if (options != null) {
123 | final Bundle args = createFragmentArguments(options, promise);
124 | if (args == null)
125 | return;
126 | fragment.setArguments(args);
127 | }
128 | final DatePickerDialogListener listener = new DatePickerDialogListener(promise);
129 | fragment.setOnDismissListener(listener);
130 | fragment.setOnDateSetListener(listener);
131 | fragment.setOnExceptionListener(listener);
132 | fragment.show(fragmentManager, FRAGMENT_TAG);
133 | } else {
134 | FragmentManager fragmentManager = activity.getFragmentManager();
135 | DialogFragment oldFragment = (DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
136 | if (oldFragment != null) {
137 | oldFragment.dismiss();
138 | }
139 | HijriDatePickerDialogFragment fragment = new HijriDatePickerDialogFragment();
140 | if (options != null) {
141 | final Bundle args = createFragmentArguments(options, promise);
142 | if (args == null)
143 | return;
144 | fragment.setArguments(args);
145 | }
146 | final DatePickerDialogListener listener = new DatePickerDialogListener(promise);
147 | fragment.setOnDismissListener(listener);
148 | fragment.setOnDateSetListener(listener);
149 | fragment.setOnExceptionListener(listener);
150 | fragment.show(fragmentManager, FRAGMENT_TAG);
151 | }
152 | } catch (Exception e) {
153 | promise.reject(ERROR_OPEN, "Exception happened while executing open method, details: " + e.getMessage());
154 | }
155 | }
156 |
157 | private Bundle createFragmentArguments(ReadableMap options, Promise promise) {
158 | final Bundle args = new Bundle();
159 | try {
160 | if (options.hasKey(ARG_DATE) && !options.isNull(ARG_DATE)) {
161 | if (!parseOptionsWithKey(ARG_DATE, options, args, promise))
162 | return null;
163 | }
164 | if (options.hasKey(ARG_MINDATE) && !options.isNull(ARG_MINDATE)) {
165 | if (!parseOptionsWithKey(ARG_MINDATE, options, args, promise))
166 | return null;
167 | }
168 | if (options.hasKey(ARG_MAXDATE) && !options.isNull(ARG_MAXDATE)) {
169 | if (!parseOptionsWithKey(ARG_MAXDATE, options, args, promise))
170 | return null;
171 | }
172 | if (options.hasKey(ARG_MODE) && !options.isNull(ARG_MODE)) {
173 | args.putString(ARG_MODE, options.getString(ARG_MODE));
174 | }
175 | if (options.hasKey(ARG_WEEK_DAY_LABELS) && !options.isNull(ARG_WEEK_DAY_LABELS)) {
176 | args.putStringArrayList(ARG_WEEK_DAY_LABELS, toStringArrayList(options.getArray(ARG_WEEK_DAY_LABELS)));
177 | }
178 | } catch (Exception e) {
179 | promise.reject(ERROR_PARSING_OPTIONS, "Exception happened while parsing options, details: " + e.getMessage());
180 | return null;
181 | }
182 | return args;
183 | }
184 |
185 | private ArrayList toStringArrayList(ReadableArray readableArray) {
186 | ArrayList stringList = new ArrayList<>();
187 | for (int i = 0; i < readableArray.size(); i++) {
188 | stringList.add(readableArray.getString(i));
189 | }
190 | return stringList;
191 | }
192 |
193 | private boolean parseOptionsWithKey(String ARG_KEY, ReadableMap options, Bundle args, Promise promise) {
194 | ReadableType argDateType = options.getType(ARG_KEY);
195 | if (ReadableType.String.equals(argDateType)) {
196 | try {
197 | long milliSeconds = 0;
198 | milliSeconds = (long) convertHijriDateToGregorianMilliseconds(options.getString(ARG_KEY));
199 | args.putLong(ARG_KEY, milliSeconds);
200 | return true;
201 | } catch (PatternSyntaxException | IndexOutOfBoundsException | NumberFormatException e) {
202 | promise.reject(ERROR_PARSING_OPTIONS, "Exception happened while parsing " + ARG_KEY +
203 | " we only accept object of Date or String with the format \"dd-MM-yyyy\" in Hijri");
204 | return false;
205 | }
206 | } else if (ReadableType.Number.equals(argDateType)) {
207 | args.putLong(ARG_KEY, (long) options.getDouble(ARG_KEY));
208 | return true;
209 | } else {
210 | promise.reject(ERROR_PARSING_OPTIONS, "Exception happened while parsing " + ARG_KEY +
211 | " we only accept object of Date or String with the format \"dd-MM-yyyy\" in Hijri");
212 | return false;
213 | }
214 | }
215 |
216 | /**
217 | * @param hijriDate must be at the format dd-MM-yyyy
218 | * @return milliseconds of Gregorian equivalent to the given hijriDate
219 | */
220 | public double convertHijriDateToGregorianMilliseconds(String hijriDate) {
221 | UmmalquraCalendar ummalquraCalendar = new UmmalquraCalendar();
222 |
223 | int year = Integer.parseInt(hijriDate.split("-")[2]);
224 | int monthOfYear = Integer.parseInt(hijriDate.split("-")[1]);
225 | int dayOfMonth = Integer.parseInt(hijriDate.split("-")[0]);
226 |
227 | ummalquraCalendar.set(UmmalquraCalendar.YEAR, year);
228 | ummalquraCalendar.set(UmmalquraCalendar.MONTH, monthOfYear - 1);
229 | ummalquraCalendar.set(UmmalquraCalendar.DAY_OF_MONTH, dayOfMonth);
230 |
231 | return ummalquraCalendar.getTime().getTime();
232 | }
233 |
234 | @ReactMethod
235 | public void convertHijriDateStrToGregorianMilliseconds(String hijriDate, Promise promise) {
236 | try {
237 | double milliseconds = convertHijriDateToGregorianMilliseconds(hijriDate);
238 | promise.resolve(milliseconds);
239 | } catch (Exception e) {
240 | promise.reject(ERROR_CONVERT, "Exception while executing convertHijriDateStrToGregorianMilliseconds, Details: " + e.getMessage());
241 |
242 | }
243 | }
244 |
245 | /**
246 | * @param milliseconds your gregorian date in milliseconds
247 | * @return hijri date at the format of "dd-MM-yyyy"
248 | */
249 | @ReactMethod
250 | public void convertMillisecondsToHijriDate(double milliseconds, Promise promise) {
251 |
252 | try {
253 | UmmalquraCalendar ummalquraCalendar = new UmmalquraCalendar();
254 | ummalquraCalendar.setTimeInMillis((long) milliseconds);
255 | WritableMap result = new WritableNativeMap();
256 | result.putInt("year", ummalquraCalendar.get(Calendar.YEAR));
257 | result.putInt("month", ummalquraCalendar.get(Calendar.MONTH));
258 | result.putInt("day", ummalquraCalendar.get(Calendar.DAY_OF_MONTH));
259 | promise.resolve(result);
260 | } catch (Exception e) {
261 | promise.reject(ERROR_CONVERT, "Exception while executing convertMillisecondsToHijriDate, Details: " + e.getMessage());
262 | }
263 | }
264 |
265 |
266 | public interface OnExceptionListener {
267 | void onException(String code, String message);
268 | }
269 |
270 | /**
271 | * Copyright (c) 2015-present, Facebook, Inc.
272 | * All rights reserved.
273 | *