This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

21
node_modules/react-native-reanimated/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Krzysztof Magiera
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

61
node_modules/react-native-reanimated/README.md generated vendored Normal file
View File

@ -0,0 +1,61 @@
<p align="center">
<h1 align="center">React Native Reanimated</h1>
<h3 align="center">React Native's Animated library reimplemented</h3>
</p>
React Native Reanimated provides a more comprehensive,
low level abstraction for the Animated library API to be built
on top of and hence allow for much greater flexibility especially when it
comes to gesture based interactions.
## Installation
Check [getting started](https://software-mansion.github.io/react-native-reanimated/getting-started.html) section of our docs for the detailed installation instructions.
## Documentation
Check out our dedicated documentation page for info about this library, API reference and more: [https://software-mansion.github.io/react-native-reanimated](https://software-mansion.github.io/react-native-reanimated)
## Examples
The source code for the example (showcase) app is under the [`Example/`](https://github.com/software-mansion/react-native-reanimated/blob/master/Example/) directory.
If you want to play with the API but don't feel like trying it on a real app, you can run the example project. Clone the repo, go to the Example/ folder and run:
```
yarn install
```
### Running on iOS
Before running the app, install the cocoapods dependencies:
```
cd ios && pod install && cd ..
```
Now, you can start the app:
```
react-native run-ios
```
### Running on Android
Run the react native's cli command:
```
react-native run-android
```
**Important:** You will need to have an Android or iOS device or emulator connected as well as react-native-cli package installed globally.
## License
Reanimated library is licensed under [The MIT License](LICENSE).
## Credits
This project is supported by amazing people from [Expo.io](https://expo.io) and [Software Mansion](https://swmansion.com)
[![expo](https://avatars2.githubusercontent.com/u/12504344?v=3&s=100 'Expo.io')](https://expo.io)
[![swm](https://avatars0.githubusercontent.com/u/56880679?v=3&s=100 'Software Mansion')](https://swmansion.com)

View File

@ -0,0 +1,24 @@
require "json"
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
Pod::Spec.new do |s|
s.name = "RNReanimated"
s.version = package["version"]
s.summary = package["description"]
s.description = <<-DESC
RNReanimated
DESC
s.homepage = "https://github.com/software-mansion/react-native-reanimated"
s.license = "MIT"
# s.license = { :type => "MIT", :file => "FILE_LICENSE" }
s.author = { "author" => "author@domain.cn" }
s.platforms = { :ios => "9.0", :tvos => "9.0" }
s.source = { :git => "https://github.com/software-mansion/react-native-reanimated.git", :tag => "#{s.version}" }
s.source_files = "ios/**/*.{h,m}"
s.requires_arc = true
s.dependency "React-Core"
end

15
node_modules/react-native-reanimated/android/README.md generated vendored Normal file
View File

@ -0,0 +1,15 @@
README
======
If you want to publish the lib as a maven dependency, follow these steps before publishing a new version to npm:
1. Be sure to have the Android [SDK](https://developer.android.com/studio/index.html) and [NDK](https://developer.android.com/ndk/guides/index.html) installed
2. Be sure to have a `local.properties` file in this folder that points to the Android SDK and NDK
```
ndk.dir=/Users/{username}/Library/Android/sdk/ndk-bundle
sdk.dir=/Users/{username}/Library/Android/sdk
```
3. Delete the `maven` folder
4. Run `sudo ./gradlew installArchives`
5. Verify that latest set of generated files is in the maven folder with the correct version number

View File

@ -0,0 +1,133 @@
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
buildscript {
if (project == rootProject) {
// The Android Gradle plugin is only required when opening the android folder stand-alone.
// This avoids unnecessary downloads and potential conflicts when the library is included as a
// module dependency in an application project.
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
}
}
}
apply plugin: 'com.android.library'
apply plugin: 'maven'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
versionCode 1
versionName "1.0"
}
lintOptions {
abortOnError false
}
}
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
maven {
// Android JSC is installed from npm
url "$rootDir/../node_modules/jsc-android/dist"
}
google()
jcenter()
}
dependencies {
//noinspection GradleDynamicVersion
implementation 'com.facebook.react:react-native:+' // From node_modules
implementation "androidx.transition:transition:1.1.0"
}
def configureReactNativePom(def pom) {
def packageJson = new groovy.json.JsonSlurper().parseText(file('../package.json').text)
pom.project {
name packageJson.title
artifactId packageJson.name
version = packageJson.version
group = "com.swmansion.reanimated"
description packageJson.description
url packageJson.repository.baseUrl
licenses {
license {
name packageJson.license
url packageJson.repository.baseUrl + '/blob/master/' + packageJson.licenseFilename
distribution 'repo'
}
}
developers {
developer {
id packageJson.author.username
name packageJson.author.name
}
}
}
}
afterEvaluate { project ->
task androidJavadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += files(android.bootClasspath)
classpath += files(project.getConfigurations().getByName('compile').asList())
include '**/*.java'
}
task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) {
classifier = 'javadoc'
from androidJavadoc.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
include '**/*.java'
}
android.libraryVariants.all { variant ->
def compileTask
if (variant.hasProperty('javaCompileProvider')){
compileTask = variant.javaCompileProvider.get()
}else{
compileTask = variant.javaCompile
}
def name = variant.name.capitalize()
task "jar${name}"(type: Jar, dependsOn: compileTask) {
from compileTask.destinationDir
}
}
artifacts {
archives androidSourcesJar
archives androidJavadocJar
}
task installArchives(type: Upload) {
configuration = configurations.archives
repositories.mavenDeployer {
// Deploy to react-native-event-bridge/maven, ready to publish to npm
repository url: "file://${projectDir}/../android/maven"
configureReactNativePom pom
}
}
}

View File

@ -0,0 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.swmansion.reanimated">
</manifest>

View File

@ -0,0 +1,14 @@
package com.facebook.react.uimanager;
/**
* This class provides a way to workaround limited visibility of UIViewOperationQueue#getUIViewOperationQueue.
* We rely on accessing that method to check if operation queue is empty or not. This in turn indicates if
* we are in a middle of processing batch of operations from JS. In such a case we can rely on the enqueued update
* operations to be flushed onto the shadow view hierarchy. Otherwise we want to trigger "dispatchViewUpdates" and
* enforce flush immediately.
*/
public class UIManagerReanimatedHelper {
public static boolean isOperationQueueEmpty(UIImplementation uiImplementation) {
return uiImplementation.getUIViewOperationQueue().isEmpty();
}
}

View File

@ -0,0 +1,28 @@
package com.swmansion.reanimated;
import com.facebook.react.bridge.JSApplicationCausedNativeException;
import com.facebook.react.bridge.NoSuchKeyException;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class MapUtils {
public static int getInt(ReadableMap map, @Nonnull String name, String errorMsg) {
try {
return map.getInt(name);
} catch (NoSuchKeyException e) {
throw new JSApplicationCausedNativeException(errorMsg);
}
}
@Nullable
public static String getString(ReadableMap map, @Nonnull String name, String errorMsg) {
try {
return map.getString(name);
} catch (NoSuchKeyException e) {
throw new JSApplicationCausedNativeException(errorMsg);
}
}
}

View File

@ -0,0 +1,414 @@
package com.swmansion.reanimated;
import android.util.SparseArray;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.GuardedRunnable;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.modules.core.ReactChoreographer;
import com.facebook.react.uimanager.GuardedFrameCallback;
import com.facebook.react.uimanager.ReactShadowNode;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.UIManagerReanimatedHelper;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.EventDispatcherListener;
import com.swmansion.reanimated.nodes.AlwaysNode;
import com.swmansion.reanimated.nodes.BezierNode;
import com.swmansion.reanimated.nodes.BlockNode;
import com.swmansion.reanimated.nodes.ClockNode;
import com.swmansion.reanimated.nodes.ClockOpNode;
import com.swmansion.reanimated.nodes.ConcatNode;
import com.swmansion.reanimated.nodes.CondNode;
import com.swmansion.reanimated.nodes.DebugNode;
import com.swmansion.reanimated.nodes.EventNode;
import com.swmansion.reanimated.nodes.JSCallNode;
import com.swmansion.reanimated.nodes.Node;
import com.swmansion.reanimated.nodes.NoopNode;
import com.swmansion.reanimated.nodes.OperatorNode;
import com.swmansion.reanimated.nodes.PropsNode;
import com.swmansion.reanimated.nodes.SetNode;
import com.swmansion.reanimated.nodes.StyleNode;
import com.swmansion.reanimated.nodes.TransformNode;
import com.swmansion.reanimated.nodes.ValueNode;
import com.swmansion.reanimated.nodes.ParamNode;
import com.swmansion.reanimated.nodes.FunctionNode;
import com.swmansion.reanimated.nodes.CallFuncNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
public class NodesManager implements EventDispatcherListener {
private static final Double ZERO = Double.valueOf(0);
public interface OnAnimationFrame {
void onAnimationFrame();
}
private final SparseArray<Node> mAnimatedNodes = new SparseArray<>();
private final Map<String, EventNode> mEventMapping = new HashMap<>();
private final UIImplementation mUIImplementation;
private final DeviceEventManagerModule.RCTDeviceEventEmitter mEventEmitter;
private final ReactChoreographer mReactChoreographer;
private final GuardedFrameCallback mChoreographerCallback;
private final UIManagerModule.CustomEventNamesResolver mCustomEventNamesResolver;
private final AtomicBoolean mCallbackPosted = new AtomicBoolean();
private final NoopNode mNoopNode;
private final ReactContext mContext;
private final UIManagerModule mUIManager;
private List<OnAnimationFrame> mFrameCallbacks = new ArrayList<>();
private ConcurrentLinkedQueue<Event> mEventQueue = new ConcurrentLinkedQueue<>();
private boolean mWantRunUpdates;
public double currentFrameTimeMs;
public final UpdateContext updateContext;
public Set<String> uiProps = Collections.emptySet();
public Set<String> nativeProps = Collections.emptySet();
private final class NativeUpdateOperation {
public int mViewTag;
public WritableMap mNativeProps;
public NativeUpdateOperation(int viewTag, WritableMap nativeProps) {
mViewTag = viewTag;
mNativeProps = nativeProps;
}
}
private Queue<NativeUpdateOperation> mOperationsInBatch = new LinkedList<>();
public NodesManager(ReactContext context) {
mContext = context;
mUIManager = context.getNativeModule(UIManagerModule.class);
updateContext = new UpdateContext();
mUIImplementation = mUIManager.getUIImplementation();
mCustomEventNamesResolver = mUIManager.getDirectEventNamesResolver();
mEventEmitter = context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
mReactChoreographer = ReactChoreographer.getInstance();
mChoreographerCallback = new GuardedFrameCallback(context) {
@Override
protected void doFrameGuarded(long frameTimeNanos) {
onAnimationFrame(frameTimeNanos);
}
};
mNoopNode = new NoopNode(this);
// We register as event listener at the end, because we pass `this` and we haven't finished contructing an object yet.
// This lead to a crash described in https://github.com/software-mansion/react-native-reanimated/issues/604 which was caused by Nodes Manager being constructed on UI thread and registering for events.
// Events are handled in the native modules thread in the `onEventDispatch()` method.
// This method indirectly uses `mChoreographerCallback` which was created after event registration, creating race condition
mUIManager.getEventDispatcher().addListener(this);
}
public void onHostPause() {
if (mCallbackPosted.get()) {
stopUpdatingOnAnimationFrame();
mCallbackPosted.set(true);
}
}
public void onHostResume() {
if (mCallbackPosted.getAndSet(false)) {
startUpdatingOnAnimationFrame();
}
}
private void startUpdatingOnAnimationFrame() {
if (!mCallbackPosted.getAndSet(true)) {
mReactChoreographer.postFrameCallback(
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE,
mChoreographerCallback);
}
}
private void stopUpdatingOnAnimationFrame() {
if (mCallbackPosted.getAndSet(false)) {
mReactChoreographer.removeFrameCallback(
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE,
mChoreographerCallback);
}
}
private void onAnimationFrame(long frameTimeNanos) {
currentFrameTimeMs = frameTimeNanos / 1000000.;
while (!mEventQueue.isEmpty()) {
handleEvent(mEventQueue.poll());
}
if (!mFrameCallbacks.isEmpty()) {
List<OnAnimationFrame> frameCallbacks = mFrameCallbacks;
mFrameCallbacks = new ArrayList<>(frameCallbacks.size());
for (int i = 0, size = frameCallbacks.size(); i < size; i++) {
frameCallbacks.get(i).onAnimationFrame();
}
}
if (mWantRunUpdates) {
Node.runUpdates(updateContext);
}
if (!mOperationsInBatch.isEmpty()) {
final Queue<NativeUpdateOperation> copiedOperationsQueue = mOperationsInBatch;
mOperationsInBatch = new LinkedList<>();
mContext.runOnNativeModulesQueueThread(
// FIXME replace `mContext` with `mContext.getExceptionHandler()` after RN 0.59 support is dropped
new GuardedRunnable(mContext) {
@Override
public void runGuarded() {
boolean shouldDispatchUpdates = UIManagerReanimatedHelper.isOperationQueueEmpty(mUIImplementation);
while (!copiedOperationsQueue.isEmpty()) {
NativeUpdateOperation op = copiedOperationsQueue.remove();
ReactShadowNode shadowNode = mUIImplementation.resolveShadowNode(op.mViewTag);
if (shadowNode != null) {
mUIManager.updateView(op.mViewTag, shadowNode.getViewClass(), op.mNativeProps);
}
}
if (shouldDispatchUpdates) {
mUIImplementation.dispatchViewUpdates(-1); // no associated batchId
}
}
});
}
mCallbackPosted.set(false);
mWantRunUpdates = false;
if (!mFrameCallbacks.isEmpty() || !mEventQueue.isEmpty()) {
// enqueue next frame
startUpdatingOnAnimationFrame();
}
}
/**
* Null-safe way of getting node's value. If node is not present we return 0. This also matches
* iOS behavior when the app won't just crash.
*/
public Object getNodeValue(int nodeID) {
Node node = mAnimatedNodes.get(nodeID);
if (node != null) {
return node.value();
}
return ZERO;
}
/**
* Null-safe way of getting node reference. This method always returns non-null instance. If the
* node is not present we try to return a "no-op" node that allows for "set" calls and always
* returns 0 as a value.
*/
public <T extends Node> T findNodeById(int id, Class<T> type) {
Node node = mAnimatedNodes.get(id);
if (node == null) {
if (type == Node.class || type == ValueNode.class) {
return (T) mNoopNode;
}
throw new IllegalArgumentException("Requested node with id " + id + " of type " + type +
" cannot be found");
}
if (type.isInstance(node)) {
return (T) node;
}
throw new IllegalArgumentException("Node with id " + id + " is of incompatible type " +
node.getClass() + ", requested type was " + type);
}
public void createNode(int nodeID, ReadableMap config) {
if (mAnimatedNodes.get(nodeID) != null) {
throw new JSApplicationIllegalArgumentException("Animated node with ID " + nodeID +
" already exists");
}
String type = config.getString("type");
final Node node;
if ("props".equals(type)) {
node = new PropsNode(nodeID, config, this, mUIImplementation);
} else if ("style".equals(type)) {
node = new StyleNode(nodeID, config, this);
} else if ("transform".equals(type)) {
node = new TransformNode(nodeID, config, this);
} else if ("value".equals(type)) {
node = new ValueNode(nodeID, config, this);
} else if ("block".equals(type)) {
node = new BlockNode(nodeID, config, this);
} else if ("cond".equals(type)) {
node = new CondNode(nodeID, config, this);
} else if ("op".equals(type)) {
node = new OperatorNode(nodeID, config, this);
} else if ("set".equals(type)) {
node = new SetNode(nodeID, config, this);
} else if ("debug".equals(type)) {
node = new DebugNode(nodeID, config, this);
} else if ("clock".equals(type)) {
node = new ClockNode(nodeID, config, this);
} else if ("clockStart".equals(type)) {
node = new ClockOpNode.ClockStartNode(nodeID, config, this);
} else if ("clockStop".equals(type)) {
node = new ClockOpNode.ClockStopNode(nodeID, config, this);
} else if ("clockTest".equals(type)) {
node = new ClockOpNode.ClockTestNode(nodeID, config, this);
} else if ("call".equals(type)) {
node = new JSCallNode(nodeID, config, this);
} else if ("bezier".equals(type)) {
node = new BezierNode(nodeID, config, this);
} else if ("event".equals(type)) {
node = new EventNode(nodeID, config, this);
} else if ("always".equals(type)) {
node = new AlwaysNode(nodeID, config, this);
} else if ("concat".equals(type)) {
node = new ConcatNode(nodeID, config, this);
} else if ("param".equals(type)) {
node = new ParamNode(nodeID, config, this);
} else if ("func".equals(type)) {
node = new FunctionNode(nodeID, config, this);
} else if ("callfunc".equals(type)) {
node = new CallFuncNode(nodeID, config, this);
} else {
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
}
mAnimatedNodes.put(nodeID, node);
}
public void dropNode(int tag) {
mAnimatedNodes.remove(tag);
}
public void connectNodes(int parentID, int childID) {
Node parentNode = mAnimatedNodes.get(parentID);
Node childNode = mAnimatedNodes.get(childID);
if (childNode == null) {
throw new JSApplicationIllegalArgumentException("Animated node with ID " + childID +
" does not exists");
}
parentNode.addChild(childNode);
}
public void disconnectNodes(int parentID, int childID) {
Node parentNode = mAnimatedNodes.get(parentID);
Node childNode = mAnimatedNodes.get(childID);
if (childNode == null) {
throw new JSApplicationIllegalArgumentException("Animated node with ID " + childID +
" does not exists");
}
parentNode.removeChild(childNode);
}
public void connectNodeToView(int nodeID, int viewTag) {
Node node = mAnimatedNodes.get(nodeID);
if (node == null) {
throw new JSApplicationIllegalArgumentException("Animated node with ID " + nodeID +
" does not exists");
}
if (!(node instanceof PropsNode)) {
throw new JSApplicationIllegalArgumentException("Animated node connected to view should be" +
"of type " + PropsNode.class.getName());
}
((PropsNode) node).connectToView(viewTag);
}
public void disconnectNodeFromView(int nodeID, int viewTag) {
Node node = mAnimatedNodes.get(nodeID);
if (node == null) {
throw new JSApplicationIllegalArgumentException("Animated node with ID " + nodeID +
" does not exists");
}
if (!(node instanceof PropsNode)) {
throw new JSApplicationIllegalArgumentException("Animated node connected to view should be" +
"of type " + PropsNode.class.getName());
}
((PropsNode) node).disconnectFromView(viewTag);
}
public void enqueueUpdateViewOnNativeThread(int viewTag, WritableMap nativeProps) {
mOperationsInBatch.add(new NativeUpdateOperation(viewTag, nativeProps));
}
public void attachEvent(int viewTag, String eventName, int eventNodeID) {
String key = viewTag + eventName;
EventNode node = (EventNode) mAnimatedNodes.get(eventNodeID);
if (node == null) {
throw new JSApplicationIllegalArgumentException("Event node " + eventNodeID + " does not exists");
}
if (mEventMapping.containsKey(key)) {
throw new JSApplicationIllegalArgumentException("Event handler already set for the given view and event type");
}
mEventMapping.put(key, node);
}
public void detachEvent(int viewTag, String eventName, int eventNodeID) {
String key = viewTag + eventName;
mEventMapping.remove(key);
}
public void configureProps(Set<String> nativePropsSet, Set<String> uiPropsSet) {
nativeProps = nativePropsSet;
uiProps = uiPropsSet;
}
public void getValue(int nodeID, Callback callback) {
callback.invoke(mAnimatedNodes.get(nodeID).value());
}
public void postRunUpdatesAfterAnimation() {
mWantRunUpdates = true;
startUpdatingOnAnimationFrame();
}
public void postOnAnimation(OnAnimationFrame onAnimationFrame) {
mFrameCallbacks.add(onAnimationFrame);
startUpdatingOnAnimationFrame();
}
@Override
public void onEventDispatch(Event event) {
// Events can be dispatched from any thread so we have to make sure handleEvent is run from the
// UI thread.
if (UiThreadUtil.isOnUiThread()) {
handleEvent(event);
} else {
mEventQueue.offer(event);
startUpdatingOnAnimationFrame();
}
}
private void handleEvent(Event event) {
if (!mEventMapping.isEmpty()) {
// If the event has a different name in native convert it to it's JS name.
String eventName = mCustomEventNamesResolver.resolveCustomEventName(event.getEventName());
int viewTag = event.getViewTag();
String key = viewTag + eventName;
EventNode node = mEventMapping.get(key);
if (node != null) {
event.dispatch(node);
}
}
}
public void sendEvent(String name, WritableMap body) {
mEventEmitter.emit(name, body);
}
public void setValue(int nodeID, Double newValue) {
Node node = mAnimatedNodes.get(nodeID);
if (node != null) {
((ValueNode) node).setValue(newValue);
}
}
}

View File

@ -0,0 +1,226 @@
package com.swmansion.reanimated;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.NativeViewHierarchyManager;
import com.facebook.react.uimanager.UIBlock;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.UIManagerModuleListener;
import com.swmansion.reanimated.transitions.TransitionModule;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nullable;
@ReactModule(name = ReanimatedModule.NAME)
public class ReanimatedModule extends ReactContextBaseJavaModule implements
LifecycleEventListener, UIManagerModuleListener {
public static final String NAME = "ReanimatedModule";
private interface UIThreadOperation {
void execute(NodesManager nodesManager);
}
private ArrayList<UIThreadOperation> mOperations = new ArrayList<>();
private @Nullable NodesManager mNodesManager;
private @Nullable TransitionModule mTransitionManager;
public ReanimatedModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public void initialize() {
ReactApplicationContext reactCtx = getReactApplicationContext();
UIManagerModule uiManager = reactCtx.getNativeModule(UIManagerModule.class);
reactCtx.addLifecycleEventListener(this);
uiManager.addUIManagerListener(this);
mTransitionManager = new TransitionModule(uiManager);
}
@Override
public void onHostPause() {
if (mNodesManager != null) {
mNodesManager.onHostPause();
}
}
@Override
public void onHostResume() {
if (mNodesManager != null) {
mNodesManager.onHostResume();
}
}
@Override
public void onHostDestroy() {
// do nothing
}
@Override
public void willDispatchViewUpdates(final UIManagerModule uiManager) {
if (mOperations.isEmpty()) {
return;
}
final ArrayList<UIThreadOperation> operations = mOperations;
mOperations = new ArrayList<>();
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
NodesManager nodesManager = getNodesManager();
for (UIThreadOperation operation : operations) {
operation.execute(nodesManager);
}
}
});
}
@Override
public String getName() {
return NAME;
}
private NodesManager getNodesManager() {
if (mNodesManager == null) {
mNodesManager = new NodesManager(getReactApplicationContext());
}
return mNodesManager;
}
@ReactMethod
public void animateNextTransition(int tag, ReadableMap config) {
mTransitionManager.animateNextTransition(tag, config);
}
@ReactMethod
public void createNode(final int tag, final ReadableMap config) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.createNode(tag, config);
}
});
}
@ReactMethod
public void dropNode(final int tag) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.dropNode(tag);
}
});
}
@ReactMethod
public void connectNodes(final int parentID, final int childID) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.connectNodes(parentID, childID);
}
});
}
@ReactMethod
public void disconnectNodes(final int parentID, final int childID) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.disconnectNodes(parentID, childID);
}
});
}
@ReactMethod
public void connectNodeToView(final int nodeID, final int viewTag) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.connectNodeToView(nodeID, viewTag);
}
});
}
@ReactMethod
public void disconnectNodeFromView(final int nodeID, final int viewTag) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.disconnectNodeFromView(nodeID, viewTag);
}
});
}
@ReactMethod
public void attachEvent(final int viewTag, final String eventName, final int eventNodeID) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.attachEvent(viewTag, eventName, eventNodeID);
}
});
}
@ReactMethod
public void detachEvent(final int viewTag, final String eventName, final int eventNodeID) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.detachEvent(viewTag, eventName, eventNodeID);
}
});
}
@ReactMethod
public void configureProps(ReadableArray nativePropsArray, ReadableArray uiPropsArray) {
int size = nativePropsArray.size();
final Set<String> nativeProps = new HashSet<>(size);
for (int i = 0; i < size; i++) {
nativeProps.add(nativePropsArray.getString(i));
}
size = uiPropsArray.size();
final Set<String> uiProps = new HashSet<>(size);
for (int i = 0; i < size; i++) {
uiProps.add(uiPropsArray.getString(i));
}
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.configureProps(nativeProps, uiProps);
}
});
}
@ReactMethod
public void getValue(final int nodeID, final Callback callback) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.getValue(nodeID, callback);
}
});
}
@ReactMethod
public void setValue(final int nodeID, final Double newValue) {
mOperations.add(new UIThreadOperation() {
@Override
public void execute(NodesManager nodesManager) {
nodesManager.setValue(nodeID, newValue);
}
});
}
}

