com.facebook.react.bridge.ReadableMap#getArray ( )源码实例Demo

下面列出了com.facebook.react.bridge.ReadableMap#getArray ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。

private TextTemplate createTextTemplate(ReadableMap options) {
  TextTemplate.Builder textTemplate = TextTemplate.newBuilder(
    options.getString("text"),
    createLinkObject(options.getMap("link"))
  );

  String buttonTitle = options.getString("buttonTitle");
  if (buttonTitle != null) {
    textTemplate.setButtonTitle(buttonTitle);
  }

  //add buttons
  ReadableArray buttons = options.getArray("buttons");
  if (buttons != null) {
    for (int i = 0; i < buttons.size(); i++) {
      textTemplate.addButton(createButtonObject(buttons.getMap(i)));
    }
  }
  return textTemplate.build();
}
 
private LocationTemplate createLocationTemplate(ReadableMap options) {
  LocationTemplate.Builder locationTemplate = LocationTemplate.newBuilder(
    options.getString("address"),
    createContentObject(options.getMap("content"))
  );

  String addressTitle = options.getString("addressTitle");
  if (addressTitle != null) {
    locationTemplate.setAddressTitle(addressTitle);
  }

  ReadableMap social = options.getMap("social");
  if (social != null) {
    locationTemplate.setSocial(createSocialObject(social));
  }

  ReadableArray buttons = options.getArray("buttons");
  if (buttons != null) {
    for (int i = 0; i < buttons.size(); i++) {
      locationTemplate.addButton(createButtonObject(buttons.getMap(i)));
    }
  }
  return locationTemplate.build();

}
 
private ListTemplate createListTemplate(ReadableMap options) {
  ListTemplate.Builder listTemplate = ListTemplate.newBuilder(
    options.getString("headerTitle"),
    createLinkObject(options.getMap("headerLink"))
  );

  ReadableArray contents = options.getArray("contents");
  if (contents.size() > 1) {
    for (int i = 0; i < contents.size(); i++) {
      listTemplate.addContent(createContentObject(contents.getMap(i)));
    }
  }

  //add buttons
  ReadableArray buttons = options.getArray("buttons");
  if (buttons.size() > 0) {
    for (int i = 0; i < buttons.size(); i++) {
      listTemplate.addButton(createButtonObject(buttons.getMap(i)));
    }
  }
  return listTemplate.build();
}
 
static private TipSettings buildTipSettings(ReadableMap tipSettingsConfig) {
    TipSettings.Builder tipSettingsBuilder = TipSettings.newBuilder();

    if (tipSettingsConfig.hasKey("showCustomTipField")) {
        tipSettingsBuilder.showCustomTipField(tipSettingsConfig.getBoolean("showCustomTipField"));
    }
    if (tipSettingsConfig.hasKey("showSeparateTipScreen")) {
        tipSettingsBuilder.showSeparateTipScreen(tipSettingsConfig.getBoolean("showSeparateTipScreen"));
    }
    if (tipSettingsConfig.hasKey("tipPercentages")) {
        ReadableArray tipPercentages = tipSettingsConfig.getArray("tipPercentages");
        if (tipPercentages != null) {
            List<Integer> percentagesList = new ArrayList<>();
            for (int i = 0; i < tipPercentages.size(); i++) {
                percentagesList.add(tipPercentages.getInt(i));
            }
            tipSettingsBuilder.tipPercentages(percentagesList);
        }
    }

    return tipSettingsBuilder.build();
}
 
源代码5 项目: react-native-GPay   文件: CameraRollManager.java
/**
 * Get photos from {@link MediaStore.Images}, most recent first.
 *
 * @param params a map containing the following keys:
 *        <ul>
 *          <li>first (mandatory): a number representing the number of photos to fetch</li>
 *          <li>
 *            after (optional): a cursor that matches page_info[end_cursor] returned by a
 *            previous call to {@link #getPhotos}
 *          </li>
 *          <li>groupName (optional): an album name</li>
 *          <li>
 *            mimeType (optional): restrict returned images to a specific mimetype (e.g.
 *            image/jpeg)
 *          </li>
 *          <li>
 *            assetType (optional): chooses between either photos or videos from the camera roll.
 *            Valid values are "Photos" or "Videos". Defaults to photos.
 *          </li>
 *        </ul>
 * @param promise the Promise to be resolved when the photos are loaded; for a format of the
 *        parameters passed to this callback, see {@code getPhotosReturnChecker} in CameraRoll.js
 */
