@Test public void testTextDecorationLineUnderlineLineThroughApplied() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = createText( uiManager, JavaOnlyMap.of(ViewProps.TEXT_DECORATION_LINE, "underline line-through"), JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); UnderlineSpan underlineSpan = getSingleSpan((TextView) rootView.getChildAt(0), UnderlineSpan.class); StrikethroughSpan strikeThroughSpan = getSingleSpan((TextView) rootView.getChildAt(0), StrikethroughSpan.class); assertThat(underlineSpan instanceof UnderlineSpan).isTrue(); assertThat(strikeThroughSpan instanceof StrikethroughSpan).isTrue(); }
@ReactProp(name = ViewProps.TEXT_BREAK_STRATEGY) public void setTextBreakStrategy(@Nullable String textBreakStrategy) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { return; } if (textBreakStrategy == null || "highQuality".equals(textBreakStrategy)) { mTextBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY; } else if ("simple".equals(textBreakStrategy)) { mTextBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE; } else if ("balanced".equals(textBreakStrategy)) { mTextBreakStrategy = Layout.BREAK_STRATEGY_BALANCED; } else { throw new JSApplicationIllegalArgumentException("Invalid textBreakStrategy: " + textBreakStrategy); } markUpdated(); }
@ReactProp(name = ViewProps.FONT_WEIGHT) public void setFontWeight(@Nullable String fontWeightString) { final int fontWeight; if (fontWeightString == null) { fontWeight = -1; } else if (BOLD.equals(fontWeightString)) { fontWeight = Typeface.BOLD; } else if (NORMAL.equals(fontWeightString)) { fontWeight = Typeface.NORMAL; } else { int fontWeightNumeric = parseNumericFontWeight(fontWeightString); if (fontWeightNumeric == -1) { throw new RuntimeException("invalid font weight " + fontWeightString); } fontWeight = fontWeightNumeric >= 500 ? Typeface.BOLD : Typeface.NORMAL; } if (mFontStylingSpan.getFontWeight() != fontWeight) { getSpan().setFontWeight(fontWeight); notifyChanged(true); } }
@ReactProp(name = ViewProps.TEXT_DECORATION_LINE) public void setTextDecorationLine(@Nullable String textDecorationLineString) { boolean isUnderlineTextDecorationSet = false; boolean isLineThroughTextDecorationSet = false; if (textDecorationLineString != null) { for (String textDecorationLineSubString : textDecorationLineString.split(" ")) { if ("underline".equals(textDecorationLineSubString)) { isUnderlineTextDecorationSet = true; } else if ("line-through".equals(textDecorationLineSubString)) { isLineThroughTextDecorationSet = true; } } } if (isUnderlineTextDecorationSet != mFontStylingSpan.hasUnderline() || isLineThroughTextDecorationSet != mFontStylingSpan.hasStrikeThrough()) { FontStylingSpan span = getSpan(); span.setHasUnderline(isUnderlineTextDecorationSet); span.setHasStrikeThrough(isLineThroughTextDecorationSet); notifyChanged(true); } }
@ReactProp(name = ViewProps.FONT_STYLE) public void setFontStyle(@Nullable String fontStyleString) { final int fontStyle; if (fontStyleString == null) { fontStyle = -1; } else if (ITALIC.equals(fontStyleString)) { fontStyle = Typeface.ITALIC; } else if (NORMAL.equals(fontStyleString)) { fontStyle = Typeface.NORMAL; } else { throw new RuntimeException("invalid font style " + fontStyleString); } if (mFontStylingSpan.getFontStyle() != fontStyle) { getSpan().setFontStyle(fontStyle); notifyChanged(true); } }
@ReactProp(name = ViewProps.TEXT_ALIGN) public void setTextAlign(@Nullable String textAlign) { if (textAlign == null || "auto".equals(textAlign)) { mAlignment = Gravity.NO_GRAVITY; } else if ("left".equals(textAlign)) { // left and right may yield potentially different results (relative to non-nodes) in cases // when supportsRTL="true" in the manifest. mAlignment = Gravity.LEFT; } else if ("right".equals(textAlign)) { mAlignment = Gravity.RIGHT; } else if ("center".equals(textAlign)) { mAlignment = Gravity.CENTER; } else { throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign); } notifyChanged(false); }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactScrollView view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
/** /* This code was taken from the method setFontStyle of the class ReactTextShadowNode /* TODO: Factor into a common place they can both use */ @ReactProp(name = ViewProps.FONT_STYLE) public void setFontStyle(ReactEditText view, @Nullable String fontStyleString) { int fontStyle = UNSET; if ("italic".equals(fontStyleString)) { fontStyle = Typeface.ITALIC; } else if ("normal".equals(fontStyleString)) { fontStyle = Typeface.NORMAL; } Typeface currentTypeface = view.getTypeface(); if (currentTypeface == null) { currentTypeface = Typeface.DEFAULT; } if (fontStyle != currentTypeface.getStyle()) { view.setTypeface(currentTypeface, fontStyle); } }
@Test public void testFontFamilyBoldItalicStyleApplied() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = createText( uiManager, JavaOnlyMap.of( ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_WEIGHT, "500", ViewProps.FONT_STYLE, "italic"), JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); CustomStyleSpan customStyleSpan = getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class); assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif"); assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero(); assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero(); }
@ReactProp(name = ViewProps.TEXT_ALIGN) public void setTextAlign(@Nullable String textAlign) { if (textAlign == null || "auto".equals(textAlign)) { mTextAlign = Gravity.NO_GRAVITY; } else if ("left".equals(textAlign)) { mTextAlign = Gravity.LEFT; } else if ("right".equals(textAlign)) { mTextAlign = Gravity.RIGHT; } else if ("center".equals(textAlign)) { mTextAlign = Gravity.CENTER_HORIZONTAL; } else if ("justify".equals(textAlign)) { // Fallback gracefully for cross-platform compat instead of error mTextAlign = Gravity.LEFT; } else { throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign); } markUpdated(); }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactViewGroup view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactTextView view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactHorizontalScrollView view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
@ReactPropGroup(names = { ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactImageView view, int index, float borderRadius) { if (!YogaConstants.isUndefined(borderRadius)) { borderRadius = PixelUtil.toPixelFromDIP(borderRadius); } if (index == 0) { view.setBorderRadius(borderRadius); } else { view.setBorderRadius(borderRadius, index - 1); } }
/** /* This code is duplicated in ReactTextInputManager /* TODO: Factor into a common place they can both use */ @ReactProp(name = ViewProps.FONT_WEIGHT) public void setFontWeight(@Nullable String fontWeightString) { int fontWeightNumeric = fontWeightString != null ? parseNumericFontWeight(fontWeightString) : -1; int fontWeight = UNSET; if (fontWeightNumeric >= 500 || "bold".equals(fontWeightString)) { fontWeight = Typeface.BOLD; } else if ("normal".equals(fontWeightString) || (fontWeightNumeric != -1 && fontWeightNumeric < 500)) { fontWeight = Typeface.NORMAL; } if (fontWeight != mFontWeight) { mFontWeight = fontWeight; markUpdated(); } }
@Test public void testTextDecorationLineLineThroughApplied() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = createText( uiManager, JavaOnlyMap.of(ViewProps.TEXT_DECORATION_LINE, "line-through"), JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); TextView textView = (TextView) rootView.getChildAt(0); Spanned text = (Spanned) textView.getText(); UnderlineSpan[] underlineSpans = text.getSpans(0, text.length(), UnderlineSpan.class); StrikethroughSpan strikeThroughSpan = getSingleSpan(textView, StrikethroughSpan.class); assertThat(underlineSpans).hasSize(0); assertThat(strikeThroughSpan instanceof StrikethroughSpan).isTrue(); }
/** /* This code was taken from the method setFontWeight of the class ReactTextShadowNode /* TODO: Factor into a common place they can both use */ @ReactProp(name = ViewProps.FONT_WEIGHT) public void setFontWeight(ReactEditText view, @Nullable String fontWeightString) { int fontWeightNumeric = fontWeightString != null ? parseNumericFontWeight(fontWeightString) : -1; int fontWeight = UNSET; if (fontWeightNumeric >= 500 || "bold".equals(fontWeightString)) { fontWeight = Typeface.BOLD; } else if ("normal".equals(fontWeightString) || (fontWeightNumeric != -1 && fontWeightNumeric < 500)) { fontWeight = Typeface.NORMAL; } Typeface currentTypeface = view.getTypeface(); if (currentTypeface == null) { currentTypeface = Typeface.DEFAULT; } if (fontWeight != currentTypeface.getStyle()) { view.setTypeface(currentTypeface, fontWeight); } }
@ReactProp(name = ViewProps.TEXT_ALIGN) public void setTextAlign(ReactEditText view, @Nullable String textAlign) { if (textAlign == null || "auto".equals(textAlign)) { view.setGravityHorizontal(Gravity.NO_GRAVITY); } else if ("left".equals(textAlign)) { view.setGravityHorizontal(Gravity.LEFT); } else if ("right".equals(textAlign)) { view.setGravityHorizontal(Gravity.RIGHT); } else if ("center".equals(textAlign)) { view.setGravityHorizontal(Gravity.CENTER_HORIZONTAL); } else if ("justify".equals(textAlign)) { // Fallback gracefully for cross-platform compat instead of error view.setGravityHorizontal(Gravity.LEFT); } else { throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign); } }
@Test public void testFontFamilyItalicStyleApplied() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = createText( uiManager, JavaOnlyMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_STYLE, "italic"), JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); CustomStyleSpan customStyleSpan = getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class); assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif"); assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero(); assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero(); }
@ReactProp(name = ViewProps.LINE_HEIGHT, defaultDouble = Double.NaN) public void setLineHeight(double lineHeight) { if (Double.isNaN(lineHeight)) { mSpacingMult = 1.0f; mSpacingAdd = 0.0f; } else { mSpacingMult = 0.0f; mSpacingAdd = PixelUtil.toPixelFromSP((float) lineHeight); } notifyChanged(true); }
@Test public void testBoldItalicFontApplied() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = createText( uiManager, JavaOnlyMap.of(ViewProps.FONT_WEIGHT, "bold", ViewProps.FONT_STYLE, "italic"), JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); CustomStyleSpan customStyleSpan = getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class); assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero(); assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero(); }
@ReactProp(name = ViewProps.RESIZE_METHOD) public void setResizeMethod(ReactImageView view, @Nullable String resizeMethod) { if (resizeMethod == null || "auto".equals(resizeMethod)) { view.setResizeMethod(ImageResizeMethod.AUTO); } else if ("resize".equals(resizeMethod)) { view.setResizeMethod(ImageResizeMethod.RESIZE); } else if ("scale".equals(resizeMethod)) { view.setResizeMethod(ImageResizeMethod.SCALE); } else { throw new JSApplicationIllegalArgumentException("Invalid resize method: '" + resizeMethod+ "'"); } }
@ReactProp(name = ViewProps.RESIZE_MODE) public void setResizeMode(@Nullable String resizeMode) { ScaleType scaleType = ImageResizeMode.toScaleType(resizeMode); if (mDrawImage.getScaleType() != scaleType) { getMutableDrawImage().setScaleType(scaleType); } }
@ReactProp(name = ViewProps.FONT_FAMILY) public void setFontFamily(ReactEditText view, String fontFamily) { int style = Typeface.NORMAL; if (view.getTypeface() != null) { style = view.getTypeface().getStyle(); } Typeface newTypeface = ReactFontManager.getInstance().getTypeface( fontFamily, style, view.getContext().getAssets()); view.setTypeface(newTypeface); }
@Test public void testNormalFontWeightApplied() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = createText( uiManager, JavaOnlyMap.of(ViewProps.FONT_WEIGHT, "normal"), JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); CustomStyleSpan customStyleSpan = getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class); assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero(); }
@ReactProp(name = ViewProps.TEXT_ALIGN_VERTICAL) public void setTextAlignVertical(ReactEditText view, @Nullable String textAlignVertical) { if (textAlignVertical == null || "auto".equals(textAlignVertical)) { view.setGravityVertical(Gravity.NO_GRAVITY); } else if ("top".equals(textAlignVertical)) { view.setGravityVertical(Gravity.TOP); } else if ("bottom".equals(textAlignVertical)) { view.setGravityVertical(Gravity.BOTTOM); } else if ("center".equals(textAlignVertical)) { view.setGravityVertical(Gravity.CENTER_VERTICAL); } else { throw new JSApplicationIllegalArgumentException("Invalid textAlignVertical: " + textAlignVertical); } }
@ReactProp(name = ViewProps.ELLIPSIZE_MODE) public void setEllipsizeMode(ReactTextView view, @Nullable String ellipsizeMode) { if (ellipsizeMode == null || ellipsizeMode.equals("tail")) { view.setEllipsizeLocation(TextUtils.TruncateAt.END); } else if (ellipsizeMode.equals("head")) { view.setEllipsizeLocation(TextUtils.TruncateAt.START); } else if (ellipsizeMode.equals("middle")) { view.setEllipsizeLocation(TextUtils.TruncateAt.MIDDLE); } else { throw new JSApplicationIllegalArgumentException("Invalid ellipsizeMode: " + ellipsizeMode); } }
@Test public void testFontFamilyBoldStyleApplied() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = createText( uiManager, JavaOnlyMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_WEIGHT, "bold"), JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text")); CustomStyleSpan customStyleSpan = getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class); assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif"); assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero(); assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero(); }
@ReactPropGroup(names = { ViewProps.BORDER_WIDTH, ViewProps.BORDER_LEFT_WIDTH, ViewProps.BORDER_RIGHT_WIDTH, ViewProps.BORDER_TOP_WIDTH, ViewProps.BORDER_BOTTOM_WIDTH, }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderWidth(ReactEditText view, int index, float width) { if (!YogaConstants.isUndefined(width)) { width = PixelUtil.toPixelFromDIP(width); } view.setBorderWidth(SPACING_TYPES[index], width); }