mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-29 12:45:37 +08:00
Updates from Wed 3 Jun
This commit is contained in:
@@ -17,6 +17,6 @@
|
|||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
||||||
XCTAssertTrue(foundElement, @"Cound't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,16 @@ var propTypes = {
|
|||||||
* imagesPerRow: Number of images to be shown in each row.
|
* imagesPerRow: Number of images to be shown in each row.
|
||||||
*/
|
*/
|
||||||
imagesPerRow: React.PropTypes.number,
|
imagesPerRow: React.PropTypes.number,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The asset type, one of 'Photos', 'Videos' or 'All'
|
||||||
|
*/
|
||||||
|
assetType: React.PropTypes.oneOf([
|
||||||
|
'Photos',
|
||||||
|
'Videos',
|
||||||
|
'All',
|
||||||
|
]),
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var CameraRollView = React.createClass({
|
var CameraRollView = React.createClass({
|
||||||
@@ -69,6 +79,7 @@ var CameraRollView = React.createClass({
|
|||||||
groupTypes: 'SavedPhotos',
|
groupTypes: 'SavedPhotos',
|
||||||
batchSize: 5,
|
batchSize: 5,
|
||||||
imagesPerRow: 1,
|
imagesPerRow: 1,
|
||||||
|
assetType: 'Photos',
|
||||||
renderImage: function(asset) {
|
renderImage: function(asset) {
|
||||||
var imageSize = 150;
|
var imageSize = 150;
|
||||||
var imageStyle = [styles.image, {width: imageSize, height: imageSize}];
|
var imageStyle = [styles.image, {width: imageSize, height: imageSize}];
|
||||||
@@ -89,6 +100,7 @@ var CameraRollView = React.createClass({
|
|||||||
assets: ([]: Array<Image>),
|
assets: ([]: Array<Image>),
|
||||||
groupTypes: this.props.groupTypes,
|
groupTypes: this.props.groupTypes,
|
||||||
lastCursor: (null : ?string),
|
lastCursor: (null : ?string),
|
||||||
|
assetType: this.props.assetType,
|
||||||
noMore: false,
|
noMore: false,
|
||||||
loadingMore: false,
|
loadingMore: false,
|
||||||
dataSource: ds,
|
dataSource: ds,
|
||||||
@@ -124,7 +136,8 @@ var CameraRollView = React.createClass({
|
|||||||
|
|
||||||
var fetchParams: Object = {
|
var fetchParams: Object = {
|
||||||
first: this.props.batchSize,
|
first: this.props.batchSize,
|
||||||
groupTypes: this.props.groupTypes
|
groupTypes: this.props.groupTypes,
|
||||||
|
assetType: this.props.assetType,
|
||||||
};
|
};
|
||||||
if (this.state.lastCursor) {
|
if (this.state.lastCursor) {
|
||||||
fetchParams.after = this.state.lastCursor;
|
fetchParams.after = this.state.lastCursor;
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ var ReachabilitySubscription = React.createClass({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
NetInfo.reachabilityIOS.addEventListener(
|
NetInfo.addEventListener(
|
||||||
'change',
|
'change',
|
||||||
this._handleReachabilityChange
|
this._handleReachabilityChange
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
NetInfo.reachabilityIOS.removeEventListener(
|
NetInfo.removeEventListener(
|
||||||
'change',
|
'change',
|
||||||
this._handleReachabilityChange
|
this._handleReachabilityChange
|
||||||
);
|
);
|
||||||
@@ -63,16 +63,16 @@ var ReachabilityCurrent = React.createClass({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
NetInfo.reachabilityIOS.addEventListener(
|
NetInfo.addEventListener(
|
||||||
'change',
|
'change',
|
||||||
this._handleReachabilityChange
|
this._handleReachabilityChange
|
||||||
);
|
);
|
||||||
NetInfo.reachabilityIOS.fetch().done(
|
NetInfo.fetch().done(
|
||||||
(reachability) => { this.setState({reachability}); }
|
(reachability) => { this.setState({reachability}); }
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
NetInfo.reachabilityIOS.removeEventListener(
|
NetInfo.removeEventListener(
|
||||||
'change',
|
'change',
|
||||||
this._handleReachabilityChange
|
this._handleReachabilityChange
|
||||||
);
|
);
|
||||||
|
|||||||
159
Examples/UIExplorer/TransformExample.js
Normal file
159
Examples/UIExplorer/TransformExample.js
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* @providesModule TransformExample
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('React');
|
||||||
|
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
var TimerMixin = require('react-timer-mixin');
|
||||||
|
var UIExplorerBlock = require('UIExplorerBlock');
|
||||||
|
var UIExplorerPage = require('UIExplorerPage');
|
||||||
|
var View = require('View');
|
||||||
|
|
||||||
|
var TransformExample = React.createClass({
|
||||||
|
|
||||||
|
mixins: [TimerMixin],
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return {
|
||||||
|
interval: this.setInterval(this._update, 800),
|
||||||
|
pulse: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<UIExplorerPage title="Transforms">
|
||||||
|
<UIExplorerBlock title="foo bar">
|
||||||
|
<View style={{height: 500}}>
|
||||||
|
<View style={styles.box1} />
|
||||||
|
<View style={styles.box2} />
|
||||||
|
<View style={styles.box3step1} />
|
||||||
|
<View style={styles.box3step2} />
|
||||||
|
<View style={styles.box3step3} />
|
||||||
|
<View style={styles.box4} />
|
||||||
|
<View style={[
|
||||||
|
styles.box5,
|
||||||
|
this.state.pulse ? styles.box5Transform : null
|
||||||
|
]} />
|
||||||
|
</View>
|
||||||
|
</UIExplorerBlock>
|
||||||
|
</UIExplorerPage>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_update() {
|
||||||
|
this.setState({
|
||||||
|
pulse: !this.state.pulse,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
box1: {
|
||||||
|
left: 0,
|
||||||
|
backgroundColor: 'green',
|
||||||
|
height: 50,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
transform: [
|
||||||
|
{translateX: 100},
|
||||||
|
{translateY: 50},
|
||||||
|
{rotate: '30deg'},
|
||||||
|
{scaleX: 2},
|
||||||
|
{scaleY: 2},
|
||||||
|
],
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
box2: {
|
||||||
|
left: 0,
|
||||||
|
backgroundColor: 'purple',
|
||||||
|
height: 50,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
transform: [
|
||||||
|
{scaleX: 2},
|
||||||
|
{scaleY: 2},
|
||||||
|
{translateX: 100},
|
||||||
|
{translateY: 50},
|
||||||
|
{rotate: '30deg'},
|
||||||
|
],
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
box3step1: {
|
||||||
|
left: 0,
|
||||||
|
backgroundColor: '#ffb6c1', // lightpink
|
||||||
|
height: 50,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
transform: [
|
||||||
|
{rotate: '30deg'},
|
||||||
|
],
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
box3step2: {
|
||||||
|
left: 0,
|
||||||
|
backgroundColor: '#ff69b4', //hotpink
|
||||||
|
height: 50,
|
||||||
|
opacity: 0.5,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
transform: [
|
||||||
|
{rotate: '30deg'},
|
||||||
|
{scaleX: 2},
|
||||||
|
{scaleY: 2},
|
||||||
|
],
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
box3step3: {
|
||||||
|
left: 0,
|
||||||
|
backgroundColor: '#ff1493', // deeppink
|
||||||
|
height: 50,
|
||||||
|
opacity: 0.5,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
transform: [
|
||||||
|
{rotate: '30deg'},
|
||||||
|
{scaleX: 2},
|
||||||
|
{scaleY: 2},
|
||||||
|
{translateX: 100},
|
||||||
|
{translateY: 50},
|
||||||
|
],
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
box4: {
|
||||||
|
left: 0,
|
||||||
|
backgroundColor: '#ff8c00', // darkorange
|
||||||
|
height: 50,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
transform: [
|
||||||
|
{translate: [200, 350]},
|
||||||
|
{scale: 2.5},
|
||||||
|
{rotate: '-0.2rad'},
|
||||||
|
],
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
box5: {
|
||||||
|
backgroundColor: '#800000', // maroon
|
||||||
|
height: 50,
|
||||||
|
position: 'absolute',
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
box5Transform: {
|
||||||
|
transform: [
|
||||||
|
{translate: [-50, 35]},
|
||||||
|
{rotate: '50deg'},
|
||||||
|
{scale: 2},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = TransformExample;
|
||||||
@@ -30,7 +30,7 @@ var {
|
|||||||
var { TestModule } = React.addons;
|
var { TestModule } = React.addons;
|
||||||
var Settings = require('Settings');
|
var Settings = require('Settings');
|
||||||
|
|
||||||
import type { Example, ExampleModule } from 'ExampleTypes';
|
import type { ExampleModule } from 'ExampleTypes';
|
||||||
|
|
||||||
var createExamplePage = require('./createExamplePage');
|
var createExamplePage = require('./createExamplePage');
|
||||||
|
|
||||||
@@ -154,7 +154,9 @@ class UIExplorerList extends React.Component {
|
|||||||
dataSource={this.state.dataSource}
|
dataSource={this.state.dataSource}
|
||||||
renderRow={this._renderRow.bind(this)}
|
renderRow={this._renderRow.bind(this)}
|
||||||
renderSectionHeader={this._renderSectionHeader}
|
renderSectionHeader={this._renderSectionHeader}
|
||||||
|
keyboardShouldPersistTaps={true}
|
||||||
automaticallyAdjustContentInsets={false}
|
automaticallyAdjustContentInsets={false}
|
||||||
|
keyboardDismissMode="onDrag"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -62,6 +62,9 @@
|
|||||||
// Make sure this test runs first because the other tests will tear out the rootView
|
// Make sure this test runs first because the other tests will tear out the rootView
|
||||||
- (void)testAAA_RootViewLoadsAndRenders
|
- (void)testAAA_RootViewLoadsAndRenders
|
||||||
{
|
{
|
||||||
|
// TODO (t7296305) Fix and Re-Enable this UIExplorer Test
|
||||||
|
return;
|
||||||
|
|
||||||
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
|
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
|
||||||
RCTAssert([vc.view isKindOfClass:[RCTRootView class]], @"This test must run first.");
|
RCTAssert([vc.view isKindOfClass:[RCTRootView class]], @"This test must run first.");
|
||||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
||||||
@@ -82,7 +85,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
||||||
XCTAssertTrue(foundElement, @"Cound't find element with '<View>' text in %d seconds", TIMEOUT_SECONDS);
|
XCTAssertTrue(foundElement, @"Couldn't find element with '<View>' text in %d seconds", TIMEOUT_SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RCT_SNAPSHOT_TEST(name, reRecord) \
|
#define RCT_SNAPSHOT_TEST(name, reRecord) \
|
||||||
|
|||||||
@@ -29,8 +29,16 @@ var GROUP_TYPES_OPTIONS = [
|
|||||||
'SavedPhotos', // default
|
'SavedPhotos', // default
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var ASSET_TYPE_OPTIONS = [
|
||||||
|
'All',
|
||||||
|
'Videos',
|
||||||
|
'Photos', // default
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
// Flow treats Object and Array as disjoint types, currently.
|
// Flow treats Object and Array as disjoint types, currently.
|
||||||
deepFreezeAndThrowOnMutationInDev((GROUP_TYPES_OPTIONS: any));
|
deepFreezeAndThrowOnMutationInDev((GROUP_TYPES_OPTIONS: any));
|
||||||
|
deepFreezeAndThrowOnMutationInDev((ASSET_TYPE_OPTIONS: any));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shape of the param arg for the `getPhotos` function.
|
* Shape of the param arg for the `getPhotos` function.
|
||||||
@@ -58,6 +66,11 @@ var getPhotosParamChecker = createStrictShapeTypeChecker({
|
|||||||
* titles.
|
* titles.
|
||||||
*/
|
*/
|
||||||
groupName: ReactPropTypes.string,
|
groupName: ReactPropTypes.string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies filter on asset type
|
||||||
|
*/
|
||||||
|
assetType: ReactPropTypes.oneOf(ASSET_TYPE_OPTIONS),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,6 +107,7 @@ var getPhotosReturnChecker = createStrictShapeTypeChecker({
|
|||||||
class CameraRoll {
|
class CameraRoll {
|
||||||
|
|
||||||
static GroupTypesOptions: Array<string>;
|
static GroupTypesOptions: Array<string>;
|
||||||
|
static AssetTypeOptions: Array<string>;
|
||||||
/**
|
/**
|
||||||
* Saves the image with tag `tag` to the camera roll.
|
* Saves the image with tag `tag` to the camera roll.
|
||||||
*
|
*
|
||||||
@@ -154,5 +168,6 @@ class CameraRoll {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CameraRoll.GroupTypesOptions = GROUP_TYPES_OPTIONS;
|
CameraRoll.GroupTypesOptions = GROUP_TYPES_OPTIONS;
|
||||||
|
CameraRoll.AssetTypeOptions = ASSET_TYPE_OPTIONS;
|
||||||
|
|
||||||
module.exports = CameraRoll;
|
module.exports = CameraRoll;
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ var DEFAULT_INITIAL_ROWS = 10;
|
|||||||
var DEFAULT_SCROLL_RENDER_AHEAD = 1000;
|
var DEFAULT_SCROLL_RENDER_AHEAD = 1000;
|
||||||
var DEFAULT_END_REACHED_THRESHOLD = 1000;
|
var DEFAULT_END_REACHED_THRESHOLD = 1000;
|
||||||
var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
|
var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
|
||||||
var RENDER_INTERVAL = 20;
|
|
||||||
var SCROLLVIEW_REF = 'listviewscroll';
|
var SCROLLVIEW_REF = 'listviewscroll';
|
||||||
|
|
||||||
|
|
||||||
@@ -258,7 +257,6 @@ var ListView = React.createClass({
|
|||||||
// the component is laid out
|
// the component is laid out
|
||||||
this.requestAnimationFrame(() => {
|
this.requestAnimationFrame(() => {
|
||||||
this._measureAndUpdateScrollProps();
|
this._measureAndUpdateScrollProps();
|
||||||
this.setInterval(this._renderMoreRowsIfNeeded, RENDER_INTERVAL);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -329,7 +327,7 @@ var ListView = React.createClass({
|
|||||||
totalIndex++;
|
totalIndex++;
|
||||||
|
|
||||||
if (this.props.renderSeparator &&
|
if (this.props.renderSeparator &&
|
||||||
(rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length -1)) {
|
(rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)) {
|
||||||
var adjacentRowHighlighted =
|
var adjacentRowHighlighted =
|
||||||
this.state.highlightedRow.sectionID === sectionID && (
|
this.state.highlightedRow.sectionID === sectionID && (
|
||||||
this.state.highlightedRow.rowID === rowID ||
|
this.state.highlightedRow.rowID === rowID ||
|
||||||
@@ -397,6 +395,7 @@ var ListView = React.createClass({
|
|||||||
_setScrollVisibleHeight: function(left, top, width, height) {
|
_setScrollVisibleHeight: function(left, top, width, height) {
|
||||||
this.scrollProperties.visibleHeight = height;
|
this.scrollProperties.visibleHeight = height;
|
||||||
this._updateVisibleRows();
|
this._updateVisibleRows();
|
||||||
|
this._renderMoreRowsIfNeeded();
|
||||||
},
|
},
|
||||||
|
|
||||||
_renderMoreRowsIfNeeded: function() {
|
_renderMoreRowsIfNeeded: function() {
|
||||||
@@ -443,8 +442,8 @@ var ListView = React.createClass({
|
|||||||
}
|
}
|
||||||
var updatedFrames = e && e.nativeEvent.updatedChildFrames;
|
var updatedFrames = e && e.nativeEvent.updatedChildFrames;
|
||||||
if (updatedFrames) {
|
if (updatedFrames) {
|
||||||
updatedFrames.forEach((frame) => {
|
updatedFrames.forEach((newFrame) => {
|
||||||
this._childFrames[frame.index] = merge(frame);
|
this._childFrames[newFrame.index] = merge(newFrame);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var dataSource = this.props.dataSource;
|
var dataSource = this.props.dataSource;
|
||||||
|
|||||||
@@ -1290,7 +1290,7 @@ var Navigator = React.createClass({
|
|||||||
key={this.state.idStack[i]}
|
key={this.state.idStack[i]}
|
||||||
ref={'scene_' + i}
|
ref={'scene_' + i}
|
||||||
onStartShouldSetResponderCapture={() => {
|
onStartShouldSetResponderCapture={() => {
|
||||||
return i !== this.state.presentedIndex;
|
return !!this.state.transitionFromIndex || !!this.state.activeGesture;
|
||||||
}}
|
}}
|
||||||
style={[styles.baseScene, this.props.sceneStyle, disabledSceneStyle]}>
|
style={[styles.baseScene, this.props.sceneStyle, disabledSceneStyle]}>
|
||||||
{React.cloneElement(child, {
|
{React.cloneElement(child, {
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
|||||||
NSString *afterCursor = params[@"after"];
|
NSString *afterCursor = params[@"after"];
|
||||||
NSString *groupTypesStr = params[@"groupTypes"];
|
NSString *groupTypesStr = params[@"groupTypes"];
|
||||||
NSString *groupName = params[@"groupName"];
|
NSString *groupName = params[@"groupName"];
|
||||||
|
NSString *assetType = params[@"assetType"];
|
||||||
ALAssetsGroupType groupTypes;
|
ALAssetsGroupType groupTypes;
|
||||||
|
|
||||||
if ([groupTypesStr isEqualToString:@"Album"]) {
|
if ([groupTypesStr isEqualToString:@"Album"]) {
|
||||||
groupTypes = ALAssetsGroupAlbum;
|
groupTypes = ALAssetsGroupAlbum;
|
||||||
} else if ([groupTypesStr isEqualToString:@"All"]) {
|
} else if ([groupTypesStr isEqualToString:@"All"]) {
|
||||||
@@ -93,7 +95,15 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
|||||||
|
|
||||||
[[RCTImageLoader assetsLibrary] enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) {
|
[[RCTImageLoader assetsLibrary] enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) {
|
||||||
if (group && (groupName == nil || [groupName isEqualToString:[group valueForProperty:ALAssetsGroupPropertyName]])) {
|
if (group && (groupName == nil || [groupName isEqualToString:[group valueForProperty:ALAssetsGroupPropertyName]])) {
|
||||||
[group setAssetsFilter:ALAssetsFilter.allPhotos];
|
|
||||||
|
if (assetType == nil || [assetType isEqualToString:@"Photos"]) {
|
||||||
|
[group setAssetsFilter:ALAssetsFilter.allPhotos];
|
||||||
|
} else if ([assetType isEqualToString:@"Videos"]) {
|
||||||
|
[group setAssetsFilter:ALAssetsFilter.allVideos];
|
||||||
|
} else if ([assetType isEqualToString:@"All"]) {
|
||||||
|
[group setAssetsFilter:ALAssetsFilter.allAssets];
|
||||||
|
}
|
||||||
|
|
||||||
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopAssets) {
|
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopAssets) {
|
||||||
if (result) {
|
if (result) {
|
||||||
NSString *uri = [(NSURL *)[result valueForProperty:ALAssetPropertyAssetURL] absoluteString];
|
NSString *uri = [(NSURL *)[result valueForProperty:ALAssetPropertyAssetURL] absoluteString];
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ describe('resolveAssetSource', () => {
|
|||||||
isStatic: true,
|
isStatic: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 200,
|
height: 200,
|
||||||
uri: 'assets_awesomemodule_subdir_logo1_',
|
uri: 'awesomemodule_subdir_logo1_',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ function getPathInArchive(asset) {
|
|||||||
return (assetDir + '/' + asset.name)
|
return (assetDir + '/' + asset.name)
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/\//g, '_') // Encode folder structure in file name
|
.replace(/\//g, '_') // Encode folder structure in file name
|
||||||
.replace(/([^a-z0-9_])/g, ''); // Remove illegal chars
|
.replace(/([^a-z0-9_])/g, '') // Remove illegal chars
|
||||||
|
.replace(/^assets_/, ''); // Remove "assets_" prefix
|
||||||
} else {
|
} else {
|
||||||
// E.g. 'assets/AwesomeModule/icon@2x.png'
|
// E.g. 'assets/AwesomeModule/icon@2x.png'
|
||||||
return getScaledAssetPath(asset);
|
return getScaledAssetPath(asset);
|
||||||
|
|||||||
@@ -30,17 +30,10 @@ function reportException(e: Exception, isFatal: bool, stack?: any) {
|
|||||||
if (!stack) {
|
if (!stack) {
|
||||||
stack = parseErrorStack(e);
|
stack = parseErrorStack(e);
|
||||||
}
|
}
|
||||||
if (!RCTExceptionsManager.reportFatalException ||
|
if (isFatal) {
|
||||||
!RCTExceptionsManager.reportSoftException) {
|
RCTExceptionsManager.reportFatalException(e.message, stack);
|
||||||
// Backwards compatibility - no differentiation
|
|
||||||
// TODO(#7049989): deprecate reportUnhandledException on Android
|
|
||||||
RCTExceptionsManager.reportUnhandledException(e.message, stack);
|
|
||||||
} else {
|
} else {
|
||||||
if (isFatal) {
|
RCTExceptionsManager.reportSoftException(e.message, stack);
|
||||||
RCTExceptionsManager.reportFatalException(e.message, stack);
|
|
||||||
} else {
|
|
||||||
RCTExceptionsManager.reportSoftException(e.message, stack);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
(sourceMapPromise = sourceMapPromise || loadSourceMap())
|
(sourceMapPromise = sourceMapPromise || loadSourceMap())
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ if (typeof window === 'undefined') {
|
|||||||
window = GLOBAL;
|
window = GLOBAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleErrorWithRedBox(e, isFatal) {
|
function handleError(e, isFatal) {
|
||||||
try {
|
try {
|
||||||
require('ExceptionsManager').handleException(e, isFatal);
|
require('ExceptionsManager').handleException(e, isFatal);
|
||||||
} catch(ee) {
|
} catch(ee) {
|
||||||
@@ -43,7 +43,7 @@ function handleErrorWithRedBox(e, isFatal) {
|
|||||||
|
|
||||||
function setUpRedBoxErrorHandler() {
|
function setUpRedBoxErrorHandler() {
|
||||||
var ErrorUtils = require('ErrorUtils');
|
var ErrorUtils = require('ErrorUtils');
|
||||||
ErrorUtils.setGlobalHandler(handleErrorWithRedBox);
|
ErrorUtils.setGlobalHandler(handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUpRedBoxConsoleErrorHandler() {
|
function setUpRedBoxConsoleErrorHandler() {
|
||||||
|
|||||||
@@ -12,8 +12,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var NativeModules = require('NativeModules');
|
var NativeModules = require('NativeModules');
|
||||||
|
var Platform = require('Platform');
|
||||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||||
var RCTReachability = NativeModules.Reachability;
|
|
||||||
|
if (Platform.OS === 'ios') {
|
||||||
|
var RCTNetInfo = NativeModules.Reachability;
|
||||||
|
} else if (Platform.OS === 'android') {
|
||||||
|
var RCTNetInfo = NativeModules.NetInfo;
|
||||||
|
}
|
||||||
|
|
||||||
var DEVICE_REACHABILITY_EVENT = 'reachabilityDidChange';
|
var DEVICE_REACHABILITY_EVENT = 'reachabilityDidChange';
|
||||||
|
|
||||||
@@ -28,11 +34,50 @@ type ReachabilityStateIOS = $Enum<{
|
|||||||
wifi: string;
|
wifi: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
type ConnectivityStateAndroid = $Enum<{
|
||||||
|
NONE: string;
|
||||||
|
MOBILE: string;
|
||||||
|
WIFI: string;
|
||||||
|
MOBILE_MMS: string;
|
||||||
|
MOBILE_SUPL: string;
|
||||||
|
MOBILE_DUN: string;
|
||||||
|
MOBILE_HIPRI: string;
|
||||||
|
WIMAX: string;
|
||||||
|
BLUETOOTH: string;
|
||||||
|
DUMMY: string;
|
||||||
|
ETHERNET: string;
|
||||||
|
MOBILE_FOTA: string;
|
||||||
|
MOBILE_IMS: string;
|
||||||
|
MOBILE_CBS: string;
|
||||||
|
WIFI_P2P: string;
|
||||||
|
MOBILE_IA: string;
|
||||||
|
MOBILE_EMERGENCY: string;
|
||||||
|
PROXY: string;
|
||||||
|
VPN: string;
|
||||||
|
UNKNOWN: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetInfo exposes info about online/offline status
|
* NetInfo exposes info about online/offline status
|
||||||
*
|
*
|
||||||
* ### reachabilityIOS
|
* ```
|
||||||
|
* NetInfo.fetch().done((reach) => {
|
||||||
|
* console.log('Initial: ' + reach);
|
||||||
|
* });
|
||||||
|
* function handleFirstConnectivityChange(reach) {
|
||||||
|
* console.log('First change: ' + reach);
|
||||||
|
* NetInfo.removeEventListener(
|
||||||
|
* 'change',
|
||||||
|
* handleFirstConnectivityChange
|
||||||
|
* );
|
||||||
|
* }
|
||||||
|
* NetInfo.addEventListener(
|
||||||
|
* 'change',
|
||||||
|
* handleFirstConnectivityChange
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ### IOS
|
||||||
*
|
*
|
||||||
* Asynchronously determine if the device is online and on a cellular network.
|
* Asynchronously determine if the device is online and on a cellular network.
|
||||||
*
|
*
|
||||||
@@ -41,21 +86,35 @@ type ReachabilityStateIOS = $Enum<{
|
|||||||
* - `cell` - device is connected via Edge, 3G, WiMax, or LTE
|
* - `cell` - device is connected via Edge, 3G, WiMax, or LTE
|
||||||
* - `unknown` - error case and the network status is unknown
|
* - `unknown` - error case and the network status is unknown
|
||||||
*
|
*
|
||||||
* ```
|
* ### Android
|
||||||
* NetInfo.reachabilityIOS.fetch().done((reach) => {
|
*
|
||||||
* console.log('Initial: ' + reach);
|
* Asynchronously determine if the device is connected and details about that connection.
|
||||||
|
*
|
||||||
|
* Android Connectivity Types
|
||||||
|
* - `NONE` - device is offline
|
||||||
|
* - `BLUETOOTH` - The Bluetooth data connection.
|
||||||
|
* - `DUMMY` - Dummy data connection.
|
||||||
|
* - `ETHERNET` - The Ethernet data connection.
|
||||||
|
* - `MOBILE` - The Mobile data connection.
|
||||||
|
* - `MOBILE_DUN` - A DUN-specific Mobile data connection.
|
||||||
|
* - `MOBILE_HIPRI` - A High Priority Mobile data connection.
|
||||||
|
* - `MOBILE_MMS` - An MMS-specific Mobile data connection.
|
||||||
|
* - `MOBILE_SUPL` - A SUPL-specific Mobile data connection.
|
||||||
|
* - `VPN` - A virtual network using one or more native bearers. Requires API Level 21
|
||||||
|
* - `WIFI` - The WIFI data connection.
|
||||||
|
* - `WIMAX` - The WiMAX data connection.
|
||||||
|
* - `UNKNOWN` - Unknown data connection.
|
||||||
|
* The rest ConnectivityStates are hidden by the Android API, but can be used if necessary.
|
||||||
|
*
|
||||||
|
* ### isConnectionMetered
|
||||||
|
*
|
||||||
|
* Available on Android. Detect if the current active connection is metered or not. A network is
|
||||||
|
* classified as metered when the user is sensitive to heavy data usage on that connection due to
|
||||||
|
* monetary costs, data limitations or battery/performance issues.
|
||||||
|
*
|
||||||
|
* NetInfo.isConnectionMetered((isConnectionMetered) => {
|
||||||
|
* console.log('Connection is ' + (isConnectionMetered ? 'Metered' : 'Not Metered'));
|
||||||
* });
|
* });
|
||||||
* function handleFirstReachabilityChange(reach) {
|
|
||||||
* console.log('First change: ' + reach);
|
|
||||||
* NetInfo.reachabilityIOS.removeEventListener(
|
|
||||||
* 'change',
|
|
||||||
* handleFirstReachabilityChange
|
|
||||||
* );
|
|
||||||
* }
|
|
||||||
* NetInfo.reachabilityIOS.addEventListener(
|
|
||||||
* 'change',
|
|
||||||
* handleFirstReachabilityChange
|
|
||||||
* );
|
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* ### isConnected
|
* ### isConnected
|
||||||
@@ -81,89 +140,101 @@ type ReachabilityStateIOS = $Enum<{
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var NetInfo = {};
|
var _subscriptions = {};
|
||||||
|
|
||||||
if (RCTReachability) {
|
var NetInfo = {
|
||||||
|
addEventListener: function (
|
||||||
// RCTReachability is exposed, so this is an iOS-like environment and we will
|
eventName: ChangeEventName,
|
||||||
// expose reachabilityIOS
|
handler: Function
|
||||||
|
): void {
|
||||||
var _reachabilitySubscriptions = {};
|
_subscriptions[handler] = RCTDeviceEventEmitter.addListener(
|
||||||
|
DEVICE_REACHABILITY_EVENT,
|
||||||
NetInfo.reachabilityIOS = {
|
(appStateData) => {
|
||||||
addEventListener: function (
|
handler(appStateData.network_reachability);
|
||||||
eventName: ChangeEventName,
|
|
||||||
handler: Function
|
|
||||||
): void {
|
|
||||||
_reachabilitySubscriptions[handler] = RCTDeviceEventEmitter.addListener(
|
|
||||||
DEVICE_REACHABILITY_EVENT,
|
|
||||||
(appStateData) => {
|
|
||||||
handler(appStateData.network_reachability);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
removeEventListener: function(
|
|
||||||
eventName: ChangeEventName,
|
|
||||||
handler: Function
|
|
||||||
): void {
|
|
||||||
if (!_reachabilitySubscriptions[handler]) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_reachabilitySubscriptions[handler].remove();
|
);
|
||||||
_reachabilitySubscriptions[handler] = null;
|
},
|
||||||
},
|
|
||||||
|
|
||||||
fetch: function(): Promise {
|
removeEventListener: function(
|
||||||
return new Promise((resolve, reject) => {
|
eventName: ChangeEventName,
|
||||||
RCTReachability.getCurrentReachability(
|
handler: Function
|
||||||
function(resp) {
|
): void {
|
||||||
resolve(resp.network_reachability);
|
if (!_subscriptions[handler]) {
|
||||||
},
|
return;
|
||||||
reject
|
}
|
||||||
);
|
_subscriptions[handler].remove();
|
||||||
});
|
_subscriptions[handler] = null;
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
var _isConnectedSubscriptions = {};
|
fetch: function(): Promise {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
RCTNetInfo.getCurrentReachability(
|
||||||
|
function(resp) {
|
||||||
|
resolve(resp.network_reachability);
|
||||||
|
},
|
||||||
|
reject
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
var _iosReachabilityIsConnected = function(
|
isConnected: {},
|
||||||
|
|
||||||
|
isConnectionMetered: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Platform.OS === 'ios') {
|
||||||
|
var _isConnected = function(
|
||||||
reachability: ReachabilityStateIOS
|
reachability: ReachabilityStateIOS
|
||||||
): bool {
|
): bool {
|
||||||
return reachability !== 'none' &&
|
return reachability !== 'none' &&
|
||||||
reachability !== 'unknown';
|
reachability !== 'unknown';
|
||||||
};
|
};
|
||||||
|
} else if (Platform.OS === 'android') {
|
||||||
|
var _isConnected = function(
|
||||||
|
connectionType: ConnectivityStateAndroid
|
||||||
|
): bool {
|
||||||
|
return connectionType !== 'NONE' && connectionType !== 'UNKNOWN';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
NetInfo.isConnected = {
|
var _isConnectedSubscriptions = {};
|
||||||
addEventListener: function (
|
|
||||||
eventName: ChangeEventName,
|
|
||||||
handler: Function
|
|
||||||
): void {
|
|
||||||
_isConnectedSubscriptions[handler] = (reachability) => {
|
|
||||||
handler(_iosReachabilityIsConnected(reachability));
|
|
||||||
};
|
|
||||||
NetInfo.reachabilityIOS.addEventListener(
|
|
||||||
eventName,
|
|
||||||
_isConnectedSubscriptions[handler]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
removeEventListener: function(
|
NetInfo.isConnected = {
|
||||||
eventName: ChangeEventName,
|
addEventListener: function (
|
||||||
handler: Function
|
eventName: ChangeEventName,
|
||||||
): void {
|
handler: Function
|
||||||
NetInfo.reachabilityIOS.removeEventListener(
|
): void {
|
||||||
eventName,
|
_isConnectedSubscriptions[handler] = (connection) => {
|
||||||
_isConnectedSubscriptions[handler]
|
handler(_isConnected(connection));
|
||||||
);
|
};
|
||||||
},
|
NetInfo.addEventListener(
|
||||||
|
eventName,
|
||||||
|
_isConnectedSubscriptions[handler]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
fetch: function(): Promise {
|
removeEventListener: function(
|
||||||
return NetInfo.reachabilityIOS.fetch().then(
|
eventName: ChangeEventName,
|
||||||
(reachability) => _iosReachabilityIsConnected(reachability)
|
handler: Function
|
||||||
);
|
): void {
|
||||||
},
|
NetInfo.removeEventListener(
|
||||||
|
eventName,
|
||||||
|
_isConnectedSubscriptions[handler]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
fetch: function(): Promise {
|
||||||
|
return NetInfo.fetch().then(
|
||||||
|
(connection) => _isConnected(connection)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
NetInfo.isConnectionMetered = function(callback): void {
|
||||||
|
RCTNetInfo.isConnectionMetered((_isMetered) => {
|
||||||
|
callback(_isMetered);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ RCT_EXPORT_MODULE()
|
|||||||
*/
|
*/
|
||||||
RCT_EXPORT_METHOD(queryData:(NSString *)queryType
|
RCT_EXPORT_METHOD(queryData:(NSString *)queryType
|
||||||
withQuery:(NSDictionary *)query
|
withQuery:(NSDictionary *)query
|
||||||
queryHash:(__unused NSString *)queryHash
|
|
||||||
responseSender:(RCTResponseSenderBlock)responseSender)
|
responseSender:(RCTResponseSenderBlock)responseSender)
|
||||||
{
|
{
|
||||||
if ([queryType isEqualToString:@"http"]) {
|
if ([queryType isEqualToString:@"http"]) {
|
||||||
@@ -39,34 +38,35 @@ RCT_EXPORT_METHOD(queryData:(NSString *)queryType
|
|||||||
// Build data task
|
// Build data task
|
||||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError) {
|
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError) {
|
||||||
|
|
||||||
|
NSHTTPURLResponse *httpResponse = nil;
|
||||||
|
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||||
|
// Might be a local file request
|
||||||
|
httpResponse = (NSHTTPURLResponse *)response;
|
||||||
|
}
|
||||||
|
|
||||||
// Build response
|
// Build response
|
||||||
NSDictionary *responseJSON;
|
NSArray *responseJSON;
|
||||||
if (connectionError == nil) {
|
if (connectionError == nil) {
|
||||||
NSStringEncoding encoding = NSUTF8StringEncoding;
|
NSStringEncoding encoding = NSUTF8StringEncoding;
|
||||||
if (response.textEncodingName) {
|
if (response.textEncodingName) {
|
||||||
CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
|
CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
|
||||||
encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
|
encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
|
||||||
}
|
}
|
||||||
NSHTTPURLResponse *httpResponse = nil;
|
responseJSON = @[
|
||||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
@(httpResponse.statusCode ?: 200),
|
||||||
// Might be a local file request
|
httpResponse.allHeaderFields ?: @{},
|
||||||
httpResponse = (NSHTTPURLResponse *)response;
|
[[NSString alloc] initWithData:data encoding:encoding] ?: @"",
|
||||||
}
|
];
|
||||||
responseJSON = @{
|
|
||||||
@"status": @([httpResponse statusCode] ?: 200),
|
|
||||||
@"responseHeaders": [httpResponse allHeaderFields] ?: @{},
|
|
||||||
@"responseText": [[NSString alloc] initWithData:data encoding:encoding] ?: @""
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
responseJSON = @{
|
responseJSON = @[
|
||||||
@"status": @0,
|
@(httpResponse.statusCode),
|
||||||
@"responseHeaders": @{},
|
httpResponse.allHeaderFields ?: @{},
|
||||||
@"responseText": [connectionError localizedDescription] ?: [NSNull null]
|
connectionError.localizedDescription ?: [NSNull null],
|
||||||
};
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send response (won't be sent on same thread as caller)
|
// Send response (won't be sent on same thread as caller)
|
||||||
responseSender(@[RCTJSONStringify(responseJSON, NULL)]);
|
responseSender(responseJSON);
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,6 @@
|
|||||||
|
|
||||||
var RCTDataManager = require('NativeModules').DataManager;
|
var RCTDataManager = require('NativeModules').DataManager;
|
||||||
|
|
||||||
var crc32 = require('crc32');
|
|
||||||
|
|
||||||
var XMLHttpRequestBase = require('XMLHttpRequestBase');
|
var XMLHttpRequestBase = require('XMLHttpRequestBase');
|
||||||
|
|
||||||
class XMLHttpRequest extends XMLHttpRequestBase {
|
class XMLHttpRequest extends XMLHttpRequestBase {
|
||||||
@@ -28,12 +26,7 @@ class XMLHttpRequest extends XMLHttpRequestBase {
|
|||||||
data: data,
|
data: data,
|
||||||
headers: headers,
|
headers: headers,
|
||||||
},
|
},
|
||||||
// TODO: Do we need this? is it used anywhere?
|
this.callback.bind(this)
|
||||||
'h' + crc32(method + '|' + url + '|' + data),
|
|
||||||
(result) => {
|
|
||||||
result = JSON.parse(result);
|
|
||||||
this.callback(result.status, result.responseHeaders, result.responseText);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ var InspectorOverlay = React.createClass({
|
|||||||
? 'flex-start'
|
? 'flex-start'
|
||||||
: 'flex-end';
|
: 'flex-end';
|
||||||
|
|
||||||
content.push(<View style={[styles.frame, this.state.frame]} />);
|
content.push(<View pointerEvents="none" style={[styles.frame, this.state.frame]} />);
|
||||||
content.push(<ElementProperties hierarchy={this.state.hierarchy} />);
|
content.push(<ElementProperties hierarchy={this.state.hierarchy} />);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ extern NSString *const RCTReactTagAttributeName;
|
|||||||
@property (nonatomic, strong) UIColor *textBackgroundColor;
|
@property (nonatomic, strong) UIColor *textBackgroundColor;
|
||||||
@property (nonatomic, assign) NSWritingDirection writingDirection;
|
@property (nonatomic, assign) NSWritingDirection writingDirection;
|
||||||
|
|
||||||
- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width;
|
|
||||||
- (void)recomputeText;
|
- (void)recomputeText;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
#import "RCTConvert.h"
|
#import "RCTConvert.h"
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
#import "RCTShadowRawText.h"
|
#import "RCTShadowRawText.h"
|
||||||
|
#import "RCTSparseArray.h"
|
||||||
|
#import "RCTText.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
|
|
||||||
NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName";
|
NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName";
|
||||||
@@ -19,6 +21,8 @@ NSString *const RCTReactTagAttributeName = @"ReactTagAttributeName";
|
|||||||
|
|
||||||
@implementation RCTShadowText
|
@implementation RCTShadowText
|
||||||
{
|
{
|
||||||
|
NSTextStorage *_cachedTextStorage;
|
||||||
|
CGFloat _cachedTextStorageWidth;
|
||||||
NSAttributedString *_cachedAttributedString;
|
NSAttributedString *_cachedAttributedString;
|
||||||
CGFloat _effectiveLetterSpacing;
|
CGFloat _effectiveLetterSpacing;
|
||||||
}
|
}
|
||||||
@@ -50,8 +54,35 @@ static css_dim_t RCTMeasure(void *context, float width)
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *)processUpdatedProperties:(NSMutableSet *)applierBlocks
|
||||||
|
parentProperties:(NSDictionary *)parentProperties
|
||||||
|
{
|
||||||
|
parentProperties = [super processUpdatedProperties:applierBlocks
|
||||||
|
parentProperties:parentProperties];
|
||||||
|
|
||||||
|
NSTextStorage *textStorage = [self buildTextStorageForWidth:self.frame.size.width];
|
||||||
|
[applierBlocks addObject:^(RCTSparseArray *viewRegistry) {
|
||||||
|
RCTText *view = viewRegistry[self.reactTag];
|
||||||
|
view.textStorage = textStorage;
|
||||||
|
}];
|
||||||
|
|
||||||
|
return parentProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applyLayoutNode:(css_node_t *)node
|
||||||
|
viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame
|
||||||
|
absolutePosition:(CGPoint)absolutePosition
|
||||||
|
{
|
||||||
|
[super applyLayoutNode:node viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition];
|
||||||
|
[self dirtyPropagation];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width
|
- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width
|
||||||
{
|
{
|
||||||
|
if (_cachedTextStorage && width == _cachedTextStorageWidth) {
|
||||||
|
return _cachedTextStorage;
|
||||||
|
}
|
||||||
|
|
||||||
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
|
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
|
||||||
|
|
||||||
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedString];
|
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedString];
|
||||||
@@ -69,13 +100,23 @@ static css_dim_t RCTMeasure(void *context, float width)
|
|||||||
[layoutManager addTextContainer:textContainer];
|
[layoutManager addTextContainer:textContainer];
|
||||||
[layoutManager ensureLayoutForTextContainer:textContainer];
|
[layoutManager ensureLayoutForTextContainer:textContainer];
|
||||||
|
|
||||||
|
_cachedTextStorage = textStorage;
|
||||||
|
_cachedTextStorageWidth = width;
|
||||||
|
|
||||||
return textStorage;
|
return textStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dirtyText
|
||||||
|
{
|
||||||
|
[super dirtyText];
|
||||||
|
_cachedTextStorage = nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)recomputeText
|
- (void)recomputeText
|
||||||
{
|
{
|
||||||
[self attributedString];
|
[self attributedString];
|
||||||
[self setTextComputed];
|
[self setTextComputed];
|
||||||
|
[self dirtyPropagation];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSAttributedString *)attributedString
|
- (NSAttributedString *)attributedString
|
||||||
|
|||||||
@@ -96,12 +96,10 @@ RCT_EXPORT_SHADOW_PROPERTY(numberOfLines, NSUInteger)
|
|||||||
{
|
{
|
||||||
NSNumber *reactTag = shadowView.reactTag;
|
NSNumber *reactTag = shadowView.reactTag;
|
||||||
UIEdgeInsets padding = shadowView.paddingAsInsets;
|
UIEdgeInsets padding = shadowView.paddingAsInsets;
|
||||||
NSTextStorage *textStorage = [shadowView buildTextStorageForWidth:shadowView.frame.size.width];
|
|
||||||
|
|
||||||
return ^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
return ^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||||
RCTText *text = viewRegistry[reactTag];
|
RCTText *text = viewRegistry[reactTag];
|
||||||
text.contentInset = padding;
|
text.contentInset = padding;
|
||||||
text.textStorage = textStorage;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
Libraries/Utilities/BridgeProfiling.js
Normal file
37
Libraries/Utilities/BridgeProfiling.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @providesModule BridgeProfiling
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var GLOBAL = GLOBAL || this;
|
||||||
|
|
||||||
|
var BridgeProfiling = {
|
||||||
|
profile(profileName: String, args?: any) {
|
||||||
|
if (GLOBAL.__BridgeProfilingIsProfiling) {
|
||||||
|
if (args) {
|
||||||
|
try {
|
||||||
|
args = JSON.stringify(args);
|
||||||
|
} catch(err) {
|
||||||
|
args = err.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.profile(profileName, args);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
profileEnd() {
|
||||||
|
if (GLOBAL.__BridgeProfilingIsProfiling) {
|
||||||
|
console.profileEnd();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = BridgeProfiling;
|
||||||
@@ -29,6 +29,7 @@ if (dimensions && dimensions.windowPhysicalPixels) {
|
|||||||
width: windowPhysicalPixels.width / windowPhysicalPixels.scale,
|
width: windowPhysicalPixels.width / windowPhysicalPixels.scale,
|
||||||
height: windowPhysicalPixels.height / windowPhysicalPixels.scale,
|
height: windowPhysicalPixels.height / windowPhysicalPixels.scale,
|
||||||
scale: windowPhysicalPixels.scale,
|
scale: windowPhysicalPixels.scale,
|
||||||
|
fontScale: windowPhysicalPixels.fontScale,
|
||||||
};
|
};
|
||||||
|
|
||||||
// delete so no callers rely on this existing
|
// delete so no callers rely on this existing
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ var GLOBAL = this;
|
|||||||
*
|
*
|
||||||
* However, we still want to treat ErrorUtils as a module so that other modules
|
* However, we still want to treat ErrorUtils as a module so that other modules
|
||||||
* that use it aren't just using a global variable, so simply export the global
|
* that use it aren't just using a global variable, so simply export the global
|
||||||
* variable here. ErrorUtils is original defined in a file named error-guard.js.
|
* variable here. ErrorUtils is originally defined in a file named error-guard.js.
|
||||||
*/
|
*/
|
||||||
module.exports = GLOBAL.ErrorUtils;
|
module.exports = GLOBAL.ErrorUtils;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ var ReactUpdates = require('ReactUpdates');
|
|||||||
var invariant = require('invariant');
|
var invariant = require('invariant');
|
||||||
var warning = require('warning');
|
var warning = require('warning');
|
||||||
|
|
||||||
|
var BridgeProfiling = require('BridgeProfiling');
|
||||||
var JSTimersExecution = require('JSTimersExecution');
|
var JSTimersExecution = require('JSTimersExecution');
|
||||||
|
|
||||||
var INTERNAL_ERROR = 'Error in MessageQueue implementation';
|
var INTERNAL_ERROR = 'Error in MessageQueue implementation';
|
||||||
@@ -277,7 +278,9 @@ var MessageQueueMixin = {
|
|||||||
if (DEBUG_SPY_MODE) {
|
if (DEBUG_SPY_MODE) {
|
||||||
console.log('N->JS: Callback#' + cbID + '(' + JSON.stringify(args) + ')');
|
console.log('N->JS: Callback#' + cbID + '(' + JSON.stringify(args) + ')');
|
||||||
}
|
}
|
||||||
|
BridgeProfiling.profile('Callback#' + cbID + '(' + JSON.stringify(args) + ')');
|
||||||
cb.apply(scope, args);
|
cb.apply(scope, args);
|
||||||
|
BridgeProfiling.profileEnd();
|
||||||
} catch(ie_requires_catch) {
|
} catch(ie_requires_catch) {
|
||||||
throw ie_requires_catch;
|
throw ie_requires_catch;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -311,7 +314,9 @@ var MessageQueueMixin = {
|
|||||||
'N->JS: ' + moduleName + '.' + methodName +
|
'N->JS: ' + moduleName + '.' + methodName +
|
||||||
'(' + JSON.stringify(params) + ')');
|
'(' + JSON.stringify(params) + ')');
|
||||||
}
|
}
|
||||||
|
BridgeProfiling.profile(moduleName + '.' + methodName + '(' + JSON.stringify(params) + ')');
|
||||||
var ret = jsCall(this._requireFunc(moduleName), methodName, params);
|
var ret = jsCall(this._requireFunc(moduleName), methodName, params);
|
||||||
|
BridgeProfiling.profileEnd();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
@@ -330,7 +335,8 @@ var MessageQueueMixin = {
|
|||||||
|
|
||||||
processBatch: function(batch) {
|
processBatch: function(batch) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return guardReturn(function () {
|
BridgeProfiling.profile('MessageQueue.processBatch()');
|
||||||
|
var flushedQueue = guardReturn(function () {
|
||||||
ReactUpdates.batchedUpdates(function() {
|
ReactUpdates.batchedUpdates(function() {
|
||||||
batch.forEach(function(call) {
|
batch.forEach(function(call) {
|
||||||
invariant(
|
invariant(
|
||||||
@@ -346,8 +352,12 @@ var MessageQueueMixin = {
|
|||||||
'Unrecognized method called on BatchedBridge: ' + call.method);
|
'Unrecognized method called on BatchedBridge: ' + call.method);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
BridgeProfiling.profile('React.batchedUpdates()');
|
||||||
});
|
});
|
||||||
|
BridgeProfiling.profileEnd();
|
||||||
}, null, this._flushedQueueUnguarded, this);
|
}, null, this._flushedQueueUnguarded, this);
|
||||||
|
BridgeProfiling.profileEnd();
|
||||||
|
return flushedQueue;
|
||||||
},
|
},
|
||||||
|
|
||||||
setLoggingEnabled: function(enabled) {
|
setLoggingEnabled: function(enabled) {
|
||||||
@@ -472,8 +482,10 @@ var MessageQueueMixin = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_flushedQueueUnguarded: function() {
|
_flushedQueueUnguarded: function() {
|
||||||
// Call the functions registred via setImmediate
|
BridgeProfiling.profile('JSTimersExecution.callImmediates()');
|
||||||
|
// Call the functions registered via setImmediate
|
||||||
JSTimersExecution.callImmediates();
|
JSTimersExecution.callImmediates();
|
||||||
|
BridgeProfiling.profileEnd();
|
||||||
|
|
||||||
var currentOutgoingItems = this._outgoingItems;
|
var currentOutgoingItems = this._outgoingItems;
|
||||||
this._swapAndReinitializeBuffer();
|
this._swapAndReinitializeBuffer();
|
||||||
|
|||||||
@@ -59,6 +59,20 @@ class PixelRatio {
|
|||||||
return Dimensions.get('window').scale;
|
return Dimensions.get('window').scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scaling factor for font sizes. This is the ratio that is used to calculate the
|
||||||
|
* absolute font size, so any elements that heavily depend on that should use this to do
|
||||||
|
* calculations.
|
||||||
|
*
|
||||||
|
* If a font scale is not set, this returns the device pixel ratio.
|
||||||
|
*
|
||||||
|
* Currently this is only implemented on Android and reflects the user preference set in
|
||||||
|
* Settings > Display > Font size, on iOS it will always return the default pixel ratio.
|
||||||
|
*/
|
||||||
|
static getFontScale(): number {
|
||||||
|
return Dimensions.get('window').fontScale || PixelRatio.get();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a layout size (dp) to pixel size (px).
|
* Converts a layout size (dp) to pixel size (px).
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1339,8 +1339,11 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
* AnyThread
|
* AnyThread
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
RCTProfileBeginFlowEvent();
|
||||||
|
|
||||||
__weak RCTBatchedBridge *weakSelf = self;
|
__weak RCTBatchedBridge *weakSelf = self;
|
||||||
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
||||||
|
RCTProfileEndFlowEvent();
|
||||||
RCTProfileBeginEvent();
|
RCTProfileBeginEvent();
|
||||||
|
|
||||||
RCTBatchedBridge *strongSelf = weakSelf;
|
RCTBatchedBridge *strongSelf = weakSelf;
|
||||||
@@ -1348,13 +1351,17 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
id call = @{
|
|
||||||
@"module": module,
|
|
||||||
@"method": method,
|
|
||||||
@"args": args,
|
|
||||||
@"context": context ?: @0,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
RCT_IF_DEV(NSNumber *callID = _RCTProfileBeginFlowEvent();)
|
||||||
|
id call = @{
|
||||||
|
@"js_args": @{
|
||||||
|
@"module": module,
|
||||||
|
@"method": method,
|
||||||
|
@"args": args,
|
||||||
|
},
|
||||||
|
@"context": context ?: @0,
|
||||||
|
RCT_IF_DEV(@"call_id": callID,)
|
||||||
|
};
|
||||||
if ([method isEqualToString:@"invokeCallbackAndReturnFlushedQueue"]) {
|
if ([method isEqualToString:@"invokeCallbackAndReturnFlushedQueue"]) {
|
||||||
strongSelf->_scheduledCallbacks[args[0]] = call;
|
strongSelf->_scheduledCallbacks[args[0]] = call;
|
||||||
} else {
|
} else {
|
||||||
@@ -1490,8 +1497,10 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCTProfileBeginFlowEvent();
|
||||||
__weak RCTBatchedBridge *weakSelf = self;
|
__weak RCTBatchedBridge *weakSelf = self;
|
||||||
[self dispatchBlock:^{
|
[self dispatchBlock:^{
|
||||||
|
RCTProfileEndFlowEvent();
|
||||||
RCTProfileBeginEvent();
|
RCTProfileBeginEvent();
|
||||||
RCTBatchedBridge *strongSelf = weakSelf;
|
RCTBatchedBridge *strongSelf = weakSelf;
|
||||||
|
|
||||||
@@ -1525,16 +1534,18 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
- (void)_jsThreadUpdate:(CADisplayLink *)displayLink
|
- (void)_jsThreadUpdate:(CADisplayLink *)displayLink
|
||||||
{
|
{
|
||||||
RCTAssertJSThread();
|
RCTAssertJSThread();
|
||||||
|
|
||||||
RCTProfileImmediateEvent(@"JS Thread Tick", displayLink.timestamp, @"g");
|
|
||||||
|
|
||||||
RCTProfileBeginEvent();
|
RCTProfileBeginEvent();
|
||||||
|
|
||||||
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
|
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
|
||||||
for (id<RCTFrameUpdateObserver> observer in _frameUpdateObservers) {
|
for (id<RCTFrameUpdateObserver> observer in _frameUpdateObservers) {
|
||||||
if (![observer respondsToSelector:@selector(isPaused)] || ![observer isPaused]) {
|
if (![observer respondsToSelector:@selector(isPaused)] || ![observer isPaused]) {
|
||||||
|
RCT_IF_DEV(NSString *name = [NSString stringWithFormat:@"[%@ didUpdateFrame:%f]", observer, displayLink.timestamp];)
|
||||||
|
RCTProfileBeginFlowEvent();
|
||||||
[self dispatchBlock:^{
|
[self dispatchBlock:^{
|
||||||
|
RCTProfileEndFlowEvent();
|
||||||
|
RCTProfileBeginEvent();
|
||||||
[observer didUpdateFrame:frameUpdate];
|
[observer didUpdateFrame:frameUpdate];
|
||||||
|
RCTProfileEndEvent(name, @"objc_call,fps", nil);
|
||||||
} forModule:RCTModuleIDsByName[RCTBridgeModuleNameForClass([observer class])]];
|
} forModule:RCTModuleIDsByName[RCTBridgeModuleNameForClass([observer class])]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1544,18 +1555,29 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
calls = [calls filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSDictionary *call, NSDictionary *bindings) {
|
calls = [calls filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSDictionary *call, NSDictionary *bindings) {
|
||||||
return [call[@"context"] isEqualToNumber:currentExecutorID];
|
return [call[@"context"] isEqualToNumber:currentExecutorID];
|
||||||
}]];
|
}]];
|
||||||
|
|
||||||
|
RCT_IF_DEV(
|
||||||
|
RCTProfileImmediateEvent(@"JS Thread Tick", displayLink.timestamp, @"g");
|
||||||
|
|
||||||
|
for (NSDictionary *call in calls) {
|
||||||
|
_RCTProfileEndFlowEvent(call[@"call_id"]);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if (calls.count > 0) {
|
if (calls.count > 0) {
|
||||||
_scheduledCalls = [[NSMutableArray alloc] init];
|
_scheduledCalls = [[NSMutableArray alloc] init];
|
||||||
_scheduledCallbacks = [[RCTSparseArray alloc] init];
|
_scheduledCallbacks = [[RCTSparseArray alloc] init];
|
||||||
[self _actuallyInvokeAndProcessModule:@"BatchedBridge"
|
[self _actuallyInvokeAndProcessModule:@"BatchedBridge"
|
||||||
method:@"processBatch"
|
method:@"processBatch"
|
||||||
arguments:@[calls]
|
arguments:@[[calls valueForKey:@"js_args"]]
|
||||||
context:RCTGetExecutorID(_javaScriptExecutor)];
|
context:RCTGetExecutorID(_javaScriptExecutor)];
|
||||||
}
|
}
|
||||||
|
|
||||||
RCTProfileEndEvent(@"DispatchFrameUpdate", @"objc_call", nil);
|
RCTProfileEndEvent(@"DispatchFrameUpdate", @"objc_call", nil);
|
||||||
|
|
||||||
[self.perfStats.jsGraph tick:displayLink.timestamp];
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self.perfStats.jsGraph tick:displayLink.timestamp];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_mainThreadUpdate:(CADisplayLink *)displayLink
|
- (void)_mainThreadUpdate:(CADisplayLink *)displayLink
|
||||||
|
|||||||
@@ -42,6 +42,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if RCT_DEV
|
||||||
|
#define RCT_IF_DEV(...) __VA_ARGS__
|
||||||
|
#else
|
||||||
|
#define RCT_IF_DEV(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default, only raise an NSAssertion in debug mode
|
* By default, only raise an NSAssertion in debug mode
|
||||||
* (custom assert functions will still be called).
|
* (custom assert functions will still be called).
|
||||||
|
|||||||
@@ -11,11 +11,10 @@
|
|||||||
|
|
||||||
#import "RCTAssert.h"
|
#import "RCTAssert.h"
|
||||||
#import "RCTBridge.h"
|
#import "RCTBridge.h"
|
||||||
#import "RCTSparseArray.h"
|
|
||||||
|
|
||||||
static uint64_t RCTGetEventID(id<RCTEvent> event)
|
static NSNumber *RCTGetEventID(id<RCTEvent> event)
|
||||||
{
|
{
|
||||||
return (
|
return @(
|
||||||
[event.viewTag intValue] |
|
[event.viewTag intValue] |
|
||||||
(((uint64_t)event.eventName.hash & 0xFFFF) << 32) |
|
(((uint64_t)event.eventName.hash & 0xFFFF) << 32) |
|
||||||
(((uint64_t)event.coalescingKey) << 48)
|
(((uint64_t)event.coalescingKey) << 48)
|
||||||
@@ -68,7 +67,7 @@ static uint64_t RCTGetEventID(id<RCTEvent> event)
|
|||||||
|
|
||||||
@implementation RCTEventDispatcher
|
@implementation RCTEventDispatcher
|
||||||
{
|
{
|
||||||
RCTSparseArray *_eventQueue;
|
NSMutableDictionary *_eventQueue;
|
||||||
NSLock *_eventQueueLock;
|
NSLock *_eventQueueLock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ RCT_EXPORT_MODULE()
|
|||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_eventQueue = [[RCTSparseArray alloc] init];
|
_eventQueue = [[NSMutableDictionary alloc] init];
|
||||||
_eventQueueLock = [[NSLock alloc] init];
|
_eventQueueLock = [[NSLock alloc] init];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -139,7 +138,7 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveEvent);
|
|||||||
|
|
||||||
[_eventQueueLock lock];
|
[_eventQueueLock lock];
|
||||||
|
|
||||||
uint64_t eventID = RCTGetEventID(event);
|
NSNumber *eventID = RCTGetEventID(event);
|
||||||
id<RCTEvent> previousEvent = _eventQueue[eventID];
|
id<RCTEvent> previousEvent = _eventQueue[eventID];
|
||||||
|
|
||||||
if (previousEvent) {
|
if (previousEvent) {
|
||||||
@@ -176,14 +175,14 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveEvent);
|
|||||||
|
|
||||||
- (void)didUpdateFrame:(RCTFrameUpdate *)update
|
- (void)didUpdateFrame:(RCTFrameUpdate *)update
|
||||||
{
|
{
|
||||||
RCTSparseArray *eventQueue;
|
NSDictionary *eventQueue;
|
||||||
|
|
||||||
[_eventQueueLock lock];
|
[_eventQueueLock lock];
|
||||||
eventQueue = _eventQueue;
|
eventQueue = _eventQueue;
|
||||||
_eventQueue = [[RCTSparseArray alloc] init];
|
_eventQueue = [[NSMutableDictionary alloc] init];
|
||||||
[_eventQueueLock unlock];
|
[_eventQueueLock unlock];
|
||||||
|
|
||||||
for (id<RCTEvent> event in eventQueue.allObjects) {
|
for (id<RCTEvent> event in eventQueue.allValues) {
|
||||||
[self dispatchEvent:event];
|
[self dispatchEvent:event];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,23 @@
|
|||||||
* before before using it.
|
* before before using it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
NSString *const RCTProfileDidStartProfiling;
|
||||||
|
NSString *const RCTProfileDidEndProfiling;
|
||||||
|
|
||||||
#if RCT_DEV
|
#if RCT_DEV
|
||||||
|
|
||||||
|
#define RCTProfileBeginFlowEvent() \
|
||||||
|
_Pragma("clang diagnostic push") \
|
||||||
|
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
|
||||||
|
NSNumber *__rct_profile_flow_id = _RCTProfileBeginFlowEvent(); \
|
||||||
|
_Pragma("clang diagnostic pop")
|
||||||
|
|
||||||
|
#define RCTProfileEndFlowEvent() \
|
||||||
|
_RCTProfileEndFlowEvent(__rct_profile_flow_id)
|
||||||
|
|
||||||
|
RCT_EXTERN NSNumber *_RCTProfileBeginFlowEvent(void);
|
||||||
|
RCT_EXTERN void _RCTProfileEndFlowEvent(NSNumber *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns YES if the profiling information is currently being collected
|
* Returns YES if the profiling information is currently being collected
|
||||||
*/
|
*/
|
||||||
@@ -88,6 +103,12 @@ RCT_EXTERN void RCTProfileImmediateEvent(NSString *, NSTimeInterval , NSString *
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#define RCTProfileBeginFlowEvent()
|
||||||
|
#define _RCTProfileBeginFlowEvent() @0
|
||||||
|
|
||||||
|
#define RCTProfileEndFlowEvent()
|
||||||
|
#define _RCTProfileEndFlowEvent()
|
||||||
|
|
||||||
#define RCTProfileIsProfiling(...) NO
|
#define RCTProfileIsProfiling(...) NO
|
||||||
#define RCTProfileInit(...)
|
#define RCTProfileInit(...)
|
||||||
#define RCTProfileEnd(...) @""
|
#define RCTProfileEnd(...) @""
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
#import "RCTDefines.h"
|
#import "RCTDefines.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
|
|
||||||
|
NSString *const RCTProfileDidStartProfiling = @"RCTProfileDidStartProfiling";
|
||||||
|
NSString *const RCTProfileDidEndProfiling = @"RCTProfileDidEndProfiling";
|
||||||
|
|
||||||
#if RCT_DEV
|
#if RCT_DEV
|
||||||
|
|
||||||
#pragma mark - Prototypes
|
#pragma mark - Prototypes
|
||||||
@@ -113,10 +116,16 @@ void RCTProfileInit(void)
|
|||||||
RCTProfileSamples: [[NSMutableArray alloc] init],
|
RCTProfileSamples: [[NSMutableArray alloc] init],
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidStartProfiling
|
||||||
|
object:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *RCTProfileEnd(void)
|
NSString *RCTProfileEnd(void)
|
||||||
{
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidEndProfiling
|
||||||
|
object:nil];
|
||||||
|
|
||||||
RCTProfileLock(
|
RCTProfileLock(
|
||||||
NSString *log = RCTJSONStringify(RCTProfileInfo, NULL);
|
NSString *log = RCTJSONStringify(RCTProfileInfo, NULL);
|
||||||
RCTProfileEventID = 0;
|
RCTProfileEventID = 0;
|
||||||
@@ -171,4 +180,32 @@ void RCTProfileImmediateEvent(NSString *name, NSTimeInterval timestamp, NSString
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSNumber *_RCTProfileBeginFlowEvent(void)
|
||||||
|
{
|
||||||
|
static NSUInteger flowID = 0;
|
||||||
|
|
||||||
|
CHECK(@0);
|
||||||
|
RCTProfileAddEvent(RCTProfileTraceEvents,
|
||||||
|
@"name": @"flow",
|
||||||
|
@"id": @(++flowID),
|
||||||
|
@"cat": @"flow",
|
||||||
|
@"ph": @"s",
|
||||||
|
@"ts": RCTProfileTimestamp(CACurrentMediaTime()),
|
||||||
|
);
|
||||||
|
|
||||||
|
return @(flowID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _RCTProfileEndFlowEvent(NSNumber *flowID)
|
||||||
|
{
|
||||||
|
CHECK();
|
||||||
|
RCTProfileAddEvent(RCTProfileTraceEvents,
|
||||||
|
@"name": @"flow",
|
||||||
|
@"id": flowID,
|
||||||
|
@"cat": @"flow",
|
||||||
|
@"ph": @"f",
|
||||||
|
@"ts": RCTProfileTimestamp(CACurrentMediaTime()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -133,22 +133,27 @@ static JSValueRef RCTConsoleProfile(JSContextRef context, JSObjectRef object, JS
|
|||||||
profileName = [NSString stringWithFormat:@"Profile %d", profileCounter++];
|
profileName = [NSString stringWithFormat:@"Profile %d", profileCounter++];
|
||||||
}
|
}
|
||||||
|
|
||||||
[profiles addObjectsFromArray:@[profileName, profileID]];
|
id profileInfo = [NSNull null];
|
||||||
|
if (argumentCount > 1 && !JSValueIsUndefined(context, arguments[1])) {
|
||||||
|
profileInfo = @[RCTJSValueToNSString(context, arguments[1])];
|
||||||
|
}
|
||||||
|
|
||||||
|
[profiles addObjectsFromArray:@[profileName, profileID, profileInfo]];
|
||||||
|
|
||||||
RCTLog(@"Profile '%@' finished.", profileName);
|
|
||||||
return JSValueMakeUndefined(context);
|
return JSValueMakeUndefined(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValueRef RCTConsoleProfileEnd(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception)
|
static JSValueRef RCTConsoleProfileEnd(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception)
|
||||||
{
|
{
|
||||||
|
NSString *profileInfo = [profiles lastObject];
|
||||||
|
[profiles removeLastObject];
|
||||||
NSNumber *profileID = [profiles lastObject];
|
NSNumber *profileID = [profiles lastObject];
|
||||||
[profiles removeLastObject];
|
[profiles removeLastObject];
|
||||||
NSString *profileName = [profiles lastObject];
|
NSString *profileName = [profiles lastObject];
|
||||||
[profiles removeLastObject];
|
[profiles removeLastObject];
|
||||||
|
|
||||||
_RCTProfileEndEvent(profileID, profileName, @"console", nil);
|
_RCTProfileEndEvent(profileID, profileName, @"console", profileInfo);
|
||||||
|
|
||||||
RCTLog(@"Profile '%@' started.", profileName);
|
|
||||||
return JSValueMakeUndefined(context);
|
return JSValueMakeUndefined(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +249,13 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||||||
#if RCT_DEV
|
#if RCT_DEV
|
||||||
[strongSelf _addNativeHook:RCTConsoleProfile withName:"consoleProfile"];
|
[strongSelf _addNativeHook:RCTConsoleProfile withName:"consoleProfile"];
|
||||||
[strongSelf _addNativeHook:RCTConsoleProfileEnd withName:"consoleProfileEnd"];
|
[strongSelf _addNativeHook:RCTConsoleProfileEnd withName:"consoleProfileEnd"];
|
||||||
|
|
||||||
|
for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(toggleProfilingFlag:)
|
||||||
|
name:event
|
||||||
|
object:nil];
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}];
|
}];
|
||||||
@@ -252,6 +264,21 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)toggleProfilingFlag:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
JSObjectRef globalObject = JSContextGetGlobalObject(_context.ctx);
|
||||||
|
|
||||||
|
bool enabled = [notification.name isEqualToString:RCTProfileDidStartProfiling];
|
||||||
|
JSStringRef JSName = JSStringCreateWithUTF8CString("__BridgeProfilingIsProfiling");
|
||||||
|
JSObjectSetProperty(_context.ctx,
|
||||||
|
globalObject,
|
||||||
|
JSName,
|
||||||
|
JSValueMakeBoolean(_context.ctx, enabled),
|
||||||
|
kJSPropertyAttributeNone,
|
||||||
|
NULL);
|
||||||
|
JSStringRelease(JSName);
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_addNativeHook:(JSObjectCallAsFunctionCallback)hook withName:(const char *)name
|
- (void)_addNativeHook:(JSObjectCallAsFunctionCallback)hook withName:(const char *)name
|
||||||
{
|
{
|
||||||
JSObjectRef globalObject = JSContextGetGlobalObject(_context.ctx);
|
JSObjectRef globalObject = JSContextGetGlobalObject(_context.ctx);
|
||||||
@@ -269,6 +296,10 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||||||
|
|
||||||
- (void)invalidate
|
- (void)invalidate
|
||||||
{
|
{
|
||||||
|
#if RCT_DEV
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
#endif
|
||||||
|
|
||||||
[_context performSelector:@selector(invalidate) onThread:_javaScriptThread withObject:nil waitUntilDone:NO];
|
[_context performSelector:@selector(invalidate) onThread:_javaScriptThread withObject:nil waitUntilDone:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
|
|||||||
[_delegate handleSoftJSExceptionWithMessage:message stack:stack];
|
[_delegate handleSoftJSExceptionWithMessage:message stack:stack];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// JS already logs the error via console.
|
||||||
[[RCTRedBox sharedInstance] showErrorMessage:message withStack:stack];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
|
RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
|
||||||
|
|||||||
@@ -481,6 +481,10 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa
|
|||||||
shadowView.newView = NO;
|
shadowView.newView = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These are blocks to be executed on each view, immediately after
|
||||||
|
// reactSetFrame: has been called. Note that if reactSetFrame: is not called,
|
||||||
|
// these won't be called either, so this is not a suitable place to update
|
||||||
|
// properties that aren't related to layout.
|
||||||
NSMutableArray *updateBlocks = [[NSMutableArray alloc] init];
|
NSMutableArray *updateBlocks = [[NSMutableArray alloc] init];
|
||||||
for (RCTShadowView *shadowView in viewsWithNewFrames) {
|
for (RCTShadowView *shadowView in viewsWithNewFrames) {
|
||||||
RCTViewManager *manager = _viewManagerRegistry[shadowView.reactTag];
|
RCTViewManager *manager = _viewManagerRegistry[shadowView.reactTag];
|
||||||
@@ -917,6 +921,7 @@ RCT_EXPORT_METHOD(findSubviewIn:(NSNumber *)reactTag atPoint:(CGPoint)point call
|
|||||||
|
|
||||||
- (void)batchDidComplete
|
- (void)batchDidComplete
|
||||||
{
|
{
|
||||||
|
RCTProfileBeginEvent();
|
||||||
// Gather blocks to be executed now that all view hierarchy manipulations have
|
// Gather blocks to be executed now that all view hierarchy manipulations have
|
||||||
// been completed (note that these may still take place before layout has finished)
|
// been completed (note that these may still take place before layout has finished)
|
||||||
for (RCTViewManager *manager in _viewManagers.allValues) {
|
for (RCTViewManager *manager in _viewManagers.allValues) {
|
||||||
@@ -947,6 +952,9 @@ RCT_EXPORT_METHOD(findSubviewIn:(NSNumber *)reactTag atPoint:(CGPoint)point call
|
|||||||
_nextLayoutAnimation = nil;
|
_nextLayoutAnimation = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCTProfileEndEvent(@"[RCTUIManager batchDidComplete]", @"uimanager", @{
|
||||||
|
@"view_count": @([_viewRegistry count]),
|
||||||
|
});
|
||||||
[self flushUIBlocks];
|
[self flushUIBlocks];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ typedef NS_ENUM(NSUInteger, RCTUpdateLifecycle) {
|
|||||||
RCTUpdateLifecycleDirtied,
|
RCTUpdateLifecycleDirtied,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: is this redundact now?
|
typedef void (^RCTApplierBlock)(RCTSparseArray *viewRegistry);
|
||||||
typedef void (^RCTApplierBlock)(RCTSparseArray *);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ShadowView tree mirrors RCT view tree. Every node is highly stateful.
|
* ShadowView tree mirrors RCT view tree. Every node is highly stateful.
|
||||||
@@ -117,34 +116,48 @@ typedef void (^RCTApplierBlock)(RCTSparseArray *);
|
|||||||
* The applierBlocks set contains RCTApplierBlock functions that must be applied
|
* The applierBlocks set contains RCTApplierBlock functions that must be applied
|
||||||
* on the main thread in order to update the view.
|
* on the main thread in order to update the view.
|
||||||
*/
|
*/
|
||||||
- (void)collectUpdatedProperties:(NSMutableSet *)applierBlocks parentProperties:(NSDictionary *)parentProperties;
|
- (void)collectUpdatedProperties:(NSMutableSet *)applierBlocks
|
||||||
|
parentProperties:(NSDictionary *)parentProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the updated properties and apply them to view. Shadow view classes
|
||||||
|
* that add additional propagating properties should override this method.
|
||||||
|
*/
|
||||||
|
- (NSDictionary *)processUpdatedProperties:(NSMutableSet *)applierBlocks
|
||||||
|
parentProperties:(NSDictionary *)parentProperties NS_REQUIRES_SUPER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate all views whose frame needs updating after layout has been calculated.
|
* Calculate all views whose frame needs updating after layout has been calculated.
|
||||||
* The viewsWithNewFrame set contains the reactTags of the views that need updating.
|
* The viewsWithNewFrame set contains the reactTags of the views that need updating.
|
||||||
*/
|
*/
|
||||||
- (void)collectRootUpdatedFrames:(NSMutableSet *)viewsWithNewFrame parentConstraint:(CGSize)parentConstraint;
|
- (void)collectRootUpdatedFrames:(NSMutableSet *)viewsWithNewFrame
|
||||||
|
parentConstraint:(CGSize)parentConstraint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively apply layout to children.
|
||||||
|
*/
|
||||||
|
- (void)applyLayoutNode:(css_node_t *)node
|
||||||
|
viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame
|
||||||
|
absolutePosition:(CGPoint)absolutePosition NS_REQUIRES_SUPER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following are implementation details exposed to subclasses. Do not call them directly
|
* The following are implementation details exposed to subclasses. Do not call them directly
|
||||||
*/
|
*/
|
||||||
- (void)fillCSSNode:(css_node_t *)node;
|
- (void)fillCSSNode:(css_node_t *)node NS_REQUIRES_SUPER;
|
||||||
- (void)dirtyLayout;
|
- (void)dirtyLayout NS_REQUIRES_SUPER;
|
||||||
- (BOOL)isLayoutDirty;
|
- (BOOL)isLayoutDirty;
|
||||||
|
|
||||||
// TODO: is this still needed?
|
- (void)dirtyPropagation NS_REQUIRES_SUPER;
|
||||||
- (void)dirtyPropagation;
|
|
||||||
- (BOOL)isPropagationDirty;
|
- (BOOL)isPropagationDirty;
|
||||||
|
|
||||||
// TODO: move this to text node?
|
- (void)dirtyText NS_REQUIRES_SUPER;
|
||||||
- (void)dirtyText;
|
- (void)setTextComputed NS_REQUIRES_SUPER;
|
||||||
- (BOOL)isTextDirty;
|
- (BOOL)isTextDirty;
|
||||||
- (void)setTextComputed;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers a recalculation of the shadow view's layout.
|
* Triggers a recalculation of the shadow view's layout.
|
||||||
*/
|
*/
|
||||||
- (void)updateLayout;
|
- (void)updateLayout NS_REQUIRES_SUPER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the recursive offset, meaning the sum of all descendant offsets -
|
* Computes the recursive offset, meaning the sum of all descendant offsets -
|
||||||
|
|||||||
@@ -120,7 +120,9 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
|
|||||||
// width = 213.5 - 106.5 = 107
|
// width = 213.5 - 106.5 = 107
|
||||||
// You'll notice that this is the same width we calculated for the parent view because we've taken its position into account.
|
// You'll notice that this is the same width we calculated for the parent view because we've taken its position into account.
|
||||||
|
|
||||||
- (void)applyLayoutNode:(css_node_t *)node viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame absolutePosition:(CGPoint)absolutePosition
|
- (void)applyLayoutNode:(css_node_t *)node
|
||||||
|
viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame
|
||||||
|
absolutePosition:(CGPoint)absolutePosition
|
||||||
{
|
{
|
||||||
if (!node->layout.should_update) {
|
if (!node->layout.should_update) {
|
||||||
return;
|
return;
|
||||||
@@ -161,12 +163,19 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
|
|||||||
|
|
||||||
for (int i = 0; i < node->children_count; ++i) {
|
for (int i = 0; i < node->children_count; ++i) {
|
||||||
RCTShadowView *child = (RCTShadowView *)_reactSubviews[i];
|
RCTShadowView *child = (RCTShadowView *)_reactSubviews[i];
|
||||||
[child applyLayoutNode:node->get_child(node->context, i) viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition];
|
[child applyLayoutNode:node->get_child(node->context, i)
|
||||||
|
viewsWithNewFrame:viewsWithNewFrame
|
||||||
|
absolutePosition:absolutePosition];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)processBackgroundColor:(NSMutableSet *)applierBlocks parentProperties:(NSDictionary *)parentProperties
|
- (NSDictionary *)processUpdatedProperties:(NSMutableSet *)applierBlocks
|
||||||
|
parentProperties:(NSDictionary *)parentProperties
|
||||||
{
|
{
|
||||||
|
// TODO: we always refresh all propagated properties when propagation is
|
||||||
|
// dirtied, but really we should track which properties have changed and
|
||||||
|
// only update those.
|
||||||
|
|
||||||
if (!_backgroundColor) {
|
if (!_backgroundColor) {
|
||||||
UIColor *parentBackgroundColor = parentProperties[RCTBackgroundColorProp];
|
UIColor *parentBackgroundColor = parentProperties[RCTBackgroundColorProp];
|
||||||
if (parentBackgroundColor) {
|
if (parentBackgroundColor) {
|
||||||
@@ -190,14 +199,15 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
|
|||||||
return parentProperties;
|
return parentProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)collectUpdatedProperties:(NSMutableSet *)applierBlocks parentProperties:(NSDictionary *)parentProperties
|
- (void)collectUpdatedProperties:(NSMutableSet *)applierBlocks
|
||||||
|
parentProperties:(NSDictionary *)parentProperties
|
||||||
{
|
{
|
||||||
if (_propagationLifecycle == RCTUpdateLifecycleComputed && [parentProperties isEqualToDictionary:_lastParentProperties]) {
|
if (_propagationLifecycle == RCTUpdateLifecycleComputed && [parentProperties isEqualToDictionary:_lastParentProperties]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_propagationLifecycle = RCTUpdateLifecycleComputed;
|
_propagationLifecycle = RCTUpdateLifecycleComputed;
|
||||||
_lastParentProperties = parentProperties;
|
_lastParentProperties = parentProperties;
|
||||||
NSDictionary *nextProps = [self processBackgroundColor:applierBlocks parentProperties:parentProperties];
|
NSDictionary *nextProps = [self processUpdatedProperties:applierBlocks parentProperties:parentProperties];
|
||||||
for (RCTShadowView *child in _reactSubviews) {
|
for (RCTShadowView *child in _reactSubviews) {
|
||||||
[child collectUpdatedProperties:applierBlocks parentProperties:nextProps];
|
[child collectUpdatedProperties:applierBlocks parentProperties:nextProps];
|
||||||
}
|
}
|
||||||
@@ -212,21 +222,19 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
|
|||||||
|
|
||||||
- (CGRect)measureLayoutRelativeToAncestor:(RCTShadowView *)ancestor
|
- (CGRect)measureLayoutRelativeToAncestor:(RCTShadowView *)ancestor
|
||||||
{
|
{
|
||||||
CGFloat totalOffsetTop = 0.0;
|
CGPoint offset = CGPointZero;
|
||||||
CGFloat totalOffsetLeft = 0.0;
|
|
||||||
CGSize size = self.frame.size;
|
|
||||||
NSInteger depth = 30; // max depth to search
|
NSInteger depth = 30; // max depth to search
|
||||||
RCTShadowView *shadowView = self;
|
RCTShadowView *shadowView = self;
|
||||||
while (depth && shadowView && shadowView != ancestor) {
|
while (depth && shadowView && shadowView != ancestor) {
|
||||||
totalOffsetTop += shadowView.frame.origin.y;
|
offset.x += shadowView.frame.origin.x;
|
||||||
totalOffsetLeft += shadowView.frame.origin.x;
|
offset.y += shadowView.frame.origin.y;
|
||||||
shadowView = shadowView->_superview;
|
shadowView = shadowView->_superview;
|
||||||
depth--;
|
depth--;
|
||||||
}
|
}
|
||||||
if (ancestor != shadowView) {
|
if (ancestor != shadowView) {
|
||||||
return CGRectNull;
|
return CGRectNull;
|
||||||
}
|
}
|
||||||
return (CGRect){{totalOffsetLeft, totalOffsetTop}, size};
|
return (CGRect){offset, self.frame.size};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
|||||||
// View has cliping enabled, so we can easily test if it is partially
|
// View has cliping enabled, so we can easily test if it is partially
|
||||||
// or completely within the clipRect, and mount or unmount it accordingly
|
// or completely within the clipRect, and mount or unmount it accordingly
|
||||||
|
|
||||||
if (CGRectIntersectsRect(clipRect, view.frame)) {
|
if (!CGRectIsEmpty(CGRectIntersection(clipRect, view.frame))) {
|
||||||
|
|
||||||
// View is at least partially visible, so remount it if unmounted
|
// View is at least partially visible, so remount it if unmounted
|
||||||
if (view.superview == nil) {
|
if (view.superview == nil) {
|
||||||
|
|||||||
@@ -60,9 +60,9 @@
|
|||||||
"react-timer-mixin": "^0.13.1",
|
"react-timer-mixin": "^0.13.1",
|
||||||
"react-tools": "0.13.2",
|
"react-tools": "0.13.2",
|
||||||
"rebound": "^0.0.12",
|
"rebound": "^0.0.12",
|
||||||
"sane": "git://github.com/tadeuzagallo/sane.git#a029f8b04a",
|
"sane": "tadeuzagallo/sane#a029f8b04a",
|
||||||
"source-map": "0.1.31",
|
"source-map": "0.1.31",
|
||||||
"stacktrace-parser": "git://github.com/frantic/stacktrace-parser.git#493c5e5638",
|
"stacktrace-parser": "frantic/stacktrace-parser#493c5e5638",
|
||||||
"uglify-js": "~2.4.16",
|
"uglify-js": "~2.4.16",
|
||||||
"underscore": "1.7.0",
|
"underscore": "1.7.0",
|
||||||
"worker-farm": "^1.3.1",
|
"worker-farm": "^1.3.1",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var exec = require('child_process').exec;
|
var execFile = require('child_process').execFile;
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
|
|
||||||
var getFlowTypeCheckMiddleware = require('./getFlowTypeCheckMiddleware');
|
var getFlowTypeCheckMiddleware = require('./getFlowTypeCheckMiddleware');
|
||||||
@@ -172,7 +172,7 @@ function getDevToolsLauncher(options) {
|
|||||||
var debuggerURL = 'http://localhost:' + options.port + '/debugger-ui';
|
var debuggerURL = 'http://localhost:' + options.port + '/debugger-ui';
|
||||||
var script = 'launchChromeDevTools.applescript';
|
var script = 'launchChromeDevTools.applescript';
|
||||||
console.log('Launching Dev Tools...');
|
console.log('Launching Dev Tools...');
|
||||||
exec(path.join(__dirname, script) + ' ' + debuggerURL, function(err, stdout, stderr) {
|
execFile(path.join(__dirname, script), [debuggerURL], function(err, stdout, stderr) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('Failed to run ' + script, err);
|
console.log('Failed to run ' + script, err);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user