View File

@ -0,0 +1,21 @@
package com.swmansion.reanimated;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.List;
public class ReanimatedPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new ReanimatedModule(reactContext));
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.asList();
}
}

View File

@ -0,0 +1,13 @@
package com.swmansion.reanimated;
import com.swmansion.reanimated.nodes.Node;
import java.util.ArrayList;
public class UpdateContext {
public long updateLoopID = 0;
public String callID = "";
public final ArrayList<Node> updatedNodes = new ArrayList<>();
}

View File

@ -0,0 +1,31 @@
package com.swmansion.reanimated;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import java.util.HashMap;
import java.util.Map;
public class Utils {
public static Map<String, Integer> processMapping(ReadableMap style) {
ReadableMapKeySetIterator iter = style.keySetIterator();
HashMap<String, Integer> mapping = new HashMap<>();
while (iter.hasNextKey()) {
String propKey = iter.nextKey();
int nodeIndex = style.getInt(propKey);
mapping.put(propKey, nodeIndex);
}
return mapping;
}
public static int[] processIntArray(ReadableArray ary) {
int size = ary.size();
int[] res = new int[size];
for (int i = 0; i < size; i++) {
res[i] = ary.getInt(i);
}
return res;
}
}

View File

@ -0,0 +1,25 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.MapUtils;
import com.swmansion.reanimated.NodesManager;
public class AlwaysNode extends Node implements FinalNode {
public AlwaysNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mNodeToBeEvaluated = MapUtils.getInt(config, "what", "Reanimated: Argument passed to always node is either of wrong type or is missing.");
}
private int mNodeToBeEvaluated;
@Override
public void update() {
this.value();
}
@Override
protected Double evaluate() {
mNodesManager.findNodeById(mNodeToBeEvaluated, Node.class).value();
return ZERO;
}
}

View File

@ -0,0 +1,84 @@
package com.swmansion.reanimated.nodes;
import android.graphics.PointF;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.MapUtils;
import com.swmansion.reanimated.NodesManager;
public class BezierNode extends Node {
private static class CubicBezierInterpolator {
protected PointF start;
protected PointF end;
protected PointF a = new PointF();
protected PointF b = new PointF();
protected PointF c = new PointF();
public CubicBezierInterpolator(PointF start, PointF end) {
this.start = start;
this.end = end;
}
public CubicBezierInterpolator(float startX, float startY, float endX, float endY) {
this(new PointF(startX, startY), new PointF(endX, endY));
}
public float getInterpolation(float time) {
return getBezierCoordinateY(getXForTime(time));
}
protected float getBezierCoordinateY(float time) {
c.y = 3 * start.y;
b.y = 3 * (end.y - start.y) - c.y;
a.y = 1 - c.y - b.y;
return time * (c.y + time * (b.y + time * a.y));
}
protected float getXForTime(float time) {
float x = time;
float z;
for (int i = 1; i < 14; i++) {
z = getBezierCoordinateX(x) - time;
if (Math.abs(z) < 1e-3) {
break;
}
x -= z / getXDerivate(x);
}
return x;
}
private float getXDerivate(float t) {
return c.x + t * (2 * b.x + 3 * a.x * t);
}
private float getBezierCoordinateX(float time) {
c.x = 3 * start.x;
b.x = 3 * (end.x - start.x) - c.x;
a.x = 1 - c.x - b.x;
return time * (c.x + time * (b.x + time * a.x));
}
}
private final int mInputID;
private final CubicBezierInterpolator mInterpolator;
public BezierNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mInputID = MapUtils.getInt(config, "input", "Reanimated: Argument passed to bezier node is either of wrong type or is missing.");
float startX = (float) config.getDouble("mX1");
float startY = (float) config.getDouble("mY1");
float endX = (float) config.getDouble("mX2");
float endY = (float) config.getDouble("mY2");
mInterpolator = new CubicBezierInterpolator(startX, startY, endX, endY);
}
@Override
protected Double evaluate() {
Double in = (Double) mNodesManager.getNodeValue(mInputID);
return Double.valueOf(mInterpolator.getInterpolation(in.floatValue()));
}
}

View File

@ -0,0 +1,24 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.Utils;
public class BlockNode extends Node {
private final int[] mBlock;
public BlockNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mBlock = Utils.processIntArray(config.getArray("block"));
}
@Override
protected Object evaluate() {
Object res = null;
for (int i = 0; i < mBlock.length; i++) {
res = mNodesManager.findNodeById(mBlock[i], Node.class).value();
}
return res;
}
}

View File

@ -0,0 +1,48 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.Utils;
public class CallFuncNode extends Node {
private String mPreviousCallID;
private final int mWhatNodeID;
private final int[] mArgs;
private final int[] mParams;
public CallFuncNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mWhatNodeID = config.getInt("what");
mParams = Utils.processIntArray(config.getArray("params"));
mArgs = Utils.processIntArray(config.getArray("args"));
}
private void beginContext() {
mPreviousCallID = mNodesManager.updateContext.callID;
mNodesManager.updateContext.callID = mNodesManager.updateContext.callID + '/' + String.valueOf(mNodeID);
for (int i = 0; i < mParams.length; i++) {
int paramId = mParams[i];
ParamNode paramNode = mNodesManager.findNodeById(paramId, ParamNode.class);
paramNode.beginContext(mArgs[i], mPreviousCallID);
}
}
private void endContext() {
for (int i = 0; i < mParams.length; i++) {
int paramId = mParams[i];
ParamNode paramNode = mNodesManager.findNodeById(paramId, ParamNode.class);
paramNode.endContext();
}
mNodesManager.updateContext.callID = mPreviousCallID;
}
@Override
protected Object evaluate() {
beginContext();
Node whatNode = mNodesManager.findNodeById(mWhatNodeID, Node.class);
Object retVal = whatNode.value();
endContext();
return retVal;
}
}

View File

@ -0,0 +1,38 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.NodesManager;
public class ClockNode extends Node implements NodesManager.OnAnimationFrame {
public boolean isRunning;
public ClockNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
}
public void start() {
if (isRunning) {
return;
}
isRunning = true;
mNodesManager.postOnAnimation(this);
}
public void stop() {
isRunning = false;
}
@Override
protected Double evaluate() {
return mNodesManager.currentFrameTimeMs;
}
@Override
public void onAnimationFrame() {
if (isRunning) {
markUpdated();
mNodesManager.postOnAnimation(this);
}
}
}

View File

@ -0,0 +1,69 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.MapUtils;
import com.swmansion.reanimated.NodesManager;
public abstract class ClockOpNode extends Node {
public static class ClockStartNode extends ClockOpNode {
public ClockStartNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
}
@Override
protected Double eval(Node clock) {
if (clock instanceof ParamNode) {
((ParamNode) clock).start();
} else {
((ClockNode) clock).start();
}
return ZERO;
}
}
public static class ClockStopNode extends ClockOpNode {
public ClockStopNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
}
@Override
protected Double eval(Node clock) {
if (clock instanceof ParamNode) {
((ParamNode) clock).stop();
} else {
((ClockNode) clock).stop();
}
return ZERO;
}
}
public static class ClockTestNode extends ClockOpNode {
public ClockTestNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
}
@Override
protected Double eval(Node clock) {
if (clock instanceof ParamNode) {
return ((ParamNode) clock).isRunning() ? 1. : 0.;
}
return ((ClockNode) clock).isRunning ? 1. : 0.;
}
}
private int clockID;
public ClockOpNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
clockID = MapUtils.getInt(config, "clock", "Reanimated: Argument passed to clock node is either of wrong type or is missing.");
}
@Override
protected Double evaluate() {
Node clock = mNodesManager.findNodeById(clockID, Node.class);
return eval(clock);
}
protected abstract Double eval(Node clock);
}

View File

@ -0,0 +1,36 @@
package com.swmansion.reanimated.nodes;
import java.text.NumberFormat;
import java.util.Locale;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.Utils;
public class ConcatNode extends Node {
private final int[] mInputIDs;
private final static NumberFormat sFormatter = NumberFormat.getInstance(Locale.ENGLISH);
static {
sFormatter.setMinimumFractionDigits(0);
sFormatter.setGroupingUsed(false);
}
public ConcatNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mInputIDs = Utils.processIntArray(config.getArray("input"));
}
@Override
protected String evaluate() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < mInputIDs.length; i++) {
Node inputNodes = mNodesManager.findNodeById(mInputIDs[i], Node.class);
Object value = inputNodes.value();
if (value instanceof Double) {
value = sFormatter.format((Double) value);
}
builder.append(value);
}
return builder.toString();
}
}

View File

@ -0,0 +1,29 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.MapUtils;
import com.swmansion.reanimated.NodesManager;
public class CondNode extends Node {
private final int mCondID, mIfBlockID, mElseBlockID;
public CondNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mCondID = MapUtils.getInt(config, "cond", "Reanimated: First argument passed to cond node is either of wrong type or is missing.");
mIfBlockID = MapUtils.getInt(config, "ifBlock", "Reanimated: Second argument passed to cond node is either of wrong type or is missing.");
mElseBlockID = config.hasKey("elseBlock")
? MapUtils.getInt(config, "elseBlock", "Reanimated: Second argument passed to cond node is either of wrong type or is missing.")
: -1;
}
@Override
protected Object evaluate() {
Object cond = mNodesManager.getNodeValue(mCondID);
if (cond instanceof Number && ((Number) cond).doubleValue() != 0.0) {
// This is not a good way to compare doubles but in this case it is what we want
return mIfBlockID != -1 ? mNodesManager.getNodeValue(mIfBlockID) : ZERO;
}
return mElseBlockID != -1 ? mNodesManager.getNodeValue(mElseBlockID) : ZERO;
}
}

View File

@ -0,0 +1,26 @@
package com.swmansion.reanimated.nodes;
import android.util.Log;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.MapUtils;
import com.swmansion.reanimated.NodesManager;
public class DebugNode extends Node {
private final String mMessage;
private final int mValueID;
public DebugNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mMessage = MapUtils.getString(config, "message", "Reanimated: First argument passed to debug node is either of wrong type or is missing.");
mValueID = MapUtils.getInt(config, "value", "Reanimated: Second argument passed to debug node is either of wrong type or is missing.");
}
@Override
protected Object evaluate() {
Object value = mNodesManager.findNodeById(mValueID, Node.class).value();
Log.d("REANIMATED", String.format("%s %s", mMessage, value));
return value;
}
}

View File

@ -0,0 +1,84 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.swmansion.reanimated.NodesManager;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
public class EventNode extends Node implements RCTEventEmitter {
private static class EventMap {
private final int nodeID;
private final String[] path;
public EventMap(ReadableArray eventPath) {
int size = eventPath.size();
path = new String[size - 1];
for (int i = 0; i < size - 1; i++) {
path[i] = eventPath.getString(i);
}
nodeID = eventPath.getInt(size - 1);
}
public Double lookupValue(ReadableMap event) {
ReadableMap map = event;
for (int i = 0; map != null && i < path.length - 1; i++) {
String key = path[i];
map = map.hasKey(key) ? map.getMap(key) : null;
}
if (map != null) {
String key = path[path.length - 1];
return map.hasKey(key) ? map.getDouble(key) : null;
}
return null;
}
}
private static List<EventMap> processMapping(ReadableArray mapping) {
int size = mapping.size();
List<EventMap> res = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
res.add(new EventMap(mapping.getArray(i)));
}
return res;
}
private final List<EventMap> mMapping;
public EventNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mMapping = processMapping(config.getArray("argMapping"));
}
@Override
public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event) {
if (event == null) {
throw new IllegalArgumentException("Animated events must have event data.");
}
for (int i = 0; i < mMapping.size(); i++) {
EventMap eventMap = mMapping.get(i);
Double value = eventMap.lookupValue(event);
if (value != null) {
mNodesManager.findNodeById(eventMap.nodeID, ValueNode.class).setValue(value);
}
}
}
@Override
public void receiveTouches(String eventName, WritableArray touches, WritableArray changedIndices) {
throw new RuntimeException("receiveTouches is not support by animated events");
}
@Override
protected Double evaluate() {
return ZERO;
}
}

View File

@ -0,0 +1,5 @@
package com.swmansion.reanimated.nodes;
public interface FinalNode {
void update();
}

View File

@ -0,0 +1,20 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.NodesManager;
public class FunctionNode extends Node {
private final int mWhatNodeID;
public FunctionNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mWhatNodeID = config.getInt("what");
}
@Override
protected Object evaluate() {
Node what = mNodesManager.findNodeById(mWhatNodeID, Node.class);
return what.value();
}
}

View File

@ -0,0 +1,41 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.Utils;
public class JSCallNode extends Node {
private final int[] mInputIDs;
public JSCallNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mInputIDs = Utils.processIntArray(config.getArray("input"));
}
@Override
protected Double evaluate() {
WritableArray args = Arguments.createArray();
for (int i = 0; i < mInputIDs.length; i++) {
Node node = mNodesManager.findNodeById(mInputIDs[i], Node.class);
if (node.value() == null) {
args.pushNull();
} else {
Object value = node.value();
if (value instanceof String) {
args.pushString((String) value);
} else {
args.pushDouble(node.doubleValue());
}
}
}
WritableMap eventData = Arguments.createMap();
eventData.putInt("id", mNodeID);
eventData.putArray("args", args);
mNodesManager.sendEvent("onReanimatedCall", eventData);
return ZERO;
}
}

View File

@ -0,0 +1,137 @@
package com.swmansion.reanimated.nodes;
import android.util.SparseArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.UpdateContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import javax.annotation.Nullable;
public abstract class Node {
public static final Double ZERO = Double.valueOf(0);
public static final Double ONE = Double.valueOf(1);
protected final int mNodeID;
protected final NodesManager mNodesManager;
protected final UpdateContext mUpdateContext;
private final Map<String, Long> mLastLoopID = new HashMap<>();
private final Map<String, Object> mMemoizedValue = new HashMap<>();
private @Nullable List<Node> mChildren; /* lazy-initialized when a child is added */
public Node(int nodeID, @Nullable ReadableMap config, NodesManager nodesManager) {
mLastLoopID.put("", -1L);
mNodeID = nodeID;
mNodesManager = nodesManager;
mUpdateContext = nodesManager.updateContext;
}
protected abstract @Nullable Object evaluate();
public final @Nullable Object value() {
if (!mLastLoopID.containsKey(mUpdateContext.callID) || mLastLoopID.get(mUpdateContext.callID) < mUpdateContext.updateLoopID) {
mLastLoopID.put(mUpdateContext.callID, mUpdateContext.updateLoopID);
Object result = evaluate();
mMemoizedValue.put(mUpdateContext.callID, result);
return result;
}
return mMemoizedValue.get(mUpdateContext.callID);
}
/**
* This method will never return null. If value is null or of a different type we try to cast and
* return 0 if we fail to properly cast the value. This is to match iOS behavior where the node
* would not throw even if the value was not set.
*/
public final Double doubleValue() {
Object value = value();
if (value == null) {
return ZERO;
} else if (value instanceof Double) {
return (Double) value;
} else if (value instanceof Number) {
return Double.valueOf(((Number) value).doubleValue());
} else if (value instanceof Boolean) {
return ((Boolean) value).booleanValue() ? ONE : ZERO;
}
throw new IllegalStateException("Value of node " + this + " cannot be cast to a number");
}
public void addChild(Node child) {
if (mChildren == null) {
mChildren = new ArrayList<>();
}
mChildren.add(child);
child.dangerouslyRescheduleEvaluate();
}
public void removeChild(Node child) {
if (mChildren != null) {
mChildren.remove(child);
}
}
protected void markUpdated() {
UiThreadUtil.assertOnUiThread();
mUpdateContext.updatedNodes.add(this);
mNodesManager.postRunUpdatesAfterAnimation();
}
protected final void dangerouslyRescheduleEvaluate() {
mLastLoopID.put(mUpdateContext.callID, -1L);
markUpdated();
}
protected final void forceUpdateMemoizedValue(Object value) {
mMemoizedValue.put(mUpdateContext.callID, value);
markUpdated();
}
private static void findAndUpdateNodes(Node node, Set<Node> visitedNodes, Stack<FinalNode> finalNodes) {
if (visitedNodes.contains(node)) {
return;
} else {
visitedNodes.add(node);
}
List<Node> children = node.mChildren;
if (children != null) {
for (Node child : children) {
findAndUpdateNodes(child, visitedNodes, finalNodes);
}
}
if (node instanceof FinalNode) {
finalNodes.push((FinalNode) node);
}
}
public static void runUpdates(UpdateContext updateContext) {
UiThreadUtil.assertOnUiThread();
ArrayList<Node> updatedNodes = updateContext.updatedNodes;
Set<Node> visitedNodes = new HashSet<>();
Stack<FinalNode> finalNodes = new Stack<>();
for (int i = 0; i < updatedNodes.size(); i++) {
findAndUpdateNodes(updatedNodes.get(i), visitedNodes, finalNodes);
if (i == updatedNodes.size() - 1) {
while (!finalNodes.isEmpty()) {
finalNodes.pop().update();
}
}
}
updatedNodes.clear();
updateContext.updateLoopID++;
}
}

View File

@ -0,0 +1,37 @@
package com.swmansion.reanimated.nodes;
import com.swmansion.reanimated.NodesManager;
/**
* This node is used by {@link NodesManager} to return in place of a missing node that might have
* been requested. This way we avoid a top of null-checks and we make nodes manager compatible with
* the iOS code which does not crash for missing nodes. In most of the cases it is desirable to
* handle missing nodes gracefully as it usually means the node hasn't been hooked under animated
* view prop but is referenced in the graph (e.g. to support some edge case).
*/
public class NoopNode extends ValueNode {
public NoopNode(NodesManager nodesManager) {
super(-2, null, nodesManager);
}
@Override
public void setValue(Object value) {
// no-op
}
@Override
public void addChild(Node child) {
// no-op
}
@Override
public void removeChild(Node child) {
// no-op
}
@Override
protected void markUpdated() {
// no-op
}
}

View File

@ -0,0 +1,346 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.Utils;
public class OperatorNode extends Node {
private static boolean truthy(Object value) {
return value != null && !value.equals(0.);
}
private interface Operator {
double evaluate(Node[] input);
}
private static abstract class ReduceOperator implements Operator {
@Override
public double evaluate(Node[] input) {
double acc = input[0].doubleValue();
for (int i = 1; i < input.length; i++) {
acc = reduce(acc, input[i].doubleValue());
}
return acc;
}
public abstract double reduce(Double x, Double y);
}
private static abstract class SingleOperator implements Operator {
@Override
public double evaluate(Node[] input) {
return eval((Double) input[0].value());
}
public abstract double eval(Double x);
}
private static abstract class CompOperator implements Operator {
@Override
public double evaluate(Node[] input) {
return eval((Double) input[0].value(), (Double) input[1].value()) ? 1. : 0.;
}
public abstract boolean eval(Double x, Double y);
}
// arithmetic
private static final Operator ADD = new ReduceOperator() {
@Override
public double reduce(Double x, Double y) {
return x + y;
}
};
private static final Operator SUB = new ReduceOperator() {
@Override
public double reduce(Double x, Double y) {
return x - y;
}
};
private static final Operator MULTIPLY= new ReduceOperator() {
@Override
public double reduce(Double x, Double y) {
return x * y;
}
};
private static final Operator DIVIDE = new ReduceOperator() {
@Override
public double reduce(Double x, Double y) {
return x / y;
}
};
private static final Operator POW = new ReduceOperator() {
@Override
public double reduce(Double x, Double y) {
return Math.pow(x, y);
}
};
private static final Operator MODULO = new ReduceOperator() {
@Override
public double reduce(Double x, Double y) {
return ((x % y) + y) % y;
}
};
private static final Operator SQRT = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.sqrt(x);
}
};
private static final Operator LOG = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.log(x);
}
};
private static final Operator SIN = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.sin(x);
}
};
private static final Operator COS = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.cos(x);
}
};
private static final Operator TAN = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.tan(x);
}
};
private static final Operator ACOS = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.acos(x);
}
};
private static final Operator ASIN = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.asin(x);
}
};
private static final Operator ATAN = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.atan(x);
}
};
private static final Operator EXP = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.exp(x);
}
};
private static final Operator ROUND = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.round(x);
}
};
private static final Operator ABS = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.abs(x);
}
};
private static final Operator FLOOR = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.floor(x);
}
};
private static final Operator CEIL = new SingleOperator() {
@Override
public double eval(Double x) {
return Math.ceil(x);
}
};
private static final Operator MIN = new ReduceOperator() {
@Override
public double reduce(Double x, Double y) {
return Math.min(x, y);
}
};
private static final Operator MAX = new ReduceOperator() {
@Override
public double reduce(Double x, Double y) {
return Math.max(x, y);
}
};
// logical
private static final Operator AND = new Operator() {
@Override
public double evaluate(Node[] input) {
boolean res = truthy(input[0].value());
for (int i = 1; i < input.length && res; i++) {
res = res && truthy(input[i].value());
}
return res ? 1. : 0.;
}
};
private static final Operator OR = new Operator() {
@Override
public double evaluate(Node[] input) {
boolean res = truthy(input[0].value());
for (int i = 1; i < input.length && !res; i++) {
res = res || truthy(input[i].value());
}
return res ? 1. : 0.;
}
};
private static final Operator NOT = new Operator() {
@Override
public double evaluate(Node[] input) {
return truthy(input[0].value()) ? 0. : 1.;
}
};
private static final Operator DEFINED = new Operator() {
@Override
public double evaluate(Node[] input) {
Object res = input[0].value();
return (res != null && !(res instanceof Double && ((Double) res).isNaN())) ? 1. : 0.;
}
};
// comparison
private static final Operator LESS_THAN = new CompOperator() {
@Override
public boolean eval(Double x, Double y) {
if (x == null || y == null) {
return false;
}
return x < y;
}
};
private static final Operator EQ = new CompOperator() {
@Override
public boolean eval(Double x, Double y) {
if (x == null || y == null) {
return x == y;
}
return x.doubleValue() == y.doubleValue();
}
};
private static final Operator GREATER_THAN = new CompOperator() {
@Override
public boolean eval(Double x, Double y) {
if (x == null || y == null) {
return false;
}
return x > y;
}
};
private static final Operator LESS_OR_EQ = new CompOperator() {
@Override
public boolean eval(Double x, Double y) {
return x <= y;
}
};
private static final Operator GREATER_OR_EQ = new CompOperator() {
@Override
public boolean eval(Double x, Double y) {
return x >= y;
}
};
private static final Operator NEQ = new CompOperator() {
@Override
public boolean eval(Double x, Double y) {
if (x == null || y == null) {
return x == y;
}
return x.doubleValue() != y.doubleValue();
}
};
private final int[] mInputIDs;
private final Node[] mInputNodes;
private final Operator mOperator;
public OperatorNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mInputIDs = Utils.processIntArray(config.getArray("input"));
mInputNodes = new Node[mInputIDs.length];
String op = config.getString("op");
if ("add".equals(op)) {
mOperator = ADD;
} else if ("sub".equals(op)) {
mOperator = SUB;
} else if ("multiply".equals(op)) {
mOperator = MULTIPLY;
} else if ("divide".equals(op)) {
mOperator = DIVIDE;
} else if ("pow".equals(op)) {
mOperator = POW;
} else if ("modulo".equals(op)) {
mOperator = MODULO;
} else if ("sqrt".equals(op)) {
mOperator = SQRT;
} else if ("log".equals(op)) {
mOperator = LOG;
} else if ("sin".equals(op)) {
mOperator = SIN;
} else if ("cos".equals(op)) {
mOperator = COS;
} else if ("tan".equals(op)) {
mOperator = TAN;
} else if ("acos".equals(op)) {
mOperator = ACOS;
} else if ("asin".equals(op)) {
mOperator = ASIN;
} else if ("atan".equals(op)) {
mOperator = ATAN;
} else if ("exp".equals(op)) {
mOperator = EXP;
} else if ("round".equals(op)) {
mOperator = ROUND;
} else if ("and".equals(op)) {
mOperator = AND;
} else if ("or".equals(op)) {
mOperator = OR;
} else if ("not".equals(op)) {
mOperator = NOT;
} else if ("defined".equals(op)) {
mOperator = DEFINED;
} else if ("lessThan".equals(op)) {
mOperator = LESS_THAN;
} else if ("eq".equals(op)) {
mOperator = EQ;
} else if ("greaterThan".equals(op)) {
mOperator = GREATER_THAN;
} else if ("lessOrEq".equals(op)) {
mOperator = LESS_OR_EQ;
} else if ("greaterOrEq".equals(op)) {
mOperator = GREATER_OR_EQ;
} else if ("neq".equals(op)) {
mOperator = NEQ;
} else if ("abs".equals(op)) {
mOperator = ABS;
}else if ("floor".equals(op)) {
mOperator = FLOOR;
}else if ("ceil".equals(op)) {
mOperator = CEIL;
}else if ("max".equals(op)) {
mOperator = MAX;
}else if ("min".equals(op)) {
mOperator = MIN;
} else {
throw new JSApplicationIllegalArgumentException("Unrecognized operator " + op);
}
}
@Override
protected Object evaluate() {
for (int i = 0; i < mInputIDs.length; i++) {
mInputNodes[i] = mNodesManager.findNodeById(mInputIDs[i], Node.class);
}
return mOperator.evaluate(mInputNodes);
}
}