@ReactMethod
public void getPhotos(final ReadableMap params, final Promise promise) {
  int first = params.getInt("first");
  String after = params.hasKey("after") ? params.getString("after") : null;
  String groupName = params.hasKey("groupName") ? params.getString("groupName") : null;
  String assetType = params.hasKey("assetType") ? params.getString("assetType") : null;
  ReadableArray mimeTypes = params.hasKey("mimeTypes")
      ? params.getArray("mimeTypes")
      : null;
  if (params.hasKey("groupTypes")) {
    throw new JSApplicationIllegalArgumentException("groupTypes is not supported on Android");
  }

  new GetPhotosTask(
        getReactApplicationContext(),
        first,
        after,
        groupName,
        mimeTypes,
        assetType,
        promise)
        .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
 
源代码6 项目: google-signin   文件: RNGoogleSigninModule.java
@ReactMethod
public void configure(
        final ReadableMap config,
        final Promise promise
) {
    final ReadableArray scopes = config.hasKey("scopes") ? config.getArray("scopes") : Arguments.createArray();
    final String webClientId = config.hasKey("webClientId") ? config.getString("webClientId") : null;
    final boolean offlineAccess = config.hasKey("offlineAccess") && config.getBoolean("offlineAccess");
    final boolean forceCodeForRefreshToken = config.hasKey("forceCodeForRefreshToken") && config.getBoolean("forceCodeForRefreshToken");
    final String accountName = config.hasKey("accountName") ? config.getString("accountName") : null;
    final String hostedDomain = config.hasKey("hostedDomain") ? config.getString("hostedDomain") : null;

    GoogleSignInOptions options = getSignInOptions(createScopesArray(scopes), webClientId, offlineAccess, forceCodeForRefreshToken, accountName, hostedDomain);
    _apiClient = GoogleSignIn.getClient(getReactApplicationContext(), options);
    promise.resolve(null);
}
 
private void mapGetByType(ReadableMap map, String key, String typeToAskFor) {
  if (typeToAskFor.equals("double")) {
    map.getDouble(key);
  } else if (typeToAskFor.equals("int")) {
    map.getInt(key);
  } else if (typeToAskFor.equals("string")) {
    map.getString(key);
  } else if (typeToAskFor.equals("array")) {
    map.getArray(key);
  } else if (typeToAskFor.equals("map")) {
    map.getMap(key);
  } else if (typeToAskFor.equals("boolean")) {
    map.getBoolean(key);
  } else {
    throw new RuntimeException("Unknown type: " + typeToAskFor);
  }
}
 
源代码8 项目: react-native-bottom-sheet   文件: RNBottomSheet.java
@ReactMethod
public void showBottomSheetWithOptions(ReadableMap options, final Callback onSelect) {
    ReadableArray optionArray = options.getArray("options");
    final Integer cancelButtonIndex = options.getInt("cancelButtonIndex");

    final BottomSheet.Builder builder = new BottomSheet.Builder(this.getCurrentActivity());

    // create options
    Integer size = optionArray.size();
    for (int i = 0; i < size; i++) {
        builder.sheet(i, optionArray.getString(i));
    }

    builder.listener(new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            if (which == cancelButtonIndex) {
                dialog.dismiss();
            } else {
                onSelect.invoke(which);
            }
        }
    });

    UiThreadUtil.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            builder.build().show();
        }
    });
}
 
private CommerceTemplate createCommerceTemplate(ReadableMap options) {
  CommerceTemplate.Builder commerceTemplate = CommerceTemplate.newBuilder(
    createContentObject(options.getMap("content")),
    createCommerceDetailObject(options.getMap("commerce"))
  );

  //add buttons
  ReadableArray buttons = options.getArray("buttons");
  if (buttons != null) {
    for (int i = 0; i < buttons.size(); i++) {
      commerceTemplate.addButton(createButtonObject(buttons.getMap(i)));
    }
  }
  return commerceTemplate.build();
}
 
