Skip to content

Commit

Permalink
Layout Reanimation (software-mansion#2058)
Browse files Browse the repository at this point in the history
Introduce the very first version of Layout Animations in Reanimated

Co-authored-by: Krzysztof Piaskowy <krzychu2956@gmail.com>
  • Loading branch information
Szymon20000 and piaskowyk authored May 28, 2021
1 parent b1fd5e3 commit 9a71f34
Show file tree
Hide file tree
Showing 70 changed files with 3,680 additions and 119 deletions.
36 changes: 36 additions & 0 deletions Common/cpp/LayoutAnimations/LayoutAnimationsProxy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "LayoutAnimationsProxy.h"
#include "MutableValue.h"
#include "ValueWrapper.h"
#include "ShareableValue.h"
#include "FrozenObject.h"

namespace reanimated {

const long long idOffset = 1e9;

LayoutAnimationsProxy::LayoutAnimationsProxy(std::function<void(int, jsi::Object newProps)> _notifyAboutProgress, std::function<void(int, bool)> _notifyAboutEnd): notifyAboutProgress(std::move(_notifyAboutProgress)), notifyAboutEnd(std::move(_notifyAboutEnd)) {
}

void LayoutAnimationsProxy::startObserving(int tag, std::shared_ptr<MutableValue> sv, jsi::Runtime &rt) {
observedValues[tag] = sv;
sv->addListener(tag + idOffset, [sv, tag, this, &rt](){
std::shared_ptr<FrozenObject> newValue = ValueWrapper::asFrozenObject(sv->value->valueContainer);
this->notifyAboutProgress(tag, newValue->shallowClone(rt));
});
}

void LayoutAnimationsProxy::stopObserving(int tag, bool finished) {
if (observedValues.count(tag) == 0) {
return;
}
std::shared_ptr<MutableValue> sv = observedValues[tag];
sv->removeListener(tag + idOffset);
observedValues.erase(tag);
this->notifyAboutEnd(tag, !finished);
}

void LayoutAnimationsProxy::notifyAboutCancellation(int tag) {
this->notifyAboutEnd(tag, false);
}

}
14 changes: 9 additions & 5 deletions Common/cpp/NativeModules/NativeReanimatedModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ std::vector<std::shared_ptr<MutableValue>> extractMutablesFromArray(jsi::Runtime

NativeReanimatedModule::NativeReanimatedModule(std::shared_ptr<CallInvoker> jsInvoker,
std::shared_ptr<Scheduler> scheduler,
std::unique_ptr<jsi::Runtime> rt,
std::shared_ptr<jsi::Runtime> rt,
std::shared_ptr<ErrorHandler> errorHandler,
std::function<jsi::Value(jsi::Runtime &, const int, const jsi::String &)> propObtainer,
PlatformDepMethodsHolder platformDepMethodsHolder) :
NativeReanimatedModuleSpec(jsInvoker),
RuntimeManager(std::move(rt), errorHandler, scheduler),
std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy,
PlatformDepMethodsHolder platformDepMethodsHolder) : NativeReanimatedModuleSpec(jsInvoker),
RuntimeManager(rt, errorHandler, scheduler),
mapperRegistry(std::make_shared<MapperRegistry>()),
eventHandlerRegistry(std::make_shared<EventHandlerRegistry>()),
requestRender(platformDepMethodsHolder.requestRender),
Expand All @@ -74,12 +74,16 @@ NativeReanimatedModule::NativeReanimatedModule(std::shared_ptr<CallInvoker> jsIn
frameCallbacks.push_back(callback);
maybeRequestRender();
};

this->layoutAnimationsProxy = layoutAnimationsProxy;

RuntimeDecorator::decorateUIRuntime(*runtime,
platformDepMethodsHolder.updaterFunction,
requestAnimationFrame,
platformDepMethodsHolder.scrollToFunction,
platformDepMethodsHolder.measuringFunction,
platformDepMethodsHolder.getCurrentTime);
platformDepMethodsHolder.getCurrentTime,
layoutAnimationsProxy);
}

