com.hijridatepicker.HijriDatePickerAndroidModule.java Source code

Java tutorial

Introduction

Here is the source code for com.hijridatepicker.HijriDatePickerAndroidModule.java

Source

package com.hijridatepicker;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.widget.DatePicker;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.github.msarhan.ummalqura.calendar.UmmalquraCalendar;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.PatternSyntaxException;

public class HijriDatePickerAndroidModule extends ReactContextBaseJavaModule {
    private static final String REACT_CLASS = "HijriDatePickerAndroid";

    public static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
    public static final String ERROR_OPEN = "E_OPEN";
    public static final String ERROR_PARSING_OPTIONS = "E_PARSING_OPTIONS";
    private static final String ERROR_CONVERT = "E_CONVERT";

    private static final String ACTION_DATE_SET = "dateSetAction";
    private static final String ACTION_DISMISSED = "dismissedAction";

    private static final String FRAGMENT_TAG = "DatePickerAndroid";
    static final String ARG_DATE = "date";
    static final String ARG_MINDATE = "minDate";
    static final String ARG_MAXDATE = "maxDate";
    static final String ARG_WEEK_DAY_LABELS = "weekDayLabels";
    public static final String ARG_MODE = "mode";

    public HijriDatePickerAndroidModule(final ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return REACT_CLASS;
    }

    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        Map<String, Object> constants = new HashMap<>();
        constants.put(ACTION_DATE_SET, ACTION_DATE_SET);
        constants.put(ACTION_DISMISSED, ACTION_DISMISSED);
        constants.put(ERROR_NO_ACTIVITY, ERROR_NO_ACTIVITY);
        constants.put(ERROR_OPEN, ERROR_OPEN);
        constants.put(ERROR_CONVERT, ERROR_CONVERT);
        constants.put(ERROR_PARSING_OPTIONS, ERROR_PARSING_OPTIONS);
        return constants;
    }

    /**
     * Copyright (c) 2015-present, Facebook, Inc.
     * All rights reserved.
     * <p>
     * This source code is licensed under the BSD-style license found in the
     * LICENSE file in the root directory of this source tree. An additional grant
     * of patent rights can be found in the PATENTS file in the same directory.
     * Show a date picker dialog.
     *
     * @param options a map containing options. Available keys are:
     *                <p>
     *                <ul>
     *                <li>{@code date} (timestamp in milliseconds) the date to show by default</li>
     *                <li>
     *                {@code minDate} (timestamp in milliseconds) the minimum date the user should be allowed
     *                to select
     *                </li>
     *                <li>
     *                {@code maxDate} (timestamp in milliseconds) the maximum date the user should be allowed
     *                to select
     *                </li>
     *                <li>
     *                {@code mode} To set the date picker mode to ' no_arrows/default' ,
     *                currently there's only one mode for HijriDatePicker, so this field works only with mode no_arrows/default
     *                </li>
     *                <li>
     *                {@code weekDayLabels} (array of strings) the day labels that appears on the calendar
     *                </li>
     *                </ul>
     * @param promise This will be invoked with parameters action, year,
     *                month (0-11), day, where action is {@code dateSetAction} or
     *                {@code dismissedAction}, depending on what the user did. If the action is
     *                dismiss, year, month and date are undefined.
     */
    @ReactMethod
    public void open(@Nullable final ReadableMap options, Promise promise) {
        try {
            Activity activity = getCurrentActivity();
            if (activity == null) {
                promise.reject(ERROR_NO_ACTIVITY,
                        "Tried to open a DatePicker dialog while not attached to an Activity");
                return;
            }
            // We want to support both android.app.Activity and the pre-Honeycomb FragmentActivity
            // (for apps that use it for legacy reasons). This unfortunately leads to some code duplication.
            if (activity instanceof android.support.v4.app.FragmentActivity) {
                android.support.v4.app.FragmentManager fragmentManager = ((android.support.v4.app.FragmentActivity) activity)
                        .getSupportFragmentManager();
                android.support.v4.app.DialogFragment oldFragment = (android.support.v4.app.DialogFragment) fragmentManager
                        .findFragmentByTag(FRAGMENT_TAG);
                if (oldFragment != null) {
                    oldFragment.dismiss();
                }
                SupportHijriDatePickerDialogFragment fragment = new SupportHijriDatePickerDialogFragment();
                if (options != null) {
                    final Bundle args = createFragmentArguments(options, promise);
                    if (args == null)
                        return;
                    fragment.setArguments(args);
                }
                final DatePickerDialogListener listener = new DatePickerDialogListener(promise);
                fragment.setOnDismissListener(listener);
                fragment.setOnDateSetListener(listener);
                fragment.setOnExceptionListener(listener);
                fragment.show(fragmentManager, FRAGMENT_TAG);
            } else {
                FragmentManager fragmentManager = activity.getFragmentManager();
                DialogFragment oldFragment = (DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
                if (oldFragment != null) {
                    oldFragment.dismiss();
                }
                HijriDatePickerDialogFragment fragment = new HijriDatePickerDialogFragment();
                if (options != null) {
                    final Bundle args = createFragmentArguments(options, promise);
                    if (args == null)
                        return;
                    fragment.setArguments(args);
                }
                final DatePickerDialogListener listener = new DatePickerDialogListener(promise);
                fragment.setOnDismissListener(listener);
                fragment.setOnDateSetListener(listener);
                fragment.setOnExceptionListener(listener);
                fragment.show(fragmentManager, FRAGMENT_TAG);
            }
        } catch (Exception e) {
            promise.reject(ERROR_OPEN,
                    "Exception happened while executing open method, details: " + e.getMessage());
        }
    }

    private Bundle createFragmentArguments(ReadableMap options, Promise promise) {
        final Bundle args = new Bundle();
        try {
            if (options.hasKey(ARG_DATE) && !options.isNull(ARG_DATE)) {
                if (!parseOptionsWithKey(ARG_DATE, options, args, promise))
                    return null;
            }
            if (options.hasKey(ARG_MINDATE) && !options.isNull(ARG_MINDATE)) {
                if (!parseOptionsWithKey(ARG_MINDATE, options, args, promise))
                    return null;
            }
            if (options.hasKey(ARG_MAXDATE) && !options.isNull(ARG_MAXDATE)) {
                if (!parseOptionsWithKey(ARG_MAXDATE, options, args, promise))
                    return null;
            }
            if (options.hasKey(ARG_MODE) && !options.isNull(ARG_MODE)) {
                args.putString(ARG_MODE, options.getString(ARG_MODE));
            }
            if (options.hasKey(ARG_WEEK_DAY_LABELS) && !options.isNull(ARG_WEEK_DAY_LABELS)) {
                args.putStringArrayList(ARG_WEEK_DAY_LABELS,
                        toStringArrayList(options.getArray(ARG_WEEK_DAY_LABELS)));
            }
        } catch (Exception e) {
            promise.reject(ERROR_PARSING_OPTIONS,
                    "Exception happened while parsing options, details: " + e.getMessage());
            return null;
        }
        return args;
    }

    private ArrayList<String> toStringArrayList(ReadableArray readableArray) {
        ArrayList<String> stringList = new ArrayList<>();
        for (int i = 0; i < readableArray.size(); i++) {
            stringList.add(readableArray.getString(i));
        }
        return stringList;
    }

    private boolean parseOptionsWithKey(String ARG_KEY, ReadableMap options, Bundle args, Promise promise) {
        ReadableType argDateType = options.getType(ARG_KEY);
        if (ReadableType.String.equals(argDateType)) {
            try {
                long milliSeconds = 0;
                milliSeconds = (long) convertHijriDateToGregorianMilliseconds(options.getString(ARG_KEY));
                args.putLong(ARG_KEY, milliSeconds);
                return true;
            } catch (PatternSyntaxException | IndexOutOfBoundsException | NumberFormatException e) {
                promise.reject(ERROR_PARSING_OPTIONS, "Exception happened while parsing " + ARG_KEY
                        + " we only accept object of Date or String with the format \"dd-MM-yyyy\" in Hijri");
                return false;
            }
        } else if (ReadableType.Number.equals(argDateType)) {
            args.putLong(ARG_KEY, (long) options.getDouble(ARG_KEY));
            return true;
        } else {
            promise.reject(ERROR_PARSING_OPTIONS, "Exception happened while parsing " + ARG_KEY
                    + " we only accept object of Date or String with the format \"dd-MM-yyyy\" in Hijri");
            return false;
        }
    }

    /**
     * @param hijriDate must be at the format dd-MM-yyyy
     * @return milliseconds of Gregorian equivalent to the given hijriDate
     */
    public double convertHijriDateToGregorianMilliseconds(String hijriDate) {
        UmmalquraCalendar ummalquraCalendar = new UmmalquraCalendar();

        int year = Integer.parseInt(hijriDate.split("-")[2]);
        int monthOfYear = Integer.parseInt(hijriDate.split("-")[1]);
        int dayOfMonth = Integer.parseInt(hijriDate.split("-")[0]);

        ummalquraCalendar.set(UmmalquraCalendar.YEAR, year);
        ummalquraCalendar.set(UmmalquraCalendar.MONTH, monthOfYear - 1);
        ummalquraCalendar.set(UmmalquraCalendar.DAY_OF_MONTH, dayOfMonth);

        return ummalquraCalendar.getTime().getTime();
    }

    @ReactMethod
    public void convertHijriDateStrToGregorianMilliseconds(String hijriDate, Promise promise) {
        try {
            double milliseconds = convertHijriDateToGregorianMilliseconds(hijriDate);
            promise.resolve(milliseconds);
        } catch (Exception e) {
            promise.reject(ERROR_CONVERT,
                    "Exception while executing convertHijriDateStrToGregorianMilliseconds, Details: "
                            + e.getMessage());

        }
    }

    /**
     * @param milliseconds your gregorian date in milliseconds
     * @return hijri date at the format of "dd-MM-yyyy"
     */
    @ReactMethod
    public void convertMillisecondsToHijriDate(double milliseconds, Promise promise) {

        try {
            UmmalquraCalendar ummalquraCalendar = new UmmalquraCalendar();
            ummalquraCalendar.setTimeInMillis((long) milliseconds);
            WritableMap result = new WritableNativeMap();
            result.putInt("year", ummalquraCalendar.get(Calendar.YEAR));
            result.putInt("month", ummalquraCalendar.get(Calendar.MONTH));
            result.putInt("day", ummalquraCalendar.get(Calendar.DAY_OF_MONTH));
            promise.resolve(result);
        } catch (Exception e) {
            promise.reject(ERROR_CONVERT,
                    "Exception while executing convertMillisecondsToHijriDate, Details: " + e.getMessage());
        }
    }

    public interface OnExceptionListener {
        void onException(String code, String message);
    }

    /**
     * Copyright (c) 2015-present, Facebook, Inc.
     * All rights reserved.
     * <p>
     * This source code is licensed under the BSD-style license found in the
     * LICENSE file in the root directory of this source tree. An additional grant
     * of patent rights can be found in the PATENTS file in the same directory.
     */
    private class DatePickerDialogListener
            implements DatePickerDialog.OnDateSetListener, DialogInterface.OnDismissListener, OnExceptionListener {

        private final Promise mPromise;
        private boolean mPromiseResolved = false;

        public DatePickerDialogListener(final Promise promise) {
            mPromise = promise;
        }

        @Override
        public void onDateSet(DatePicker ignored, int year, int month, int day) {
            if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
                WritableMap result = new WritableNativeMap();
                result.putString("action", ACTION_DATE_SET);
                result.putInt("year", year);
                result.putInt("month", month);
                result.putInt("day", day);
                mPromise.resolve(result);
                mPromiseResolved = true;
            }
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
                WritableMap result = new WritableNativeMap();
                result.putString("action", ACTION_DISMISSED);
                mPromise.resolve(result);
                mPromiseResolved = true;
            }
        }

        @Override
        public void onException(String code, String message) {
            if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
                mPromise.reject(code, message);
                mPromiseResolved = true;
            }
        }
    }
}