源代码10 项目: react-native-paged-contacts   文件: Contact.java
private void fillFromContactMap(ReadableMap contactMap) {
    this.name = new Name(contactMap);
    this.organization = new Organization(contactMap);
    this.note = new Note(contactMap);

    ReadableArray _phoneNumbers = contactMap.hasKey(Field.phoneNumbers.getKey()) ? contactMap.getArray(Field.phoneNumbers.getKey()) : new EmptyReadableArray();

    for (int i = 0; i < _phoneNumbers.size(); i++) {
        phoneNumbers.add(new PhoneNumber(_phoneNumbers.getMap(i)));
    }

    ReadableArray _emails = contactMap.hasKey(Field.emailAddresses.getKey()) ? contactMap.getArray(Field.emailAddresses.getKey()) : new EmptyReadableArray();

    for (int i = 0; i < _emails.size(); i++) {
        emails.add(new Email(_emails.getMap(i)));
    }

    ReadableArray _urlAddresses = contactMap.hasKey(Field.urlAddresses.getKey()) ? contactMap.getArray(Field.urlAddresses.getKey()): new EmptyReadableArray();

    for (int i = 0; i < _urlAddresses .size(); i++) {
        urlAddresses.add(new UrlAddress(_urlAddresses.getMap(i)));
    }

    ReadableArray _postalAddresses = contactMap.hasKey(Field.postalAddresses.getKey()) ? contactMap.getArray(Field.postalAddresses.getKey()): new EmptyReadableArray();

    for (int i = 0; i < _postalAddresses.size(); i++) {
        postalAddresses.add(new PostalAddress(_postalAddresses.getMap(i)));
    }
}
 
源代码11 项目: react-native-GPay   文件: AdditionAnimatedNode.java
public AdditionAnimatedNode(
    ReadableMap config,
    NativeAnimatedNodesManager nativeAnimatedNodesManager) {
  mNativeAnimatedNodesManager = nativeAnimatedNodesManager;
  ReadableArray inputNodes = config.getArray("input");
  mInputNodes = new int[inputNodes.size()];
  for (int i = 0; i < mInputNodes.length; i++) {
    mInputNodes[i] = inputNodes.getInt(i);
  }
}
 
public void addAnimatedEventToView(int viewTag, String eventName, ReadableMap eventMapping) {
  int nodeTag = eventMapping.getInt("animatedValueTag");
  AnimatedNode node = mAnimatedNodes.get(nodeTag);
  if (node == null) {
    throw new JSApplicationIllegalArgumentException("Animated node with tag " + nodeTag +
      " does not exists");
  }
  if (!(node instanceof ValueAnimatedNode)) {
    throw new JSApplicationIllegalArgumentException("Animated node connected to event should be" +
      "of type " + ValueAnimatedNode.class.getName());
  }

  ReadableArray path = eventMapping.getArray("nativeEventPath");
  List<String> pathList = new ArrayList<>(path.size());
  for (int i = 0; i < path.size(); i++) {
    pathList.add(path.getString(i));
  }

  EventAnimationDriver event = new EventAnimationDriver(pathList, (ValueAnimatedNode) node);
  String key = viewTag + eventName;
  if (mEventDrivers.containsKey(key)) {
    mEventDrivers.get(key).add(event);
  } else {
    List<EventAnimationDriver> drivers = new ArrayList<>(1);
    drivers.add(event);
    mEventDrivers.put(key, drivers);
  }
}
 
源代码13 项目: react-native-GPay   文件: DivisionAnimatedNode.java
public DivisionAnimatedNode(
    ReadableMap config,
    NativeAnimatedNodesManager nativeAnimatedNodesManager) {
  mNativeAnimatedNodesManager = nativeAnimatedNodesManager;
  ReadableArray inputNodes = config.getArray("input");
  mInputNodes = new int[inputNodes.size()];
  for (int i = 0; i < mInputNodes.length; i++) {
    mInputNodes[i] = inputNodes.getInt(i);
  }
}
 
