From b9bc1c49fcb78a3da7dbc575bf83d74378898015 Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Sun, 28 Jul 2024 07:45:24 -0700 Subject: [PATCH 1/3] ObjectAnimatedNode.java->.kt Differential Revision: D60284429 --- .../react/animated/ObjectAnimatedNode.java | 161 ------------------ .../react/animated/ObjectAnimatedNode.kt | 120 +++++++++++++ 2 files changed, 120 insertions(+), 161 deletions(-) delete mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/ObjectAnimatedNode.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/ObjectAnimatedNode.kt diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/ObjectAnimatedNode.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/ObjectAnimatedNode.java deleted file mode 100644 index 258ff5f098758e..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/ObjectAnimatedNode.java +++ /dev/null @@ -1,161 +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.animated; - -import androidx.annotation.Nullable; -import com.facebook.infer.annotation.Nullsafe; -import com.facebook.react.bridge.JavaOnlyArray; -import com.facebook.react.bridge.JavaOnlyMap; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableMapKeySetIterator; -import com.facebook.react.bridge.ReadableType; - -/** - * Native counterpart of object animated node (see AnimatedObject class in - * AnimatedImplementation.js) - */ -/* package */ @Nullsafe(Nullsafe.Mode.LOCAL) -class ObjectAnimatedNode extends AnimatedNode { - - private static final String VALUE_KEY = "value"; - private static final String NODE_TAG_KEY = "nodeTag"; - - private final NativeAnimatedNodesManager mNativeAnimatedNodesManager; - private final JavaOnlyMap mConfig; - - ObjectAnimatedNode(ReadableMap config, NativeAnimatedNodesManager nativeAnimatedNodesManager) { - mConfig = JavaOnlyMap.deepClone(config); - mNativeAnimatedNodesManager = nativeAnimatedNodesManager; - } - - public void collectViewUpdates(String propKey, JavaOnlyMap propsMap) { - ReadableType valueType = mConfig.getType(VALUE_KEY); - if (valueType == ReadableType.Map) { - propsMap.putMap(propKey, collectViewUpdatesHelper(mConfig.getMap(VALUE_KEY))); - } else if (valueType == ReadableType.Array) { - propsMap.putArray(propKey, collectViewUpdatesHelper(mConfig.getArray(VALUE_KEY))); - } else { - throw new IllegalArgumentException("Invalid value type for ObjectAnimatedNode"); - } - } - - private @Nullable JavaOnlyArray collectViewUpdatesHelper(@Nullable ReadableArray source) { - if (source == null) { - return null; - } - - JavaOnlyArray result = new JavaOnlyArray(); - for (int i = 0; i < source.size(); i++) { - switch (source.getType(i)) { - case Null: - result.pushNull(); - break; - case Boolean: - result.pushBoolean(source.getBoolean(i)); - break; - case Number: - result.pushDouble(source.getDouble(i)); - break; - case String: - result.pushString(source.getString(i)); - break; - case Map: - ReadableMap map = source.getMap(i); - if (map.hasKey(NODE_TAG_KEY) && map.getType(NODE_TAG_KEY) == ReadableType.Number) { - AnimatedNode node = mNativeAnimatedNodesManager.getNodeById(map.getInt(NODE_TAG_KEY)); - if (node == null) { - throw new IllegalArgumentException("Mapped value node does not exist"); - } else if (node instanceof ValueAnimatedNode) { - ValueAnimatedNode valueAnimatedNode = (ValueAnimatedNode) node; - Object animatedObject = valueAnimatedNode.getAnimatedObject(); - if (animatedObject instanceof Integer) { - result.pushInt((Integer) animatedObject); - } else if (animatedObject instanceof String) { - result.pushString((String) animatedObject); - } else { - result.pushDouble(valueAnimatedNode.getValue()); - } - } else if (node instanceof ColorAnimatedNode) { - result.pushInt(((ColorAnimatedNode) node).getColor()); - } - } else { - result.pushMap(collectViewUpdatesHelper(source.getMap(i))); - } - break; - case Array: - result.pushArray(collectViewUpdatesHelper(source.getArray(i))); - break; - } - } - return result; - } - - private @Nullable JavaOnlyMap collectViewUpdatesHelper(@Nullable ReadableMap source) { - if (source == null) { - return null; - } - - JavaOnlyMap result = new JavaOnlyMap(); - ReadableMapKeySetIterator iter = source.keySetIterator(); - while (iter.hasNextKey()) { - String propKey = iter.nextKey(); - switch (source.getType(propKey)) { - case Null: - result.putNull(propKey); - break; - case Boolean: - result.putBoolean(propKey, source.getBoolean(propKey)); - break; - case Number: - result.putDouble(propKey, source.getDouble(propKey)); - break; - case String: - result.putString(propKey, source.getString(propKey)); - break; - case Map: - ReadableMap map = source.getMap(propKey); - if (map != null - && map.hasKey(NODE_TAG_KEY) - && map.getType(NODE_TAG_KEY) == ReadableType.Number) { - AnimatedNode node = mNativeAnimatedNodesManager.getNodeById(map.getInt(NODE_TAG_KEY)); - if (node == null) { - throw new IllegalArgumentException("Mapped value node does not exist"); - } else if (node instanceof ValueAnimatedNode) { - ValueAnimatedNode valueAnimatedNode = (ValueAnimatedNode) node; - Object animatedObject = valueAnimatedNode.getAnimatedObject(); - if (animatedObject instanceof Integer) { - result.putInt(propKey, (Integer) animatedObject); - } else if (animatedObject instanceof String) { - result.putString(propKey, (String) animatedObject); - } else { - result.putDouble(propKey, valueAnimatedNode.getValue()); - } - } else if (node instanceof ColorAnimatedNode) { - result.putInt(propKey, ((ColorAnimatedNode) node).getColor()); - } - } else { - result.putMap(propKey, collectViewUpdatesHelper(map)); - } - break; - case Array: - result.putArray(propKey, collectViewUpdatesHelper(source.getArray(propKey))); - break; - } - } - return result; - } - - @Override - public String prettyPrint() { - return "ObjectAnimatedNode[" - + tag - + "]: mConfig: " - + (mConfig != null ? mConfig.toString() : "null"); - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/ObjectAnimatedNode.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/ObjectAnimatedNode.kt new file mode 100644 index 00000000000000..cef12f149aab63 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/ObjectAnimatedNode.kt @@ -0,0 +1,120 @@ +/* + * 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.animated + +import com.facebook.react.bridge.JavaOnlyArray +import com.facebook.react.bridge.JavaOnlyMap +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.bridge.ReadableType + +/** + * Native counterpart of object animated node (see AnimatedObject class in + * AnimatedImplementation.js) + */ +internal class ObjectAnimatedNode( + config: ReadableMap, + private val nativeAnimatedNodesManager: NativeAnimatedNodesManager +) : AnimatedNode() { + private val configClone: JavaOnlyMap = JavaOnlyMap.deepClone(config) + + fun collectViewUpdates(propKey: String, propsMap: JavaOnlyMap) { + val valueType = configClone.getType(VALUE_KEY) + if (valueType == ReadableType.Map) { + propsMap.putMap(propKey, collectViewUpdatesHelper(configClone.getMap(VALUE_KEY))) + } else if (valueType == ReadableType.Array) { + propsMap.putArray(propKey, collectViewUpdatesHelper(configClone.getArray(VALUE_KEY))) + } else { + throw IllegalArgumentException("Invalid value type for ObjectAnimatedNode") + } + } + + private fun collectViewUpdatesHelper(source: ReadableArray?): JavaOnlyArray? { + source ?: return null + val result = JavaOnlyArray() + for (i in 0 until source.size()) { + when (source.getType(i)) { + ReadableType.Null -> result.pushNull() + ReadableType.Boolean -> result.pushBoolean(source.getBoolean(i)) + ReadableType.Number -> result.pushDouble(source.getDouble(i)) + ReadableType.String -> result.pushString(source.getString(i)) + ReadableType.Map -> { + val map = source.getMap(i) + if (map.hasKey(NODE_TAG_KEY) && map.getType(NODE_TAG_KEY) == ReadableType.Number) { + val node = nativeAnimatedNodesManager.getNodeById(map.getInt(NODE_TAG_KEY)) + requireNotNull(node) { "Mapped value node does not exist" } + if (node is ValueAnimatedNode) { + val animatedObject = node.getAnimatedObject() + if (animatedObject is Int) { + result.pushInt(animatedObject) + } else if (animatedObject is String) { + result.pushString(animatedObject) + } else { + result.pushDouble(node.getValue()) + } + } else if (node is ColorAnimatedNode) { + result.pushInt(node.color) + } + } else { + result.pushMap(collectViewUpdatesHelper(source.getMap(i))) + } + } + ReadableType.Array -> result.pushArray(collectViewUpdatesHelper(source.getArray(i))) + } + } + return result + } + + private fun collectViewUpdatesHelper(source: ReadableMap?): JavaOnlyMap? { + source ?: return null + val result = JavaOnlyMap() + val iter = source.keySetIterator() + while (iter.hasNextKey()) { + val propKey = iter.nextKey() + when (source.getType(propKey)) { + ReadableType.Null -> result.putNull(propKey) + ReadableType.Boolean -> result.putBoolean(propKey, source.getBoolean(propKey)) + ReadableType.Number -> result.putDouble(propKey, source.getDouble(propKey)) + ReadableType.String -> result.putString(propKey, source.getString(propKey)) + ReadableType.Map -> { + val map = source.getMap(propKey) + if (map != null && + map.hasKey(NODE_TAG_KEY) && + map.getType(NODE_TAG_KEY) == ReadableType.Number) { + val node = nativeAnimatedNodesManager.getNodeById(map.getInt(NODE_TAG_KEY)) + requireNotNull(node) { "Mapped value node does not exist" } + if (node is ValueAnimatedNode) { + val animatedObject = node.getAnimatedObject() + if (animatedObject is Int) { + result.putInt(propKey, animatedObject) + } else if (animatedObject is String) { + result.putString(propKey, animatedObject) + } else { + result.putDouble(propKey, node.getValue()) + } + } else if (node is ColorAnimatedNode) { + result.putInt(propKey, node.color) + } + } else { + result.putMap(propKey, collectViewUpdatesHelper(map)) + } + } + ReadableType.Array -> + result.putArray(propKey, collectViewUpdatesHelper(source.getArray(propKey))) + } + } + return result + } + + override fun prettyPrint(): String = "ObjectAnimatedNode[$tag]: mConfig: $configClone" + + companion object { + private const val VALUE_KEY = "value" + private const val NODE_TAG_KEY = "nodeTag" + } +} From 06d4b69f825f0deaf14c0c27fbc9e511623ba4e3 Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Sun, 28 Jul 2024 07:45:24 -0700 Subject: [PATCH 2/3] Kotlinify react/animated interfaces Differential Revision: D60284765 --- packages/react-native/ReactAndroid/api/ReactAndroid.api | 8 ++++++++ ...odeValueListener.java => AnimatedNodeValueListener.kt} | 8 ++++---- ...bleConfig.java => AnimatedNodeWithUpdateableConfig.kt} | 8 ++++---- 3 files changed, 16 insertions(+), 8 deletions(-) rename packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/{AnimatedNodeValueListener.java => AnimatedNodeValueListener.kt} (50%) rename packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/{AnimatedNodeWithUpdateableConfig.java => AnimatedNodeWithUpdateableConfig.kt} (59%) diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 5048163dc0e8cc..58bb2042c359c3 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -456,6 +456,14 @@ public abstract class com/facebook/react/animated/AnimatedNode { public final class com/facebook/react/animated/AnimatedNode$Companion { } +public abstract interface class com/facebook/react/animated/AnimatedNodeValueListener { + public abstract fun onValueUpdate (D)V +} + +public abstract interface class com/facebook/react/animated/AnimatedNodeWithUpdateableConfig { + public abstract fun onUpdateConfig (Lcom/facebook/react/bridge/ReadableMap;)V +} + public class com/facebook/react/animated/NativeAnimatedModule : com/facebook/fbreact/specs/NativeAnimatedModuleSpec, com/facebook/react/bridge/LifecycleEventListener, com/facebook/react/bridge/UIManagerListener { public static final field ANIMATED_MODULE_DEBUG Z public fun (Lcom/facebook/react/bridge/ReactApplicationContext;)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeValueListener.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeValueListener.kt similarity index 50% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeValueListener.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeValueListener.kt index 512fda12ad8025..234f1ce01a8d17 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeValueListener.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeValueListener.kt @@ -5,9 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.react.animated; +package com.facebook.react.animated -/** Interface used to listen to {@link ValueAnimatedNode} updates. */ -interface AnimatedNodeValueListener { - void onValueUpdate(double value); +/** Interface used to listen to [ValueAnimatedNode] updates. */ +public fun interface AnimatedNodeValueListener { + public fun onValueUpdate(value: Double) } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeWithUpdateableConfig.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeWithUpdateableConfig.kt similarity index 59% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeWithUpdateableConfig.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeWithUpdateableConfig.kt index a8cf01e11f1456..bd5c8dff0a8de4 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeWithUpdateableConfig.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/AnimatedNodeWithUpdateableConfig.kt @@ -5,11 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.react.animated; +package com.facebook.react.animated -import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableMap /** Indicates that AnimatedNode is able to receive native config updates. */ -interface AnimatedNodeWithUpdateableConfig { - void onUpdateConfig(ReadableMap config); +public fun interface AnimatedNodeWithUpdateableConfig { + public fun onUpdateConfig(config: ReadableMap?) } From 7740792093df7c3eb2a5e8418c1788791d7863c8 Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Sun, 28 Jul 2024 07:56:02 -0700 Subject: [PATCH 3/3] '[skip ci] [RN][Android] Convert TrackingAnimatedNode to Kotlin (#45728) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45728 # Changelog: [Internal] - As in the title. Reviewed By: tdn120 Differential Revision: D60286293 --- .../java/com/facebook/react/animated/TrackingAnimatedNode.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/TrackingAnimatedNode.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/TrackingAnimatedNode.kt index cffb1894fc6720..de6dd8885e7148 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/TrackingAnimatedNode.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/TrackingAnimatedNode.kt @@ -14,10 +14,10 @@ internal class TrackingAnimatedNode( config: ReadableMap, private val nativeAnimatedNodesManager: NativeAnimatedNodesManager ) : AnimatedNode() { + private val animationConfig: JavaOnlyMap = JavaOnlyMap.deepClone(config.getMap("animationConfig")) private val animationId: Int = config.getInt("animationId") private val toValueNode: Int = config.getInt("toValue") private val valueNode: Int = config.getInt("value") - private val animationConfig: JavaOnlyMap = JavaOnlyMap.deepClone(config.getMap("animationConfig")) public override fun update() { val toValue = nativeAnimatedNodesManager.getNodeById(toValueNode)