Merge commit '54016faa7dfdde321023e729636a45b5bb682856' into amgleitman/0.64-merge-head

This commit is contained in:
Adam Gleitman 2021-09-22 13:05:18 -07:00
Родитель 3e0ced8068 54016faa7d
Коммит 100b98f8ab
36 изменённых файлов: 440 добавлений и 311 удалений

Просмотреть файл

@ -80,4 +80,4 @@ untyped-import
untyped-type-import
[version]
^0.133.0
^0.134.0

Просмотреть файл

@ -83,4 +83,4 @@ untyped-import
untyped-type-import
[version]
^0.133.0
^0.134.0

Просмотреть файл

@ -81,4 +81,4 @@ untyped-import
untyped-type-import
[version]
^0.133.0
^0.134.0

Просмотреть файл

@ -5,6 +5,10 @@
LOCAL_PATH := $(call my-dir)
#########################
### callinvokerholder ###
#########################
include $(CLEAR_VARS)
# Header search path for all source files in this module.
@ -15,10 +19,10 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall
LOCAL_STATIC_LIBRARIES = libcallinvoker libreactperfloggerjni
LOCAL_SHARED_LIBRARIES = libfb libfbjni
LOCAL_STATIC_LIBRARIES = libcallinvoker libreactperfloggerjni
# Name of this module.
LOCAL_MODULE := callinvokerholder
@ -27,3 +31,30 @@ LOCAL_SRC_FILES := $(LOCAL_PATH)/ReactCommon/CallInvokerHolder.cpp
# Build the files in this directory as a shared library
include $(BUILD_STATIC_LIBRARY)
##################################
### react_nativemodule_manager ###
##################################
include $(CLEAR_VARS)
# Name of this module.
LOCAL_MODULE := react_nativemodule_manager
# Header search path for all source files in this module.
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ReactCommon
# Header search path for modules that depend on this module
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall
LOCAL_SHARED_LIBRARIES = libfb libfbjni libreact_nativemodule_core
LOCAL_STATIC_LIBRARIES = libcallinvokerholder libreactperfloggerjni
# Compile all local c++ files
LOCAL_SRC_FILES := $(LOCAL_PATH)/ReactCommon/TurboModuleManager.cpp $(LOCAL_PATH)/ReactCommon/OnLoad.cpp
# Build the files in this directory as a shared library
include $(BUILD_SHARED_LIBRARY)

Просмотреть файл

@ -80,7 +80,7 @@ LOCAL_LDLIBS += -landroid
LOCAL_SHARED_LIBRARIES := libreactnativeutilsjni libfolly_json libfb libfbjni libglog_init libyoga
# The static libraries (.a files) that this module depends on.
LOCAL_STATIC_LIBRARIES := libreactnative libcallinvokerholder libruntimeexecutor
LOCAL_STATIC_LIBRARIES := libreactnative libruntimeexecutor libcallinvokerholder
# Name of this module.
#
@ -128,8 +128,11 @@ $(call import-module,callinvoker)
$(call import-module,reactperflogger)
$(call import-module,hermes)
$(call import-module,runtimeexecutor)
$(call import-module,react/nativemodule/core)
include $(REACT_SRC_DIR)/reactperflogger/jni/Android.mk
# TODO (T48588859): Restructure this target to align with dir structure: "react/nativemodule/..."
# Note: Update this only when ready to minimize breaking changes.
include $(REACT_SRC_DIR)/turbomodule/core/jni/Android.mk
ifeq ($(BUILD_FABRIC),true)

Просмотреть файл

@ -49,13 +49,13 @@ Pod::Spec.new do |s|
ss.dependency "glog"
ss.subspec "core" do |sss|
sss.source_files = "react/nativemodule/core/*.{cpp,h}",
"react/nativemodule/core/platform/ios/*.{mm,cpp,h}"
sss.source_files = "react/nativemodule/core/ReactCommon/**/*.{cpp,h}",
"react/nativemodule/core/platform/ios/**/*.{mm,cpp,h}"
end
ss.subspec "samples" do |sss|
sss.source_files = "react/nativemodule/samples/*.{cpp,h}",
"react/nativemodule/samples/platform/ios/*.{mm,cpp,h}"
"react/nativemodule/samples/platform/ios/**/*.{mm,cpp,h}"
sss.dependency "ReactCommon/turbomodule/core", version
end
end

Просмотреть файл

