From 1aaa52853f86450db9a9a7035d5dcbebfd0b101e Mon Sep 17 00:00:00 2001 From: Maxime Aoustin Date: Thu, 13 Apr 2017 13:08:32 +1000 Subject: [PATCH 01/69] Add mock for the Linking library --- jest/setup.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/jest/setup.js b/jest/setup.js index 68492e651091a5..f637764457354e 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -129,6 +129,13 @@ const mockNativeModules = { addListener: jest.fn(), removeListeners: jest.fn(), }, + Linking: { + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + openURL: jest.fn(), + canOpenURL: jest.fn(), + getInitialURL: jest.fn() + }, ModalFullscreenViewManager: {}, Networking: { sendRequest: jest.fn(), From 9eed7b6578856f6c85ae8e6d787ec9be96c682e5 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Thu, 13 Apr 2017 04:38:13 -0700 Subject: [PATCH 02/69] Log to console in RCTTestRunner Reviewed By: fkgozali Differential Revision: D4875352 fbshipit-source-id: 68f9caf4f350d34b2fd180ff19353c698bfce452 --- Libraries/RCTTest/RCTTestModule.m | 3 +++ Libraries/RCTTest/RCTTestRunner.m | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Libraries/RCTTest/RCTTestModule.m b/Libraries/RCTTest/RCTTestModule.m index c5741e93df2416..dd2424d31ddbbc 100644 --- a/Libraries/RCTTest/RCTTestModule.m +++ b/Libraries/RCTTest/RCTTestModule.m @@ -51,6 +51,9 @@ - (dispatch_queue_t)methodQueue selector:self->_testSelector identifier:identifier error:&error]; + if (!success) { + RCTLogInfo(@"Failed to verify snapshot %@ (error: %@)", identifier, error); + } callback(@[@(success)]); }]; } diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m index 6f3ed05631c4aa..e32af66bc33e35 100644 --- a/Libraries/RCTTest/RCTTestRunner.m +++ b/Libraries/RCTTest/RCTTestRunner.m @@ -97,9 +97,12 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName { @autoreleasepool { __block NSString *error = nil; + RCTLogFunction defaultLogFunction = RCTGetLogFunction(); RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { if (level >= RCTLogLevelError) { error = message; + } else { + defaultLogFunction(level, source, fileName, lineNumber, message); } }); @@ -137,7 +140,7 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName [rootView removeFromSuperview]; - RCTSetLogFunction(RCTDefaultLogFunction); + RCTSetLogFunction(defaultLogFunction); NSArray *nonLayoutSubviews = [vc.view.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id subview, NSDictionary *bindings) { return ![NSStringFromClass([subview class]) isEqualToString:@"_UILayoutGuide"]; From eeb86454f64242409cab3b305d04105036c4ecdd Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Thu, 13 Apr 2017 04:57:13 -0700 Subject: [PATCH 03/69] fix typo Summary: Closes https://github.com/facebook/react-native/pull/13418 Differential Revision: D4883386 Pulled By: javache fbshipit-source-id: aa6195d4015ae5eb240b135a3c265be823652b11 --- docs/LinkingLibraries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/LinkingLibraries.md b/docs/LinkingLibraries.md index f3c360a58c0e87..315a0f038365de 100644 --- a/docs/LinkingLibraries.md +++ b/docs/LinkingLibraries.md @@ -45,7 +45,7 @@ Link your native dependencies: $ react-native link ``` -Done! All libraries with a native dependencies should be successfully linked to your iOS/Android project. +Done! All libraries with native dependencies should be successfully linked to your iOS/Android project. ### Manual linking From 7a7e0873aa231a807a25071e768948d792965a43 Mon Sep 17 00:00:00 2001 From: Kathy Gray Date: Thu, 13 Apr 2017 05:19:07 -0700 Subject: [PATCH 04/69] Find hasConstant status via preprocessing Reviewed By: javache Differential Revision: D4867563 fbshipit-source-id: 66e4505d142fc4776cd727a025005b43d500b167 --- .../react/animated/NativeAnimatedModule.java | 2 +- .../react/devsupport/JSCSamplingProfiler.java | 2 +- .../com/facebook/react/module/processing/BUCK | 4 ++-- .../processing/ReactModuleSpecProcessor.java | 18 +++++++++++++++++- .../react/modules/appstate/AppStateModule.java | 2 +- .../modules/core/DeviceEventManagerModule.java | 2 +- .../modules/core/ExceptionsManagerModule.java | 2 +- .../core/HeadlessJsTaskSupportModule.java | 2 +- .../facebook/react/modules/core/Timing.java | 2 +- .../modules/debug/AnimationsDebugModule.java | 2 +- .../modules/storage/AsyncStorageModule.java | 2 +- .../debug/DebugComponentOwnershipModule.java | 2 +- 12 files changed, 29 insertions(+), 13 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java index 217e1a8277a378..d4fd0680ff5147 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java @@ -71,7 +71,7 @@ * isolates us from the problems that may be caused by concurrent updates of animated graph while UI * thread is "executing" the animation loop. */ -@ReactModule(name = NativeAnimatedModule.NAME, hasConstants = false) +@ReactModule(name = NativeAnimatedModule.NAME) public class NativeAnimatedModule extends ReactContextBaseJavaModule implements OnBatchCompleteListener, LifecycleEventListener { diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java index eeec004f8325cc..049f72c3284468 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java @@ -23,7 +23,7 @@ // This module is being called only by Java via the static method "poke" that // requires it to alreay be initialized, thus we eagerly initialize this module -@ReactModule(name = "JSCSamplingProfiler", needsEagerInit = true, hasConstants = false) +@ReactModule(name = "JSCSamplingProfiler", needsEagerInit = true) public class JSCSamplingProfiler extends ReactContextBaseJavaModule { public interface SamplingProfiler extends JavaScriptModule { void poke(int token); diff --git a/ReactAndroid/src/main/java/com/facebook/react/module/processing/BUCK b/ReactAndroid/src/main/java/com/facebook/react/module/processing/BUCK index 42c9fe88b91323..063d0f7fa96ada 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/module/processing/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/module/processing/BUCK @@ -14,8 +14,8 @@ java_annotation_processor( java_library( name = "processing-lib", srcs = glob(["*.java"]), - source = "7", - target = "7", + source = "8", + target = "8", deps = [ react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/javapoet:javapoet"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/module/processing/ReactModuleSpecProcessor.java b/ReactAndroid/src/main/java/com/facebook/react/module/processing/ReactModuleSpecProcessor.java index a4b113dd7ff84f..f48f869c2b0dd6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/module/processing/ReactModuleSpecProcessor.java +++ b/ReactAndroid/src/main/java/com/facebook/react/module/processing/ReactModuleSpecProcessor.java @@ -10,7 +10,9 @@ import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.MirroredTypesException; @@ -19,6 +21,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.stream.Stream; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -149,19 +152,32 @@ private CodeBlock getCodeBlockForReactModuleInfos(List nativeModules) String keyString = nativeModule + ".class"; TypeElement typeElement = mElements.getTypeElement(nativeModule); + if (typeElement == null) { + throw new ReactModuleSpecException( + keyString + " not found by ReactModuleSpecProcessor. " + + "Did you misspell the module?"); + } ReactModule reactModule = typeElement.getAnnotation(ReactModule.class); if (reactModule == null) { throw new ReactModuleSpecException( keyString + " not found by ReactModuleSpecProcessor. " + "Did you forget to add the @ReactModule annotation to the native module?"); } + + List elements = typeElement.getEnclosedElements(); + boolean hasConstants = false; + if (elements != null) { + hasConstants = elements.stream() + .anyMatch((Element m) -> m.getKind() == ElementKind.METHOD && m.getSimpleName().contentEquals("getConstants")); + } + String valueString = new StringBuilder() .append("new ReactModuleInfo(") .append("\"").append(reactModule.name()).append("\"").append(", ") .append(reactModule.canOverrideExistingModule()).append(", ") .append(reactModule.supportsWebWorkers()).append(", ") .append(reactModule.needsEagerInit()).append(", ") - .append(reactModule.hasConstants()) + .append(hasConstants) .append(")") .toString(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java index bf3dc276f1a7b2..78be38352c55f5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java @@ -19,7 +19,7 @@ import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; -@ReactModule(name = AppStateModule.NAME, hasConstants = false) +@ReactModule(name = AppStateModule.NAME) public class AppStateModule extends ReactContextBaseJavaModule implements LifecycleEventListener { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java index d76c79940402bc..85b9c3853c12c8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java @@ -26,7 +26,7 @@ /** * Native module that handles device hardware events like hardware back presses. */ -@ReactModule(name = "DeviceEventManager", hasConstants = false) +@ReactModule(name = "DeviceEventManager") public class DeviceEventManagerModule extends ReactContextBaseJavaModule { @SupportsWebWorkers diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java index f50c3d99faa505..b92d22ad778f89 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java @@ -23,7 +23,7 @@ import com.facebook.react.common.ReactConstants; import com.facebook.react.module.annotations.ReactModule; -@ReactModule(name = ExceptionsManagerModule.NAME, hasConstants = false) +@ReactModule(name = ExceptionsManagerModule.NAME) public class ExceptionsManagerModule extends BaseJavaModule { protected static final String NAME = "ExceptionsManager"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java index fb2c370eeb5790..5f4c0799d422a2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java @@ -20,7 +20,7 @@ * Simple native module that allows JS to notify native of having completed some task work, so that * it can e.g. release any resources, stop timers etc. */ -@ReactModule(name = HeadlessJsTaskSupportModule.MODULE_NAME, hasConstants = false) +@ReactModule(name = HeadlessJsTaskSupportModule.MODULE_NAME) public class HeadlessJsTaskSupportModule extends ReactContextBaseJavaModule { protected static final String MODULE_NAME = "HeadlessJsTaskSupport"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java index 317f98fab888ab..0e504d5d8c6ba9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java @@ -42,7 +42,7 @@ /** * Native module for JS timer execution. Timers fire on frame boundaries. */ -@ReactModule(name = Timing.NAME, supportsWebWorkers = true, hasConstants = false) +@ReactModule(name = Timing.NAME, supportsWebWorkers = true) public final class Timing extends ReactContextBaseJavaModule implements LifecycleEventListener, OnExecutorUnregisteredListener, HeadlessJsTaskEventListener { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java index 454dd5baaef109..5e991d4c48c67d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java @@ -29,7 +29,7 @@ * Module that records debug information during transitions (animated navigation events such as * going from one screen to another). */ -@ReactModule(name = AnimationsDebugModule.NAME, hasConstants = false) +@ReactModule(name = AnimationsDebugModule.NAME) public class AnimationsDebugModule extends ReactContextBaseJavaModule { protected static final String NAME = "AnimationsDebugModule"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/AsyncStorageModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/AsyncStorageModule.java index 28267e124816e3..5fdcbeb488cbfb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/AsyncStorageModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/AsyncStorageModule.java @@ -33,7 +33,7 @@ import static com.facebook.react.modules.storage.ReactDatabaseSupplier.TABLE_CATALYST; import static com.facebook.react.modules.storage.ReactDatabaseSupplier.VALUE_COLUMN; -@ReactModule(name = AsyncStorageModule.NAME, hasConstants = false) +@ReactModule(name = AsyncStorageModule.NAME) public final class AsyncStorageModule extends ReactContextBaseJavaModule implements ModuleDataCleaner.Cleanable { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/DebugComponentOwnershipModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/DebugComponentOwnershipModule.java index 2ba0dddf1fa2ef..a38af1d06004a1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/DebugComponentOwnershipModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/DebugComponentOwnershipModule.java @@ -27,7 +27,7 @@ * * Example returned owner hierarchy: ['RootView', 'Dialog', 'TitleView', 'Text'] */ -@ReactModule(name = "DebugComponentOwnershipModule", hasConstants = false) +@ReactModule(name = "DebugComponentOwnershipModule") public class DebugComponentOwnershipModule extends ReactContextBaseJavaModule { public interface RCTDebugComponentOwnership extends JavaScriptModule { From d419ccb9d17d49a090a54f05496a7dac7599c2ef Mon Sep 17 00:00:00 2001 From: Victor Ilyukevich Date: Thu, 13 Apr 2017 05:50:24 -0700 Subject: [PATCH 05/69] =?UTF-8?q?Fix=20typo=20in=20documentation:=20"?= =?UTF-8?q?=E2=80=A6controls=20how=20rows=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Closes https://github.com/facebook/react-native/pull/13482 Differential Revision: D4883387 Pulled By: javache fbshipit-source-id: fab3ce3136b18079a566e93fb3d388abc27dd41c --- Libraries/StyleSheet/LayoutPropTypes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/StyleSheet/LayoutPropTypes.js b/Libraries/StyleSheet/LayoutPropTypes.js index a8ab32c0772d72..56e42a5af5c912 100644 --- a/Libraries/StyleSheet/LayoutPropTypes.js +++ b/Libraries/StyleSheet/LayoutPropTypes.js @@ -409,7 +409,7 @@ var LayoutPropTypes = { 'baseline' ]), - /** `alignContent` controls how a rows align in the cross direction, + /** `alignContent` controls how rows align in the cross direction, * overriding the `alignContent` of the parent. * See https://developer.mozilla.org/en-US/docs/Web/CSS/align-content * for more details. From 3c8608e31bde9e204e407611bc478600adfd5784 Mon Sep 17 00:00:00 2001 From: ZauberNerd Date: Thu, 13 Apr 2017 06:17:15 -0700 Subject: [PATCH 06/69] fix mock for AsyncLocalStorage Summary: The current mock of `AsyncLocalStorage` seems to mock parts of the `AsyncStorage` API that can't be found on the `AsyncLocalStorage` object itself and therefore it doesn't work as expected. What it should do is mock the API of `AsyncLocalStorage` which is a `NativeModule` so that the `AsyncStorage` module can be used in tests and it will require the mocked methods. In order to enable behaviour in unit tests it is possible to replace or overwrite the mock implementation, see the [jest guide on mocks](https://facebook.github.io/jest/docs/mock-functions.html). By doing something similar to: ```javascript import { NativeModules } from 'react-native'; const { AsyncLocalStorage } = NativeModules; // mock 'multiGet', in order to allow 'AsyncStorage.getItem('myKey')' AsyncLocalStorage.multiGet.mockImplementationOnce((keys, callback) => { callback(null, [['myKey', 'myValue']]); }); // execute unit tests for code that makes use of 'AsyncStorage' ``` Closes https://github.com/facebook/react-native/pull/13433 Differential Revision: D4883389 Pulled By: javache fbshipit-source-id: 92a0ee94480b3022acc748e306ee2d4ee7a9869d --- jest/setup.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/jest/setup.js b/jest/setup.js index f637764457354e..f9a22f2c6b78bc 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -72,10 +72,12 @@ const mockNativeModules = { addEventListener: jest.fn(), }, AsyncLocalStorage: { - clear: jest.fn(), - getItem: jest.fn(), - removeItem: jest.fn(), - setItem: jest.fn(), + multiGet: jest.fn((keys, callback) => process.nextTick(() => callback(null, []))), + multiSet: jest.fn((entries, callback) => process.nextTick(() => callback(null))), + multiRemove: jest.fn((keys, callback) => process.nextTick(() => callback(null))), + multiMerge: jest.fn((entries, callback) => process.nextTick(() => callback(null))), + clear: jest.fn(callback => process.nextTick(() => callback(null))), + getAllKeys: jest.fn(callback => process.nextTick(() => callback(null, []))), }, BuildInfo: { appVersion: '0', From 833ef425fe7eaafd42ea97243c564fc1cf4cca19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Thu, 13 Apr 2017 07:36:55 -0700 Subject: [PATCH 07/69] Fix sizing of non strech items Summary: Fixes the sizing of items so that under most scenarios it calcultes its height by it's content for non exact measurings. See facebook/yoga#505 Closes https://github.com/facebook/yoga/pull/506 Differential Revision: D4878875 Pulled By: emilsjolander fbshipit-source-id: ab1174ac7a76dcf20aae7b29a3bc396e11077c4d --- ReactCommon/yoga/yoga/Yoga.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index f7be592aacdb72..98dec048517d45 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -2197,6 +2197,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, // If the main dimension size isn't known, it is computed based on // the line length, so there's no more space left to distribute. + bool sizeBasedOnContent = false; // If we don't measure with exact main dimension we want to ensure we don't violate min and max if (measureModeMainDim != YGMeasureModeExactly) { if (!YGFloatIsUndefined(minInnerMainDim) && sizeConsumedOnCurrentLine < minInnerMainDim) { @@ -2207,11 +2208,14 @@ static void YGNodelayoutImpl(const YGNodeRef node, // TODO: this needs to be moved out of experimental feature, as this is legitimate fix // If the measurement isn't exact, we want to use as little space as possible availableInnerMainDim = sizeConsumedOnCurrentLine; + sizeBasedOnContent = true; + } else { + sizeBasedOnContent = true; } } float remainingFreeSpace = 0; - if (!YGFloatIsUndefined(availableInnerMainDim)) { + if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) { remainingFreeSpace = availableInnerMainDim - sizeConsumedOnCurrentLine; } else if (sizeConsumedOnCurrentLine < 0) { // availableInnerMainDim is indefinite which means the node is being sized From 6cb1979df95127f299bf03fc424bea9f18a03e02 Mon Sep 17 00:00:00 2001 From: Georgiy Kassabli Date: Thu, 13 Apr 2017 08:38:02 -0700 Subject: [PATCH 08/69] Correct fix for flexing grandchildren Reviewed By: emilsjolander Differential Revision: D4875343 fbshipit-source-id: 634e961f9798dff43eae2c6564b28c6629b816e0 --- ReactCommon/yoga/yoga/YGEnums.c | 2 -- ReactCommon/yoga/yoga/YGEnums.h | 1 - ReactCommon/yoga/yoga/Yoga.c | 7 +++---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGEnums.c b/ReactCommon/yoga/yoga/YGEnums.c index 0108e6a616cfa3..53a057780a68f4 100644 --- a/ReactCommon/yoga/yoga/YGEnums.c +++ b/ReactCommon/yoga/yoga/YGEnums.c @@ -93,8 +93,6 @@ const char *YGExperimentalFeatureToString(const YGExperimentalFeature value){ return "rounding"; case YGExperimentalFeatureWebFlexBasis: return "web-flex-basis"; - case YGExperimentalFeatureMinFlexFix: - return "min-flex-fix"; } return "unknown"; } diff --git a/ReactCommon/yoga/yoga/YGEnums.h b/ReactCommon/yoga/yoga/YGEnums.h index 8a929b9e7ad9a9..aa14933b77b1d8 100644 --- a/ReactCommon/yoga/yoga/YGEnums.h +++ b/ReactCommon/yoga/yoga/YGEnums.h @@ -66,7 +66,6 @@ WIN_EXPORT const char *YGEdgeToString(const YGEdge value); typedef YG_ENUM_BEGIN(YGExperimentalFeature) { YGExperimentalFeatureRounding, YGExperimentalFeatureWebFlexBasis, - YGExperimentalFeatureMinFlexFix, } YG_ENUM_END(YGExperimentalFeature); WIN_EXPORT const char *YGExperimentalFeatureToString(const YGExperimentalFeature value); diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index 98dec048517d45..f0f406e34fb4f0 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -203,7 +203,6 @@ static YGConfig gYGConfigDefaults = { .experimentalFeatures = { [YGExperimentalFeatureRounding] = false, - [YGExperimentalFeatureMinFlexFix] = false, [YGExperimentalFeatureWebFlexBasis] = false, }, .useWebDefaults = false, @@ -2204,9 +2203,9 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerMainDim = minInnerMainDim; } else if (!YGFloatIsUndefined(maxInnerMainDim) && sizeConsumedOnCurrentLine > maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; - } else if (YGConfigIsExperimentalFeatureEnabled(node->config, YGExperimentalFeatureMinFlexFix)) { - // TODO: this needs to be moved out of experimental feature, as this is legitimate fix - // If the measurement isn't exact, we want to use as little space as possible + } else if (totalFlexGrowFactors == 0 || YGResolveFlexGrow(node) == 0) { + // If we don't have any children to flex or we can't flex the node itself, + // space we've used is all space we need availableInnerMainDim = sizeConsumedOnCurrentLine; sizeBasedOnContent = true; } else { From b87de4d4642df19495c38058a158154a9b985540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Thu, 13 Apr 2017 08:39:40 -0700 Subject: [PATCH 09/69] Let measure behave more like on the web Summary: Nodes with a measure function needs to be measured even so it seems there is no available space. So it behaves more like on the web. Fix facebook/yoga#488 Closes https://github.com/facebook/yoga/pull/499 Differential Revision: D4850458 Pulled By: emilsjolander fbshipit-source-id: be5e35a670ddcbf3cd426fc3c2a0c9b60a874cdc --- ReactCommon/yoga/yoga/Yoga.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index f0f406e34fb4f0..e8155ebe82f9cb 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -1654,13 +1654,6 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, node, YGFlexDirectionRow, availableWidth - marginAxisRow, parentWidth, parentWidth); node->layout.measuredDimensions[YGDimensionHeight] = YGNodeBoundAxis( node, YGFlexDirectionColumn, availableHeight - marginAxisColumn, parentHeight, parentWidth); - } else if (innerWidth <= 0.0f || innerHeight <= 0.0f) { - // Don't bother sizing the text if there's no horizontal or vertical - // space. - node->layout.measuredDimensions[YGDimensionWidth] = - YGNodeBoundAxis(node, YGFlexDirectionRow, 0.0f, availableWidth, availableWidth); - node->layout.measuredDimensions[YGDimensionHeight] = - YGNodeBoundAxis(node, YGFlexDirectionColumn, 0.0f, availableHeight, availableWidth); } else { // Measure the text under the current constraints. const YGSize measuredSize = From 7c8c57a84a62aa4faf7551fe3300204119837810 Mon Sep 17 00:00:00 2001 From: William Durand Date: Thu, 13 Apr 2017 09:16:09 -0700 Subject: [PATCH 10/69] Add Geolocation API Jest mock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Hello! The [Geolocation API](https://facebook.github.io/react-native/docs/geolocation.html) is currently not mocked in Jest, which often leads to an `Invariant Violation: Native module cannot be null` error. This patch adds a basic Jest configuration similar to the existing ones for the other modules. None unfortunately, but this patch makes my test suite all green 😉 Thanks, William Closes https://github.com/facebook/react-native/pull/13442 Differential Revision: D4883830 Pulled By: javache fbshipit-source-id: c2a976834cca7537bd832a698e8cd25cf877705b --- jest/setup.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jest/setup.js b/jest/setup.js index f9a22f2c6b78bc..5a5af40f4f7f5c 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -138,6 +138,11 @@ const mockNativeModules = { canOpenURL: jest.fn(), getInitialURL: jest.fn() }, + LocationObserver: { + getCurrentPosition: jest.fn(), + startObserving: jest.fn(), + stopObserving: jest.fn(), + }, ModalFullscreenViewManager: {}, Networking: { sendRequest: jest.fn(), From d8ff02b1067f10d94993a5e672dc187cca390022 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Thu, 13 Apr 2017 09:51:45 -0700 Subject: [PATCH 11/69] Revert D4878875: [yoga][PR] Fix sizing of non strech items Differential Revision: D4878875 fbshipit-source-id: 8927438e7a1969deb617434369af53f71f625638 --- ReactCommon/yoga/yoga/Yoga.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index e8155ebe82f9cb..e70cb5f8746ca8 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -2189,7 +2189,6 @@ static void YGNodelayoutImpl(const YGNodeRef node, // If the main dimension size isn't known, it is computed based on // the line length, so there's no more space left to distribute. - bool sizeBasedOnContent = false; // If we don't measure with exact main dimension we want to ensure we don't violate min and max if (measureModeMainDim != YGMeasureModeExactly) { if (!YGFloatIsUndefined(minInnerMainDim) && sizeConsumedOnCurrentLine < minInnerMainDim) { @@ -2200,14 +2199,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, // If we don't have any children to flex or we can't flex the node itself, // space we've used is all space we need availableInnerMainDim = sizeConsumedOnCurrentLine; - sizeBasedOnContent = true; - } else { - sizeBasedOnContent = true; } } float remainingFreeSpace = 0; - if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) { + if (!YGFloatIsUndefined(availableInnerMainDim)) { remainingFreeSpace = availableInnerMainDim - sizeConsumedOnCurrentLine; } else if (sizeConsumedOnCurrentLine < 0) { // availableInnerMainDim is indefinite which means the node is being sized From 8565f4f2b6858211fd1b67ec57349acb30381724 Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Thu, 13 Apr 2017 10:28:45 -0700 Subject: [PATCH 12/69] packager: ResolutionRequest: correct mistaken callsite Reviewed By: cpojer Differential Revision: D4875756 fbshipit-source-id: cdf29e3c1115003596f6a7b4d27988010d56d88d --- packager/src/node-haste/DependencyGraph/ResolutionRequest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packager/src/node-haste/DependencyGraph/ResolutionRequest.js b/packager/src/node-haste/DependencyGraph/ResolutionRequest.js index 77ec18e097832a..60a7204928b323 100644 --- a/packager/src/node-haste/DependencyGraph/ResolutionRequest.js +++ b/packager/src/node-haste/DependencyGraph/ResolutionRequest.js @@ -191,7 +191,7 @@ class ResolutionRequest { if (result != null) { return this.resolveModuleDependencies(module, result.dependencies); } - return module.read(transformOptions) + return module.readFresh(transformOptions) .then(({dependencies}) => this.resolveModuleDependencies(module, dependencies)); }); From f588c8152a97a54f1071732df04e8c28095cb634 Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Thu, 13 Apr 2017 10:28:46 -0700 Subject: [PATCH 13/69] packager: preprocess outdated dependencies Summary: Note: if this changeset causes some breakage, consider disabling rather than reverting. To disable, the call to `_preprocessPotentialDependencies` in `ResolutionRequest` can be removed. It's a bit of an experiment. I couldn't see any particular regression caused by this, but I could see net improvement of the global cache performance, as it unlock much, much stronger batching: indeed, instead of discovering dependencies progressively, we synchronously figure out the list of all potential modules of a bundle, and kick-off cache fetching and/or transformations. So when it comes to fetching from the global cache, it'll do less requests, and each requests will ask for considerably more keys at a time. Potential problem caused by this changeset: if a module's dependencies completely changed, then the first time we try to build the bundle it'll start transforming modules that we probably don't care at all anymore, spending precious CPU time for nothing. I've been thinking about it and I cannot see such a case happening much often. Even if it happens, it should not cause any bug or corruption, it would just take additional time. Other potential problem: that this new code doesn't handle some types of edge cases. It's quite hard to figure out what could possibly break in the `ResolutionRequest` code (and I think it would benefit from a larger refactor). We do have a good test coverage for `DependencyGraph` and it seems to work smoothly, so I'm relatively confident we're not breaking edge cases. Reviewed By: davidaurelio Differential Revision: D4875467 fbshipit-source-id: 2dfcc755bec638d3d1c47862ec1de5220953e812 --- packager/src/ModuleGraph/node-haste/Module.js | 9 ++ .../src/ModuleGraph/node-haste/node-haste.js | 2 + packager/src/lib/GlobalTransformCache.js | 2 +- packager/src/lib/TransformCache.js | 30 ++++-- packager/src/lib/__mocks__/TransformCache.js | 2 +- .../src/lib/__tests__/TransformCache-test.js | 9 +- packager/src/node-haste/AssetModule.js | 9 +- .../DependencyGraph/ResolutionRequest.js | 98 +++++++++++++++++-- packager/src/node-haste/Module.js | 43 ++++---- 9 files changed, 159 insertions(+), 45 deletions(-) diff --git a/packager/src/ModuleGraph/node-haste/Module.js b/packager/src/ModuleGraph/node-haste/Module.js index 6c7e84aec951a8..d57f14ea1c06ec 100644 --- a/packager/src/ModuleGraph/node-haste/Module.js +++ b/packager/src/ModuleGraph/node-haste/Module.js @@ -11,6 +11,7 @@ 'use strict'; +import type {CachedReadResult, ReadResult} from '../../node-haste/Module'; import type {TransformedFile} from '../types.flow'; import type {ModuleCache} from './node-haste.flow'; @@ -33,6 +34,14 @@ module.exports = class Module { this.type = 'Module'; } + readCached(): CachedReadResult { + throw new Error('not implemented'); + } + + readFresh(): Promise { + return Promise.reject(new Error('not implemented')); + } + getName() { return this.name; } diff --git a/packager/src/ModuleGraph/node-haste/node-haste.js b/packager/src/ModuleGraph/node-haste/node-haste.js index daf739a7fd47d8..7f9b7005812403 100644 --- a/packager/src/ModuleGraph/node-haste/node-haste.js +++ b/packager/src/ModuleGraph/node-haste/node-haste.js @@ -63,6 +63,8 @@ const nullModule = { hash() { throw new Error('not implemented'); }, + readCached() { throw new Error('not implemented'); }, + readFresh() { return Promise.reject(new Error('not implemented')); }, }; exports.createResolveFn = function(options: ResolveOptions): ResolveFn { diff --git a/packager/src/lib/GlobalTransformCache.js b/packager/src/lib/GlobalTransformCache.js index 44661e34a90c0f..82527bbe5588f0 100644 --- a/packager/src/lib/GlobalTransformCache.js +++ b/packager/src/lib/GlobalTransformCache.js @@ -95,7 +95,7 @@ class KeyURIFetcher { this._batchProcessor = new BatchProcessor({ maximumDelayMs: 10, maximumItems: 500, - concurrency: 25, + concurrency: 2, }, this._processKeys.bind(this)); } diff --git a/packager/src/lib/TransformCache.js b/packager/src/lib/TransformCache.js index 5f164ca162452f..0175e1fcb0672f 100644 --- a/packager/src/lib/TransformCache.js +++ b/packager/src/lib/TransformCache.js @@ -95,6 +95,11 @@ export type CachedResult = { map?: ?SourceMap, }; +export type TransformCacheResult = {| + +result: ?CachedResult, + +outdatedDependencies: $ReadOnlyArray, +|}; + /** * We want to unlink all cache files before writing, so that it is as much * atomic as possible. @@ -299,6 +304,8 @@ export type ReadTransformProps = { cacheOptions: CacheOptions, }; +const EMPTY_ARRAY = []; + /** * We verify the source hash matches to ensure we always favor rebuilding when * source change (rather than just using fs.mtime(), a bit less robust). @@ -312,41 +319,44 @@ export type ReadTransformProps = { * Meanwhile we store transforms with different options in different files so * that it is fast to switch between ex. minified, or not. */ -function readSync(props: ReadTransformProps): ?CachedResult { +function readSync(props: ReadTransformProps): TransformCacheResult { GARBAGE_COLLECTOR.collectIfNecessarySync(props.cacheOptions); const cacheFilePaths = getCacheFilePaths(props); let metadata, transformedCode; try { metadata = readMetadataFileSync(cacheFilePaths.metadata); if (metadata == null) { - return null; + return {result: null, outdatedDependencies: EMPTY_ARRAY}; } const sourceHash = hashSourceCode(props); if (sourceHash !== metadata.cachedSourceHash) { - return null; + return {result: null, outdatedDependencies: metadata.dependencies}; } transformedCode = fs.readFileSync(cacheFilePaths.transformedCode, 'utf8'); const codeHash = crypto.createHash('sha1').update(transformedCode).digest('hex'); if (metadata.cachedResultHash !== codeHash) { - return null; + return {result: null, outdatedDependencies: metadata.dependencies}; } } catch (error) { if (error.code === 'ENOENT') { - return null; + return {result: null, outdatedDependencies: EMPTY_ARRAY}; } throw error; } return { - code: transformedCode, - dependencies: metadata.dependencies, - dependencyOffsets: metadata.dependencyOffsets, - map: metadata.sourceMap, + result: { + code: transformedCode, + dependencies: metadata.dependencies, + dependencyOffsets: metadata.dependencyOffsets, + map: metadata.sourceMap, + }, + outdatedDependencies: EMPTY_ARRAY, }; } module.exports = { writeSync, - readSync(props: ReadTransformProps): ?CachedResult { + readSync(props: ReadTransformProps): TransformCacheResult { const result = readSync(props); const msg = result ? 'Cache hit: ' : 'Cache miss: '; debugRead(msg + props.filePath); diff --git a/packager/src/lib/__mocks__/TransformCache.js b/packager/src/lib/__mocks__/TransformCache.js index 807d2f93345919..1fd2261b755f03 100644 --- a/packager/src/lib/__mocks__/TransformCache.js +++ b/packager/src/lib/__mocks__/TransformCache.js @@ -34,7 +34,7 @@ function writeSync(props) { } function readSync(props) { - return transformCache.get(transformCacheKeyOf(props)); + return {result: transformCache.get(transformCacheKeyOf(props)), outdatedDependencies: []}; } module.exports = { diff --git a/packager/src/lib/__tests__/TransformCache-test.js b/packager/src/lib/__tests__/TransformCache-test.js index e9bab8eb3b2aa5..af123ecb7437a6 100644 --- a/packager/src/lib/__tests__/TransformCache-test.js +++ b/packager/src/lib/__tests__/TransformCache-test.js @@ -92,7 +92,7 @@ describe('TransformCache', () => { ...args, cacheOptions: {resetCache: false}, }); - expect(cachedResult).toEqual(result); + expect(cachedResult.result).toEqual(result); }); }); @@ -107,7 +107,7 @@ describe('TransformCache', () => { transformOptionsKey: 'boo!', result: { code: `/* result for ${key} */`, - dependencies: ['foo', `dep of ${key}`], + dependencies: ['foo', 'bar'], dependencyOffsets: [12, imurmurhash('dep' + key).result()], map: {desc: `source map for ${key}`}, }, @@ -125,7 +125,7 @@ describe('TransformCache', () => { ...args, cacheOptions: {resetCache: false}, }); - expect(cachedResult).toEqual(result); + expect(cachedResult.result).toEqual(result); }); allCases.pop(); allCases.forEach(entry => { @@ -133,7 +133,8 @@ describe('TransformCache', () => { ...argsFor(entry), cacheOptions: {resetCache: false}, }); - expect(cachedResult).toBeNull(); + expect(cachedResult.result).toBeNull(); + expect(cachedResult.outdatedDependencies).toEqual(['foo', 'bar']); }); }); diff --git a/packager/src/node-haste/AssetModule.js b/packager/src/node-haste/AssetModule.js index 4d0687876a49a5..2d8523cdcb8d52 100644 --- a/packager/src/node-haste/AssetModule.js +++ b/packager/src/node-haste/AssetModule.js @@ -15,7 +15,7 @@ const Module = require('./Module'); const getAssetDataFromName = require('./lib/getAssetDataFromName'); -import type {ConstructorArgs, ReadResult} from './Module'; +import type {CachedReadResult, ConstructorArgs, ReadResult} from './Module'; class AssetModule extends Module { @@ -37,14 +37,15 @@ class AssetModule extends Module { return Promise.resolve(false); } - readCached(): ReadResult { + readCached(): CachedReadResult { /** $FlowFixMe: improper OOP design. AssetModule, being different from a * normal Module, shouldn't inherit it in the first place. */ - return {dependencies: this._dependencies}; + return {result: {dependencies: this._dependencies}, outdatedDependencies: []}; } + /** $FlowFixMe: improper OOP design. */ readFresh(): Promise { - return Promise.resolve(this.readCached()); + return Promise.resolve({dependencies: this._dependencies}); } getName() { diff --git a/packager/src/node-haste/DependencyGraph/ResolutionRequest.js b/packager/src/node-haste/DependencyGraph/ResolutionRequest.js index 60a7204928b323..4d1b810bb24580 100644 --- a/packager/src/node-haste/DependencyGraph/ResolutionRequest.js +++ b/packager/src/node-haste/DependencyGraph/ResolutionRequest.js @@ -24,6 +24,8 @@ const getAssetDataFromName = require('../lib/getAssetDataFromName'); import type {HasteFS} from '../types'; import type DependencyGraphHelpers from './DependencyGraphHelpers'; import type ResolutionResponse from './ResolutionResponse'; +import type {Options as TransformWorkerOptions} from '../../JSTransformer/worker/worker'; +import type {ReadResult, CachedReadResult} from '../Module'; type DirExistsFn = (filePath: string) => boolean; @@ -45,6 +47,8 @@ type Moduleish = { +path: string, getPackage(): ?Packageish, hash(): string, + readCached(transformOptions: TransformWorkerOptions): CachedReadResult, + readFresh(transformOptions: TransformWorkerOptions): Promise, }; type ModuleishCache = { @@ -163,8 +167,8 @@ class ResolutionRequest { resolveModuleDependencies( module: TModule, - dependencyNames: Array, - ): [Array, Array] { + dependencyNames: $ReadOnlyArray, + ): [$ReadOnlyArray, $ReadOnlyArray] { const dependencies = dependencyNames.map(name => this.resolveDependency(module, name)); return [dependencyNames, dependencies]; } @@ -176,7 +180,7 @@ class ResolutionRequest { recursive = true, }: { response: ResolutionResponse, - transformOptions: Object, + transformOptions: TransformWorkerOptions, onProgress?: ?(finishedModules: number, totalModules: number) => mixed, recursive: boolean, }) { @@ -186,10 +190,23 @@ class ResolutionRequest { let totalModules = 1; let finishedModules = 0; - const resolveDependencies = module => Promise.resolve().then(() => { - const result = module.readCached(transformOptions); - if (result != null) { - return this.resolveModuleDependencies(module, result.dependencies); + let preprocessedModuleCount = 1; + if (recursive) { + this._preprocessPotentialDependencies(transformOptions, entry, count => { + if (count + 1 <= preprocessedModuleCount) { + return; + } + preprocessedModuleCount = count + 1; + if (onProgress != null) { + onProgress(finishedModules, preprocessedModuleCount); + } + }); + } + + const resolveDependencies = (module: TModule) => Promise.resolve().then(() => { + const cached = module.readCached(transformOptions); + if (cached.result != null) { + return this.resolveModuleDependencies(module, cached.result.dependencies); } return module.readFresh(transformOptions) .then(({dependencies}) => this.resolveModuleDependencies(module, dependencies)); @@ -221,7 +238,7 @@ class ResolutionRequest { if (onProgress) { finishedModules += 1; totalModules += newDependencies.length; - onProgress(finishedModules, totalModules); + onProgress(finishedModules, Math.max(totalModules, preprocessedModuleCount)); } if (recursive) { @@ -273,6 +290,71 @@ class ResolutionRequest { }); } + /** + * This synchronously look at all the specified modules and recursively kicks off global cache + * fetching or transforming (via `readFresh`). This is a hack that workaround the current + * structure, because we could do better. First off, the algorithm that resolves dependencies + * recursively should be synchronous itself until it cannot progress anymore (and needs to + * call `readFresh`), so that this algo would be integrated into it. + */ + _preprocessPotentialDependencies( + transformOptions: TransformWorkerOptions, + module: TModule, + onProgress: (moduleCount: number) => mixed, + ): void { + const visitedModulePaths = new Set(); + const pendingBatches = [this.preprocessModule(transformOptions, module, visitedModulePaths)]; + onProgress(visitedModulePaths.size); + while (pendingBatches.length > 0) { + const dependencyModules = pendingBatches.pop(); + while (dependencyModules.length > 0) { + const dependencyModule = dependencyModules.pop(); + const deps = this.preprocessModule(transformOptions, dependencyModule, visitedModulePaths); + pendingBatches.push(deps); + onProgress(visitedModulePaths.size); + } + } + } + + preprocessModule( + transformOptions: TransformWorkerOptions, + module: TModule, + visitedModulePaths: Set, + ): Array { + const cached = module.readCached(transformOptions); + if (cached.result == null) { + module.readFresh(transformOptions).catch(error => { + /* ignore errors, they'll be handled later if the dependency is actually + * not obsolete, and required from somewhere */ + }); + } + const dependencies = cached.result != null + ? cached.result.dependencies : cached.outdatedDependencies; + return this.tryResolveModuleDependencies(module, dependencies, visitedModulePaths); + } + + tryResolveModuleDependencies( + module: TModule, + dependencyNames: $ReadOnlyArray, + visitedModulePaths: Set, + ): Array { + const result = []; + for (let i = 0; i < dependencyNames.length; ++i) { + try { + const depModule = this.resolveDependency(module, dependencyNames[i]); + if (!visitedModulePaths.has(depModule.path)) { + visitedModulePaths.add(depModule.path); + result.push(depModule); + } + } catch (error) { + if (!(error instanceof UnableToResolveError)) { + throw error; + } + } + } + return result; + } + _resolveHasteDependency(fromModule: TModule, toModuleName: string): TModule { toModuleName = normalizePath(toModuleName); diff --git a/packager/src/node-haste/Module.js b/packager/src/node-haste/Module.js index f63998b5250a63..36b63d0ca07512 100644 --- a/packager/src/node-haste/Module.js +++ b/packager/src/node-haste/Module.js @@ -33,13 +33,18 @@ import type DependencyGraphHelpers from './DependencyGraph/DependencyGraphHelper import type ModuleCache from './ModuleCache'; export type ReadResult = { - code: string, - dependencies?: ?Array, - dependencyOffsets?: ?Array, - map?: ?SourceMap, - source: string, + +code: string, + +dependencies: Array, + +dependencyOffsets?: ?Array, + +map?: ?SourceMap, + +source: string, }; +export type CachedReadResult = {| + +result: ?ReadResult, + +outdatedDependencies: $ReadOnlyArray, +|}; + export type TransformCode = ( module: Module, sourceCode: string, @@ -95,7 +100,7 @@ class Module { _sourceCode: ?string; _readPromises: Map>; - _readResultsByOptionsKey: Map; + _readResultsByOptionsKey: Map; constructor({ cache, @@ -346,8 +351,8 @@ class Module { read(transformOptions: TransformOptions): Promise { return Promise.resolve().then(() => { const cached = this.readCached(transformOptions); - if (cached != null) { - return cached; + if (cached.result != null) { + return cached.result; } return this.readFresh(transformOptions); }); @@ -358,12 +363,13 @@ class Module { * the file from source. This has the benefit of being synchronous. As a * result it is possible to read many cached Module in a row, synchronously. */ - readCached(transformOptions: TransformOptions): ?ReadResult { + readCached(transformOptions: TransformOptions): CachedReadResult { const key = stableObjectHash(transformOptions || {}); - if (this._readResultsByOptionsKey.has(key)) { - return this._readResultsByOptionsKey.get(key); + let result = this._readResultsByOptionsKey.get(key); + if (result != null) { + return result; } - const result = this._readFromTransformCache(transformOptions, key); + result = this._readFromTransformCache(transformOptions, key); this._readResultsByOptionsKey.set(key, result); return result; } @@ -375,13 +381,16 @@ class Module { _readFromTransformCache( transformOptions: TransformOptions, transformOptionsKey: string, - ): ?ReadResult { + ): CachedReadResult { const cacheProps = this._getCacheProps(transformOptions, transformOptionsKey); const cachedResult = TransformCache.readSync(cacheProps); - if (cachedResult) { - return this._finalizeReadResult(cacheProps.sourceCode, cachedResult); + if (cachedResult.result == null) { + return {result: null, outdatedDependencies: cachedResult.outdatedDependencies}; } - return null; + return { + result: this._finalizeReadResult(cacheProps.sourceCode, cachedResult.result), + outdatedDependencies: [], + }; } /** @@ -411,7 +420,7 @@ class Module { }, ); }).then(result => { - this._readResultsByOptionsKey.set(key, result); + this._readResultsByOptionsKey.set(key, {result, outdatedDependencies: []}); return result; }); }); From 2682e1465199e1713aabc360f00fc43a33697dcc Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Thu, 13 Apr 2017 12:38:45 -0700 Subject: [PATCH 14/69] Remove references to CSSLayoutDEPRECATED Reviewed By: marco-cova Differential Revision: D4859822 fbshipit-source-id: 2588c1b3334f28332ae43e6c0bdec65934ca84c4 --- .../react/flat/FlatARTSurfaceViewManager.java | 4 +- .../java/com/facebook/react/flat/RCTText.java | 4 +- .../com/facebook/react/flat/RCTTextInput.java | 4 +- .../views/art/ARTSurfaceViewManager.java | 4 +- .../progressbar/ProgressBarShadowNode.java | 4 +- .../views/slider/ReactSliderManager.java | 4 +- .../views/switchview/ReactSwitchManager.java | 4 +- .../react/views/text/ReactTextShadowNode.java | 4 +- .../textinput/ReactTextInputShadowNode.java | 4 +- .../facebook/yoga/YogaBaselineFunction.java | 2 +- .../facebook/yoga/YogaMeasureFunction.java | 2 +- .../main/java/com/facebook/yoga/YogaNode.java | 89 +--------------- .../java/com/facebook/yoga/YogaNodeAPI.java | 100 ------------------ 13 files changed, 21 insertions(+), 208 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeAPI.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatARTSurfaceViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatARTSurfaceViewManager.java index 730af183dbb99d..a3fad3aba70891 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatARTSurfaceViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatARTSurfaceViewManager.java @@ -11,7 +11,7 @@ import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.views.art.ARTSurfaceView; @@ -24,7 +24,7 @@ public class FlatARTSurfaceViewManager extends private static final YogaMeasureFunction MEASURE_FUNCTION = new YogaMeasureFunction() { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTText.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTText.java index fb97bdeab59bee..e1027817191cfd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTText.java @@ -19,7 +19,7 @@ import com.facebook.yoga.YogaDirection; import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import com.facebook.yoga.YogaMeasureOutput; import com.facebook.fbui.textlayoutbuilder.TextLayoutBuilder; import com.facebook.fbui.textlayoutbuilder.glyphwarmer.GlyphWarmerImpl; @@ -75,7 +75,7 @@ public boolean isVirtualAnchor() { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java index 4b609d737daa02..2af86a5a7340c8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTTextInput.java @@ -20,7 +20,7 @@ import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import com.facebook.yoga.YogaMeasureOutput; import com.facebook.infer.annotation.Assertions; import com.facebook.react.uimanager.PixelUtil; @@ -78,7 +78,7 @@ public void setThemedContext(ThemedReactContext themedContext) { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java index 23d59072962ba2..13745a58ad6160 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java @@ -11,7 +11,7 @@ import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.ThemedReactContext; @@ -29,7 +29,7 @@ public class ARTSurfaceViewManager extends private static final YogaMeasureFunction MEASURE_FUNCTION = new YogaMeasureFunction() { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java index 48266ba0b15974..e8209c002b6298 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java @@ -21,7 +21,7 @@ import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import com.facebook.yoga.YogaMeasureOutput; import com.facebook.react.uimanager.LayoutShadowNode; import com.facebook.react.uimanager.annotations.ReactProp; @@ -54,7 +54,7 @@ public void setStyle(@Nullable String style) { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java index c7488091acd3e3..fe9ac422096c9c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/slider/ReactSliderManager.java @@ -30,7 +30,7 @@ import com.facebook.yoga.YogaMeasureFunction; import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureOutput; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import java.util.Map; @@ -58,7 +58,7 @@ private ReactSliderShadowNode() { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java index 5c70e8b35d3a62..73f687345fc930 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java @@ -17,7 +17,7 @@ import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import com.facebook.yoga.YogaMeasureOutput; import com.facebook.react.bridge.ReactContext; import com.facebook.react.uimanager.LayoutShadowNode; @@ -47,7 +47,7 @@ private ReactSwitchShadowNode() { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index fbfe8a75389937..dbdcc2963b6304 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -35,7 +35,7 @@ import com.facebook.yoga.YogaConstants; import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import com.facebook.yoga.YogaMeasureOutput; import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; @@ -225,7 +225,7 @@ protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) { new YogaMeasureFunction() { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index 362e50c899ef19..2e6c5493c920ed 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -22,7 +22,7 @@ import com.facebook.yoga.YogaDirection; import com.facebook.yoga.YogaMeasureMode; import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaNodeAPI; +import com.facebook.yoga.YogaNode; import com.facebook.yoga.YogaMeasureOutput; import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; @@ -73,7 +73,7 @@ public void setThemedContext(ThemedReactContext themedContext) { @Override public long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaBaselineFunction.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaBaselineFunction.java index 60de81c560fda2..845b128f02f2f4 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaBaselineFunction.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaBaselineFunction.java @@ -18,5 +18,5 @@ public interface YogaBaselineFunction { * default to the computed height of the node. */ @DoNotStrip - float baseline(YogaNodeAPI node, float width, float height); + float baseline(YogaNode node, float width, float height); } diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaMeasureFunction.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaMeasureFunction.java index 6570e5b5b78c60..637551f34a08f8 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaMeasureFunction.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaMeasureFunction.java @@ -18,7 +18,7 @@ public interface YogaMeasureFunction { */ @DoNotStrip long measure( - YogaNodeAPI node, + YogaNode node, float width, YogaMeasureMode widthMode, float height, diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index a0770e9a025fa3..f5d4fab0384a06 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -18,7 +18,7 @@ import com.facebook.soloader.SoLoader; @DoNotStrip -public class YogaNode implements YogaNodeAPI { +public class YogaNode { static { SoLoader.loadLibrary("yoga"); @@ -106,7 +106,6 @@ public YogaNode(YogaConfig config) { } private native void jni_YGNodeFree(long nativePointer); - @Override protected void finalize() throws Throwable { try { jni_YGNodeFree(mNativePointer); @@ -116,7 +115,6 @@ protected void finalize() throws Throwable { } private native void jni_YGNodeReset(long nativePointer); - @Override public void reset() { mEdgeSetFlag = 0; mHasSetPosition = false; @@ -146,18 +144,15 @@ public void reset() { jni_YGNodeReset(mNativePointer); } - @Override public int getChildCount() { return mChildren == null ? 0 : mChildren.size(); } - @Override public YogaNode getChildAt(int i) { return mChildren.get(i); } private native void jni_YGNodeInsertChild(long nativePointer, long childPointer, int index); - @Override public void addChildAt(YogaNode child, int i) { if (child.mParent != null) { throw new IllegalStateException("Child already has a parent, it must be removed first."); @@ -172,7 +167,6 @@ public void addChildAt(YogaNode child, int i) { } private native void jni_YGNodeRemoveChild(long nativePointer, long childPointer); - @Override public YogaNode removeChildAt(int i) { final YogaNode child = mChildren.remove(i); @@ -181,221 +175,184 @@ public YogaNode removeChildAt(int i) { return child; } - @Override public @Nullable YogaNode getParent() { return mParent; } - @Override public int indexOf(YogaNode child) { return mChildren == null ? -1 : mChildren.indexOf(child); } private native void jni_YGNodeCalculateLayout(long nativePointer, float width, float height); - @Override public void calculateLayout(float width, float height) { jni_YGNodeCalculateLayout(mNativePointer, width, height); } - @Override public boolean hasNewLayout() { return mHasNewLayout; } private native void jni_YGNodeMarkDirty(long nativePointer); - @Override public void dirty() { jni_YGNodeMarkDirty(mNativePointer); } private native boolean jni_YGNodeIsDirty(long nativePointer); - @Override public boolean isDirty() { return jni_YGNodeIsDirty(mNativePointer); } private native void jni_YGNodeCopyStyle(long dstNativePointer, long srcNativePointer); - @Override public void copyStyle(YogaNode srcNode) { jni_YGNodeCopyStyle(mNativePointer, srcNode.mNativePointer); } - @Override public void markLayoutSeen() { mHasNewLayout = false; } private native int jni_YGNodeStyleGetDirection(long nativePointer); - @Override public YogaDirection getStyleDirection() { return YogaDirection.fromInt(jni_YGNodeStyleGetDirection(mNativePointer)); } private native void jni_YGNodeStyleSetDirection(long nativePointer, int direction); - @Override public void setDirection(YogaDirection direction) { jni_YGNodeStyleSetDirection(mNativePointer, direction.intValue()); } private native int jni_YGNodeStyleGetFlexDirection(long nativePointer); - @Override public YogaFlexDirection getFlexDirection() { return YogaFlexDirection.fromInt(jni_YGNodeStyleGetFlexDirection(mNativePointer)); } private native void jni_YGNodeStyleSetFlexDirection(long nativePointer, int flexDirection); - @Override public void setFlexDirection(YogaFlexDirection flexDirection) { jni_YGNodeStyleSetFlexDirection(mNativePointer, flexDirection.intValue()); } private native int jni_YGNodeStyleGetJustifyContent(long nativePointer); - @Override public YogaJustify getJustifyContent() { return YogaJustify.fromInt(jni_YGNodeStyleGetJustifyContent(mNativePointer)); } private native void jni_YGNodeStyleSetJustifyContent(long nativePointer, int justifyContent); - @Override public void setJustifyContent(YogaJustify justifyContent) { jni_YGNodeStyleSetJustifyContent(mNativePointer, justifyContent.intValue()); } private native int jni_YGNodeStyleGetAlignItems(long nativePointer); - @Override public YogaAlign getAlignItems() { return YogaAlign.fromInt(jni_YGNodeStyleGetAlignItems(mNativePointer)); } private native void jni_YGNodeStyleSetAlignItems(long nativePointer, int alignItems); - @Override public void setAlignItems(YogaAlign alignItems) { jni_YGNodeStyleSetAlignItems(mNativePointer, alignItems.intValue()); } private native int jni_YGNodeStyleGetAlignSelf(long nativePointer); - @Override public YogaAlign getAlignSelf() { return YogaAlign.fromInt(jni_YGNodeStyleGetAlignSelf(mNativePointer)); } private native void jni_YGNodeStyleSetAlignSelf(long nativePointer, int alignSelf); - @Override public void setAlignSelf(YogaAlign alignSelf) { jni_YGNodeStyleSetAlignSelf(mNativePointer, alignSelf.intValue()); } private native int jni_YGNodeStyleGetAlignContent(long nativePointer); - @Override public YogaAlign getAlignContent() { return YogaAlign.fromInt(jni_YGNodeStyleGetAlignContent(mNativePointer)); } private native void jni_YGNodeStyleSetAlignContent(long nativePointer, int alignContent); - @Override public void setAlignContent(YogaAlign alignContent) { jni_YGNodeStyleSetAlignContent(mNativePointer, alignContent.intValue()); } private native int jni_YGNodeStyleGetPositionType(long nativePointer); - @Override public YogaPositionType getPositionType() { return YogaPositionType.fromInt(jni_YGNodeStyleGetPositionType(mNativePointer)); } private native void jni_YGNodeStyleSetPositionType(long nativePointer, int positionType); - @Override public void setPositionType(YogaPositionType positionType) { jni_YGNodeStyleSetPositionType(mNativePointer, positionType.intValue()); } private native void jni_YGNodeStyleSetFlexWrap(long nativePointer, int wrapType); - @Override public void setWrap(YogaWrap flexWrap) { jni_YGNodeStyleSetFlexWrap(mNativePointer, flexWrap.intValue()); } private native int jni_YGNodeStyleGetOverflow(long nativePointer); - @Override public YogaOverflow getOverflow() { return YogaOverflow.fromInt(jni_YGNodeStyleGetOverflow(mNativePointer)); } private native void jni_YGNodeStyleSetOverflow(long nativePointer, int overflow); - @Override public void setOverflow(YogaOverflow overflow) { jni_YGNodeStyleSetOverflow(mNativePointer, overflow.intValue()); } private native int jni_YGNodeStyleGetDisplay(long nativePointer); - @Override public YogaDisplay getDisplay() { return YogaDisplay.fromInt(jni_YGNodeStyleGetDisplay(mNativePointer)); } private native void jni_YGNodeStyleSetDisplay(long nativePointer, int display); - @Override public void setDisplay(YogaDisplay display) { jni_YGNodeStyleSetDisplay(mNativePointer, display.intValue()); } private native void jni_YGNodeStyleSetFlex(long nativePointer, float flex); - @Override public void setFlex(float flex) { jni_YGNodeStyleSetFlex(mNativePointer, flex); } private native float jni_YGNodeStyleGetFlexGrow(long nativePointer); - @Override public float getFlexGrow() { return jni_YGNodeStyleGetFlexGrow(mNativePointer); } private native void jni_YGNodeStyleSetFlexGrow(long nativePointer, float flexGrow); - @Override public void setFlexGrow(float flexGrow) { jni_YGNodeStyleSetFlexGrow(mNativePointer, flexGrow); } private native float jni_YGNodeStyleGetFlexShrink(long nativePointer); - @Override public float getFlexShrink() { return jni_YGNodeStyleGetFlexShrink(mNativePointer); } private native void jni_YGNodeStyleSetFlexShrink(long nativePointer, float flexShrink); - @Override public void setFlexShrink(float flexShrink) { jni_YGNodeStyleSetFlexShrink(mNativePointer, flexShrink); } private native Object jni_YGNodeStyleGetFlexBasis(long nativePointer); - @Override public YogaValue getFlexBasis() { return (YogaValue) jni_YGNodeStyleGetFlexBasis(mNativePointer); } private native void jni_YGNodeStyleSetFlexBasis(long nativePointer, float flexBasis); - @Override public void setFlexBasis(float flexBasis) { jni_YGNodeStyleSetFlexBasis(mNativePointer, flexBasis); } private native void jni_YGNodeStyleSetFlexBasisPercent(long nativePointer, float percent); - @Override public void setFlexBasisPercent(float percent) { jni_YGNodeStyleSetFlexBasisPercent(mNativePointer, percent); } private native void jni_YGNodeStyleSetFlexBasisAuto(long nativePointer); - @Override public void setFlexBasisAuto() { jni_YGNodeStyleSetFlexBasisAuto(mNativePointer); } private native Object jni_YGNodeStyleGetMargin(long nativePointer, int edge); - @Override public YogaValue getMargin(YogaEdge edge) { if (!((mEdgeSetFlag & MARGIN) == MARGIN)) { return YogaValue.UNDEFINED; @@ -404,28 +361,24 @@ public YogaValue getMargin(YogaEdge edge) { } private native void jni_YGNodeStyleSetMargin(long nativePointer, int edge, float margin); - @Override public void setMargin(YogaEdge edge, float margin) { mEdgeSetFlag |= MARGIN; jni_YGNodeStyleSetMargin(mNativePointer, edge.intValue(), margin); } private native void jni_YGNodeStyleSetMarginPercent(long nativePointer, int edge, float percent); - @Override public void setMarginPercent(YogaEdge edge, float percent) { mEdgeSetFlag |= MARGIN; jni_YGNodeStyleSetMarginPercent(mNativePointer, edge.intValue(), percent); } private native void jni_YGNodeStyleSetMarginAuto(long nativePointer, int edge); - @Override public void setMarginAuto(YogaEdge edge) { mEdgeSetFlag |= MARGIN; jni_YGNodeStyleSetMarginAuto(mNativePointer, edge.intValue()); } private native Object jni_YGNodeStyleGetPadding(long nativePointer, int edge); - @Override public YogaValue getPadding(YogaEdge edge) { if (!((mEdgeSetFlag & PADDING) == PADDING)) { return YogaValue.UNDEFINED; @@ -434,21 +387,18 @@ public YogaValue getPadding(YogaEdge edge) { } private native void jni_YGNodeStyleSetPadding(long nativePointer, int edge, float padding); - @Override public void setPadding(YogaEdge edge, float padding) { mEdgeSetFlag |= PADDING; jni_YGNodeStyleSetPadding(mNativePointer, edge.intValue(), padding); } private native void jni_YGNodeStyleSetPaddingPercent(long nativePointer, int edge, float percent); - @Override public void setPaddingPercent(YogaEdge edge, float percent) { mEdgeSetFlag |= PADDING; jni_YGNodeStyleSetPaddingPercent(mNativePointer, edge.intValue(), percent); } private native float jni_YGNodeStyleGetBorder(long nativePointer, int edge); - @Override public float getBorder(YogaEdge edge) { if (!((mEdgeSetFlag & BORDER) == BORDER)) { return YogaConstants.UNDEFINED; @@ -457,14 +407,12 @@ public float getBorder(YogaEdge edge) { } private native void jni_YGNodeStyleSetBorder(long nativePointer, int edge, float border); - @Override public void setBorder(YogaEdge edge, float border) { mEdgeSetFlag |= BORDER; jni_YGNodeStyleSetBorder(mNativePointer, edge.intValue(), border); } private native Object jni_YGNodeStyleGetPosition(long nativePointer, int edge); - @Override public YogaValue getPosition(YogaEdge edge) { if (!mHasSetPosition) { return YogaValue.UNDEFINED; @@ -473,135 +421,113 @@ public YogaValue getPosition(YogaEdge edge) { } private native void jni_YGNodeStyleSetPosition(long nativePointer, int edge, float position); - @Override public void setPosition(YogaEdge edge, float position) { mHasSetPosition = true; jni_YGNodeStyleSetPosition(mNativePointer, edge.intValue(), position); } private native void jni_YGNodeStyleSetPositionPercent(long nativePointer, int edge, float percent); - @Override public void setPositionPercent(YogaEdge edge, float percent) { mHasSetPosition = true; jni_YGNodeStyleSetPositionPercent(mNativePointer, edge.intValue(), percent); } private native Object jni_YGNodeStyleGetWidth(long nativePointer); - @Override public YogaValue getWidth() { return (YogaValue) jni_YGNodeStyleGetWidth(mNativePointer); } private native void jni_YGNodeStyleSetWidth(long nativePointer, float width); - @Override public void setWidth(float width) { jni_YGNodeStyleSetWidth(mNativePointer, width); } private native void jni_YGNodeStyleSetWidthPercent(long nativePointer, float percent); - @Override public void setWidthPercent(float percent) { jni_YGNodeStyleSetWidthPercent(mNativePointer, percent); } private native void jni_YGNodeStyleSetWidthAuto(long nativePointer); - @Override public void setWidthAuto() { jni_YGNodeStyleSetWidthAuto(mNativePointer); } private native Object jni_YGNodeStyleGetHeight(long nativePointer); - @Override public YogaValue getHeight() { return (YogaValue) jni_YGNodeStyleGetHeight(mNativePointer); } private native void jni_YGNodeStyleSetHeight(long nativePointer, float height); - @Override public void setHeight(float height) { jni_YGNodeStyleSetHeight(mNativePointer, height); } private native void jni_YGNodeStyleSetHeightPercent(long nativePointer, float percent); - @Override public void setHeightPercent(float percent) { jni_YGNodeStyleSetHeightPercent(mNativePointer, percent); } private native void jni_YGNodeStyleSetHeightAuto(long nativePointer); - @Override public void setHeightAuto() { jni_YGNodeStyleSetHeightAuto(mNativePointer); } private native Object jni_YGNodeStyleGetMinWidth(long nativePointer); - @Override public YogaValue getMinWidth() { return (YogaValue) jni_YGNodeStyleGetMinWidth(mNativePointer); } private native void jni_YGNodeStyleSetMinWidth(long nativePointer, float minWidth); - @Override public void setMinWidth(float minWidth) { jni_YGNodeStyleSetMinWidth(mNativePointer, minWidth); } private native void jni_YGNodeStyleSetMinWidthPercent(long nativePointer, float percent); - @Override public void setMinWidthPercent(float percent) { jni_YGNodeStyleSetMinWidthPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetMinHeight(long nativePointer); - @Override public YogaValue getMinHeight() { return (YogaValue) jni_YGNodeStyleGetMinHeight(mNativePointer); } private native void jni_YGNodeStyleSetMinHeight(long nativePointer, float minHeight); - @Override public void setMinHeight(float minHeight) { jni_YGNodeStyleSetMinHeight(mNativePointer, minHeight); } private native void jni_YGNodeStyleSetMinHeightPercent(long nativePointer, float percent); - @Override public void setMinHeightPercent(float percent) { jni_YGNodeStyleSetMinHeightPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetMaxWidth(long nativePointer); - @Override public YogaValue getMaxWidth() { return (YogaValue) jni_YGNodeStyleGetMaxWidth(mNativePointer); } private native void jni_YGNodeStyleSetMaxWidth(long nativePointer, float maxWidth); - @Override public void setMaxWidth(float maxWidth) { jni_YGNodeStyleSetMaxWidth(mNativePointer, maxWidth); } private native void jni_YGNodeStyleSetMaxWidthPercent(long nativePointer, float percent); - @Override public void setMaxWidthPercent(float percent) { jni_YGNodeStyleSetMaxWidthPercent(mNativePointer, percent); } private native Object jni_YGNodeStyleGetMaxHeight(long nativePointer); - @Override public YogaValue getMaxHeight() { return (YogaValue) jni_YGNodeStyleGetMaxHeight(mNativePointer); } private native void jni_YGNodeStyleSetMaxHeight(long nativePointer, float maxheight); - @Override public void setMaxHeight(float maxheight) { jni_YGNodeStyleSetMaxHeight(mNativePointer, maxheight); } private native void jni_YGNodeStyleSetMaxHeightPercent(long nativePointer, float percent); - @Override public void setMaxHeightPercent(float percent) { jni_YGNodeStyleSetMaxHeightPercent(mNativePointer, percent); } @@ -616,27 +542,22 @@ public void setAspectRatio(float aspectRatio) { jni_YGNodeStyleSetAspectRatio(mNativePointer, aspectRatio); } - @Override public float getLayoutX() { return mLeft; } - @Override public float getLayoutY() { return mTop; } - @Override public float getLayoutWidth() { return mWidth; } - @Override public float getLayoutHeight() { return mHeight; } - @Override public float getLayoutMargin(YogaEdge edge) { switch (edge) { case LEFT: @@ -656,7 +577,6 @@ public float getLayoutMargin(YogaEdge edge) { } } - @Override public float getLayoutPadding(YogaEdge edge) { switch (edge) { case LEFT: @@ -676,7 +596,6 @@ public float getLayoutPadding(YogaEdge edge) { } } - @Override public float getLayoutBorder(YogaEdge edge) { switch (edge) { case LEFT: @@ -696,13 +615,11 @@ public float getLayoutBorder(YogaEdge edge) { } } - @Override public YogaDirection getLayoutDirection() { return YogaDirection.fromInt(mLayoutDirection); } private native void jni_YGNodeSetHasMeasureFunc(long nativePointer, boolean hasMeasureFunc); - @Override public void setMeasureFunction(YogaMeasureFunction measureFunction) { mMeasureFunction = measureFunction; jni_YGNodeSetHasMeasureFunc(mNativePointer, measureFunction != null); @@ -728,7 +645,6 @@ public final long measure(float width, int widthMode, float height, int heightMo } private native void jni_YGNodeSetHasBaselineFunc(long nativePointer, boolean hasMeasureFunc); - @Override public void setBaselineFunction(YogaBaselineFunction baselineFunction) { mBaselineFunction = baselineFunction; jni_YGNodeSetHasBaselineFunc(mNativePointer, baselineFunction != null); @@ -739,17 +655,14 @@ public final float baseline(float width, float height) { return mBaselineFunction.baseline(this, width, height); } - @Override public boolean isMeasureDefined() { return mMeasureFunction != null; } - @Override public void setData(Object data) { mData = data; } - @Override public Object getData() { return mData; } diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeAPI.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeAPI.java deleted file mode 100644 index 1c4af327d70911..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeAPI.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.yoga; - -// This only exists for legacy reasons. It will be removed sometime in the near future. -public interface YogaNodeAPI { - int getChildCount(); - YogaNodeType getChildAt(int i); - void addChildAt(YogaNodeType child, int i); - YogaNodeType removeChildAt(int i); - YogaNodeType getParent(); - int indexOf(YogaNodeType child); - void setMeasureFunction(YogaMeasureFunction measureFunction); - void setBaselineFunction(YogaBaselineFunction measureFunction); - boolean isMeasureDefined(); - void calculateLayout(float width, float height); - boolean isDirty(); - boolean hasNewLayout(); - void dirty(); - void markLayoutSeen(); - void copyStyle(YogaNodeType srcNode); - YogaDirection getStyleDirection(); - void setDirection(YogaDirection direction); - YogaFlexDirection getFlexDirection(); - void setFlexDirection(YogaFlexDirection flexDirection); - YogaJustify getJustifyContent(); - void setJustifyContent(YogaJustify justifyContent); - YogaAlign getAlignItems(); - void setAlignItems(YogaAlign alignItems); - YogaAlign getAlignSelf(); - void setAlignSelf(YogaAlign alignSelf); - YogaAlign getAlignContent(); - void setAlignContent(YogaAlign alignContent); - YogaPositionType getPositionType(); - void setPositionType(YogaPositionType positionType); - void setWrap(YogaWrap flexWrap); - void setFlex(float flex); - float getFlexGrow(); - void setFlexGrow(float flexGrow); - float getFlexShrink(); - void setFlexShrink(float flexShrink); - YogaValue getFlexBasis(); - void setFlexBasis(float flexBasis); - void setFlexBasisPercent(float percent); - void setFlexBasisAuto(); - YogaValue getMargin(YogaEdge edge); - void setMargin(YogaEdge edge, float margin); - void setMarginPercent(YogaEdge edge, float percent); - void setMarginAuto(YogaEdge edge); - YogaValue getPadding(YogaEdge edge); - void setPadding(YogaEdge edge, float padding); - void setPaddingPercent(YogaEdge edge, float percent); - float getBorder(YogaEdge edge); - void setBorder(YogaEdge edge, float border); - YogaValue getPosition(YogaEdge edge); - void setPosition(YogaEdge edge, float position); - void setPositionPercent(YogaEdge edge, float percent); - YogaValue getWidth(); - void setWidth(float width); - void setWidthPercent(float percent); - void setWidthAuto(); - YogaValue getHeight(); - void setHeight(float height); - void setHeightPercent(float percent); - void setHeightAuto(); - YogaValue getMaxWidth(); - void setMaxWidth(float maxWidth); - void setMaxWidthPercent(float percent); - YogaValue getMinWidth(); - void setMinWidth(float minWidth); - void setMinWidthPercent(float percent); - YogaValue getMaxHeight(); - void setMaxHeight(float maxHeight); - void setMaxHeightPercent(float percent); - YogaValue getMinHeight(); - void setMinHeight(float minHeight); - void setMinHeightPercent(float percent); - float getLayoutX(); - float getLayoutY(); - float getLayoutWidth(); - float getLayoutHeight(); - float getLayoutMargin(YogaEdge edge); - float getLayoutPadding(YogaEdge edge); - float getLayoutBorder(YogaEdge edge); - YogaDirection getLayoutDirection(); - YogaOverflow getOverflow(); - void setOverflow(YogaOverflow overflow); - YogaDisplay getDisplay(); - void setDisplay(YogaDisplay display); - void setData(Object data); - Object getData(); - void reset(); -} From a311d126d464a9721ecc3318ca4c41b3e1ac0fda Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 13 Apr 2017 14:53:45 -0700 Subject: [PATCH 15/69] Fixed bad ReactPropTypes reference in ViewPagerAndroid Reviewed By: spicyj Differential Revision: D4885894 fbshipit-source-id: 2e225354b76bf21dca84c2e723d9b7e27882648d --- .../ViewPager/ViewPagerAndroid.android.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js index cf0192c2bd237e..5d15a25db3fb44 100644 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js +++ b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js @@ -85,7 +85,7 @@ class ViewPagerAndroid extends React.Component { * Index of initial page that should be selected. Use `setPage` method to * update the page, and `onPageSelected` to monitor page changes */ - initialPage: ReactPropTypes.number, + initialPage: PropTypes.number, /** * Executed when transitioning between pages (ether because of animation for @@ -96,7 +96,7 @@ class ViewPagerAndroid extends React.Component { * Value x means that (1 - x) fraction of the page at "position" index is * visible, and x fraction of the next page is visible. */ - onPageScroll: ReactPropTypes.func, + onPageScroll: PropTypes.func, /** * Function called when the page scrolling state has changed. @@ -106,7 +106,7 @@ class ViewPagerAndroid extends React.Component { * - settling, meaning that there was an interaction with the page scroller, and the * page scroller is now finishing it's closing or opening animation */ - onPageScrollStateChanged: ReactPropTypes.func, + onPageScrollStateChanged: PropTypes.func, /** * This callback will be called once ViewPager finish navigating to selected page @@ -114,20 +114,20 @@ class ViewPagerAndroid extends React.Component { * callback will have following fields: * - position - index of page that has been selected */ - onPageSelected: ReactPropTypes.func, + onPageSelected: PropTypes.func, /** * Blank space to show between pages. This is only visible while scrolling, pages are still * edge-to-edge. */ - pageMargin: ReactPropTypes.number, + pageMargin: PropTypes.number, /** * Determines whether the keyboard gets dismissed in response to a drag. * - 'none' (the default), drags do not dismiss the keyboard. * - 'on-drag', the keyboard is dismissed when a drag begins. */ - keyboardDismissMode: ReactPropTypes.oneOf([ + keyboardDismissMode: PropTypes.oneOf([ 'none', // default 'on-drag', ]), @@ -136,7 +136,7 @@ class ViewPagerAndroid extends React.Component { * When false, the content does not scroll. * The default value is true. */ - scrollEnabled: ReactPropTypes.bool, + scrollEnabled: PropTypes.bool, }; componentDidMount() { From e25f4fa8ac6e71eaffcdfd09a683f3854eb09c49 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Thu, 13 Apr 2017 15:32:47 -0700 Subject: [PATCH 16/69] Revert D4850458: [yoga][PR] Let measure behave more like on the web Differential Revision: D4850458 fbshipit-source-id: 2ecb6c8627a84b52ade968fd18331a7473369ebe --- ReactCommon/yoga/yoga/Yoga.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index e70cb5f8746ca8..4acfae7415c8f8 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -1654,6 +1654,13 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, node, YGFlexDirectionRow, availableWidth - marginAxisRow, parentWidth, parentWidth); node->layout.measuredDimensions[YGDimensionHeight] = YGNodeBoundAxis( node, YGFlexDirectionColumn, availableHeight - marginAxisColumn, parentHeight, parentWidth); + } else if (innerWidth <= 0.0f || innerHeight <= 0.0f) { + // Don't bother sizing the text if there's no horizontal or vertical + // space. + node->layout.measuredDimensions[YGDimensionWidth] = + YGNodeBoundAxis(node, YGFlexDirectionRow, 0.0f, availableWidth, availableWidth); + node->layout.measuredDimensions[YGDimensionHeight] = + YGNodeBoundAxis(node, YGFlexDirectionColumn, 0.0f, availableHeight, availableWidth); } else { // Measure the text under the current constraints. const YGSize measuredSize = From 6835aca7170ea1e44e2c992ecd9d03ad12cf4689 Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Thu, 13 Apr 2017 15:56:50 -0700 Subject: [PATCH 17/69] disable removeClippedSubviews by default Summary: It's just causing problems (e.g. when combined with transform animations like those used in some navigators) and hopefully it's not necessary with JS-side windowing. If people need the perf, they can turn it on themselves. Should fix https://github.com/facebook/react-native/issues/13316 and related issues. Reviewed By: achen1 Differential Revision: D4884147 fbshipit-source-id: 95c82448581076c0d0b2c80b1cd80cc294898174 --- Libraries/Lists/FlatList.js | 10 ++++++---- Libraries/Lists/SectionList.js | 10 ++++++---- Libraries/Lists/VirtualizedList.js | 11 +++-------- .../__tests__/__snapshots__/FlatList-test.js.snap | 4 ---- .../__tests__/__snapshots__/SectionList-test.js.snap | 3 --- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index af8511e663889c..ca00b5621b7b42 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -156,6 +156,12 @@ type OptionalProps = { * Set this true while waiting for new data from a refresh. */ refreshing?: ?boolean, + /** + * Note: may have bugs (missing content) in some circumstances - use at your own risk. + * + * This may improve scroll performance for large lists. + */ + removeClippedSubviews?: boolean, /** * See `ViewabilityHelper` for flow type and further documentation. */ @@ -273,10 +279,6 @@ type DefaultProps = typeof defaultProps; * - By default, the list looks for a `key` prop on each item and uses that for the React key. * Alternatively, you can provide a custom `keyExtractor` prop. * - * NOTE: `removeClippedSubviews` might not be necessary and may cause bugs. If you see issues with - * content not rendering, e.g when using `LayoutAnimation`, try setting - * `removeClippedSubviews={false}`, and we may change the default in the future after more - * experimentation in production apps. */ class FlatList extends React.PureComponent, void> { static defaultProps: DefaultProps = defaultProps; diff --git a/Libraries/Lists/SectionList.js b/Libraries/Lists/SectionList.js index c73d121b8e7896..0643994d2b9e8e 100644 --- a/Libraries/Lists/SectionList.js +++ b/Libraries/Lists/SectionList.js @@ -140,6 +140,12 @@ type OptionalProps> = { * Set this true while waiting for new data from a refresh. */ refreshing?: ?boolean, + /** + * Note: may have bugs (missing content) in some circumstances - use at your own risk. + * + * This may improve scroll performance for large lists. + */ + removeClippedSubviews?: boolean, /** * Rendered at the top of each section. These stick to the top of the `ScrollView` by default on * iOS. See `stickySectionHeadersEnabled`. @@ -217,10 +223,6 @@ type DefaultProps = typeof defaultProps; * - By default, the list looks for a `key` prop on each item and uses that for the React key. * Alternatively, you can provide a custom `keyExtractor` prop. * - * NOTE: `removeClippedSubviews` might not be necessary and may cause bugs. If you see issues with - * content not rendering, e.g when using `LayoutAnimation`, try setting - * `removeClippedSubviews={false}`, and we may change the default in the future after more - * experimentation in production apps. */ class SectionList> extends React.PureComponent, void> diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index b03d8198aa7c6f..2a909e1c8fe419 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -110,9 +110,9 @@ type OptionalProps = { */ refreshing?: ?boolean, /** - * A native optimization that removes clipped subviews (those outside the parent) from the view - * hierarchy to offload work from the native rendering system. They are still kept around so no - * memory is saved and state is preserved. + * Note: may have bugs (missing content) in some circumstances - use at your own risk. + * + * This may improve scroll performance for large lists. */ removeClippedSubviews?: boolean, /** @@ -167,10 +167,6 @@ type State = {first: number, last: number}; * - By default, the list looks for a `key` prop on each item and uses that for the React key. * Alternatively, you can provide a custom `keyExtractor` prop. * - * NOTE: `removeClippedSubviews` might not be necessary and may cause bugs. If you see issues with - * content not rendering, e.g when using `LayoutAnimation`, try setting - * `removeClippedSubviews={false}`, and we may change the default in the future after more - * experimentation in production apps. */ class VirtualizedList extends React.PureComponent { props: Props; @@ -270,7 +266,6 @@ class VirtualizedList extends React.PureComponent { }, maxToRenderPerBatch: 10, onEndReachedThreshold: 2, // multiples of length - removeClippedSubviews: true, renderScrollComponent: (props: Props) => { if (props.onRefresh) { invariant( diff --git a/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap b/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap index db1a896ae114b2..9d6860f5b55f1e 100644 --- a/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap +++ b/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap @@ -47,7 +47,6 @@ exports[`FlatList renders all the bells and whistles 1`] = ` /> } refreshing={false} - removeClippedSubviews={true} renderItem={[Function]} renderScrollComponent={[Function]} scrollEventThrottle={50} @@ -150,7 +149,6 @@ exports[`FlatList renders empty list 1`] = ` onScroll={[Function]} onScrollBeginDrag={[Function]} onViewableItemsChanged={undefined} - removeClippedSubviews={true} renderItem={[Function]} renderScrollComponent={[Function]} scrollEventThrottle={50} @@ -179,7 +177,6 @@ exports[`FlatList renders null list 1`] = ` onScroll={[Function]} onScrollBeginDrag={[Function]} onViewableItemsChanged={undefined} - removeClippedSubviews={true} renderItem={[Function]} renderScrollComponent={[Function]} scrollEventThrottle={50} @@ -220,7 +217,6 @@ exports[`FlatList renders simple list 1`] = ` onScroll={[Function]} onScrollBeginDrag={[Function]} onViewableItemsChanged={undefined} - removeClippedSubviews={true} renderItem={[Function]} renderScrollComponent={[Function]} scrollEventThrottle={50} diff --git a/Libraries/Lists/__tests__/__snapshots__/SectionList-test.js.snap b/Libraries/Lists/__tests__/__snapshots__/SectionList-test.js.snap index 62ef2dfb90c0d2..409523f84fc93d 100644 --- a/Libraries/Lists/__tests__/__snapshots__/SectionList-test.js.snap +++ b/Libraries/Lists/__tests__/__snapshots__/SectionList-test.js.snap @@ -31,7 +31,6 @@ exports[`SectionList rendering empty section headers is fine 1`] = ` onScroll={[Function]} onScrollBeginDrag={[Function]} onViewableItemsChanged={undefined} - removeClippedSubviews={true} renderItem={[Function]} renderScrollComponent={[Function]} renderSectionHeader={[Function]} @@ -138,7 +137,6 @@ exports[`SectionList renders all the bells and whistles 1`] = ` /> } refreshing={false} - removeClippedSubviews={true} renderItem={[Function]} renderScrollComponent={[Function]} renderSectionHeader={[Function]} @@ -271,7 +269,6 @@ exports[`SectionList renders empty list 1`] = ` onScroll={[Function]} onScrollBeginDrag={[Function]} onViewableItemsChanged={undefined} - removeClippedSubviews={true} renderItem={[Function]} renderScrollComponent={[Function]} scrollEventThrottle={50} From d1e8cd7df0caf9777d70b894d00500ef765a2a39 Mon Sep 17 00:00:00 2001 From: George Xu Date: Thu, 13 Apr 2017 18:01:35 -0700 Subject: [PATCH 18/69] Revert D4875343: Correct fix for flexing grandchildren Differential Revision: D4875343 fbshipit-source-id: 2949762bf47e151c8c0ff923d501859b3e0a567a --- ReactCommon/yoga/yoga/YGEnums.c | 2 ++ ReactCommon/yoga/yoga/YGEnums.h | 1 + ReactCommon/yoga/yoga/Yoga.c | 7 ++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGEnums.c b/ReactCommon/yoga/yoga/YGEnums.c index 53a057780a68f4..0108e6a616cfa3 100644 --- a/ReactCommon/yoga/yoga/YGEnums.c +++ b/ReactCommon/yoga/yoga/YGEnums.c @@ -93,6 +93,8 @@ const char *YGExperimentalFeatureToString(const YGExperimentalFeature value){ return "rounding"; case YGExperimentalFeatureWebFlexBasis: return "web-flex-basis"; + case YGExperimentalFeatureMinFlexFix: + return "min-flex-fix"; } return "unknown"; } diff --git a/ReactCommon/yoga/yoga/YGEnums.h b/ReactCommon/yoga/yoga/YGEnums.h index aa14933b77b1d8..8a929b9e7ad9a9 100644 --- a/ReactCommon/yoga/yoga/YGEnums.h +++ b/ReactCommon/yoga/yoga/YGEnums.h @@ -66,6 +66,7 @@ WIN_EXPORT const char *YGEdgeToString(const YGEdge value); typedef YG_ENUM_BEGIN(YGExperimentalFeature) { YGExperimentalFeatureRounding, YGExperimentalFeatureWebFlexBasis, + YGExperimentalFeatureMinFlexFix, } YG_ENUM_END(YGExperimentalFeature); WIN_EXPORT const char *YGExperimentalFeatureToString(const YGExperimentalFeature value); diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index 4acfae7415c8f8..f7be592aacdb72 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -203,6 +203,7 @@ static YGConfig gYGConfigDefaults = { .experimentalFeatures = { [YGExperimentalFeatureRounding] = false, + [YGExperimentalFeatureMinFlexFix] = false, [YGExperimentalFeatureWebFlexBasis] = false, }, .useWebDefaults = false, @@ -2202,9 +2203,9 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerMainDim = minInnerMainDim; } else if (!YGFloatIsUndefined(maxInnerMainDim) && sizeConsumedOnCurrentLine > maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; - } else if (totalFlexGrowFactors == 0 || YGResolveFlexGrow(node) == 0) { - // If we don't have any children to flex or we can't flex the node itself, - // space we've used is all space we need + } else if (YGConfigIsExperimentalFeatureEnabled(node->config, YGExperimentalFeatureMinFlexFix)) { + // TODO: this needs to be moved out of experimental feature, as this is legitimate fix + // If the measurement isn't exact, we want to use as little space as possible availableInnerMainDim = sizeConsumedOnCurrentLine; } } From da296ebac9f9f5ea5e9d1da5a44922e53343f8ea Mon Sep 17 00:00:00 2001 From: Aaron Chiu Date: Fri, 14 Apr 2017 02:03:56 -0700 Subject: [PATCH 19/69] make mHasDispatchScheduledCount in EventDispatcher atomic Reviewed By: achen1 Differential Revision: D4882881 fbshipit-source-id: ac9a985287bd4720846ecde97ebb4935963c0d9f --- .../react/uimanager/events/EventDispatcher.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java index 540714b2feefb0..22e6c35f51cafd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java @@ -15,6 +15,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import android.util.LongSparseArray; @@ -93,19 +94,19 @@ public int compare(Event lhs, Event rhs) { private final DispatchEventsRunnable mDispatchEventsRunnable = new DispatchEventsRunnable(); private final ArrayList mEventStaging = new ArrayList<>(); private final ArrayList mListeners = new ArrayList<>(); + private final ScheduleDispatchFrameCallback mCurrentFrameCallback = + new ScheduleDispatchFrameCallback(); + private final AtomicInteger mHasDispatchScheduledCount = new AtomicInteger(); private Event[] mEventsToDispatch = new Event[16]; private int mEventsToDispatchSize = 0; private volatile @Nullable RCTEventEmitter mRCTEventEmitter; - private final ScheduleDispatchFrameCallback mCurrentFrameCallback; private short mNextEventTypeId = 0; private volatile boolean mHasDispatchScheduled = false; - private volatile int mHasDispatchScheduledCount = 0; public EventDispatcher(ReactApplicationContext reactContext) { mReactContext = reactContext; mReactContext.addLifecycleEventListener(this); - mCurrentFrameCallback = new ScheduleDispatchFrameCallback(); } /** @@ -279,7 +280,7 @@ public void doFrame(long frameTimeNanos) { Systrace.startAsyncFlow( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ScheduleDispatchFrameCallback", - mHasDispatchScheduledCount); + mHasDispatchScheduledCount.get()); mReactContext.runOnJSQueueThread(mDispatchEventsRunnable); } } finally { @@ -331,9 +332,8 @@ public void run() { Systrace.endAsyncFlow( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ScheduleDispatchFrameCallback", - mHasDispatchScheduledCount); + mHasDispatchScheduledCount.getAndIncrement()); mHasDispatchScheduled = false; - mHasDispatchScheduledCount++; Assertions.assertNotNull(mRCTEventEmitter); synchronized (mEventsToDispatchLock) { // We avoid allocating an array and iterator, and "sorting" if we don't need to. From fd8c816c46d4ead2a7d7b866c523f492557607a0 Mon Sep 17 00:00:00 2001 From: Aaron Chiu Date: Fri, 14 Apr 2017 02:43:07 -0700 Subject: [PATCH 20/69] loosen the ReactChoreographer UI thread assert Reviewed By: achen1 Differential Revision: D4873553 fbshipit-source-id: 7dbf771e744f6b33e6edb3ad4c227c3a63c3e3e3 --- .../react/testing/ReactTestHelper.java | 2 ++ .../facebook/react/ReactInstanceManager.java | 4 +++ .../modules/core/ReactChoreographer.java | 36 +++++++++++-------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java index 6250d24148e4e1..13a38acd00b569 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java @@ -31,6 +31,7 @@ import com.facebook.react.cxxbridge.JSBundleLoader; import com.facebook.react.cxxbridge.JSCJavaScriptExecutor; import com.facebook.react.cxxbridge.JavaScriptExecutor; +import com.facebook.react.modules.core.ReactChoreographer; import com.android.internal.util.Predicate; @@ -153,6 +154,7 @@ public CatalystInstance build() { InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { + ReactChoreographer.initialize(); instance.initialize(); } }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 97f6f5142d5f5a..cce6499465b0ab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -61,6 +61,7 @@ import com.facebook.react.modules.appregistry.AppRegistry; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.modules.debug.interfaces.DeveloperSettings; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.UIImplementationProvider; @@ -348,6 +349,9 @@ public static ReactInstanceManagerBuilder builder() { mLazyNativeModulesEnabled = lazyNativeModulesEnabled; mLazyViewManagersEnabled = lazyViewManagersEnabled; mUseStartupThread = useStartupThread; + + // Instantiate ReactChoreographer in UI thread. + ReactChoreographer.initialize(); } public DevSupportManager getDevSupportManager() { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java index 71aecde7516277..4e622f52451ec0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java @@ -12,8 +12,8 @@ import java.util.ArrayDeque; import com.facebook.common.logging.FLog; -import com.facebook.react.bridge.UiThreadUtil; import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.common.ReactConstants; /** @@ -65,11 +65,15 @@ private CallbackType(int order) { private static ReactChoreographer sInstance; - public static ReactChoreographer getInstance() { - UiThreadUtil.assertOnUiThread(); + public static void initialize() { if (sInstance == null) { + UiThreadUtil.assertOnUiThread(); sInstance = new ReactChoreographer(); } + } + + public static ReactChoreographer getInstance() { + Assertions.assertNotNull(sInstance, "ReactChoreographer needs to be initialized."); return sInstance; } @@ -89,8 +93,9 @@ private ReactChoreographer() { } } - public void postFrameCallback(CallbackType type, ChoreographerCompat.FrameCallback frameCallback) { - UiThreadUtil.assertOnUiThread(); + public synchronized void postFrameCallback( + CallbackType type, + ChoreographerCompat.FrameCallback frameCallback) { mCallbackQueues[type.getOrder()].addLast(frameCallback); mTotalCallbacks++; Assertions.assertCondition(mTotalCallbacks > 0); @@ -100,8 +105,9 @@ public void postFrameCallback(CallbackType type, ChoreographerCompat.FrameCallba } } - public void removeFrameCallback(CallbackType type, ChoreographerCompat.FrameCallback frameCallback) { - UiThreadUtil.assertOnUiThread(); + public synchronized void removeFrameCallback( + CallbackType type, + ChoreographerCompat.FrameCallback frameCallback) { if (mCallbackQueues[type.getOrder()].removeFirstOccurrence(frameCallback)) { mTotalCallbacks--; maybeRemoveFrameCallback(); @@ -122,15 +128,17 @@ private class ReactChoreographerDispatcher extends ChoreographerCompat.FrameCall @Override public void doFrame(long frameTimeNanos) { - mHasPostedCallback = false; - for (int i = 0; i < mCallbackQueues.length; i++) { - int initialLength = mCallbackQueues[i].size(); - for (int callback = 0; callback < initialLength; callback++) { - mCallbackQueues[i].removeFirst().doFrame(frameTimeNanos); - mTotalCallbacks--; + synchronized (ReactChoreographer.this) { + mHasPostedCallback = false; + for (int i = 0; i < mCallbackQueues.length; i++) { + int initialLength = mCallbackQueues[i].size(); + for (int callback = 0; callback < initialLength; callback++) { + mCallbackQueues[i].removeFirst().doFrame(frameTimeNanos); + mTotalCallbacks--; + } } + maybeRemoveFrameCallback(); } - maybeRemoveFrameCallback(); } } } From 810e9b5b83d2fb4281be7abb497733fe3bcafdd5 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 14 Apr 2017 15:42:47 -0700 Subject: [PATCH 21/69] Ran React.PropTypes codemod on fbsource again in case anything was missed Reviewed By: flarnie Differential Revision: D4890226 fbshipit-source-id: 36b87bd4395c8cfbe260d2c73f919e62b11439a7 --- Libraries/Components/ScrollView/ScrollView.js | 2 +- .../fiber/__tests__/ReactIncremental-test.js | 34 ++++++++++--------- .../__tests__/ReactIncrementalPerf-test.js | 4 ++- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 387465ab3a1b93..bda7aa4cf477dc 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -16,6 +16,7 @@ const ColorPropType = require('ColorPropType'); const EdgeInsetsPropType = require('EdgeInsetsPropType'); const Platform = require('Platform'); const PointPropType = require('PointPropType'); +const PropTypes = require('prop-types'); const React = require('React'); const ReactNative = require('ReactNative'); const ScrollResponder = require('ScrollResponder'); @@ -30,7 +31,6 @@ const dismissKeyboard = require('dismissKeyboard'); const flattenStyle = require('flattenStyle'); const invariant = require('fbjs/lib/invariant'); const processDecelerationRate = require('processDecelerationRate'); -const PropTypes = React.PropTypes; const requireNativeComponent = require('requireNativeComponent'); /** diff --git a/Libraries/Renderer/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js b/Libraries/Renderer/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js index 96a3f032e5f9d8..79874ae698979b 100644 --- a/Libraries/Renderer/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js +++ b/Libraries/Renderer/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js @@ -11,6 +11,7 @@ 'use strict'; +var PropTypes; var React; var ReactNoop; var ReactFeatureFlags; @@ -18,6 +19,7 @@ var ReactFeatureFlags; describe('ReactIncremental', () => { beforeEach(() => { jest.resetModules(); + PropTypes = require('prop-types'); React = require('react'); ReactNoop = require('ReactNoop'); @@ -1594,7 +1596,7 @@ describe('ReactIncremental', () => { class Intl extends React.Component { static childContextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; getChildContext() { return { @@ -1609,7 +1611,7 @@ describe('ReactIncremental', () => { class Router extends React.Component { static childContextTypes = { - route: React.PropTypes.string, + route: PropTypes.string, }; getChildContext() { return { @@ -1624,7 +1626,7 @@ describe('ReactIncremental', () => { class ShowLocale extends React.Component { static contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; render() { ops.push('ShowLocale ' + JSON.stringify(this.context)); @@ -1634,7 +1636,7 @@ describe('ReactIncremental', () => { class ShowRoute extends React.Component { static contextTypes = { - route: React.PropTypes.string, + route: PropTypes.string, }; render() { ops.push('ShowRoute ' + JSON.stringify(this.context)); @@ -1647,8 +1649,8 @@ describe('ReactIncremental', () => { return `${context.route} in ${context.locale}`; } ShowBoth.contextTypes = { - locale: React.PropTypes.string, - route: React.PropTypes.string, + locale: PropTypes.string, + route: PropTypes.string, }; class ShowNeither extends React.Component { @@ -1747,10 +1749,10 @@ describe('ReactIncremental', () => { var ops = []; class Recurse extends React.Component { static contextTypes = { - n: React.PropTypes.number, + n: PropTypes.number, }; static childContextTypes = { - n: React.PropTypes.number, + n: PropTypes.number, }; getChildContext() { return {n: (this.context.n || 3) - 1}; @@ -1779,7 +1781,7 @@ describe('ReactIncremental', () => { class Intl extends React.Component { static childContextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; getChildContext() { return { @@ -1794,7 +1796,7 @@ describe('ReactIncremental', () => { class ShowLocale extends React.Component { static contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; render() { ops.push('ShowLocale ' + JSON.stringify(this.context)); @@ -1837,7 +1839,7 @@ describe('ReactIncremental', () => { class Intl extends React.Component { static childContextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; getChildContext() { const childContext = { @@ -1854,7 +1856,7 @@ describe('ReactIncremental', () => { class ShowLocaleClass extends React.Component { static contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; render() { ops.push('ShowLocaleClass:read ' + JSON.stringify(this.context)); @@ -1867,7 +1869,7 @@ describe('ReactIncremental', () => { return context.locale; } ShowLocaleFn.contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; class Stateful extends React.Component { @@ -1927,7 +1929,7 @@ describe('ReactIncremental', () => { class Intl extends React.Component { static childContextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; getChildContext() { const childContext = { @@ -1944,7 +1946,7 @@ describe('ReactIncremental', () => { class ShowLocaleClass extends React.Component { static contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; render() { ops.push('ShowLocaleClass:read ' + JSON.stringify(this.context)); @@ -1957,7 +1959,7 @@ describe('ReactIncremental', () => { return context.locale; } ShowLocaleFn.contextTypes = { - locale: React.PropTypes.string, + locale: PropTypes.string, }; function IndirectionFn(props, context) { diff --git a/Libraries/Renderer/src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js b/Libraries/Renderer/src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js index b4a47480039fd3..43bec80165da21 100644 --- a/Libraries/Renderer/src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js +++ b/Libraries/Renderer/src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js @@ -12,6 +12,7 @@ 'use strict'; describe('ReactDebugFiberPerf', () => { + let PropTypes; let React; let ReactCoroutine; let ReactFeatureFlags; @@ -113,6 +114,7 @@ describe('ReactDebugFiberPerf', () => { global.performance = createUserTimingPolyfill(); // Import after the polyfill is set up: + PropTypes = require('prop-types'); React = require('React'); ReactCoroutine = require('ReactCoroutine'); ReactFeatureFlags = require('ReactFeatureFlags'); @@ -245,7 +247,7 @@ describe('ReactDebugFiberPerf', () => { it('captures all lifecycles', () => { class AllLifecycles extends React.Component { static childContextTypes = { - foo: React.PropTypes.any, + foo: PropTypes.any, }; shouldComponentUpdate() { return true; From 2a86d745c06b86dcb8a1409c3b73322058ea77d9 Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Fri, 14 Apr 2017 16:10:20 -0700 Subject: [PATCH 22/69] Make invalid scrolling bugs easier to track down Reviewed By: jingc, olegbl Differential Revision: D4887662 fbshipit-source-id: d24590fd79ad1b5f6ada79583dbe870b350ec358 --- Libraries/Components/ScrollResponder.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index 76f58fa69471e4..8d6bbc17b23cf6 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -13,19 +13,19 @@ var Dimensions = require('Dimensions'); var FrameRateLogger = require('FrameRateLogger'); -var Platform = require('Platform'); var Keyboard = require('Keyboard'); var ReactNative = require('ReactNative'); var Subscribable = require('Subscribable'); var TextInputState = require('TextInputState'); var UIManager = require('UIManager'); -var warning = require('fbjs/lib/warning'); - -var { getInstanceFromNode } = require('ReactNativeComponentTree'); -var { ScrollViewManager } = require('NativeModules'); var invariant = require('fbjs/lib/invariant'); +var nullthrows = require('fbjs/lib/nullthrows'); var performanceNow = require('fbjs/lib/performanceNow'); +var warning = require('fbjs/lib/warning'); + +var { ScrollViewManager } = require('NativeModules'); +var { getInstanceFromNode } = require('ReactNativeComponentTree'); /** * Mixin that can be integrated in order to handle scrolling that plays well @@ -412,7 +412,7 @@ var ScrollResponderMixin = { ({x, y, animated} = x || {}); } UIManager.dispatchViewManagerCommand( - this.scrollResponderGetScrollableNode(), + nullthrows(this.scrollResponderGetScrollableNode()), UIManager.RCTScrollView.Commands.scrollTo, [x || 0, y || 0, animated !== false], ); From 591499b4cdde8009ede1d49c9c5eab6c1b7e4c79 Mon Sep 17 00:00:00 2001 From: Aaron Chiu Date: Fri, 14 Apr 2017 16:16:16 -0700 Subject: [PATCH 23/69] clean up NativeAnimatedModule Reviewed By: achen1 Differential Revision: D4883111 fbshipit-source-id: 63873d46db8d2736672a6d102e86dabfbf4f4610 --- .../react/animated/NativeAnimatedModule.java | 85 +++++++++---------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java index d4fd0680ff5147..f03cc8a460fbd5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java @@ -13,7 +13,6 @@ import java.util.ArrayList; -import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; @@ -82,13 +81,51 @@ private interface UIThreadOperation { } private final Object mOperationsCopyLock = new Object(); - private @Nullable GuardedFrameCallback mAnimatedFrameCallback; - private @Nullable ReactChoreographer mReactChoreographer; + private final GuardedFrameCallback mAnimatedFrameCallback; + private final ReactChoreographer mReactChoreographer; private ArrayList mOperations = new ArrayList<>(); private volatile @Nullable ArrayList mReadyOperations = null; + private @Nullable NativeAnimatedNodesManager mNodesManager; + public NativeAnimatedModule(ReactApplicationContext reactContext) { super(reactContext); + + mReactChoreographer = ReactChoreographer.getInstance(); + mAnimatedFrameCallback = new GuardedFrameCallback(reactContext) { + @Override + protected void doFrameGuarded(final long frameTimeNanos) { + if (mNodesManager == null) { + UIManagerModule uiManager = getReactApplicationContext() + .getNativeModule(UIManagerModule.class); + mNodesManager = new NativeAnimatedNodesManager(uiManager); + } + + ArrayList operations; + synchronized (mOperationsCopyLock) { + operations = mReadyOperations; + mReadyOperations = null; + } + + if (operations != null) { + for (int i = 0, size = operations.size(); i < size; i++) { + operations.get(i).execute(mNodesManager); + } + } + + if (mNodesManager.hasActiveAnimations()) { + mNodesManager.runUpdates(frameTimeNanos); + } + + // TODO: Would be great to avoid adding this callback in case there are no active animations + // and no outstanding tasks on the operations queue. Apparently frame callbacks can only + // be posted from the UI thread and therefore we cannot schedule them directly from + // @ReactMethod methods + Assertions.assertNotNull(mReactChoreographer).postFrameCallback( + ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, + mAnimatedFrameCallback); + } + }; } @Override @@ -98,44 +135,6 @@ public void initialize() { @Override public void onHostResume() { - if (mReactChoreographer == null) { - // Safe to acquire choreographer here, as onHostResume() is invoked from UI thread. - mReactChoreographer = ReactChoreographer.getInstance(); - - ReactApplicationContext reactCtx = getReactApplicationContext(); - UIManagerModule uiManager = reactCtx.getNativeModule(UIManagerModule.class); - - final NativeAnimatedNodesManager nodesManager = new NativeAnimatedNodesManager(uiManager); - mAnimatedFrameCallback = new GuardedFrameCallback(reactCtx) { - @Override - protected void doFrameGuarded(final long frameTimeNanos) { - - ArrayList operations; - synchronized (mOperationsCopyLock) { - operations = mReadyOperations; - mReadyOperations = null; - } - - if (operations != null) { - for (int i = 0, size = operations.size(); i < size; i++) { - operations.get(i).execute(nodesManager); - } - } - - if (nodesManager.hasActiveAnimations()) { - nodesManager.runUpdates(frameTimeNanos); - } - - // TODO: Would be great to avoid adding this callback in case there are no active animations - // and no outstanding tasks on the operations queue. Apparently frame callbacks can only - // be posted from the UI thread and therefore we cannot schedule them directly from - // @ReactMethod methods - Assertions.assertNotNull(mReactChoreographer).postFrameCallback( - ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, - mAnimatedFrameCallback); - } - }; - } enqueueFrameCallback(); } @@ -162,10 +161,6 @@ public void onBatchComplete() { @Override public void onHostPause() { - if (mReactChoreographer == null) { - FLog.e(NAME, "Called NativeAnimated.onHostPause() with a null ReactChoreographer."); - return; - } clearFrameCallback(); } From f54fda4c88a2ca390e49f2d7b26600a02c06b071 Mon Sep 17 00:00:00 2001 From: Douglas Lowder Date: Fri, 14 Apr 2017 16:57:09 -0700 Subject: [PATCH 24/69] Add missing prop-types dependency to website/package.json Summary: **Motivation** Website generation is broken unless prop-types is added as a dependency. **Test plan** This fixes website generation in existing Circle CI tests. Closes https://github.com/facebook/react-native/pull/13498 Differential Revision: D4888859 Pulled By: bvaughn fbshipit-source-id: d43afbf3b56c189e723e5628e169947ed5dbacd8 --- website/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/website/package.json b/website/package.json index afab3d1bc8e520..17bb746a5880de 100644 --- a/website/package.json +++ b/website/package.json @@ -23,6 +23,7 @@ "memory-cache": "^0.1.6", "mkdirp": "^0.5.1", "optimist": "0.6.0", + "prop-types": "^15.5.7", "react": "~0.13.0", "react-docgen": "3.0.0-beta2", "react-page-middleware": "0.4.1", From 1bc27a9da3c3f58050816aff6b3257bd2f498330 Mon Sep 17 00:00:00 2001 From: Alex Kring Date: Sat, 15 Apr 2017 10:08:26 -0700 Subject: [PATCH 25/69] Don't build js bundles for debug simulator build configurations Summary: Don't build js bundles for debug simulator build configurations Motivation: We have more than one debug build configuration that we run in the simulator, and none of them are exactly named 'Debug'. We want to establish the convention that any simulator build configuration containing the word 'Debug' will not build the react js bundles. We believe this is less intrusive to the developer. Closes https://github.com/facebook/react-native/pull/13472 Differential Revision: D4890622 Pulled By: javache fbshipit-source-id: 4c809551f64ad575335416de28887a90b0756de1 --- packager/react-native-xcode.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh index dc83971fbe477a..9271538e39ca30 100755 --- a/packager/react-native-xcode.sh +++ b/packager/react-native-xcode.sh @@ -11,7 +11,7 @@ # and relies on environment variables (including PWD) set by Xcode case "$CONFIGURATION" in - Debug) + *Debug*) # Speed up build times by skipping the creation of the offline package for debug # builds on the simulator since the packager is supposed to be running anyways. if [[ "$PLATFORM_NAME" == *simulator ]]; then From ee058b3f629e2c4a0c2c680b7f748ce58803e65a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=A0imo?= Date: Sun, 16 Apr 2017 15:25:05 -0700 Subject: [PATCH 26/69] Change Promise.done to Promise.then Summary: - [X] Explain the **motivation** for making this change. - [X] Provide a **test plan** demonstrating that the code is solid. - [X] Match the **code formatting** of the rest of the codebase. - [X] Target the `master` branch, NOT a "stable" branch. `Promise.done` is non-standard, `Promise.then` is preferred as a standardized method. On Android, polyfill filling in `Promise.done` has been most probably taken out in newer versions of `react-native` and app crashes when it tries to query network state through `NetInfo`. No tests are required for this change. Closes https://github.com/facebook/react-native/pull/13489 Differential Revision: D4897566 Pulled By: mkonicek fbshipit-source-id: 140720d7367cd1d9bf8924ec8a118c1bff4e461d --- Libraries/Network/NetInfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js index 4d1df4ae3d371c..c10166a53c2322 100644 --- a/Libraries/Network/NetInfo.js +++ b/Libraries/Network/NetInfo.js @@ -79,7 +79,7 @@ const _isConnectedSubscriptions = new Map(); * NetInfo exposes info about online/offline status * * ``` - * NetInfo.fetch().done((reach) => { + * NetInfo.fetch().then((reach) => { * console.log('Initial: ' + reach); * }); * function handleFirstConnectivityChange(reach) { From 4705ee1b649e489c505fc0ed6fee565b4776bbd6 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Mon, 17 Apr 2017 07:28:46 -0700 Subject: [PATCH 27/69] Align ios api with android Reviewed By: kittens Differential Revision: D4897832 fbshipit-source-id: ff3215b45de389b91825371a987314e4bab5421f --- Libraries/WebSocket/RCTReconnectingWebSocket.h | 1 + Libraries/WebSocket/RCTReconnectingWebSocket.m | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Libraries/WebSocket/RCTReconnectingWebSocket.h b/Libraries/WebSocket/RCTReconnectingWebSocket.h index 69d4143c2178da..4d15d06792985e 100644 --- a/Libraries/WebSocket/RCTReconnectingWebSocket.h +++ b/Libraries/WebSocket/RCTReconnectingWebSocket.h @@ -23,6 +23,7 @@ - (instancetype)initWithURL:(NSURL *)url; @property (nonatomic, weak) id delegate; +- (void)send:(id)data; - (void)start; - (void)stop; diff --git a/Libraries/WebSocket/RCTReconnectingWebSocket.m b/Libraries/WebSocket/RCTReconnectingWebSocket.m index a2f20c64f8ea7c..a3caa41c9aeb26 100644 --- a/Libraries/WebSocket/RCTReconnectingWebSocket.m +++ b/Libraries/WebSocket/RCTReconnectingWebSocket.m @@ -34,6 +34,11 @@ - (instancetype)initWithURL:(NSURL *)url return self; } +- (void)send:(id)data +{ + [_socket send:data]; +} + - (void)start { [self stop]; From 2c0c3f4b76b74bd44086c78b0fc49ac435727b79 Mon Sep 17 00:00:00 2001 From: Gabe Levi Date: Mon, 17 Apr 2017 09:25:28 -0700 Subject: [PATCH 28/69] Upgrade to v0.44.0 Reviewed By: zertosh Differential Revision: D4893660 fbshipit-source-id: ed85f5d4c585164d464a7e009888a28e5af339cd --- .flowconfig | 6 +++--- Libraries/Lists/MetroListView.js | 11 +++++++++-- Libraries/Lists/SectionList.js | 2 ++ Libraries/Lists/VirtualizedList.js | 2 ++ local-cli/templates/HelloWorld/_flowconfig | 6 +++--- package.json | 2 +- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/.flowconfig b/.flowconfig index 7eec6f4162328f..206069d0d1aabd 100644 --- a/.flowconfig +++ b/.flowconfig @@ -41,12 +41,12 @@ suppress_type=$FlowIssue suppress_type=$FlowFixMe suppress_type=$FixMe -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-3]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native_oss[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-3]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native_oss[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-4]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native_oss[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-4]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native_oss[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError unsafe.enable_getters_and_setters=true [version] -^0.43.1 +^0.44.0 diff --git a/Libraries/Lists/MetroListView.js b/Libraries/Lists/MetroListView.js index 125c605840e1fe..96f04ca2203769 100644 --- a/Libraries/Lists/MetroListView.js +++ b/Libraries/Lists/MetroListView.js @@ -28,6 +28,7 @@ type NormalProps = { // Provide either `items` or `sections` items?: ?Array, // By default, an Item is assumed to be {key: string} + // $FlowFixMe - Something is a little off with the type Array sections?: ?Array<{key: string, data: Array}>, /** @@ -39,10 +40,16 @@ type NormalProps = { * Set this true while waiting for new data from a refresh. */ refreshing?: boolean, + /** + * If true, renders items next to each other horizontally instead of stacked vertically. + */ + horizontal?: ?boolean, }; type DefaultProps = { - keyExtractor: (item: Item) => string, + keyExtractor: (item: Item, index: number) => string, }; +/* $FlowFixMe - the renderItem passed in from SectionList is optional there but + * required here */ type Props = NormalProps & DefaultProps; /** @@ -74,7 +81,7 @@ class MetroListView extends React.Component { return this._listRef; } static defaultProps: DefaultProps = { - keyExtractor: (item, index) => item.key || index, + keyExtractor: (item, index) => item.key || String(index), renderScrollComponent: (props: Props) => { if (props.onRefresh) { return ( diff --git a/Libraries/Lists/SectionList.js b/Libraries/Lists/SectionList.js index 0643994d2b9e8e..757714678764ef 100644 --- a/Libraries/Lists/SectionList.js +++ b/Libraries/Lists/SectionList.js @@ -156,6 +156,8 @@ type OptionalProps> = { * enabled by default on iOS because that is the platform standard there. */ stickySectionHeadersEnabled?: boolean, + + legacyImplementation?: ?boolean, }; type Props = RequiredProps diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 2a909e1c8fe419..16a8b5f9dd60eb 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -134,6 +134,8 @@ type OptionalProps = { */ windowSize: number, }; +/* $FlowFixMe - this Props seems to be missing a bunch of stuff. Remove this + * comment to see the errors */ export type Props = RequiredProps & OptionalProps; let _usedIndexForKey = false; diff --git a/local-cli/templates/HelloWorld/_flowconfig b/local-cli/templates/HelloWorld/_flowconfig index fdac4d6d72d842..7c4a432ca204df 100644 --- a/local-cli/templates/HelloWorld/_flowconfig +++ b/local-cli/templates/HelloWorld/_flowconfig @@ -36,12 +36,12 @@ suppress_type=$FlowIssue suppress_type=$FlowFixMe suppress_type=$FixMe -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-3]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-3]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-4]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-4]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError unsafe.enable_getters_and_setters=true [version] -^0.43.1 +^0.44.0 diff --git a/package.json b/package.json index 30a5fb0519a6ba..d57918e8d4c459 100644 --- a/package.json +++ b/package.json @@ -221,7 +221,7 @@ "eslint-plugin-flowtype": "^2.20.0", "eslint-plugin-react": "^6.4.1", "eslint-config-fbjs": "^1.1.1", - "flow-bin": "^0.43.1", + "flow-bin": "^0.44.0", "jest": "19.0.2", "jest-repl": "19.0.2", "jest-runtime": "19.0.2", From 3abadb3e11ce6e533bcc59e63f972ae4b2713596 Mon Sep 17 00:00:00 2001 From: Aaron Chiu Date: Mon, 17 Apr 2017 13:23:56 -0700 Subject: [PATCH 29/69] make mReactChoreographer final in Timing.java Reviewed By: achen1 Differential Revision: D4883119 fbshipit-source-id: 1adb57f333742fca9c5e1ece6355ee18881c48a4 --- .../facebook/react/modules/core/Timing.java | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java index 0e504d5d8c6ba9..275f3798cc6070 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java @@ -23,7 +23,6 @@ import android.util.SparseArray; -import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ExecutorToken; import com.facebook.react.bridge.LifecycleEventListener; @@ -125,8 +124,7 @@ public void doFrame(long frameTimeNanos) { } mTimersToCall.clear(); - Assertions.assertNotNull(mReactChoreographer) - .postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, this); + mReactChoreographer.postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, this); } } @@ -146,9 +144,7 @@ public void doFrame(long frameTimeNanos) { mCurrentIdleCallbackRunnable = new IdleCallbackRunnable(frameTimeNanos); getReactApplicationContext().runOnJSQueueThread(mCurrentIdleCallbackRunnable); - Assertions.assertNotNull(mReactChoreographer).postFrameCallback( - ReactChoreographer.CallbackType.IDLE_EVENT, - this); + mReactChoreographer.postFrameCallback(ReactChoreographer.CallbackType.IDLE_EVENT, this); } } @@ -202,8 +198,8 @@ public void cancel() { private final AtomicBoolean isRunningTasks = new AtomicBoolean(false); private final TimerFrameCallback mTimerFrameCallback = new TimerFrameCallback(); private final IdleFrameCallback mIdleFrameCallback = new IdleFrameCallback(); + private final ReactChoreographer mReactChoreographer; private @Nullable IdleCallbackRunnable mCurrentIdleCallbackRunnable; - private @Nullable ReactChoreographer mReactChoreographer; private boolean mFrameCallbackPosted = false; private boolean mFrameIdleCallbackPosted = false; private final Set mSendIdleEventsExecutorTokens; @@ -232,6 +228,7 @@ public int compare(Timer lhs, Timer rhs) { mTimerIdsToTimers = new HashMap<>(); mSendIdleEventsExecutorTokens = new HashSet<>(); mIdleCallbackContextsToCall = new ArrayList<>(); + mReactChoreographer = ReactChoreographer.getInstance(); } @Override @@ -257,11 +254,6 @@ public void onHostDestroy() { @Override public void onHostResume() { - if (mReactChoreographer == null) { - // Safe to acquire choreographer here, as onHostResume() is invoked from UI thread. - mReactChoreographer = ReactChoreographer.getInstance(); - } - isPaused.set(false); // TODO(5195192) Investigate possible problems related to restarting all tasks at the same // moment @@ -271,11 +263,6 @@ public void onHostResume() { @Override public void onHeadlessJsTaskStart(int taskId) { - if (mReactChoreographer == null) { - // Safe to acquire choreographer here, as onHeadlessJsTaskStart() is invoked from UI thread. - mReactChoreographer = ReactChoreographer.getInstance(); - } - if (!isRunningTasks.getAndSet(true)) { setChoreographerCallback(); maybeSetChoreographerIdleCallback(); @@ -318,7 +305,7 @@ private void maybeIdleCallback() { private void setChoreographerCallback() { if (!mFrameCallbackPosted) { - Assertions.assertNotNull(mReactChoreographer).postFrameCallback( + mReactChoreographer.postFrameCallback( ReactChoreographer.CallbackType.TIMERS_EVENTS, mTimerFrameCallback); mFrameCallbackPosted = true; @@ -330,7 +317,7 @@ private void clearFrameCallback() { HeadlessJsTaskContext.getInstance(getReactApplicationContext()); if (mFrameCallbackPosted && isPaused.get() && !headlessJsTaskContext.hasActiveTasks()) { - Assertions.assertNotNull(mReactChoreographer).removeFrameCallback( + mReactChoreographer.removeFrameCallback( ReactChoreographer.CallbackType.TIMERS_EVENTS, mTimerFrameCallback); mFrameCallbackPosted = false; @@ -339,7 +326,7 @@ private void clearFrameCallback() { private void setChoreographerIdleCallback() { if (!mFrameIdleCallbackPosted) { - Assertions.assertNotNull(mReactChoreographer).postFrameCallback( + mReactChoreographer.postFrameCallback( ReactChoreographer.CallbackType.IDLE_EVENT, mIdleFrameCallback); mFrameIdleCallbackPosted = true; @@ -348,7 +335,7 @@ private void setChoreographerIdleCallback() { private void clearChoreographerIdleCallback() { if (mFrameIdleCallbackPosted) { - Assertions.assertNotNull(mReactChoreographer).removeFrameCallback( + mReactChoreographer.removeFrameCallback( ReactChoreographer.CallbackType.IDLE_EVENT, mIdleFrameCallback); mFrameIdleCallbackPosted = false; From 9747ad29366ba1d69ed34972197b658ba1496366 Mon Sep 17 00:00:00 2001 From: "Andrew Y. Chen" Date: Mon, 17 Apr 2017 14:45:38 -0700 Subject: [PATCH 30/69] Instrumentation tests for apps that provide a testPayload Reviewed By: AaaChiuuu Differential Revision: D4873849 fbshipit-source-id: b5235b952faea2e42fb4292fac4ca409e22ecb56 --- .../main/java/com/facebook/react/bridge/ReactMarker.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarker.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarker.java index 5dc1dc9fd3b090..c2df8f0d6af90d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarker.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarker.java @@ -5,6 +5,7 @@ import javax.annotation.Nullable; import com.facebook.proguard.annotations.DoNotStrip; + /** * Static class that allows markers to be placed in React code and responded to in a * configurable way @@ -25,6 +26,11 @@ public static void setMarkerListener(MarkerListener listener) { sMarkerListener = listener; } + @DoNotStrip + public static void clearMarkerListener() { + sMarkerListener = null; + } + @DoNotStrip public static void logMarker(String name) { logMarker(name, null); From e99b3899a2cc321b860aa00b2d2684859bcb480b Mon Sep 17 00:00:00 2001 From: Aaron Chiu Date: Mon, 17 Apr 2017 15:36:36 -0700 Subject: [PATCH 31/69] update the infer-annotation jar for open source to unblock D4883219 Reviewed By: achen1 Differential Revision: D4890251 fbshipit-source-id: 3945c0e85fba15d588aa3b5760c64c5d81c6c516 --- .../third-party/java/infer-annotations/BUCK | 6 +++--- .../infer-annotations/infer-annotations-1.5.jar | Bin 11990 -> 0 bytes .../infer-annotations/infer-annotations-4.0.jar | Bin 0 -> 14300 bytes 3 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 ReactAndroid/src/main/third-party/java/infer-annotations/infer-annotations-1.5.jar create mode 100644 ReactAndroid/src/main/third-party/java/infer-annotations/infer-annotations-4.0.jar diff --git a/ReactAndroid/src/main/third-party/java/infer-annotations/BUCK b/ReactAndroid/src/main/third-party/java/infer-annotations/BUCK index a48316a4ea79e0..0164406c0e985f 100644 --- a/ReactAndroid/src/main/third-party/java/infer-annotations/BUCK +++ b/ReactAndroid/src/main/third-party/java/infer-annotations/BUCK @@ -1,5 +1,5 @@ prebuilt_jar( - name = "infer-annotations", - binary_jar = "infer-annotations-1.5.jar", - visibility = ["//ReactAndroid/..."], + name = "infer-annotations", + binary_jar = "infer-annotations-4.0.jar", + visibility = ["//ReactAndroid/..."], ) diff --git a/ReactAndroid/src/main/third-party/java/infer-annotations/infer-annotations-1.5.jar b/ReactAndroid/src/main/third-party/java/infer-annotations/infer-annotations-1.5.jar deleted file mode 100644 index eaab472f3782efae4c4fcdc02c7aad033cf36f0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11990 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

MTGfXx-r*jlFez~maRtD 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 diff --git a/ReactAndroid/src/main/third-party/java/infer-annotations/infer-annotations-4.0.jar b/ReactAndroid/src/main/third-party/java/infer-annotations/infer-annotations-4.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..418995d9a5df9fbed5c156542b18e3132d7a138e GIT binary patch literal 14300 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 literal 0 HcmV?d00001 From 620b625510f47ec03c297ef09a0774313bdc0ab1 Mon Sep 17 00:00:00 2001 From: Tony Tan Date: Mon, 17 Apr 2017 18:10:39 -0700 Subject: [PATCH 32/69] Fix bug - FlatList component did not render more items when content was filtered Summary: **Bug Description** The FlatList component receives content items via the data prop, and renders an initial number of items on the app's view. When a user scrolls to the end of the list, the component will append and render more available items at the end of the list. There was a bug where when the content was filtered, there were more available items but the component did not append/render them. This is due to the current appending/rendering logic in VirtualizedList, which does not account for data changes as a condition for updating/rendering. VirtualizedList is a dependency of FlatList, so this issue affects FlatList as well. **Approach to Fixing Bug** (i) Reproduce bug on iOS view of FlatList. (ii) For VirtualizedList component: # Isolate onEndReached function that appends more data to component UI. # Isolate _onContentSizeChange function that is called when list content changes. # Write snapshot tests using jest, based off existing test for FlatList. # Refactor logic to append more data to list into _maybeCallOnEndReached function. # Call _maybeCallOnEndReached in both _onContentSizeChange and _onScroll. (iii) Run snapshot tests and observe jest output. (iv) Bring up iOS view of FlatList and check that component now renders more items when content is filtered. Many thanks to sahrens for guidance in developing this code! Reviewed By: sahrens Differential Revision: D4877388 fbshipit-source-id: c10c9eef1912f491450a62b81a9bc41f7f784203 --- Libraries/Lists/VirtualizedList.js | 34 ++- .../Lists/__tests__/VirtualizedList-test.js | 80 ++++++ .../VirtualizedList-test.js.snap | 261 ++++++++++++++++++ 3 files changed, 362 insertions(+), 13 deletions(-) create mode 100644 Libraries/Lists/__tests__/VirtualizedList-test.js create mode 100644 Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 16a8b5f9dd60eb..111d9e2bb98748 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -623,12 +623,29 @@ class VirtualizedList extends React.PureComponent { return !this.props.horizontal ? metrics.y : metrics.x; } + _maybeCallOnEndReached() { + const {data, getItemCount, onEndReached, onEndReachedThreshold} = this.props; + const {contentLength, visibleLength, offset} = this._scrollMetrics; + const distanceFromEnd = contentLength - visibleLength - offset; + if (onEndReached && + this.state.last === getItemCount(data) - 1 && + distanceFromEnd < onEndReachedThreshold * visibleLength && + (this._hasDataChangedSinceEndReached || + this._scrollMetrics.contentLength !== this._sentEndForContentLength)) { + // Only call onEndReached once for a given dataset + content length. + this._hasDataChangedSinceEndReached = false; + this._sentEndForContentLength = this._scrollMetrics.contentLength; + onEndReached({distanceFromEnd}); + } + } + _onContentSizeChange = (width: number, height: number) => { if (this.props.onContentSizeChange) { this.props.onContentSizeChange(width, height); } this._scrollMetrics.contentLength = this._selectLength({height, width}); this._updateCellsToRenderBatcher.schedule(); + this._maybeCallOnEndReached(); }; _sampleFillRate(sampleType: string) { @@ -662,7 +679,7 @@ class VirtualizedList extends React.PureComponent { const dOffset = offset - this._scrollMetrics.offset; const velocity = dOffset / dt; this._scrollMetrics = {contentLength, dt, offset, timestamp, velocity, visibleLength}; - const {data, getItemCount, onEndReached, onEndReachedThreshold, windowSize} = this.props; + const {data, getItemCount, windowSize} = this.props; this._sampleFillRate('onScroll'); @@ -670,19 +687,10 @@ class VirtualizedList extends React.PureComponent { if (!data) { return; } - const distanceFromEnd = contentLength - visibleLength - offset; - const itemCount = getItemCount(data); - if (onEndReached && - this.state.last === itemCount - 1 && - distanceFromEnd < onEndReachedThreshold * visibleLength && - (this._hasDataChangedSinceEndReached || - this._scrollMetrics.contentLength !== this._sentEndForContentLength)) { - // Only call onEndReached once for a given dataset + content length. - this._hasDataChangedSinceEndReached = false; - this._sentEndForContentLength = this._scrollMetrics.contentLength; - onEndReached({distanceFromEnd}); - } + this._maybeCallOnEndReached(); + const {first, last} = this.state; + const itemCount = getItemCount(data); if ((first > 0 && velocity < 0) || (last < itemCount - 1 && velocity > 0)) { const distanceToContentEdge = Math.min( Math.abs(this._getFrameMetricsApprox(first).offset - offset), diff --git a/Libraries/Lists/__tests__/VirtualizedList-test.js b/Libraries/Lists/__tests__/VirtualizedList-test.js new file mode 100644 index 00000000000000..50ee662d32a7bf --- /dev/null +++ b/Libraries/Lists/__tests__/VirtualizedList-test.js @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ +'use strict'; + +jest.disableAutomock(); + +const React = require('React'); +const ReactTestRenderer = require('react-test-renderer'); + +const VirtualizedList = require('VirtualizedList'); + +describe('VirtualizedList', () => { + + it('renders simple list', () => { + const component = ReactTestRenderer.create( + } + /> + ); + expect(component).toMatchSnapshot(); + }); + + it('renders empty list', () => { + const component = ReactTestRenderer.create( + } + /> + ); + expect(component).toMatchSnapshot(); + }); + + it('renders null list', () => { + const component = ReactTestRenderer.create( + } + /> + ); + expect(component).toMatchSnapshot(); + }); + + it('renders all the bells and whistles', () => { + const component = ReactTestRenderer.create( + } + ListFooterComponent={() =>