View File

@ -0,0 +1,76 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.NodesManager;
import java.util.Stack;
public class ParamNode extends ValueNode {
private final Stack<Integer> mArgsStack;
private String mPrevCallID;
public ParamNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mArgsStack = new Stack<>();
}
@Override
public void setValue(Object value) {
Node node = mNodesManager.findNodeById(mArgsStack.peek(), Node.class);
String callID = mUpdateContext.callID;
mUpdateContext.callID = mPrevCallID;
((ValueNode) node).setValue(value);
mUpdateContext.callID = callID;
forceUpdateMemoizedValue(value);
}
public void beginContext(Integer ref, String prevCallID) {
mPrevCallID = prevCallID;
mArgsStack.push(ref);
}
public void endContext() {
mArgsStack.pop();
}
@Override
protected Object evaluate() {
String callID = mUpdateContext.callID;
mUpdateContext.callID = mPrevCallID;
Node node = mNodesManager.findNodeById(mArgsStack.peek(), Node.class);
Object val = node.value();
mUpdateContext.callID = callID;
return val;
}
public void start() {
Node node = mNodesManager.findNodeById(mArgsStack.peek(), Node.class);
if (node instanceof ParamNode) {
((ParamNode) node).start();
} else {
((ClockNode) node).start();
}
}
public void stop() {
Node node = mNodesManager.findNodeById(mArgsStack.peek(), Node.class);
if (node instanceof ParamNode) {
((ParamNode) node).stop();
} else {
((ClockNode) node).stop();
}
}
public boolean isRunning() {
Node node = mNodesManager.findNodeById(mArgsStack.peek(), Node.class);
if (node instanceof ParamNode) {
return ((ParamNode) node).isRunning();
}
return ((ClockNode) node).isRunning;
}
}

View File

@ -0,0 +1,157 @@
package com.swmansion.reanimated.nodes;
import android.view.View;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.UIImplementation;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.Utils;
import java.util.Map;
public class PropsNode extends Node implements FinalNode {
private final Map<String, Integer> mMapping;
private final UIImplementation mUIImplementation;
private int mConnectedViewTag = View.NO_ID;
private final JavaOnlyMap mPropMap;
private final ReactStylesDiffMap mDiffMap;
private static void addProp(WritableMap propMap, String key, Object value) {
if (value == null) {
propMap.putNull(key);
} else if (value instanceof Double) {
propMap.putDouble(key, (Double) value);
} else if (value instanceof Integer) {
propMap.putInt(key, (Integer) value);
} else if (value instanceof Number) {
propMap.putDouble(key, ((Number) value).doubleValue());
} else if (value instanceof Boolean) {
propMap.putBoolean(key, (Boolean) value);
} else if (value instanceof String) {
propMap.putString(key, (String) value);
} else if (value instanceof WritableArray) {
propMap.putArray(key, (WritableArray)value);
} else if (value instanceof WritableMap) {
propMap.putMap(key, (WritableMap)value);
} else {
throw new IllegalStateException("Unknown type of animated value");
}
}
public PropsNode(
int nodeID,
ReadableMap config,
NodesManager nodesManager,
UIImplementation uiImplementation) {
super(nodeID, config, nodesManager);
mMapping = Utils.processMapping(config.getMap("props"));
mUIImplementation = uiImplementation;
mPropMap = new JavaOnlyMap();
mDiffMap = new ReactStylesDiffMap(mPropMap);
}
public void connectToView(int viewTag) {
mConnectedViewTag = viewTag;
dangerouslyRescheduleEvaluate();
}
public void disconnectFromView(int viewTag) {
mConnectedViewTag = View.NO_ID;
}
@Override
protected Double evaluate() {
boolean hasUIProps = false;
boolean hasNativeProps = false;
boolean hasJSProps = false;
WritableMap jsProps = Arguments.createMap();
final WritableMap nativeProps = Arguments.createMap();
for (Map.Entry<String, Integer> entry : mMapping.entrySet()) {
Node node = mNodesManager.findNodeById(entry.getValue(), Node.class);
if (node instanceof StyleNode) {
WritableMap style = (WritableMap) node.value();
ReadableMapKeySetIterator iter = style.keySetIterator();
while (iter.hasNextKey()) {
String key = iter.nextKey();
WritableMap dest;
if (mNodesManager.uiProps.contains(key)) {
hasUIProps = true;
dest = mPropMap;
} else if (mNodesManager.nativeProps.contains(key)){
hasNativeProps = true;
dest = nativeProps;
} else {
hasJSProps = true;
dest = jsProps;
}
ReadableType type = style.getType(key);
switch (type) {
case Number:
dest.putDouble(key, style.getDouble(key));
break;
case String:
dest.putString(key, style.getString(key));
break;
case Array:
dest.putArray(key, (WritableArray) style.getArray(key));
break;
default:
throw new IllegalArgumentException("Unexpected type " + type);
}
}
} else {
String key = entry.getKey();
Object value = node.value();
if (mNodesManager.uiProps.contains(key)) {
hasUIProps = true;
addProp(mPropMap, key, value);
} else {
hasNativeProps = true;
addProp(nativeProps, key, value);
}
}
}
if (mConnectedViewTag != View.NO_ID) {
if (hasUIProps) {
mUIImplementation.synchronouslyUpdateViewOnUIThread(
mConnectedViewTag,
mDiffMap);
}
if (hasNativeProps) {
mNodesManager.enqueueUpdateViewOnNativeThread(mConnectedViewTag, nativeProps);
}
if (hasJSProps) {
WritableMap evt = Arguments.createMap();
evt.putInt("viewTag", mConnectedViewTag);
evt.putMap("props", jsProps);
mNodesManager.sendEvent("onReanimatedPropsChange", evt);
}
}
return ZERO;
}
@Override
public void update() {
// Since we are updating nodes after detaching them from views there is a time where it's
// possible that the view was disconnected and still receive an update, this is normal and
// we can simply skip that update.
if (mConnectedViewTag == View.NO_ID) {
return;
}
// call value for side effect (diff map update via changes made to prop map)
value();
}
}

View File

@ -0,0 +1,27 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.JSApplicationCausedNativeException;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.NoSuchKeyException;
import com.facebook.react.bridge.ReadableMap;
import com.swmansion.reanimated.MapUtils;
import com.swmansion.reanimated.NodesManager;
public class SetNode extends Node {
private int mWhatNodeID, mValueNodeID;
public SetNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mWhatNodeID = MapUtils.getInt(config, "what", "Reanimated: First argument passed to set node is either of wrong type or is missing.");
mValueNodeID = MapUtils.getInt(config, "value", "Reanimated: Second argument passed to set node is either of wrong type or is missing.");
}
@Override
protected Object evaluate() {
Object newValue = mNodesManager.getNodeValue(mValueNodeID);
ValueNode what = mNodesManager.findNodeById(mWhatNodeID, ValueNode.class);
what.setValue(newValue);
return newValue;
}
}

View File

@ -0,0 +1,43 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.swmansion.reanimated.NodesManager;
import com.swmansion.reanimated.Utils;
import java.util.Map;
import javax.annotation.Nullable;
public class StyleNode extends Node {
private final Map<String, Integer> mMapping;
public StyleNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mMapping = Utils.processMapping(config.getMap("style"));
}
@Override
protected WritableMap evaluate() {
JavaOnlyMap propMap = new JavaOnlyMap();
for (Map.Entry<String, Integer> entry : mMapping.entrySet()) {
Node node = mNodesManager.findNodeById(entry.getValue(), Node.class);
if (node instanceof TransformNode) {
propMap.putArray(entry.getKey(), (WritableArray) node.value());
} else {
Object val = node.value();
if (val instanceof Double) {
propMap.putDouble(entry.getKey(), (Double) val);
} else if (val instanceof String) {
propMap.putString(entry.getKey(), (String) val);
} else {
throw new IllegalStateException("Wrong style form");
}
}
}
return propMap;
}
}

View File

@ -0,0 +1,85 @@
package com.swmansion.reanimated.nodes;
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;
import com.facebook.react.bridge.WritableArray;
import com.swmansion.reanimated.NodesManager;
import java.util.ArrayList;
import java.util.List;
public class TransformNode extends Node {
private static abstract class TransformConfig {
public String propertyName;
public abstract Object getValue(NodesManager nodesManager);
}
private static class AnimatedTransformConfig extends TransformConfig {
public int nodeID;
@Override
public Object getValue(NodesManager nodesManager) {
return nodesManager.getNodeValue(nodeID);
}
}
private static class StaticTransformConfig extends TransformConfig {
public Object value;
@Override
public Object getValue(NodesManager nodesManager) {
return value;
}
}
private static List<TransformConfig> processTransforms(ReadableArray transforms) {
List<TransformConfig> configs = new ArrayList<>(transforms.size());
for (int i = 0; i < transforms.size(); i++) {
ReadableMap transformConfigMap = transforms.getMap(i);
String property = transformConfigMap.getString("property");
if (transformConfigMap.hasKey("nodeID")) {
AnimatedTransformConfig transformConfig = new AnimatedTransformConfig();
transformConfig.propertyName = property;
transformConfig.nodeID = transformConfigMap.getInt("nodeID");
configs.add(transformConfig);
} else {
StaticTransformConfig transformConfig = new StaticTransformConfig();
transformConfig.propertyName = property;
ReadableType type = transformConfigMap.getType("value");
if(type == ReadableType.String) {
transformConfig.value = transformConfigMap.getString("value");
} else if(type == ReadableType.Array) {
transformConfig.value = transformConfigMap.getArray("value");
} else {
transformConfig.value = transformConfigMap.getDouble("value");
}
configs.add(transformConfig);
}
}
return configs;
}
private List<TransformConfig> mTransforms;
public TransformNode(int nodeID, ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
mTransforms = processTransforms(config.getArray("transform"));
}
@Override
protected WritableArray evaluate() {
List<JavaOnlyMap> transforms = new ArrayList<>(mTransforms.size());
for (TransformConfig transformConfig : mTransforms) {
transforms.add(
JavaOnlyMap.of(transformConfig.propertyName, transformConfig.getValue(mNodesManager)));
}
return JavaOnlyArray.from(transforms);
}
}

View File

@ -0,0 +1,40 @@
package com.swmansion.reanimated.nodes;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.swmansion.reanimated.NodesManager;
import javax.annotation.Nullable;
public class ValueNode extends Node {
private Object mValue;
public ValueNode(int nodeID, @Nullable ReadableMap config, NodesManager nodesManager) {
super(nodeID, config, nodesManager);
if (config == null || !config.hasKey("value")) {
mValue = null;
return;
}
ReadableType type = config.getType("value");
if (type == ReadableType.String) {
mValue = config.getString("value");
} else if (type == ReadableType.Number) {
mValue = config.getDouble("value");
} else if (type == ReadableType.Null) {
mValue = null;
} else {
throw new IllegalStateException("Not supported value type. Must be boolean, number or string");
}
}
public void setValue(Object value) {
mValue = value;
forceUpdateMemoizedValue(mValue);
}
@Override
protected Object evaluate() {
return mValue;
}
}

View File

@ -0,0 +1,82 @@
package com.swmansion.reanimated.transitions;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.TimeInterpolator;
import androidx.annotation.Nullable;
import androidx.transition.ChangeBounds;
import androidx.transition.ChangeTransform;
import androidx.transition.Transition;
import androidx.transition.TransitionPropagation;
import androidx.transition.TransitionValues;
import android.view.ViewGroup;
final class ChangeTransition extends Transition {
private final ChangeTransform mChangeTransform;
private final ChangeBounds mChangeBounds;
public ChangeTransition() {
mChangeTransform = new ChangeTransform();
mChangeBounds = new ChangeBounds();
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
mChangeTransform.captureStartValues(transitionValues);
mChangeBounds.captureStartValues(transitionValues);
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
mChangeTransform.captureEndValues(transitionValues);
mChangeBounds.captureEndValues(transitionValues);
}
@Override
public Transition setDuration(long duration) {
mChangeTransform.setDuration(duration);
mChangeBounds.setDuration(duration);
return super.setDuration(duration);
}
@Override
public Transition setStartDelay(long startDelay) {
mChangeTransform.setStartDelay(startDelay);
mChangeBounds.setStartDelay(startDelay);
return super.setStartDelay(startDelay);
}
@Override
public Transition setInterpolator(@Nullable TimeInterpolator interpolator) {
mChangeTransform.setInterpolator(interpolator);
mChangeBounds.setInterpolator(interpolator);
return super.setInterpolator(interpolator);
}
@Override
public void setPropagation(@Nullable TransitionPropagation transitionPropagation) {
mChangeTransform.setPropagation(transitionPropagation);
mChangeBounds.setPropagation(transitionPropagation);
super.setPropagation(transitionPropagation);
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
mChangeTransform.setReparent(false);
Animator changeTransformAnimator = mChangeTransform.createAnimator(sceneRoot, startValues, endValues);
Animator changeBoundsAnimator = mChangeBounds.createAnimator(sceneRoot, startValues, endValues);
if (changeTransformAnimator == null) {
return changeBoundsAnimator;
}
if (changeBoundsAnimator == null) {
return changeTransformAnimator;
}
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(changeTransformAnimator, changeBoundsAnimator);
return animatorSet;
}
}

View File

@ -0,0 +1,22 @@
package com.swmansion.reanimated.transitions;
import androidx.transition.SidePropagation;
import androidx.transition.Transition;
import androidx.transition.TransitionValues;
import android.view.View;
import android.view.ViewGroup;
public class SaneSidePropagation extends SidePropagation {
@Override
public long getStartDelay(ViewGroup sceneRoot, Transition transition, TransitionValues startValues, TransitionValues endValues) {
long delay = super.getStartDelay(sceneRoot, transition, startValues, endValues);
if (delay != 0) {
if (endValues == null || getViewVisibility(startValues) == View.VISIBLE) {
return -delay;
}
}
return delay;
}
}

View File

@ -0,0 +1,83 @@
package com.swmansion.reanimated.transitions;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import androidx.transition.Transition;
import androidx.transition.TransitionListenerAdapter;
import androidx.transition.TransitionValues;
import androidx.transition.Visibility;
import android.view.View;
import android.view.ViewGroup;
public class Scale extends Visibility {
static final String PROPNAME_SCALE_X = "scale:scaleX";
static final String PROPNAME_SCALE_Y = "scale:scaleY";
@Override
public void captureStartValues(TransitionValues transitionValues) {
super.captureStartValues(transitionValues);
transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX());
transitionValues.values.put(PROPNAME_SCALE_Y, transitionValues.view.getScaleY());
}
public Scale setDisappearedScale(float disappearedScale) {
if (disappearedScale < 0f) {
throw new IllegalArgumentException("disappearedScale cannot be negative!");
}
return this;
}
private Animator createAnimation(final View view, float startScale, float endScale, TransitionValues values) {
final float initialScaleX = view.getScaleX();
final float initialScaleY = view.getScaleY();
float startScaleX = initialScaleX * startScale;
float endScaleX = initialScaleX * endScale;
float startScaleY = initialScaleY * startScale;
float endScaleY = initialScaleY * endScale;
if (values != null) {
Float savedScaleX = (Float) values.values.get(PROPNAME_SCALE_X);
Float savedScaleY = (Float) values.values.get(PROPNAME_SCALE_Y);
// if saved value is not equal initial value it means that previous
// transition was interrupted and in the onTransitionEnd
// we've applied endScale. we should apply proper value to
// continue animation from the interrupted state
if (savedScaleX != null && savedScaleX != initialScaleX) {
startScaleX = savedScaleX;
}
if (savedScaleY != null && savedScaleY != initialScaleY) {
startScaleY = savedScaleY;
}
}
view.setScaleX(startScaleX);
view.setScaleY(startScaleY);
AnimatorSet animator = new AnimatorSet();
animator.playTogether(
ObjectAnimator.ofFloat(view, View.SCALE_X, startScaleX, endScaleX),
ObjectAnimator.ofFloat(view, View.SCALE_Y, startScaleY, endScaleY));
addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
view.setScaleX(initialScaleX);
view.setScaleY(initialScaleY);
transition.removeListener(this);
}
});
return animator;
}
@Override
public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
return createAnimation(view, 0f, 1f, startValues);
}
@Override
public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
return createAnimation(view, 1f, 0f, startValues);
}
}

View File

@ -0,0 +1,45 @@
package com.swmansion.reanimated.transitions;
import androidx.transition.TransitionManager;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.NativeViewHierarchyManager;
import com.facebook.react.uimanager.UIBlock;
import com.facebook.react.uimanager.UIManagerModule;
public class TransitionModule {
private final UIManagerModule mUIManager;
public TransitionModule(UIManagerModule uiManager) {
mUIManager = uiManager;
}
public void animateNextTransition(final int rootTag, final ReadableMap config) {
mUIManager.prependUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
try {
View rootView = nativeViewHierarchyManager.resolveView(rootTag);
if (rootView instanceof ViewGroup) {
ReadableArray transitions = config.getArray("transitions");
for (int i = 0, size = transitions.size(); i < size; i++) {
TransitionManager.beginDelayedTransition(
(ViewGroup) rootView,
TransitionUtils.inflate(transitions.getMap(i)));
}
}
} catch (IllegalViewOperationException ex) {
// ignore, view might have not been registered yet
}
}
});
}
}

View File

@ -0,0 +1,162 @@
package com.swmansion.reanimated.transitions;
import androidx.transition.ChangeBounds;
import androidx.transition.ChangeTransform;
import androidx.transition.Fade;
import androidx.transition.SidePropagation;
import androidx.transition.Slide;
import androidx.transition.Transition;
import androidx.transition.TransitionSet;
import androidx.transition.Visibility;
import android.view.Gravity;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import javax.annotation.Nullable;
class TransitionUtils {
static @Nullable Transition inflate(ReadableMap config) {
String type = config.getString("type");
if ("group".equals(type)) {
return inflateGroup(config);
} else if ("in".equals(type)) {
return inflateIn(config);
} else if ("out".equals(type)) {
return inflateOut(config);
} else if ("change".equals(type)) {
return inflateChange(config);
}
throw new JSApplicationIllegalArgumentException("Unrecognized transition type " + type);
}
private static @Nullable Transition inflateGroup(ReadableMap config) {
TransitionSet set = new TransitionSet();
if (config.hasKey("sequence") && config.getBoolean("sequence")) {
set.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
} else {
set.setOrdering(TransitionSet.ORDERING_TOGETHER);
}
ReadableArray transitions = config.getArray("transitions");
for (int i = 0, size = transitions.size(); i < size; i++) {
Transition next = inflate(transitions.getMap(i));
if (next != null) {
set.addTransition(next);
}
}
return set;
}
static Visibility createVisibilityTransition(String type) {
if (type == null || "none".equals(type)) {
return null;
} else if ("fade".equals(type)) {
return new Fade(Fade.IN | Fade.OUT);
} else if ("scale".equals(type)) {
return new Scale();
} else if ("slide-top".equals(type)) {
return new Slide(Gravity.TOP);
} else if ("slide-bottom".equals(type)) {
return new Slide(Gravity.BOTTOM);
} else if ("slide-right".equals(type)) {
return new Slide(Gravity.RIGHT);
} else if ("slide-left".equals(type)) {
return new Slide(Gravity.LEFT);
}
throw new JSApplicationIllegalArgumentException("Invalid transition type " + type);
}
private static Transition inflateIn(ReadableMap config) {
Visibility transition = createTransition(config.getString("animation"));
if (transition == null) {
return null;
}
transition.setMode(Visibility.MODE_IN);
configureTransition(transition, config);
return transition;
}
private static Transition inflateOut(ReadableMap config) {
Visibility transition = createTransition(config.getString("animation"));
if (transition == null) {
return null;
}
transition.setMode(Visibility.MODE_OUT);
configureTransition(transition, config);
return transition;
}
private static Transition inflateChange(ReadableMap config) {
ChangeBounds changeBounds = new ChangeBounds();
ChangeTransform changeTransform = new ChangeTransform();
configureTransition(changeBounds, config);
configureTransition(changeTransform, config);
return new TransitionSet().addTransition(changeBounds).addTransition(changeTransform);
}
private static Visibility createTransition(String type) {
if (type == null || "none".equals(type)) {
return null;
} else if ("fade".equals(type)) {
return new Fade(Fade.IN | Fade.OUT);
} else if ("scale".equals(type)) {
return new Scale();
} else if ("slide-top".equals(type)) {
return new Slide(Gravity.TOP);
} else if ("slide-bottom".equals(type)) {
return new Slide(Gravity.BOTTOM);
} else if ("slide-right".equals(type)) {
return new Slide(Gravity.RIGHT);
} else if ("slide-left".equals(type)) {
return new Slide(Gravity.LEFT);
}
throw new JSApplicationIllegalArgumentException("Invalid transition type " + type);
}
private static void configureTransition(Transition transition, ReadableMap params) {
if (params.hasKey("durationMs")) {
int durationMs = params.getInt("durationMs");
transition.setDuration(durationMs);
}
if (params.hasKey("interpolation")) {
String interpolation = params.getString("interpolation");
if (interpolation.equals("easeIn")) {
transition.setInterpolator(new AccelerateInterpolator());
} else if (interpolation.equals("easeOut")) {
transition.setInterpolator(new DecelerateInterpolator());
} else if (interpolation.equals("easeInOut")) {
transition.setInterpolator(new AccelerateDecelerateInterpolator());
} else if (interpolation.equals("linear")) {
transition.setInterpolator(new LinearInterpolator());
} else {
throw new JSApplicationIllegalArgumentException("Invalid interpolation type " + interpolation);
}
}
if (params.hasKey("propagation")) {
String propagation = params.getString("propagation");
SidePropagation sidePropagation = new SaneSidePropagation();
if ("top".equals(propagation)) {
sidePropagation.setSide(Gravity.BOTTOM);
} else if ("bottom".equals(propagation)) {
sidePropagation.setSide(Gravity.TOP);
} else if ("left".equals(propagation)) {
sidePropagation.setSide(Gravity.RIGHT);
} else if ("right".equals(propagation)) {
sidePropagation.setSide(Gravity.LEFT);
}
transition.setPropagation(sidePropagation);
} else {
transition.setPropagation(null);
}
if (params.hasKey("delayMs")) {
int delayMs = params.getInt("delayMs");
transition.setStartDelay(delayMs);
}
}
}