源代码14 项目: react-native-dialogs   文件: DialogAndroid.java
@ReactMethod
public void list(ReadableMap options, final Callback callback) {
    final MaterialSimpleListAdapter simpleListAdapter = new MaterialSimpleListAdapter(new MaterialSimpleListAdapter.Callback() {
        @Override
        public void onMaterialListItemSelected(MaterialDialog dialog, int index, MaterialSimpleListItem item) {
            if (!mCallbackConsumed) {
                mCallbackConsumed = true;
                callback.invoke(index, item.getContent());
            }
            if (simple != null) {
                simple.dismiss();
            }
        }
    });

    ReadableArray arr = options.getArray("items");
    for(int i = 0; i < arr.size(); i++){
        simpleListAdapter.add(new MaterialSimpleListItem.Builder(getCurrentActivity())
                .content(arr.getString(i))
                .build());
    }

    final MaterialDialog.Builder adapter = new MaterialDialog.Builder(getCurrentActivity())
            .title(options.hasKey("title") ? options.getString("title") : "")
            .adapter(simpleListAdapter, null)
            .autoDismiss(true);

    UiThreadUtil.runOnUiThread(new Runnable() {
        public void run() {
            if (simple != null) {
                simple.dismiss();
            }
            simple = adapter.build();
            simple.show();
        }
    });
}
 
public void testMapParameterWithArrays() throws InterruptedException {
  mCatalystInstance.getJSModule(TestJSToJavaParametersModule.class).returnMapWithArrays();
  waitForBridgeAndUIIdle();

  List<ReadableMap> calls = mRecordingTestModule.getMapCalls();
  assertEquals(1, calls.size());
  ReadableMap map = calls.get(0);
  assertNotNull(map);

  ReadableArray arrayParameter;
  assertTrue(map.hasKey("empty"));
  arrayParameter = map.getArray("empty");
  assertNotNull(arrayParameter);
  assertEquals(0, arrayParameter.size());

  assertTrue(map.hasKey("ints"));
  assertFalse(map.isNull("ints"));
  arrayParameter = map.getArray("ints");
  assertNotNull(arrayParameter);
  assertEquals(2, arrayParameter.size());
  assertEquals(43, arrayParameter.getInt(0));
  assertEquals(44, arrayParameter.getInt(1));

  assertTrue(map.hasKey("mixed"));
  arrayParameter = map.getArray("mixed");
  assertNotNull(arrayParameter);
  assertEquals(3, arrayParameter.size());
  assertEquals(77, arrayParameter.getInt(0));
  assertEquals("string", arrayParameter.getString(1));
  ReadableArray nestedArray = arrayParameter.getArray(2);
  assertEquals(2, nestedArray.size());
}
 
@ReactMethod
public void promptWithArgs(ReadableMap options, final Callback callback) {
    final FragmentManagerHelper fragmentManagerHelper = getFragmentManagerHelper();
    if (fragmentManagerHelper == null) {
        FLog.w(RNPromptModule.class, "Tried to show an alert while not attached to an Activity");
        return;
    }

    final Bundle args = new Bundle();
    if (options.hasKey(KEY_TITLE)) {
        args.putString(RNPromptFragment.ARG_TITLE, options.getString(KEY_TITLE));
    }
    if (options.hasKey(KEY_MESSAGE)) {
        String message = options.getString(KEY_MESSAGE);
        if (!message.isEmpty()) {
            args.putString(RNPromptFragment.ARG_MESSAGE, options.getString(KEY_MESSAGE));
        }
    }
    if (options.hasKey(KEY_BUTTON_POSITIVE)) {
        args.putString(RNPromptFragment.ARG_BUTTON_POSITIVE, options.getString(KEY_BUTTON_POSITIVE));
    }
    if (options.hasKey(KEY_BUTTON_NEGATIVE)) {
        args.putString(RNPromptFragment.ARG_BUTTON_NEGATIVE, options.getString(KEY_BUTTON_NEGATIVE));
    }
    if (options.hasKey(KEY_BUTTON_NEUTRAL)) {
        args.putString(RNPromptFragment.ARG_BUTTON_NEUTRAL, options.getString(KEY_BUTTON_NEUTRAL));
    }
    if (options.hasKey(KEY_ITEMS)) {
        ReadableArray items = options.getArray(KEY_ITEMS);
        CharSequence[] itemsArray = new CharSequence[items.size()];
        for (int i = 0; i < items.size(); i++) {
            itemsArray[i] = items.getString(i);
        }
        args.putCharSequenceArray(RNPromptFragment.ARG_ITEMS, itemsArray);
    }
    if (options.hasKey(KEY_CANCELABLE)) {
        args.putBoolean(KEY_CANCELABLE, options.getBoolean(KEY_CANCELABLE));
    }
    if (options.hasKey(KEY_TYPE)) {
        args.putString(KEY_TYPE, options.getString(KEY_TYPE));
    }
    if (options.hasKey(KEY_STYLE)) {
        args.putString(KEY_STYLE, options.getString(KEY_STYLE));
    }
    if (options.hasKey(KEY_DEFAULT_VALUE)) {
        args.putString(KEY_DEFAULT_VALUE, options.getString(KEY_DEFAULT_VALUE));
    }
    if (options.hasKey(KEY_PLACEHOLDER)) {
        args.putString(KEY_PLACEHOLDER, options.getString(KEY_PLACEHOLDER));
    }
    fragmentManagerHelper.showNewAlert(mIsInForeground, args, callback);
}
 