@ -0,0 +1,31 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := react_nativemodule_core
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../ $(LOCAL_PATH)/ReactCommon $(LOCAL_PATH)/platform/android/ReactCommon
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/ReactCommon/*.cpp) $(wildcard $(LOCAL_PATH)/platform/android/ReactCommon/*.cpp)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/platform/android/
LOCAL_SHARED_LIBRARIES := libfbjni libfolly_json libreactnativejni
LOCAL_STATIC_LIBRARIES := libjsi libreactperflogger
LOCAL_CFLAGS := \
-DLOG_TAG=\"ReactNative\"
LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall
include $(BUILD_SHARED_LIBRARY)
$(call import-module,folly)
$(call import-module,jsi)
$(call import-module,reactperflogger)

Просмотреть файл

@ -4,12 +4,12 @@ load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "FBJNI_TARGET", "
rn_xplat_cxx_library(
name = "core",
srcs = glob(
["*.cpp"],
["ReactCommon/**/*.cpp"],
),
header_namespace = "",
exported_headers = subdir_glob(
[
("", "*.h"),
("ReactCommon", "*.h"),
],
prefix = "ReactCommon",
),
@ -26,13 +26,13 @@ rn_xplat_cxx_library(
],
fbandroid_exported_headers = subdir_glob(
[
("platform/android", "*.h"),
("platform/android/ReactCommon", "*.h"),
],
prefix = "ReactCommon",
),
fbandroid_srcs = glob(
[
"platform/android/**/*.cpp",
"platform/android/ReactCommon/*.cpp",
],
),
fbobjc_compiler_flags = [

Просмотреть файл

@ -19,6 +19,7 @@
#include <react/renderer/core/Props.h>
#include <react/renderer/core/RawValue.h>
#include <react/renderer/mounting/MountingCoordinator.h>
#include <react/renderer/mounting/ShadowViewMutation.h>
#include <react/renderer/mounting/Differentiator.h>
#include <react/renderer/mounting/ShadowTreeRevision.h>
@ -396,9 +397,12 @@ void LayoutAnimationKeyFrameManager::
adjustImmediateMutationIndicesForDelayedMutations(
SurfaceId surfaceId,
ShadowViewMutation &mutation,
ShadowViewMutationList *auxiliaryMutations) const {
ConsecutiveAdjustmentMetadata &consecutiveAdjustmentMetadata,
bool skipLastAnimation,
bool lastAnimationOnly) const {
bool isRemoveMutation = mutation.type == ShadowViewMutation::Type::Remove;
assert(isRemoveMutation || mutation.type == ShadowViewMutation::Type::Insert);
bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert;
assert(isRemoveMutation || isInsertMutation);
// TODO: turn all of this into a lambda and share code?
if (mutatedViewIsVirtual(mutation)) {
@ -412,36 +416,35 @@ void LayoutAnimationKeyFrameManager::
"[IndexAdjustment] Calling adjustImmediateMutationIndicesForDelayedMutations for:",
mutation);
// When adjusting INSERTs, we want to batch adjacent inserts so they're all
// adjacent to each other in the resulting view. For instance, if we're
// processing INSERTS into positions 2,3,4,5,6, etc, it is possible that
// delayed mutations would otherwise cause the inserts to be adjusted to
// positions 2, 4, 6, 8... etc, creating a striping effect. We want to prevent
// that.
if (isInsertMutation &&
mutation.parentShadowView.tag ==
consecutiveAdjustmentMetadata.lastAdjustedParent &&
mutation.index == (consecutiveAdjustmentMetadata.lastIndexOriginal + 1)) {
PrintMutationInstruction(
std::string(
"[IndexAdjustment] adjustImmediateMutationIndicesForDelayedMutations: Adjusting consecutive INSERT mutation by ") +
std::to_string(consecutiveAdjustmentMetadata.lastAdjustedDelta),
mutation);
consecutiveAdjustmentMetadata.lastIndexOriginal = mutation.index;
mutation.index += consecutiveAdjustmentMetadata.lastAdjustedDelta;
return;
}
// First, collect all final mutations that could impact this immediate
// mutation.
std::vector<ShadowViewMutation *> candidateMutations{};
if (auxiliaryMutations != nullptr) {
for (auto &auxMutation : *auxiliaryMutations) {
if (auxMutation.parentShadowView.tag != mutation.parentShadowView.tag) {
continue;
}
if (auxMutation.type != ShadowViewMutation::Type::Remove) {
continue;
}
if (mutatedViewIsVirtual(auxMutation)) {
continue;
}
if (auxMutation.oldChildShadowView.tag ==
(isRemoveMutation ? mutation.oldChildShadowView.tag
: mutation.newChildShadowView.tag)) {
continue;
}
PrintMutationInstructionRelative(
"[IndexAdjustment] adjustImmediateMutationIndicesForDelayedMutations auxiliary CANDIDATE for:",
mutation,
auxMutation);
candidateMutations.push_back(&auxMutation);
}
}
for (auto &inflightAnimation : inflightAnimations_) {
for (auto inflightAnimationIt =
inflightAnimations_.rbegin() + (skipLastAnimation ? 1 : 0);
inflightAnimationIt != inflightAnimations_.rend();
inflightAnimationIt++) {
auto &inflightAnimation = *inflightAnimationIt;
if (inflightAnimation.surfaceId != surfaceId) {
continue;
}
@ -464,9 +467,6 @@ void LayoutAnimationKeyFrameManager::
continue;
}
if (animatedKeyFrame.type != AnimationConfigurationType::Noop) {
continue;
}
if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) {
continue;
}
@ -491,21 +491,33 @@ void LayoutAnimationKeyFrameManager::
delayedMutation);
candidateMutations.push_back(&delayedMutation);
}
if (lastAnimationOnly) {
break;
}
}
// While the mutation keeps being affected, keep checking. We use the vector
// so we only perform one adjustment per delayed mutation. See comments at
// bottom of adjustDelayedMutationIndicesForMutation for further explanation.
bool changed = true;
int adjustedDelta = 0;
if (isInsertMutation) {
consecutiveAdjustmentMetadata.lastAdjustedParent =
mutation.parentShadowView.tag;
consecutiveAdjustmentMetadata.lastIndexOriginal = mutation.index;
}
while (changed) {
changed = false;
candidateMutations.erase(
std::remove_if(
candidateMutations.begin(),
candidateMutations.end(),
[&mutation, &changed](ShadowViewMutation *candidateMutation) {
if (candidateMutation->index <= mutation.index) {
[&](ShadowViewMutation *candidateMutation) {
bool indexConflicts = candidateMutation->index <= mutation.index;
if (indexConflicts) {
mutation.index++;
adjustedDelta++;
changed = true;
PrintMutationInstructionRelative(
"[IndexAdjustment] adjustImmediateMutationIndicesForDelayedMutations: Adjusting mutation UPWARD",
@ -517,19 +529,17 @@ void LayoutAnimationKeyFrameManager::
}),
candidateMutations.end());
}
}
void LayoutAnimationKeyFrameManager::
adjustLastAnimationDelayedMutationIndicesForMutation(
SurfaceId surfaceId,
ShadowViewMutation const &mutation) const {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation, true);
if (isInsertMutation) {
consecutiveAdjustmentMetadata.lastAdjustedDelta = adjustedDelta;
} else {
consecutiveAdjustmentMetadata.lastAdjustedParent = -1;
}
}
void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
SurfaceId surfaceId,
ShadowViewMutation const &mutation,
bool lastAnimationOnly) const {
bool skipLastAnimation) const {
bool isRemoveMutation = mutation.type == ShadowViewMutation::Type::Remove;
bool isInsertMutation = mutation.type == ShadowViewMutation::Type::Insert;
assert(isRemoveMutation || isInsertMutation);
@ -545,7 +555,8 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
// mutation.
std::vector<ShadowViewMutation *> candidateMutations{};
for (auto inflightAnimationIt = inflightAnimations_.rbegin();
for (auto inflightAnimationIt =
inflightAnimations_.rbegin() + (skipLastAnimation ? 1 : 0);
inflightAnimationIt != inflightAnimations_.rend();
inflightAnimationIt++) {
auto &inflightAnimation = *inflightAnimationIt;
@ -572,9 +583,6 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
continue;
}
if (animatedKeyFrame.type != AnimationConfigurationType::Noop) {
continue;
}
if (!animatedKeyFrame.finalMutationForKeyFrame.has_value()) {
continue;
}
@ -587,19 +595,19 @@ void LayoutAnimationKeyFrameManager::adjustDelayedMutationIndicesForMutation(
continue;
}
if (!mutatedViewIsVirtual(*animatedKeyFrame.finalMutationForKeyFrame) &&
finalAnimationMutation.type == ShadowViewMutation::Type::Remove) {
PrintMutationInstructionRelative(
"[IndexAdjustment] adjustDelayedMutationIndicesForMutation: CANDIDATE:",
mutation,
*animatedKeyFrame.finalMutationForKeyFrame);
candidateMutations.push_back(
animatedKeyFrame.finalMutationForKeyFrame.get_pointer());
if (finalAnimationMutation.type != ShadowViewMutation::Type::Remove) {
continue;
}
if (mutatedViewIsVirtual(*animatedKeyFrame.finalMutationForKeyFrame)) {
continue;
}
}
if (lastAnimationOnly) {
break;
PrintMutationInstructionRelative(
"[IndexAdjustment] adjustDelayedMutationIndicesForMutation: CANDIDATE:",
mutation,
*animatedKeyFrame.finalMutationForKeyFrame);
candidateMutations.push_back(
animatedKeyFrame.finalMutationForKeyFrame.get_pointer());
}
}
@ -685,18 +693,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
continue;
}
// bool hasFinalMutation =
// animatedKeyFrame.finalMutationForKeyFrame.hasValue();
// int finalMutationTag = hasFinalMutation
// ? (((*animatedKeyFrame.finalMutationForKeyFrame).type ==
// ShadowViewMutation::Create ||
// (*animatedKeyFrame.finalMutationForKeyFrame).type ==
// ShadowViewMutation::Insert)
// ? (*animatedKeyFrame.finalMutationForKeyFrame)
// .newChildShadowView.tag
// : (*animatedKeyFrame.finalMutationForKeyFrame)
// .oldChildShadowView.tag)
// : -1;
bool conflicting = animatedKeyFrame.tag == baselineShadowView.tag ||
((mutation.type == ShadowViewMutation::Type::Delete ||
mutation.type == ShadowViewMutation::Type::Create) &&
@ -704,20 +700,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
finalMutationTag == baselineShadowView.tag*/
;
// In some bizarre situations, there can be an ongoing Delete
// animation, and then a conflicting mutation to create and/or delete
// the same tag. In actuality this "bizarre" situation is just the
// animation of repeatedly flattening and unflattening a view; but
// it's not clear how to gracefully recover from this, so we just
// ensure that the Deletion is never executed in those cases. In these
// cases, the ongoing animation will stop; the view still exists; and
// then either a "Create" or "delete" animation will be recreated and
// executed for that tag.
bool shouldExecuteFinalMutation =
!(animatedKeyFrame.finalMutationForKeyFrame.hasValue() &&
(*animatedKeyFrame.finalMutationForKeyFrame).type ==
ShadowViewMutation::Delete);
// Conflicting animation detected: if we're mutating a tag under
// animation, or deleting the parent of a tag under animation, or
// reparenting.
@ -735,7 +717,9 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
animatedKeyFrame.invalidated = true;
if (shouldExecuteFinalMutation) {
if (animatedKeyFrame.finalMutationForKeyFrame.has_value() &&
!mutatedViewIsVirtual(
*animatedKeyFrame.finalMutationForKeyFrame)) {
conflictingAnimations.push_back(std::make_tuple(
animatedKeyFrame, *mutationConfig, &inflightAnimation));
}
@ -748,7 +732,7 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
*animatedKeyFrame.finalMutationForKeyFrame);
} else {
PrintMutationInstruction(
"Found mutation that conflicts with existing in-flight animation:",
"Found mutation that conflicts with existing in-flight animation (no final mutation):",
mutation);
}
#endif
@ -756,13 +740,6 @@ LayoutAnimationKeyFrameManager::getAndEraseConflictingAnimations(
// Delete from existing animation
it = inflightAnimation.keyFrames.erase(it);
} else {
//#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
// if (hasFinalMutation) {
// PrintMutationInstructionRelative("getAndEraseConflictingAnimations,
// NOT erasing non-conflicting mutation of ", mutation,
// *animatedKeyFrame.finalMutationForKeyFrame);
// }
//#endif
it++;
}
}
@ -844,7 +821,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
if (keyframe.invalidated) {
continue;
}
if (keyframe.finalMutationForKeyFrame) {
if (keyframe.finalMutationForKeyFrame &&
!mutatedViewIsVirtual(*keyframe.finalMutationForKeyFrame)) {
std::string msg = "Animation " + std::to_string(i) + " keyframe " +
std::to_string(j) + ": Final Animation";
PrintMutationInstruction(msg, *keyframe.finalMutationForKeyFrame);
@ -899,15 +877,23 @@ LayoutAnimationKeyFrameManager::pullTransaction(
// being moves on the Differ level, since we know that there? We could use
// TinyMap here, but it's not exposed by Differentiator (yet).
std::vector<Tag> insertedTags;
std::vector<Tag> createdTags;
std::vector<Tag> deletedTags;
std::vector<Tag> reparentedTags; // tags that are deleted and recreated
std::unordered_map<Tag, ShadowViewMutation> movedTags;
std::vector<Tag> reparentedTags;
for (const auto &mutation : mutations) {
if (mutation.type == ShadowViewMutation::Type::Insert) {
insertedTags.push_back(mutation.newChildShadowView.tag);
}
if (mutation.type == ShadowViewMutation::Type::Delete) {
deletedTags.push_back(mutation.oldChildShadowView.tag);
}
if (mutation.type == ShadowViewMutation::Type::Create) {
createdTags.push_back(mutation.newChildShadowView.tag);
if (std::find(
deletedTags.begin(),
deletedTags.end(),
mutation.newChildShadowView.tag) != deletedTags.end()) {
reparentedTags.push_back(mutation.newChildShadowView.tag);
}
}
}
@ -954,26 +940,15 @@ LayoutAnimationKeyFrameManager::pullTransaction(
// This should eventually be optimized out of the diffing algorithm, but
// for now we detect reparenting and prevent the corresponding
// Delete/Create instructions from being animated.
bool isReparented =
(mutation.type == ShadowViewMutation::Delete &&
std::find(
createdTags.begin(),
createdTags.end(),
mutation.oldChildShadowView.tag) != createdTags.end()) ||
(mutation.type == ShadowViewMutation::Create &&
std::find(
reparentedTags.begin(),
reparentedTags.end(),
mutation.newChildShadowView.tag) != reparentedTags.end());
bool isReparented = std::find(
reparentedTags.begin(),
reparentedTags.end(),
baselineShadowView.tag) != reparentedTags.end();
if (isRemoveReinserted) {
movedTags.insert({mutation.oldChildShadowView.tag, mutation});
}
if (isReparented && mutation.type == ShadowViewMutation::Delete) {
reparentedTags.push_back(mutation.oldChildShadowView.tag);
}
// Inserts that follow a "remove" of the same tag should be treated as
// an update (move) animation.
bool wasInsertedTagRemoved = false;
@ -1205,30 +1180,31 @@ LayoutAnimationKeyFrameManager::pullTransaction(
}
#ifdef RN_SHADOW_TREE_INTROSPECTION
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
{
std::stringstream ss(getDebugDescription(immediateMutations, {}));
std::string to;
while (std::getline(ss, to, '\n')) {
LOG(ERROR)
<< "LayoutAnimationKeyFrameManager.cpp: got IMMEDIATE list: Line: "
<< to;
int idx = 0;
for (auto &mutation : immediateMutations) {
PrintMutationInstruction(
std::string("IMMEDIATE list: ") + std::to_string(idx) + "/" +
std::to_string(immediateMutations.size()),
mutation);
idx++;
}
}
{
int idx = 0;
for (const auto &keyframe : keyFramesToAnimate) {
if (keyframe.finalMutationForKeyFrame) {
std::stringstream ss(
getDebugDescription(*keyframe.finalMutationForKeyFrame, {}));
std::string to;
while (std::getline(ss, to, '\n')) {
LOG(ERROR)
<< "LayoutAnimationKeyFrameManager.cpp: got FINAL list: Line: "
<< to;
}
if (keyframe.finalMutationForKeyFrame.has_value()) {
PrintMutationInstruction(
std::string("FINAL list: ") + std::to_string(idx) + "/" +
std::to_string(keyFramesToAnimate.size()),
*keyframe.finalMutationForKeyFrame);
}
idx++;
}
}
#endif
#endif
auto finalConflictingMutations = ShadowViewMutationList{};
@ -1247,59 +1223,121 @@ LayoutAnimationKeyFrameManager::pullTransaction(
finalConflictingMutations.end(),
&shouldFirstComeBeforeSecondMutation);
// Use "final conflicting mutations" to adjust delayed mutations *before*
// we adjust immediate mutations based on delayed mutations
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust delayed mutations based on finalConflictingMutations";
#endif
for (auto &mutation : finalConflictingMutations) {
if (mutation.type == ShadowViewMutation::Remove ||
mutation.type == ShadowViewMutation::Insert) {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// Adjust keyframes based on already-delayed, existing animations, before
// queueing. We adjust them as if finalConflictingMutations have already
// been executed - in all cases, finalConflictingMutations will be
// executed before any of these delayed mutations are.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust immediate keyFramesToAnimate based on delayed mutations and finalConflictingMutations";
#endif
for (auto &keyframe : keyFramesToAnimate) {
if (keyframe.finalMutationForKeyFrame.has_value()) {
auto &delayedMutation = *keyframe.finalMutationForKeyFrame;
if (delayedMutation.type == ShadowViewMutation::Type::Remove) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, delayedMutation /*, &finalConflictingMutations*/);
}
}
}
// REMOVE mutations from this animation batch *cannot* be impacted by
// other REMOVEs from this batch, since they're already taken into
// account. INSERTs can impact delayed REMOVEs; see below.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust immediateMutations REMOVEs only, based on previously delayed mutations, without most-recent animation";
#endif
std::stable_sort(
immediateMutations.begin(),
immediateMutations.end(),
&shouldFirstComeBeforeSecondRemovesOnly);
for (auto &mutation : immediateMutations) {
if (mutation.type == ShadowViewMutation::Type::Remove) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation);
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
animation.keyFrames = keyFramesToAnimate;
inflightAnimations_.push_back(std::move(animation));
// At this point, we have the following information and knowledge graph:
// Knowledge Graph:
// [ImmediateMutations] -> assumes [FinalConflicting], [FrameDelayed],
// [Delayed] already executed [FrameDelayed] -> assumes
// [FinalConflicting], [Delayed] already executed [FinalConflicting] -> is
// adjusted based on [Delayed], no dependency on [FinalConflicting],
// [FrameDelayed] [Delayed] -> assumes [FinalConflicting],
// [ImmediateMutations] not executed yet
ConsecutiveAdjustmentMetadata consecutiveAdjustmentMetadata{};
// Adjust [Delayed] based on [FinalConflicting]
// Knowledge Graph:
// [ImmediateMutations] -> assumes [FinalConflicting], [FrameDelayed],
// [Delayed] already executed [FrameDelayed] -> assumes
// [FinalConflicting], [Delayed] already executed [FinalConflicting] -> is
// adjusted based on [Delayed], no dependency on [FinalConflicting],
// [FrameDelayed] [Delayed] -> adjusted for [FinalConflicting]; assumes
// [ImmediateMutations] not executed yet
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) << "Adjust [Delayed] based on [FinalConflicting]";
#endif
for (auto &mutation : finalConflictingMutations) {
if (mutation.type == ShadowViewMutation::Type::Insert ||
mutation.type == ShadowViewMutation::Type::Remove) {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation, true);
}
}
// Adjust [FrameDelayed] based on [Delayed]
// Knowledge Graph:
// [ImmediateExecutions] -> assumes [FinalConflicting], [Delayed],
// [FrameDelayed] already executed [FrameDelayed] -> adjusted for
// [Delayed]; assumes [FinalConflicting] already executed
// [FinalConflicting] -> is adjusted based on [Delayed], no dependency on
// [FinalConflicting], [FrameDelayed] [Delayed] -> adjusted for
// [FinalConflicting]; assumes [ImmediateExecutions] not executed yet
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) << "Adjust [FrameDelayed] based on [Delayed]";
#endif
for (auto &keyframe : inflightAnimations_.back().keyFrames) {
if (keyframe.finalMutationForKeyFrame.has_value()) {
auto &mutation = *keyframe.finalMutationForKeyFrame;
if (mutation.type == ShadowViewMutation::Type::Insert ||
mutation.type == ShadowViewMutation::Type::Remove) {
// When adjusting, skip adjusting against last animation - because
// all `mutation`s here come from the last animation, so we can't
// adjust a batch against itself.
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation, consecutiveAdjustmentMetadata, true);
}
}
}
// Adjust [ImmediateExecutions] based on [Delayed]
// Knowledge Graph:
// [ImmediateExecutions] -> adjusted for [FrameDelayed], [Delayed];
// assumes [FinalConflicting] already executed [FrameDelayed] -> adjusted
// for [Delayed]; assumes [FinalConflicting] already executed
// [FinalConflicting] -> is adjusted based on [Delayed], no dependency on
// [FinalConflicting], [FrameDelayed] [Delayed] -> adjusted for
// [FinalConflicting]; assumes [ImmediateExecutions] not executed yet
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) << "Adjust [ImmediateExecutions] based on [Delayed]";
#endif
consecutiveAdjustmentMetadata = ConsecutiveAdjustmentMetadata{};
for (auto &mutation : immediateMutations) {
// Note: when adjusting [ImmediateExecutions] based on [FrameDelayed],
// we need only adjust Inserts. Since inserts are executed
// highest-index-first, lower indices being delayed does not impact the
// higher-index removals; and conversely, higher indices being delayed
// cannot impact lower index removal, regardless of order.
if (mutation.type == ShadowViewMutation::Type::Insert ||
mutation.type == ShadowViewMutation::Type::Remove) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId,
mutation,
consecutiveAdjustmentMetadata,
mutation.type == ShadowViewMutation::Type::Remove);
}
}
// Adjust [Delayed] based on [ImmediateExecutions] and [FinalConflicting]
// Knowledge Graph:
// [ImmediateExecutions] -> adjusted for [FrameDelayed], [Delayed];
// assumes [FinalConflicting] already executed [FrameDelayed] -> adjusted
// for [Delayed]; assumes [FinalConflicting] already executed
// [FinalConflicting] -> is adjusted based on [Delayed], no dependency on
// [FinalConflicting], [FrameDelayed] [Delayed] -> adjusted for
// [FinalConflicting], [ImmediateExecutions]
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust [Delayed] based on [ImmediateExecutions] and [FinalConflicting]";
#endif
for (auto &mutation : immediateMutations) {
if (mutation.type == ShadowViewMutation::Type::Insert ||
mutation.type == ShadowViewMutation::Type::Remove) {
// Here we need to adjust both Delayed and FrameDelayed mutations.
// Delayed Removes can be impacted by non-delayed Inserts from the
// same frame.
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// If the knowledge graph progression above is correct, it is now safe to
// execute finalConflictingMutations and immediateMutations in that order,
// and to queue the delayed animations from this frame.
//
// Execute the conflicting, delayed operations immediately. Any UPDATE
// operations that smoothly transition into another animation will be
// overridden by generated UPDATE operations at the end of the list, and
@ -1307,60 +1345,24 @@ LayoutAnimationKeyFrameManager::pullTransaction(
// Additionally, this should allow us to avoid performing index adjustment
// between this list of conflicting animations and the batch we're about
// to execute.
mutations = ShadowViewMutationList{};
for (auto &mutation : finalConflictingMutations) {
mutations.push_back(mutation);
}
// Before computing mutations based on animations / final mutations for
// this frame, we want to update any pending final mutations since they
// will execute *after* this batch of immediate mutations. Important case
// to consider (as an example, there are other interesting cases): there's
// a delayed "Remove", then an immediate "insert" is scheduled for an
// earlier index with the same parent. The remove needs to be adjusted
// upward here. Conversely, Inserts at later indices will assume the
// remove has already been executed, which may not be the case.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "Adjust immediateMutations and delayed mutations, including just-queued animations, based on each one";
#endif
for (auto &mutation : immediateMutations) {
if (mutation.type == ShadowViewMutation::Type::Remove) {
adjustLastAnimationDelayedMutationIndicesForMutation(
surfaceId, mutation);
} else if (mutation.type == ShadowViewMutation::Type::Insert) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation);
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// These will be executed immediately. These should already be sorted
// properly.
mutations.insert(
mutations.end(),
finalConflictingMutations.insert(
finalConflictingMutations.end(),
immediateMutations.begin(),
immediateMutations.end());
mutations = finalConflictingMutations;
} /* if (currentAnimation) */ else {
// The ShadowTree layer doesn't realize that certain operations have been
// delayed, so we must adjust all Remove and Insert operations based on
// what else has been deferred, whether we are executing this immediately
// or later.
for (auto &mutation : mutations) {
if (mutation.type == ShadowViewMutation::Type::Remove ||
mutation.type == ShadowViewMutation::Type::Insert) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation);
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// If there's no "next" animation, make sure we queue up "final"
// operations from all ongoing, conflicting animations.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR) << "No Animation: Queue up final conflicting animations";
#endif
ShadowViewMutationList finalMutationsForConflictingAnimations{};
for (auto &conflictingKeyframeTuple : conflictingAnimations) {
auto &keyFrame = std::get<0>(conflictingKeyframeTuple);
if (keyFrame.finalMutationForKeyFrame.hasValue()) {
PrintMutationInstruction(
"No Animation: Queueing final mutation instruction",
*keyFrame.finalMutationForKeyFrame);
finalMutationsForConflictingAnimations.push_back(
*keyFrame.finalMutationForKeyFrame);
}
@ -1373,6 +1375,45 @@ LayoutAnimationKeyFrameManager::pullTransaction(
finalMutationsForConflictingAnimations.end(),
&shouldFirstComeBeforeSecondMutation);
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "No Animation: Adjust delayed mutations based on all finalMutationsForConflictingAnimations";
#endif
for (auto &mutation : finalMutationsForConflictingAnimations) {
if (mutation.type == ShadowViewMutation::Type::Remove ||
mutation.type == ShadowViewMutation::Type::Insert) {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// The ShadowTree layer doesn't realize that certain operations have been
// delayed, so we must adjust all Remove and Insert operations based on
// what else has been deferred, whether we are executing this immediately
// or later.
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "No Animation: Adjust mutations based on remaining delayed mutations";
#endif
ConsecutiveAdjustmentMetadata consecutiveAdjustmentMetadata{};
for (auto &mutation : mutations) {
if (mutation.type == ShadowViewMutation::Type::Remove ||
mutation.type == ShadowViewMutation::Type::Insert) {
adjustImmediateMutationIndicesForDelayedMutations(
surfaceId, mutation, consecutiveAdjustmentMetadata);
}
}
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
<< "No Animation: Adjust delayed mutations based on all immediate mutations";
#endif
for (auto &mutation : mutations) {
if (mutation.type == ShadowViewMutation::Type::Remove ||
mutation.type == ShadowViewMutation::Type::Insert) {
adjustDelayedMutationIndicesForMutation(surfaceId, mutation);
}
}
// Append mutations to this list and swap - so that the final
// conflicting mutations happen before any other mutations
finalMutationsForConflictingAnimations.insert(
@ -1392,13 +1433,6 @@ LayoutAnimationKeyFrameManager::pullTransaction(
ShadowViewMutationList mutationsForAnimation{};
animationMutationsForFrame(surfaceId, mutationsForAnimation, now);
// Erase any remaining animations that conflict with these mutations
// In some marginal cases, a DELETE animation can be queued up and a final
// DELETE mutation be executed by the animation driver. These cases deserve
// further scrutiny, but for now to prevent crashes, just make sure the queued
// DELETE operations are removed.
getAndEraseConflictingAnimations(surfaceId, mutationsForAnimation, true);
// If any delayed removes were executed, update remaining delayed keyframes
#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING
LOG(ERROR)
@ -1431,7 +1465,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
if (keyframe.invalidated) {
continue;
}
if (keyframe.finalMutationForKeyFrame) {
if (keyframe.finalMutationForKeyFrame &&
!mutatedViewIsVirtual(*keyframe.finalMutationForKeyFrame)) {
std::string msg = "Animation " + std::to_string(i) + " keyframe " +
std::to_string(j) + ": Final Animation";
PrintMutationInstruction(msg, *keyframe.finalMutationForKeyFrame);

Просмотреть файл

@ -110,6 +110,12 @@ struct AnimationKeyFrame {
bool invalidated{false};
};
struct ConsecutiveAdjustmentMetadata {
Tag lastAdjustedParent{-1};
int lastAdjustedDelta{0};
int lastIndexOriginal{0};
};
class LayoutAnimationCallbackWrapper {
public:
LayoutAnimationCallbackWrapper(jsi::Function &&callback)
@ -212,16 +218,14 @@ class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate,
void adjustImmediateMutationIndicesForDelayedMutations(
SurfaceId surfaceId,
ShadowViewMutation &mutation,
ShadowViewMutationList *auxiliaryMutations = nullptr) const;
ConsecutiveAdjustmentMetadata &consecutiveAdjustmentMetadata,
bool skipLastAnimation = false,
bool lastAnimationOnly = false) const;
void adjustDelayedMutationIndicesForMutation(
SurfaceId surfaceId,
ShadowViewMutation const &mutation,
bool lastAnimationOnly = false) const;
void adjustLastAnimationDelayedMutationIndicesForMutation(
SurfaceId surfaceId,
ShadowViewMutation const &mutation) const;
bool skipLastAnimation = false) const;
std::vector<std::tuple<AnimationKeyFrame, AnimationConfig, LayoutAnimation *>>
getAndEraseConflictingAnimations(

Просмотреть файл

@ -38,12 +38,17 @@ static jsi::Value linesMeasurementsPayload(
void ParagraphEventEmitter::onTextLayout(
LinesMeasurements const &linesMeasurements) const {
dispatchEvent(
"textLayout",
[linesMeasurements](jsi::Runtime &runtime) {
return linesMeasurementsPayload(runtime, linesMeasurements);
},
EventPriority::AsynchronousBatched);
{
std::lock_guard<std::mutex> guard(linesMeasurementsMutex_);
if (linesMeasurementsMetrics_ == linesMeasurements) {
return;
}
linesMeasurementsMetrics_ = linesMeasurements;
}
dispatchEvent("textLayout", [linesMeasurements](jsi::Runtime &runtime) {
return linesMeasurementsPayload(runtime, linesMeasurements);
});
}
} // namespace react

Просмотреть файл

@ -18,6 +18,10 @@ class ParagraphEventEmitter : public ViewEventEmitter {
using ViewEventEmitter::ViewEventEmitter;
void onTextLayout(LinesMeasurements const &linesMeasurements) const;
private:
mutable std::mutex linesMeasurementsMutex_;
mutable LinesMeasurements linesMeasurementsMetrics_;
};
} // namespace react

Просмотреть файл

@ -164,18 +164,6 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
updateStateIfNeeded(content);
if (content.attachments.empty()) {
#ifndef ANDROID
if (getConcreteProps().onTextLayout) {
// `onTextLayout` needs to be called even if text is empty
// to be compatible with Paper.
getConcreteEventEmitter().onTextLayout({});
}
#endif
// No attachments, nothing to layout.
return;
}
auto measurement = textLayoutManager_->measure(
AttributedStringBox{content.attributedString},
content.paragraphAttributes,
@ -191,6 +179,11 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
}
#endif
if (content.attachments.empty()) {
// No attachments to layout.
return;
}
// Iterating on attachments, we clone shadow nodes and moving
// `paragraphShadowNode` that represents clones of `this` object.
auto paragraphShadowNode = static_cast<ParagraphShadowNode *>(this);

Просмотреть файл

@ -1076,11 +1076,7 @@ static void calculateShadowViewMutationsV2(
for (auto &oldFlattenedNode : oldFlattenedNodes) {
auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find(
oldFlattenedNode.shadowView.tag);
if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) {
// Node unvisited - delete it entirely
deleteMutations.push_back(ShadowViewMutation::DeleteMutation(
oldFlattenedNode.shadowView));
} else {
if (unvisitedOldChildPairIt == unvisitedOldChildPairs.end()) {
// Node was visited - make sure to remove it from
// "newRemainingPairs" map
auto newRemainingIt =
@ -1202,11 +1198,7 @@ static void calculateShadowViewMutationsV2(
for (auto &oldFlattenedNode : oldFlattenedNodes) {
auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find(
oldFlattenedNode.shadowView.tag);
if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) {
// Node unvisited - delete it entirely
deleteMutations.push_back(ShadowViewMutation::DeleteMutation(
oldFlattenedNode.shadowView));
} else {
if (unvisitedOldChildPairIt == unvisitedOldChildPairs.end()) {
// Node was visited - make sure to remove it from
// "newRemainingPairs" map
auto newRemainingIt =

Просмотреть файл

@ -83,13 +83,15 @@ void StubViewTree::mutate(
STUB_VIEW_ASSERT(registry.find(parentTag) != registry.end());
auto parentStubView = registry[parentTag];
auto childTag = mutation.newChildShadowView.tag;
STUB_VIEW_LOG({
LOG(ERROR) << "StubView: Insert: " << childTag << " into "
<< parentTag << " at " << mutation.index;
});
STUB_VIEW_ASSERT(registry.find(childTag) != registry.end());
auto childStubView = registry[childTag];
childStubView->update(mutation.newChildShadowView);
STUB_VIEW_LOG({
LOG(ERROR) << "StubView: Insert: " << childTag << " into "
<< parentTag << " at " << mutation.index << "("
<< parentStubView->children.size() << " children)";
});
STUB_VIEW_ASSERT(parentStubView->children.size() >= mutation.index);
parentStubView->children.insert(
parentStubView->children.begin() + mutation.index, childStubView);
break;
@ -106,6 +108,7 @@ void StubViewTree::mutate(
<< parentTag << " at index " << mutation.index << " with "
<< parentStubView->children.size() << " children";
});
STUB_VIEW_ASSERT(parentStubView->children.size() > mutation.index);
STUB_VIEW_ASSERT(registry.find(childTag) != registry.end());
auto childStubView = registry[childTag];
bool childIsCorrect =
@ -130,8 +133,15 @@ void StubViewTree::mutate(
STUB_VIEW_LOG({
LOG(ERROR) << "StubView: Update: " << mutation.newChildShadowView.tag;
});
// We don't have a strict requirement that oldChildShadowView has any
// data. In particular, LayoutAnimations can produce UPDATEs with only a
// new node.
STUB_VIEW_ASSERT(
mutation.newChildShadowView.tag == mutation.oldChildShadowView.tag);
mutation.newChildShadowView.tag ==
mutation.oldChildShadowView.tag ||
mutation.oldChildShadowView.tag == 0);
STUB_VIEW_ASSERT(
registry.find(mutation.newChildShadowView.tag) != registry.end());
auto stubView = registry[mutation.newChildShadowView.tag];

Просмотреть файл

@ -8,5 +8,24 @@
#include "TextMeasureCache.h"
namespace facebook {
namespace react {} // namespace react
namespace react {
bool LineMeasurement::operator==(LineMeasurement const &rhs) const {
return std::tie(
this->text,
this->frame,
this->descender,
this->capHeight,
this->ascender,
this->xHeight) ==
std::tie(
rhs.text,
rhs.frame,
rhs.descender,
rhs.capHeight,
rhs.ascender,
rhs.xHeight);
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -23,6 +23,8 @@ struct LineMeasurement {
Float capHeight;
Float ascender;
Float xHeight;
bool operator==(LineMeasurement const &rhs) const;
};
using LinesMeasurements = std::vector<LineMeasurement>;

Просмотреть файл

@ -123,7 +123,7 @@
"ws": "^6.1.4"
},
"devDependencies": {
"flow-bin": "^0.133.0",
"flow-bin": "^0.134.0",
"react": "16.13.1"
},
"detox": {

Просмотреть файл

@ -510,8 +510,8 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
DoubleConversion: 2b45d0f8e156a5b02354c8a4062de64d41ccb4e0
FBLazyVector: 6840df244b2930eadc86dfddd63dd586de8fbf4b
FBReactNativeSpec: 6a5b272a87d8fba0a0267169a9c69104a33f4104
FBLazyVector: a2e74b28704250f5c2840b8ac0c36a550fc58c5c
FBReactNativeSpec: f32ba61faf46d74f93ee06325baab8f1f160cd4d
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
@ -522,33 +522,33 @@ SPEC CHECKSUMS:
glog: 789873d01e4b200777d0a09bc23d548446758699
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
RCT-Folly: 55d0039b24e192081ec0b2257f7bd9f42e382fb7
RCTRequired: 8aab7fd83973da16ad4a7c320ab60d95daaf3a49
RCTTypeSafety: 1b9fcfa91c95a819c8ee11b2d78792a1a0c9f008
React: 0d0bbc598d4e4a42c2d8f501e2d85bf68f4b4c58
React-callinvoker: 7171dcdb2310bc9843acfd9e9d1ad4432f069343
React-Core: f9261d49de3292529f426b0337589cf85cbd2be5
React-CoreModules: 6cd34c4feb240e2243a2b766ac42b4922a43f272
React-cxxreact: 1d94eae472a7d96512c9616b79755f17b7d9e60d
React-jsi: 738aad53cef29cda532eb60393636882b048aa63
React-jsiexecutor: 4f307d9cf526c904c6a29a492ee0d0a56a3955ac
React-jsinspector: 9a11ad30cee910a8f9af0f93863b3583512ea3ca
React-perflogger: 869de521c7b7dbdbb1b0ef973a3c00f7c8046ff8
React-RCTActionSheet: a0bd6037f343183655817e8ccfb517d227ce89c6
React-RCTAnimation: b89077f33ada3bc4d37b4b431810a90bce548395
React-RCTBlob: ee093fdd17bea7fccea6b7798112d70f32e14590
React-RCTImage: 6260a130d38065a6b6a0053b066b693b88bfcfb1
React-RCTLinking: 455be7c2c9b567d1e8225d28cefbf0d6c3364f85
React-RCTNetwork: a1d28da57b4d322b4dfd7c036da4e3fddc220ef1
React-RCTPushNotification: 843cd5fdc428814ad09eef327f5e069e2962e5bc
React-RCTSettings: 2fd29ce8818a57f6016243ca3857a36dfda3f73a
React-RCTTest: f5e9ca6222f647dde3ca536ce5d983da1028cbb8
React-RCTText: ae07257137eb22d788947b76d7176418c18d7f8b
React-RCTVibration: 96e1d2916264a8787a2a409e9a3dd1ded5f2a404
React-runtimeexecutor: 165044764bc0b6176e07f654f57d3c84567107b8
RCTRequired: f69bc029b4e19411dd37c82521ee7f40451c39bd
RCTTypeSafety: eac4bf166ab078acc91d836bf91c19227a52b5cb
React: e3ead01467fceb6371308544f0e94f35052230e7
React-callinvoker: 14f7c592814aa4ed38de8ee15c87fb3284affcf0
React-Core: 56999fc712186d46fcd3b82563dbc1cdcfbbab47
React-CoreModules: 4f16f6042a515d575c6a8e745345403527c6b292
React-cxxreact: efd175939ed4f9ed26c39ae528151841e785187c
React-jsi: 52b19336123975495cc71d6f8881f599ad5fc301
React-jsiexecutor: 75e0be97411644e306e86ff043bc35eb9bf57f5d
React-jsinspector: 9ca47f83b073fba6c03b1271403d9a3cb811e46c
React-perflogger: f3c3ce0e1e370cf52418687d585e283daa1f00a2
React-RCTActionSheet: 2e56a81fedeab83a4c143f5edebafd960a0486c5
React-RCTAnimation: 0aa022dd8a649fd9c120e11b674a771d69a941b8
React-RCTBlob: ce8f9f12e944a62845982fa0ffbb9be8c622cbe6
React-RCTImage: f7cdc51bac96c263278fa86ed20d4c9d4b5b3bd3
React-RCTLinking: bdc37257824e77aab193cb26b0dab9b99a31fd51
React-RCTNetwork: 48fc780d995fc21ce459c9e081f9dd0d20aa774f
React-RCTPushNotification: 1ddbd932094081df005382c448bab53246e7ed21
React-RCTSettings: 29752424f95d45c3540e98a1e6c6c22fce064679
React-RCTTest: 3365b714e83c56defc48bf8b42643221db2bbc07
React-RCTText: 5b09d89d4e07910d36e2ffd74c3a876aac00e67f
React-RCTVibration: 2cfcfe6f1688d04da1ae34a5c35261dfa3bfad04
React-runtimeexecutor: 6ec1f9d6106b9f0b041a41c89abc7dd040b39437
React-TurboModuleCxx-RNW: 18bb71af41fe34c8b12a56bef60aae7ee32b0817
React-TurboModuleCxx-WinRTPort: 8a81b72f4adac4e05a468c73e399c32a65bfcee9
ReactCommon: f4ea3975534282e48263f282d0d6deb8a7e546a1
Yoga: a55415d3b511bbb13a9689678be7e18a6cac73d2
React-TurboModuleCxx-WinRTPort: c95d24f313b49e94af9111d0a42a84ff64a4a8ae
ReactCommon: 77f4858f4785302af8b5d4d8abd93b8a6a431a88
Yoga: 3da5d46e05d2f7cd9a30618090e0d0fdee43e279
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: cb260f8f7765c910b68f8267cbd74709f6ae6e54

Просмотреть файл

@ -35,7 +35,7 @@
"eslint-plugin-react-hooks": "^4.0.7",
"eslint-plugin-react-native": "3.8.1",
"eslint-plugin-relay": "1.7.1",
"flow-bin": "^0.133.0",
"flow-bin": "^0.134.0",
"flow-remove-types": "1.2.3",
"hermes-engine-darwin": "~0.5.0",
"jest": "^26.0.1",

Просмотреть файл

@ -66,4 +66,4 @@ untyped-import
untyped-type-import
[version]
^0.133.0
^0.134.0

Просмотреть файл

@ -4170,10 +4170,10 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
flow-bin@^0.133.0:
version "0.133.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.133.0.tgz#2ee44e3f5d0c0256cfe8e99d9a85e9801c281c50"
integrity sha512-01T5g8GdhtJEn+lhAwuv5zkrMStrmkuHrY3Nn9/aS9y6waNmNgimMKlzRpFH66S0F6Ez9EqU9psz5QaRveSJIA==
flow-bin@^0.134.0:
version "0.134.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.134.0.tgz#e98e5724f6ed5a1265cf904bbb5e4c096ea3a026"
integrity sha512-j5aCugO3jmwDsUKc+7KReArgnL6aVjHLo6DlozKhxKYN+TaP8BY+mintPSISjSQtKZFJyvoNAc1oXA79X5WjIA==
flow-parser@0.*:
version "0.89.0"