View File

@ -0,0 +1,4 @@
#import "REANode.h"
@interface REAAlwaysNode : REANode <REAFinalNode>
@end

View File

@ -0,0 +1,36 @@
#import "REAAlwaysNode.h"
#import "REAUtils.h"
#import "REANodesManager.h"
#import "REAStyleNode.h"
#import "REAModule.h"
#import <React/RCTLog.h>
#import <React/RCTConvert.h>
#import <React/RCTUIManager.h>
@implementation REAAlwaysNode
{
NSNumber * _nodeToBeEvaluated;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_nodeToBeEvaluated = [RCTConvert NSNumber:config[@"what"]];
REA_LOG_ERROR_IF_NIL(_nodeToBeEvaluated, @"Reanimated: First argument passed to always node is either of wrong type or is missing.");
}
return self;
}
- (id)evaluate
{
[[self.nodesManager findNodeByID:_nodeToBeEvaluated] value];
return @(0);
}
- (void)update
{
[self value];
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REABezierNode : REANode
@end

View File

@ -0,0 +1,103 @@
#include <tgmath.h>
#import "REABezierNode.h"
#import "REAUtils.h"
#import "REANodesManager.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
#define EPS 1e-5
@implementation REABezierNode {
CGFloat ax, bx, cx, ay, by, cy;
NSNumber *_inputNodeID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_inputNodeID = [RCTConvert NSNumber:config[@"input"]];
REA_LOG_ERROR_IF_NIL(_inputNodeID, @"Reanimated: First argument passed to bezier node is either of wrong type or is missing.");
CGFloat mX1 = [config[@"mX1"] doubleValue];
CGFloat mY1 = [config[@"mY1"] doubleValue];
CGFloat mX2 = [config[@"mX2"] doubleValue];
CGFloat mY2 = [config[@"mY2"] doubleValue];
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
cx = 3.0 * mX1;
bx = 3.0 * (mX2 - mX1) - cx;
ax = 1.0 - cx -bx;
cy = 3.0 * mY1;
by = 3.0 * (mY2 - mY1) - cy;
ay = 1.0 - cy - by;
}
return self;
}
- (CGFloat)sampleCurveX:(CGFloat)t
{
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
return ((ax * t + bx) * t + cx) * t;
}
- (CGFloat)sampleCurveY:(CGFloat)t
{
return ((ay * t + by) * t + cy) * t;
}
- (CGFloat)sampleCurveDerivativeX:(CGFloat)t
{
return (3.0 * ax * t + 2.0 * bx) * t + cx;
}
- (CGFloat)solveCurveX:(CGFloat)x withEpsilon:(CGFloat)epsilon
{
CGFloat t0, t1, t2, x2, d2;
NSUInteger i;
// First try a few iterations of Newton's method -- normally very fast.
for (t2 = x, i = 0; i < 8; i++) {
x2 = [self sampleCurveX:t2] - x;
if (fabs (x2) < epsilon)
return t2;
d2 = [self sampleCurveDerivativeX:t2];
if (fabs(d2) < 1e-6)
break;
t2 = t2 - x2 / d2;
}
// Fall back to the bisection method for reliability.
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0)
return t0;
if (t2 > t1)
return t1;
while (t0 < t1) {
x2 = [self sampleCurveX:t2];
if (fabs(x2 - x) < epsilon)
return t2;
if (x > x2)
t0 = t2;
else
t1 = t2;
t2 = (t1 - t0) * .5 + t0;
}
// Failure.
return t2;
}
- (id)evaluate
{
CGFloat x = [[[self.nodesManager findNodeByID:_inputNodeID] value] doubleValue];
CGFloat y = [self sampleCurveY:[self solveCurveX:x withEpsilon:EPS]];
return @(y);
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REABlockNode : REANode
@end

View File

@ -0,0 +1,25 @@
#import "REABlockNode.h"
#import "REANodesManager.h"
@implementation REABlockNode {
NSArray<NSNumber *> *_block;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_block = config[@"block"];
}
return self;
}
- (id)evaluate
{
id result;
for (NSNumber *inputID in _block) {
result = [[self.nodesManager findNodeByID:inputID] value];
}
return result;
}
@end

View File

@ -0,0 +1,7 @@
#import "REANode.h"
@interface REACallFuncNode : REANode
@end

View File

@ -0,0 +1,67 @@
#import "REACallFuncNode.h"
#import "REAFunctionNode.h"
#import "REAUtils.h"
#import "REAParamNode.h"
#import "REANodesManager.h"
@implementation REACallFuncNode {
NSNumber *_whatNodeID;
NSArray<NSNumber *> *_args;
NSArray<NSNumber *> *_params;
NSString* _prevCallID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_whatNodeID = config[@"what"];
REA_LOG_ERROR_IF_NIL(_whatNodeID, @"Reanimated: First argument passed to callFunc node is either of wrong type or is missing.");
_args = config[@"args"];
_params = config[@"params"];
_prevCallID = NULL;
}
return self;
}
- (void)beginContext
{
// To ensure that functions can be called multiple times in the same animation frame
// (functions might have different parameters and might be called multiple times)
// we inform the current update context about where we are called from by setting the
// current call id - this will ensure that memoization is correct for function nodes.
_prevCallID = self.updateContext.callID;
self.updateContext.callID = [NSString stringWithFormat:@"%@/%@", self.updateContext.callID, [self.nodeID stringValue]];
// A CallFuncNode has a reference to a function node which holds the node graph that should
// be updated. A Function node has a list of ParamNodes which are basically nodes that can
// reference other nodes. When we start a new function call we update the parameter nodes
// with the current arguments:
for (NSUInteger i = 0; i < _params.count; i++) {
NSNumber *paramID = [_params objectAtIndex:i];
REAParamNode *param = (REAParamNode *)[self.nodesManager findNodeByID:paramID];
[param beginContext:_args[i] prevCallID:_prevCallID];
}
}
- (void)endContext
{
for (NSUInteger i = 0; i < _params.count; i++) {
NSNumber *paramID = [_params objectAtIndex:i];
REAParamNode *param = (REAParamNode *)[self.nodesManager findNodeByID:paramID];
[param endContext];
}
self.updateContext.callID = _prevCallID;
}
- (id)evaluate
{
[self beginContext];
REAFunctionNode *what = (REAFunctionNode *)[self.nodesManager findNodeByID:_whatNodeID];
NSNumber *newValue = [what value];
[self endContext];
return newValue;
}
@end

View File

@ -0,0 +1,19 @@
#import "REANode.h"
@interface REAClockNode : REANode
@property (nonatomic, readonly) BOOL isRunning;
- (void)start;
- (void)stop;
@end
@interface REAClockOpNode : REANode
@end
@interface REAClockStartNode : REAClockOpNode
@end
@interface REAClockStopNode : REAClockOpNode
@end
@interface REAClockTestNode : REAClockOpNode
@end

View File

@ -0,0 +1,116 @@
#import "REAClockNodes.h"
#import "REAUtils.h"
#import "REANodesManager.h"
#import "REAParamNode.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
@interface REAClockNode ()
@property (nonatomic) NSNumber *lastTimestampMs;
@end
@implementation REAClockNode
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_isRunning = NO;
}
return self;
}
- (void)start
{
if (_isRunning) return;
_isRunning = YES;
__block __weak void (^weak_animationClb)(CADisplayLink *displayLink);
void (^animationClb)(CADisplayLink *displayLink);
__weak REAClockNode *weakSelf = self;
weak_animationClb = animationClb = ^(CADisplayLink *displayLink) {
if (!weakSelf.isRunning) return;
[weakSelf markUpdated];
[weakSelf.nodesManager postOnAnimation:weak_animationClb];
};
[self.nodesManager postOnAnimation:animationClb];
}
- (void)stop
{
_isRunning = false;
}
- (id)evaluate
{
return @(self.nodesManager.currentAnimationTimestamp * 1000.);
}
@end
@implementation REAClockOpNode {
NSNumber *_clockNodeID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_clockNodeID = [RCTConvert NSNumber:config[@"clock"]];
REA_LOG_ERROR_IF_NIL(_clockNodeID, @"Reanimated: First argument passed to clock node is either of wrong type or is missing.");
}
return self;
}
- (REANode*)clockNode
{
return (REANode*)[self.nodesManager findNodeByID:_clockNodeID];
}
@end
@implementation REAClockStartNode
- (id)evaluate
{
REANode* node = [self clockNode];
if ([node isKindOfClass:[REAParamNode class]]) {
[(REAParamNode* )node start];
} else {
[(REAClockNode* )node start];
}
return @(0);
}
@end
@implementation REAClockStopNode
- (id)evaluate
{
REANode* node = [self clockNode];
if ([node isKindOfClass:[REAParamNode class]]) {
[(REAParamNode* )node stop];
} else {
[(REAClockNode* )node stop];
}
return @(0);
}
@end
@implementation REAClockTestNode
- (id)evaluate
{
REANode* node = [self clockNode];
if ([node isKindOfClass:[REAParamNode class]]) {
return @(((REAParamNode* )node).isRunning ? 1 : 0);
}
return @([(REAClockNode* )node isRunning] ? 1 : 0);
}
@end

View File

@ -0,0 +1,6 @@
#import "REANode.h"
@interface REAConcatNode : REANode
@end

View File

@ -0,0 +1,32 @@
#import "REAConcatNode.h"
#import "REAValueNode.h"
#import "REANodesManager.h"
@implementation REAConcatNode {
NSArray<NSNumber *> *_input;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_input = config[@"input"];
}
return self;
}
- (id)evaluate
{
NSMutableString *result = [NSMutableString new];
for (int i = 0; i < _input.count; i++) {
NSObject *val = [[self.nodesManager findNodeByID:_input[i]] value];
if ([val isKindOfClass:[NSNumber class]]) {
[result appendString:[(NSNumber *)val stringValue]];
}
if ([val isKindOfClass:[NSString class]]) {
[result appendString:val];
}
}
return result;
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REACondNode : REANode
@end

View File

@ -0,0 +1,34 @@
#import "REACondNode.h"
#import "REANodesManager.h"
#import <React/RCTConvert.h>
#import "REAUtils.h"
#import <React/RCTLog.h>
@implementation REACondNode {
NSNumber *_condNodeID;
NSNumber *_ifBlockID;
NSNumber *_elseBlockID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_condNodeID = [RCTConvert NSNumber:config[@"cond"]];
REA_LOG_ERROR_IF_NIL(_condNodeID, @"Reanimated: First argument passed to cond node is either of wrong type or is missing.");
_ifBlockID = [RCTConvert NSNumber:config[@"ifBlock"]];
REA_LOG_ERROR_IF_NIL(_ifBlockID, @"Reanimated: Second argument passed to cond node is either of wrong type or is missing.");
_elseBlockID = [RCTConvert NSNumber:config[@"elseBlock"]];
}
return self;
}
- (id)evaluate
{
id cond = [[self.nodesManager findNodeByID:_condNodeID] value];
if ([cond doubleValue]) {
return [[self.nodesManager findNodeByID:_ifBlockID] value];
}
return _elseBlockID != nil ? [[self.nodesManager findNodeByID:_elseBlockID] value] : @(0);
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface READebugNode : REANode
@end

View File

@ -0,0 +1,29 @@
#import "READebugNode.h"
#import "REAUtils.h"
#import "REANodesManager.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
@implementation READebugNode {
NSNumber *_valueNodeID;
NSString *_message;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_message = [RCTConvert NSString:config[@"message"]];
_valueNodeID = [RCTConvert NSNumber:config[@"value"]];
REA_LOG_ERROR_IF_NIL(_valueNodeID, @"Reanimated: Second argument passed to debug node is either of wrong type or is missing.");
}
return self;
}
- (id)evaluate
{
id value = [[self.nodesManager findNodeByID:_valueNodeID] value];
NSLog(@"%@ %@", _message, value);
return value;
}
@end

View File

@ -0,0 +1,9 @@
#import "REANode.h"
#import <React/RCTEventDispatcher.h>
@interface REAEventNode : REANode
- (void)processEvent:(id<RCTEvent>)event;
@end

View File

@ -0,0 +1,35 @@
#import "REAEventNode.h"
#import "REANodesManager.h"
#import "REAValueNode.h"
@implementation REAEventNode {
NSArray *_argMapping;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_argMapping = config[@"argMapping"];
}
return self;
}
- (void)processEvent:(id<RCTEvent>)event
{
NSArray *args = event.arguments;
// argMapping is an array of eventPaths, each even path ends with a target node ID
for (NSArray *eventPath in _argMapping) {
// Supported events args are in the following order: viewTag, eventName, eventData.
id value = args[2];
for (NSUInteger i = 0; i < eventPath.count; i++) {
if (i < eventPath.count - 1) {
value = [value valueForKey:eventPath[i]];
} else {
REAValueNode *node = (REAValueNode *)[self.nodesManager findNodeByID:eventPath[i]];
[node setValue:value];
}
}
}
}
@end

View File

@ -0,0 +1,7 @@
#import "REANode.h"
@interface REAFunctionNode : REANode
@end

View File

@ -0,0 +1,24 @@
#import "REAFunctionNode.h"
#import "REAParamNode.h"
#import "REANodesManager.h"
@implementation REAFunctionNode {
NSNumber *_nodeToBeEvaluated;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_nodeToBeEvaluated = config[@"what"];
}
return self;
}
- (id)evaluate
{
REANode *node = [self.nodesManager findNodeByID:_nodeToBeEvaluated];
return [node value];
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REAJSCallNode : REANode
@end

View File

@ -0,0 +1,31 @@
#import "REAJSCallNode.h"
#import "REANodesManager.h"
#import "REAModule.h"
@implementation REAJSCallNode {
NSArray<NSNumber *> *_input;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_input = config[@"input"];
}
return self;
}
- (id)evaluate
{
NSMutableArray *args = [NSMutableArray arrayWithCapacity:_input.count];
for (NSUInteger i = 0; i < _input.count; i++) {
args[i] = [[self.nodesManager findNodeByID:_input[i]] value];
}
[self.nodesManager.reanimatedModule
sendEventWithName:@"onReanimatedCall"
body:@{@"id": self.nodeID, @"args": args }];
return @(0);
}
@end

View File

@ -0,0 +1,39 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class REANodesManager;
typedef NSNumber* REANodeID;
@protocol REAFinalNode
- (void)update;
@end
@interface REAUpdateContext : NSObject
@property (nonatomic) NSString* callID;
@end
@interface REANode : NSObject
+ (void)runPropUpdates:(nonnull REAUpdateContext *)context;
- (instancetype)initWithID:(REANodeID)nodeID
config:(NSDictionary<NSString *, id> *)config NS_DESIGNATED_INITIALIZER;
@property (nonatomic, weak, nullable) REANodesManager *nodesManager;
@property (nonatomic, nullable) REAUpdateContext *updateContext;
@property (nonatomic, readonly, nonnull) REANodeID nodeID;
- (_Nullable id)evaluate;
- (_Nullable id)value;
- (void)markUpdated;
- (void)addChild:(REANode *)child NS_REQUIRES_SUPER;
- (void)removeChild:(REANode *)child NS_REQUIRES_SUPER;
- (void)dangerouslyRescheduleEvaluate;
- (void)forceUpdateMemoizedValue:(id)value;
@end

View File

@ -0,0 +1,152 @@
#import "REANode.h"
#import "REANodesManager.h"
#import <React/RCTDefines.h>
@interface REAUpdateContext ()
@property (nonatomic, nonnull) NSMutableArray<REANode *> *updatedNodes;
@property (nonatomic) NSNumber* loopID;
@end
@implementation REAUpdateContext
- (instancetype)init
{
if ((self = [super init])) {
_loopID = [[NSNumber alloc] initWithInt:1];
_updatedNodes = [NSMutableArray new];
_callID = @"";
}
return self;
}
@end
@interface REANode ()
@property (nonatomic) NSMutableDictionary<REANodeID, NSNumber*>* lastLoopID;
@property (nonatomic) NSMutableDictionary<REANodeID, id>* memoizedValue;
@property (nonatomic, nullable) NSMutableArray<REANode *> *childNodes;
@end
@implementation REANode
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super init])) {
_nodeID = nodeID;
_lastLoopID = [NSMutableDictionary dictionary];
_memoizedValue = [NSMutableDictionary dictionary];
_lastLoopID[@""] = 0;
}
return self;
}
RCT_NOT_IMPLEMENTED(- (instancetype)init)
- (void)dangerouslyRescheduleEvaluate
{
_lastLoopID[self.updateContext.callID] = 0;
[self markUpdated];
}
- (void)forceUpdateMemoizedValue:(id)value
{
_memoizedValue[self.updateContext.callID] = value;
[self markUpdated];
}
- (id)evaluate
{
return 0;
}
- (id)value
{
if (![_lastLoopID objectForKey:_updateContext.callID] || [[_lastLoopID objectForKey:_updateContext.callID] longValue] < [_updateContext.loopID longValue]) {
[_lastLoopID setObject:_updateContext.loopID forKey:_updateContext.callID];
id val = [self evaluate];
[_memoizedValue setObject:(val == nil ? [NSNull null] : val) forKey:_updateContext.callID];
return val;
}
id memoizedValue = [_memoizedValue objectForKey:_updateContext.callID];
return [memoizedValue isKindOfClass:[NSNull class]] ? nil : memoizedValue;
}
- (void)addChild:(REANode *)child
{
if (!_childNodes) {
_childNodes = [NSMutableArray new];
}
if (child) {
[_childNodes addObject:child];
[child dangerouslyRescheduleEvaluate];
}
}
- (void)removeChild:(REANode *)child
{
if (child) {
[_childNodes removeObject:child];
}
}
- (void)markUpdated
{
[_updateContext.updatedNodes addObject:self];
[self.nodesManager postRunUpdatesAfterAnimation];
}
+ (NSMutableArray<REANode *> *)updatedNodes
{
static NSMutableArray<REANode *> *updatedNodes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
updatedNodes = [NSMutableArray new];
});
return updatedNodes;
}
+ (void)findAndUpdateNodes:(nonnull REANode *)node
withVisitedSet:(NSMutableSet<REANode *> *)visitedNodes
withFinalNodes:(NSMutableArray<id<REAFinalNode>> *)finalNodes
{
if ([visitedNodes containsObject:node]) {
return;
} else {
[visitedNodes addObject:node];
}
for (REANode *child in node.childNodes) {
[self findAndUpdateNodes:child withVisitedSet:visitedNodes withFinalNodes:finalNodes];
}
if ([node conformsToProtocol:@protocol(REAFinalNode)]) {
[finalNodes addObject:(id<REAFinalNode>)node];
}
}
+ (void)runPropUpdates:(REAUpdateContext *)context
{
NSMutableSet<REANode *> *visitedNodes = [NSMutableSet new];
NSMutableArray<id<REAFinalNode>> *finalNodes = [NSMutableArray new];
for (NSUInteger i = 0; i < context.updatedNodes.count; i++) {
[self findAndUpdateNodes:context.updatedNodes[i]
withVisitedSet:visitedNodes
withFinalNodes:finalNodes];
if (i == context.updatedNodes.count - 1) {
while (finalNodes.count > 0) {
// NSMutableArray used for stack implementation
[[finalNodes lastObject] update];
[finalNodes removeLastObject];
}
}
}
[context.updatedNodes removeAllObjects];
context.loopID = [[NSNumber alloc] initWithLong:context.loopID.longValue + 1];
}
@end

View File

@ -0,0 +1,5 @@
#import "REANode.h"
@interface REAOperatorNode : REANode
@end

View File

@ -0,0 +1,114 @@
#include <tgmath.h>
#import "REAOperatorNode.h"
#import "REANodesManager.h"
typedef id (^REAOperatorBlock)(NSArray<REANode *> *inputNodes);
#define REA_REDUCE(OP) ^(NSArray<REANode *> *inputNodes) { \
double acc = [[inputNodes[0] value] doubleValue]; \
for (NSUInteger i = 1; i < inputNodes.count; i++) { \
double a = acc, b = [[inputNodes[i] value] doubleValue]; \
acc = OP; \
} \
return @(acc); \
}
#define REA_SINGLE(OP) ^(NSArray<REANode *> *inputNodes) { \
double a = [[inputNodes[0] value] doubleValue]; \
return @(OP); \
}
#define REA_INFIX(OP) ^(NSArray<REANode *> *inputNodes) { \
double a = [[inputNodes[0] value] doubleValue]; \
double b = [[inputNodes[1] value] doubleValue]; \
return @(OP); \
}
@implementation REAOperatorNode {
NSArray<NSNumber *> *_input;
NSMutableArray<REANode *> *_inputNodes;
REAOperatorBlock _op;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
static NSDictionary *OPS;
static dispatch_once_t opsToken;
dispatch_once(&opsToken, ^{
OPS = @{
// arithmetic
@"add": REA_REDUCE(a + b),
@"sub": REA_REDUCE(a - b),
@"multiply": REA_REDUCE(a * b),
@"divide": REA_REDUCE(a / b),
@"pow": REA_REDUCE(pow(a, b)),
@"modulo": REA_REDUCE(fmod(fmod(a, b) + b, b)),
@"sqrt": REA_SINGLE(sqrt(a)),
@"log": REA_SINGLE(log(a)),
@"sin": REA_SINGLE(sin(a)),
@"cos": REA_SINGLE(cos(a)),
@"tan": REA_SINGLE(tan(a)),
@"acos": REA_SINGLE(acos(a)),
@"asin": REA_SINGLE(asin(a)),
@"atan": REA_SINGLE(atan(a)),
@"exp": REA_SINGLE(exp(a)),
@"round": REA_SINGLE(round(a)),
@"abs": REA_SINGLE(fabs(a)),
@"ceil": REA_SINGLE(ceil(a)),
@"floor": REA_SINGLE(floor(a)),
@"max": REA_REDUCE(MAX(a, b)),
@"min": REA_REDUCE(MIN(a, b)),
// logical
@"and": ^(NSArray<REANode *> *inputNodes) {
BOOL res = [[inputNodes[0] value] doubleValue];
for (NSUInteger i = 1; i < inputNodes.count && res; i++) {
res = res && [[inputNodes[i] value] doubleValue];
}
return res ? @(1.) : @(0.);
},
@"or": ^(NSArray<REANode *> *inputNodes) {
BOOL res = [[inputNodes[0] value] doubleValue];
for (NSUInteger i = 1; i < inputNodes.count && !res; i++) {
res = res || [[inputNodes[i] value] doubleValue];
}
return res ? @(1.) : @(0.);
},
@"not": REA_SINGLE(!a),
@"defined": ^(NSArray<REANode *> *inputNodes) {
id val = [inputNodes[0] value];
id res = @(val != nil && !([val isKindOfClass:[NSNumber class]] && isnan([val doubleValue])));
return res;
},
// comparing
@"lessThan": REA_INFIX(a < b),
@"eq": REA_INFIX(a == b),
@"greaterThan": REA_INFIX(a > b),
@"lessOrEq": REA_INFIX(a <= b),
@"greaterOrEq": REA_INFIX(a >= b),
@"neq": REA_INFIX(a != b),
};
});
if ((self = [super initWithID:nodeID config:config])) {
_input = config[@"input"];
_inputNodes = [NSMutableArray arrayWithCapacity:_input.count];
_op = OPS[config[@"op"]];
if (!_op) {
RCTLogError(@"Operator '%@' not found", config[@"op"]);
}
}
return self;
}
- (id)evaluate
{
for (NSUInteger i = 0; i < _input.count; i++) {
_inputNodes[i] = [self.nodesManager findNodeByID:_input[i]];
}
return _op(_inputNodes);
}
@end