源代码17 项目: react-native-lock   文件: ShowOptions.java
public ShowOptions(@Nullable ReadableMap options) {
    if (options == null) {
        return;
    }

    if (options.hasKey(CLOSABLE_KEY)) {
        closable = options.getBoolean(CLOSABLE_KEY);
        Log.d(TAG, CLOSABLE_KEY + closable);
    }

    if (options.hasKey(DISABLE_SIGNUP)) {
         disableSignUp = options.getBoolean(DISABLE_SIGNUP);
         Log.d(TAG, DISABLE_SIGNUP + disableSignUp);
    }

    if (options.hasKey(DISABLE_RESET_PASSWORD)) {
         disableResetPassword = options.getBoolean(DISABLE_RESET_PASSWORD);
         Log.d(TAG, DISABLE_RESET_PASSWORD + disableResetPassword);
    }

    if (options.hasKey(USE_MAGIC_LINK_KEY)) {
        useMagicLink = options.getBoolean(USE_MAGIC_LINK_KEY);
        Log.d(TAG, USE_MAGIC_LINK_KEY + useMagicLink);
    }

    if (options.hasKey(AUTH_PARAMS_KEY)) {
        ReadableMap reactMap = options.getMap(AUTH_PARAMS_KEY);
        authParams = OptionsHelper.convertReadableMapToMap(reactMap);
        Log.d(TAG, AUTH_PARAMS_KEY + authParams);
    }

    if (options.hasKey(CONNECTIONS_KEY)) {
        ReadableArray connections = options.getArray(CONNECTIONS_KEY);
        List<String> list = new ArrayList<>(connections.size());
        for (int i = 0; i < connections.size(); i++) {
            String connectionName = connections.getString(i);
            switch (connectionName) {
                case LockReactModule.CONNECTION_EMAIL:
                    connectionType = LockReactModule.CONNECTION_EMAIL;
                    break;
                case LockReactModule.CONNECTION_SMS:
                    connectionType = LockReactModule.CONNECTION_SMS;
                    break;
            }
            list.add(connectionName);
        }
        this.connections = new String[list.size()];
        this.connections = list.toArray(this.connections);
        Log.d(TAG, CONNECTIONS_KEY + list);
    }
}
 
