@react-native-ohos/react-native-reanimated 3.18.1-rc.1 → 3.18.1-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.OpenSource +11 -0
  3. package/README.md +10 -0
  4. package/harmony/reanimated/BuildProfile.ets +16 -16
  5. package/harmony/reanimated/build-profile.json5 +11 -11
  6. package/harmony/reanimated/oh-package.json5 +11 -11
  7. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/AnimatedSensor/AnimatedSensorModule.cpp +86 -86
  8. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/AnimatedSensor/AnimatedSensorModule.h +47 -47
  9. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/PropsRegistry.cpp +68 -68
  10. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/PropsRegistry.h +68 -68
  11. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedCommitHook.cpp +101 -101
  12. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedCommitHook.h +51 -51
  13. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedCommitShadowNode.h +49 -49
  14. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp +87 -87
  15. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedMountHook.h +33 -33
  16. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ShadowTreeCloner.cpp +95 -95
  17. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ShadowTreeCloner.h +29 -29
  18. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationType.h +9 -9
  19. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsManager.cpp +232 -232
  20. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsManager.h +90 -90
  21. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy.cpp +870 -870
  22. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy.h +147 -147
  23. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsUtils.cpp +91 -91
  24. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsUtils.h +176 -176
  25. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp +971 -971
  26. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.h +252 -252
  27. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxySpec.cpp +231 -231
  28. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxySpec.h +109 -109
  29. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/RuntimeDecorators/RNRuntimeDecorator.cpp +56 -56
  30. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/RuntimeDecorators/RNRuntimeDecorator.h +20 -20
  31. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/RuntimeDecorators/UIRuntimeDecorator.cpp +70 -70
  32. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/RuntimeDecorators/UIRuntimeDecorator.h +35 -35
  33. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/CollectionUtils.h +14 -14
  34. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/FeaturesConfig.cpp +5 -5
  35. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/FeaturesConfig.h +19 -19
  36. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/PlatformDepMethodsHolder.h +98 -98
  37. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/ReanimatedSystraceSection.h +135 -135
  38. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp +47 -47
  39. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h +59 -59
  40. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/NativeModules/WorkletsModuleProxySpec.cpp +27 -27
  41. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/NativeModules/WorkletsModuleProxySpec.h +25 -25
  42. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Registries/EventHandlerRegistry.cpp +94 -94
  43. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Registries/EventHandlerRegistry.h +49 -49
  44. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.cpp +8 -8
  45. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.h +39 -39
  46. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/SharedItems/Shareables.cpp +326 -326
  47. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/SharedItems/Shareables.h +345 -345
  48. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/AsyncQueue.cpp +52 -52
  49. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/AsyncQueue.h +35 -35
  50. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/Defs.h +10 -10
  51. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSISerializer.cpp +342 -342
  52. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSISerializer.h +47 -47
  53. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSLogger.cpp +16 -16
  54. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSLogger.h +20 -20
  55. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSScheduler.cpp +20 -20
  56. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSScheduler.h +29 -29
  57. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/PlatformLogger.h +16 -16
  58. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ReanimatedJSIUtils.cpp +26 -26
  59. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ReanimatedJSIUtils.h +199 -199
  60. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ReanimatedVersion.cpp +95 -95
  61. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ReanimatedVersion.h +19 -19
  62. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/SingleInstanceChecker.h +72 -72
  63. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ThreadSafeQueue.h +49 -49
  64. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/UIScheduler.cpp +20 -20
  65. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/UIScheduler.h +22 -22
  66. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/WorkletEventHandler.cpp +29 -29
  67. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/WorkletEventHandler.h +41 -41
  68. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.cpp +16 -16
  69. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.h +19 -19
  70. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/ReanimatedHermesRuntime.cpp +112 -112
  71. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/ReanimatedHermesRuntime.h +127 -127
  72. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/ReanimatedRuntime.cpp +53 -53
  73. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/ReanimatedRuntime.h +22 -22
  74. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/RuntimeInitialization.md +191 -191
  75. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.cpp +155 -155
  76. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h +90 -90
  77. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeCollector.h +36 -36
  78. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.cpp +182 -182
  79. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.h +22 -22
  80. package/harmony/reanimated/src/main/cpp/WorkletsModule.cpp +57 -57
  81. package/harmony/reanimated/src/main/cpp/patches/AnimatedSensor/AnimatedSensorModule.cpp +89 -89
  82. package/harmony/reanimated/src/main/cpp/patches/NativeModules/ReanimatedModuleProxy.cpp +3 -0
  83. package/harmony/reanimated/src/main/module.json5 +12 -12
  84. package/harmony/reanimated/src/main/resources/base/element/color.json +7 -7
  85. package/harmony/reanimated/src/main/resources/base/element/string.json +15 -15
  86. package/harmony/reanimated/src/main/resources/base/profile/main_pages.json +5 -5
  87. package/harmony/reanimated/src/main/resources/en_US/element/string.json +15 -15
  88. package/harmony/reanimated/src/main/resources/zh_CN/element/string.json +15 -15
  89. package/harmony/reanimated/ts.ts +6 -6
  90. package/harmony/reanimated.har +0 -0
  91. package/package.json +50 -50