View File

@ -0,0 +1,12 @@
#import "REAValueNode.h"
@interface REAParamNode : REAValueNode
- (void)beginContext:(NSNumber*) ref
prevCallID:(NSNumber*) prevCallID;
- (void)endContext;
- (void)start;
- (void)stop;
- (BOOL)isRunning;
@end

View File

@ -0,0 +1,81 @@
#import "REAParamNode.h"
#import "REAValueNode.h"
#import "REANodesManager.h"
#import "REAClockNodes.h"
@implementation REAParamNode {
NSMutableArray<REANodeID> *_argstack;
NSString *_prevCallID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_argstack = [NSMutableArray<REANodeID> arrayWithCapacity:0];
}
return self;
}
- (void)setValue:(NSNumber *)value
{
REANode *node = [self.nodesManager findNodeByID:[_argstack lastObject]];
NSString *callID = self.updateContext.callID;
self.updateContext.callID = _prevCallID;
[(REAValueNode*)node setValue:value];
self.updateContext.callID = callID;
[self forceUpdateMemoizedValue:value];
}
- (void)beginContext:(NSNumber*) ref
prevCallID:(NSString*) prevCallID
{
_prevCallID = prevCallID;
[_argstack addObject:ref];
}
- (void)endContext
{
[_argstack removeLastObject];
}
- (id)evaluate
{
NSString *callID = self.updateContext.callID;
self.updateContext.callID = _prevCallID;
REANode * node = [self.nodesManager findNodeByID:[_argstack lastObject]];
id val = [node value];
self.updateContext.callID = callID;
return val;
}
- (void)start
{
REANode* node = [self.nodesManager findNodeByID:[_argstack lastObject]];
if ([node isKindOfClass:[REAParamNode class]]) {
[(REAParamNode* )node start];
} else {
[(REAClockNode* )node start];
}
}
- (void)stop
{
REANode* node = [self.nodesManager findNodeByID:[_argstack lastObject]];
if ([node isKindOfClass:[REAParamNode class]]) {
[(REAParamNode* )node stop];
} else {
[(REAClockNode* )node stop];
}
}
- (BOOL)isRunning
{
REANode* node = [self.nodesManager findNodeByID:[_argstack lastObject]];
if ([node isKindOfClass:[REAParamNode class]]) {
return [(REAParamNode* )node isRunning];
}
return [(REAClockNode* )node isRunning];
}
@end

View File

@ -0,0 +1,11 @@
#import "REANode.h"
@interface REAPropsNode : REANode <REAFinalNode>
- (void)connectToView:(NSNumber *_Nonnull)viewTag
viewName:(NSString *_Nonnull)viewName;
- (void)disconnectFromView:(NSNumber *_Nonnull)viewTag;
@end

View File

@ -0,0 +1,101 @@
#import "REAPropsNode.h"
#import "REANodesManager.h"
#import "REAStyleNode.h"
#import "REAModule.h"
#import <React/RCTLog.h>
#import <React/RCTUIManager.h>
#import "React/RCTComponentData.h"
@implementation REAPropsNode
{
NSNumber *_connectedViewTag;
NSString *_connectedViewName;
NSMutableDictionary<NSString *, REANodeID> *_propsConfig;
}
- (instancetype)initWithID:(REANodeID)nodeID
config:(NSDictionary<NSString *,id> *)config
{
if (self = [super initWithID:nodeID config:config]) {
_propsConfig = config[@"props"];
}
return self;
}
- (void)connectToView:(NSNumber *)viewTag
viewName:(NSString *)viewName
{
_connectedViewTag = viewTag;
_connectedViewName = viewName;
[self dangerouslyRescheduleEvaluate];
}
- (void)disconnectFromView:(NSNumber *)viewTag
{
_connectedViewTag = nil;
_connectedViewName = nil;
}
- (id)evaluate
{
NSMutableDictionary *uiProps = [NSMutableDictionary new];
NSMutableDictionary *nativeProps = [NSMutableDictionary new];
NSMutableDictionary *jsProps = [NSMutableDictionary new];
void (^addBlock)(NSString *key, id obj, BOOL * stop) = ^(NSString *key, id obj, BOOL * stop){
if ([self.nodesManager.uiProps containsObject:key]) {
uiProps[key] = obj;
} else if ([self.nodesManager.nativeProps containsObject:key]) {
nativeProps[key] = obj;
} else {
jsProps[key] = obj;
}
};
for (NSString *prop in _propsConfig) {
REANode *propNode = [self.nodesManager findNodeByID:_propsConfig[prop]];
if ([propNode isKindOfClass:[REAStyleNode class]]) {
[[propNode value] enumerateKeysAndObjectsUsingBlock:addBlock];
} else {
addBlock(prop, [propNode value], nil);
}
}
if (_connectedViewTag != nil) {
if (uiProps.count > 0) {
[self.nodesManager.uiManager
synchronouslyUpdateViewOnUIThread:_connectedViewTag
viewName:_connectedViewName
props:uiProps];
}
if (nativeProps.count > 0) {
[self.nodesManager enqueueUpdateViewOnNativeThread:_connectedViewTag viewName:_connectedViewName nativeProps:nativeProps];
}
if (jsProps.count > 0) {
[self.nodesManager.reanimatedModule
sendEventWithName:@"onReanimatedPropsChange"
body:@{@"viewTag": _connectedViewTag, @"props": jsProps }];
}
}
return @(0);
}
- (void)update
{
// Since we are updating nodes after detaching them from views there is a time where it's
// possible that the view was disconnected and still receive an update, this is normal and we can
// simply skip that update.
if (!_connectedViewTag) {
return;
}
// triger for side effect
[self value];
}
@end

View File

@ -0,0 +1,6 @@
#import "REANode.h"
@interface REASetNode : REANode
@end

View File

@ -0,0 +1,32 @@
#import "REASetNode.h"
#import "REAUtils.h"
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
#import "REAValueNode.h"
#import "REANodesManager.h"
@implementation REASetNode {
NSNumber *_whatNodeID;
NSNumber *_valueNodeID;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_whatNodeID = [RCTConvert NSNumber:config[@"what"]];
REA_LOG_ERROR_IF_NIL(_whatNodeID, @"Reanimated: First argument passed to set node is either of wrong type or is missing.");
_valueNodeID = [RCTConvert NSNumber:config[@"value"]];
REA_LOG_ERROR_IF_NIL(_valueNodeID, @"Reanimated: Second argument passed to set node is either of wrong type or is missing.");
}
return self;
}
- (id)evaluate
{
NSNumber *newValue = [[self.nodesManager findNodeByID:_valueNodeID] value];
REAValueNode *what = (REAValueNode *)[self.nodesManager findNodeByID:_whatNodeID];
[what setValue:newValue];
return newValue;
}
@end

View File

@ -0,0 +1,6 @@
#import "REANode.h"
@interface REAStyleNode : REANode
@end

View File

@ -0,0 +1,30 @@
#import "REAStyleNode.h"
#import "REANodesManager.h"
@implementation REAStyleNode
{
NSMutableDictionary<NSString *, REANodeID> *_styleConfig;
}
- (instancetype)initWithID:(REANodeID)nodeID
config:(NSDictionary<NSString *, id> *)config;
{
if ((self = [super initWithID:nodeID config:config])) {
_styleConfig = config[@"style"];
}
return self;
}
- (id)evaluate
{
NSMutableDictionary *styles = [NSMutableDictionary new];
for (NSString *prop in _styleConfig) {
REANode *propNode = [self.nodesManager findNodeByID:_styleConfig[prop]];
styles[prop] = [propNode value];
}
return styles;
}
@end

View File

@ -0,0 +1,6 @@
#import "REANode.h"
@interface REATransformNode : REANode
@end

View File

@ -0,0 +1,38 @@
#import "REATransformNode.h"
#import <React/RCTConvert.h>
#import "REANodesManager.h"
@implementation REATransformNode
{
NSArray<id> *_transformConfigs;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)config
{
if ((self = [super initWithID:nodeID config:config])) {
_transformConfigs = config[@"transform"];
}
return self;
}
- (id)evaluate
{
NSMutableArray<NSDictionary *> *transform = [NSMutableArray arrayWithCapacity:_transformConfigs.count];
for (NSDictionary *transformConfig in _transformConfigs) {
NSString *property = transformConfig[@"property"];
REANodeID nodeID = [RCTConvert NSNumber:transformConfig[@"nodeID"]];
NSNumber *value;
if (nodeID) {
REANode *node = [self.nodesManager findNodeByID:nodeID];
value = [node value];
} else {
value = transformConfig[@"value"];
}
[transform addObject:@{property: value}];
}
return transform;
}
@end

View File

@ -0,0 +1,11 @@
#import <UIKit/UIKit.h>
#import "REANode.h"
@class REAValueNode;
@interface REAValueNode : REANode
- (void)setValue:(NSNumber *)value;
@end

View File

@ -0,0 +1,28 @@
#import "REAValueNode.h"
@implementation REAValueNode {
NSNumber *_value;
}
- (instancetype)initWithID:(REANodeID)nodeID
config:(NSDictionary<NSString *, id> *)config
{
if (self = [super initWithID:nodeID config:config]) {
_value = config[@"value"];
}
return self;
}
- (void)setValue:(NSNumber *)value
{
_value = value;
[self forceUpdateMemoizedValue:value];
}
- (id)evaluate
{
return _value;
}
@end

12
node_modules/react-native-reanimated/ios/REAModule.h generated vendored Normal file
View File

@ -0,0 +1,12 @@
#import <React/RCTBridgeModule.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerObserverCoordinator.h>
#import <React/RCTUIManagerUtils.h>
#import "REAValueNode.h"
@interface REAModule : RCTEventEmitter <RCTBridgeModule, RCTEventDispatcherObserver, RCTUIManagerObserver>
@end

187
node_modules/react-native-reanimated/ios/REAModule.m generated vendored Normal file
View File

@ -0,0 +1,187 @@
#import "REAModule.h"
#import "REANodesManager.h"
#import "Transitioning/REATransitionManager.h"
typedef void (^AnimatedOperation)(REANodesManager *nodesManager);
@implementation REAModule
{
REANodesManager *_nodesManager;
NSMutableArray<AnimatedOperation> *_operations;
REATransitionManager *_transitionManager;
}
RCT_EXPORT_MODULE(ReanimatedModule);
- (void)invalidate
{
_transitionManager = nil;
[_nodesManager invalidate];
[self.bridge.eventDispatcher removeDispatchObserver:self];
[self.bridge.uiManager.observerCoordinator removeObserver:self];
}
- (dispatch_queue_t)methodQueue
{
// This module needs to be on the same queue as the UIManager to avoid
// having to lock `_operations` and `_preOperations` since `uiManagerWillPerformMounting`
// will be called from that queue.
return RCTGetUIManagerQueue();
}
- (void)setBridge:(RCTBridge *)bridge
{
[super setBridge:bridge];
_nodesManager = [[REANodesManager alloc] initWithModule:self
uiManager:self.bridge.uiManager];
_operations = [NSMutableArray new];
_transitionManager = [[REATransitionManager alloc] initWithUIManager:self.bridge.uiManager];
[bridge.eventDispatcher addDispatchObserver:self];
[bridge.uiManager.observerCoordinator addObserver:self];
}
#pragma mark -- Transitioning API
RCT_EXPORT_METHOD(animateNextTransition:(nonnull NSNumber *)rootTag config:(NSDictionary *)config)
{
[_transitionManager animateNextTransitionInRoot:rootTag withConfig:config];
}
#pragma mark -- API
RCT_EXPORT_METHOD(createNode:(nonnull NSNumber *)nodeID
config:(NSDictionary<NSString *, id> *)config)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager createNode:nodeID config:config];
}];
}
RCT_EXPORT_METHOD(dropNode:(nonnull NSNumber *)nodeID)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager dropNode:nodeID];
}];
}
RCT_EXPORT_METHOD(getValue:(nonnull NSNumber *)nodeID
callback:(RCTResponseSenderBlock)callback) {
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager getValue:nodeID callback:(RCTResponseSenderBlock)callback];
}];
}
RCT_EXPORT_METHOD(connectNodes:(nonnull NSNumber *)parentID
childTag:(nonnull NSNumber *)childID)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager connectNodes:parentID childID:childID];
}];
}
RCT_EXPORT_METHOD(disconnectNodes:(nonnull NSNumber *)parentID
childTag:(nonnull NSNumber *)childID)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager disconnectNodes:parentID childID:childID];
}];
}
RCT_EXPORT_METHOD(connectNodeToView:(nonnull NSNumber *)nodeID
viewTag:(nonnull NSNumber *)viewTag)
{
NSString *viewName = [self.bridge.uiManager viewNameForReactTag:viewTag];
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager connectNodeToView:nodeID viewTag:viewTag viewName:viewName];
}];
}
RCT_EXPORT_METHOD(disconnectNodeFromView:(nonnull NSNumber *)nodeID
viewTag:(nonnull NSNumber *)viewTag)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager disconnectNodeFromView:nodeID viewTag:viewTag];
}];
}
RCT_EXPORT_METHOD(attachEvent:(nonnull NSNumber *)viewTag
eventName:(nonnull NSString *)eventName
eventNodeID:(nonnull NSNumber *)eventNodeID)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager attachEvent:viewTag eventName:eventName eventNodeID:eventNodeID];
}];
}
RCT_EXPORT_METHOD(detachEvent:(nonnull NSNumber *)viewTag
eventName:(nonnull NSString *)eventName
eventNodeID:(nonnull NSNumber *)eventNodeID)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager detachEvent:viewTag eventName:eventName eventNodeID:eventNodeID];
}];
}
RCT_EXPORT_METHOD(configureProps:(nonnull NSArray<NSString *> *)nativeProps
uiProps:(nonnull NSArray<NSString *> *)uiProps)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager configureProps:[NSSet setWithArray:nativeProps] uiProps:[NSSet setWithArray:uiProps]];
}];
}
RCT_EXPORT_METHOD(setValue:(nonnull NSNumber *)nodeID
newValue:(nonnull NSNumber *)newValue
)
{
[self addOperationBlock:^(REANodesManager *nodesManager) {
[nodesManager setValueForNodeID:nodeID value:newValue];
}];
}
#pragma mark -- Batch handling
- (void)addOperationBlock:(AnimatedOperation)operation
{
[_operations addObject:operation];
}
#pragma mark - RCTUIManagerObserver
- (void)uiManagerWillPerformMounting:(RCTUIManager *)uiManager
{
if (_operations.count == 0) {
return;
}
NSArray<AnimatedOperation> *operations = _operations;
_operations = [NSMutableArray new];
REANodesManager *nodesManager = _nodesManager;
[uiManager addUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, UIView *> *viewRegistry) {
for (AnimatedOperation operation in operations) {
operation(nodesManager);
}
[nodesManager operationsBatchDidComplete];
}];
}
#pragma mark -- Events
- (NSArray<NSString *> *)supportedEvents
{
return @[@"onReanimatedCall", @"onReanimatedPropsChange"];
}
- (void)eventDispatcherWillDispatchEvent:(id<RCTEvent>)event
{
// Events can be dispatched from any queue
[_nodesManager dispatchEvent:event];
}
@end

View File

@ -0,0 +1,79 @@
#import <Foundation/Foundation.h>
#import "REANode.h"
#import <React/RCTBridgeModule.h>
#import <React/RCTUIManager.h>
@class REAModule;
typedef void (^REAOnAnimationCallback)(CADisplayLink *displayLink);
typedef void (^REANativeAnimationOp)(RCTUIManager *uiManager);
@interface REANodesManager : NSObject
@property (nonatomic, weak, nullable) RCTUIManager *uiManager;
@property (nonatomic, weak, nullable) REAModule *reanimatedModule;
@property (nonatomic, readonly) CFTimeInterval currentAnimationTimestamp;
@property (nonatomic, nullable) NSSet<NSString *> *uiProps;
@property (nonatomic, nullable) NSSet<NSString *> *nativeProps;
- (nonnull instancetype)initWithModule:(REAModule *)reanimatedModule
uiManager:(nonnull RCTUIManager *)uiManager;
- (REANode* _Nullable)findNodeByID:(nonnull REANodeID)nodeID;
- (void)invalidate;
- (void)operationsBatchDidComplete;
//
- (void)postOnAnimation:(REAOnAnimationCallback)clb;
- (void)postRunUpdatesAfterAnimation;
- (void)enqueueUpdateViewOnNativeThread:(nonnull NSNumber *)reactTag
viewName:(NSString *) viewName
nativeProps:(NSMutableDictionary *)nativeProps;
- (void)getValue:(REANodeID)nodeID
callback:(RCTResponseSenderBlock)callback;
// graph
- (void)createNode:(nonnull REANodeID)tag
config:(NSDictionary<NSString *, id> *__nonnull)config;
- (void)dropNode:(nonnull REANodeID)tag;
- (void)connectNodes:(nonnull REANodeID)parentID
childID:(nonnull REANodeID)childID;
- (void)disconnectNodes:(nonnull REANodeID)parentID
childID:(nonnull REANodeID)childID;
- (void)connectNodeToView:(nonnull REANodeID)nodeID
viewTag:(nonnull NSNumber *)viewTag
viewName:(nonnull NSString *)viewName;
- (void)disconnectNodeFromView:(nonnull REANodeID)nodeID
viewTag:(nonnull NSNumber *)viewTag;
- (void)attachEvent:(nonnull NSNumber *)viewTag
eventName:(nonnull NSString *)eventName
eventNodeID:(nonnull REANodeID)eventNodeID;
- (void)detachEvent:(nonnull NSNumber *)viewTag
eventName:(nonnull NSString *)eventName
eventNodeID:(nonnull REANodeID)eventNodeID;
// configuration
- (void)configureProps:(nonnull NSSet<NSString *> *)nativeProps
uiProps:(nonnull NSSet<NSString *> *)uiProps;
// events
- (void)dispatchEvent:(id<RCTEvent>)event;
- (void)setValueForNodeID:(nonnull NSNumber *)nodeID value:(nonnull NSNumber *)newValue;
@end

View File