源代码18 项目: react-native-contacts   文件: ContactsManager.java
@ReactMethod
public void editExistingContact(ReadableMap contact, Callback callback) {

    String recordID = contact.hasKey("recordID") ? contact.getString("recordID") : null;

    try {
        Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, recordID);

        ReadableArray phoneNumbers = contact.hasKey("phoneNumbers") ? contact.getArray("phoneNumbers") : null;
        int numOfPhones = 0;
        String[] phones = null;
        Integer[] phonesLabels = null;
        if (phoneNumbers != null) {
            numOfPhones = phoneNumbers.size();
            phones = new String[numOfPhones];
            phonesLabels = new Integer[numOfPhones];
            for (int i = 0; i < numOfPhones; i++) {
                phones[i] = phoneNumbers.getMap(i).getString("number");
                String label = phoneNumbers.getMap(i).getString("label");
                phonesLabels[i] = mapStringToPhoneType(label);
            }
        }

        ArrayList<ContentValues> contactData = new ArrayList<>();
        for (int i = 0; i < numOfPhones; i++) {
            ContentValues phone = new ContentValues();
            phone.put(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
            phone.put(CommonDataKinds.Phone.TYPE, phonesLabels[i]);
            phone.put(CommonDataKinds.Phone.NUMBER, phones[i]);
            contactData.add(phone);
        }

        Intent intent = new Intent(Intent.ACTION_EDIT);
        intent.setDataAndType(uri, ContactsContract.Contacts.CONTENT_ITEM_TYPE);
        intent.putExtra("finishActivityOnSaveCompleted", true);
        intent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);

        updateContactCallback = callback;
        getReactApplicationContext().startActivityForResult(intent, REQUEST_OPEN_EXISTING_CONTACT, Bundle.EMPTY);

    } catch (Exception e) {
        callback.invoke(e.toString());
    }
}
 
源代码19 项目: react-native-GPay   文件: TransformHelper.java
public static void processTransform(ReadableArray transforms, double[] result) {
  double[] helperMatrix = sHelperMatrix.get();
  MatrixMathHelper.resetIdentityMatrix(result);

  for (int transformIdx = 0, size = transforms.size(); transformIdx < size; transformIdx++) {
    ReadableMap transform = transforms.getMap(transformIdx);
    String transformType = transform.keySetIterator().nextKey();

    MatrixMathHelper.resetIdentityMatrix(helperMatrix);
    if ("matrix".equals(transformType)) {
      ReadableArray matrix = transform.getArray(transformType);
      for (int i = 0; i < 16; i++) {
        helperMatrix[i] = matrix.getDouble(i);
      }
    } else if ("perspective".equals(transformType)) {
      MatrixMathHelper.applyPerspective(helperMatrix, transform.getDouble(transformType));
    } else if ("rotateX".equals(transformType)) {
      MatrixMathHelper.applyRotateX(
        helperMatrix,
        convertToRadians(transform, transformType));
    } else if ("rotateY".equals(transformType)) {
      MatrixMathHelper.applyRotateY(
        helperMatrix,
        convertToRadians(transform, transformType));
    } else if ("rotate".equals(transformType) || "rotateZ".equals(transformType)) {
      MatrixMathHelper.applyRotateZ(
        helperMatrix,
        convertToRadians(transform, transformType));
    } else if ("scale".equals(transformType)) {
      double scale = transform.getDouble(transformType);
      MatrixMathHelper.applyScaleX(helperMatrix, scale);
      MatrixMathHelper.applyScaleY(helperMatrix, scale);
    } else if ("scaleX".equals(transformType)) {
      MatrixMathHelper.applyScaleX(helperMatrix, transform.getDouble(transformType));
    } else if ("scaleY".equals(transformType)) {
      MatrixMathHelper.applyScaleY(helperMatrix, transform.getDouble(transformType));
    } else if ("translate".equals(transformType)) {
      ReadableArray value = transform.getArray(transformType);
      double x = value.getDouble(0);
      double y = value.getDouble(1);
      double z = value.size() > 2 ? value.getDouble(2) : 0d;
      MatrixMathHelper.applyTranslate3D(helperMatrix, x, y, z);
    } else if ("translateX".equals(transformType)) {
      MatrixMathHelper.applyTranslate2D(helperMatrix, transform.getDouble(transformType), 0d);
    } else if ("translateY".equals(transformType)) {
      MatrixMathHelper.applyTranslate2D(helperMatrix, 0d, transform.getDouble(transformType));
    } else if ("skewX".equals(transformType)) {
      MatrixMathHelper.applySkewX(
        helperMatrix,
        convertToRadians(transform, transformType));
    } else if ("skewY".equals(transformType)) {
      MatrixMathHelper.applySkewY(
        helperMatrix,
        convertToRadians(transform, transformType));
    } else {
      throw new JSApplicationIllegalArgumentException("Unsupported transform type: "
        + transformType);
    }

    MatrixMathHelper.multiplyInto(result, result, helperMatrix);
  }
}
 
