1 #include "MutableValue.h"
2 #include "RuntimeDecorator.h"
3 #include "RuntimeManager.h"
4 #include "ShareableValue.h"
5 #include "SharedParent.h"
6
7 #include <string>
8
9 namespace reanimated {
10
setValue(jsi::Runtime & rt,const jsi::Value & newValue)11 void MutableValue::setValue(jsi::Runtime &rt, const jsi::Value &newValue) {
12 std::lock_guard<std::mutex> lock(readWriteMutex);
13 value = ShareableValue::adapt(rt, newValue, runtimeManager);
14
15 std::shared_ptr<MutableValue> thiz = shared_from_this();
16 auto notifyListeners = [thiz]() {
17 for (auto listener : thiz->listeners) {
18 listener.second();
19 }
20 };
21 if (RuntimeDecorator::isUIRuntime(rt)) {
22 notifyListeners();
23 } else {
24 runtimeManager->scheduler->scheduleOnUI(
25 [notifyListeners] { notifyListeners(); });
26 }
27 }
28
getValue(jsi::Runtime & rt)29 jsi::Value MutableValue::getValue(jsi::Runtime &rt) {
30 std::lock_guard<std::mutex> lock(readWriteMutex);
31 return value->getValue(rt);
32 }
33
set(jsi::Runtime & rt,const jsi::PropNameID & name,const jsi::Value & newValue)34 void MutableValue::set(
35 jsi::Runtime &rt,
36 const jsi::PropNameID &name,
37 const jsi::Value &newValue) {
38 auto propName = name.utf8(rt);
39 if (!runtimeManager->valueSetter) {
40 throw jsi::JSError(
41 rt,
42 "Value-Setter is not yet configured! Make sure the core-functions are installed.");
43 }
44
45 if (RuntimeDecorator::isUIRuntime(rt)) {
46 // UI thread
47 if (propName == "value") {
48 auto setterProxy = jsi::Object::createFromHostObject(
49 rt, std::make_shared<MutableValueSetterProxy>(shared_from_this()));
50 runtimeManager->valueSetter->getValue(rt)
51 .asObject(rt)
52 .asFunction(rt)
53 .callWithThis(rt, setterProxy, newValue);
54 } else if (propName == "_animation") {
55 // TODO: assert to allow animation to be set from UI only
56 if (animation.expired()) {
57 animation = getWeakRef(rt);
58 }
59 *animation.lock() = jsi::Value(rt, newValue);
60 } else if (propName == "_value") {
61 auto setter =
62 std::make_shared<MutableValueSetterProxy>(shared_from_this());
63 setter->set(rt, jsi::PropNameID::forAscii(rt, "_value"), newValue);
64 }
65 } else {
66 // React-JS Thread or another threaded Runtime.
67 if (propName == "value") {
68 auto shareable = ShareableValue::adapt(rt, newValue, runtimeManager);
69 runtimeManager->scheduler->scheduleOnUI([this, shareable] {
70 jsi::Runtime &rt = *this->runtimeManager->runtime.get();
71 auto setterProxy = jsi::Object::createFromHostObject(
72 rt, std::make_shared<MutableValueSetterProxy>(shared_from_this()));
73 jsi::Value newValue = shareable->getValue(rt);
74 runtimeManager->valueSetter->getValue(rt)
75 .asObject(rt)
76 .asFunction(rt)
77 .callWithThis(rt, setterProxy, newValue);
78 });
79 }
80 }
81 }
82
get(jsi::Runtime & rt,const jsi::PropNameID & name)83 jsi::Value MutableValue::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
84 auto propName = name.utf8(rt);
85
86 if (propName == "value") {
87 return getValue(rt);
88 }
89
90 if (RuntimeDecorator::isUIRuntime(rt)) {
91 // _value and _animation should be accessed from UI only
92 if (propName == "_value") {
93 return getValue(rt);
94 } else if (propName == "_animation") {
95 // TODO: assert to allow animation to be read from UI only
96 if (animation.expired()) {
97 animation = getWeakRef(rt);
98 }
99 return jsi::Value(rt, *(animation.lock()));
100 }
101 }
102
103 return jsi::Value::undefined();
104 }
105
getPropertyNames(jsi::Runtime & rt)106 std::vector<jsi::PropNameID> MutableValue::getPropertyNames(jsi::Runtime &rt) {
107 std::vector<jsi::PropNameID> result;
108 result.push_back(jsi::PropNameID::forUtf8(rt, std::string("value")));
109 return result;
110 }
111
MutableValue(jsi::Runtime & rt,const jsi::Value & initial,RuntimeManager * runtimeManager,std::shared_ptr<Scheduler> s)112 MutableValue::MutableValue(
113 jsi::Runtime &rt,
114 const jsi::Value &initial,
115 RuntimeManager *runtimeManager,
116 std::shared_ptr<Scheduler> s)
117 : StoreUser(s, *runtimeManager),
118 runtimeManager(runtimeManager),
119 value(ShareableValue::adapt(rt, initial, runtimeManager)) {}
120
addListener(unsigned long id,std::function<void ()> listener)121 unsigned long int MutableValue::addListener(
122 unsigned long id,
123 std::function<void()> listener) {
124 listeners[id] = listener;
125 return id;
126 }
127
removeListener(unsigned long listenerId)128 void MutableValue::removeListener(unsigned long listenerId) {
129 if (listeners.count(listenerId) > 0) {
130 listeners.erase(listenerId);
131 }
132 }
133
134 } // namespace reanimated
135