@ -0,0 +1,402 @@
#import "REANodesManager.h"
#import <React/RCTConvert.h>
#import "Nodes/REANode.h"
#import "Nodes/REAPropsNode.h"
#import "Nodes/REAStyleNode.h"
#import "Nodes/REATransformNode.h"
#import "Nodes/REAValueNode.h"
#import "Nodes/REABlockNode.h"
#import "Nodes/REACondNode.h"
#import "Nodes/REAOperatorNode.h"
#import "Nodes/REASetNode.h"
#import "Nodes/READebugNode.h"
#import "Nodes/REAClockNodes.h"
#import "Nodes/REAJSCallNode.h"
#import "Nodes/REABezierNode.h"
#import "Nodes/REAEventNode.h"
#import "REAModule.h"
#import "Nodes/REAAlwaysNode.h"
#import "Nodes/REAConcatNode.h"
#import "Nodes/REAParamNode.h"
#import "Nodes/REAFunctionNode.h"
#import "Nodes/REACallFuncNode.h"
// Interface below has been added in order to use private methods of RCTUIManager,
// RCTUIManager#UpdateView is a React Method which is exported to JS but in
// Objective-C it stays private
// RCTUIManager#setNeedsLayout is a method which updated layout only which
// in its turn will trigger relayout if no batch has been activated
@interface RCTUIManager ()
- (void)updateView:(nonnull NSNumber *)reactTag
viewName:(NSString *)viewName
props:(NSDictionary *)props;
- (void)setNeedsLayout;
@end
@implementation REANodesManager
{
NSMutableDictionary<REANodeID, REANode *> *_nodes;
NSMapTable<NSString *, REANode *> *_eventMapping;
NSMutableArray<id<RCTEvent>> *_eventQueue;
CADisplayLink *_displayLink;
REAUpdateContext *_updateContext;
BOOL _wantRunUpdates;
BOOL _processingDirectEvent;
NSMutableArray<REAOnAnimationCallback> *_onAnimationCallbacks;
NSMutableArray<REANativeAnimationOp> *_operationsInBatch;
}
- (instancetype)initWithModule:(REAModule *)reanimatedModule
uiManager:(RCTUIManager *)uiManager
{
if ((self = [super init])) {
_reanimatedModule = reanimatedModule;
_uiManager = uiManager;
_nodes = [NSMutableDictionary new];
_eventMapping = [NSMapTable strongToWeakObjectsMapTable];
_eventQueue = [NSMutableArray new];
_updateContext = [REAUpdateContext new];
_wantRunUpdates = NO;
_onAnimationCallbacks = [NSMutableArray new];
_operationsInBatch = [NSMutableArray new];
}
return self;
}
- (void)invalidate
{
[self stopUpdatingOnAnimationFrame];
}
- (void)operationsBatchDidComplete
{
if (_displayLink) {
// if display link is set it means some of the operations that have run as a part of the batch
// requested updates. We want updates to be run in the same frame as in which operations have
// been scheduled as it may mean the new view has just been mounted and expects its initial
// props to be calculated.
// Unfortunately if the operation has just scheduled animation callback it won't run until the
// next frame, so it's being triggered manually.
_wantRunUpdates = YES;
[self performOperations];
}
}
- (REANode *)findNodeByID:(REANodeID)nodeID
{
return _nodes[nodeID];
}
- (void)postOnAnimation:(REAOnAnimationCallback)clb
{
[_onAnimationCallbacks addObject:clb];
[self startUpdatingOnAnimationFrame];
}
- (void)postRunUpdatesAfterAnimation
{
_wantRunUpdates = YES;
if (!_processingDirectEvent) {
[self startUpdatingOnAnimationFrame];
}
}
- (void)startUpdatingOnAnimationFrame
{
if (!_displayLink) {
// Setting _currentAnimationTimestamp here is connected with manual triggering of performOperations
// in operationsBatchDidComplete. If new node has been created and clock has not been started,
// _displayLink won't be initialized soon enough and _displayLink.timestamp will be 0.
// However, CADisplayLink is using CACurrentMediaTime so if there's need to perform one more
// evaluation, it could be used it here. In usual case, CACurrentMediaTime is not being used in
// favor of setting it with _displayLink.timestamp in onAnimationFrame method.
_currentAnimationTimestamp = CACurrentMediaTime();
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onAnimationFrame:)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
}
- (void)stopUpdatingOnAnimationFrame
{
if (_displayLink) {
[_displayLink invalidate];
_displayLink = nil;
}
}
- (void)onAnimationFrame:(CADisplayLink *)displayLink
{
// We process all enqueued events first
_currentAnimationTimestamp = _displayLink.timestamp;
for (NSUInteger i = 0; i < _eventQueue.count; i++) {
id<RCTEvent> event = _eventQueue[i];
[self processEvent:event];
}
[_eventQueue removeAllObjects];
NSArray<REAOnAnimationCallback> *callbacks = _onAnimationCallbacks;
_onAnimationCallbacks = [NSMutableArray new];
// When one of the callbacks would postOnAnimation callback we don't want
// to process it until the next frame. This is why we cpy the array before
// we iterate over it
for (REAOnAnimationCallback block in callbacks) {
block(displayLink);
}
[self performOperations];
if (_onAnimationCallbacks.count == 0) {
[self stopUpdatingOnAnimationFrame];
}
}
- (void)performOperations
{
if (_wantRunUpdates) {
[REANode runPropUpdates:_updateContext];
}
if (_operationsInBatch.count != 0) {
NSMutableArray<REANativeAnimationOp> *copiedOperationsQueue = _operationsInBatch;
_operationsInBatch = [NSMutableArray new];
RCTExecuteOnUIManagerQueue(^{
for (int i = 0; i < copiedOperationsQueue.count; i++) {
copiedOperationsQueue[i](self.uiManager);
}
[self.uiManager setNeedsLayout];
});
}
_wantRunUpdates = NO;
}
- (void)enqueueUpdateViewOnNativeThread:(nonnull NSNumber *)reactTag
viewName:(NSString *) viewName
nativeProps:(NSMutableDictionary *)nativeProps {
[_operationsInBatch addObject:^(RCTUIManager *uiManager) {
[uiManager updateView:reactTag viewName:viewName props:nativeProps];
}];
}
- (void)getValue:(REANodeID)nodeID
callback:(RCTResponseSenderBlock)callback
{
id val = _nodes[nodeID].value;
if (val) {
callback(@[val]);
} else {
// NULL is not an object and it's not possible to pass it as callback's argument
callback(@[[NSNull null]]);
}
}
#pragma mark -- Graph
- (void)createNode:(REANodeID)nodeID
config:(NSDictionary<NSString *, id> *)config
{
static NSDictionary *map;
static dispatch_once_t mapToken;
dispatch_once(&mapToken, ^{
map = @{@"props": [REAPropsNode class],
@"style": [REAStyleNode class],
@"transform": [REATransformNode class],
@"value": [REAValueNode class],
@"block": [REABlockNode class],
@"cond": [REACondNode class],
@"op": [REAOperatorNode class],
@"set": [REASetNode class],
@"debug": [READebugNode class],
@"clock": [REAClockNode class],
@"clockStart": [REAClockStartNode class],
@"clockStop": [REAClockStopNode class],
@"clockTest": [REAClockTestNode class],
@"call": [REAJSCallNode class],
@"bezier": [REABezierNode class],
@"event": [REAEventNode class],
@"always": [REAAlwaysNode class],
@"concat": [REAConcatNode class],
@"param": [REAParamNode class],
@"func": [REAFunctionNode class],
@"callfunc": [REACallFuncNode class],
// @"listener": nil,
};
});
NSString *nodeType = [RCTConvert NSString:config[@"type"]];
Class nodeClass = map[nodeType];
if (!nodeClass) {
RCTLogError(@"Animated node type %@ not supported natively", nodeType);
return;
}
REANode *node = [[nodeClass alloc] initWithID:nodeID config:config];
node.nodesManager = self;
node.updateContext = _updateContext;
_nodes[nodeID] = node;
}
- (void)dropNode:(REANodeID)nodeID
{
REANode *node = _nodes[nodeID];
if (node) {
[_nodes removeObjectForKey:nodeID];
}
}
- (void)connectNodes:(nonnull NSNumber *)parentID childID:(nonnull REANodeID)childID
{
RCTAssertParam(parentID);
RCTAssertParam(childID);
REANode *parentNode = _nodes[parentID];
REANode *childNode = _nodes[childID];
RCTAssertParam(childNode);
[parentNode addChild:childNode];
}
- (void)disconnectNodes:(REANodeID)parentID childID:(REANodeID)childID
{
RCTAssertParam(parentID);
RCTAssertParam(childID);
REANode *parentNode = _nodes[parentID];
REANode *childNode = _nodes[childID];
RCTAssertParam(childNode);
[parentNode removeChild:childNode];
}
- (void)connectNodeToView:(REANodeID)nodeID
viewTag:(NSNumber *)viewTag
viewName:(NSString *)viewName
{
RCTAssertParam(nodeID);
REANode *node = _nodes[nodeID];
RCTAssertParam(node);
if ([node isKindOfClass:[REAPropsNode class]]) {
[(REAPropsNode *)node connectToView:viewTag viewName:viewName];
}
}
- (void)disconnectNodeFromView:(REANodeID)nodeID
viewTag:(NSNumber *)viewTag
{
RCTAssertParam(nodeID);
REANode *node = _nodes[nodeID];
RCTAssertParam(node);
if ([node isKindOfClass:[REAPropsNode class]]) {
[(REAPropsNode *)node disconnectFromView:viewTag];
}
}
- (void)attachEvent:(NSNumber *)viewTag
eventName:(NSString *)eventName
eventNodeID:(REANodeID)eventNodeID
{
RCTAssertParam(eventNodeID);
REANode *eventNode = _nodes[eventNodeID];
RCTAssert([eventNode isKindOfClass:[REAEventNode class]], @"Event node is of an invalid type");
NSString *key = [NSString stringWithFormat:@"%@%@",
viewTag,
RCTNormalizeInputEventName(eventName)];
RCTAssert([_eventMapping objectForKey:key] == nil, @"Event handler already set for the given view and event type");
[_eventMapping setObject:eventNode forKey:key];
}
- (void)detachEvent:(NSNumber *)viewTag
eventName:(NSString *)eventName
eventNodeID:(REANodeID)eventNodeID
{
NSString *key = [NSString stringWithFormat:@"%@%@",
viewTag,
RCTNormalizeInputEventName(eventName)];
[_eventMapping removeObjectForKey:key];
}
- (void)processEvent:(id<RCTEvent>)event
{
NSString *key = [NSString stringWithFormat:@"%@%@",
event.viewTag,
RCTNormalizeInputEventName(event.eventName)];
REAEventNode *eventNode = [_eventMapping objectForKey:key];
[eventNode processEvent:event];
}
- (void)processDirectEvent:(id<RCTEvent>)event
{
_processingDirectEvent = YES;
[self processEvent:event];
[self performOperations];
_processingDirectEvent = NO;
}
- (BOOL)isDirectEvent:(id<RCTEvent>)event
{
static NSArray<NSString *> *directEventNames;
static dispatch_once_t directEventNamesToken;
dispatch_once(&directEventNamesToken, ^{
directEventNames = @[
@"topContentSizeChange",
@"topMomentumScrollBegin",
@"topMomentumScrollEnd",
@"topScroll",
@"topScrollBeginDrag",
@"topScrollEndDrag"
];
});
return [directEventNames containsObject:RCTNormalizeInputEventName(event.eventName)];
}
- (void)dispatchEvent:(id<RCTEvent>)event
{
NSString *key = [NSString stringWithFormat:@"%@%@",
event.viewTag,
RCTNormalizeInputEventName(event.eventName)];
REANode *eventNode = [_eventMapping objectForKey:key];
if (eventNode != nil) {
if ([self isDirectEvent:event]) {
// Bypass the event queue/animation frames and process scroll events
// immediately to avoid getting out of sync with the scroll position
[self processDirectEvent:event];
} else {
// enqueue node to be processed
[_eventQueue addObject:event];
[self startUpdatingOnAnimationFrame];
}
}
}
- (void)configureProps:(NSSet<NSString *> *)nativeProps
uiProps:(NSSet<NSString *> *)uiProps
{
_uiProps = uiProps;
_nativeProps = nativeProps;
}
- (void)setValueForNodeID:(nonnull NSNumber *)nodeID value:(nonnull NSNumber *)newValue
{
RCTAssertParam(nodeID);
REANode *node = _nodes[nodeID];
REAValueNode *valueNode = (REAValueNode *)node;
[valueNode setValue:newValue];
}
@end

5
node_modules/react-native-reanimated/ios/REAUtils.h generated vendored Normal file
View File

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
#define REA_LOG_ERROR_IF_NIL(value, errorMsg) ({\
if (value == nil) RCTLogError(errorMsg);\
})

View File

@ -0,0 +1,609 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
440FEC2C209062F100EEC73A /* REAPropsNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC0D209062F100EEC73A /* REAPropsNode.m */; };
440FEC2D209062F100EEC73A /* REAStyleNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC13209062F100EEC73A /* REAStyleNode.m */; };
440FEC2E209062F100EEC73A /* READebugNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC14209062F100EEC73A /* READebugNode.m */; };
440FEC2F209062F100EEC73A /* REAClockNodes.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC18209062F100EEC73A /* REAClockNodes.m */; };
440FEC30209062F100EEC73A /* REAValueNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC19209062F100EEC73A /* REAValueNode.m */; };
440FEC31209062F100EEC73A /* REACondNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC1A209062F100EEC73A /* REACondNode.m */; };
440FEC32209062F100EEC73A /* REAJSCallNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC1B209062F100EEC73A /* REAJSCallNode.m */; };
440FEC33209062F100EEC73A /* REABezierNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC1C209062F100EEC73A /* REABezierNode.m */; };
440FEC34209062F100EEC73A /* REANode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC1F209062F100EEC73A /* REANode.m */; };
440FEC35209062F100EEC73A /* REATransformNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC20209062F100EEC73A /* REATransformNode.m */; };
440FEC36209062F100EEC73A /* REAEventNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC21209062F100EEC73A /* REAEventNode.m */; };
440FEC37209062F100EEC73A /* REASetNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC23209062F100EEC73A /* REASetNode.m */; };
440FEC38209062F100EEC73A /* REAOperatorNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC24209062F100EEC73A /* REAOperatorNode.m */; };
440FEC39209062F100EEC73A /* REABlockNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC25209062F100EEC73A /* REABlockNode.m */; };
440FEC3A209062F100EEC73A /* REAModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC2A209062F100EEC73A /* REAModule.m */; };
440FEC3B209062F100EEC73A /* REANodesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC2B209062F100EEC73A /* REANodesManager.m */; };
44125DC022538E6D003C1762 /* REATransitionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DBF22538E6D003C1762 /* REATransitionManager.m */; };
44125DC322538F68003C1762 /* REATransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DC222538F68003C1762 /* REATransition.m */; };
44125DC82253906B003C1762 /* REAAllTransitions.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DC72253906A003C1762 /* REAAllTransitions.m */; };
44125DCB22539177003C1762 /* REATransitionAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DCA22539177003C1762 /* REATransitionAnimation.m */; };
44125DCE2253A038003C1762 /* REATransitionValues.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DCD2253A038003C1762 /* REATransitionValues.m */; };
44125DD12253A3C0003C1762 /* RCTConvert+REATransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DD02253A3C0003C1762 /* RCTConvert+REATransition.m */; };
660A44292119B821006BFD5E /* REAConcatNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 660A44282119B820006BFD5E /* REAConcatNode.m */; };
66240C6920C68DEA00648F55 /* REAAlwaysNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 66240C6820C68DEA00648F55 /* REAAlwaysNode.m */; };
A12DA6B722EC228D00E8271A /* REAParamNode.m in Sources */ = {isa = PBXBuildFile; fileRef = A12DA6B622EC228D00E8271A /* REAParamNode.m */; };
A12DA6B822EC228D00E8271A /* REAParamNode.m in Sources */ = {isa = PBXBuildFile; fileRef = A12DA6B622EC228D00E8271A /* REAParamNode.m */; };
A12DA6BE22EC22E400E8271A /* REAFunctionNode.m in Sources */ = {isa = PBXBuildFile; fileRef = A12DA6BA22EC22E300E8271A /* REAFunctionNode.m */; };
A12DA6BF22EC22E400E8271A /* REAFunctionNode.m in Sources */ = {isa = PBXBuildFile; fileRef = A12DA6BA22EC22E300E8271A /* REAFunctionNode.m */; };
A12DA6C022EC22E400E8271A /* REACallFuncNode.m in Sources */ = {isa = PBXBuildFile; fileRef = A12DA6BC22EC22E300E8271A /* REACallFuncNode.m */; };
A12DA6C122EC22E400E8271A /* REACallFuncNode.m in Sources */ = {isa = PBXBuildFile; fileRef = A12DA6BC22EC22E300E8271A /* REACallFuncNode.m */; };
FDBB1777229BF0DE00D1E455 /* REAModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC2A209062F100EEC73A /* REAModule.m */; };
FDBB1778229BF0DE00D1E455 /* REANodesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC2B209062F100EEC73A /* REANodesManager.m */; };
FDBB1779229BF0E700D1E455 /* REATransitionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DBF22538E6D003C1762 /* REATransitionManager.m */; };
FDBB177A229BF0E700D1E455 /* REATransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DC222538F68003C1762 /* REATransition.m */; };
FDBB177B229BF0E700D1E455 /* REAAllTransitions.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DC72253906A003C1762 /* REAAllTransitions.m */; };
FDBB177C229BF0E700D1E455 /* REATransitionAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DCA22539177003C1762 /* REATransitionAnimation.m */; };
FDBB177D229BF0E700D1E455 /* REATransitionValues.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DCD2253A038003C1762 /* REATransitionValues.m */; };
FDBB177E229BF0E700D1E455 /* RCTConvert+REATransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 44125DD02253A3C0003C1762 /* RCTConvert+REATransition.m */; };
FDE6D933229BF70F007F6716 /* REAConcatNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 660A44282119B820006BFD5E /* REAConcatNode.m */; };
FDE6D934229BF70F007F6716 /* REAAlwaysNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 66240C6820C68DEA00648F55 /* REAAlwaysNode.m */; };
FDE6D935229BF70F007F6716 /* REANode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC1F209062F100EEC73A /* REANode.m */; };
FDE6D936229BF70F007F6716 /* REAValueNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC19209062F100EEC73A /* REAValueNode.m */; };
FDE6D937229BF70F007F6716 /* REAStyleNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC13209062F100EEC73A /* REAStyleNode.m */; };
FDE6D938229BF70F007F6716 /* REATransformNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC20209062F100EEC73A /* REATransformNode.m */; };
FDE6D939229BF70F007F6716 /* REAPropsNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC0D209062F100EEC73A /* REAPropsNode.m */; };
FDE6D93A229BF70F007F6716 /* REABlockNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC25209062F100EEC73A /* REABlockNode.m */; };
FDE6D93B229BF70F007F6716 /* REACondNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC1A209062F100EEC73A /* REACondNode.m */; };
FDE6D93C229BF70F007F6716 /* REAOperatorNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC24209062F100EEC73A /* REAOperatorNode.m */; };
FDE6D93D229BF70F007F6716 /* REASetNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC23209062F100EEC73A /* REASetNode.m */; };
FDE6D93E229BF70F007F6716 /* READebugNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC14209062F100EEC73A /* READebugNode.m */; };
FDE6D93F229BF70F007F6716 /* REAClockNodes.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC18209062F100EEC73A /* REAClockNodes.m */; };
FDE6D940229BF70F007F6716 /* REAJSCallNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC1B209062F100EEC73A /* REAJSCallNode.m */; };
FDE6D941229BF70F007F6716 /* REABezierNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC1C209062F100EEC73A /* REABezierNode.m */; };
FDE6D942229BF70F007F6716 /* REAEventNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 440FEC21209062F100EEC73A /* REAEventNode.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
58B511D91A9E6C8500147676 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
FDBB176C229BF04900D1E455 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRNReanimated.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNReanimated.a; sourceTree = BUILT_PRODUCTS_DIR; };
440FEC01209062F100EEC73A /* REANodesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REANodesManager.h; sourceTree = "<group>"; };
440FEC0A209062F100EEC73A /* REAModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAModule.h; sourceTree = "<group>"; };
440FEC0D209062F100EEC73A /* REAPropsNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAPropsNode.m; sourceTree = "<group>"; };
440FEC0E209062F100EEC73A /* REABezierNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REABezierNode.h; sourceTree = "<group>"; };
440FEC0F209062F100EEC73A /* REAJSCallNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAJSCallNode.h; sourceTree = "<group>"; };
440FEC10209062F100EEC73A /* REAEventNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAEventNode.h; sourceTree = "<group>"; };
440FEC11209062F100EEC73A /* REANode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REANode.h; sourceTree = "<group>"; };
440FEC12209062F100EEC73A /* REATransformNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REATransformNode.h; sourceTree = "<group>"; };
440FEC13209062F100EEC73A /* REAStyleNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAStyleNode.m; sourceTree = "<group>"; };
440FEC14209062F100EEC73A /* READebugNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = READebugNode.m; sourceTree = "<group>"; };
440FEC15209062F100EEC73A /* REABlockNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REABlockNode.h; sourceTree = "<group>"; };
440FEC16209062F100EEC73A /* REAOperatorNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAOperatorNode.h; sourceTree = "<group>"; };
440FEC17209062F100EEC73A /* REASetNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REASetNode.h; sourceTree = "<group>"; };
440FEC18209062F100EEC73A /* REAClockNodes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAClockNodes.m; sourceTree = "<group>"; };
440FEC19209062F100EEC73A /* REAValueNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAValueNode.m; sourceTree = "<group>"; };
440FEC1A209062F100EEC73A /* REACondNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REACondNode.m; sourceTree = "<group>"; };
440FEC1B209062F100EEC73A /* REAJSCallNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAJSCallNode.m; sourceTree = "<group>"; };
440FEC1C209062F100EEC73A /* REABezierNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REABezierNode.m; sourceTree = "<group>"; };
440FEC1D209062F100EEC73A /* REAPropsNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAPropsNode.h; sourceTree = "<group>"; };
440FEC1E209062F100EEC73A /* REAStyleNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAStyleNode.h; sourceTree = "<group>"; };
440FEC1F209062F100EEC73A /* REANode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REANode.m; sourceTree = "<group>"; };
440FEC20209062F100EEC73A /* REATransformNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REATransformNode.m; sourceTree = "<group>"; };
440FEC21209062F100EEC73A /* REAEventNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAEventNode.m; sourceTree = "<group>"; };
440FEC22209062F100EEC73A /* REAClockNodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAClockNodes.h; sourceTree = "<group>"; };
440FEC23209062F100EEC73A /* REASetNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REASetNode.m; sourceTree = "<group>"; };
440FEC24209062F100EEC73A /* REAOperatorNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAOperatorNode.m; sourceTree = "<group>"; };
440FEC25209062F100EEC73A /* REABlockNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REABlockNode.m; sourceTree = "<group>"; };
440FEC26209062F100EEC73A /* READebugNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = READebugNode.h; sourceTree = "<group>"; };
440FEC27209062F100EEC73A /* REACondNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REACondNode.h; sourceTree = "<group>"; };
440FEC28209062F100EEC73A /* REAValueNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAValueNode.h; sourceTree = "<group>"; };
440FEC2A209062F100EEC73A /* REAModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAModule.m; sourceTree = "<group>"; };
440FEC2B209062F100EEC73A /* REANodesManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REANodesManager.m; sourceTree = "<group>"; };
44125DBE22538E6D003C1762 /* REATransitionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = REATransitionManager.h; sourceTree = "<group>"; };
44125DBF22538E6D003C1762 /* REATransitionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = REATransitionManager.m; sourceTree = "<group>"; };
44125DC122538F68003C1762 /* REATransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = REATransition.h; sourceTree = "<group>"; };
44125DC222538F68003C1762 /* REATransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = REATransition.m; sourceTree = "<group>"; };
44125DC62253906A003C1762 /* REAAllTransitions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = REAAllTransitions.h; sourceTree = "<group>"; };
44125DC72253906A003C1762 /* REAAllTransitions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = REAAllTransitions.m; sourceTree = "<group>"; };
44125DC922539177003C1762 /* REATransitionAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = REATransitionAnimation.h; sourceTree = "<group>"; };
44125DCA22539177003C1762 /* REATransitionAnimation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = REATransitionAnimation.m; sourceTree = "<group>"; };
44125DCC2253A038003C1762 /* REATransitionValues.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = REATransitionValues.h; sourceTree = "<group>"; };
44125DCD2253A038003C1762 /* REATransitionValues.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = REATransitionValues.m; sourceTree = "<group>"; };
44125DCF2253A3C0003C1762 /* RCTConvert+REATransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+REATransition.h"; sourceTree = "<group>"; };
44125DD02253A3C0003C1762 /* RCTConvert+REATransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+REATransition.m"; sourceTree = "<group>"; };
4DA383A8226FA6A400582919 /* REAUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = REAUtils.h; sourceTree = "<group>"; };
660A44282119B820006BFD5E /* REAConcatNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAConcatNode.m; sourceTree = "<group>"; };
660A442A2119B83E006BFD5E /* REAConcatNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAConcatNode.h; sourceTree = "<group>"; };
66240C6720C68DEA00648F55 /* REAAlwaysNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAAlwaysNode.h; sourceTree = "<group>"; };
66240C6820C68DEA00648F55 /* REAAlwaysNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAAlwaysNode.m; sourceTree = "<group>"; };
A12DA6B622EC228D00E8271A /* REAParamNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = REAParamNode.m; sourceTree = "<group>"; };
A12DA6B922EC22A900E8271A /* REAParamNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = REAParamNode.h; sourceTree = "<group>"; };
A12DA6BA22EC22E300E8271A /* REAFunctionNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REAFunctionNode.m; sourceTree = "<group>"; };
A12DA6BB22EC22E300E8271A /* REACallFuncNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REACallFuncNode.h; sourceTree = "<group>"; };
A12DA6BC22EC22E300E8271A /* REACallFuncNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = REACallFuncNode.m; sourceTree = "<group>"; };
A12DA6BD22EC22E300E8271A /* REAFunctionNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = REAFunctionNode.h; sourceTree = "<group>"; };
FDBB176E229BF04900D1E455 /* libRNReanimated-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRNReanimated-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
58B511D81A9E6C8500147676 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
FDBB176B229BF04900D1E455 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
134814211AA4EA7D00B7C361 /* Products */ = {
isa = PBXGroup;
children = (
134814201AA4EA6300B7C361 /* libRNReanimated.a */,
);
name = Products;
sourceTree = "<group>";
};
440FEC0C209062F100EEC73A /* Nodes */ = {
isa = PBXGroup;
children = (
A12DA6B922EC22A900E8271A /* REAParamNode.h */,
A12DA6B622EC228D00E8271A /* REAParamNode.m */,
A12DA6BB22EC22E300E8271A /* REACallFuncNode.h */,
A12DA6BC22EC22E300E8271A /* REACallFuncNode.m */,
A12DA6BD22EC22E300E8271A /* REAFunctionNode.h */,
A12DA6BA22EC22E300E8271A /* REAFunctionNode.m */,
660A442A2119B83E006BFD5E /* REAConcatNode.h */,
660A44282119B820006BFD5E /* REAConcatNode.m */,
66240C6720C68DEA00648F55 /* REAAlwaysNode.h */,
66240C6820C68DEA00648F55 /* REAAlwaysNode.m */,
440FEC11209062F100EEC73A /* REANode.h */,
440FEC1F209062F100EEC73A /* REANode.m */,
440FEC28209062F100EEC73A /* REAValueNode.h */,
440FEC19209062F100EEC73A /* REAValueNode.m */,
440FEC1E209062F100EEC73A /* REAStyleNode.h */,
440FEC13209062F100EEC73A /* REAStyleNode.m */,
440FEC12209062F100EEC73A /* REATransformNode.h */,
440FEC20209062F100EEC73A /* REATransformNode.m */,
440FEC1D209062F100EEC73A /* REAPropsNode.h */,
440FEC0D209062F100EEC73A /* REAPropsNode.m */,
440FEC15209062F100EEC73A /* REABlockNode.h */,
440FEC25209062F100EEC73A /* REABlockNode.m */,
440FEC27209062F100EEC73A /* REACondNode.h */,
440FEC1A209062F100EEC73A /* REACondNode.m */,
440FEC16209062F100EEC73A /* REAOperatorNode.h */,
440FEC24209062F100EEC73A /* REAOperatorNode.m */,
440FEC17209062F100EEC73A /* REASetNode.h */,
440FEC23209062F100EEC73A /* REASetNode.m */,
440FEC26209062F100EEC73A /* READebugNode.h */,
440FEC14209062F100EEC73A /* READebugNode.m */,
440FEC22209062F100EEC73A /* REAClockNodes.h */,
440FEC18209062F100EEC73A /* REAClockNodes.m */,
440FEC0F209062F100EEC73A /* REAJSCallNode.h */,
440FEC1B209062F100EEC73A /* REAJSCallNode.m */,
440FEC0E209062F100EEC73A /* REABezierNode.h */,
440FEC1C209062F100EEC73A /* REABezierNode.m */,
440FEC10209062F100EEC73A /* REAEventNode.h */,
440FEC21209062F100EEC73A /* REAEventNode.m */,
);
path = Nodes;
sourceTree = "<group>";
};
44125C76224FBE0B003C1762 /* Transitioning */ = {
isa = PBXGroup;
children = (
44125DBE22538E6D003C1762 /* REATransitionManager.h */,
44125DBF22538E6D003C1762 /* REATransitionManager.m */,
44125DC122538F68003C1762 /* REATransition.h */,
44125DC222538F68003C1762 /* REATransition.m */,
44125DC62253906A003C1762 /* REAAllTransitions.h */,
44125DC72253906A003C1762 /* REAAllTransitions.m */,
44125DC922539177003C1762 /* REATransitionAnimation.h */,
44125DCA22539177003C1762 /* REATransitionAnimation.m */,
44125DCC2253A038003C1762 /* REATransitionValues.h */,
44125DCD2253A038003C1762 /* REATransitionValues.m */,
44125DCF2253A3C0003C1762 /* RCTConvert+REATransition.h */,
44125DD02253A3C0003C1762 /* RCTConvert+REATransition.m */,
);
path = Transitioning;
sourceTree = "<group>";
};
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
4DA383A8226FA6A400582919 /* REAUtils.h */,
44125C76224FBE0B003C1762 /* Transitioning */,
440FEC0C209062F100EEC73A /* Nodes */,
440FEC0A209062F100EEC73A /* REAModule.h */,
440FEC2A209062F100EEC73A /* REAModule.m */,
440FEC01209062F100EEC73A /* REANodesManager.h */,
440FEC2B209062F100EEC73A /* REANodesManager.m */,
134814211AA4EA7D00B7C361 /* Products */,
FDBB176E229BF04900D1E455 /* libRNReanimated-tvOS.a */,
);
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
58B511DA1A9E6C8500147676 /* RNReanimated */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNReanimated" */;
buildPhases = (
58B511D71A9E6C8500147676 /* Sources */,
58B511D81A9E6C8500147676 /* Frameworks */,
58B511D91A9E6C8500147676 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RNReanimated;
productName = RCTDataManager;
productReference = 134814201AA4EA6300B7C361 /* libRNReanimated.a */;
productType = "com.apple.product-type.library.static";
};
FDBB176D229BF04900D1E455 /* RNReanimated-tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = FDBB1774229BF04900D1E455 /* Build configuration list for PBXNativeTarget "RNReanimated-tvOS" */;
buildPhases = (
FDBB176A229BF04900D1E455 /* Sources */,
FDBB176B229BF04900D1E455 /* Frameworks */,
FDBB176C229BF04900D1E455 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = "RNReanimated-tvOS";
productName = "RNReanimated-tvOS";
productReference = FDBB176E229BF04900D1E455 /* libRNReanimated-tvOS.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
58B511D31A9E6C8500147676 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
58B511DA1A9E6C8500147676 = {
CreatedOnToolsVersion = 6.1.1;
};
FDBB176D229BF04900D1E455 = {
CreatedOnToolsVersion = 10.2.1;
DevelopmentTeam = NZDV3AFAEG;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNReanimated" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
);
mainGroup = 58B511D21A9E6C8500147676;
productRefGroup = 58B511D21A9E6C8500147676;
projectDirPath = "";
projectRoot = "";
targets = (
58B511DA1A9E6C8500147676 /* RNReanimated */,
FDBB176D229BF04900D1E455 /* RNReanimated-tvOS */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
58B511D71A9E6C8500147676 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
440FEC2E209062F100EEC73A /* READebugNode.m in Sources */,
440FEC37209062F100EEC73A /* REASetNode.m in Sources */,
440FEC3A209062F100EEC73A /* REAModule.m in Sources */,
44125DCE2253A038003C1762 /* REATransitionValues.m in Sources */,
44125DC82253906B003C1762 /* REAAllTransitions.m in Sources */,
A12DA6B722EC228D00E8271A /* REAParamNode.m in Sources */,
44125DC022538E6D003C1762 /* REATransitionManager.m in Sources */,
440FEC39209062F100EEC73A /* REABlockNode.m in Sources */,
A12DA6C022EC22E400E8271A /* REACallFuncNode.m in Sources */,
440FEC33209062F100EEC73A /* REABezierNode.m in Sources */,
44125DC322538F68003C1762 /* REATransition.m in Sources */,
440FEC2D209062F100EEC73A /* REAStyleNode.m in Sources */,
440FEC31209062F100EEC73A /* REACondNode.m in Sources */,
44125DD12253A3C0003C1762 /* RCTConvert+REATransition.m in Sources */,
440FEC2C209062F100EEC73A /* REAPropsNode.m in Sources */,
A12DA6BE22EC22E400E8271A /* REAFunctionNode.m in Sources */,
440FEC3B209062F100EEC73A /* REANodesManager.m in Sources */,
440FEC36209062F100EEC73A /* REAEventNode.m in Sources */,
44125DCB22539177003C1762 /* REATransitionAnimation.m in Sources */,
66240C6920C68DEA00648F55 /* REAAlwaysNode.m in Sources */,
440FEC2F209062F100EEC73A /* REAClockNodes.m in Sources */,
660A44292119B821006BFD5E /* REAConcatNode.m in Sources */,
440FEC38209062F100EEC73A /* REAOperatorNode.m in Sources */,
440FEC34209062F100EEC73A /* REANode.m in Sources */,
440FEC30209062F100EEC73A /* REAValueNode.m in Sources */,
440FEC32209062F100EEC73A /* REAJSCallNode.m in Sources */,
440FEC35209062F100EEC73A /* REATransformNode.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
FDBB176A229BF04900D1E455 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FDE6D93C229BF70F007F6716 /* REAOperatorNode.m in Sources */,
FDE6D93F229BF70F007F6716 /* REAClockNodes.m in Sources */,
FDE6D936229BF70F007F6716 /* REAValueNode.m in Sources */,
FDE6D941229BF70F007F6716 /* REABezierNode.m in Sources */,
FDBB177B229BF0E700D1E455 /* REAAllTransitions.m in Sources */,
A12DA6B822EC228D00E8271A /* REAParamNode.m in Sources */,
FDE6D93D229BF70F007F6716 /* REASetNode.m in Sources */,
FDE6D93A229BF70F007F6716 /* REABlockNode.m in Sources */,
A12DA6C122EC22E400E8271A /* REACallFuncNode.m in Sources */,
FDE6D939229BF70F007F6716 /* REAPropsNode.m in Sources */,
FDBB1778229BF0DE00D1E455 /* REANodesManager.m in Sources */,
FDE6D937229BF70F007F6716 /* REAStyleNode.m in Sources */,
FDE6D940229BF70F007F6716 /* REAJSCallNode.m in Sources */,
FDE6D935229BF70F007F6716 /* REANode.m in Sources */,
FDE6D93B229BF70F007F6716 /* REACondNode.m in Sources */,
A12DA6BF22EC22E400E8271A /* REAFunctionNode.m in Sources */,
FDBB177C229BF0E700D1E455 /* REATransitionAnimation.m in Sources */,
FDE6D934229BF70F007F6716 /* REAAlwaysNode.m in Sources */,
FDE6D933229BF70F007F6716 /* REAConcatNode.m in Sources */,
FDBB177D229BF0E700D1E455 /* REATransitionValues.m in Sources */,
FDE6D942229BF70F007F6716 /* REAEventNode.m in Sources */,
FDE6D93E229BF70F007F6716 /* READebugNode.m in Sources */,
FDE6D938229BF70F007F6716 /* REATransformNode.m in Sources */,
FDBB177A229BF0E700D1E455 /* REATransition.m in Sources */,
FDBB177E229BF0E700D1E455 /* RCTConvert+REATransition.m in Sources */,
FDBB1777229BF0DE00D1E455 /* REAModule.m in Sources */,
FDBB1779229BF0E700D1E455 /* REATransitionManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
58B511ED1A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
58B511EE1A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
58B511F01A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../../React/**",
"$(SRCROOT)/../../react-native/React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RNReanimated;
SKIP_INSTALL = YES;
};
name = Debug;
};
58B511F11A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../../React/**",
"$(SRCROOT)/../../react-native/React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RNReanimated;
SKIP_INSTALL = YES;
};
name = Release;
};
FDBB1775229BF04900D1E455 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = NZDV3AFAEG;
GCC_C_LANGUAGE_STANDARD = gnu11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 12.2;
};
name = Debug;
};
FDBB1776229BF04900D1E455 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = NZDV3AFAEG;
GCC_C_LANGUAGE_STANDARD = gnu11;
MTL_FAST_MATH = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 12.2;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNReanimated" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511ED1A9E6C8500147676 /* Debug */,
58B511EE1A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNReanimated" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511F01A9E6C8500147676 /* Debug */,
58B511F11A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
FDBB1774229BF04900D1E455 /* Build configuration list for PBXNativeTarget "RNReanimated-tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
FDBB1775229BF04900D1E455 /* Debug */,
FDBB1776229BF04900D1E455 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
}

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FDBB176D229BF04900D1E455"
BuildableName = "libRNReanimated-tvOS.a"
BlueprintName = "RNReanimated-tvOS"
ReferencedContainer = "container:RNReanimated.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FDBB176D229BF04900D1E455"
BuildableName = "libRNReanimated-tvOS.a"
BlueprintName = "RNReanimated-tvOS"
ReferencedContainer = "container:RNReanimated.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FDBB176D229BF04900D1E455"
BuildableName = "libRNReanimated-tvOS.a"
BlueprintName = "RNReanimated-tvOS"
ReferencedContainer = "container:RNReanimated.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,12 @@
#import <React/RCTConvert.h>
#import "REATransition.h"
@interface RCTConvert (REATransition)
+ (REATransitionType)REATransitionType:(id)json;
+ (REATransitionAnimationType)REATransitionAnimationType:(id)json;
+ (REATransitionInterpolationType)REATransitionInterpolationType:(id)json;
+ (REATransitionPropagationType)REATransitionPropagationType:(id)json;
@end