/**
 * More details about legend customization: https://github.com/PhilJay/MPAndroidChart/wiki/Legend
 */
@ReactProp(name = "legend")
public void setLegend(T chart, ReadableMap propMap) {
    Legend legend = chart.getLegend();

    if (BridgeUtils.validate(propMap, ReadableType.Boolean, "enabled")) {
        legend.setEnabled(propMap.getBoolean("enabled"));
    }

    // Styling
    if (BridgeUtils.validate(propMap, ReadableType.String, "textColor")) {
        legend.setTextColor(Color.parseColor(propMap.getString("textColor")));
    }
    if (BridgeUtils.validate(propMap, ReadableType.Number, "textSize")) {
        legend.setTextSize((float) propMap.getDouble("textSize"));
    }
    if (BridgeUtils.validate(propMap, ReadableType.String, "fontFamily") ||
            BridgeUtils.validate(propMap, ReadableType.Number, "fontStyle")) {
        legend.setTypeface(BridgeUtils.parseTypeface(chart.getContext(), propMap, "fontStyle", "fontFamily"));
    }

    // Wrapping / clipping avoidance
    if (BridgeUtils.validate(propMap, ReadableType.Boolean, "wordWrapEnabled")) {
        legend.setWordWrapEnabled(propMap.getBoolean("wordWrapEnabled"));
    }
    if (BridgeUtils.validate(propMap, ReadableType.Number, "maxSizePercent")) {
        legend.setMaxSizePercent((float) propMap.getDouble("maxSizePercent"));
    }

    // Customizing
    if (BridgeUtils.validate(propMap, ReadableType.String, "position")) {
        legend.setPosition(LegendPosition.valueOf(propMap.getString("position").toUpperCase()));
    }
    if (BridgeUtils.validate(propMap, ReadableType.String, "form")) {
        legend.setForm(LegendForm.valueOf(propMap.getString("form").toUpperCase()));
    }
    if (BridgeUtils.validate(propMap, ReadableType.Number, "formSize")) {
        legend.setFormSize((float) propMap.getDouble("formSize"));
    }
    if (BridgeUtils.validate(propMap, ReadableType.Number, "xEntrySpace")) {
        legend.setXEntrySpace((float) propMap.getDouble("xEntrySpace"));
    }
    if (BridgeUtils.validate(propMap, ReadableType.Number, "yEntrySpace")) {
        legend.setYEntrySpace((float) propMap.getDouble("yEntrySpace"));
    }
    if (BridgeUtils.validate(propMap, ReadableType.Number, "formToTextSpace")) {
        legend.setFormToTextSpace((float) propMap.getDouble("formToTextSpace"));
    }

    // Custom labels & colors
    if (BridgeUtils.validate(propMap, ReadableType.Map, "custom")) {
        ReadableMap customMap = propMap.getMap("custom");
        if (BridgeUtils.validate(customMap, ReadableType.Array, "colors") &&
                BridgeUtils.validate(customMap, ReadableType.Array, "labels")) {

            ReadableArray colorsArray = customMap.getArray("colors");
            ReadableArray labelsArray = customMap.getArray("labels");

            if (colorsArray.size() == labelsArray.size()) {
                // TODO null label should start a group
                // TODO -2 color should avoid drawing a form
                String[] labels = BridgeUtils.convertToStringArray(labelsArray);
                String[] colors = BridgeUtils.convertToStringArray(colorsArray);

                int[] colorsParsed = new int[colors.length];
                for (int i = 0; i < colors.length; i++) {
                    colorsParsed[i] = Color.parseColor(colors[i]);
                }

                legend.setCustom(colorsParsed, labels);
            }
        }
    }

    // TODO resetCustom function
    // TODO extra

    chart.invalidate();     // TODO is this necessary? Looks like enabled is not refreshing without it
}