void NativeReanimatedModule::installCoreFunctions(jsi::Runtime &rt, const jsi::Value &valueSetter)
Expand Down
4 changes: 3 additions & 1 deletion Common/cpp/SharedItems/MutableValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ void MutableValue::set(jsi::Runtime &rt, const jsi::PropNameID &name, const jsi:
animation = getWeakRef(rt);
}
*animation.lock() = jsi::Value(rt, newValue);
} else if (propName == "_value") {
auto setter = std::make_shared<MutableValueSetterProxy>(shared_from_this());
setter->set(rt, jsi::PropNameID::forAscii(rt, "_value"), newValue);
}
} else {
// React-JS Thread or another threaded Runtime.
Expand All @@ -66,7 +69,6 @@ void MutableValue::set(jsi::Runtime &rt, const jsi::PropNameID &name, const jsi:
});
}
}

}

jsi::Value MutableValue::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
Expand Down
39 changes: 38 additions & 1 deletion Common/cpp/Tools/RuntimeDecorator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include "ReanimatedHiddenHeaders.h"
#include <unordered_map>
#include <memory>
#include "MutableValue.h"
#include "LayoutAnimationsProxy.h"

namespace reanimated {

Expand Down Expand Up @@ -65,7 +67,8 @@ void RuntimeDecorator::decorateUIRuntime(jsi::Runtime &rt,
RequestFrameFunction requestFrame,
ScrollToFunction scrollTo,
MeasuringFunction measure,
TimeProviderFunction getCurrentTime) {
TimeProviderFunction getCurrentTime,
std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy) {
RuntimeDecorator::decorateRuntime(rt, "UI");
rt.global().setProperty(rt, "_UI", jsi::Value(true));

Expand Down Expand Up @@ -146,6 +149,40 @@ void RuntimeDecorator::decorateUIRuntime(jsi::Runtime &rt,

rt.global().setProperty(rt, "_frameTimestamp", jsi::Value::undefined());
rt.global().setProperty(rt, "_eventTimestamp", jsi::Value::undefined());

// layout animation
std::weak_ptr<LayoutAnimationsProxy> layoutProxy = layoutAnimationsProxy;
auto clb7 = [layoutProxy](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
std::shared_ptr<LayoutAnimationsProxy> proxy = layoutProxy.lock();
if (layoutProxy.expired()) {
return jsi::Value::undefined();
}
proxy->startObserving(args[0].asNumber(), args[1].asObject(rt).getHostObject<MutableValue>(rt), rt);
return jsi::Value::undefined();
};
jsi::Value _startObservingProgress = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_startObservingProgress"), 0, clb7);
rt.global().setProperty(rt, "_startObservingProgress", _startObservingProgress);

auto clb8 = [layoutProxy](
jsi::Runtime &rt,
const jsi::Value &thisValue,
const jsi::Value *args,
size_t count
) -> jsi::Value {
std::shared_ptr<LayoutAnimationsProxy> proxy = layoutProxy.lock();
if (layoutProxy.expired()) {
return jsi::Value::undefined();
}
proxy->stopObserving(args[0].asNumber(), args[1].getBool());
return jsi::Value::undefined();
};
jsi::Value _stopObservingProgress = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_stopObservingProgress"), 0, clb8);
rt.global().setProperty(rt, "_stopObservingProgress", _stopObservingProgress);
}

bool RuntimeDecorator::isUIRuntime(jsi::Runtime& rt) {
Expand Down
31 changes: 31 additions & 0 deletions Common/cpp/headers/LayoutAnimations/LayoutAnimationsProxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <stdio.h>
#include <memory>
#include <functional>
#include <map>
#include <jsi/jsi.h>

namespace reanimated {

using namespace facebook;

class MutableValue;

class LayoutAnimationsProxy {

public:
LayoutAnimationsProxy(std::function<void(int, jsi::Object newProps)> _notifyAboutProgress, std::function<void(int, bool)> _notifyAboutEnd);

void startObserving(int tag, std::shared_ptr<MutableValue> sv, jsi::Runtime &rt);
void stopObserving(int tag, bool finished);
void notifyAboutCancellation(int tag);

private:
std::function<void(int, jsi::Object newProps)> notifyAboutProgress;
std::function<void(int, bool)> notifyAboutEnd;
std::map<int, std::shared_ptr<MutableValue>> observedValues;
};

}

5 changes: 4 additions & 1 deletion Common/cpp/headers/NativeModules/NativeReanimatedModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <memory>
#include <vector>
#include "RuntimeManager.h"
#include "LayoutAnimationsProxy.h"

namespace reanimated
{
Expand All @@ -28,9 +29,10 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec, public Runtime
public:
NativeReanimatedModule(std::shared_ptr<CallInvoker> jsInvoker,
std::shared_ptr<Scheduler> scheduler,
std::unique_ptr<jsi::Runtime> rt,
std::shared_ptr<jsi::Runtime> rt,
std::shared_ptr<ErrorHandler> errorHandler,
std::function<jsi::Value(jsi::Runtime &, const int, const jsi::String &)> propObtainer,
std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy,
PlatformDepMethodsHolder platformDepMethodsHolder);

virtual ~NativeReanimatedModule();
Expand Down Expand Up @@ -62,6 +64,7 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec, public Runtime
std::vector<FrameCallback> frameCallbacks;
bool renderRequested = false;
std::function<jsi::Value(jsi::Runtime &, const int, const jsi::String &)> propObtainer;
std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy;
};

} // namespace reanimated
2 changes: 2 additions & 0 deletions Common/cpp/headers/SharedItems/MutableValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <map>
#include "JSIStoreValueUser.h"
#include "RuntimeManager.h"
#include "LayoutAnimationsProxy.h"

using namespace facebook;

Expand All @@ -16,6 +17,7 @@ class MutableValue : public jsi::HostObject, public std::enable_shared_from_this
private:
friend MutableValueSetterProxy;
RuntimeManager *runtimeManager;
friend LayoutAnimationsProxy;
std::mutex readWriteMutex;
std::shared_ptr<ShareableValue> value;
std::weak_ptr<jsi::Value> animation;
Expand Down
6 changes: 3 additions & 3 deletions Common/cpp/headers/SharedItems/RuntimeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ using namespace facebook;
*/
class RuntimeManager {
public:
RuntimeManager(std::unique_ptr<jsi::Runtime>&& runtime,
RuntimeManager(std::shared_ptr<jsi::Runtime> runtime,
std::shared_ptr<ErrorHandler> errorHandler,
std::shared_ptr<Scheduler> scheduler): runtime(std::move(runtime)), errorHandler(errorHandler), scheduler(scheduler), workletsCache(std::make_unique<WorkletsCache>()) { }
std::shared_ptr<Scheduler> scheduler): runtime(runtime), errorHandler(errorHandler), scheduler(scheduler), workletsCache(std::make_unique<WorkletsCache>()) { }
public:
/**
Holds the jsi::Function worklet that is responsible for updating values in JS.
Expand All @@ -28,7 +28,7 @@ class RuntimeManager {
/**
Holds the jsi::Runtime this RuntimeManager is managing.
*/
std::unique_ptr<jsi::Runtime> runtime;
std::shared_ptr<jsi::Runtime> runtime;
/**
Holds the error handler that will be invoked when any kind of error occurs.
*/
Expand Down
2 changes: 2 additions & 0 deletions Common/cpp/headers/SharedItems/ShareableValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <mutex>
#include <unordered_map>
#include <jsi/jsi.h>
#include "LayoutAnimationsProxy.h"

using namespace facebook;

Expand All @@ -19,6 +20,7 @@ namespace reanimated {
class ShareableValue: public std::enable_shared_from_this<ShareableValue>, public StoreUser {
friend WorkletsCache;
friend FrozenObject;
friend LayoutAnimationsProxy;
friend void extractMutables(jsi::Runtime &rt,
std::shared_ptr<ShareableValue> sv,
std::vector<std::shared_ptr<MutableValue>> &res);
Expand Down
4 changes: 3 additions & 1 deletion Common/cpp/headers/Tools/RuntimeDecorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "PlatformDepMethodsHolder.h"
#include <stdio.h>
#include <jsi/jsi.h>
#include "LayoutAnimationsProxy.h"

using namespace facebook;

Expand All @@ -18,7 +19,8 @@ class RuntimeDecorator {
RequestFrameFunction requestFrame,
ScrollToFunction scrollTo,
MeasuringFunction measure,
TimeProviderFunction getCurrentTime);
TimeProviderFunction getCurrentTime,
std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy);

/**
Returns true if the given Runtime is the Reanimated UI-Thread Runtime.
Expand Down
2 changes: 1 addition & 1 deletion Example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de
FBLazyVector: 49cbe4b43e445b06bf29199b6ad2057649e4c8f5
FBReactNativeSpec: 6d46d7c05350e10b3e711c32af90bb188b792a56
FBReactNativeSpec: a231a5702f05925855ad8d6449930e1a024bf38b
glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62
RCT-Folly: ec7a233ccc97cc556cf7237f0db1ff65b986f27c
RCTRequired: 2f8cb5b7533219bf4218a045f92768129cf7050a
Expand Down
Loading

0 comments on commit 9a71f34

Please sign in to comment.