View File

@ -0,0 +1,37 @@
#import "RCTConvert+REATransition.h"
@implementation RCTConvert (REATransition)
RCT_ENUM_CONVERTER(REATransitionType, (@{
@"none": @(REATransitionTypeNone),
@"group": @(REATransitionTypeGroup),
@"in": @(REATransitionTypeIn),
@"out": @(REATransitionTypeOut),
@"change": @(REATransitionTypeChange),
}), REATransitionTypeNone, integerValue)
RCT_ENUM_CONVERTER(REATransitionAnimationType, (@{
@"none": @(REATransitionAnimationTypeNone),
@"fade": @(REATransitionAnimationTypeFade),
@"scale": @(REATransitionAnimationTypeScale),
@"slide-top": @(REATransitionAnimationTypeSlideTop),
@"slide-bottom": @(REATransitionAnimationTypeSlideBottom),
@"slide-right": @(REATransitionAnimationTypeSlideRight),
@"slide-left": @(REATransitionAnimationTypeSlideLeft)
}), REATransitionAnimationTypeNone, integerValue)
RCT_ENUM_CONVERTER(REATransitionInterpolationType, (@{
@"linear": @(REATransitionInterpolationLinear),
@"easeIn": @(REATransitionInterpolationEaseIn),
@"easeOut": @(REATransitionInterpolationEaseOut),
@"easeInOut": @(REATransitionInterpolationEaseInOut),
}), REATransitionInterpolationLinear, integerValue)
RCT_ENUM_CONVERTER(REATransitionPropagationType, (@{
@"none": @(REATransitionPropagationNone),
@"top": @(REATransitionPropagationTop),
@"bottom": @(REATransitionPropagationBottom),
@"left": @(REATransitionPropagationLeft),
@"right": @(REATransitionPropagationRight)
}), REATransitionPropagationNone, integerValue)
@end

View File

@ -0,0 +1,26 @@
#import "REATransition.h"
@interface REATransitionGroup : REATransition
@property (nonatomic) BOOL sequence;
@property (nonatomic) NSArray *transitions;
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAVisibilityTransition : REATransition
@property (nonatomic) REATransitionAnimationType animationType;
- (REATransitionAnimation *)appearView:(UIView*)view inParent:(UIView*)parent;
- (REATransitionAnimation *)disappearView:(UIView*)view fromParent:(UIView*)parent;
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAInTransition : REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAOutTransition : REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAChangeTransition : REATransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end

View File

@ -0,0 +1,308 @@
#import <React/RCTViewManager.h>
#import "REAAllTransitions.h"
#import "RCTConvert+REATransition.h"
@interface REASnapshotRemover : NSObject <CAAnimationDelegate>
@end
@implementation REASnapshotRemover {
UIView *_view;
}
- (instancetype)initWithView:(UIView *)view;
{
self = [super init];
if (self) {
_view = view;
}
return self;
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
[_view removeFromSuperview];
}
@end
@implementation REATransitionGroup
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super initWithConfig:config]) {
_sequence = [RCTConvert BOOL:config[@"sequence"]];
NSArray *transitions = [RCTConvert NSArray:config[@"transitions"]];
NSMutableArray<REATransition*> *inflated = [NSMutableArray new];
for (NSDictionary *transitionConfig in transitions) {
[inflated addObject:[REATransition inflate:transitionConfig]];
inflated.lastObject.parent = self;
}
_transitions = inflated;
}
return self;
}
- (instancetype)init
{
if (self = [super init]) {
_transitions = [NSMutableArray new];
}
return self;
}
- (NSArray<REATransitionAnimation *> *)animationsForTransitioning:(NSMutableDictionary<NSNumber *,REATransitionValues *> *)startValues
endValues:(NSMutableDictionary<NSNumber *,REATransitionValues *> *)endValues
forRoot:(UIView *)root
{
CFTimeInterval delay = self.delay;
NSMutableArray *animations = [NSMutableArray new];
for (REATransition *transition in _transitions) {
NSArray *subanims = [transition animationsForTransitioning:startValues endValues:endValues forRoot:root];
CFTimeInterval finishTime = CACurrentMediaTime();
for (REATransitionAnimation *anim in subanims) {
[anim delayBy:delay];
finishTime = MAX(finishTime, anim.finishTime);
}
[animations addObjectsFromArray:subanims];
if (_sequence) {
delay = finishTime - CACurrentMediaTime();
}
}
return animations;
}
@end
@implementation REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super initWithConfig:config]) {
_animationType = [RCTConvert REATransitionAnimationType:config[@"animation"]];
}
return self;
}
- (REATransitionAnimation *)appearView:(UIView *)view
inParent:(UIView *)parent
forRoot:(UIView *)root
{
return nil;
}
- (REATransitionAnimation *)disappearView:(UIView *)view
fromParent:(UIView *)parent
forRoot:(UIView *)root
{
return nil;
}
- (REATransitionAnimation *)animationForTransitioning:(REATransitionValues *)startValues
endValues:(REATransitionValues *)endValues
forRoot:(UIView *)root
{
BOOL isViewAppearing = (startValues == nil);
if (isViewAppearing && !IS_LAYOUT_ONLY(endValues.view)) {
NSNumber *parentKey = endValues.reactParent.reactTag;
REATransitionValues *parentStartValues = [self findStartValuesForKey:parentKey];
REATransitionValues *parentEndValues = [self findEndValuesForKey:parentKey];
BOOL isParentAppearing = (parentStartValues == nil && parentEndValues != nil);
if (!isParentAppearing) {
return [self appearView:endValues.view inParent:endValues.parent forRoot:root];
}
}
if (endValues == nil && !IS_LAYOUT_ONLY(startValues.view) && startValues.reactParent.window != nil) {
startValues.view.center = startValues.centerInReactParent;
return [self disappearView:startValues.view fromParent:startValues.reactParent forRoot:root];
}
return nil;
}
@end
@implementation REAInTransition
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super initWithConfig:config]) {
}
return self;
}
- (REATransitionAnimation *)appearView:(UIView *)view
inParent:(UIView *)parent
forRoot:(UIView *)root
{
CABasicAnimation *animation;
switch (self.animationType) {
case REATransitionAnimationTypeNone:
return nil;
case REATransitionAnimationTypeFade: {
CGFloat finalOpacity = view.layer.opacity;
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = @(0.0f);
animation.toValue = @(finalOpacity);
break;
}
case REATransitionAnimationTypeScale: {
CATransform3D finalTransform = view.layer.transform;
animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0, 0.0, 0)];
animation.toValue = [NSValue valueWithCATransform3D:finalTransform];
break;
}
case REATransitionAnimationTypeSlideTop:
case REATransitionAnimationTypeSlideBottom:
case REATransitionAnimationTypeSlideLeft:
case REATransitionAnimationTypeSlideRight: {
CGPoint finalPosition = view.layer.position;
CGPoint startPosition = finalPosition;
switch (self.animationType) {
case REATransitionAnimationTypeSlideTop:
startPosition.y -= root.frame.size.height;
break;
case REATransitionAnimationTypeSlideBottom:
startPosition.y += root.frame.size.height;
break;
case REATransitionAnimationTypeSlideLeft:
startPosition.x -= root.frame.size.width;
break;
case REATransitionAnimationTypeSlideRight:
startPosition.x += root.frame.size.width;
break;
}
animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = @(startPosition);
animation.toValue = @(finalPosition);
break;
}
}
animation.fillMode = kCAFillModeBackwards;
return [REATransitionAnimation transitionWithAnimation:animation layer:view.layer andKeyPath:animation.keyPath];
}
@end
@implementation REAOutTransition
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super initWithConfig:config]) {
}
return self;
}
- (REATransitionAnimation *)disappearView:(UIView *)view
fromParent:(UIView *)parent
forRoot:(UIView *)root
{
if (self.animationType == REATransitionAnimationTypeNone) {
return nil;
}
// Add view back to parent temporarily in order to take snapshot
[parent addSubview:view];
UIView *snapshotView = [view snapshotViewAfterScreenUpdates:NO];
[view removeFromSuperview];
snapshotView.frame = view.frame;
[parent addSubview:snapshotView];
CALayer *snapshot = snapshotView.layer;
CABasicAnimation *animation;
switch (self.animationType) {
case REATransitionAnimationTypeFade: {
CGFloat fromValue = snapshot.opacity;
snapshot.opacity = 0.0f;
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = @(fromValue);
animation.toValue = @(0.0f);
break;
}
case REATransitionAnimationTypeScale: {
CATransform3D fromValue = snapshot.transform;
snapshot.transform = CATransform3DMakeScale(0.001, 0.001, 0.001);
animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:fromValue];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.001, 0.001, 0.001)];
break;
}
case REATransitionAnimationTypeSlideTop:
case REATransitionAnimationTypeSlideBottom:
case REATransitionAnimationTypeSlideLeft:
case REATransitionAnimationTypeSlideRight: {
CGPoint startPosition = snapshot.position;
CGPoint finalPosition = startPosition;
switch (self.animationType) {
case REATransitionAnimationTypeSlideTop:
finalPosition.y -= root.frame.size.height;
break;
case REATransitionAnimationTypeSlideBottom:
finalPosition.y += root.frame.size.height;
break;
case REATransitionAnimationTypeSlideLeft:
finalPosition.x -= root.frame.size.width;
break;
case REATransitionAnimationTypeSlideRight:
finalPosition.x += root.frame.size.width;
break;
}
snapshot.position = finalPosition;
animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = @(startPosition);
animation.toValue = @(finalPosition);
break;
}
}
animation.fillMode = kCAFillModeBackwards;
animation.delegate = [[REASnapshotRemover alloc] initWithView:snapshotView];
return [REATransitionAnimation transitionWithAnimation:animation layer:snapshot andKeyPath:animation.keyPath];
}
@end
@implementation REAChangeTransition
- (REATransitionAnimation *)animationForTransitioning:(REATransitionValues *)startValues
endValues:(REATransitionValues *)endValues
forRoot:(UIView *)root
{
if (startValues == nil || endValues == nil || endValues.view.window == nil) {
return nil;
}
BOOL animatePosition = !CGPointEqualToPoint(startValues.center, endValues.center);
BOOL animateBounds = !CGRectEqualToRect(startValues.bounds, endValues.bounds);
if (!animatePosition && !animateBounds) {
return nil;
}
CALayer *layer = endValues.view.layer;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.fillMode = kCAFillModeBackwards;
NSMutableArray *animations = [NSMutableArray new];
if (animatePosition) {
CGPoint fromValue = layer.presentationLayer.position;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = [NSValue valueWithCGPoint:fromValue];
animation.toValue = [NSValue valueWithCGPoint:endValues.center];
[animations addObject:animation];
}
if (animateBounds) {
CGRect fromValue = layer.presentationLayer.bounds;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
animation.fromValue = [NSValue valueWithCGRect:fromValue];
animation.toValue = [NSValue valueWithCGRect:endValues.bounds];
[animations addObject:animation];
}
group.animations = animations;
return [REATransitionAnimation transitionWithAnimation:group layer:layer andKeyPath:nil];
}
@end

View File

@ -0,0 +1,64 @@
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <React/RCTView.h>
#import "REATransitionAnimation.h"
#import "REATransitionValues.h"
// TODO: fix below implementation
#define IS_LAYOUT_ONLY(view) ([view isKindOfClass:[RCTView class]] && view.backgroundColor == nil)
typedef NS_ENUM(NSInteger, REATransitionType) {
REATransitionTypeNone = 0,
REATransitionTypeGroup,
REATransitionTypeIn,
REATransitionTypeOut,
REATransitionTypeChange
};
typedef NS_ENUM(NSInteger, REATransitionAnimationType) {
REATransitionAnimationTypeNone = 0,
REATransitionAnimationTypeFade,
REATransitionAnimationTypeScale,
REATransitionAnimationTypeSlideTop,
REATransitionAnimationTypeSlideBottom,
REATransitionAnimationTypeSlideRight,
REATransitionAnimationTypeSlideLeft,
};
typedef NS_ENUM(NSInteger, REATransitionInterpolationType) {
REATransitionInterpolationLinear = 0,
REATransitionInterpolationEaseIn,
REATransitionInterpolationEaseOut,
REATransitionInterpolationEaseInOut,
};
typedef NS_ENUM(NSInteger, REATransitionPropagationType) {
REATransitionPropagationNone = 0,
REATransitionPropagationTop,
REATransitionPropagationBottom,
REATransitionPropagationLeft,
REATransitionPropagationRight,
};
@interface REATransition : NSObject
@property (nonatomic, weak) REATransition *parent;
@property (nonatomic) CFTimeInterval duration;
@property (nonatomic) CFTimeInterval delay;
@property (nonatomic) REATransitionInterpolationType interpolation;
@property (nonatomic) REATransitionPropagationType propagation;
- (instancetype)initWithConfig:(NSDictionary *)config;
- (CAMediaTimingFunction *)mediaTiming;
- (void)startCaptureInRoot:(UIView *)root;
- (void)playInRoot:(UIView *)root;
- (REATransitionValues *)findStartValuesForKey:(NSNumber *)key;
- (REATransitionValues *)findEndValuesForKey:(NSNumber *)key;
- (REATransitionAnimation *)animationForTransitioning:(REATransitionValues*)startValues
endValues:(REATransitionValues*)endValues
forRoot:(UIView *)root;
- (NSArray<REATransitionAnimation*> *)animationsForTransitioning:(NSMutableDictionary<NSNumber*, REATransitionValues*> *)startValues
endValues:(NSMutableDictionary<NSNumber*, REATransitionValues*> *)endValues
forRoot:(UIView *)root;
+ (REATransition *)inflate:(NSDictionary *)config;
@end

View File