@@ -1,870 +1,870 @@
1
- #ifdef RCT_NEW_ARCH_ENABLED
2
-
3
- #include <reanimated/LayoutAnimations/LayoutAnimationsProxy.h>
4
- #include <reanimated/NativeModules/ReanimatedModuleProxy.h>
5
-
6
- #include <react/renderer/animations/utils.h>
7
- #include <react/renderer/mounting/ShadowViewMutation.h>
8
-
9
- #include <set>
10
- #include <utility>
11
-
12
- namespace reanimated {
13
-
14
- // We never modify the Shadow Tree, we just send some additional
15
- // mutations to the mounting layer.
16
- // When animations finish, the Host Tree will represent the most recent Shadow
17
- // Tree
18
- // On android this code will be sometimes executed on the JS thread.
19
- // That's why we have to schedule some of animation manager function on the UI
20
- // thread
21
- std::optional<MountingTransaction> LayoutAnimationsProxy::pullTransaction(
22
- SurfaceId surfaceId,
23
- MountingTransaction::Number transactionNumber,
24
- const TransactionTelemetry &telemetry,
25
- ShadowViewMutationList mutations) const {
26
- #ifdef LAYOUT_ANIMATIONS_LOGS
27
- LOG(INFO) << std::endl;
28
- LOG(INFO) << "pullTransaction " << std::this_thread::get_id() << " "
29
- << surfaceId << std::endl;
30
- #endif
31
- auto lock = std::unique_lock<std::recursive_mutex>(mutex);
32
- PropsParserContext propsParserContext{surfaceId, *contextContainer_};
33
- ShadowViewMutationList filteredMutations;
34
-
35
- std::vector<std::shared_ptr<MutationNode>> roots;
36
- std::unordered_map<Tag, ShadowView> movedViews;
37
-
38
- parseRemoveMutations(movedViews, mutations, roots);
39
-
40
- handleRemovals(filteredMutations, roots);
41
-
42
- handleUpdatesAndEnterings(
43
- filteredMutations, movedViews, mutations, propsParserContext, surfaceId);
44
-
45
- addOngoingAnimations(surfaceId, filteredMutations);
46
-
47
- return MountingTransaction{
48
- surfaceId, transactionNumber, std::move(filteredMutations), telemetry};
49
- }
50
-
51
- std::optional<SurfaceId> LayoutAnimationsProxy::progressLayoutAnimation(
52
- int tag,
53
- const jsi::Object &newStyle) {
54
- #ifdef LAYOUT_ANIMATIONS_LOGS
55
- LOG(INFO) << "progress layout animation for tag " << tag << std::endl;
56
- #endif
57
- auto lock = std::unique_lock<std::recursive_mutex>(mutex);
58
- auto layoutAnimationIt = layoutAnimations_.find(tag);
59
-
60
- if (layoutAnimationIt == layoutAnimations_.end()) {
61
- return {};
62
- }
63
-
64
- auto &layoutAnimation = layoutAnimationIt->second;
65
-
66
- maybeRestoreOpacity(layoutAnimation, newStyle);
67
-
68
- auto rawProps =
69
- std::make_shared<RawProps>(uiRuntime_, jsi::Value(uiRuntime_, newStyle));
70
-
71
- PropsParserContext propsParserContext{
72
- layoutAnimation.finalView->surfaceId, *contextContainer_};
73
- #ifdef ANDROID
74
- rawProps = std::make_shared<RawProps>(folly::dynamic::merge(
75
- layoutAnimation.finalView->props->rawProps, (folly::dynamic)*rawProps));
76
- #endif
77
- auto newProps =
78
- getComponentDescriptorForShadowView(*layoutAnimation.finalView)
79
- .cloneProps(
80
- propsParserContext,
81
- layoutAnimation.finalView->props,
82
- std::move(*rawProps));
83
- auto &updateMap =
84
- surfaceManager.getUpdateMap(layoutAnimation.finalView->surfaceId);
85
- updateMap.insert_or_assign(
86
- tag, UpdateValues{newProps, Frame(uiRuntime_, newStyle)});
87
-
88
- return layoutAnimation.finalView->surfaceId;
89
- }
90
-
91
- std::optional<SurfaceId> LayoutAnimationsProxy::endLayoutAnimation(
92
- int tag,
93
- bool shouldRemove) {
94
- #ifdef LAYOUT_ANIMATIONS_LOGS
95
- LOG(INFO) << "end layout animation for " << tag << " - should remove "
96
- << shouldRemove << std::endl;
97
- #endif
98
- auto lock = std::unique_lock<std::recursive_mutex>(mutex);
99
- auto layoutAnimationIt = layoutAnimations_.find(tag);
100
-
101
- if (layoutAnimationIt == layoutAnimations_.end()) {
102
- return {};
103
- }
104
-
105
- auto &layoutAnimation = layoutAnimationIt->second;
106
-
107
- // multiple layout animations can be triggered for a view
108
- // one after the other, so we need to keep count of how many
109
- // were actually triggered, so that we don't cleanup necessary
110
- // structures too early
111
- if (layoutAnimation.count > 1) {
112
- layoutAnimation.count--;
113
- return {};
114
- }
115
-
116
- auto surfaceId = layoutAnimation.finalView->surfaceId;
117
- auto &updateMap = surfaceManager.getUpdateMap(surfaceId);
118
- layoutAnimations_.erase(tag);
119
- updateMap.erase(tag);
120
-
121
- if (!shouldRemove || !nodeForTag_.contains(tag)) {
122
- return {};
123
- }
124
-
125
- auto node = nodeForTag_[tag];
126
- auto mutationNode = std::static_pointer_cast<MutationNode>(node);
127
- mutationNode->state = DEAD;
128
- deadNodes.insert(mutationNode);
129
-
130
- return surfaceId;
131
- }
132
-
133
- /**
134
- Organizes removed views into a tree structure, allowing for convenient
135
- traversals and index maintenance
136
- */
137
- void LayoutAnimationsProxy::parseRemoveMutations(
138
- std::unordered_map<Tag, ShadowView> &movedViews,
139
- ShadowViewMutationList &mutations,
140
- std::vector<std::shared_ptr<MutationNode>> &roots) const {
141
- std::set<Tag> deletedViews;
142
- std::unordered_map<Tag, std::vector<std::shared_ptr<MutationNode>>>
143
- childrenForTag, unflattenedChildrenForTag;
144
-
145
- std::vector<std::shared_ptr<MutationNode>> mutationNodes;
146
-
147
- // iterate from the end, so that parents appear before children
148
- for (auto it = mutations.rbegin(); it != mutations.rend(); it++) {
149
- auto &mutation = *it;
150
- if (mutation.type == ShadowViewMutation::Delete) {
151
- deletedViews.insert(mutation.oldChildShadowView.tag);
152
- }
153
- if (mutation.type == ShadowViewMutation::Remove) {
154
- updateIndexForMutation(mutation);
155
- auto tag = mutation.oldChildShadowView.tag;
156
- #if REACT_NATIVE_MINOR_VERSION >= 78
157
- auto parentTag = mutation.parentTag;
158
- #else
159
- auto parentTag = mutation.parentShadowView.tag;
160
- #endif // REACT_NATIVE_MINOR_VERSION >= 78
161
- auto unflattenedParentTag = parentTag; // temporary
162
-
163
- std::shared_ptr<MutationNode> mutationNode;
164
- std::shared_ptr<Node> node = nodeForTag_[tag],
165
- parent = nodeForTag_[parentTag],
166
- unflattenedParent =
167
- nodeForTag_[unflattenedParentTag];
168
-
169
- if (!node) {
170
- mutationNode = std::make_shared<MutationNode>(mutation);
171
- } else {
172
- mutationNode =
173
- std::make_shared<MutationNode>(mutation, std::move(*node));
174
- for (auto &subNode : mutationNode->children) {
175
- subNode->parent = mutationNode;
176
- }
177
- for (auto &subNode : mutationNode->unflattenedChildren) {
178
- subNode->unflattenedParent = mutationNode;
179
- }
180
- }
181
- if (!deletedViews.contains(mutation.oldChildShadowView.tag)) {
182
- mutationNode->state = MOVED;
183
- movedViews.insert_or_assign(
184
- mutation.oldChildShadowView.tag, mutation.oldChildShadowView);
185
- }
186
- nodeForTag_[tag] = mutationNode;
187
-
188
- if (!parent) {
189
- parent = std::make_shared<Node>(parentTag);
190
- nodeForTag_[parentTag] = parent;
191
- }
192
-
193
- if (!unflattenedParent) {
194
- if (parentTag == unflattenedParentTag) {
195
- unflattenedParent = parent;
196
- } else {
197
- unflattenedParent = std::make_shared<Node>(unflattenedParentTag);
198
- nodeForTag_[unflattenedParentTag] = unflattenedParent;
199
- }
200
- }
201
-
202
- mutationNodes.push_back(mutationNode);
203
-
204
- childrenForTag[parentTag].push_back(mutationNode);
205
- unflattenedChildrenForTag[unflattenedParentTag].push_back(mutationNode);
206
- mutationNode->parent = parent;
207
- mutationNode->unflattenedParent = unflattenedParent;
208
- }
209
- if (mutation.type == ShadowViewMutation::Update &&
210
- movedViews.contains(mutation.newChildShadowView.tag)) {
211
- auto node = nodeForTag_[mutation.newChildShadowView.tag];
212
- auto mutationNode = std::static_pointer_cast<MutationNode>(node);
213
- mutationNode->mutation.oldChildShadowView = mutation.oldChildShadowView;
214
- movedViews[mutation.newChildShadowView.tag] = mutation.oldChildShadowView;
215
- }
216
- }
217
-
218
- for (auto &[parentTag, children] : childrenForTag) {
219
- auto &parent = nodeForTag_[parentTag];
220
- parent->insertChildren(children);
221
- for (auto &child : children) {
222
- child->parent = parent;
223
- }
224
- }
225
- for (auto &[unflattenedParentTag, children] : unflattenedChildrenForTag) {
226
- auto &unflattenedParent = nodeForTag_[unflattenedParentTag];
227
- unflattenedParent->insertUnflattenedChildren(children);
228
- for (auto &child : children) {
229
- child->unflattenedParent = unflattenedParent;
230
- }
231
- }
232
-
233
- for (auto &mutationNode : mutationNodes) {
234
- if (!mutationNode->unflattenedParent->isMutationMode()) {
235
- roots.push_back(mutationNode);
236
- }
237
- }
238
- }
239
-
240
- void LayoutAnimationsProxy::handleRemovals(
241
- ShadowViewMutationList &filteredMutations,
242
- std::vector<std::shared_ptr<MutationNode>> &roots) const {
243
- // iterate from the end, so that children
244
- // with higher indices appear first in the mutations list
245
- for (auto it = roots.rbegin(); it != roots.rend(); it++) {
246
- auto &node = *it;
247
- if (!startAnimationsRecursively(
248
- node, true, true, false, filteredMutations)) {
249
- filteredMutations.push_back(node->mutation);
250
- node->unflattenedParent->removeChildFromUnflattenedTree(node); //???
251
- if (node->state != MOVED) {
252
- maybeCancelAnimation(node->tag);
253
- filteredMutations.push_back(ShadowViewMutation::DeleteMutation(
254
- node->mutation.oldChildShadowView));
255
- nodeForTag_.erase(node->tag);
256
- #ifdef LAYOUT_ANIMATIONS_LOGS
257
- LOG(INFO) << "delete " << node->tag << std::endl;
258
- #endif
259
- }
260
- }
261
- }
262
-
263
- for (auto node : deadNodes) {
264
- if (node->state != DELETED) {
265
- endAnimationsRecursively(node, filteredMutations);
266
- maybeDropAncestors(node->unflattenedParent, node, filteredMutations);
267
- }
268
- }
269
- deadNodes.clear();
270
- }
271
-
272
- void LayoutAnimationsProxy::handleUpdatesAndEnterings(
273
- ShadowViewMutationList &filteredMutations,
274
- const std::unordered_map<Tag, ShadowView> &movedViews,
275
- ShadowViewMutationList &mutations,
276
- const PropsParserContext &propsParserContext,
277
- SurfaceId surfaceId) const {
278
- std::unordered_map<Tag, ShadowView> oldShadowViewsForReparentings;
279
- for (auto &mutation : mutations) {
280
- maybeUpdateWindowDimensions(mutation, surfaceId);
281
-
282
- Tag tag = mutation.type == ShadowViewMutation::Type::Create ||
283
- mutation.type == ShadowViewMutation::Type::Insert
284
- ? mutation.newChildShadowView.tag
285
- : mutation.oldChildShadowView.tag;
286
-
287
- switch (mutation.type) {
288
- case ShadowViewMutation::Type::Create: {
289
- filteredMutations.push_back(mutation);
290
- break;
291
- }
292
- case ShadowViewMutation::Type::Insert: {
293
- updateIndexForMutation(mutation);
294
-
295
- #if REACT_NATIVE_MINOR_VERSION >= 78
296
- const auto parentTag = mutation.parentTag;
297
- const auto mutationParent = parentTag;
298
- #else
299
- const auto parentTag = mutation.parentShadowView.tag;
300
- const auto mutationParent = mutation.parentShadowView;
301
- #endif // REACT_NATIVE_MINOR_VERSION >= 78
302
- if (nodeForTag_.contains(parentTag)) {
303
- nodeForTag_[parentTag]->applyMutationToIndices(mutation);
304
- }
305
-
306
- if (movedViews.contains(tag)) {
307
- auto layoutAnimationIt = layoutAnimations_.find(tag);
308
- if (layoutAnimationIt == layoutAnimations_.end()) {
309
- if (oldShadowViewsForReparentings.contains(tag)) {
310
- filteredMutations.push_back(ShadowViewMutation::InsertMutation(
311
- mutationParent,
312
- oldShadowViewsForReparentings[tag],
313
- mutation.index));
314
- } else {
315
- filteredMutations.push_back(mutation);
316
- }
317
- continue;
318
- }
319
-
320
- auto oldView = *layoutAnimationIt->second.currentView;
321
- filteredMutations.push_back(ShadowViewMutation::InsertMutation(
322
- mutationParent, oldView, mutation.index));
323
- continue;
324
- }
325
-
326
- transferConfigFromNativeID(
327
- mutation.newChildShadowView.props->nativeId,
328
- mutation.newChildShadowView.tag);
329
- if (!layoutAnimationsManager_->hasLayoutAnimation(tag, ENTERING)) {
330
- filteredMutations.push_back(mutation);
331
- continue;
332
- }
333
-
334
- startEnteringAnimation(tag, mutation);
335
- filteredMutations.push_back(mutation);
336
-
337
- // temporarily set opacity to 0 to prevent flickering on android
338
- std::shared_ptr<ShadowView> newView =
339
- cloneViewWithoutOpacity(mutation, propsParserContext);
340
-
341
- filteredMutations.push_back(ShadowViewMutation::UpdateMutation(
342
- mutation.newChildShadowView, *newView, mutationParent));
343
- break;
344
- }
345
-
346
- case ShadowViewMutation::Type::Update: {
347
- auto shouldAnimate = hasLayoutChanged(mutation);
348
- if (!layoutAnimationsManager_->hasLayoutAnimation(tag, LAYOUT) ||
349
- (!shouldAnimate && !layoutAnimations_.contains(tag))) {
350
- // We should cancel any ongoing animation here to ensure that the
351
- // proper final state is reached for this view However, due to how
352
- // RNSScreens handle adding headers (a second commit is triggered to
353
- // offset all the elements by the header height) this would lead to
354
- // all entering animations being cancelled when a screen with a header
355
- // is pushed onto a stack
356
- // TODO: find a better solution for this problem
357
- filteredMutations.push_back(mutation);
358
- continue;
359
- } else if (!shouldAnimate) {
360
- updateOngoingAnimationTarget(tag, mutation);
361
- continue;
362
- }
363
-
364
- // store the oldChildShadowView, so that we can use this ShadowView when
365
- // the view is inserted
366
- oldShadowViewsForReparentings[tag] = mutation.oldChildShadowView;
367
- startLayoutAnimation(tag, mutation);
368
- break;
369
- }
370
-
371
- case ShadowViewMutation::Type::Remove:
372
- case ShadowViewMutation::Type::Delete: {
373
- break;
374
- }
375
-
376
- default:
377
- filteredMutations.push_back(mutation);
378
- }
379
- }
380
- }
381
-
382
- void LayoutAnimationsProxy::addOngoingAnimations(
383
- SurfaceId surfaceId,
384
- ShadowViewMutationList &mutations) const {
385
- auto &updateMap = surfaceManager.getUpdateMap(surfaceId);
386
- for (auto &[tag, updateValues] : updateMap) {
387
- auto layoutAnimationIt = layoutAnimations_.find(tag);
388
-
389
- if (layoutAnimationIt == layoutAnimations_.end()) {
390
- continue;
391
- }
392
-
393
- auto &layoutAnimation = layoutAnimationIt->second;
394
-
395
- auto newView = std::make_shared<ShadowView>(*layoutAnimation.finalView);
396
- newView->props = updateValues.newProps;
397
- updateLayoutMetrics(newView->layoutMetrics, updateValues.frame);
398
-
399
- mutations.push_back(ShadowViewMutation::UpdateMutation(
400
- *layoutAnimation.currentView,
401
- *newView,
402
- #if REACT_NATIVE_MINOR_VERSION >= 78
403
- layoutAnimation.parentTag
404
- #else
405
- *layoutAnimation.parentView
406
- #endif // REACT_NATIVE_MINOR_VERSION >= 78
407
- ));
408
- layoutAnimation.currentView = newView;
409
- }
410
- updateMap.clear();
411
- }
412
-
413
- void LayoutAnimationsProxy::endAnimationsRecursively(
414
- std::shared_ptr<MutationNode> node,
415
- ShadowViewMutationList &mutations) const {
416
- maybeCancelAnimation(node->tag);
417
- node->state = DELETED;
418
- // iterate from the end, so that children
419
- // with higher indices appear first in the mutations list
420
- for (auto it = node->unflattenedChildren.rbegin();
421
- it != node->unflattenedChildren.rend();
422
- it++) {
423
- auto &subNode = *it;
424
- if (subNode->state != DELETED) {
425
- endAnimationsRecursively(subNode, mutations);
426
- }
427
- }
428
- mutations.push_back(node->mutation);
429
- nodeForTag_.erase(node->tag);
430
- #ifdef LAYOUT_ANIMATIONS_LOGS
431
- LOG(INFO) << "delete " << node->tag << std::endl;
432
- #endif
433
- mutations.push_back(
434
- ShadowViewMutation::DeleteMutation(node->mutation.oldChildShadowView));
435
- }
436
-
437
- void LayoutAnimationsProxy::maybeDropAncestors(
438
- std::shared_ptr<Node> parent,
439
- std::shared_ptr<MutationNode> child,
440
- ShadowViewMutationList &cleanupMutations) const {
441
- parent->removeChildFromUnflattenedTree(child);
442
- if (!parent->isMutationMode()) {
443
- return;
444
- }
445
-
446
- auto node = std::static_pointer_cast<MutationNode>(parent);
447
-
448
- if (node->children.size() == 0 && node->state != ANIMATING) {
449
- nodeForTag_.erase(node->tag);
450
- cleanupMutations.push_back(node->mutation);
451
- maybeCancelAnimation(node->tag);
452
- #ifdef LAYOUT_ANIMATIONS_LOGS
453
- LOG(INFO) << "delete " << node->tag << std::endl;
454
- #endif
455
- cleanupMutations.push_back(
456
- ShadowViewMutation::DeleteMutation(node->mutation.oldChildShadowView));
457
- maybeDropAncestors(node->unflattenedParent, node, cleanupMutations);
458
- }
459
- }
460
-
461
- const ComponentDescriptor &
462
- LayoutAnimationsProxy::getComponentDescriptorForShadowView(
463
- const ShadowView &shadowView) const {
464
- return componentDescriptorRegistry_->at(shadowView.componentHandle);
465
- }
466
-
467
- bool LayoutAnimationsProxy::startAnimationsRecursively(
468
- std::shared_ptr<MutationNode> node,
469
- bool shouldRemoveSubviewsWithoutAnimations,
470
- bool shouldAnimate,
471
- bool isScreenPop,
472
- ShadowViewMutationList &mutations) const {
473
- if (isRNSScreen(node)) {
474
- isScreenPop = true;
475
- }
476
-
477
- shouldAnimate = !isScreenPop &&
478
- layoutAnimationsManager_->shouldAnimateExiting(node->tag, shouldAnimate);
479
-
480
- bool hasExitAnimation = shouldAnimate &&
481
- layoutAnimationsManager_->hasLayoutAnimation(
482
- node->tag, LayoutAnimationType::EXITING);
483
- bool hasAnimatedChildren = false;
484
-
485
- shouldRemoveSubviewsWithoutAnimations =
486
- shouldRemoveSubviewsWithoutAnimations && !hasExitAnimation;
487
- std::vector<std::shared_ptr<MutationNode>> toBeRemoved;
488
-
489
- // iterate from the end, so that children
490
- // with higher indices appear first in the mutations list
491
- for (auto it = node->unflattenedChildren.rbegin();
492
- it != node->unflattenedChildren.rend();
493
- it++) {
494
- auto &subNode = *it;
495
- #ifdef LAYOUT_ANIMATIONS_LOGS
496
- LOG(INFO) << "child " << subNode->tag << " "
497
- << " " << shouldAnimate << " "
498
- << shouldRemoveSubviewsWithoutAnimations << std::endl;
499
- #endif
500
- if (subNode->state != UNDEFINED && subNode->state != MOVED) {
501
- if (shouldAnimate && subNode->state != DEAD) {
502
- hasAnimatedChildren = true;
503
- } else {
504
- endAnimationsRecursively(subNode, mutations);
505
- toBeRemoved.push_back(subNode);
506
- }
507
- } else if (startAnimationsRecursively(
508
- subNode,
509
- shouldRemoveSubviewsWithoutAnimations,
510
- shouldAnimate,
511
- isScreenPop,
512
- mutations)) {
513
- #ifdef LAYOUT_ANIMATIONS_LOGS
514
- LOG(INFO) << "child " << subNode->tag
515
- << " start animations returned true " << std::endl;
516
- #endif
517
- hasAnimatedChildren = true;
518
- } else if (subNode->state == MOVED) {
519
- mutations.push_back(subNode->mutation);
520
- toBeRemoved.push_back(subNode);
521
- } else if (shouldRemoveSubviewsWithoutAnimations) {
522
- maybeCancelAnimation(subNode->tag);
523
- mutations.push_back(subNode->mutation);
524
- toBeRemoved.push_back(subNode);
525
- subNode->state = DELETED;
526
- nodeForTag_.erase(subNode->tag);
527
- #ifdef LAYOUT_ANIMATIONS_LOGS
528
- LOG(INFO) << "delete " << subNode->tag << std::endl;
529
- #endif
530
- mutations.push_back(ShadowViewMutation::DeleteMutation(
531
- subNode->mutation.oldChildShadowView));
532
- } else {
533
- subNode->state = WAITING;
534
- }
535
- }
536
-
537
- for (auto &subNode : toBeRemoved) {
538
- node->removeChildFromUnflattenedTree(subNode);
539
- }
540
-
541
- if (node->state == MOVED) {
542
- auto replacement = std::make_shared<Node>(*node);
543
- for (auto subNode : node->children) {
544
- subNode->parent = replacement;
545
- }
546
- for (auto subNode : node->unflattenedChildren) {
547
- subNode->unflattenedParent = replacement;
548
- }
549
- nodeForTag_[replacement->tag] = replacement;
550
- return false;
551
- }
552
-
553
- bool wantAnimateExit = hasExitAnimation || hasAnimatedChildren;
554
-
555
- if (hasExitAnimation) {
556
- node->state = ANIMATING;
557
- startExitingAnimation(node->tag, node->mutation);
558
- } else {
559
- layoutAnimationsManager_->clearLayoutAnimationConfig(node->tag);
560
- }
561
-
562
- return wantAnimateExit;
563
- }
564
-
565
- void LayoutAnimationsProxy::updateIndexForMutation(
566
- ShadowViewMutation &mutation) const {
567
- if (mutation.index == -1) {
568
- return;
569
- }
570
-
571
- #if REACT_NATIVE_MINOR_VERSION >= 78
572
- const auto parentTag = mutation.parentTag;
573
- #else
574
- const auto parentTag = mutation.parentShadowView.tag;
575
- #endif // REACT_NATIVE_MINOR_VERSION >= 78
576
-
577
- if (!nodeForTag_.contains(parentTag)) {
578
- return;
579
- }
580
-
581
- auto parent = nodeForTag_[parentTag];
582
- int size = 0, prevIndex = -1, offset = 0;
583
-
584
- for (auto &subNode : parent->children) {
585
- size += subNode->mutation.index - prevIndex - 1;
586
- if (mutation.index < size) {
587
- break;
588
- }
589
- offset++;
590
- prevIndex = subNode->mutation.index;
591
- }
592
- #ifdef LAYOUT_ANIMATIONS_LOGS
593
- int tag = mutation.type == ShadowViewMutation::Insert
594
- ? mutation.newChildShadowView.tag
595
- : mutation.oldChildShadowView.tag;
596
- LOG(INFO) << "update index for " << tag << " in " << parentTag << ": "
597
- << mutation.index << " -> " << mutation.index + offset << std::endl;
598
- #endif
599
- mutation.index += offset;
600
- }
601
-
602
- bool LayoutAnimationsProxy::shouldOverridePullTransaction() const {
603
- return true;
604
- }
605
-
606
- void LayoutAnimationsProxy::createLayoutAnimation(
607
- const ShadowViewMutation &mutation,
608
- ShadowView &oldView,
609
- const SurfaceId &surfaceId,
610
- const int tag) const {
611
- int count = 1;
612
- auto layoutAnimationIt = layoutAnimations_.find(tag);
613
-
614
- if (layoutAnimationIt != layoutAnimations_.end()) {
615
- auto &layoutAnimation = layoutAnimationIt->second;
616
- oldView = *layoutAnimation.currentView;
617
- count = layoutAnimation.count + 1;
618
- }
619
-
620
- auto finalView = std::make_shared<ShadowView>(
621
- mutation.type == ShadowViewMutation::Remove
622
- ? mutation.oldChildShadowView
623
- : mutation.newChildShadowView);
624
- auto currentView = std::make_shared<ShadowView>(oldView);
625
-
626
- #if REACT_NATIVE_MINOR_VERSION >= 78
627
- layoutAnimations_.insert_or_assign(
628
- tag,
629
- LayoutAnimation{finalView, currentView, mutation.parentTag, {}, count});
630
- #else
631
- auto parentView = std::make_shared<ShadowView>(mutation.parentShadowView);
632
- layoutAnimations_.insert_or_assign(
633
- tag, LayoutAnimation{finalView, currentView, parentView, {}, count});
634
- #endif // REACT_NATIVE_MINOR_VERSION >= 78
635
- }
636
-
637
- void LayoutAnimationsProxy::startEnteringAnimation(
638
- const int tag,
639
- ShadowViewMutation &mutation) const {
640
- #ifdef LAYOUT_ANIMATIONS_LOGS
641
- LOG(INFO) << "start entering animation for tag " << tag << std::endl;
642
- #endif
643
- auto finalView = std::make_shared<ShadowView>(mutation.newChildShadowView);
644
- auto current = std::make_shared<ShadowView>(mutation.newChildShadowView);
645
- #if REACT_NATIVE_MINOR_VERSION < 78
646
- auto parent = std::make_shared<ShadowView>(mutation.parentShadowView);
647
- #endif
648
-
649
- auto &viewProps =
650
- static_cast<const ViewProps &>(*mutation.newChildShadowView.props);
651
- auto opacity = viewProps.opacity;
652
-
653
- uiScheduler_->scheduleOnUI([weakThis = weak_from_this(),
654
- finalView,
655
- current,
656
- #if REACT_NATIVE_MINOR_VERSION < 78
657
- parent,
658
- #endif // RE
659
- mutation,
660
- opacity,
661
- tag]() {
662
- auto strongThis = weakThis.lock();
663
- if (!strongThis) {
664
- return;
665
- }
666
-
667
- Rect window{};
668
- {
669
- auto &mutex = strongThis->mutex;
670
- auto lock = std::unique_lock<std::recursive_mutex>(mutex);
671
- strongThis->layoutAnimations_.insert_or_assign(
672
- tag, LayoutAnimation {
673
- finalView, current,
674
- #if REACT_NATIVE_MINOR_VERSION >= 78
675
- mutation.parentTag,
676
- #else
677
- parent,
678
- #endif // REACT_NATIVE_MINOR_VERSION >= 78
679
- opacity
680
- });
681
- window = strongThis->surfaceManager.getWindow(
682
- mutation.newChildShadowView.surfaceId);
683
- }
684
-
685
- Snapshot values(mutation.newChildShadowView, window);
686
- auto &uiRuntime = strongThis->uiRuntime_;
687
- jsi::Object yogaValues(uiRuntime);
688
- yogaValues.setProperty(uiRuntime, "targetOriginX", values.x);
689
- yogaValues.setProperty(uiRuntime, "targetGlobalOriginX", values.x);
690
- yogaValues.setProperty(uiRuntime, "targetOriginY", values.y);
691
- yogaValues.setProperty(uiRuntime, "targetGlobalOriginY", values.y);
692
- yogaValues.setProperty(uiRuntime, "targetWidth", values.width);
693
- yogaValues.setProperty(uiRuntime, "targetHeight", values.height);
694
- yogaValues.setProperty(uiRuntime, "windowWidth", values.windowWidth);
695
- yogaValues.setProperty(uiRuntime, "windowHeight", values.windowHeight);
696
- strongThis->layoutAnimationsManager_->startLayoutAnimation(
697
- uiRuntime, tag, LayoutAnimationType::ENTERING, yogaValues);
698
- });
699
- }
700
-
701
- void LayoutAnimationsProxy::startExitingAnimation(
702
- const int tag,
703
- ShadowViewMutation &mutation) const {
704
- #ifdef LAYOUT_ANIMATIONS_LOGS
705
- LOG(INFO) << "start exiting animation for tag " << tag << std::endl;
706
- #endif
707
- auto surfaceId = mutation.oldChildShadowView.surfaceId;
708
-
709
- uiScheduler_->scheduleOnUI(
710
- [weakThis = weak_from_this(), tag, mutation, surfaceId]() {
711
- auto strongThis = weakThis.lock();
712
- if (!strongThis) {
713
- return;
714
- }
715
-
716
- auto oldView = mutation.oldChildShadowView;
717
- Rect window{};
718
- {
719
- auto &mutex = strongThis->mutex;
720
- auto lock = std::unique_lock<std::recursive_mutex>(mutex);
721
- strongThis->createLayoutAnimation(mutation, oldView, surfaceId, tag);
722
- window = strongThis->surfaceManager.getWindow(surfaceId);
723
- }
724
-
725
- Snapshot values(oldView, window);
726
-
727
- auto &uiRuntime = strongThis->uiRuntime_;
728
- jsi::Object yogaValues(uiRuntime);
729
- yogaValues.setProperty(uiRuntime, "currentOriginX", values.x);
730
- yogaValues.setProperty(uiRuntime, "currentGlobalOriginX", values.x);
731
- yogaValues.setProperty(uiRuntime, "currentOriginY", values.y);
732
- yogaValues.setProperty(uiRuntime, "currentGlobalOriginY", values.y);
733
- yogaValues.setProperty(uiRuntime, "currentWidth", values.width);
734
- yogaValues.setProperty(uiRuntime, "currentHeight", values.height);
735
- yogaValues.setProperty(uiRuntime, "windowWidth", values.windowWidth);
736
- yogaValues.setProperty(uiRuntime, "windowHeight", values.windowHeight);
737
- strongThis->layoutAnimationsManager_->startLayoutAnimation(
738
- uiRuntime, tag, LayoutAnimationType::EXITING, yogaValues);
739
- strongThis->layoutAnimationsManager_->clearLayoutAnimationConfig(tag);
740
- });
741
- }
742
-
743
- void LayoutAnimationsProxy::startLayoutAnimation(
744
- const int tag,
745
- const ShadowViewMutation &mutation) const {
746
- #ifdef LAYOUT_ANIMATIONS_LOGS
747
- LOG(INFO) << "start layout animation for tag " << tag << std::endl;
748
- #endif
749
- auto surfaceId = mutation.oldChildShadowView.surfaceId;
750
-
751
- uiScheduler_->scheduleOnUI([weakThis = weak_from_this(),
752
- mutation,
753
- surfaceId,
754
- tag]() {
755
- auto strongThis = weakThis.lock();
756
- if (!strongThis) {
757
- return;
758
- }
759
-
760
- auto oldView = mutation.oldChildShadowView;
761
- Rect window{};
762
- {
763
- auto &mutex = strongThis->mutex;
764
- auto lock = std::unique_lock<std::recursive_mutex>(mutex);
765
- strongThis->createLayoutAnimation(mutation, oldView, surfaceId, tag);
766
- window = strongThis->surfaceManager.getWindow(surfaceId);
767
- }
768
-
769
- Snapshot currentValues(oldView, window);
770
- Snapshot targetValues(mutation.newChildShadowView, window);
771
-
772
- auto &uiRuntime = strongThis->uiRuntime_;
773
- jsi::Object yogaValues(uiRuntime);
774
- yogaValues.setProperty(uiRuntime, "currentOriginX", currentValues.x);
775
- yogaValues.setProperty(uiRuntime, "currentGlobalOriginX", currentValues.x);
776
- yogaValues.setProperty(uiRuntime, "currentOriginY", currentValues.y);
777
- yogaValues.setProperty(uiRuntime, "currentGlobalOriginY", currentValues.y);
778
- yogaValues.setProperty(uiRuntime, "currentWidth", currentValues.width);
779
- yogaValues.setProperty(uiRuntime, "currentHeight", currentValues.height);
780
- yogaValues.setProperty(uiRuntime, "targetOriginX", targetValues.x);
781
- yogaValues.setProperty(uiRuntime, "targetGlobalOriginX", targetValues.x);
782
- yogaValues.setProperty(uiRuntime, "targetOriginY", targetValues.y);
783
- yogaValues.setProperty(uiRuntime, "targetGlobalOriginY", targetValues.y);
784
- yogaValues.setProperty(uiRuntime, "targetWidth", targetValues.width);
785
- yogaValues.setProperty(uiRuntime, "targetHeight", targetValues.height);
786
- yogaValues.setProperty(uiRuntime, "windowWidth", targetValues.windowWidth);
787
- yogaValues.setProperty(
788
- uiRuntime, "windowHeight", targetValues.windowHeight);
789
- strongThis->layoutAnimationsManager_->startLayoutAnimation(
790
- uiRuntime, tag, LayoutAnimationType::LAYOUT, yogaValues);
791
- });
792
- }
793
-
794
- void LayoutAnimationsProxy::updateOngoingAnimationTarget(
795
- const int tag,
796
- const ShadowViewMutation &mutation) const {
797
- layoutAnimations_[tag].finalView =
798
- std::make_shared<ShadowView>(mutation.newChildShadowView);
799
- }
800
-
801
- void LayoutAnimationsProxy::maybeCancelAnimation(const int tag) const {
802
- if (!layoutAnimations_.contains(tag)) {
803
- return;
804
- }
805
- layoutAnimations_.erase(tag);
806
- uiScheduler_->scheduleOnUI([weakThis = weak_from_this(), tag]() {
807
- auto strongThis = weakThis.lock();
808
- if (!strongThis) {
809
- return;
810
- }
811
-
812
- auto &uiRuntime = strongThis->uiRuntime_;
813
- strongThis->layoutAnimationsManager_->cancelLayoutAnimation(uiRuntime, tag);
814
- });
815
- }
816
-
817
- void LayoutAnimationsProxy::transferConfigFromNativeID(
818
- const std::string nativeIdString,
819
- const int tag) const {
820
- if (nativeIdString.empty()) {
821
- return;
822
- }
823
- try {
824
- auto nativeId = stoi(nativeIdString);
825
- layoutAnimationsManager_->transferConfigFromNativeID(nativeId, tag);
826
- } catch (std::invalid_argument) {
827
- } catch (std::out_of_range) {
828
- }
829
- }
830
-
831
- // When entering animations start, we temporarily set opacity to 0
832
- // so that we can immediately insert the view at the right position
833
- // and schedule the animation on the UI thread
834
- std::shared_ptr<ShadowView> LayoutAnimationsProxy::cloneViewWithoutOpacity(
835
- facebook::react::ShadowViewMutation &mutation,
836
- const PropsParserContext &propsParserContext) const {
837
- auto newView = std::make_shared<ShadowView>(mutation.newChildShadowView);
838
- folly::dynamic opacity = folly::dynamic::object("opacity", 0);
839
- auto newProps = getComponentDescriptorForShadowView(*newView).cloneProps(
840
- propsParserContext, newView->props, RawProps(opacity));
841
- newView->props = newProps;
842
- return newView;
843
- }
844
-
845
- void LayoutAnimationsProxy::maybeRestoreOpacity(
846
- LayoutAnimation &layoutAnimation,
847
- const jsi::Object &newStyle) const {
848
- if (layoutAnimation.opacity && !newStyle.hasProperty(uiRuntime_, "opacity")) {
849
- newStyle.setProperty(
850
- uiRuntime_, "opacity", jsi::Value(*layoutAnimation.opacity));
851
- layoutAnimation.opacity.reset();
852
- }
853
- }
854
-
855
- void LayoutAnimationsProxy::maybeUpdateWindowDimensions(
856
- facebook::react::ShadowViewMutation &mutation,
857
- SurfaceId surfaceId) const {
858
- if (mutation.type == ShadowViewMutation::Update &&
859
- !std::strcmp(
860
- mutation.oldChildShadowView.componentName, RootComponentName)) {
861
- surfaceManager.updateWindow(
862
- surfaceId,
863
- mutation.newChildShadowView.layoutMetrics.frame.size.width,
864
- mutation.newChildShadowView.layoutMetrics.frame.size.height);
865
- }
866
- }
867
-
868
- } // namespace reanimated
869
-
870
- #endif // RCT_NEW_ARCH_ENABLED
1
+ #ifdef RCT_NEW_ARCH_ENABLED
2
+
3
+ #include <reanimated/LayoutAnimations/LayoutAnimationsProxy.h>
4
+ #include <reanimated/NativeModules/ReanimatedModuleProxy.h>
5
+
6
+ #include <react/renderer/animations/utils.h>
7
+ #include <react/renderer/mounting/ShadowViewMutation.h>
8
+
9
+ #include <set>
10
+ #include <utility>
11
+
12
+ namespace reanimated {
13
+
14
+ // We never modify the Shadow Tree, we just send some additional
15
+ // mutations to the mounting layer.
16
+ // When animations finish, the Host Tree will represent the most recent Shadow
17
+ // Tree
18
+ // On android this code will be sometimes executed on the JS thread.
19
+ // That's why we have to schedule some of animation manager function on the UI
20
+ // thread
21
+ std::optional<MountingTransaction> LayoutAnimationsProxy::pullTransaction(
22
+ SurfaceId surfaceId,
23
+ MountingTransaction::Number transactionNumber,
24
+ const TransactionTelemetry &telemetry,
25
+ ShadowViewMutationList mutations) const {
26
+ #ifdef LAYOUT_ANIMATIONS_LOGS
27
+ LOG(INFO) << std::endl;
28
+ LOG(INFO) << "pullTransaction " << std::this_thread::get_id() << " "
29
+ << surfaceId << std::endl;
30
+ #endif
31
+ auto lock = std::unique_lock<std::recursive_mutex>(mutex);
32
+ PropsParserContext propsParserContext{surfaceId, *contextContainer_};
33
+ ShadowViewMutationList filteredMutations;
34
+
35
+ std::vector<std::shared_ptr<MutationNode>> roots;
36
+ std::unordered_map<Tag, ShadowView> movedViews;
37
+
38
+ parseRemoveMutations(movedViews, mutations, roots);
39
+
40
+ handleRemovals(filteredMutations, roots);
41
+
42
+ handleUpdatesAndEnterings(
43
+ filteredMutations, movedViews, mutations, propsParserContext, surfaceId);
44
+
45
+ addOngoingAnimations(surfaceId, filteredMutations);
46
+
47
+ return MountingTransaction{
48
+ surfaceId, transactionNumber, std::move(filteredMutations), telemetry};
49
+ }
50
+
51
+ std::optional<SurfaceId> LayoutAnimationsProxy::progressLayoutAnimation(
52
+ int tag,
53
+ const jsi::Object &newStyle) {
54
+ #ifdef LAYOUT_ANIMATIONS_LOGS
55
+ LOG(INFO) << "progress layout animation for tag " << tag << std::endl;
56
+ #endif
57
+ auto lock = std::unique_lock<std::recursive_mutex>(mutex);
58
+ auto layoutAnimationIt = layoutAnimations_.find(tag);
59
+
60
+ if (layoutAnimationIt == layoutAnimations_.end()) {
61
+ return {};
62
+ }
63
+
64
+ auto &layoutAnimation = layoutAnimationIt->second;
65
+
66
+ maybeRestoreOpacity(layoutAnimation, newStyle);
67
+
68
+ auto rawProps =
69
+ std::make_shared<RawProps>(uiRuntime_, jsi::Value(uiRuntime_, newStyle));
70
+
71
+ PropsParserContext propsParserContext{
72
+ layoutAnimation.finalView->surfaceId, *contextContainer_};
73
+ #ifdef ANDROID
74
+ rawProps = std::make_shared<RawProps>(folly::dynamic::merge(
75
+ layoutAnimation.finalView->props->rawProps, (folly::dynamic)*rawProps));
76
+ #endif
77
+ auto newProps =
78
+ getComponentDescriptorForShadowView(*layoutAnimation.finalView)
79
+ .cloneProps(
80
+ propsParserContext,
81
+ layoutAnimation.finalView->props,
82
+ std::move(*rawProps));
83
+ auto &updateMap =
84
+ surfaceManager.getUpdateMap(layoutAnimation.finalView->surfaceId);
85
+ updateMap.insert_or_assign(
86
+ tag, UpdateValues{newProps, Frame(uiRuntime_, newStyle)});
87
+
88
+ return layoutAnimation.finalView->surfaceId;
89
+ }
90
+
91
+ std::optional<SurfaceId> LayoutAnimationsProxy::endLayoutAnimation(
92
+ int tag,
93
+ bool shouldRemove) {
94
+ #ifdef LAYOUT_ANIMATIONS_LOGS
95
+ LOG(INFO) << "end layout animation for " << tag << " - should remove "
96
+ << shouldRemove << std::endl;
97
+ #endif
98
+ auto lock = std::unique_lock<std::recursive_mutex>(mutex);
99
+ auto layoutAnimationIt = layoutAnimations_.find(tag);
100
+
101
+ if (layoutAnimationIt == layoutAnimations_.end()) {
102
+ return {};
103
+ }
104
+
105
+ auto &layoutAnimation = layoutAnimationIt->second;
106
+
107
+ // multiple layout animations can be triggered for a view
108
+ // one after the other, so we need to keep count of how many
109
+ // were actually triggered, so that we don't cleanup necessary
110
+ // structures too early
111
+ if (layoutAnimation.count > 1) {
112
+ layoutAnimation.count--;
113
+ return {};
114
+ }
115
+
116
+ auto surfaceId = layoutAnimation.finalView->surfaceId;
117
+ auto &updateMap = surfaceManager.getUpdateMap(surfaceId);
118
+ layoutAnimations_.erase(tag);
119
+ updateMap.erase(tag);
120
+
121
+ if (!shouldRemove || !nodeForTag_.contains(tag)) {
122
+ return {};
123
+ }
124
+
125
+ auto node = nodeForTag_[tag];
126
+ auto mutationNode = std::static_pointer_cast<MutationNode>(node);
127
+ mutationNode->state = DEAD;
128
+ deadNodes.insert(mutationNode);
129
+
130
+ return surfaceId;
131
+ }
132
+
133
+ /**
134
+ Organizes removed views into a tree structure, allowing for convenient
135
+ traversals and index maintenance
136
+ */
137
+ void LayoutAnimationsProxy::parseRemoveMutations(
138
+ std::unordered_map<Tag, ShadowView> &movedViews,
139
+ ShadowViewMutationList &mutations,
140
+ std::vector<std::shared_ptr<MutationNode>> &roots) const {
141
+ std::set<Tag> deletedViews;
142
+ std::unordered_map<Tag, std::vector<std::shared_ptr<MutationNode>>>
143
+ childrenForTag, unflattenedChildrenForTag;
144
+
145
+ std::vector<std::shared_ptr<MutationNode>> mutationNodes;
146
+
147
+ // iterate from the end, so that parents appear before children
148
+ for (auto it = mutations.rbegin(); it != mutations.rend(); it++) {
149
+ auto &mutation = *it;
150
+ if (mutation.type == ShadowViewMutation::Delete) {
151
+ deletedViews.insert(mutation.oldChildShadowView.tag);
152
+ }
153
+ if (mutation.type == ShadowViewMutation::Remove) {
154
+ updateIndexForMutation(mutation);
155
+ auto tag = mutation.oldChildShadowView.tag;
156
+ #if REACT_NATIVE_MINOR_VERSION >= 78
157
+ auto parentTag = mutation.parentTag;
158
+ #else
159
+ auto parentTag = mutation.parentShadowView.tag;
160
+ #endif // REACT_NATIVE_MINOR_VERSION >= 78
161
+ auto unflattenedParentTag = parentTag; // temporary
162
+
163
+ std::shared_ptr<MutationNode> mutationNode;
164
+ std::shared_ptr<Node> node = nodeForTag_[tag],
165
+ parent = nodeForTag_[parentTag],
166
+ unflattenedParent =
167
+ nodeForTag_[unflattenedParentTag];
168
+
169
+ if (!node) {
170
+ mutationNode = std::make_shared<MutationNode>(mutation);
171
+ } else {
172
+ mutationNode =
173
+ std::make_shared<MutationNode>(mutation, std::move(*node));
174
+ for (auto &subNode : mutationNode->children) {
175
+ subNode->parent = mutationNode;
176
+ }
177
+ for (auto &subNode : mutationNode->unflattenedChildren) {
178
+ subNode->unflattenedParent = mutationNode;
179
+ }
180
+ }
181
+ if (!deletedViews.contains(mutation.oldChildShadowView.tag)) {
182
+ mutationNode->state = MOVED;
183
+ movedViews.insert_or_assign(
184
+ mutation.oldChildShadowView.tag, mutation.oldChildShadowView);
185
+ }
186
+ nodeForTag_[tag] = mutationNode;
187
+
188
+ if (!parent) {
189
+ parent = std::make_shared<Node>(parentTag);
190
+ nodeForTag_[parentTag] = parent;
191
+ }
192
+
193
+ if (!unflattenedParent) {
194
+ if (parentTag == unflattenedParentTag) {
195
+ unflattenedParent = parent;
196
+ } else {
197
+ unflattenedParent = std::make_shared<Node>(unflattenedParentTag);
198
+ nodeForTag_[unflattenedParentTag] = unflattenedParent;
199
+ }
200
+ }
201
+
202
+ mutationNodes.push_back(mutationNode);
203
+
204
+ childrenForTag[parentTag].push_back(mutationNode);
205
+ unflattenedChildrenForTag[unflattenedParentTag].push_back(mutationNode);
206
+ mutationNode->parent = parent;
207
+ mutationNode->unflattenedParent = unflattenedParent;
208
+ }
209
+ if (mutation.type == ShadowViewMutation::Update &&
210
+ movedViews.contains(mutation.newChildShadowView.tag)) {
211
+ auto node = nodeForTag_[mutation.newChildShadowView.tag];
212
+ auto mutationNode = std::static_pointer_cast<MutationNode>(node);
213
+ mutationNode->mutation.oldChildShadowView = mutation.oldChildShadowView;
214
+ movedViews[mutation.newChildShadowView.tag] = mutation.oldChildShadowView;
215
+ }
216
+ }
217
+
218
+ for (auto &[parentTag, children] : childrenForTag) {
219
+ auto &parent = nodeForTag_[parentTag];
220
+ parent->insertChildren(children);
221
+ for (auto &child : children) {
222
+ child->parent = parent;
223
+ }
224
+ }
225
+ for (auto &[unflattenedParentTag, children] : unflattenedChildrenForTag) {
226
+ auto &unflattenedParent = nodeForTag_[unflattenedParentTag];
227
+ unflattenedParent->insertUnflattenedChildren(children);
228
+ for (auto &child : children) {
229
+ child->unflattenedParent = unflattenedParent;
230
+ }
231
+ }
232
+
233
+ for (auto &mutationNode : mutationNodes) {
234
+ if (!mutationNode->unflattenedParent->isMutationMode()) {
235
+ roots.push_back(mutationNode);
236
+ }
237
+ }
238
+ }
239
+
240
+ void LayoutAnimationsProxy::handleRemovals(
241
+ ShadowViewMutationList &filteredMutations,
242
+ std::vector<std::shared_ptr<MutationNode>> &roots) const {
243
+ // iterate from the end, so that children
244
+ // with higher indices appear first in the mutations list
245
+ for (auto it = roots.rbegin(); it != roots.rend(); it++) {
246
+ auto &node = *it;
247
+ if (!startAnimationsRecursively(
248
+ node, true, true, false, filteredMutations)) {
249
+ filteredMutations.push_back(node->mutation);
250
+ node->unflattenedParent->removeChildFromUnflattenedTree(node); //???
251
+ if (node->state != MOVED) {
252
+ maybeCancelAnimation(node->tag);
253
+ filteredMutations.push_back(ShadowViewMutation::DeleteMutation(
254
+ node->mutation.oldChildShadowView));
255
+ nodeForTag_.erase(node->tag);
256
+ #ifdef LAYOUT_ANIMATIONS_LOGS
257
+ LOG(INFO) << "delete " << node->tag << std::endl;
258
+ #endif
259
+ }
260
+ }
261
+ }
262
+
263
+ for (auto node : deadNodes) {
264
+ if (node->state != DELETED) {
265
+ endAnimationsRecursively(node, filteredMutations);
266
+ maybeDropAncestors(node->unflattenedParent, node, filteredMutations);
267
+ }
268
+ }
269
+ deadNodes.clear();
270
+ }
271
+
272
+ void LayoutAnimationsProxy::handleUpdatesAndEnterings(
273
+ ShadowViewMutationList &filteredMutations,
274
+ const std::unordered_map<Tag, ShadowView> &movedViews,
275
+ ShadowViewMutationList &mutations,
276
+ const PropsParserContext &propsParserContext,
277
+ SurfaceId surfaceId) const {
278
+ std::unordered_map<Tag, ShadowView> oldShadowViewsForReparentings;
279
+ for (auto &mutation : mutations) {
280
+ maybeUpdateWindowDimensions(mutation, surfaceId);
281
+
282
+ Tag tag = mutation.type == ShadowViewMutation::Type::Create ||
283
+ mutation.type == ShadowViewMutation::Type::Insert
284
+ ? mutation.newChildShadowView.tag
285
+ : mutation.oldChildShadowView.tag;
286
+
287
+ switch (mutation.type) {
288
+ case ShadowViewMutation::Type::Create: {
289
+ filteredMutations.push_back(mutation);
290
+ break;
291
+ }
292
+ case ShadowViewMutation::Type::Insert: {
293
+ updateIndexForMutation(mutation);
294
+
295
+ #if REACT_NATIVE_MINOR_VERSION >= 78
296
+ const auto parentTag = mutation.parentTag;
297
+ const auto mutationParent = parentTag;
298
+ #else
299
+ const auto parentTag = mutation.parentShadowView.tag;
300
+ const auto mutationParent = mutation.parentShadowView;
301
+ #endif // REACT_NATIVE_MINOR_VERSION >= 78
302
+ if (nodeForTag_.contains(parentTag)) {
303
+ nodeForTag_[parentTag]->applyMutationToIndices(mutation);
304
+ }
305
+
306
+ if (movedViews.contains(tag)) {
307
+ auto layoutAnimationIt = layoutAnimations_.find(tag);
308
+ if (layoutAnimationIt == layoutAnimations_.end()) {
309
+ if (oldShadowViewsForReparentings.contains(tag)) {
310
+ filteredMutations.push_back(ShadowViewMutation::InsertMutation(
311
+ mutationParent,
312
+ oldShadowViewsForReparentings[tag],
313
+ mutation.index));
314
+ } else {
315
+ filteredMutations.push_back(mutation);
316
+ }
317
+ continue;
318
+ }
319
+
320
+ auto oldView = *layoutAnimationIt->second.currentView;
321
+ filteredMutations.push_back(ShadowViewMutation::InsertMutation(
322
+ mutationParent, oldView, mutation.index));
323
+ continue;
324
+ }
325
+
326
+ transferConfigFromNativeID(
327
+ mutation.newChildShadowView.props->nativeId,
328
+ mutation.newChildShadowView.tag);
329
+ if (!layoutAnimationsManager_->hasLayoutAnimation(tag, ENTERING)) {
330
+ filteredMutations.push_back(mutation);
331
+ continue;
332
+ }
333
+
334
+ startEnteringAnimation(tag, mutation);
335
+ filteredMutations.push_back(mutation);
336
+
337
+ // temporarily set opacity to 0 to prevent flickering on android
338
+ std::shared_ptr<ShadowView> newView =
339
+ cloneViewWithoutOpacity(mutation, propsParserContext);
340
+
341
+ filteredMutations.push_back(ShadowViewMutation::UpdateMutation(
342
+ mutation.newChildShadowView, *newView, mutationParent));
343
+ break;
344
+ }
345
+
346
+ case ShadowViewMutation::Type::Update: {
347
+ auto shouldAnimate = hasLayoutChanged(mutation);
348
+ if (!layoutAnimationsManager_->hasLayoutAnimation(tag, LAYOUT) ||
349
+ (!shouldAnimate && !layoutAnimations_.contains(tag))) {
350
+ // We should cancel any ongoing animation here to ensure that the
351
+ // proper final state is reached for this view However, due to how
352
+ // RNSScreens handle adding headers (a second commit is triggered to
353
+ // offset all the elements by the header height) this would lead to
354
+ // all entering animations being cancelled when a screen with a header
355
+ // is pushed onto a stack
356
+ // TODO: find a better solution for this problem
357
+ filteredMutations.push_back(mutation);
358
+ continue;
359
+ } else if (!shouldAnimate) {
360
+ updateOngoingAnimationTarget(tag, mutation);
361
+ continue;
362
+ }
363
+
364
+ // store the oldChildShadowView, so that we can use this ShadowView when
365
+ // the view is inserted
366
+ oldShadowViewsForReparentings[tag] = mutation.oldChildShadowView;
367
+ startLayoutAnimation(tag, mutation);
368
+ break;
369
+ }
370
+
371
+ case ShadowViewMutation::Type::Remove:
372
+ case ShadowViewMutation::Type::Delete: {
373
+ break;
374
+ }
375
+
376
+ default:
377
+ filteredMutations.push_back(mutation);
378
+ }
379
+ }
380
+ }
381
+
382
+ void LayoutAnimationsProxy::addOngoingAnimations(
383
+ SurfaceId surfaceId,
384
+ ShadowViewMutationList &mutations) const {
385
+ auto &updateMap = surfaceManager.getUpdateMap(surfaceId);
386
+ for (auto &[tag, updateValues] : updateMap) {
387
+ auto layoutAnimationIt = layoutAnimations_.find(tag);
388
+
389
+ if (layoutAnimationIt == layoutAnimations_.end()) {
390
+ continue;
391
+ }
392
+
393
+ auto &layoutAnimation = layoutAnimationIt->second;
394
+
395
+ auto newView = std::make_shared<ShadowView>(*layoutAnimation.finalView);
396
+ newView->props = updateValues.newProps;
397
+ updateLayoutMetrics(newView->layoutMetrics, updateValues.frame);
398
+
399
+ mutations.push_back(ShadowViewMutation::UpdateMutation(
400
+ *layoutAnimation.currentView,
401
+ *newView,
402
+ #if REACT_NATIVE_MINOR_VERSION >= 78
403
+ layoutAnimation.parentTag
404
+ #else
405
+ *layoutAnimation.parentView
406
+ #endif // REACT_NATIVE_MINOR_VERSION >= 78
407
+ ));
408
+ layoutAnimation.currentView = newView;
409
+ }
410
+ updateMap.clear();
411
+ }
412
+
413
+ void LayoutAnimationsProxy::endAnimationsRecursively(
414
+ std::shared_ptr<MutationNode> node,
415
+ ShadowViewMutationList &mutations) const {
416
+ maybeCancelAnimation(node->tag);
417
+ node->state = DELETED;
418
+ // iterate from the end, so that children
419
+ // with higher indices appear first in the mutations list
420
+ for (auto it = node->unflattenedChildren.rbegin();
421
+ it != node->unflattenedChildren.rend();
422
+ it++) {
423
+ auto &subNode = *it;
424
+ if (subNode->state != DELETED) {
425
+ endAnimationsRecursively(subNode, mutations);
426
+ }
427
+ }
428
+ mutations.push_back(node->mutation);
429
+ nodeForTag_.erase(node->tag);
430
+ #ifdef LAYOUT_ANIMATIONS_LOGS
431
+ LOG(INFO) << "delete " << node->tag << std::endl;
432
+ #endif
433
+ mutations.push_back(
434
+ ShadowViewMutation::DeleteMutation(node->mutation.oldChildShadowView));
435
+ }
436
+
437
+ void LayoutAnimationsProxy::maybeDropAncestors(
438
+ std::shared_ptr<Node> parent,
439
+ std::shared_ptr<MutationNode> child,
440
+ ShadowViewMutationList &cleanupMutations) const {
441
+ parent->removeChildFromUnflattenedTree(child);
442
+ if (!parent->isMutationMode()) {
443
+ return;
444
+ }
445
+
446
+ auto node = std::static_pointer_cast<MutationNode>(parent);
447
+
448
+ if (node->children.size() == 0 && node->state != ANIMATING) {
449
+ nodeForTag_.erase(node->tag);
450
+ cleanupMutations.push_back(node->mutation);
451
+ maybeCancelAnimation(node->tag);
452
+ #ifdef LAYOUT_ANIMATIONS_LOGS
453
+ LOG(INFO) << "delete " << node->tag << std::endl;
454
+ #endif
455
+ cleanupMutations.push_back(
456
+ ShadowViewMutation::DeleteMutation(node->mutation.oldChildShadowView));
457
+ maybeDropAncestors(node->unflattenedParent, node, cleanupMutations);
458
+ }
459
+ }
460
+
461
+ const ComponentDescriptor &
462
+ LayoutAnimationsProxy::getComponentDescriptorForShadowView(
463
+ const ShadowView &shadowView) const {
464
+ return componentDescriptorRegistry_->at(shadowView.componentHandle);
465
+ }
466
+
467
+ bool LayoutAnimationsProxy::startAnimationsRecursively(
468
+ std::shared_ptr<MutationNode> node,
469
+ bool shouldRemoveSubviewsWithoutAnimations,
470
+ bool shouldAnimate,
471
+ bool isScreenPop,
472
+ ShadowViewMutationList &mutations) const {
473
+ if (isRNSScreen(node)) {
474
+ isScreenPop = true;
475
+ }
476
+
477
+ shouldAnimate = !isScreenPop &&
478
+ layoutAnimationsManager_->shouldAnimateExiting(node->tag, shouldAnimate);
479
+
480
+ bool hasExitAnimation = shouldAnimate &&
481
+ layoutAnimationsManager_->hasLayoutAnimation(
482
+ node->tag, LayoutAnimationType::EXITING);
483
+ bool hasAnimatedChildren = false;
484
+
485
+ shouldRemoveSubviewsWithoutAnimations =
486
+ shouldRemoveSubviewsWithoutAnimations && !hasExitAnimation;
487
+ std::vector<std::shared_ptr<MutationNode>> toBeRemoved;
488
+
489
+ // iterate from the end, so that children
490
+ // with higher indices appear first in the mutations list
491
+ for (auto it = node->unflattenedChildren.rbegin();
492
+ it != node->unflattenedChildren.rend();
493
+ it++) {
494
+ auto &subNode = *it;
495
+ #ifdef LAYOUT_ANIMATIONS_LOGS
496
+ LOG(INFO) << "child " << subNode->tag << " "
497
+ << " " << shouldAnimate << " "
498
+ << shouldRemoveSubviewsWithoutAnimations << std::endl;
499
+ #endif
500
+ if (subNode->state != UNDEFINED && subNode->state != MOVED) {
501
+ if (shouldAnimate && subNode->state != DEAD) {
502
+ hasAnimatedChildren = true;
503
+ } else {
504
+ endAnimationsRecursively(subNode, mutations);
505
+ toBeRemoved.push_back(subNode);
506
+ }
507
+ } else if (startAnimationsRecursively(
508
+ subNode,
509
+ shouldRemoveSubviewsWithoutAnimations,
510
+ shouldAnimate,
511
+ isScreenPop,
512
+ mutations)) {
513
+ #ifdef LAYOUT_ANIMATIONS_LOGS
514
+ LOG(INFO) << "child " << subNode->tag
515
+ << " start animations returned true " << std::endl;
516
+ #endif
517
+ hasAnimatedChildren = true;
518
+ } else if (subNode->state == MOVED) {
519
+ mutations.push_back(subNode->mutation);
520
+ toBeRemoved.push_back(subNode);
521
+ } else if (shouldRemoveSubviewsWithoutAnimations) {
522
+ maybeCancelAnimation(subNode->tag);
523
+ mutations.push_back(subNode->mutation);
524
+ toBeRemoved.push_back(subNode);
525
+ subNode->state = DELETED;
526
+ nodeForTag_.erase(subNode->tag);
527
+ #ifdef LAYOUT_ANIMATIONS_LOGS
528
+ LOG(INFO) << "delete " << subNode->tag << std::endl;
529
+ #endif
530
+ mutations.push_back(ShadowViewMutation::DeleteMutation(
531
+ subNode->mutation.oldChildShadowView));
532
+ } else {
533
+ subNode->state = WAITING;
534
+ }
535
+ }
536
+
537
+ for (auto &subNode : toBeRemoved) {
538
+ node->removeChildFromUnflattenedTree(subNode);
539
+ }
540
+
541
+ if (node->state == MOVED) {
542
+ auto replacement = std::make_shared<Node>(*node);
543
+ for (auto subNode : node->children) {
544
+ subNode->parent = replacement;
545
+ }
546
+ for (auto subNode : node->unflattenedChildren) {
547
+ subNode->unflattenedParent = replacement;
548
+ }
549
+ nodeForTag_[replacement->tag] = replacement;
550
+ return false;
551
+ }
552
+
553
+ bool wantAnimateExit = hasExitAnimation || hasAnimatedChildren;
554
+
555
+ if (hasExitAnimation) {
556
+ node->state = ANIMATING;
557
+ startExitingAnimation(node->tag, node->mutation);
558
+ } else {
559
+ layoutAnimationsManager_->clearLayoutAnimationConfig(node->tag);
560
+ }
561
+
562
+ return wantAnimateExit;
563
+ }
564
+
565
+ void LayoutAnimationsProxy::updateIndexForMutation(
566
+ ShadowViewMutation &mutation) const {
567
+ if (mutation.index == -1) {
568
+ return;
569
+ }
570
+
571
+ #if REACT_NATIVE_MINOR_VERSION >= 78
572
+ const auto parentTag = mutation.parentTag;
573
+ #else
574
+ const auto parentTag = mutation.parentShadowView.tag;
575
+ #endif // REACT_NATIVE_MINOR_VERSION >= 78
576
+
577
+ if (!nodeForTag_.contains(parentTag)) {
578
+ return;
579
+ }
580
+
581
+ auto parent = nodeForTag_[parentTag];
582
+ int size = 0, prevIndex = -1, offset = 0;
583
+
584
+ for (auto &subNode : parent->children) {
585
+ size += subNode->mutation.index - prevIndex - 1;
586
+ if (mutation.index < size) {
587
+ break;
588
+ }
589
+ offset++;
590
+ prevIndex = subNode->mutation.index;
591
+ }
592
+ #ifdef LAYOUT_ANIMATIONS_LOGS
593
+ int tag = mutation.type == ShadowViewMutation::Insert
594
+ ? mutation.newChildShadowView.tag
595
+ : mutation.oldChildShadowView.tag;
596
+ LOG(INFO) << "update index for " << tag << " in " << parentTag << ": "
597
+ << mutation.index << " -> " << mutation.index + offset << std::endl;
598
+ #endif
599
+ mutation.index += offset;
600
+ }
601
+
602
+ bool LayoutAnimationsProxy::shouldOverridePullTransaction() const {
603
+ return true;
604
+ }
605
+
606
+ void LayoutAnimationsProxy::createLayoutAnimation(
607
+ const ShadowViewMutation &mutation,
608
+ ShadowView &oldView,
609
+ const SurfaceId &surfaceId,
610
+ const int tag) const {
611
+ int count = 1;
612
+ auto layoutAnimationIt = layoutAnimations_.find(tag);
613
+
614
+ if (layoutAnimationIt != layoutAnimations_.end()) {
615
+ auto &layoutAnimation = layoutAnimationIt->second;
616
+ oldView = *layoutAnimation.currentView;
617
+ count = layoutAnimation.count + 1;
618
+ }
619
+
620
+ auto finalView = std::make_shared<ShadowView>(
621
+ mutation.type == ShadowViewMutation::Remove
622
+ ? mutation.oldChildShadowView
623
+ : mutation.newChildShadowView);
624
+ auto currentView = std::make_shared<ShadowView>(oldView);
625
+
626
+ #if REACT_NATIVE_MINOR_VERSION >= 78
627
+ layoutAnimations_.insert_or_assign(
628
+ tag,
629
+ LayoutAnimation{finalView, currentView, mutation.parentTag, {}, count});
630
+ #else
631
+ auto parentView = std::make_shared<ShadowView>(mutation.parentShadowView);
632
+ layoutAnimations_.insert_or_assign(
633
+ tag, LayoutAnimation{finalView, currentView, parentView, {}, count});
634
+ #endif // REACT_NATIVE_MINOR_VERSION >= 78
635
+ }
636
+
637
+ void LayoutAnimationsProxy::startEnteringAnimation(
638
+ const int tag,
639
+ ShadowViewMutation &mutation) const {
640
+ #ifdef LAYOUT_ANIMATIONS_LOGS
641
+ LOG(INFO) << "start entering animation for tag " << tag << std::endl;
642
+ #endif
643
+ auto finalView = std::make_shared<ShadowView>(mutation.newChildShadowView);
644
+ auto current = std::make_shared<ShadowView>(mutation.newChildShadowView);
645
+ #if REACT_NATIVE_MINOR_VERSION < 78
646
+ auto parent = std::make_shared<ShadowView>(mutation.parentShadowView);
647
+ #endif
648
+
649
+ auto &viewProps =
650
+ static_cast<const ViewProps &>(*mutation.newChildShadowView.props);
651
+ auto opacity = viewProps.opacity;
652
+
653
+ uiScheduler_->scheduleOnUI([weakThis = weak_from_this(),
654
+ finalView,
655
+ current,
656
+ #if REACT_NATIVE_MINOR_VERSION < 78
657
+ parent,
658
+ #endif // RE
659
+ mutation,
660
+ opacity,
661
+ tag]() {
662
+ auto strongThis = weakThis.lock();
663
+ if (!strongThis) {
664
+ return;
665
+ }
666
+
667
+ Rect window{};
668
+ {
669
+ auto &mutex = strongThis->mutex;
670
+ auto lock = std::unique_lock<std::recursive_mutex>(mutex);
671
+ strongThis->layoutAnimations_.insert_or_assign(
672
+ tag, LayoutAnimation {
673
+ finalView, current,
674
+ #if REACT_NATIVE_MINOR_VERSION >= 78
675
+ mutation.parentTag,
676
+ #else
677
+ parent,
678
+ #endif // REACT_NATIVE_MINOR_VERSION >= 78
679
+ opacity
680
+ });
681
+ window = strongThis->surfaceManager.getWindow(
682
+ mutation.newChildShadowView.surfaceId);
683
+ }
684
+
685
+ Snapshot values(mutation.newChildShadowView, window);
686
+ auto &uiRuntime = strongThis->uiRuntime_;
687
+ jsi::Object yogaValues(uiRuntime);
688
+ yogaValues.setProperty(uiRuntime, "targetOriginX", values.x);
689
+ yogaValues.setProperty(uiRuntime, "targetGlobalOriginX", values.x);
690
+ yogaValues.setProperty(uiRuntime, "targetOriginY", values.y);
691
+ yogaValues.setProperty(uiRuntime, "targetGlobalOriginY", values.y);
692
+ yogaValues.setProperty(uiRuntime, "targetWidth", values.width);
693
+ yogaValues.setProperty(uiRuntime, "targetHeight", values.height);
694
+ yogaValues.setProperty(uiRuntime, "windowWidth", values.windowWidth);
695
+ yogaValues.setProperty(uiRuntime, "windowHeight", values.windowHeight);
696
+ strongThis->layoutAnimationsManager_->startLayoutAnimation(
697
+ uiRuntime, tag, LayoutAnimationType::ENTERING, yogaValues);
698
+ });
699
+ }
700
+
701
+ void LayoutAnimationsProxy::startExitingAnimation(
702
+ const int tag,
703
+ ShadowViewMutation &mutation) const {
704
+ #ifdef LAYOUT_ANIMATIONS_LOGS
705
+ LOG(INFO) << "start exiting animation for tag " << tag << std::endl;
706
+ #endif
707
+ auto surfaceId = mutation.oldChildShadowView.surfaceId;
708
+
709
+ uiScheduler_->scheduleOnUI(
710
+ [weakThis = weak_from_this(), tag, mutation, surfaceId]() {
711
+ auto strongThis = weakThis.lock();
712
+ if (!strongThis) {
713
+ return;
714
+ }
715
+
716
+ auto oldView = mutation.oldChildShadowView;
717
+ Rect window{};
718
+ {
719
+ auto &mutex = strongThis->mutex;
720
+ auto lock = std::unique_lock<std::recursive_mutex>(mutex);
721
+ strongThis->createLayoutAnimation(mutation, oldView, surfaceId, tag);
722
+ window = strongThis->surfaceManager.getWindow(surfaceId);
723
+ }
724
+
725
+ Snapshot values(oldView, window);
726
+
727
+ auto &uiRuntime = strongThis->uiRuntime_;
728
+ jsi::Object yogaValues(uiRuntime);
729
+ yogaValues.setProperty(uiRuntime, "currentOriginX", values.x);
730
+ yogaValues.setProperty(uiRuntime, "currentGlobalOriginX", values.x);
731
+ yogaValues.setProperty(uiRuntime, "currentOriginY", values.y);
732
+ yogaValues.setProperty(uiRuntime, "currentGlobalOriginY", values.y);
733
+ yogaValues.setProperty(uiRuntime, "currentWidth", values.width);
734
+ yogaValues.setProperty(uiRuntime, "currentHeight", values.height);
735
+ yogaValues.setProperty(uiRuntime, "windowWidth", values.windowWidth);
736
+ yogaValues.setProperty(uiRuntime, "windowHeight", values.windowHeight);
737
+ strongThis->layoutAnimationsManager_->startLayoutAnimation(
738
+ uiRuntime, tag, LayoutAnimationType::EXITING, yogaValues);
739
+ strongThis->layoutAnimationsManager_->clearLayoutAnimationConfig(tag);
740
+ });
741
+ }
742
+
743
+ void LayoutAnimationsProxy::startLayoutAnimation(
744
+ const int tag,
745
+ const ShadowViewMutation &mutation) const {
746
+ #ifdef LAYOUT_ANIMATIONS_LOGS
747
+ LOG(INFO) << "start layout animation for tag " << tag << std::endl;
748
+ #endif
749
+ auto surfaceId = mutation.oldChildShadowView.surfaceId;
750
+
751
+ uiScheduler_->scheduleOnUI([weakThis = weak_from_this(),
752
+ mutation,
753
+ surfaceId,
754
+ tag]() {
755
+ auto strongThis = weakThis.lock();
756
+ if (!strongThis) {
757
+ return;
758
+ }
759
+
760
+ auto oldView = mutation.oldChildShadowView;
761
+ Rect window{};
762
+ {
763
+ auto &mutex = strongThis->mutex;
764
+ auto lock = std::unique_lock<std::recursive_mutex>(mutex);
765
+ strongThis->createLayoutAnimation(mutation, oldView, surfaceId, tag);
766
+ window = strongThis->surfaceManager.getWindow(surfaceId);
767
+ }
768
+
769
+ Snapshot currentValues(oldView, window);
770
+ Snapshot targetValues(mutation.newChildShadowView, window);
771
+
772
+ auto &uiRuntime = strongThis->uiRuntime_;
773
+ jsi::Object yogaValues(uiRuntime);
774
+ yogaValues.setProperty(uiRuntime, "currentOriginX", currentValues.x);
775
+ yogaValues.setProperty(uiRuntime, "currentGlobalOriginX", currentValues.x);
776
+ yogaValues.setProperty(uiRuntime, "currentOriginY", currentValues.y);
777
+ yogaValues.setProperty(uiRuntime, "currentGlobalOriginY", currentValues.y);
778
+ yogaValues.setProperty(uiRuntime, "currentWidth", currentValues.width);
779
+ yogaValues.setProperty(uiRuntime, "currentHeight", currentValues.height);
780
+ yogaValues.setProperty(uiRuntime, "targetOriginX", targetValues.x);
781
+ yogaValues.setProperty(uiRuntime, "targetGlobalOriginX", targetValues.x);
782
+ yogaValues.setProperty(uiRuntime, "targetOriginY", targetValues.y);
783
+ yogaValues.setProperty(uiRuntime, "targetGlobalOriginY", targetValues.y);
784
+ yogaValues.setProperty(uiRuntime, "targetWidth", targetValues.width);
785
+ yogaValues.setProperty(uiRuntime, "targetHeight", targetValues.height);
786
+ yogaValues.setProperty(uiRuntime, "windowWidth", targetValues.windowWidth);
787
+ yogaValues.setProperty(
788
+ uiRuntime, "windowHeight", targetValues.windowHeight);
789
+ strongThis->layoutAnimationsManager_->startLayoutAnimation(
790
+ uiRuntime, tag, LayoutAnimationType::LAYOUT, yogaValues);
791
+ });
792
+ }
793
+
794
+ void LayoutAnimationsProxy::updateOngoingAnimationTarget(
795
+ const int tag,
796
+ const ShadowViewMutation &mutation) const {
797
+ layoutAnimations_[tag].finalView =
798
+ std::make_shared<ShadowView>(mutation.newChildShadowView);
799
+ }
800
+
801
+ void LayoutAnimationsProxy::maybeCancelAnimation(const int tag) const {
802
+ if (!layoutAnimations_.contains(tag)) {
803
+ return;
804
+ }
805
+ layoutAnimations_.erase(tag);
806
+ uiScheduler_->scheduleOnUI([weakThis = weak_from_this(), tag]() {
807
+ auto strongThis = weakThis.lock();
808
+ if (!strongThis) {
809
+ return;
810
+ }
811
+
812
+ auto &uiRuntime = strongThis->uiRuntime_;
813
+ strongThis->layoutAnimationsManager_->cancelLayoutAnimation(uiRuntime, tag);
814
+ });
815
+ }
816
+
817
+ void LayoutAnimationsProxy::transferConfigFromNativeID(
818
+ const std::string nativeIdString,
819
+ const int tag) const {
820
+ if (nativeIdString.empty()) {
821
+ return;
822
+ }
823
+ try {
824
+ auto nativeId = stoi(nativeIdString);
825
+ layoutAnimationsManager_->transferConfigFromNativeID(nativeId, tag);
826
+ } catch (std::invalid_argument) {
827
+ } catch (std::out_of_range) {
828
+ }
829
+ }
830
+
831
+ // When entering animations start, we temporarily set opacity to 0
832
+ // so that we can immediately insert the view at the right position
833
+ // and schedule the animation on the UI thread
834
+ std::shared_ptr<ShadowView> LayoutAnimationsProxy::cloneViewWithoutOpacity(
835
+ facebook::react::ShadowViewMutation &mutation,
836
+ const PropsParserContext &propsParserContext) const {
837
+ auto newView = std::make_shared<ShadowView>(mutation.newChildShadowView);
838
+ folly::dynamic opacity = folly::dynamic::object("opacity", 0);
839
+ auto newProps = getComponentDescriptorForShadowView(*newView).cloneProps(
840
+ propsParserContext, newView->props, RawProps(opacity));
841
+ newView->props = newProps;
842
+ return newView;
843
+ }
844
+
845
+ void LayoutAnimationsProxy::maybeRestoreOpacity(
846
+ LayoutAnimation &layoutAnimation,
847
+ const jsi::Object &newStyle) const {
848
+ if (layoutAnimation.opacity && !newStyle.hasProperty(uiRuntime_, "opacity")) {
849
+ newStyle.setProperty(
850
+ uiRuntime_, "opacity", jsi::Value(*layoutAnimation.opacity));
851
+ layoutAnimation.opacity.reset();
852
+ }
853
+ }
854
+
855
+ void LayoutAnimationsProxy::maybeUpdateWindowDimensions(
856
+ facebook::react::ShadowViewMutation &mutation,
857
+ SurfaceId surfaceId) const {
858
+ if (mutation.type == ShadowViewMutation::Update &&
859
+ !std::strcmp(
860
+ mutation.oldChildShadowView.componentName, RootComponentName)) {
861
+ surfaceManager.updateWindow(
862
+ surfaceId,
863
+ mutation.newChildShadowView.layoutMetrics.frame.size.width,
864
+ mutation.newChildShadowView.layoutMetrics.frame.size.height);
865
+ }
866
+ }
867
+
868
+ } // namespace reanimated
869
+
870
+ #endif // RCT_NEW_ARCH_ENABLED