mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Migrate ReactDrawableHelper to Kotlin (#48346)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/48346 Migrate ReactDrawableHelper to Kotlin changelog: [internal] internal Reviewed By: rshest Differential Revision: D67420410 fbshipit-source-id: 524062d0c0a0d3440bf5ac4c61e8cae53b32a0d2
This commit is contained in:
committed by
Facebook GitHub Bot
parent
e9faea2f3e
commit
7b8412d66d
@@ -7739,9 +7739,9 @@ public abstract class com/facebook/react/views/view/ReactClippingViewManager : c
|
||||
public fun setRemoveClippedSubviews (Lcom/facebook/react/views/view/ReactViewGroup;Z)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/views/view/ReactDrawableHelper {
|
||||
public fun <init> ()V
|
||||
public static fun createDrawableFromJSDescription (Landroid/content/Context;Lcom/facebook/react/bridge/ReadableMap;)Landroid/graphics/drawable/Drawable;
|
||||
public final class com/facebook/react/views/view/ReactDrawableHelper {
|
||||
public static final field INSTANCE Lcom/facebook/react/views/view/ReactDrawableHelper;
|
||||
public static final fun createDrawableFromJSDescription (Landroid/content/Context;Lcom/facebook/react/bridge/ReadableMap;)Landroid/graphics/drawable/Drawable;
|
||||
}
|
||||
|
||||
public class com/facebook/react/views/view/ReactViewGroup : android/view/ViewGroup, com/facebook/react/touch/ReactHitSlopView, com/facebook/react/touch/ReactInterceptingViewGroup, com/facebook/react/uimanager/ReactClippingViewGroup, com/facebook/react/uimanager/ReactOverflowViewWithInset, com/facebook/react/uimanager/ReactPointerEventsView, com/facebook/react/uimanager/ReactZIndexedViewGroup {
|
||||
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.util.TypedValue;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
|
||||
/**
|
||||
* Utility class that helps with converting android drawable description used in JS to an actual
|
||||
* instance of {@link Drawable}.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactDrawableHelper {
|
||||
|
||||
private static final TypedValue sResolveOutValue = new TypedValue();
|
||||
|
||||
public static @Nullable Drawable createDrawableFromJSDescription(
|
||||
Context context, ReadableMap drawableDescriptionDict) {
|
||||
String type = drawableDescriptionDict.getString("type");
|
||||
if ("ThemeAttrAndroid".equals(type)) {
|
||||
String attr = drawableDescriptionDict.getString("attribute");
|
||||
if (attr == null) {
|
||||
throw new JSApplicationIllegalArgumentException("JS description missing 'attribute' field");
|
||||
}
|
||||
int attrId = getAttrId(context, attr);
|
||||
if (!context.getTheme().resolveAttribute(attrId, sResolveOutValue, true)) {
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"Attribute " + attr + " with id " + attrId + " couldn't be resolved into a drawable");
|
||||
}
|
||||
Drawable drawable = getDefaultThemeDrawable(context);
|
||||
return setRadius(drawableDescriptionDict, drawable);
|
||||
} else if ("RippleAndroid".equals(type)) {
|
||||
RippleDrawable rd = getRippleDrawable(context, drawableDescriptionDict);
|
||||
return setRadius(drawableDescriptionDict, rd);
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid type for android drawable: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getAttrId(Context context, String attr) {
|
||||
if ("selectableItemBackground".equals(attr)) {
|
||||
return android.R.attr.selectableItemBackground;
|
||||
} else if ("selectableItemBackgroundBorderless".equals(attr)) {
|
||||
return android.R.attr.selectableItemBackgroundBorderless;
|
||||
} else {
|
||||
return context.getResources().getIdentifier(attr, "attr", "android");
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Drawable getDefaultThemeDrawable(Context context) {
|
||||
return context.getResources().getDrawable(sResolveOutValue.resourceId, context.getTheme());
|
||||
}
|
||||
|
||||
private static RippleDrawable getRippleDrawable(
|
||||
Context context, ReadableMap drawableDescriptionDict) {
|
||||
int color = getColor(context, drawableDescriptionDict);
|
||||
Drawable mask = getMask(drawableDescriptionDict);
|
||||
ColorStateList colorStateList =
|
||||
new ColorStateList(new int[][] {new int[] {}}, new int[] {color});
|
||||
|
||||
return new RippleDrawable(colorStateList, null, mask);
|
||||
}
|
||||
|
||||
private static @Nullable Drawable setRadius(
|
||||
ReadableMap drawableDescriptionDict, @Nullable Drawable drawable) {
|
||||
if (drawableDescriptionDict.hasKey("rippleRadius") && drawable instanceof RippleDrawable) {
|
||||
RippleDrawable rippleDrawable = (RippleDrawable) drawable;
|
||||
double rippleRadius = drawableDescriptionDict.getDouble("rippleRadius");
|
||||
rippleDrawable.setRadius((int) PixelUtil.toPixelFromDIP(rippleRadius));
|
||||
}
|
||||
return drawable;
|
||||
}
|
||||
|
||||
private static int getColor(Context context, ReadableMap drawableDescriptionDict) {
|
||||
if (drawableDescriptionDict.hasKey(ViewProps.COLOR)
|
||||
&& !drawableDescriptionDict.isNull(ViewProps.COLOR)) {
|
||||
return drawableDescriptionDict.getInt(ViewProps.COLOR);
|
||||
} else {
|
||||
if (context
|
||||
.getTheme()
|
||||
.resolveAttribute(android.R.attr.colorControlHighlight, sResolveOutValue, true)) {
|
||||
return context.getResources().getColor(sResolveOutValue.resourceId);
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"Attribute colorControlHighlight couldn't be resolved into a drawable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Drawable getMask(ReadableMap drawableDescriptionDict) {
|
||||
if (!drawableDescriptionDict.hasKey("borderless")
|
||||
|| drawableDescriptionDict.isNull("borderless")
|
||||
|| !drawableDescriptionDict.getBoolean("borderless")) {
|
||||
return new ColorDrawable(Color.WHITE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.RippleDrawable
|
||||
import android.util.TypedValue
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.uimanager.PixelUtil
|
||||
import com.facebook.react.uimanager.ViewProps
|
||||
|
||||
/**
|
||||
* Utility class that helps with converting android drawable description used in JS to an actual
|
||||
* instance of [Drawable].
|
||||
*/
|
||||
public object ReactDrawableHelper {
|
||||
|
||||
private val resolveOutValue = TypedValue()
|
||||
|
||||
@JvmStatic
|
||||
public fun createDrawableFromJSDescription(
|
||||
context: Context,
|
||||
drawableDescriptionDict: ReadableMap
|
||||
): Drawable? {
|
||||
val type = drawableDescriptionDict.getString("type")
|
||||
if ("ThemeAttrAndroid" == type) {
|
||||
val attr =
|
||||
drawableDescriptionDict.getString("attribute")
|
||||
?: throw JSApplicationIllegalArgumentException(
|
||||
"JS description missing 'attribute' field")
|
||||
val attrId = getAttrId(context, attr)
|
||||
if (!context.theme.resolveAttribute(attrId, resolveOutValue, true)) {
|
||||
throw JSApplicationIllegalArgumentException(
|
||||
"Attribute $attr with id $attrId couldn't be resolved into a drawable")
|
||||
}
|
||||
val drawable = getDefaultThemeDrawable(context)
|
||||
return setRadius(drawableDescriptionDict, drawable)
|
||||
} else if ("RippleAndroid" == type) {
|
||||
val rd = getRippleDrawable(context, drawableDescriptionDict)
|
||||
return setRadius(drawableDescriptionDict, rd)
|
||||
} else {
|
||||
throw JSApplicationIllegalArgumentException("Invalid type for android drawable: $type")
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DiscouragedApi", "InternalInsetResource")
|
||||
private fun getAttrId(context: Context, attr: String): Int =
|
||||
if ("selectableItemBackground" == attr) {
|
||||
android.R.attr.selectableItemBackground
|
||||
} else if ("selectableItemBackgroundBorderless" == attr) {
|
||||
android.R.attr.selectableItemBackgroundBorderless
|
||||
} else {
|
||||
context.resources.getIdentifier(attr, "attr", "android")
|
||||
}
|
||||
|
||||
private fun getDefaultThemeDrawable(context: Context): Drawable? =
|
||||
context.resources.getDrawable(resolveOutValue.resourceId, context.theme)
|
||||
|
||||
private fun getRippleDrawable(
|
||||
context: Context,
|
||||
drawableDescriptionDict: ReadableMap
|
||||
): RippleDrawable {
|
||||
val color = getColor(context, drawableDescriptionDict)
|
||||
val mask = getMask(drawableDescriptionDict)
|
||||
val colorStateList = ColorStateList(arrayOf(intArrayOf()), intArrayOf(color))
|
||||
|
||||
return RippleDrawable(colorStateList, null, mask)
|
||||
}
|
||||
|
||||
private fun setRadius(drawableDescriptionDict: ReadableMap, drawable: Drawable?): Drawable? {
|
||||
if (drawableDescriptionDict.hasKey("rippleRadius") && drawable is RippleDrawable) {
|
||||
val rippleRadius = drawableDescriptionDict.getDouble("rippleRadius")
|
||||
drawable.radius = PixelUtil.toPixelFromDIP(rippleRadius).toInt()
|
||||
}
|
||||
return drawable
|
||||
}
|
||||
|
||||
private fun getColor(context: Context, drawableDescriptionDict: ReadableMap): Int =
|
||||
if (drawableDescriptionDict.hasKey(ViewProps.COLOR) &&
|
||||
!drawableDescriptionDict.isNull(ViewProps.COLOR)) {
|
||||
drawableDescriptionDict.getInt(ViewProps.COLOR)
|
||||
} else {
|
||||
if (context.theme.resolveAttribute(
|
||||
android.R.attr.colorControlHighlight, resolveOutValue, true)) {
|
||||
context.resources.getColor(resolveOutValue.resourceId, context.theme)
|
||||
} else {
|
||||
throw JSApplicationIllegalArgumentException(
|
||||
"Attribute colorControlHighlight couldn't be resolved into a drawable")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMask(drawableDescriptionDict: ReadableMap): Drawable? {
|
||||
if (!drawableDescriptionDict.hasKey("borderless") ||
|
||||
drawableDescriptionDict.isNull("borderless") ||
|
||||
!drawableDescriptionDict.getBoolean("borderless")) {
|
||||
return ColorDrawable(Color.WHITE)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user