@ -0,0 +1,208 @@
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <React/RCTConvert.h>
#import <React/RCTViewManager.h>
#import "REATransition.h"
#import "REATransitionValues.h"
#import "RCTConvert+REATransition.h"
#define DEFAULT_PROPAGATION_SPEED 3
@interface REATransitionGroup : REATransition
@property (nonatomic) BOOL sequence;
@property (nonatomic) NSArray *transitions;
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAVisibilityTransition : REATransition
@property (nonatomic) REATransitionAnimationType animationType;
- (REATransitionAnimation *)appearView:(UIView*)view inParent:(UIView*)parent;
- (REATransitionAnimation *)disappearView:(UIView*)view fromParent:(UIView*)parent;
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAInTransition : REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAOutTransition : REAVisibilityTransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@interface REAChangeTransition : REATransition
- (instancetype)initWithConfig:(NSDictionary *)config;
@end
@implementation REATransition {
__weak UIView *_root;
NSMutableDictionary<NSNumber*, REATransitionValues*> *_startValues;
NSMutableDictionary<NSNumber*, REATransitionValues*> *_endValues;
}
+ (REATransition *)inflate:(NSDictionary *)config
{
REATransitionType type = [RCTConvert REATransitionType:config[@"type"]];
switch (type) {
case REATransitionTypeGroup:
return [[REATransitionGroup alloc] initWithConfig:config];
case REATransitionTypeIn:
return [[REAInTransition alloc] initWithConfig:config];
case REATransitionTypeOut:
return [[REAOutTransition alloc] initWithConfig:config];
case REATransitionTypeChange:
return [[REAChangeTransition alloc] initWithConfig:config];
case REATransitionTypeNone:
default:
RCTLogError(@"Invalid transitioning type %@", config[@"type"]);
}
return nil;
}
- (instancetype)initWithConfig:(NSDictionary *)config
{
if (self = [super init]) {
_duration = [RCTConvert double:config[@"durationMs"]] / 1000.0;
_delay = [RCTConvert double:config[@"delayMs"]] / 1000.0;
_interpolation = [RCTConvert REATransitionInterpolationType:config[@"interpolation"]];
_propagation = [RCTConvert REATransitionPropagationType:config[@"propagation"]];
}
return self;
}
- (void)captureRecursiveIn:(UIView *)view to:(NSMutableDictionary<NSNumber*, REATransitionValues*> *)map forRoot:(UIView *)root
{
NSNumber *tag = view.reactTag;
if (tag != nil) {
map[tag] = [[REATransitionValues alloc] initWithView:view forRoot:root];
for (UIView *subview in view.reactSubviews) {
[self captureRecursiveIn:subview to:map forRoot:root];
}
}
}
- (void)startCaptureInRoot:(UIView *)root
{
_startValues = [NSMutableDictionary new];
[self captureRecursiveIn:root to:_startValues forRoot:root];
}
- (void)playInRoot:(UIView *)root
{
_endValues = [NSMutableDictionary new];
[self captureRecursiveIn:root to:_endValues forRoot:root];
NSArray *animations = [self animationsForTransitioning:_startValues
endValues:_endValues
forRoot:root];
for (REATransitionAnimation *animation in animations) {
[animation play];
}
_startValues = nil;
_endValues = nil;
}
- (REATransitionValues *)findStartValuesForKey:(NSNumber *)key
{
if (_parent != nil) {
return [_parent findStartValuesForKey:key];
}
return _startValues[key];
}
- (REATransitionValues *)findEndValuesForKey:(NSNumber *)key
{
if (_parent != nil) {
return [_parent findEndValuesForKey:key];
}
return _endValues[key];
}
- (CFTimeInterval)propagationDelayForTransitioning:(REATransitionValues *)startValues
endValues:(REATransitionValues *)endValues
forRoot:(UIView *)root
{
if (self.propagation == REATransitionPropagationNone) {
return 0.;
}
REATransitionValues *values = endValues;
if (values == nil) {
values = startValues;
}
double fraction = 0.;
switch (self.propagation) {
case REATransitionPropagationLeft:
fraction = values.centerRelativeToRoot.x / root.layer.bounds.size.width;
break;
case REATransitionPropagationRight:
fraction = 1. - values.centerRelativeToRoot.x / root.layer.bounds.size.width;
break;
case REATransitionPropagationTop:
fraction = values.centerRelativeToRoot.y / root.layer.bounds.size.height;
break;
case REATransitionPropagationBottom:
fraction = 1. - values.centerRelativeToRoot.y / root.layer.bounds.size.height;
break;
}
return _duration * MIN(MAX(0., fraction), 1.) / DEFAULT_PROPAGATION_SPEED;
}
- (CAMediaTimingFunction *)mediaTiming
{
switch (self.interpolation) {
case REATransitionInterpolationLinear:
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
case REATransitionInterpolationEaseIn:
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
case REATransitionInterpolationEaseOut:
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
case REATransitionInterpolationEaseInOut:
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
}
}
- (REATransitionAnimation *)animationForTransitioning:(REATransitionValues *)startValues
endValues:(REATransitionValues *)endValues
forRoot:(UIView *)root
{
return nil;
}
- (NSArray<REATransitionAnimation*> *)animationsForTransitioning:(NSMutableDictionary<NSNumber *,REATransitionValues *> *)startValues
endValues:(NSMutableDictionary<NSNumber *,REATransitionValues *> *)endValues
forRoot:(UIView *)root
{
NSMutableArray *animations = [NSMutableArray new];
[startValues enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, REATransitionValues *startValue, BOOL *stop) {
REATransitionValues *endValue = endValues[key];
REATransitionAnimation *animation = [self animationForTransitioning:startValue endValues:endValue forRoot:root];
if (animation != nil) {
animation.animation.timingFunction = self.mediaTiming;
animation.animation.duration = self.duration;
[animation delayBy:self.delay];
CFTimeInterval propagationDelay = [self propagationDelayForTransitioning:startValue endValues:endValue forRoot:root];
[animation delayBy:propagationDelay];
// animation.animation.duration -= propagationDelay;
[animations addObject:animation];
}
}];
[endValues enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, REATransitionValues *endValue, BOOL *stop) {
if (startValues[key] == nil) {
REATransitionAnimation *animation = [self animationForTransitioning:nil endValues:endValue forRoot:root];
if (animation != nil) {
animation.animation.timingFunction = self.mediaTiming;
animation.animation.duration = self.duration;
[animation delayBy:self.delay];
CFTimeInterval propagationDelay = [self propagationDelayForTransitioning:nil endValues:endValue forRoot:root];
[animation delayBy:propagationDelay];
// animation.animation.duration -= propagationDelay;
[animations addObject:animation];
}
}
}];
return animations;
}
@end

View File

@ -0,0 +1,17 @@
#import <Foundation/Foundation.h>
@interface REATransitionAnimation : NSObject
@property (nonatomic) CAAnimation *animation;
@property (nonatomic) CALayer *layer;
@property (nonatomic) NSString *keyPath;
+ (REATransitionAnimation *)transitionWithAnimation:(CAAnimation *)animation
layer:(CALayer *)layer
andKeyPath:(NSString*)keyPath;
- (void)play;
- (void)delayBy:(CFTimeInterval)delay;
- (CFTimeInterval)finishTime;
- (CFTimeInterval)duration;
@end

View File

@ -0,0 +1,81 @@
#import <UIKit/UIKit.h>
#import "REATransitionAnimation.h"
#define DEFAULT_DURATION 0.25
#if TARGET_IPHONE_SIMULATOR
// Based on https://stackoverflow.com/a/13307674
float UIAnimationDragCoefficient(void);
#endif
CGFloat SimAnimationDragCoefficient()
{
#if TARGET_IPHONE_SIMULATOR
if (NSClassFromString(@"XCTest") != nil) {
// UIAnimationDragCoefficient is 10.0 in tests for some reason, but
// we need it to be 1.0.
return 1.0;
} else {
return (CGFloat)UIAnimationDragCoefficient();
}
#else
return 1.0;
#endif
}
@implementation REATransitionAnimation {
NSTimeInterval _delay;
}
+ (REATransitionAnimation *)transitionWithAnimation:(CAAnimation *)animation
layer:(CALayer *)layer
andKeyPath:(NSString*)keyPath;
{
REATransitionAnimation *anim = [REATransitionAnimation new];
anim.animation = animation;
anim.layer = layer;
anim.keyPath = keyPath;
return anim;
}
- (void)play
{
/*
CACurrentMediaTime introduces some kind of delay even if _delay is set to 0
it calls mach_absolute_time() which is based on the last time the device booted
which might cause the delay
*/
if (_delay > 0){
_animation.beginTime = CACurrentMediaTime() + _delay * SimAnimationDragCoefficient();
}
_animation.duration = self.duration * SimAnimationDragCoefficient();
[_layer addAnimation:_animation forKey:_keyPath];
}
- (void)delayBy:(CFTimeInterval)delay
{
if (delay <= 0) {
return;
}
_delay += delay;
}
- (CFTimeInterval)duration
{
if (_animation.duration == 0) {
return DEFAULT_DURATION;
}
return _animation.duration;
}
- (CFTimeInterval)finishTime
{
if (_animation.beginTime == 0) {
return CACurrentMediaTime() + self.duration + _delay;
}
return _animation.beginTime + self.duration + _delay;
}
@end

View File

@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
#import <React/RCTUIManager.h>
@interface REATransitionManager : NSObject
- (instancetype)initWithUIManager:(RCTUIManager *)uiManager;
- (void)animateNextTransitionInRoot:(nonnull NSNumber *)reactTag withConfig:(NSDictionary *)config;
@end

View File

@ -0,0 +1,62 @@
#import "REATransitionManager.h"
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerObserverCoordinator.h>
#import "REATransition.h"
@interface REATransitionManager () <RCTUIManagerObserver>
@end
@implementation REATransitionManager {
REATransition *_pendingTransition;
UIView *_pendingTransitionRoot;
RCTUIManager *_uiManager;
}
- (instancetype)initWithUIManager:(id)uiManager
{
if (self = [super init]) {
_uiManager = uiManager;
}
return self;
}
- (void)beginTransition:(REATransition *)transition forView:(UIView *)view
{
RCTAssertMainQueue();
if (_pendingTransition != nil) {
return;
}
_pendingTransition = transition;
_pendingTransitionRoot = view;
[transition startCaptureInRoot:view];
}
- (void)uiManagerWillPerformMounting:(RCTUIManager *)manager
{
[manager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
[_pendingTransition playInRoot:_pendingTransitionRoot];
_pendingTransitionRoot = nil;
_pendingTransition = nil;
}];
}
- (void)animateNextTransitionInRoot:(NSNumber *)reactTag withConfig:(NSDictionary *)config
{
[_uiManager.observerCoordinator addObserver:self];
[_uiManager prependUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
UIView *view = viewRegistry[reactTag];
NSArray *transitionConfigs = [RCTConvert NSArray:config[@"transitions"]];
for (id transitionConfig in transitionConfigs) {
REATransition *transition = [REATransition inflate:transitionConfig];
[self beginTransition:transition forView:view];
}
}];
__weak id weakSelf = self;
[_uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
[uiManager.observerCoordinator removeObserver:weakSelf];
}];
}
@end

View File

@ -0,0 +1,15 @@
#import <UIKit/UIKit.h>
@interface REATransitionValues : NSObject
@property (nonatomic) CGPoint center;
@property (nonatomic) CGRect bounds;
@property (nonatomic) CGPoint centerRelativeToRoot;
@property (nonatomic, retain) UIView *view;
@property (nonatomic, retain) UIView *parent;
@property (nonatomic, retain) UIView *reactParent;
@property (nonatomic) CGPoint centerInReactParent;
- (instancetype)initWithView:(UIView *)view forRoot:(UIView *)root;
@end

View File

@ -0,0 +1,26 @@
#import <React/RCTView.h>
#import <React/RCTViewManager.h>
#import "REATransition.h"
#import "REATransitionValues.h"
@implementation REATransitionValues
- (instancetype)initWithView:(UIView *)view forRoot:(UIView *)root
{
if (self = [super init]) {
_view = view;
_parent = view.superview;
_reactParent = view.reactSuperview;
while (_reactParent != nil && _reactParent != root && IS_LAYOUT_ONLY(_reactParent)) {
_reactParent = _reactParent.reactSuperview;
}
_center = view.center;
_bounds = view.bounds;
_centerRelativeToRoot = [_parent convertPoint:_center toView:root];
_centerInReactParent = [_parent convertPoint:_center toView:_reactParent];
}
return self;
}
@end

View File

@ -0,0 +1,181 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _exportNames = {
decay: true,
timing: true,
spring: true,
Easing: true,
Clock: true,
Value: true,
Node: true,
Transition: true,
Transitioning: true,
createTransitioningComponent: true,
SpringUtils: true,
useValue: true
};
Object.defineProperty(exports, "Easing", {
enumerable: true,
get: function get() {
return _Easing.default;
}
});
Object.defineProperty(exports, "Clock", {
enumerable: true,
get: function get() {
return _AnimatedClock.default;
}
});
Object.defineProperty(exports, "Value", {
enumerable: true,
get: function get() {
return _AnimatedValue.default;
}
});
Object.defineProperty(exports, "Node", {
enumerable: true,
get: function get() {
return _AnimatedNode.default;
}
});
Object.defineProperty(exports, "Transition", {
enumerable: true,
get: function get() {
return _Transitioning.Transition;
}
});
Object.defineProperty(exports, "Transitioning", {
enumerable: true,
get: function get() {
return _Transitioning.Transitioning;
}
});
Object.defineProperty(exports, "createTransitioningComponent", {
enumerable: true,
get: function get() {
return _Transitioning.createTransitioningComponent;
}
});
Object.defineProperty(exports, "SpringUtils", {
enumerable: true,
get: function get() {
return _SpringUtils.default;
}
});
Object.defineProperty(exports, "useValue", {
enumerable: true,
get: function get() {
return _useValue.default;
}
});
exports.spring = exports.timing = exports.decay = exports.default = void 0;
var _reactNative = require("react-native");
var _Easing = _interopRequireDefault(require("./Easing"));
var _AnimatedClock = _interopRequireDefault(require("./core/AnimatedClock"));
var _AnimatedValue = _interopRequireDefault(require("./core/AnimatedValue"));
var _AnimatedNode = _interopRequireDefault(require("./core/AnimatedNode"));
var _AnimatedCode = _interopRequireDefault(require("./core/AnimatedCode"));
var base = _interopRequireWildcard(require("./base"));
Object.keys(base).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function get() {
return base[key];
}
});
});
var derived = _interopRequireWildcard(require("./derived"));
Object.keys(derived).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function get() {
return derived[key];
}
});
});
var _createAnimatedComponent = _interopRequireDefault(require("./createAnimatedComponent"));
var _decay = _interopRequireDefault(require("./animations/decay"));
var _timing = _interopRequireDefault(require("./animations/timing"));
var _spring = _interopRequireDefault(require("./animations/spring"));
var _Animation = _interopRequireDefault(require("./animations/Animation"));
var _ConfigHelper = require("./ConfigHelper");
var _backwardCompatibleAnimWrapper = _interopRequireDefault(require("./animations/backwardCompatibleAnimWrapper"));
var _Transitioning = require("./Transitioning");
var _SpringUtils = _interopRequireDefault(require("./animations/SpringUtils"));
var _useValue = _interopRequireDefault(require("./useValue"));
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
const decayWrapper = (0, _backwardCompatibleAnimWrapper.default)(_decay.default, _Animation.default.decayDefaultState);
exports.decay = decayWrapper;
const timingWrapper = (0, _backwardCompatibleAnimWrapper.default)(_timing.default, _Animation.default.timingDefaultState);
exports.timing = timingWrapper;
const springWrapper = (0, _backwardCompatibleAnimWrapper.default)(_spring.default, _Animation.default.springDefaultState);
exports.spring = springWrapper;
const Animated = _objectSpread(_objectSpread(_objectSpread({
// components
View: (0, _createAnimatedComponent.default)(_reactNative.View),
Text: (0, _createAnimatedComponent.default)(_reactNative.Text),
Image: (0, _createAnimatedComponent.default)(_reactNative.Image),
ScrollView: (0, _createAnimatedComponent.default)(_reactNative.ScrollView),
Code: _AnimatedCode.default,
createAnimatedComponent: _createAnimatedComponent.default,
// classes
Clock: _AnimatedClock.default,
Value: _AnimatedValue.default,
Node: _AnimatedNode.default
}, base), derived), {}, {
// animations
decay: decayWrapper,
timing: timingWrapper,
spring: springWrapper,
SpringUtils: _SpringUtils.default,
// configuration
addWhitelistedNativeProps: _ConfigHelper.addWhitelistedNativeProps,
addWhitelistedUIProps: _ConfigHelper.addWhitelistedUIProps,
// hooks
useValue: _useValue.default
});
var _default = Animated; // operations
exports.default = _default;
//# sourceMappingURL=Animated.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["Animated.js"],"names":["decayWrapper","decay","Animation","decayDefaultState","timingWrapper","timing","timingDefaultState","springWrapper","spring","springDefaultState","Animated","View","Text","Image","ScrollView","Code","AnimatedCode","createAnimatedComponent","Clock","AnimatedClock","Value","AnimatedValue","Node","AnimatedNode","base","derived","SpringUtils","addWhitelistedNativeProps","addWhitelistedUIProps","useValue"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AAmEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAlEA;;AAmEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAlEA;;AACA;;AACA;;AACA;;AACA;;AACA;;AAIA;;AACA;;AAKA;;AACA;;;;;;;;;;;;;;AAEA,MAAMA,YAAY,GAAG,4CACnBC,cADmB,EAEnBC,mBAAUC,iBAFS,CAArB;;AAIA,MAAMC,aAAa,GAAG,4CACpBC,eADoB,EAEpBH,mBAAUI,kBAFU,CAAtB;;AAIA,MAAMC,aAAa,GAAG,4CACpBC,eADoB,EAEpBN,mBAAUO,kBAFU,CAAtB;;;AAIA,MAAMC,QAAQ;AACZ;AACAC,EAAAA,IAAI,EAAE,sCAAwBA,iBAAxB,CAFM;AAGZC,EAAAA,IAAI,EAAE,sCAAwBA,iBAAxB,CAHM;AAIZC,EAAAA,KAAK,EAAE,sCAAwBA,kBAAxB,CAJK;AAKZC,EAAAA,UAAU,EAAE,sCAAwBA,uBAAxB,CALA;AAMZC,EAAAA,IAAI,EAAEC,qBANM;AAOZC,EAAAA,uBAAuB,EAAvBA,gCAPY;AASZ;AACAC,EAAAA,KAAK,EAAEC,sBAVK;AAWZC,EAAAA,KAAK,EAAEC,sBAXK;AAYZC,EAAAA,IAAI,EAAEC;AAZM,GAeTC,IAfS,GAgBTC,OAhBS;AAkBZ;AACAxB,EAAAA,KAAK,EAAED,YAnBK;AAoBZK,EAAAA,MAAM,EAAED,aApBI;AAqBZI,EAAAA,MAAM,EAAED,aArBI;AAsBZmB,EAAAA,WAAW,EAAXA,oBAtBY;AAwBZ;AACAC,EAAAA,yBAAyB,EAAzBA,uCAzBY;AA0BZC,EAAAA,qBAAqB,EAArBA,mCA1BY;AA4BZ;AACAC,EAAAA,QAAQ,EAARA;AA7BY,EAAd;;eAgCenB,Q,EAEf","sourcesContent":["import { Image, ScrollView, Text, View } from 'react-native';\nimport Easing from './Easing';\nimport AnimatedClock from './core/AnimatedClock';\nimport AnimatedValue from './core/AnimatedValue';\nimport AnimatedNode from './core/AnimatedNode';\nimport AnimatedCode from './core/AnimatedCode';\nimport * as base from './base';\nimport * as derived from './derived';\nimport createAnimatedComponent from './createAnimatedComponent';\nimport decay from './animations/decay';\nimport timing from './animations/timing';\nimport spring from './animations/spring';\nimport Animation from './animations/Animation';\nimport {\n addWhitelistedNativeProps,\n addWhitelistedUIProps,\n} from './ConfigHelper';\nimport backwardCompatibleAnimWrapper from './animations/backwardCompatibleAnimWrapper';\nimport {\n Transition,\n Transitioning,\n createTransitioningComponent,\n} from './Transitioning';\nimport SpringUtils from './animations/SpringUtils';\nimport useValue from './useValue';\n\nconst decayWrapper = backwardCompatibleAnimWrapper(\n decay,\n Animation.decayDefaultState\n);\nconst timingWrapper = backwardCompatibleAnimWrapper(\n timing,\n Animation.timingDefaultState\n);\nconst springWrapper = backwardCompatibleAnimWrapper(\n spring,\n Animation.springDefaultState\n);\nconst Animated = {\n // components\n View: createAnimatedComponent(View),\n Text: createAnimatedComponent(Text),\n Image: createAnimatedComponent(Image),\n ScrollView: createAnimatedComponent(ScrollView),\n Code: AnimatedCode,\n createAnimatedComponent,\n\n // classes\n Clock: AnimatedClock,\n Value: AnimatedValue,\n Node: AnimatedNode,\n\n // operations\n ...base,\n ...derived,\n\n // animations\n decay: decayWrapper,\n timing: timingWrapper,\n spring: springWrapper,\n SpringUtils,\n\n // configuration\n addWhitelistedNativeProps,\n addWhitelistedUIProps,\n\n // hooks\n useValue,\n};\n\nexport default Animated;\n\n// operations\nexport * from './base';\nexport * from './derived';\n\nexport {\n Easing,\n Transitioning,\n Transition,\n createTransitioningComponent,\n // classes\n AnimatedClock as Clock,\n AnimatedValue as Value,\n AnimatedNode as Node,\n // animations\n decayWrapper as decay,\n timingWrapper as timing,\n springWrapper as spring,\n SpringUtils,\n // hooks\n useValue,\n};\n"]}

View File

@ -0,0 +1,142 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addWhitelistedNativeProps = addWhitelistedNativeProps;
exports.addWhitelistedUIProps = addWhitelistedUIProps;
var _ReanimatedModule = _interopRequireDefault(require("./ReanimatedModule"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Styles allowed to be direcly updated in UI thread
*/
let UI_THREAD_PROPS_WHITELIST = {
opacity: true,
transform: true,
/* colors */
backgroundColor: true,
borderRightColor: true,
borderBottomColor: true,
borderColor: true,
borderEndColor: true,
borderLeftColor: true,
borderStartColor: true,
borderTopColor: true,
/* ios styles */
shadowOpacity: true,
shadowRadius: true,
/* legacy android transform properties */
scaleX: true,
scaleY: true,
translateX: true,
translateY: true
};
/**
* Whitelist of view props that can be updated in native thread via UIManagerModule
*/
let NATIVE_THREAD_PROPS_WHITELIST = {
borderBottomWidth: true,
borderEndWidth: true,
borderLeftWidth: true,
borderRightWidth: true,
borderStartWidth: true,
borderTopWidth: true,
borderWidth: true,
bottom: true,
flex: true,
flexGrow: true,
flexShrink: true,
height: true,
left: true,
margin: true,
marginBottom: true,
marginEnd: true,
marginHorizontal: true,
marginLeft: true,
marginRight: true,
marginStart: true,
marginTop: true,
marginVertical: true,
maxHeight: true,
maxWidth: true,
minHeight: true,
minWidth: true,
padding: true,
paddingBottom: true,
paddingEnd: true,
paddingHorizontal: true,
paddingLeft: true,
paddingRight: true,
paddingStart: true,
paddingTop: true,
paddingVertical: true,
right: true,
start: true,
top: true,
width: true,
zIndex: true,
borderBottomEndRadius: true,
borderBottomLeftRadius: true,
borderBottomRightRadius: true,
borderBottomStartRadius: true,
borderRadius: true,
borderTopEndRadius: true,
borderTopLeftRadius: true,
borderTopRightRadius: true,
borderTopStartRadius: true,
opacity: true,
elevation: true,
fontSize: true,
lineHeight: true,
textShadowRadius: true,
letterSpacing: true,
/* strings */
display: true,
backfaceVisibility: true,
overflow: true,
resizeMode: true,
fontStyle: true,
fontWeight: true,
textAlign: true,
textDecorationLine: true,
fontFamily: true,
textAlignVertical: true,
fontVariant: true,
textDecorationStyle: true,
textTransform: true,
writingDirection: true,
/* text color */
color: true
};
function configureProps() {
_ReanimatedModule.default.configureProps(Object.keys(NATIVE_THREAD_PROPS_WHITELIST), Object.keys(UI_THREAD_PROPS_WHITELIST));
}
function addWhitelistedNativeProps(props) {
NATIVE_THREAD_PROPS_WHITELIST = _objectSpread(_objectSpread({}, NATIVE_THREAD_PROPS_WHITELIST), props);
configureProps();
}
function addWhitelistedUIProps(props) {
UI_THREAD_PROPS_WHITELIST = _objectSpread(_objectSpread({}, UI_THREAD_PROPS_WHITELIST), props);
configureProps();
}
configureProps();
//# sourceMappingURL=ConfigHelper.js.map

Some files were not shown because too many files have changed in this diff Show More