diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index 19926020b8a..fcb4d2bb4f1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -97,6 +97,7 @@ public class ViewProps { public static final String ON = "on"; public static final String RESIZE_MODE = "resizeMode"; public static final String RESIZE_METHOD = "resizeMethod"; + public static final String LAYOUT_DIRECTION = "layoutDirection"; public static final String TEXT_ALIGN = "textAlign"; public static final String TEXT_ALIGN_VERTICAL = "textAlignVertical"; public static final String TEXT_DECORATION_LINE = "textDecorationLine"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java index c6d739a586f..599ab79e666 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java @@ -87,7 +87,6 @@ public class ReactTextViewManager ReadableNativeMap state = stateWrapper.getState(); ReadableMap attributedString = state.getMap("attributedString"); ReadableMap paragraphAttributes = state.getMap("paragraphAttributes"); - Spannable spanned = TextLayoutManager.getOrCreateSpannableForText( view.getContext(), attributedString, mReactTextViewManagerCallback); @@ -100,7 +99,7 @@ public class ReactTextViewManager spanned, state.hasKey("mostRecentEventCount") ? state.getInt("mostRecentEventCount") : -1, false, // TODO add this into local Data - TextAttributeProps.getTextAlignment(props), + TextAttributeProps.getTextAlignment(props, TextLayoutManager.isRTL(attributedString)), textBreakStrategy, TextAttributeProps.getJustificationMode(props)); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java index 2562f450ea5..29e3e2969fb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java @@ -10,6 +10,7 @@ package com.facebook.react.views.text; import android.graphics.Typeface; import android.os.Build; import android.text.Layout; +import android.util.LayoutDirection; import android.view.Gravity; import androidx.annotation.Nullable; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; @@ -57,6 +58,9 @@ public class TextAttributeProps { protected float mLetterSpacingInput = Float.NaN; protected int mTextAlign = Gravity.NO_GRAVITY; + // `UNSET` is -1 and is the same as `LayoutDirection.UNDEFINED` but the symbol isn't available. + protected int mLayoutDirection = UNSET; + protected TextTransform mTextTransform = TextTransform.UNSET; protected float mTextShadowOffsetDx = 0; @@ -129,10 +133,10 @@ public class TextAttributeProps { setTextShadowRadius(getIntProp(PROP_SHADOW_RADIUS, 1)); setTextShadowColor(getIntProp(PROP_SHADOW_COLOR, DEFAULT_TEXT_SHADOW_COLOR)); setTextTransform(getStringProp(PROP_TEXT_TRANSFORM)); + setLayoutDirection(getStringProp(ViewProps.LAYOUT_DIRECTION)); } - // TODO T63645393 add support for RTL - public static int getTextAlignment(ReactStylesDiffMap props) { + public static int getTextAlignment(ReactStylesDiffMap props, boolean isRTL) { @Nullable String textAlignPropValue = props.hasKey(ViewProps.TEXT_ALIGN) ? props.getString(ViewProps.TEXT_ALIGN) : null; @@ -144,9 +148,9 @@ public class TextAttributeProps { if (textAlignPropValue == null || "auto".equals(textAlignPropValue)) { textAlignment = Gravity.NO_GRAVITY; } else if ("left".equals(textAlignPropValue)) { - textAlignment = Gravity.LEFT; + textAlignment = isRTL ? Gravity.RIGHT : Gravity.LEFT; } else if ("right".equals(textAlignPropValue)) { - textAlignment = Gravity.RIGHT; + textAlignment = isRTL ? Gravity.LEFT : Gravity.RIGHT; } else if ("center".equals(textAlignPropValue)) { textAlignment = Gravity.CENTER_HORIZONTAL; } else { @@ -369,6 +373,19 @@ public class TextAttributeProps { } } + public void setLayoutDirection(@Nullable String layoutDirection) { + if (layoutDirection == null || "undefined".equals(layoutDirection)) { + mLayoutDirection = UNSET; + } else if ("rtl".equals(layoutDirection)) { + mLayoutDirection = LayoutDirection.RTL; + } else if ("ltr".equals(layoutDirection)) { + mLayoutDirection = LayoutDirection.LTR; + } else { + throw new JSApplicationIllegalArgumentException( + "Invalid layoutDirection: " + layoutDirection); + } + } + public void setTextShadowRadius(float textShadowRadius) { if (textShadowRadius != mTextShadowRadius) { mTextShadowRadius = textShadowRadius; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java index d2a68fd4550..2213ec61282 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java @@ -18,6 +18,7 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; +import android.util.LayoutDirection; import android.util.LruCache; import androidx.annotation.Nullable; import com.facebook.react.bridge.ReadableArray; @@ -47,6 +48,17 @@ public class TextLayoutManager { private static final Object sSpannableCacheLock = new Object(); private static LruCache sSpannableCache = new LruCache<>(spannableCacheSize); + public static boolean isRTL(ReadableMap attributedString) { + ReadableArray fragments = attributedString.getArray("fragments"); + for (int i = 0, length = fragments.size(); i < length; i++) { + ReadableMap fragment = fragments.getMap(i); + ReactStylesDiffMap map = new ReactStylesDiffMap(fragment.getMap("textAttributes")); + TextAttributeProps textAttributes = new TextAttributeProps(map); + return textAttributes.mLayoutDirection == LayoutDirection.RTL; + } + return false; + } + private static void buildSpannableFromFragment( Context context, ReadableArray fragments, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 4bbbca32973..2f228cd0566 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -1285,7 +1285,7 @@ public class ReactTextInputManager extends BaseViewManager