mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c863979abc | ||
|
|
27d152cd82 | ||
|
|
b7b0013348 | ||
|
|
325217371f | ||
|
|
6f1e48d34d | ||
|
|
0aa79897e6 | ||
|
|
08a6a1ae65 | ||
|
|
ad732b84ab | ||
|
|
284a20b0de | ||
|
|
742c205e52 | ||
|
|
93dc62ac08 | ||
|
|
e0b07568fe | ||
|
|
5adfe16ad2 | ||
|
|
7b456c0e3f | ||
|
|
0e91eadc12 | ||
|
|
1e8c9639a0 | ||
|
|
269456cf55 |
+1
-3
@@ -47,8 +47,6 @@ packages/react-native/flow/
|
||||
|
||||
[options]
|
||||
enums=true
|
||||
experimental.pattern_matching=true
|
||||
experimental.pattern_matching.includes=<PROJECT_ROOT>/packages/react-native/src/private/components/virtualview/
|
||||
casting_syntax=both
|
||||
component_syntax=true
|
||||
|
||||
@@ -105,4 +103,4 @@ untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.274.0
|
||||
^0.273.1
|
||||
|
||||
@@ -14,8 +14,8 @@ jobs:
|
||||
with:
|
||||
repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
|
||||
days-before-stale: 180
|
||||
stale-issue-message: 'This issue is stale because it has been open for 180 days with no activity. It will be closed in 7 days unless you comment on it or remove the "Stale" label.'
|
||||
stale-pr-message: 'This PR is stale because it has been open for 180 days with no activity. It will be closed in 7 days unless you comment on it or remove the "Stale" label.'
|
||||
stale-issue-message: 'This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
||||
stale-pr-message: 'This PR is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
|
||||
close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
|
||||
exempt-issue-labels: 'Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+5130
-257
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -124,7 +124,7 @@ if (project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoole
|
||||
configurations.all {
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
substitute(project(":packages:react-native:ReactAndroid:hermes-engine"))
|
||||
.using(module("com.facebook.react:hermes-android:0.+"))
|
||||
.using(module("com.facebook.react:hermes-android:0.0.0-+"))
|
||||
.because("Users opted to use hermes from nightly")
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -58,7 +58,7 @@
|
||||
"@typescript-eslint/parser": "^7.1.1",
|
||||
"ansi-styles": "^4.2.1",
|
||||
"babel-plugin-minify-dead-code-elimination": "^0.5.2",
|
||||
"babel-plugin-syntax-hermes-parser": "0.29.0",
|
||||
"babel-plugin-syntax-hermes-parser": "0.28.1",
|
||||
"babel-plugin-transform-define": "^2.1.4",
|
||||
"babel-plugin-transform-flow-enums": "^0.0.2",
|
||||
"clang-format": "^1.8.0",
|
||||
@@ -76,11 +76,11 @@
|
||||
"eslint-plugin-react-native": "^4.0.0",
|
||||
"eslint-plugin-redundant-undefined": "^0.4.0",
|
||||
"eslint-plugin-relay": "^1.8.3",
|
||||
"flow-api-translator": "0.29.0",
|
||||
"flow-bin": "^0.274.0",
|
||||
"flow-api-translator": "0.28.1",
|
||||
"flow-bin": "^0.273.1",
|
||||
"glob": "^7.1.1",
|
||||
"hermes-eslint": "0.29.0",
|
||||
"hermes-transform": "0.29.0",
|
||||
"hermes-eslint": "0.28.1",
|
||||
"hermes-transform": "0.28.1",
|
||||
"inquirer": "^7.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-config": "^29.7.0",
|
||||
@@ -96,7 +96,7 @@
|
||||
"node-fetch": "^2.2.0",
|
||||
"nullthrows": "^1.1.1",
|
||||
"prettier": "2.8.8",
|
||||
"prettier-plugin-hermes-parser": "0.29.0",
|
||||
"prettier-plugin-hermes-parser": "0.28.1",
|
||||
"react": "19.1.0",
|
||||
"react-test-renderer": "19.1.0",
|
||||
"rimraf": "^3.0.2",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@generated SignedSource<<cf5be4596d1f07e220b710fc286d02fa>>
|
||||
Git revision: d95ac13bf0ab64a5e6c2eb18eb138587063b9c34
|
||||
@generated SignedSource<<9ada78dff12dcfc7937c8934261f47f4>>
|
||||
Git revision: 68cfd0ae84acb0ed8e47b421afd64ae3b0b5b727
|
||||
Built with --nohooks: false
|
||||
Is local checkout: false
|
||||
Remote URL: https://github.com/facebook/react-native-devtools-frontend
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -81,7 +81,6 @@ export default function createDevMiddleware({
|
||||
projectRoot,
|
||||
serverBaseUrl,
|
||||
logger,
|
||||
// $FlowFixMe[prop-missing]
|
||||
unstable_browserLauncher = DefaultBrowserLauncher,
|
||||
unstable_eventReporter,
|
||||
unstable_experiments: experimentConfig = {},
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"main": "index.js",
|
||||
"devDependencies": {
|
||||
"babel-plugin-syntax-hermes-parser": "0.29.0",
|
||||
"hermes-eslint": "0.29.0"
|
||||
"babel-plugin-syntax-hermes-parser": "0.28.1",
|
||||
"hermes-eslint": "0.28.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 22.14.0"
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"source-map-support": "0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-syntax-hermes-parser": "0.29.0",
|
||||
"hermes-eslint": "0.29.0"
|
||||
"babel-plugin-syntax-hermes-parser": "0.28.1",
|
||||
"hermes-eslint": "0.28.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 22.14.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
agp = "8.11.0"
|
||||
agp = "8.10.1"
|
||||
gson = "2.8.9"
|
||||
guava = "31.0.1-jre"
|
||||
javapoet = "1.13.0"
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
"@babel/plugin-transform-unicode-regex": "^7.24.7",
|
||||
"@babel/template": "^7.25.0",
|
||||
"@react-native/babel-plugin-codegen": "0.80.0-main",
|
||||
"babel-plugin-syntax-hermes-parser": "0.29.0",
|
||||
"babel-plugin-syntax-hermes-parser": "0.28.1",
|
||||
"babel-plugin-transform-flow-enums": "^0.0.2",
|
||||
"react-refresh": "^0.14.0"
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@react-native/babel-preset": "0.80.0-main",
|
||||
"hermes-parser": "0.29.0",
|
||||
"hermes-parser": "0.28.1",
|
||||
"nullthrows": "^1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"glob": "^7.1.1",
|
||||
"hermes-parser": "0.29.0",
|
||||
"hermes-parser": "0.28.1",
|
||||
"invariant": "^2.2.4",
|
||||
"nullthrows": "^1.1.1",
|
||||
"yargs": "^17.6.2"
|
||||
@@ -43,7 +43,7 @@
|
||||
"@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.8",
|
||||
"@babel/preset-env": "^7.25.3",
|
||||
"hermes-estree": "0.29.0",
|
||||
"hermes-estree": "0.28.1",
|
||||
"micromatch": "^4.0.4",
|
||||
"prettier": "2.8.8",
|
||||
"rimraf": "^3.0.2"
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#import <React/RCTUIManager.h>
|
||||
#import <React/RCTViewManager.h>
|
||||
|
||||
#import <string>
|
||||
|
||||
static UIColor *UIColorFromHexString(const std::string hexString)
|
||||
{
|
||||
unsigned rgbValue = 0;
|
||||
|
||||
@@ -26,7 +26,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("*.{m}", "")
|
||||
s.source_files = "*.{m}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTActionSheet"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export type EventConfig<T> = {
|
||||
platformConfig?: PlatformConfig,
|
||||
};
|
||||
|
||||
export function attachNativeEventImpl(
|
||||
export function attachNativeEvent(
|
||||
viewRef: any,
|
||||
eventName: string,
|
||||
argMapping: $ReadOnlyArray<?Mapping>,
|
||||
@@ -181,7 +181,7 @@ export class AnimatedEvent {
|
||||
'Only native driven events need to be attached.',
|
||||
);
|
||||
|
||||
this._attachedEvent = attachNativeEventImpl(
|
||||
this._attachedEvent = attachNativeEvent(
|
||||
viewRef,
|
||||
eventName,
|
||||
this._argMapping,
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
|
||||
import AnimatedImplementation from './AnimatedImplementation';
|
||||
|
||||
export type {DecayAnimationConfig} from './animations/DecayAnimation';
|
||||
export type {SpringAnimationConfig} from './animations/SpringAnimation';
|
||||
export type {TimingAnimationConfig} from './animations/TimingAnimation';
|
||||
|
||||
export {default as FlatList} from './components/AnimatedFlatList';
|
||||
export {default as Image} from './components/AnimatedImage';
|
||||
export {default as ScrollView} from './components/AnimatedScrollView';
|
||||
@@ -37,7 +33,6 @@ export type {default as AnimatedNode} from './nodes/AnimatedNode';
|
||||
export type {default as AnimatedAddition} from './nodes/AnimatedAddition';
|
||||
export type {default as AnimatedDiffClamp} from './nodes/AnimatedDiffClamp';
|
||||
export type {default as AnimatedDivision} from './nodes/AnimatedDivision';
|
||||
export type {InterpolationConfigType as InterpolationConfig} from './nodes/AnimatedInterpolation';
|
||||
export type {default as AnimatedModulo} from './nodes/AnimatedModulo';
|
||||
export type {default as AnimatedMultiplication} from './nodes/AnimatedMultiplication';
|
||||
export type {default as AnimatedSubtraction} from './nodes/AnimatedSubtraction';
|
||||
|
||||
@@ -20,7 +20,7 @@ import type {DecayAnimationConfig} from './animations/DecayAnimation';
|
||||
import type {SpringAnimationConfig} from './animations/SpringAnimation';
|
||||
import type {TimingAnimationConfig} from './animations/TimingAnimation';
|
||||
|
||||
import {AnimatedEvent, attachNativeEventImpl} from './AnimatedEvent';
|
||||
import {AnimatedEvent, attachNativeEvent} from './AnimatedEvent';
|
||||
import DecayAnimation from './animations/DecayAnimation';
|
||||
import SpringAnimation from './animations/SpringAnimation';
|
||||
import TimingAnimation from './animations/TimingAnimation';
|
||||
@@ -47,39 +47,39 @@ export type CompositeAnimation = {
|
||||
...
|
||||
};
|
||||
|
||||
const addImpl = function (
|
||||
const add = function (
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedAddition {
|
||||
return new AnimatedAddition(a, b);
|
||||
};
|
||||
|
||||
const subtractImpl = function (
|
||||
const subtract = function (
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedSubtraction {
|
||||
return new AnimatedSubtraction(a, b);
|
||||
};
|
||||
|
||||
const divideImpl = function (
|
||||
const divide = function (
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedDivision {
|
||||
return new AnimatedDivision(a, b);
|
||||
};
|
||||
|
||||
const multiplyImpl = function (
|
||||
const multiply = function (
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number,
|
||||
): AnimatedMultiplication {
|
||||
return new AnimatedMultiplication(a, b);
|
||||
};
|
||||
|
||||
const moduloImpl = function (a: AnimatedNode, modulus: number): AnimatedModulo {
|
||||
const modulo = function (a: AnimatedNode, modulus: number): AnimatedModulo {
|
||||
return new AnimatedModulo(a, modulus);
|
||||
};
|
||||
|
||||
const diffClampImpl = function (
|
||||
const diffClamp = function (
|
||||
a: AnimatedNode,
|
||||
min: number,
|
||||
max: number,
|
||||
@@ -120,7 +120,7 @@ const maybeVectorAnim = function (
|
||||
const aY = anim((value: AnimatedValueXY).y, configY);
|
||||
// We use `stopTogether: false` here because otherwise tracking will break
|
||||
// because the second animation will get stopped before it can update.
|
||||
return parallelImpl([aX, aY], {stopTogether: false});
|
||||
return parallel([aX, aY], {stopTogether: false});
|
||||
} else if (value instanceof AnimatedColor) {
|
||||
const configR = {...config};
|
||||
const configG = {...config};
|
||||
@@ -146,12 +146,12 @@ const maybeVectorAnim = function (
|
||||
const aA = anim((value: AnimatedColor).a, configA);
|
||||
// We use `stopTogether: false` here because otherwise tracking will break
|
||||
// because the second animation will get stopped before it can update.
|
||||
return parallelImpl([aR, aG, aB, aA], {stopTogether: false});
|
||||
return parallel([aR, aG, aB, aA], {stopTogether: false});
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const springImpl = function (
|
||||
const spring = function (
|
||||
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
|
||||
config: SpringAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
@@ -179,7 +179,7 @@ const springImpl = function (
|
||||
}
|
||||
};
|
||||
return (
|
||||
maybeVectorAnim(value, config, springImpl) || {
|
||||
maybeVectorAnim(value, config, spring) || {
|
||||
start: function (callback?: ?EndCallback): void {
|
||||
start(value, config, callback);
|
||||
},
|
||||
@@ -204,7 +204,7 @@ const springImpl = function (
|
||||
);
|
||||
};
|
||||
|
||||
const timingImpl = function (
|
||||
const timing = function (
|
||||
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
|
||||
config: TimingAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
@@ -233,7 +233,7 @@ const timingImpl = function (
|
||||
};
|
||||
|
||||
return (
|
||||
maybeVectorAnim(value, config, timingImpl) || {
|
||||
maybeVectorAnim(value, config, timing) || {
|
||||
start: function (callback?: ?EndCallback, isLooping?: boolean): void {
|
||||
start(value, {...config, isLooping}, callback);
|
||||
},
|
||||
@@ -258,7 +258,7 @@ const timingImpl = function (
|
||||
);
|
||||
};
|
||||
|
||||
const decayImpl = function (
|
||||
const decay = function (
|
||||
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
|
||||
config: DecayAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
@@ -275,7 +275,7 @@ const decayImpl = function (
|
||||
};
|
||||
|
||||
return (
|
||||
maybeVectorAnim(value, config, decayImpl) || {
|
||||
maybeVectorAnim(value, config, decay) || {
|
||||
start: function (callback?: ?EndCallback): void {
|
||||
start(value, config, callback);
|
||||
},
|
||||
@@ -300,7 +300,7 @@ const decayImpl = function (
|
||||
);
|
||||
};
|
||||
|
||||
const sequenceImpl = function (
|
||||
const sequence = function (
|
||||
animations: Array<CompositeAnimation>,
|
||||
): CompositeAnimation {
|
||||
let current = 0;
|
||||
@@ -363,7 +363,7 @@ type ParallelConfig = {
|
||||
stopTogether?: boolean,
|
||||
...
|
||||
};
|
||||
const parallelImpl = function (
|
||||
const parallel = function (
|
||||
animations: Array<CompositeAnimation>,
|
||||
config?: ?ParallelConfig,
|
||||
): CompositeAnimation {
|
||||
@@ -431,9 +431,9 @@ const parallelImpl = function (
|
||||
return result;
|
||||
};
|
||||
|
||||
const delayImpl = function (time: number): CompositeAnimation {
|
||||
const delay = function (time: number): CompositeAnimation {
|
||||
// Would be nice to make a specialized implementation
|
||||
return timingImpl(new AnimatedValue(0), {
|
||||
return timing(new AnimatedValue(0), {
|
||||
toValue: 0,
|
||||
delay: time,
|
||||
duration: 0,
|
||||
@@ -441,13 +441,13 @@ const delayImpl = function (time: number): CompositeAnimation {
|
||||
});
|
||||
};
|
||||
|
||||
const staggerImpl = function (
|
||||
const stagger = function (
|
||||
time: number,
|
||||
animations: Array<CompositeAnimation>,
|
||||
): CompositeAnimation {
|
||||
return parallelImpl(
|
||||
return parallel(
|
||||
animations.map((animation, i) => {
|
||||
return sequenceImpl([delayImpl(time * i), animation]);
|
||||
return sequence([delay(time * i), animation]);
|
||||
}),
|
||||
);
|
||||
};
|
||||
@@ -458,7 +458,7 @@ type LoopAnimationConfig = {
|
||||
...
|
||||
};
|
||||
|
||||
const loopImpl = function (
|
||||
const loop = function (
|
||||
animation: CompositeAnimation,
|
||||
// $FlowFixMe[prop-missing]
|
||||
{iterations = -1, resetBeforeIteration = true}: LoopAnimationConfig = {},
|
||||
@@ -514,7 +514,7 @@ const loopImpl = function (
|
||||
};
|
||||
};
|
||||
|
||||
function forkEventImpl(
|
||||
function forkEvent(
|
||||
event: ?AnimatedEvent | ?Function,
|
||||
listener: Function,
|
||||
): AnimatedEvent | Function {
|
||||
@@ -531,7 +531,7 @@ function forkEventImpl(
|
||||
}
|
||||
}
|
||||
|
||||
function unforkEventImpl(
|
||||
function unforkEvent(
|
||||
event: ?AnimatedEvent | ?Function,
|
||||
listener: Function,
|
||||
): void {
|
||||
@@ -540,7 +540,7 @@ function unforkEventImpl(
|
||||
}
|
||||
}
|
||||
|
||||
const eventImpl = function <T>(
|
||||
const event = function <T>(
|
||||
argMapping: $ReadOnlyArray<?Mapping>,
|
||||
config: EventConfig<T>,
|
||||
): any {
|
||||
@@ -606,25 +606,25 @@ export default {
|
||||
* See https://reactnative.dev/docs/animated#node
|
||||
*/
|
||||
Node: AnimatedNode,
|
||||
decay: decayImpl,
|
||||
timing: timingImpl,
|
||||
spring: springImpl,
|
||||
add: addImpl,
|
||||
subtract: subtractImpl,
|
||||
divide: divideImpl,
|
||||
multiply: multiplyImpl,
|
||||
modulo: moduloImpl,
|
||||
diffClamp: diffClampImpl,
|
||||
delay: delayImpl,
|
||||
sequence: sequenceImpl,
|
||||
parallel: parallelImpl,
|
||||
stagger: staggerImpl,
|
||||
loop: loopImpl,
|
||||
event: eventImpl,
|
||||
decay,
|
||||
timing,
|
||||
spring,
|
||||
add,
|
||||
subtract,
|
||||
divide,
|
||||
multiply,
|
||||
modulo,
|
||||
diffClamp,
|
||||
delay,
|
||||
sequence,
|
||||
parallel,
|
||||
stagger,
|
||||
loop,
|
||||
event,
|
||||
createAnimatedComponent,
|
||||
attachNativeEvent: attachNativeEventImpl,
|
||||
forkEvent: forkEventImpl,
|
||||
unforkEvent: unforkEventImpl,
|
||||
attachNativeEvent,
|
||||
forkEvent,
|
||||
unforkEvent,
|
||||
|
||||
/**
|
||||
* Expose Event class, so it can be used as a type for type checkers.
|
||||
|
||||
@@ -17,7 +17,7 @@ import type {DecayAnimationConfig} from './animations/DecayAnimation';
|
||||
import type {SpringAnimationConfig} from './animations/SpringAnimation';
|
||||
import type {TimingAnimationConfig} from './animations/TimingAnimation';
|
||||
|
||||
import {AnimatedEvent, attachNativeEventImpl} from './AnimatedEvent';
|
||||
import {AnimatedEvent, attachNativeEvent} from './AnimatedEvent';
|
||||
import AnimatedImplementation from './AnimatedImplementation';
|
||||
import createAnimatedComponent from './createAnimatedComponent';
|
||||
import AnimatedColor from './nodes/AnimatedColor';
|
||||
@@ -188,7 +188,7 @@ export default {
|
||||
loop,
|
||||
event: AnimatedImplementation.event,
|
||||
createAnimatedComponent,
|
||||
attachNativeEvent: attachNativeEventImpl,
|
||||
attachNativeEvent,
|
||||
forkEvent: AnimatedImplementation.forkEvent,
|
||||
unforkEvent: AnimatedImplementation.unforkEvent,
|
||||
Event: AnimatedEvent,
|
||||
|
||||
@@ -17,7 +17,6 @@ import ensureInstance from '../../../src/private/__tests__/utilities/ensureInsta
|
||||
import * as Fantom from '@react-native/fantom';
|
||||
import {createRef} from 'react';
|
||||
import {Animated, View, useAnimatedValue} from 'react-native';
|
||||
import {allowStyleProp} from 'react-native/Libraries/Animated/NativeAnimatedAllowlist';
|
||||
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
|
||||
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
|
||||
@@ -153,7 +152,6 @@ test('animation driven by onScroll event', () => {
|
||||
|
||||
test('animated opacity', () => {
|
||||
let _opacity;
|
||||
let _opacityAnimation;
|
||||
const viewRef = createRef<HostInstance>();
|
||||
|
||||
function MyApp() {
|
||||
@@ -184,7 +182,7 @@ test('animated opacity', () => {
|
||||
expect(viewElement.getBoundingClientRect().x).toBe(0);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
_opacityAnimation = Animated.timing(_opacity, {
|
||||
Animated.timing(_opacity, {
|
||||
toValue: 0,
|
||||
duration: 30,
|
||||
useNativeDriver: true,
|
||||
@@ -196,10 +194,8 @@ test('animated opacity', () => {
|
||||
0,
|
||||
);
|
||||
|
||||
// TODO: this shouldn't be neccessary since animation should be stopped after duration
|
||||
Fantom.runTask(() => {
|
||||
_opacityAnimation?.stop();
|
||||
});
|
||||
// TODO(T223344928): this shouldn't be neccessary with cxxNativeAnimatedRemoveJsSync:true
|
||||
Fantom.runWorkLoop();
|
||||
|
||||
expect(root.getRenderedOutput({props: ['opacity']}).toJSX()).toEqual(
|
||||
<rn-view opacity="0" />,
|
||||
@@ -479,61 +475,3 @@ describe('Value.extractOffset', () => {
|
||||
Fantom.runWorkLoop();
|
||||
});
|
||||
});
|
||||
|
||||
test('animate layout props', () => {
|
||||
const viewRef = createRef<HostInstance>();
|
||||
allowStyleProp('height');
|
||||
|
||||
let _animatedHeight;
|
||||
let _heightAnimation;
|
||||
|
||||
function MyApp() {
|
||||
const animatedHeight = useAnimatedValue(0);
|
||||
_animatedHeight = animatedHeight;
|
||||
return (
|
||||
<Animated.View
|
||||
ref={viewRef}
|
||||
style={[
|
||||
{
|
||||
width: 100,
|
||||
height: animatedHeight,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<MyApp />);
|
||||
});
|
||||
|
||||
const viewElement = ensureInstance(viewRef.current, ReactNativeElement);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
_heightAnimation = Animated.timing(_animatedHeight, {
|
||||
toValue: 100,
|
||||
duration: 10,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
});
|
||||
|
||||
Fantom.unstable_produceFramesForDuration(10);
|
||||
|
||||
// TODO: this shouldn't be neccessary since animation should be stopped after duration
|
||||
Fantom.runTask(() => {
|
||||
_heightAnimation?.stop();
|
||||
});
|
||||
|
||||
// $FlowFixMe[incompatible-use]
|
||||
expect(Fantom.unstable_getDirectManipulationProps(viewElement).height).toBe(
|
||||
100,
|
||||
);
|
||||
|
||||
expect(Fantom.unstable_getFabricUpdateProps(viewElement).height).toBe(100);
|
||||
|
||||
expect(root.getRenderedOutput({props: ['height']}).toJSX()).toEqual(
|
||||
<rn-view height="100.000000" />,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -15,9 +15,7 @@ import type {
|
||||
} from '../createAnimatedComponent';
|
||||
|
||||
import RefreshControl from '../../Components/RefreshControl/RefreshControl';
|
||||
import ScrollView, {
|
||||
type ScrollViewProps,
|
||||
} from '../../Components/ScrollView/ScrollView';
|
||||
import ScrollView from '../../Components/ScrollView/ScrollView';
|
||||
import flattenStyle from '../../StyleSheet/flattenStyle';
|
||||
import splitLayoutProps from '../../StyleSheet/splitLayoutProps';
|
||||
import StyleSheet from '../../StyleSheet/StyleSheet';
|
||||
@@ -28,20 +26,21 @@ import useAnimatedProps from '../useAnimatedProps';
|
||||
import * as React from 'react';
|
||||
import {cloneElement, useMemo} from 'react';
|
||||
|
||||
type AnimatedScrollViewProps = React.ElementConfig<typeof ScrollView>;
|
||||
type AnimatedScrollViewInstance = React.ElementRef<typeof ScrollView>;
|
||||
|
||||
/**
|
||||
* @see https://github.com/facebook/react-native/commit/b8c8562
|
||||
*/
|
||||
const AnimatedScrollView: AnimatedComponentType<
|
||||
ScrollViewProps,
|
||||
AnimatedScrollViewProps,
|
||||
AnimatedScrollViewInstance,
|
||||
> = function AnimatedScrollViewWithOrWithoutInvertedRefreshControl({
|
||||
ref: forwardedRef,
|
||||
...props
|
||||
}: {
|
||||
ref?: React.RefSetter<AnimatedScrollViewInstance>,
|
||||
...AnimatedProps<ScrollViewProps>,
|
||||
...AnimatedProps<AnimatedScrollViewProps>,
|
||||
}) {
|
||||
// (Android only) When a ScrollView has a RefreshControl and
|
||||
// any `style` property set with an Animated.Value, the CSS
|
||||
@@ -112,7 +111,7 @@ const AnimatedScrollViewWithInvertedRefreshControl =
|
||||
|
||||
// Handle animated props on `NativeDirectionalScrollView`.
|
||||
const [scrollViewAnimatedProps, scrollViewRef] = useAnimatedProps<
|
||||
ScrollViewProps,
|
||||
AnimatedScrollViewProps,
|
||||
AnimatedScrollViewInstance,
|
||||
>(intermediatePropsForScrollView);
|
||||
const ref = useMergeRefs<AnimatedScrollViewInstance>(
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
|
||||
import type {AnimatedComponentType} from '../createAnimatedComponent';
|
||||
|
||||
import Text, {type TextProps} from '../../Text/Text';
|
||||
import Text from '../../Text/Text';
|
||||
import createAnimatedComponent from '../createAnimatedComponent';
|
||||
import * as React from 'react';
|
||||
|
||||
export default (createAnimatedComponent(
|
||||
(Text: $FlowFixMe),
|
||||
): AnimatedComponentType<TextProps, React.ElementRef<typeof Text>>);
|
||||
): AnimatedComponentType<
|
||||
React.ElementConfig<typeof Text>,
|
||||
React.ElementRef<typeof Text>,
|
||||
>);
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {ViewProps} from '../../Components/View/ViewPropTypes';
|
||||
import type {AnimatedComponentType} from '../createAnimatedComponent';
|
||||
|
||||
import View from '../../Components/View/View';
|
||||
@@ -16,6 +15,6 @@ import createAnimatedComponent from '../createAnimatedComponent';
|
||||
import * as React from 'react';
|
||||
|
||||
export default (createAnimatedComponent(View): AnimatedComponentType<
|
||||
ViewProps,
|
||||
React.ElementConfig<typeof View>,
|
||||
React.ElementRef<typeof View>,
|
||||
>);
|
||||
|
||||
@@ -21,7 +21,7 @@ import type AnimatedValue from './nodes/AnimatedValue';
|
||||
|
||||
import createAnimatedPropsHook from '../../src/private/animated/createAnimatedPropsHook';
|
||||
import composeStyles from '../../src/private/styles/composeStyles';
|
||||
import {type ViewProps} from '../Components/View/ViewPropTypes';
|
||||
import View from '../Components/View/View';
|
||||
import useMergeRefs from '../Utilities/useMergeRefs';
|
||||
import * as React from 'react';
|
||||
import {useMemo} from 'react';
|
||||
@@ -60,7 +60,9 @@ type NonAnimatedProps =
|
||||
| 'disabled'
|
||||
| 'accessibilityLabel';
|
||||
type PassThroughProps = $ReadOnly<{
|
||||
passthroughAnimatedPropExplicitValues?: ViewProps | null,
|
||||
passthroughAnimatedPropExplicitValues?: React.ElementConfig<
|
||||
typeof View,
|
||||
> | null,
|
||||
}>;
|
||||
|
||||
export type AnimatedProps<Props: {...}> = {
|
||||
|
||||
@@ -42,7 +42,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("**/*.{c,h,m,mm,S,cpp}", "**/*.h")
|
||||
s.source_files = "**/*.{c,h,m,mm,S,cpp}"
|
||||
|
||||
# This guard prevent to install the dependencies when we run `pod install` in the old architecture.
|
||||
s.compiler_flags = other_cflags
|
||||
|
||||
@@ -30,7 +30,7 @@ Pod::Spec.new do |s|
|
||||
s.platforms = min_supported_versions
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("*.{h,m,mm}", "**/*.h")
|
||||
s.source_files = "*.{h,m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTBlob"
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
+4
-6
@@ -281,12 +281,10 @@ export type ButtonProps = $ReadOnly<{
|
||||
```
|
||||
*/
|
||||
|
||||
const NativeTouchable:
|
||||
| typeof TouchableNativeFeedback
|
||||
| typeof TouchableOpacity =
|
||||
const Touchable: typeof TouchableNativeFeedback | typeof TouchableOpacity =
|
||||
Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity;
|
||||
|
||||
type ButtonRef = React.ElementRef<typeof NativeTouchable>;
|
||||
type ButtonRef = React.ElementRef<typeof Touchable>;
|
||||
|
||||
const Button: component(
|
||||
ref?: React.RefSetter<ButtonRef>,
|
||||
@@ -364,7 +362,7 @@ const Button: component(
|
||||
: importantForAccessibility;
|
||||
|
||||
return (
|
||||
<NativeTouchable
|
||||
<Touchable
|
||||
accessible={accessible}
|
||||
accessibilityActions={accessibilityActions}
|
||||
onAccessibilityAction={onAccessibilityAction}
|
||||
@@ -393,7 +391,7 @@ const Button: component(
|
||||
{formattedTitle}
|
||||
</Text>
|
||||
</View>
|
||||
</NativeTouchable>
|
||||
</Touchable>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
|
||||
import type {
|
||||
GestureResponderEvent,
|
||||
LayoutChangeEvent,
|
||||
@@ -27,6 +26,8 @@ import useAndroidRippleForView, {
|
||||
import * as React from 'react';
|
||||
import {memo, useMemo, useRef, useState} from 'react';
|
||||
|
||||
type ViewStyleProp = React.ElementConfig<typeof View>['style'];
|
||||
|
||||
export type {PressableAndroidRippleConfig};
|
||||
|
||||
export type PressableStateCallbackType = $ReadOnly<{
|
||||
|
||||
@@ -24,7 +24,7 @@ import * as React from 'react';
|
||||
* sensor housing area on iPhone X).
|
||||
* @deprecated Use `react-native-safe-area-context` instead. This component will be removed in a future release.
|
||||
*/
|
||||
const SafeAreaView: component(
|
||||
const exported: component(
|
||||
ref?: React.RefSetter<React.ElementRef<typeof View>>,
|
||||
...props: ViewProps
|
||||
) = Platform.select({
|
||||
@@ -32,4 +32,4 @@ const SafeAreaView: component(
|
||||
default: View,
|
||||
});
|
||||
|
||||
export default SafeAreaView;
|
||||
export default exported;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
import type * as React from 'react';
|
||||
import {Constructor} from '../../../types/private/Utilities';
|
||||
import {Insets} from '../../../types/public/Insets';
|
||||
import {HostInstance} from '../../../types/public/ReactNativeTypes';
|
||||
import {ColorValue, StyleProp} from '../../StyleSheet/StyleSheet';
|
||||
import {ViewStyle} from '../../StyleSheet/StyleSheetTypes';
|
||||
import {
|
||||
@@ -879,12 +878,6 @@ export class ScrollView extends ScrollViewBase {
|
||||
// Undocumented
|
||||
getInnerViewNode(): any;
|
||||
|
||||
/**
|
||||
* Returns a reference to the underlying native scroll view, or null if the
|
||||
* native instance is not mounted.
|
||||
*/
|
||||
getNativeScrollRef: () => HostInstance | null;
|
||||
|
||||
/**
|
||||
* @deprecated Use scrollTo instead
|
||||
*/
|
||||
|
||||
@@ -1480,7 +1480,6 @@ class ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
|
||||
// then the second tap goes to the actual interior view)
|
||||
const {keyboardShouldPersistTaps} = this.props;
|
||||
const keyboardNeverPersistTaps =
|
||||
// $FlowFixMe[sketchy-null-bool]
|
||||
!keyboardShouldPersistTaps || keyboardShouldPersistTaps === 'never';
|
||||
|
||||
if (typeof e.target === 'number') {
|
||||
@@ -1563,7 +1562,6 @@ class ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
|
||||
|
||||
const {keyboardShouldPersistTaps} = this.props;
|
||||
const keyboardNeverPersistsTaps =
|
||||
// $FlowFixMe[sketchy-null-bool]
|
||||
!keyboardShouldPersistTaps || keyboardShouldPersistTaps === 'never';
|
||||
|
||||
// Dismiss the keyboard now if we didn't become responder in capture phase
|
||||
|
||||
@@ -32,7 +32,7 @@ export type {EventSubscription, EmitterSubscription};
|
||||
export type NativeEventSubscription = EventSubscription;
|
||||
|
||||
// $FlowFixMe[unclear-type] unclear type of events
|
||||
type UnsafeNativeEventObject = Object;
|
||||
type UnsafeObject = Object;
|
||||
|
||||
/**
|
||||
* `NativeEventEmitter` is intended for use by Native Modules to emit events to
|
||||
@@ -46,8 +46,8 @@ type UnsafeNativeEventObject = Object;
|
||||
*/
|
||||
export default class NativeEventEmitter<
|
||||
TEventToArgsMap: $ReadOnly<
|
||||
Record<string, $ReadOnlyArray<UnsafeNativeEventObject>>,
|
||||
> = $ReadOnly<Record<string, $ReadOnlyArray<UnsafeNativeEventObject>>>,
|
||||
Record<string, $ReadOnlyArray<UnsafeObject>>,
|
||||
> = $ReadOnly<Record<string, $ReadOnlyArray<UnsafeObject>>>,
|
||||
> implements IEventEmitter<TEventToArgsMap>
|
||||
{
|
||||
_nativeModule: ?NativeModule;
|
||||
|
||||
@@ -25,7 +25,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("**/*.{c,h,m,mm,cpp}", "**/*.h")
|
||||
s.source_files = "**/*.{c,h,m,mm,cpp}"
|
||||
s.header_dir = "FBLazyVector"
|
||||
|
||||
end
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
#import <React/RCTImageLoaderLoggable.h>
|
||||
#import <React/RCTImageLoaderProtocol.h>
|
||||
#import <React/RCTImageURLLoader.h>
|
||||
|
||||
// TODO (T61325135): Remove C++ checks
|
||||
#ifdef __cplusplus
|
||||
#import <string>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
struct ImageURLLoaderAttribution {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#import <React/RCTImageUtils.h>
|
||||
|
||||
#import <cmath>
|
||||
#import <tgmath.h>
|
||||
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
|
||||
@@ -32,7 +32,7 @@ Pod::Spec.new do |s|
|
||||
s.platforms = min_supported_versions
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("*.{m,mm}", "**/*.h")
|
||||
s.source_files = "*.{m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTImage"
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
@@ -229,8 +229,7 @@ function _processUpdate() {
|
||||
*/
|
||||
const InteractionManager = (
|
||||
ReactNativeFeatureFlags.disableInteractionManager()
|
||||
? // $FlowFixMe[incompatible-variance]
|
||||
require('./InteractionManagerStub').default
|
||||
? require('./InteractionManagerStub').default
|
||||
: InteractionManagerImpl
|
||||
) as typeof InteractionManagerImpl;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ type OnAnimationDidFailCallback = () => void;
|
||||
let isLayoutAnimationEnabled: boolean =
|
||||
ReactNativeFeatureFlags.isLayoutAnimationEnabled();
|
||||
|
||||
function setLayoutAnimationEnabled(value: boolean) {
|
||||
function setEnabled(value: boolean) {
|
||||
isLayoutAnimationEnabled = isLayoutAnimationEnabled;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ function configureNext(
|
||||
}
|
||||
}
|
||||
|
||||
function createLayoutAnimation(
|
||||
function create(
|
||||
duration: number,
|
||||
type?: LayoutAnimationType,
|
||||
property?: LayoutAnimationProperty,
|
||||
@@ -129,16 +129,12 @@ function createLayoutAnimation(
|
||||
}
|
||||
|
||||
const Presets = {
|
||||
easeInEaseOut: (createLayoutAnimation(
|
||||
easeInEaseOut: (create(
|
||||
300,
|
||||
'easeInEaseOut',
|
||||
'opacity',
|
||||
): LayoutAnimationConfig),
|
||||
linear: (createLayoutAnimation(
|
||||
500,
|
||||
'linear',
|
||||
'opacity',
|
||||
): LayoutAnimationConfig),
|
||||
linear: (create(500, 'linear', 'opacity'): LayoutAnimationConfig),
|
||||
spring: ({
|
||||
duration: 700,
|
||||
create: {
|
||||
@@ -184,7 +180,7 @@ const LayoutAnimation = {
|
||||
/**
|
||||
* Helper for creating a config for `configureNext`.
|
||||
*/
|
||||
create: createLayoutAnimation,
|
||||
create,
|
||||
Types: Object.freeze({
|
||||
spring: 'spring',
|
||||
linear: 'linear',
|
||||
@@ -212,7 +208,7 @@ const LayoutAnimation = {
|
||||
spring: (configureNext.bind(null, Presets.spring): (
|
||||
onAnimationDidEnd?: OnAnimationDidEndCallback,
|
||||
) => void),
|
||||
setEnabled: setLayoutAnimationEnabled,
|
||||
setEnabled,
|
||||
};
|
||||
|
||||
export default LayoutAnimation;
|
||||
|
||||
@@ -31,7 +31,7 @@ Pod::Spec.new do |s|
|
||||
s.platforms = min_supported_versions
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("*.{m,mm}", "")
|
||||
s.source_files = "*.{m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTLinking"
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
+2
-1
@@ -15,7 +15,6 @@ import type {
|
||||
ListRenderItemInfo,
|
||||
ViewabilityConfigCallbackPair,
|
||||
ViewToken,
|
||||
VirtualizedListProps,
|
||||
} from '@react-native/virtualized-lists';
|
||||
|
||||
import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
|
||||
@@ -182,6 +181,8 @@ type FlatListBaseProps<ItemT> = {
|
||||
...OptionalProps<ItemT>,
|
||||
};
|
||||
|
||||
type VirtualizedListProps = React.ElementConfig<typeof VirtualizedList>;
|
||||
|
||||
export type FlatListProps<ItemT> = {
|
||||
...Omit<
|
||||
VirtualizedListProps,
|
||||
|
||||
@@ -30,7 +30,7 @@ Pod::Spec.new do |s|
|
||||
s.platforms = min_supported_versions
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("**/*.{h,m,mm}", "**/*.h")
|
||||
s.source_files = "**/*.{h,m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTAnimation"
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
@@ -30,7 +30,7 @@ Pod::Spec.new do |s|
|
||||
s.platforms = min_supported_versions
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("*.{m,mm}", "")
|
||||
s.source_files = "*.{m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTNetwork"
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
@@ -130,7 +130,7 @@ const PERMISSIONS = Object.freeze({
|
||||
*
|
||||
* See https://reactnative.dev/docs/permissionsandroid
|
||||
*/
|
||||
class PermissionsAndroidImpl {
|
||||
class PermissionsAndroid {
|
||||
PERMISSIONS: PermissionsType = PERMISSIONS;
|
||||
RESULTS: $ReadOnly<{
|
||||
DENIED: 'denied',
|
||||
@@ -297,6 +297,5 @@ class PermissionsAndroidImpl {
|
||||
}
|
||||
}
|
||||
|
||||
const PermissionsAndroidInstance: PermissionsAndroidImpl =
|
||||
new PermissionsAndroidImpl();
|
||||
const PermissionsAndroidInstance: PermissionsAndroid = new PermissionsAndroid();
|
||||
export default PermissionsAndroidInstance;
|
||||
|
||||
@@ -13,8 +13,8 @@ import type {RootTag} from '../Types/RootTagTypes';
|
||||
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
|
||||
import type {DisplayModeType} from './DisplayMode';
|
||||
|
||||
type HeadlessTask = (taskData: any) => Promise<void>;
|
||||
export type TaskProvider = () => HeadlessTask;
|
||||
type Task = (taskData: any) => Promise<void>;
|
||||
export type TaskProvider = () => Task;
|
||||
|
||||
export type ComponentProvider = () => React.ComponentType<any>;
|
||||
export type ComponentProviderInstrumentationHook = (
|
||||
|
||||
@@ -25,6 +25,6 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("**/*.{c,h,m,mm,cpp}", "**/*.h")
|
||||
s.source_files = "**/*.{c,h,m,mm,cpp}"
|
||||
s.header_dir = "RCTRequired"
|
||||
end
|
||||
|
||||
@@ -31,7 +31,7 @@ Pod::Spec.new do |s|
|
||||
s.platforms = min_supported_versions
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("*.{m,mm}", "**/*.h")
|
||||
s.source_files = "*.{m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTSettings"
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
@@ -26,7 +26,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("**/*.{h,m,mm}", "**/*.h")
|
||||
s.source_files = "**/*.{h,m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTText"
|
||||
s.framework = ["MobileCoreServices"]
|
||||
|
||||
@@ -25,7 +25,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("**/*.{c,h,m,mm,cpp}", "**/*.h")
|
||||
s.source_files = "**/*.{c,h,m,mm,cpp}"
|
||||
s.header_dir = "RCTTypeSafety"
|
||||
s.pod_target_xcconfig = {
|
||||
"USE_HEADERMAP" => "YES",
|
||||
|
||||
@@ -9,4 +9,6 @@
|
||||
*/
|
||||
|
||||
export * from '../../src/private/specs_DEPRECATED/modules/NativeDeviceInfo';
|
||||
export {default} from '../../src/private/specs_DEPRECATED/modules/NativeDeviceInfo';
|
||||
import NativeDeviceInfo from '../../src/private/specs_DEPRECATED/modules/NativeDeviceInfo';
|
||||
|
||||
export default NativeDeviceInfo;
|
||||
|
||||
@@ -23,7 +23,7 @@ type Options = $ReadOnly<{
|
||||
excludedPlatforms?: $ReadOnlyArray<'iOS' | 'android'>,
|
||||
}>;
|
||||
|
||||
export type NativeComponentType<T: {...}> = HostComponent<T>;
|
||||
export type NativeComponentType<T> = HostComponent<T>;
|
||||
|
||||
// If this function runs then that means the view configs were not
|
||||
// generated at build time using `GenerateViewConfigJs.js`. Thus
|
||||
|
||||
@@ -31,7 +31,7 @@ Pod::Spec.new do |s|
|
||||
s.platforms = min_supported_versions
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("*.{m,mm}", "**/*.h")
|
||||
s.source_files = "*.{m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "RCTVibration"
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
@@ -136,7 +136,7 @@ export type EventConfig<T> = {
|
||||
useNativeDriver: boolean,
|
||||
platformConfig?: PlatformConfig,
|
||||
};
|
||||
declare export function attachNativeEventImpl(
|
||||
declare export function attachNativeEvent(
|
||||
viewRef: any,
|
||||
eventName: string,
|
||||
argMapping: $ReadOnlyArray<?Mapping>,
|
||||
@@ -166,10 +166,7 @@ declare export default {
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Animated/AnimatedExports.js.flow 1`] = `
|
||||
"export type { DecayAnimationConfig } from \\"./animations/DecayAnimation\\";
|
||||
export type { SpringAnimationConfig } from \\"./animations/SpringAnimation\\";
|
||||
export type { TimingAnimationConfig } from \\"./animations/TimingAnimation\\";
|
||||
export { default as FlatList } from \\"./components/AnimatedFlatList\\";
|
||||
"export { default as FlatList } from \\"./components/AnimatedFlatList\\";
|
||||
export { default as Image } from \\"./components/AnimatedImage\\";
|
||||
export { default as ScrollView } from \\"./components/AnimatedScrollView\\";
|
||||
export { default as SectionList } from \\"./components/AnimatedSectionList\\";
|
||||
@@ -188,7 +185,6 @@ export type { default as AnimatedNode } from \\"./nodes/AnimatedNode\\";
|
||||
export type { default as AnimatedAddition } from \\"./nodes/AnimatedAddition\\";
|
||||
export type { default as AnimatedDiffClamp } from \\"./nodes/AnimatedDiffClamp\\";
|
||||
export type { default as AnimatedDivision } from \\"./nodes/AnimatedDivision\\";
|
||||
export type { InterpolationConfigType as InterpolationConfig } from \\"./nodes/AnimatedInterpolation\\";
|
||||
export type { default as AnimatedModulo } from \\"./nodes/AnimatedModulo\\";
|
||||
export type { default as AnimatedMultiplication } from \\"./nodes/AnimatedMultiplication\\";
|
||||
export type { default as AnimatedSubtraction } from \\"./nodes/AnimatedSubtraction\\";
|
||||
@@ -226,53 +222,53 @@ exports[`public API should not change unintentionally Libraries/Animated/Animate
|
||||
reset: () => void,
|
||||
...
|
||||
};
|
||||
declare const addImpl: (
|
||||
declare const add: (
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number
|
||||
) => AnimatedAddition;
|
||||
declare const subtractImpl: (
|
||||
declare const subtract: (
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number
|
||||
) => AnimatedSubtraction;
|
||||
declare const divideImpl: (
|
||||
declare const divide: (
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number
|
||||
) => AnimatedDivision;
|
||||
declare const multiplyImpl: (
|
||||
declare const multiply: (
|
||||
a: AnimatedNode | number,
|
||||
b: AnimatedNode | number
|
||||
) => AnimatedMultiplication;
|
||||
declare const moduloImpl: (a: AnimatedNode, modulus: number) => AnimatedModulo;
|
||||
declare const diffClampImpl: (
|
||||
declare const modulo: (a: AnimatedNode, modulus: number) => AnimatedModulo;
|
||||
declare const diffClamp: (
|
||||
a: AnimatedNode,
|
||||
min: number,
|
||||
max: number
|
||||
) => AnimatedDiffClamp;
|
||||
declare const springImpl: (
|
||||
declare const spring: (
|
||||
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
|
||||
config: SpringAnimationConfig
|
||||
) => CompositeAnimation;
|
||||
declare const timingImpl: (
|
||||
declare const timing: (
|
||||
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
|
||||
config: TimingAnimationConfig
|
||||
) => CompositeAnimation;
|
||||
declare const decayImpl: (
|
||||
declare const decay: (
|
||||
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
|
||||
config: DecayAnimationConfig
|
||||
) => CompositeAnimation;
|
||||
declare const sequenceImpl: (
|
||||
declare const sequence: (
|
||||
animations: Array<CompositeAnimation>
|
||||
) => CompositeAnimation;
|
||||
type ParallelConfig = {
|
||||
stopTogether?: boolean,
|
||||
...
|
||||
};
|
||||
declare const parallelImpl: (
|
||||
declare const parallel: (
|
||||
animations: Array<CompositeAnimation>,
|
||||
config?: ?ParallelConfig
|
||||
) => CompositeAnimation;
|
||||
declare const delayImpl: (time: number) => CompositeAnimation;
|
||||
declare const staggerImpl: (
|
||||
declare const delay: (time: number) => CompositeAnimation;
|
||||
declare const stagger: (
|
||||
time: number,
|
||||
animations: Array<CompositeAnimation>
|
||||
) => CompositeAnimation;
|
||||
@@ -281,19 +277,19 @@ type LoopAnimationConfig = {
|
||||
resetBeforeIteration?: boolean,
|
||||
...
|
||||
};
|
||||
declare const loopImpl: (
|
||||
declare const loop: (
|
||||
animation: CompositeAnimation,
|
||||
$$PARAM_1$$?: LoopAnimationConfig
|
||||
) => CompositeAnimation;
|
||||
declare function forkEventImpl(
|
||||
declare function forkEvent(
|
||||
event: ?AnimatedEvent | ?Function,
|
||||
listener: Function
|
||||
): AnimatedEvent | Function;
|
||||
declare function unforkEventImpl(
|
||||
declare function unforkEvent(
|
||||
event: ?AnimatedEvent | ?Function,
|
||||
listener: Function
|
||||
): void;
|
||||
declare const eventImpl: <T>(
|
||||
declare const event: <T>(
|
||||
argMapping: $ReadOnlyArray<?Mapping>,
|
||||
config: EventConfig<T>
|
||||
) => any;
|
||||
@@ -313,25 +309,25 @@ declare export default {
|
||||
Color: typeof AnimatedColor,
|
||||
Interpolation: typeof AnimatedInterpolation,
|
||||
Node: typeof AnimatedNode,
|
||||
decay: typeof decayImpl,
|
||||
timing: typeof timingImpl,
|
||||
spring: typeof springImpl,
|
||||
add: typeof addImpl,
|
||||
subtract: typeof subtractImpl,
|
||||
divide: typeof divideImpl,
|
||||
multiply: typeof multiplyImpl,
|
||||
modulo: typeof moduloImpl,
|
||||
diffClamp: typeof diffClampImpl,
|
||||
delay: typeof delayImpl,
|
||||
sequence: typeof sequenceImpl,
|
||||
parallel: typeof parallelImpl,
|
||||
stagger: typeof staggerImpl,
|
||||
loop: typeof loopImpl,
|
||||
event: typeof eventImpl,
|
||||
decay: typeof decay,
|
||||
timing: typeof timing,
|
||||
spring: typeof spring,
|
||||
add: typeof add,
|
||||
subtract: typeof subtract,
|
||||
divide: typeof divide,
|
||||
multiply: typeof multiply,
|
||||
modulo: typeof modulo,
|
||||
diffClamp: typeof diffClamp,
|
||||
delay: typeof delay,
|
||||
sequence: typeof sequence,
|
||||
parallel: typeof parallel,
|
||||
stagger: typeof stagger,
|
||||
loop: typeof loop,
|
||||
event: typeof event,
|
||||
createAnimatedComponent: typeof createAnimatedComponent,
|
||||
attachNativeEvent: typeof attachNativeEventImpl,
|
||||
forkEvent: typeof forkEventImpl,
|
||||
unforkEvent: typeof unforkEventImpl,
|
||||
attachNativeEvent: typeof attachNativeEvent,
|
||||
forkEvent: typeof forkEvent,
|
||||
unforkEvent: typeof unforkEvent,
|
||||
Event: typeof AnimatedEvent,
|
||||
};
|
||||
"
|
||||
@@ -632,9 +628,10 @@ exports[`public API should not change unintentionally Libraries/Animated/compone
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Animated/components/AnimatedScrollView.js 1`] = `
|
||||
"type AnimatedScrollViewInstance = React.ElementRef<typeof ScrollView>;
|
||||
"type AnimatedScrollViewProps = React.ElementConfig<typeof ScrollView>;
|
||||
type AnimatedScrollViewInstance = React.ElementRef<typeof ScrollView>;
|
||||
declare const AnimatedScrollView: AnimatedComponentType<
|
||||
ScrollViewProps,
|
||||
AnimatedScrollViewProps,
|
||||
AnimatedScrollViewInstance,
|
||||
>;
|
||||
declare export default typeof AnimatedScrollView;
|
||||
@@ -651,7 +648,7 @@ exports[`public API should not change unintentionally Libraries/Animated/compone
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Animated/components/AnimatedText.js 1`] = `
|
||||
"declare export default AnimatedComponentType<
|
||||
TextProps,
|
||||
React.ElementConfig<typeof Text>,
|
||||
React.ElementRef<typeof Text>,
|
||||
>;
|
||||
"
|
||||
@@ -659,7 +656,7 @@ exports[`public API should not change unintentionally Libraries/Animated/compone
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Animated/components/AnimatedView.js 1`] = `
|
||||
"declare export default AnimatedComponentType<
|
||||
ViewProps,
|
||||
React.ElementConfig<typeof View>,
|
||||
React.ElementRef<typeof View>,
|
||||
>;
|
||||
"
|
||||
@@ -698,7 +695,9 @@ type NonAnimatedProps =
|
||||
| \\"disabled\\"
|
||||
| \\"accessibilityLabel\\";
|
||||
type PassThroughProps = $ReadOnly<{
|
||||
passthroughAnimatedPropExplicitValues?: ViewProps | null,
|
||||
passthroughAnimatedPropExplicitValues?: React.ElementConfig<
|
||||
typeof View,
|
||||
> | null,
|
||||
}>;
|
||||
export type AnimatedProps<Props: { ... }> = {
|
||||
[K in keyof Props]: K extends NonAnimatedProps
|
||||
@@ -1539,10 +1538,10 @@ exports[`public API should not change unintentionally Libraries/Components/Butto
|
||||
accessibilityHint?: ?string,
|
||||
accessibilityLanguage?: ?Stringish,
|
||||
}>;
|
||||
declare const NativeTouchable:
|
||||
declare const Touchable:
|
||||
| typeof TouchableNativeFeedback
|
||||
| typeof TouchableOpacity;
|
||||
type ButtonRef = React.ElementRef<typeof NativeTouchable>;
|
||||
type ButtonRef = React.ElementRef<typeof Touchable>;
|
||||
declare const Button: component(
|
||||
ref?: React.RefSetter<ButtonRef>,
|
||||
...props: ButtonProps
|
||||
@@ -1758,7 +1757,8 @@ declare export default typeof LayoutConformanceNativeComponent;
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Components/Pressable/Pressable.js 1`] = `
|
||||
"export type { PressableAndroidRippleConfig };
|
||||
"type ViewStyleProp = React.ElementConfig<typeof View>[\\"style\\"];
|
||||
export type { PressableAndroidRippleConfig };
|
||||
export type PressableStateCallbackType = $ReadOnly<{
|
||||
pressed: boolean,
|
||||
}>;
|
||||
@@ -1932,11 +1932,11 @@ export { default } from \\"../../../src/private/specs_DEPRECATED/components/RCTS
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Components/SafeAreaView/SafeAreaView.js 1`] = `
|
||||
"declare const SafeAreaView: component(
|
||||
"declare const exported: component(
|
||||
ref?: React.RefSetter<React.ElementRef<typeof View>>,
|
||||
...props: ViewProps
|
||||
);
|
||||
declare export default typeof SafeAreaView;
|
||||
declare export default typeof exported;
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -4179,11 +4179,11 @@ exports[`public API should not change unintentionally Libraries/EventEmitter/Nat
|
||||
type EmitterSubscription = EventSubscription;
|
||||
export type { EventSubscription, EmitterSubscription };
|
||||
export type NativeEventSubscription = EventSubscription;
|
||||
type UnsafeNativeEventObject = Object;
|
||||
type UnsafeObject = Object;
|
||||
declare export default class NativeEventEmitter<
|
||||
TEventToArgsMap: $ReadOnly<
|
||||
Record<string, $ReadOnlyArray<UnsafeNativeEventObject>>,
|
||||
> = $ReadOnly<Record<string, $ReadOnlyArray<UnsafeNativeEventObject>>>,
|
||||
Record<string, $ReadOnlyArray<UnsafeObject>>,
|
||||
> = $ReadOnly<Record<string, $ReadOnlyArray<UnsafeObject>>>,
|
||||
> implements IEventEmitter<TEventToArgsMap>
|
||||
{
|
||||
constructor(nativeModule?: ?NativeModule): void;
|
||||
@@ -4859,13 +4859,13 @@ export type LayoutAnimationProperties = $ReadOnly<{
|
||||
}>;
|
||||
type OnAnimationDidEndCallback = () => void;
|
||||
type OnAnimationDidFailCallback = () => void;
|
||||
declare function setLayoutAnimationEnabled(value: boolean): void;
|
||||
declare function setEnabled(value: boolean): void;
|
||||
declare function configureNext(
|
||||
config: LayoutAnimationConfig,
|
||||
onAnimationDidEnd?: OnAnimationDidEndCallback,
|
||||
onAnimationDidFail?: OnAnimationDidFailCallback
|
||||
): void;
|
||||
declare function createLayoutAnimation(
|
||||
declare function create(
|
||||
duration: number,
|
||||
type?: LayoutAnimationType,
|
||||
property?: LayoutAnimationProperty
|
||||
@@ -4877,7 +4877,7 @@ declare const Presets: {
|
||||
};
|
||||
declare const LayoutAnimation: {
|
||||
configureNext: typeof configureNext,
|
||||
create: typeof createLayoutAnimation,
|
||||
create: typeof create,
|
||||
Types: LayoutAnimationTypes,
|
||||
Properties: LayoutAnimationProperties,
|
||||
checkConfig(...args: Array<mixed>): void,
|
||||
@@ -4885,7 +4885,7 @@ declare const LayoutAnimation: {
|
||||
easeInEaseOut: (onAnimationDidEnd?: OnAnimationDidEndCallback) => void,
|
||||
linear: (onAnimationDidEnd?: OnAnimationDidEndCallback) => void,
|
||||
spring: (onAnimationDidEnd?: OnAnimationDidEndCallback) => void,
|
||||
setEnabled: typeof setLayoutAnimationEnabled,
|
||||
setEnabled: typeof setEnabled,
|
||||
};
|
||||
declare export default typeof LayoutAnimation;
|
||||
"
|
||||
@@ -4940,7 +4940,8 @@ declare export default typeof FillRateHelper;
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Lists/FlatList.js 1`] = `
|
||||
"type RequiredProps<ItemT> = {
|
||||
"declare const VirtualizedList: typeof VirtualizedLists.VirtualizedList;
|
||||
type RequiredProps<ItemT> = {
|
||||
data: ?$ReadOnly<$ArrayLike<ItemT>>,
|
||||
};
|
||||
type OptionalProps<ItemT> = {
|
||||
@@ -4970,6 +4971,7 @@ type FlatListBaseProps<ItemT> = {
|
||||
...RequiredProps<ItemT>,
|
||||
...OptionalProps<ItemT>,
|
||||
};
|
||||
type VirtualizedListProps = React.ElementConfig<typeof VirtualizedList>;
|
||||
export type FlatListProps<ItemT> = {
|
||||
...Omit<
|
||||
VirtualizedListProps,
|
||||
@@ -6145,7 +6147,7 @@ type PermissionsType = $ReadOnly<{
|
||||
}>;
|
||||
export type PermissionStatus = \\"granted\\" | \\"denied\\" | \\"never_ask_again\\";
|
||||
export type Permission = $Values<PermissionsType>;
|
||||
declare class PermissionsAndroidImpl {
|
||||
declare class PermissionsAndroid {
|
||||
PERMISSIONS: PermissionsType;
|
||||
RESULTS: $ReadOnly<{
|
||||
DENIED: \\"denied\\",
|
||||
@@ -6166,7 +6168,7 @@ declare class PermissionsAndroidImpl {
|
||||
permissions: Array<Permission>
|
||||
): Promise<{ [permission: Permission]: PermissionStatus, ... }>;
|
||||
}
|
||||
declare const PermissionsAndroidInstance: PermissionsAndroidImpl;
|
||||
declare const PermissionsAndroidInstance: PermissionsAndroid;
|
||||
declare export default typeof PermissionsAndroidInstance;
|
||||
"
|
||||
`;
|
||||
@@ -6432,8 +6434,8 @@ declare export default typeof AppContainer;
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/ReactNative/AppRegistry.flow.js 1`] = `
|
||||
"type HeadlessTask = (taskData: any) => Promise<void>;
|
||||
export type TaskProvider = () => HeadlessTask;
|
||||
"type Task = (taskData: any) => Promise<void>;
|
||||
export type TaskProvider = () => Task;
|
||||
export type ComponentProvider = () => React.ComponentType<any>;
|
||||
export type ComponentProviderInstrumentationHook = (
|
||||
component_: ComponentProvider,
|
||||
@@ -8363,7 +8365,7 @@ declare export default typeof NativeDevLoadingView;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/Utilities/NativeDeviceInfo.js 1`] = `
|
||||
"export * from \\"../../src/private/specs_DEPRECATED/modules/NativeDeviceInfo\\";
|
||||
export { default } from \\"../../src/private/specs_DEPRECATED/modules/NativeDeviceInfo\\";
|
||||
declare export default typeof NativeDeviceInfo;
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -8654,7 +8656,7 @@ exports[`public API should not change unintentionally Libraries/Utilities/codege
|
||||
paperComponentNameDeprecated?: string,
|
||||
excludedPlatforms?: $ReadOnlyArray<\\"iOS\\" | \\"android\\">,
|
||||
}>;
|
||||
export type NativeComponentType<T: { ... }> = HostComponent<T>;
|
||||
export type NativeComponentType<T> = HostComponent<T>;
|
||||
declare function codegenNativeComponent<Props: { ... }>(
|
||||
componentName: string,
|
||||
options?: Options
|
||||
@@ -8959,12 +8961,12 @@ declare export default ErrorUtils;
|
||||
`;
|
||||
|
||||
exports[`public API should not change unintentionally Libraries/vendor/emitter/EventEmitter.js 1`] = `
|
||||
"type UnsafeEventObject = Object;
|
||||
"type UnsafeObject = Object;
|
||||
export interface EventSubscription {
|
||||
remove(): void;
|
||||
}
|
||||
export interface IEventEmitter<
|
||||
TEventToArgsMap: $ReadOnly<Record<string, $ReadOnlyArray<UnsafeEventObject>>>,
|
||||
TEventToArgsMap: $ReadOnly<Record<string, $ReadOnlyArray<UnsafeObject>>>,
|
||||
> {
|
||||
addListener<TEvent: $Keys<TEventToArgsMap>>(
|
||||
eventType: TEvent,
|
||||
@@ -8980,8 +8982,8 @@ export interface IEventEmitter<
|
||||
}
|
||||
declare export default class EventEmitter<
|
||||
TEventToArgsMap: $ReadOnly<
|
||||
Record<string, $ReadOnlyArray<UnsafeEventObject>>,
|
||||
> = $ReadOnly<Record<string, $ReadOnlyArray<UnsafeEventObject>>>,
|
||||
Record<string, $ReadOnlyArray<UnsafeObject>>,
|
||||
> = $ReadOnly<Record<string, $ReadOnlyArray<UnsafeObject>>>,
|
||||
> implements IEventEmitter<TEventToArgsMap>
|
||||
{
|
||||
constructor(): void;
|
||||
@@ -9061,8 +9063,6 @@ export type {
|
||||
export { default as RefreshControl } from \\"./Libraries/Components/RefreshControl/RefreshControl\\";
|
||||
export { default as SafeAreaView } from \\"./Libraries/Components/SafeAreaView/SafeAreaView\\";
|
||||
export type {
|
||||
ScrollViewImperativeMethods,
|
||||
ScrollViewScrollToOptions,
|
||||
ScrollResponderType,
|
||||
ScrollViewProps,
|
||||
ScrollViewPropsAndroid,
|
||||
@@ -9349,11 +9349,6 @@ export type {
|
||||
PublicRootInstance,
|
||||
PublicTextInstance,
|
||||
} from \\"./Libraries/ReactPrivate/ReactNativePrivateInterface\\";
|
||||
export {
|
||||
default as unstable_VirtualView,
|
||||
VirtualViewMode,
|
||||
} from \\"./src/private/components/virtualview/VirtualView\\";
|
||||
export type { ModeChangeEvent } from \\"./src/private/components/virtualview/VirtualView\\";
|
||||
"
|
||||
`;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {TransformVisitor} from 'hermes-transform';
|
||||
|
||||
const {
|
||||
visitors: stripPrivateProperties,
|
||||
} = require('../../../../scripts/build-types/transforms/flow/stripPrivateProperties');
|
||||
} = require('../../../../scripts/build-types/transforms/stripPrivateProperties');
|
||||
const translate = require('flow-api-translator');
|
||||
const {existsSync, promises: fs} = require('fs');
|
||||
const glob = require('glob');
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
*/
|
||||
|
||||
// $FlowFixMe[unclear-type] unclear type of events
|
||||
type UnsafeEventObject = Object;
|
||||
type UnsafeObject = Object;
|
||||
|
||||
export interface EventSubscription {
|
||||
remove(): void;
|
||||
}
|
||||
|
||||
export interface IEventEmitter<
|
||||
TEventToArgsMap: $ReadOnly<Record<string, $ReadOnlyArray<UnsafeEventObject>>>,
|
||||
TEventToArgsMap: $ReadOnly<Record<string, $ReadOnlyArray<UnsafeObject>>>,
|
||||
> {
|
||||
addListener<TEvent: $Keys<TEventToArgsMap>>(
|
||||
eventType: TEvent,
|
||||
@@ -41,7 +41,7 @@ interface Registration<TArgs> {
|
||||
}
|
||||
|
||||
type Registry<
|
||||
TEventToArgsMap: $ReadOnly<Record<string, $ReadOnlyArray<UnsafeEventObject>>>,
|
||||
TEventToArgsMap: $ReadOnly<Record<string, $ReadOnlyArray<UnsafeObject>>>,
|
||||
> = {
|
||||
[K in keyof TEventToArgsMap]: Set<Registration<TEventToArgsMap[K]>>,
|
||||
};
|
||||
@@ -68,8 +68,8 @@ type Registry<
|
||||
*/
|
||||
export default class EventEmitter<
|
||||
TEventToArgsMap: $ReadOnly<
|
||||
Record<string, $ReadOnlyArray<UnsafeEventObject>>,
|
||||
> = $ReadOnly<Record<string, $ReadOnlyArray<UnsafeEventObject>>>,
|
||||
Record<string, $ReadOnlyArray<UnsafeObject>>,
|
||||
> = $ReadOnly<Record<string, $ReadOnlyArray<UnsafeObject>>>,
|
||||
> implements IEventEmitter<TEventToArgsMap>
|
||||
{
|
||||
#registry: Registry<TEventToArgsMap>;
|
||||
@@ -157,7 +157,7 @@ export default class EventEmitter<
|
||||
}
|
||||
|
||||
function allocate<
|
||||
TEventToArgsMap: $ReadOnly<Record<string, $ReadOnlyArray<UnsafeEventObject>>>,
|
||||
TEventToArgsMap: $ReadOnly<Record<string, $ReadOnlyArray<UnsafeObject>>>,
|
||||
TEvent: $Keys<TEventToArgsMap>,
|
||||
TEventArgs: TEventToArgsMap[TEvent],
|
||||
>(
|
||||
|
||||
@@ -397,7 +397,6 @@ let reactFabric = RNTarget(
|
||||
"components/textinput",
|
||||
"components/textinput/platform/ios/",
|
||||
"components/unimplementedview",
|
||||
"components/virtualview",
|
||||
"components/root/tests",
|
||||
],
|
||||
dependencies: [.reactNativeDependencies, .reactJsiExecutor, .rctTypesafety, .reactTurboModuleCore, .jsi, .logger, .reactDebug, .reactFeatureFlags, .reactUtils, .reactRuntimeScheduler, .reactCxxReact, .reactRendererDebug, .reactGraphics, .yoga],
|
||||
@@ -416,8 +415,6 @@ let reactFabricComponents = RNTarget(
|
||||
name: .reactFabricComponents,
|
||||
path: "ReactCommon/react/renderer",
|
||||
excludedPaths: [
|
||||
"components/modal/platform/android",
|
||||
"components/modal/platform/cxx",
|
||||
"components/view/platform/android",
|
||||
"components/view/platform/windows",
|
||||
"components/view/platform/macos",
|
||||
@@ -433,7 +430,7 @@ let reactFabricComponents = RNTarget(
|
||||
"conponents/rncore", // this was the old folder where RN Core Components were generated. If you ran codegen in the past, you might have some files in it that might make the build fail.
|
||||
],
|
||||
dependencies: [.reactNativeDependencies, .reactCore, .reactJsiExecutor, .reactTurboModuleCore, .jsi, .logger, .reactDebug, .reactFeatureFlags, .reactUtils, .reactRuntimeScheduler, .reactCxxReact, .yoga, .reactRendererDebug, .reactGraphics, .reactFabric, .reactTurboModuleBridging],
|
||||
sources: ["components/inputaccessory", "components/modal", "components/safeareaview", "components/text", "components/text/platform/cxx", "components/textinput", "components/textinput/platform/ios/", "components/unimplementedview", "components/virtualview", "textlayoutmanager", "textlayoutmanager/platform/ios"]
|
||||
sources: ["components/inputaccessory", "components/modal", "components/safeareaview", "components/text", "components/text/platform/cxx", "components/textinput", "components/textinput/platform/ios/", "components/unimplementedview", "textlayoutmanager", "textlayoutmanager/platform/ios"]
|
||||
)
|
||||
|
||||
/// React-FabricImage.podspec
|
||||
@@ -495,14 +492,6 @@ let reactRCTNetwork = RNTarget(
|
||||
dependencies: [.yoga, .jsi, .reactTurboModuleCore]
|
||||
)
|
||||
|
||||
/// React-RCTVibration.podspec
|
||||
let reactRCTVibration = RNTarget(
|
||||
name: .reactRCTVibration,
|
||||
path: "Libraries/Vibration",
|
||||
linkedFrameworks: ["AudioToolbox"],
|
||||
dependencies: [.yoga, .jsi, .reactTurboModuleCore]
|
||||
)
|
||||
|
||||
/// React-RCTAppDelegate.podspec
|
||||
let reactAppDelegate = RNTarget(
|
||||
name: .reactAppDelegate,
|
||||
@@ -568,7 +557,6 @@ let targets = [
|
||||
reactRCTText,
|
||||
reactRCTBlob,
|
||||
reactRCTNetwork,
|
||||
reactRCTVibration,
|
||||
reactRCTLinking,
|
||||
reactCoreModules,
|
||||
reactTurboModuleBridging,
|
||||
@@ -740,7 +728,6 @@ extension String {
|
||||
static let reactRCTText = "React-RCTText"
|
||||
static let reactRCTBlob = "React-RCTBlob"
|
||||
static let reactRCTNetwork = "React-RCTNetwork"
|
||||
static let reactRCTVibration = "React-RCTVibration"
|
||||
static let reactRCTActionSheet = "React-RCTActionSheet" // Empty target
|
||||
static let reactRCTLinking = "React-RCTLinking"
|
||||
static let reactCoreModules = "React-CoreModules"
|
||||
|
||||
@@ -4,53 +4,95 @@
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
require "json"
|
||||
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
||||
|
||||
begin
|
||||
react_native_path = File.dirname(Pod::Executable.execute_command('node', ['-p',
|
||||
'require.resolve(
|
||||
"react-native",
|
||||
{paths: [process.argv[1]]},
|
||||
)', __dir__]).strip
|
||||
)
|
||||
rescue => e
|
||||
# Fallback to the parent directory if the above command fails (e.g when building locally in OOT Platform)
|
||||
react_native_path = File.join(__dir__, "..", "..")
|
||||
end
|
||||
|
||||
# package.json
|
||||
package = JSON.parse(File.read(File.join(react_native_path, "package.json")))
|
||||
version = package['version']
|
||||
|
||||
source = ReactNativeCoreUtils.resolve_podspec_source()
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React-Core-prebuilt"
|
||||
s.version = version
|
||||
s.summary = "The core of React Native prebuilt frameworks."
|
||||
s.homepage = "https://reactnative.dev/"
|
||||
s.license = package["license"]
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.vendored_frameworks = "React.xcframework"
|
||||
|
||||
s.preserve_paths = '**/*.*'
|
||||
s.header_mappings_dir = 'React.xcframework/Headers'
|
||||
s.source_files = 'React.xcframework/Headers/**/*.{h,hpp}'
|
||||
header_search_paths = [
|
||||
"${PODS_ROOT}/Headers/Private/React-Core-prebuilt",
|
||||
"${PODS_ROOT}/Headers/Private/React-Core-prebuilt/RCTDeprecation",
|
||||
"${PODS_ROOT}/Headers/Private/React-Core-prebuilt/ReactCommon/yoga",
|
||||
"${PODS_ROOT}/Headers/Private/React-Core-prebuilt/ReactCommon",
|
||||
"${PODS_ROOT}/Headers/Private/React-Core-prebuilt/Libraries/AppDelegate",
|
||||
"${PODS_ROOT}/Headers/Private/React-Core-prebuilt/Libraries",
|
||||
|
||||
s.module_name = 'React'
|
||||
s.module_map = 'React.xcframework/Modules/module.modulemap'
|
||||
s.public_header_files = 'React.xcframework/Headers/**/*.h'
|
||||
"$(REACT_NATIVE_PATH)/React/Base",
|
||||
"$(REACT_NATIVE_PATH)/ReactCommon",
|
||||
"$(REACT_NATIVE_PATH)/Libraries",
|
||||
"$(REACT_NATIVE_PATH)/ReactApple",
|
||||
"$(REACT_NATIVE_PATH)/ReactCxxPlatform",
|
||||
"$(REACT_NATIVE_PATH)/ReactCommon/react/runtime/platform/ios",
|
||||
"${REACT_NATIVE_PATH}/ReactCommon/jsi",
|
||||
"$(REACT_NATIVE_PATH)/ReactCommon/jsiexecutor/",
|
||||
"$(REACT_NATIVE_PATH)/ReactCommon/react/nativemodule/samples/platform/ios",
|
||||
"$(REACT_NATIVE_PATH)/ReactCommon/react/nativemodule/samples",
|
||||
]
|
||||
|
||||
add_rn_third_party_dependencies(s)
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = 'React-Core-prebuilt'
|
||||
spec.version = version
|
||||
spec.summary = "Prebuilt core of React Native."
|
||||
spec.homepage = "https://reactnative.dev/"
|
||||
spec.description = 'Prebuilt React Native Core libraries and headers'
|
||||
spec.homepage = 'https://github.com/facebook/react-native'
|
||||
spec.license = package['license']
|
||||
spec.authors = 'meta'
|
||||
spec.platforms = min_supported_versions
|
||||
spec.source = source
|
||||
|
||||
spec.vendored_frameworks = "React.xcframework"
|
||||
|
||||
spec.preserve_paths = '**/*.*'
|
||||
spec.header_mappings_dir = 'React.xcframework/Headers'
|
||||
spec.source_files = 'React.xcframework/Headers/**/*.{h,hpp}'
|
||||
|
||||
spec.module_name = 'React'
|
||||
spec.module_map = 'React.xcframework/Modules/module.modulemap'
|
||||
spec.public_header_files = 'React.xcframework/Headers/**/*.h'
|
||||
|
||||
# Setup the consuming project's search paths
|
||||
spec.user_target_xcconfig = {
|
||||
"HEADER_SEARCH_PATHS" => header_search_paths,
|
||||
"SWIFT_INCLUDE_PATHS" => "${PODS_ROOT}/Headers/Private/React-Core-prebuilt",
|
||||
'DEFINES_MODULE' => 'YES',
|
||||
'CLANG_ENABLE_MODULES' => 'YES',
|
||||
}
|
||||
|
||||
spec.pod_target_xcconfig = {
|
||||
'WARNING_CFLAGS' => '-Wno-comma -Wno-shorten-64-to-32',
|
||||
"CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
|
||||
'DEFINES_MODULE' => 'YES',
|
||||
'CLANG_ENABLE_MODULES' => 'YES',
|
||||
}
|
||||
|
||||
# We need to make sure that the React.xcframework is copied correctly - in the downloaded tarball
|
||||
# the root directory is the framework, but when using it we need to have it in a subdirectory
|
||||
# called React.xcframework, so we need to move the contents of the tarball into that directory.
|
||||
# This is done in the prepare_command.
|
||||
# We need to make sure that the headers are copied to the right place - local tar.gz has a different structure
|
||||
# than the one from the maven repo
|
||||
s.prepare_command = <<~'CMD'
|
||||
spec.prepare_command = <<~'CMD'
|
||||
CURRENT_PATH=$(pwd)
|
||||
XCFRAMEWORK_PATH="${CURRENT_PATH}/React.xcframework"
|
||||
|
||||
# Check if XCFRAMEWORK_PATH is empty
|
||||
if [ -z "$XCFRAMEWORK_PATH" ]; then
|
||||
echo "ERROR: XCFRAMEWORK_PATH is empty."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "${XCFRAMEWORK_PATH}"
|
||||
find "$CURRENT_PATH" -mindepth 1 -maxdepth 1 ! -name "$(basename "$XCFRAMEWORK_PATH")" -exec mv {} "$XCFRAMEWORK_PATH" \;
|
||||
CMD
|
||||
|
||||
# If we are passing a local tarball, we don't want to switch between Debug and Release
|
||||
if !ENV["RCT_TESTONLY_RNCORE_TARBALL_PATH"]
|
||||
if !ENV["RCT_USE_LOCAL_RN_CORE"]
|
||||
script_phase = {
|
||||
:name => "[RNDeps] Replace React Native Core for the right configuration, if needed",
|
||||
:execution_position => :before_compile,
|
||||
@@ -73,7 +115,8 @@ Pod::Spec.new do |s|
|
||||
# always run the script without warning
|
||||
script_phase[:always_out_of_date] = "1"
|
||||
end
|
||||
|
||||
s.script_phase = script_phase
|
||||
|
||||
spec.script_phase = script_phase
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -66,7 +66,7 @@ Pod::Spec.new do |s|
|
||||
s.default_subspec = "Default"
|
||||
|
||||
s.subspec "Default" do |ss|
|
||||
ss.source_files = podspec_sources("React/**/*.{c,h,m,mm,S,cpp}", "React/**/*.h")
|
||||
ss.source_files = "React/**/*.{c,h,m,mm,S,cpp}"
|
||||
exclude_files = [
|
||||
"React/CoreModules/**/*",
|
||||
"React/DevSupport/**/*",
|
||||
@@ -76,24 +76,17 @@ Pod::Spec.new do |s|
|
||||
"React/Inspector/**/*",
|
||||
"React/Runtime/**/*",
|
||||
]
|
||||
|
||||
|
||||
# The default is use hermes, we don't have jsc installed
|
||||
exclude_files = exclude_files.append("React/CxxBridge/JSCExecutorFactory.{h,mm}")
|
||||
|
||||
ss.exclude_files = exclude_files
|
||||
ss.private_header_files = "React/Cxx*/*.h"
|
||||
|
||||
# Include prebuilt if we're not building from source
|
||||
if !ReactNativeCoreUtils.build_rncore_from_source()
|
||||
ss.dependency "React-Core-prebuilt", version
|
||||
end
|
||||
end
|
||||
|
||||
s.subspec "DevSupport" do |ss|
|
||||
ss.source_files = podspec_sources(["React/DevSupport/*.{h,mm,m}",
|
||||
"React/Inspector/*.{h,mm,m}"],
|
||||
["React/DevSupport/*.h",
|
||||
"React/Inspector/*.h"])
|
||||
ss.source_files = "React/DevSupport/*.{h,mm,m}",
|
||||
"React/Inspector/*.{h,mm,m}"
|
||||
|
||||
ss.dependency "React-Core/Default", version
|
||||
ss.dependency "React-Core/RCTWebSocket", version
|
||||
@@ -101,7 +94,7 @@ Pod::Spec.new do |s|
|
||||
end
|
||||
|
||||
s.subspec "RCTWebSocket" do |ss|
|
||||
ss.source_files = podspec_sources("Libraries/WebSocket/*.{h,m}", "Libraries/WebSocket/*.h")
|
||||
ss.source_files = "Libraries/WebSocket/*.{h,m}"
|
||||
ss.dependency "React-Core/Default", version
|
||||
end
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <tgmath.h>
|
||||
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@@ -32,7 +32,7 @@ Pod::Spec.new do |s|
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.source = source
|
||||
|
||||
s.source_files = podspec_sources("**/*.{c,m,mm,cpp}", "**/*.h")
|
||||
s.source_files = "**/*.{c,m,mm,cpp}"
|
||||
|
||||
s.ios.exclude_files = "PlatformStubs/**/*"
|
||||
exclude_files = ["RCTStatusBarManager.mm"]
|
||||
|
||||
+1
-1
@@ -1215,7 +1215,7 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||
result = [NSMutableString string];
|
||||
}
|
||||
if (result.length > 0) {
|
||||
[result appendString:@", "];
|
||||
[result appendString:@" "];
|
||||
}
|
||||
[result appendString:label];
|
||||
}
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTViewComponentView.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RCTVirtualViewComponentView : RCTViewComponentView
|
||||
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
-330
@@ -1,330 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTVirtualViewComponentView.h"
|
||||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTConversions.h>
|
||||
#import <React/RCTScrollViewComponentView.h>
|
||||
#import <React/RCTScrollableProtocol.h>
|
||||
#import <React/UIView+React.h>
|
||||
#import <jsi/jsi.h>
|
||||
|
||||
#import <react/featureflags/ReactNativeFeatureFlags.h>
|
||||
#import <react/renderer/components/FBReactNativeSpec/ComponentDescriptors.h>
|
||||
#import <react/renderer/components/FBReactNativeSpec/EventEmitters.h>
|
||||
#import <react/renderer/components/FBReactNativeSpec/Props.h>
|
||||
#import <react/renderer/components/virtualview/VirtualViewComponentDescriptor.h>
|
||||
#import <react/renderer/components/virtualview/VirtualViewShadowNode.h>
|
||||
|
||||
#import "RCTFabricComponentsPlugins.h"
|
||||
|
||||
using namespace facebook;
|
||||
using namespace facebook::react;
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTVirtualViewMode) {
|
||||
RCTVirtualViewModeVisible = 0,
|
||||
RCTVirtualViewModePrerender = 1,
|
||||
RCTVirtualViewModeHidden = 2,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTVirtualViewRenderState) {
|
||||
RCTVirtualViewRenderStateUnknown = 0,
|
||||
RCTVirtualViewRenderStateRendered = 1,
|
||||
RCTVirtualViewRenderStateNone = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether one CGRect overlaps with another CGRect.
|
||||
*
|
||||
* This is different from CGRectIntersectsRect because a CGRect representing
|
||||
* a line or a point is considered to overlap with another CGRect if the line
|
||||
* or point is within the rect bounds. However, two CGRects are not considered
|
||||
* to overlap if they only share a boundary.
|
||||
*/
|
||||
static BOOL CGRectOverlaps(CGRect rect1, CGRect rect2)
|
||||
{
|
||||
CGFloat minY1 = CGRectGetMinY(rect1);
|
||||
CGFloat maxY1 = CGRectGetMaxY(rect1);
|
||||
CGFloat minY2 = CGRectGetMinY(rect2);
|
||||
CGFloat maxY2 = CGRectGetMaxY(rect2);
|
||||
if (minY1 >= maxY2 || minY2 >= maxY1) {
|
||||
// No overlap on the y-axis.
|
||||
return NO;
|
||||
}
|
||||
CGFloat minX1 = CGRectGetMinX(rect1);
|
||||
CGFloat maxX1 = CGRectGetMaxX(rect1);
|
||||
CGFloat minX2 = CGRectGetMinX(rect2);
|
||||
CGFloat maxX2 = CGRectGetMaxX(rect2);
|
||||
if (minX1 >= maxX2 || minX2 >= maxX1) {
|
||||
// No overlap on the x-axis.
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@interface RCTVirtualViewComponentView () <UIScrollViewDelegate>
|
||||
@end
|
||||
|
||||
@implementation RCTVirtualViewComponentView {
|
||||
RCTScrollViewComponentView *_lastParentScrollViewComponentView;
|
||||
std::optional<enum RCTVirtualViewMode> _mode;
|
||||
enum RCTVirtualViewRenderState _renderState;
|
||||
std::optional<CGRect> _targetRect;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
_props = VirtualViewShadowNode::defaultSharedProps();
|
||||
_renderState = RCTVirtualViewRenderStateUnknown;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps
|
||||
{
|
||||
const auto &newViewProps = static_cast<const VirtualViewProps &>(*props);
|
||||
|
||||
if (!_mode.has_value()) {
|
||||
_mode = newViewProps.initialHidden ? RCTVirtualViewModeHidden : RCTVirtualViewModeVisible;
|
||||
}
|
||||
|
||||
// If disabled, `_renderState` will always be `RCTVirtualViewRenderStateUnknown`.
|
||||
if (ReactNativeFeatureFlags::enableVirtualViewRenderState()) {
|
||||
switch (newViewProps.renderState) {
|
||||
case 1:
|
||||
_renderState = RCTVirtualViewRenderStateRendered;
|
||||
break;
|
||||
case 2:
|
||||
_renderState = RCTVirtualViewRenderStateNone;
|
||||
break;
|
||||
default:
|
||||
_renderState = RCTVirtualViewRenderStateUnknown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[super updateProps:props oldProps:oldProps];
|
||||
}
|
||||
|
||||
- (RCTScrollViewComponentView *)getParentScrollViewComponentView
|
||||
{
|
||||
UIView *view = self.superview;
|
||||
while (view != nil) {
|
||||
if ([view isKindOfClass:[RCTScrollViewComponentView class]]) {
|
||||
return (RCTScrollViewComponentView *)view;
|
||||
}
|
||||
view = view.superview;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
{
|
||||
[super prepareForRecycle];
|
||||
|
||||
// No need to remove the scroll listener here since the view is always removed from window before being recycled and
|
||||
// we do that in didMoveToWindow, which gets called when the view is removed from window.
|
||||
RCTAssert(
|
||||
_lastParentScrollViewComponentView == nil,
|
||||
@"_lastParentScrollViewComponentView should already have been cleared in didMoveToWindow.");
|
||||
|
||||
_mode.reset();
|
||||
_targetRect.reset();
|
||||
}
|
||||
|
||||
// Handles case when sibling changes size.
|
||||
// TODO(T202601695): This doesn't yet handle the case of elements in the ScrollView outside a VirtualColumn changing
|
||||
// size.
|
||||
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
|
||||
oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
|
||||
{
|
||||
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:_layoutMetrics];
|
||||
|
||||
[self dispatchOnModeChangeIfNeeded:YES];
|
||||
}
|
||||
|
||||
- (void)didMoveToWindow
|
||||
{
|
||||
[super didMoveToWindow];
|
||||
|
||||
if (_lastParentScrollViewComponentView) {
|
||||
[_lastParentScrollViewComponentView removeScrollListener:self];
|
||||
_lastParentScrollViewComponentView = nil;
|
||||
}
|
||||
|
||||
if (RCTScrollViewComponentView *parentScrollViewComponentView = [self getParentScrollViewComponentView]) {
|
||||
if (self.window) {
|
||||
// TODO(T202601695): We also want the ScrollView to emit layout changes from didLayoutSubviews so that any event
|
||||
// that may affect visibily of this view notifies the listeners.
|
||||
[parentScrollViewComponentView addScrollListener:self];
|
||||
_lastParentScrollViewComponentView = parentScrollViewComponentView;
|
||||
|
||||
// We want to dispatch the event immediately when the view is added to the window before any scrolling occurs.
|
||||
[self dispatchOnModeChangeIfNeeded:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
||||
{
|
||||
[self dispatchOnModeChangeIfNeeded:NO];
|
||||
}
|
||||
|
||||
- (void)dispatchOnModeChangeIfNeeded:(BOOL)checkForTargetRectChange
|
||||
{
|
||||
if (!_lastParentScrollViewComponentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIScrollView *scrollView = _lastParentScrollViewComponentView.scrollView;
|
||||
CGRect targetRect = [self convertRect:self.bounds toView:scrollView];
|
||||
|
||||
// While scrolling, the `targetRect` does not change, so we don't check for changed `targetRect` in that case.
|
||||
if (checkForTargetRectChange) {
|
||||
if (_targetRect.has_value() && CGRectEqualToRect(targetRect, _targetRect.value())) {
|
||||
return;
|
||||
}
|
||||
_targetRect = targetRect;
|
||||
}
|
||||
|
||||
enum RCTVirtualViewMode newMode;
|
||||
CGRect thresholdRect = CGRectMake(
|
||||
scrollView.contentOffset.x,
|
||||
scrollView.contentOffset.y,
|
||||
scrollView.frame.size.width,
|
||||
scrollView.frame.size.height);
|
||||
if (CGRectOverlaps(targetRect, thresholdRect)) {
|
||||
newMode = RCTVirtualViewModeVisible;
|
||||
} else {
|
||||
auto prerender = false;
|
||||
const CGFloat prerenderRatio = ReactNativeFeatureFlags::virtualViewPrerenderRatio();
|
||||
if (prerenderRatio > 0) {
|
||||
thresholdRect = CGRectInset(
|
||||
thresholdRect, -thresholdRect.size.width * prerenderRatio, -thresholdRect.size.height * prerenderRatio);
|
||||
prerender = CGRectOverlaps(targetRect, thresholdRect);
|
||||
}
|
||||
if (prerender) {
|
||||
newMode = RCTVirtualViewModePrerender;
|
||||
} else {
|
||||
newMode = RCTVirtualViewModeHidden;
|
||||
thresholdRect = CGRectZero;
|
||||
}
|
||||
}
|
||||
|
||||
if (_mode.has_value() && newMode == _mode.value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Make sure to keep these props in sync with dispatchSyncModeChange below where we have to explicitly copy all
|
||||
// props.
|
||||
VirtualViewEventEmitter::OnModeChange event = {
|
||||
.mode = (int)newMode,
|
||||
.targetRect =
|
||||
{.x = targetRect.origin.x,
|
||||
.y = targetRect.origin.y,
|
||||
.width = targetRect.size.width,
|
||||
.height = targetRect.size.height},
|
||||
.thresholdRect =
|
||||
{.x = thresholdRect.origin.x,
|
||||
.y = thresholdRect.origin.y,
|
||||
.width = thresholdRect.size.width,
|
||||
.height = thresholdRect.size.height},
|
||||
};
|
||||
|
||||
const std::optional<enum RCTVirtualViewMode> oldMode = _mode;
|
||||
_mode = newMode;
|
||||
|
||||
switch (newMode) {
|
||||
case RCTVirtualViewModeVisible:
|
||||
if (_renderState == RCTVirtualViewRenderStateUnknown) {
|
||||
// Feature flag is disabled, so use the former logic.
|
||||
[self dispatchSyncModeChange:event];
|
||||
} else {
|
||||
// If the previous mode was prerender and the result of dispatching that event was committed, we do not need to
|
||||
// dispatch an event for visible.
|
||||
const auto wasPrerenderCommitted = oldMode.has_value() && oldMode == RCTVirtualViewModePrerender &&
|
||||
_renderState == RCTVirtualViewRenderStateRendered;
|
||||
if (!wasPrerenderCommitted) {
|
||||
[self dispatchSyncModeChange:event];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RCTVirtualViewModePrerender:
|
||||
if (!oldMode.has_value() || oldMode != RCTVirtualViewModeVisible) {
|
||||
[self dispatchAsyncModeChange:event];
|
||||
}
|
||||
break;
|
||||
case RCTVirtualViewModeHidden:
|
||||
[self dispatchAsyncModeChange:event];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dispatchAsyncModeChange:(VirtualViewEventEmitter::OnModeChange &)event
|
||||
{
|
||||
if (!_eventEmitter) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<const VirtualViewEventEmitter> emitter =
|
||||
std::static_pointer_cast<const VirtualViewEventEmitter>(_eventEmitter);
|
||||
emitter->onModeChange(event);
|
||||
}
|
||||
|
||||
- (void)dispatchSyncModeChange:(VirtualViewEventEmitter::OnModeChange &)event
|
||||
{
|
||||
if (!_eventEmitter) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<const VirtualViewEventEmitter> emitter =
|
||||
std::static_pointer_cast<const VirtualViewEventEmitter>(_eventEmitter);
|
||||
|
||||
// TODO: Move this into a custom event emitter. We had to duplicate the codegen code here from onModeChange in order
|
||||
// to dispatch synchronously and discrete.
|
||||
emitter->experimental_flushSync([&emitter, &event]() {
|
||||
emitter->dispatchEvent(
|
||||
"modeChange",
|
||||
[event](jsi::Runtime &runtime) {
|
||||
auto payload = jsi::Object(runtime);
|
||||
payload.setProperty(runtime, "mode", event.mode);
|
||||
{
|
||||
auto targetRect = jsi::Object(runtime);
|
||||
targetRect.setProperty(runtime, "x", event.targetRect.x);
|
||||
targetRect.setProperty(runtime, "y", event.targetRect.y);
|
||||
targetRect.setProperty(runtime, "width", event.targetRect.width);
|
||||
targetRect.setProperty(runtime, "height", event.targetRect.height);
|
||||
payload.setProperty(runtime, "targetRect", targetRect);
|
||||
}
|
||||
{
|
||||
auto thresholdRect = jsi::Object(runtime);
|
||||
thresholdRect.setProperty(runtime, "x", event.thresholdRect.x);
|
||||
thresholdRect.setProperty(runtime, "y", event.thresholdRect.y);
|
||||
thresholdRect.setProperty(runtime, "width", event.thresholdRect.width);
|
||||
thresholdRect.setProperty(runtime, "height", event.thresholdRect.height);
|
||||
payload.setProperty(runtime, "thresholdRect", thresholdRect);
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
RawEvent::Category::Discrete);
|
||||
});
|
||||
}
|
||||
|
||||
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
||||
{
|
||||
return concreteComponentDescriptorProvider<VirtualViewComponentDescriptor>();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Class<RCTComponentViewProtocol> VirtualViewCls(void)
|
||||
{
|
||||
return RCTVirtualViewComponentView.class;
|
||||
}
|
||||
@@ -72,12 +72,6 @@ class SchedulerDelegateProxy : public SchedulerDelegate {
|
||||
[scheduler.delegate schedulerDidSynchronouslyUpdateViewOnUIThread:tag props:props];
|
||||
}
|
||||
|
||||
void schedulerDidUpdateShadowTree(const std::unordered_map<Tag, folly::dynamic> &tagToProps) override
|
||||
{
|
||||
// Does nothing.
|
||||
// This delegate method is not currently used on iOS.
|
||||
}
|
||||
|
||||
private:
|
||||
void *scheduler_;
|
||||
};
|
||||
|
||||
@@ -16,13 +16,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (std::vector<facebook::react::ProcessedColorStop>)getFixedColorStops:
|
||||
(const std::vector<facebook::react::ColorStop> &)colorStops
|
||||
gradientLineLength:(CGFloat)gradientLineLength;
|
||||
|
||||
// CAGradientLayer linear gradient squishes the non-square gradient to square gradient.
|
||||
// This function fixes the "squished" effect.
|
||||
// See https://stackoverflow.com/a/43176174 for more information.
|
||||
+ (std::pair<CGPoint, CGPoint>)pointsForCAGradientLayerLinearGradient:(CGPoint)startPoint
|
||||
endPoint:(CGPoint)endPoint
|
||||
bounds:(CGSize)bounds;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -9,140 +9,10 @@
|
||||
#import <React/RCTAnimationUtils.h>
|
||||
#import <React/RCTConversions.h>
|
||||
#import <react/utils/FloatComparison.h>
|
||||
#include <optional>
|
||||
#import <vector>
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
namespace {
|
||||
|
||||
struct Line;
|
||||
|
||||
struct LineSegment {
|
||||
CGPoint p1;
|
||||
CGPoint p2;
|
||||
|
||||
LineSegment(CGPoint p1, CGPoint p2) : p1(p1), p2(p2) {}
|
||||
|
||||
LineSegment(CGPoint p1, CGFloat m, CGFloat distance);
|
||||
|
||||
CGFloat getLength() const
|
||||
{
|
||||
CGFloat dx = p2.x - p1.x;
|
||||
CGFloat dy = p2.y - p1.y;
|
||||
return sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
CGFloat getDistance() const
|
||||
{
|
||||
return p1.x <= p2.x ? getLength() : -getLength();
|
||||
}
|
||||
|
||||
CGPoint getMidpoint() const
|
||||
{
|
||||
return CGPointMake((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
|
||||
}
|
||||
|
||||
CGFloat getSlope() const
|
||||
{
|
||||
CGFloat dx = p2.x - p1.x;
|
||||
if (floatEquality(dx, 0.0)) {
|
||||
return std::numeric_limits<CGFloat>::infinity();
|
||||
}
|
||||
return (p2.y - p1.y) / dx;
|
||||
}
|
||||
|
||||
CGFloat getPerpendicularSlope() const
|
||||
{
|
||||
CGFloat slope = getSlope();
|
||||
if (std::isinf(slope)) {
|
||||
return 0.0;
|
||||
}
|
||||
if (floatEquality(slope, 0.0)) {
|
||||
return -std::numeric_limits<CGFloat>::infinity();
|
||||
}
|
||||
return -1 / slope;
|
||||
}
|
||||
|
||||
Line toLine() const;
|
||||
|
||||
LineSegment perpendicularBisector() const
|
||||
{
|
||||
CGPoint midpoint = getMidpoint();
|
||||
CGFloat perpSlope = getPerpendicularSlope();
|
||||
CGFloat dist = getDistance();
|
||||
return {LineSegment(midpoint, perpSlope, -dist / 2).p2, LineSegment(midpoint, perpSlope, dist / 2).p2};
|
||||
}
|
||||
|
||||
LineSegment multiplied(CGSize multipliers) const
|
||||
{
|
||||
return {
|
||||
CGPointMake(p1.x * multipliers.width, p1.y * multipliers.height),
|
||||
CGPointMake(p2.x * multipliers.width, p2.y * multipliers.height)};
|
||||
}
|
||||
|
||||
LineSegment divided(CGSize divisors) const
|
||||
{
|
||||
return multiplied(CGSizeMake(1 / divisors.width, 1 / divisors.height));
|
||||
}
|
||||
};
|
||||
|
||||
struct Line {
|
||||
CGFloat m;
|
||||
CGFloat b;
|
||||
|
||||
Line(CGFloat m, CGFloat b) : m(m), b(b) {}
|
||||
Line(CGFloat m, CGPoint p) : m(m), b(p.y - m * p.x) {}
|
||||
Line(CGPoint p1, CGPoint p2) : m(LineSegment(p1, p2).getSlope()), b(p1.y - m * p1.x) {}
|
||||
|
||||
CGFloat y(CGFloat x) const
|
||||
{
|
||||
return m * x + b;
|
||||
}
|
||||
|
||||
CGPoint point(CGFloat x) const
|
||||
{
|
||||
return CGPointMake(x, y(x));
|
||||
}
|
||||
|
||||
std::optional<CGPoint> intersection(const Line &other) const
|
||||
{
|
||||
CGFloat n = other.m;
|
||||
CGFloat c = other.b;
|
||||
if (floatEquality(m, n)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
CGFloat x = (c - b) / (m - n);
|
||||
return point(x);
|
||||
}
|
||||
};
|
||||
|
||||
LineSegment::LineSegment(CGPoint p1, CGFloat m, CGFloat distance) : p1(p1)
|
||||
{
|
||||
Line line(m, p1);
|
||||
CGPoint measuringPoint = line.point(p1.x + 1);
|
||||
LineSegment measuringSegment(p1, measuringPoint);
|
||||
CGFloat measuringDeltaH = measuringSegment.getDistance();
|
||||
CGFloat deltaX = !floatEquality(measuringDeltaH, 0.0) ? distance / measuringDeltaH : 0.0;
|
||||
p2 = line.point(p1.x + deltaX);
|
||||
}
|
||||
|
||||
Line LineSegment::toLine() const
|
||||
{
|
||||
return {p1, p2};
|
||||
}
|
||||
|
||||
CGSize calculateMultipliers(CGSize bounds)
|
||||
{
|
||||
if (bounds.height <= bounds.width) {
|
||||
return CGSizeMake(1, bounds.width / bounds.height);
|
||||
} else {
|
||||
return CGSizeMake(bounds.height / bounds.width, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static std::optional<Float> resolveColorStopPosition(ValueUnit position, CGFloat gradientLineLength)
|
||||
{
|
||||
if (position.unit == UnitType::Point) {
|
||||
@@ -182,21 +52,21 @@ static std::vector<ProcessedColorStop> processColorTransitionHints(const std::ve
|
||||
auto leftDist = offset - offsetLeft;
|
||||
auto rightDist = offsetRight - offset;
|
||||
auto totalDist = offsetRight - offsetLeft;
|
||||
const SharedColor &leftSharedColor = colorStops[x - 1].color;
|
||||
const SharedColor &rightSharedColor = colorStops[x + 1].color;
|
||||
SharedColor leftSharedColor = colorStops[x - 1].color;
|
||||
SharedColor rightSharedColor = colorStops[x + 1].color;
|
||||
|
||||
if (floatEquality(leftDist, rightDist)) {
|
||||
if (facebook::react::floatEquality(leftDist, rightDist)) {
|
||||
colorStops.erase(colorStops.begin() + x);
|
||||
--indexOffset;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (floatEquality(leftDist, 0.0)) {
|
||||
if (facebook::react::floatEquality(leftDist, .0f)) {
|
||||
colorStops[x].color = rightSharedColor;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (floatEquality(rightDist, 0.0)) {
|
||||
if (facebook::react::floatEquality(rightDist, .0f)) {
|
||||
colorStops[x].color = leftSharedColor;
|
||||
continue;
|
||||
}
|
||||
@@ -250,7 +120,7 @@ static std::vector<ProcessedColorStop> processColorTransitionHints(const std::ve
|
||||
auto green = (interpolatedColor >> 8) & 0xFF;
|
||||
auto blue = interpolatedColor & 0xFF;
|
||||
|
||||
newStop.color = colorFromRGBA(red, green, blue, alpha);
|
||||
newStop.color = facebook::react::colorFromRGBA(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
// Replace the color hint with new color stops
|
||||
@@ -331,47 +201,4 @@ static std::vector<ProcessedColorStop> processColorTransitionHints(const std::ve
|
||||
}
|
||||
return processColorTransitionHints(fixedColorStops);
|
||||
}
|
||||
|
||||
// CAGradientLayer linear gradient squishes the non-square gradient to square gradient.
|
||||
// This function fixes the "squished" effect.
|
||||
// See https://stackoverflow.com/a/43176174 for more information.
|
||||
+ (std::pair<CGPoint, CGPoint>)pointsForCAGradientLayerLinearGradient:(CGPoint)startPoint
|
||||
endPoint:(CGPoint)endPoint
|
||||
bounds:(CGSize)bounds
|
||||
{
|
||||
if (floatEquality(startPoint.x, endPoint.x) || floatEquality(startPoint.y, endPoint.y)) {
|
||||
// Apple's implementation of horizontal and vertical gradients works just fine
|
||||
return {startPoint, endPoint};
|
||||
}
|
||||
|
||||
LineSegment startEnd(startPoint, endPoint);
|
||||
LineSegment ab = startEnd.multiplied({bounds.width, bounds.height});
|
||||
const CGPoint a = ab.p1;
|
||||
const CGPoint b = ab.p2;
|
||||
|
||||
LineSegment cd = ab.perpendicularBisector();
|
||||
|
||||
CGSize multipliers = calculateMultipliers(bounds);
|
||||
LineSegment lineSegmentCD = cd.multiplied(multipliers);
|
||||
|
||||
LineSegment lineSegmentEF = lineSegmentCD.perpendicularBisector();
|
||||
|
||||
LineSegment ef = lineSegmentEF.divided(multipliers);
|
||||
|
||||
Line efLine = ef.toLine();
|
||||
|
||||
Line aParallelLine(cd.getSlope(), a);
|
||||
Line bParallelLine(cd.getSlope(), b);
|
||||
|
||||
std::optional<CGPoint> g_opt = efLine.intersection(aParallelLine);
|
||||
std::optional<CGPoint> h_opt = efLine.intersection(bParallelLine);
|
||||
|
||||
if (g_opt && h_opt) {
|
||||
LineSegment gh(*g_opt, *h_opt);
|
||||
LineSegment result = gh.divided({bounds.width, bounds.height});
|
||||
return {result.p1, result.p2};
|
||||
}
|
||||
|
||||
return {startPoint, endPoint};
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -19,52 +19,54 @@ using namespace facebook::react;
|
||||
|
||||
+ (CALayer *)gradientLayerWithSize:(CGSize)size gradient:(const LinearGradient &)gradient
|
||||
{
|
||||
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size];
|
||||
const auto &direction = gradient.direction;
|
||||
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
|
||||
CGPoint startPoint;
|
||||
CGPoint endPoint;
|
||||
UIImage *gradientImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
|
||||
CGPoint startPoint;
|
||||
CGPoint endPoint;
|
||||
|
||||
if (direction.type == GradientDirectionType::Angle) {
|
||||
CGFloat angle = std::get<Float>(direction.value);
|
||||
std::tie(startPoint, endPoint) = getPointsFromAngle(angle, size);
|
||||
} else if (direction.type == GradientDirectionType::Keyword) {
|
||||
auto keyword = std::get<GradientKeyword>(direction.value);
|
||||
CGFloat angle = getAngleForKeyword(keyword, size);
|
||||
std::tie(startPoint, endPoint) = getPointsFromAngle(angle, size);
|
||||
} else {
|
||||
// Default to top-to-bottom gradient
|
||||
CGFloat centerX = size.width / 2;
|
||||
startPoint = CGPointMake(centerX, 0.0);
|
||||
endPoint = CGPointMake(centerX, size.height);
|
||||
}
|
||||
if (direction.type == GradientDirectionType::Angle) {
|
||||
CGFloat angle = std::get<Float>(direction.value);
|
||||
std::tie(startPoint, endPoint) = getPointsFromAngle(angle, size);
|
||||
} else if (direction.type == GradientDirectionType::Keyword) {
|
||||
auto keyword = std::get<GradientKeyword>(direction.value);
|
||||
CGFloat angle = getAngleForKeyword(keyword, size);
|
||||
std::tie(startPoint, endPoint) = getPointsFromAngle(angle, size);
|
||||
} else {
|
||||
// Default to top-to-bottom gradient
|
||||
startPoint = CGPointMake(0.0, 0.0);
|
||||
endPoint = CGPointMake(0.0, size.height);
|
||||
}
|
||||
|
||||
CGFloat dx = endPoint.x - startPoint.x;
|
||||
CGFloat dy = endPoint.y - startPoint.y;
|
||||
CGFloat gradientLineLength = sqrt(dx * dx + dy * dy);
|
||||
const auto colorStops = [RCTGradientUtils getFixedColorStops:gradient.colorStops
|
||||
gradientLineLength:gradientLineLength];
|
||||
NSMutableArray<id> *colors = [NSMutableArray array];
|
||||
NSMutableArray<NSNumber *> *locations = [NSMutableArray array];
|
||||
CGPoint relativeStartPoint = CGPointMake(startPoint.x / size.width, startPoint.y / size.height);
|
||||
CGPoint relativeEndPoint = CGPointMake(endPoint.x / size.width, endPoint.y / size.height);
|
||||
CGFloat dx = endPoint.x - startPoint.x;
|
||||
CGFloat dy = endPoint.y - startPoint.y;
|
||||
CGFloat gradientLineLength = sqrt(dx * dx + dy * dy);
|
||||
const auto colorStops = [RCTGradientUtils getFixedColorStops:gradient.colorStops
|
||||
gradientLineLength:gradientLineLength];
|
||||
|
||||
CGPoint fixedStartPoint;
|
||||
CGPoint fixedEndPoint;
|
||||
CGContextRef context = rendererContext.CGContext;
|
||||
NSMutableArray *colors = [NSMutableArray array];
|
||||
CGFloat locations[colorStops.size()];
|
||||
|
||||
std::tie(fixedStartPoint, fixedEndPoint) = [RCTGradientUtils pointsForCAGradientLayerLinearGradient:relativeStartPoint
|
||||
endPoint:relativeEndPoint
|
||||
bounds:size];
|
||||
for (size_t i = 0; i < colorStops.size(); ++i) {
|
||||
const auto &colorStop = colorStops[i];
|
||||
CGColorRef cgColor = RCTCreateCGColorRefFromSharedColor(colorStop.color);
|
||||
[colors addObject:(__bridge id)cgColor];
|
||||
locations[i] = std::max(std::min(colorStop.position.value(), 1.0), 0.0);
|
||||
}
|
||||
|
||||
gradientLayer.startPoint = fixedStartPoint;
|
||||
gradientLayer.endPoint = fixedEndPoint;
|
||||
CGGradientRef cgGradient = CGGradientCreateWithColors(NULL, (__bridge CFArrayRef)colors, locations);
|
||||
|
||||
for (const auto &colorStop : colorStops) {
|
||||
[colors addObject:(id)RCTUIColorFromSharedColor(colorStop.color).CGColor];
|
||||
[locations addObject:@(std::max(std::min(colorStop.position.value(), 1.0), 0.0))];
|
||||
}
|
||||
CGContextDrawLinearGradient(context, cgGradient, startPoint, endPoint, 0);
|
||||
|
||||
gradientLayer.colors = colors;
|
||||
gradientLayer.locations = locations;
|
||||
for (id color in colors) {
|
||||
CGColorRelease((__bridge CGColorRef)color);
|
||||
}
|
||||
CGGradientRelease(cgGradient);
|
||||
}];
|
||||
|
||||
CALayer *gradientLayer = [CALayer layer];
|
||||
gradientLayer.contents = (__bridge id)gradientImage.CGImage;
|
||||
|
||||
return gradientLayer;
|
||||
}
|
||||
|
||||
@@ -153,42 +153,75 @@ static RadiusVector GetRadialGradientRadius(
|
||||
|
||||
+ (CALayer *)gradientLayerWithSize:(CGSize)size gradient:(const RadialGradient &)gradient
|
||||
{
|
||||
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
|
||||
gradientLayer.type = kCAGradientLayerRadial;
|
||||
CGPoint centerPoint = CGPointMake(size.width / 2.0, size.height / 2.0);
|
||||
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size];
|
||||
UIImage *gradientImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
|
||||
CGContextRef context = rendererContext.CGContext;
|
||||
|
||||
if (gradient.position.top) {
|
||||
centerPoint.y = gradient.position.top->resolve(size.height);
|
||||
} else if (gradient.position.bottom) {
|
||||
centerPoint.y = size.height - gradient.position.bottom->resolve(size.height);
|
||||
}
|
||||
CGPoint centerPoint = CGPointMake(size.width / 2.0, size.height / 2.0);
|
||||
|
||||
if (gradient.position.left) {
|
||||
centerPoint.x = gradient.position.left->resolve(size.width);
|
||||
} else if (gradient.position.right) {
|
||||
centerPoint.x = size.width - gradient.position.right->resolve(size.width);
|
||||
}
|
||||
if (gradient.position.top) {
|
||||
centerPoint.y = gradient.position.top->resolve(size.height);
|
||||
} else if (gradient.position.bottom) {
|
||||
centerPoint.y = size.height - gradient.position.bottom->resolve(size.height);
|
||||
}
|
||||
|
||||
bool isCircle = (gradient.shape == RadialGradientShape::Circle);
|
||||
auto [radiusX, radiusY] =
|
||||
GetRadialGradientRadius(isCircle, gradient.size, centerPoint.x, centerPoint.y, size.width, size.height);
|
||||
const auto gradientLineLength = std::max(radiusX, radiusY);
|
||||
const auto colorStops = [RCTGradientUtils getFixedColorStops:gradient.colorStops
|
||||
gradientLineLength:gradientLineLength];
|
||||
gradientLayer.startPoint = CGPointMake(centerPoint.x / size.width, centerPoint.y / size.height);
|
||||
// endpoint.x is horizontal length and endpoint.y is vertical length
|
||||
gradientLayer.endPoint = CGPointMake(
|
||||
gradientLayer.startPoint.x + radiusX / size.width, gradientLayer.startPoint.y + radiusY / size.height);
|
||||
if (gradient.position.left) {
|
||||
centerPoint.x = gradient.position.left->resolve(size.width);
|
||||
} else if (gradient.position.right) {
|
||||
centerPoint.x = size.width - gradient.position.right->resolve(size.width);
|
||||
}
|
||||
|
||||
NSMutableArray<id> *colors = [NSMutableArray array];
|
||||
NSMutableArray<NSNumber *> *locations = [NSMutableArray array];
|
||||
for (const auto &colorStop : colorStops) {
|
||||
[colors addObject:(id)RCTUIColorFromSharedColor(colorStop.color).CGColor];
|
||||
[locations addObject:@(std::max(std::min(colorStop.position.value(), 1.0), 0.0))];
|
||||
}
|
||||
bool isCircle = (gradient.shape == RadialGradientShape::Circle);
|
||||
auto [radiusX, radiusY] =
|
||||
GetRadialGradientRadius(isCircle, gradient.size, centerPoint.x, centerPoint.y, size.width, size.height);
|
||||
|
||||
gradientLayer.colors = colors;
|
||||
gradientLayer.locations = locations;
|
||||
CGFloat scale = 1.0;
|
||||
if (radiusX != radiusY && gradient.shape != RadialGradientShape::Circle) {
|
||||
scale = radiusX / radiusY;
|
||||
CGContextSaveGState(context);
|
||||
// Scale the context to make the circular gradient appear elliptical
|
||||
CGContextTranslateCTM(context, centerPoint.x, centerPoint.y);
|
||||
CGContextScaleCTM(context, 1.0, 1.0 / scale);
|
||||
CGContextTranslateCTM(context, -centerPoint.x, -centerPoint.y);
|
||||
radiusX = std::max(radiusX, radiusY * scale);
|
||||
}
|
||||
|
||||
const auto colorStops = [RCTGradientUtils getFixedColorStops:gradient.colorStops gradientLineLength:radiusX];
|
||||
|
||||
NSMutableArray *colors = [NSMutableArray array];
|
||||
CGFloat locations[colorStops.size()];
|
||||
|
||||
for (size_t i = 0; i < colorStops.size(); ++i) {
|
||||
const auto &colorStop = colorStops[i];
|
||||
CGColorRef cgColor = RCTCreateCGColorRefFromSharedColor(colorStop.color);
|
||||
[colors addObject:(__bridge id)cgColor];
|
||||
locations[i] = std::max(std::min(colorStop.position.value(), 1.0), 0.0);
|
||||
}
|
||||
|
||||
CGGradientRef cgGradient = CGGradientCreateWithColors(NULL, (__bridge CFArrayRef)colors, locations);
|
||||
|
||||
CGContextDrawRadialGradient(
|
||||
context,
|
||||
cgGradient,
|
||||
centerPoint,
|
||||
0,
|
||||
centerPoint,
|
||||
radiusX,
|
||||
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
|
||||
|
||||
// Restore the context state if we scaled it
|
||||
if (radiusX != radiusY && gradient.shape != RadialGradientShape::Circle) {
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
for (id color in colors) {
|
||||
CGColorRelease((__bridge CGColorRef)color);
|
||||
}
|
||||
CGGradientRelease(cgGradient);
|
||||
}];
|
||||
|
||||
CALayer *gradientLayer = [CALayer layer];
|
||||
gradientLayer.contents = (__bridge id)gradientImage.CGImage;
|
||||
|
||||
return gradientLayer;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("FBReactNativeSpec/**/*.{c,h,m,mm,cpp}", "FBReactNativeSpec/**/*.{h}")
|
||||
s.source_files = "FBReactNativeSpec/**/*.{c,h,m,mm,cpp}"
|
||||
s.exclude_files = "FBReactNativeSpec/react/renderer/components",
|
||||
s.compiler_flags = new_arch_flags
|
||||
s.header_dir = 'FBReactNativeSpec'
|
||||
@@ -63,7 +63,7 @@ Pod::Spec.new do |s|
|
||||
add_rn_third_party_dependencies(s)
|
||||
|
||||
s.subspec "components" do |ss|
|
||||
ss.source_files = podspec_sources("FBReactNativeSpec/react/renderer/components/FBReactNativeSpec/**/*.{m,mm,cpp,h}", "FBReactNativeSpec/react/renderer/components/FBReactNativeSpec/**/*.{h}")
|
||||
ss.source_files = "FBReactNativeSpec/react/renderer/components/FBReactNativeSpec/**/*.{m,mm,cpp,h}"
|
||||
ss.header_dir = "react/renderer/components/FBReactNativeSpec"
|
||||
|
||||
add_dependency(ss, "React-featureflags")
|
||||
|
||||
@@ -42,7 +42,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("Fabric/**/*.{c,h,m,mm,S,cpp}", "Fabric/**/*.{h}")
|
||||
s.source_files = "Fabric/**/*.{c,h,m,mm,S,cpp}"
|
||||
s.exclude_files = "**/tests/*",
|
||||
"**/android/*",
|
||||
s.compiler_flags = new_arch_flags
|
||||
@@ -99,7 +99,7 @@ Pod::Spec.new do |s|
|
||||
add_rn_third_party_dependencies(s)
|
||||
|
||||
s.test_spec 'Tests' do |test_spec|
|
||||
test_spec.source_files = podspec_sources("Tests/**/*.{mm}", "")
|
||||
test_spec.source_files = "Tests/**/*.{mm}"
|
||||
test_spec.framework = "XCTest"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = podspec_sources("*.{h,mm}", "*.h")
|
||||
s.source_files = "*.{h,mm}"
|
||||
s.compiler_flags = new_arch_flags
|
||||
s.header_dir = header_dir
|
||||
s.module_name = module_name
|
||||
|
||||
@@ -148,29 +148,29 @@ public class com/facebook/react/ReactDelegate {
|
||||
public fun <init> (Landroid/app/Activity;Lcom/facebook/react/ReactNativeHost;Ljava/lang/String;Landroid/os/Bundle;)V
|
||||
public fun <init> (Landroid/app/Activity;Lcom/facebook/react/ReactNativeHost;Ljava/lang/String;Landroid/os/Bundle;Z)V
|
||||
protected fun createRootView ()Lcom/facebook/react/ReactRootView;
|
||||
public final fun getCurrentReactContext ()Lcom/facebook/react/bridge/ReactContext;
|
||||
public final fun getReactHost ()Lcom/facebook/react/ReactHost;
|
||||
public final fun getReactInstanceManager ()Lcom/facebook/react/ReactInstanceManager;
|
||||
public final fun getReactRootView ()Lcom/facebook/react/ReactRootView;
|
||||
protected final fun isFabricEnabled ()Z
|
||||
public final fun loadApp ()V
|
||||
public final fun loadApp (Ljava/lang/String;)V
|
||||
public final fun onActivityResult (IILandroid/content/Intent;Z)V
|
||||
public final fun onBackPressed ()Z
|
||||
public final fun onConfigurationChanged (Landroid/content/res/Configuration;)V
|
||||
public final fun onHostDestroy ()V
|
||||
public final fun onHostPause ()V
|
||||
public final fun onHostResume ()V
|
||||
public final fun onKeyDown (ILandroid/view/KeyEvent;)Z
|
||||
public final fun onKeyLongPress (I)Z
|
||||
public final fun onNewIntent (Landroid/content/Intent;)Z
|
||||
public final fun onUserLeaveHint ()V
|
||||
public final fun onWindowFocusChanged (Z)V
|
||||
public final fun reload ()V
|
||||
public final fun setReactRootView (Lcom/facebook/react/ReactRootView;)V
|
||||
public final fun setReactSurface (Lcom/facebook/react/interfaces/fabric/ReactSurface;)V
|
||||
public final fun shouldShowDevMenuOrReload (ILandroid/view/KeyEvent;)Z
|
||||
public final fun unloadApp ()V
|
||||
public fun getCurrentReactContext ()Lcom/facebook/react/bridge/ReactContext;
|
||||
public fun getReactHost ()Lcom/facebook/react/ReactHost;
|
||||
public fun getReactInstanceManager ()Lcom/facebook/react/ReactInstanceManager;
|
||||
public fun getReactRootView ()Lcom/facebook/react/ReactRootView;
|
||||
protected fun isFabricEnabled ()Z
|
||||
public fun loadApp ()V
|
||||
public fun loadApp (Ljava/lang/String;)V
|
||||
public fun onActivityResult (IILandroid/content/Intent;Z)V
|
||||
public fun onBackPressed ()Z
|
||||
public fun onConfigurationChanged (Landroid/content/res/Configuration;)V
|
||||
public fun onHostDestroy ()V
|
||||
public fun onHostPause ()V
|
||||
public fun onHostResume ()V
|
||||
public fun onKeyDown (ILandroid/view/KeyEvent;)Z
|
||||
public fun onKeyLongPress (I)Z
|
||||
public fun onNewIntent (Landroid/content/Intent;)Z
|
||||
public fun onUserLeaveHint ()V
|
||||
public fun onWindowFocusChanged (Z)V
|
||||
public fun reload ()V
|
||||
public fun setReactRootView (Lcom/facebook/react/ReactRootView;)V
|
||||
public fun setReactSurface (Lcom/facebook/react/interfaces/fabric/ReactSurface;)V
|
||||
public fun shouldShowDevMenuOrReload (ILandroid/view/KeyEvent;)Z
|
||||
public fun unloadApp ()V
|
||||
}
|
||||
|
||||
public class com/facebook/react/ReactFragment : androidx/fragment/app/Fragment, com/facebook/react/modules/core/PermissionAwareActivity {
|
||||
@@ -259,7 +259,6 @@ public class com/facebook/react/ReactInstanceManager {
|
||||
public fun createViewManager (Ljava/lang/String;)Lcom/facebook/react/uimanager/ViewManager;
|
||||
public fun destroy ()V
|
||||
public fun detachRootView (Lcom/facebook/react/uimanager/ReactRoot;)V
|
||||
public fun getCurrentReactContext ()Lcom/facebook/react/bridge/ReactContext;
|
||||
public fun getDevSupportManager ()Lcom/facebook/react/devsupport/interfaces/DevSupportManager;
|
||||
public fun getJsExecutorName ()Ljava/lang/String;
|
||||
public fun getLifecycleState ()Lcom/facebook/react/common/LifecycleState;
|
||||
@@ -601,14 +600,12 @@ public abstract interface class com/facebook/react/bridge/CatalystInstance : com
|
||||
public abstract fun getSourceURL ()Ljava/lang/String;
|
||||
public abstract fun hasNativeModule (Ljava/lang/Class;)Z
|
||||
public abstract fun hasRunJSBundle ()Z
|
||||
public abstract fun initialize ()V
|
||||
public abstract fun invokeCallback (ILcom/facebook/react/bridge/NativeArrayInterface;)V
|
||||
public abstract fun isDestroyed ()Z
|
||||
public abstract fun registerSegment (ILjava/lang/String;)V
|
||||
public abstract fun removeBridgeIdleDebugListener (Lcom/facebook/react/bridge/NotThreadSafeBridgeIdleDebugListener;)V
|
||||
public abstract fun runJSBundle ()V
|
||||
public abstract fun setFabricUIManager (Lcom/facebook/react/bridge/UIManager;)V
|
||||
public abstract fun setGlobalVariable (Ljava/lang/String;Ljava/lang/String;)V
|
||||
public abstract fun setTurboModuleRegistry (Lcom/facebook/react/internal/turbomodule/core/interfaces/TurboModuleRegistry;)V
|
||||
}
|
||||
|
||||
@@ -2375,6 +2372,24 @@ public final class com/facebook/react/fabric/FabricUIManagerProviderImpl : com/f
|
||||
public fun createUIManager (Lcom/facebook/react/bridge/ReactApplicationContext;)Lcom/facebook/react/bridge/UIManager;
|
||||
}
|
||||
|
||||
public class com/facebook/react/fabric/mounting/MountItemDispatcher {
|
||||
public fun <init> (Lcom/facebook/react/fabric/mounting/MountingManager;Lcom/facebook/react/fabric/mounting/MountItemDispatcher$ItemDispatchListener;)V
|
||||
public fun addMountItem (Lcom/facebook/react/fabric/mounting/mountitems/MountItem;)V
|
||||
public fun addPreAllocateMountItem (Lcom/facebook/react/fabric/mounting/mountitems/MountItem;)V
|
||||
public fun addViewCommandMountItem (Lcom/facebook/react/fabric/mounting/mountitems/DispatchCommandMountItem;)V
|
||||
public fun dispatchMountItems (Ljava/util/Queue;)V
|
||||
public fun dispatchPreMountItems (J)V
|
||||
public fun getBatchedExecutionTime ()J
|
||||
public fun getRunStartTime ()J
|
||||
public fun tryDispatchMountItems ()V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/fabric/mounting/MountItemDispatcher$ItemDispatchListener {
|
||||
public abstract fun didDispatchMountItems ()V
|
||||
public abstract fun didMountItems (Ljava/util/List;)V
|
||||
public abstract fun willMountItems (Ljava/util/List;)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/fabric/mounting/SurfaceMountingManager {
|
||||
public static final field TAG Ljava/lang/String;
|
||||
public fun <init> (ILcom/facebook/react/touch/JSResponderHandler;Lcom/facebook/react/uimanager/ViewManagerRegistry;Lcom/facebook/react/uimanager/RootViewManager;Lcom/facebook/react/fabric/mounting/MountingManager$MountItemExecutor;Lcom/facebook/react/uimanager/ThemedReactContext;)V
|
||||
@@ -3300,7 +3315,6 @@ public abstract class com/facebook/react/uimanager/BaseViewManager : com/faceboo
|
||||
public fun getExportedCustomBubblingEventTypeConstants ()Ljava/util/Map;
|
||||
public fun getExportedCustomDirectEventTypeConstants ()Ljava/util/Map;
|
||||
protected fun onAfterUpdateTransaction (Landroid/view/View;)V
|
||||
public fun onDropViewInstance (Landroid/view/View;)V
|
||||
public fun onLayoutChange (Landroid/view/View;IIIIIIII)V
|
||||
protected fun prepareToRecycleView (Lcom/facebook/react/uimanager/ThemedReactContext;Landroid/view/View;)Landroid/view/View;
|
||||
public fun setAccessibilityActions (Landroid/view/View;Lcom/facebook/react/bridge/ReadableArray;)V
|
||||
@@ -3659,7 +3673,6 @@ public class com/facebook/react/uimanager/ReactAccessibilityDelegate : androidx/
|
||||
public static final field TOP_ACCESSIBILITY_ACTION_EVENT Ljava/lang/String;
|
||||
public static final field sActionIdMap Ljava/util/HashMap;
|
||||
public fun <init> (Landroid/view/View;ZI)V
|
||||
public fun cleanUp ()V
|
||||
public static fun createNodeInfoFromView (Landroid/view/View;)Landroidx/core/view/accessibility/AccessibilityNodeInfoCompat;
|
||||
public fun getAccessibilityNodeProvider (Landroid/view/View;)Landroidx/core/view/accessibility/AccessibilityNodeProviderCompat;
|
||||
protected fun getHostView ()Landroid/view/View;
|
||||
@@ -4340,20 +4353,20 @@ public abstract interface class com/facebook/react/uimanager/UIImplementation$La
|
||||
public abstract fun onLayoutUpdated (Lcom/facebook/react/uimanager/ReactShadowNode;)V
|
||||
}
|
||||
|
||||
public final class com/facebook/react/uimanager/UIManagerHelper {
|
||||
public static final field INSTANCE Lcom/facebook/react/uimanager/UIManagerHelper;
|
||||
public class com/facebook/react/uimanager/UIManagerHelper {
|
||||
public static final field PADDING_BOTTOM_INDEX I
|
||||
public static final field PADDING_END_INDEX I
|
||||
public static final field PADDING_START_INDEX I
|
||||
public static final field PADDING_TOP_INDEX I
|
||||
public static final fun getDefaultTextInputPadding (Landroid/content/Context;)[F
|
||||
public static final fun getEventDispatcher (Lcom/facebook/react/bridge/ReactContext;I)Lcom/facebook/react/uimanager/events/EventDispatcher;
|
||||
public static final fun getEventDispatcherForReactTag (Lcom/facebook/react/bridge/ReactContext;I)Lcom/facebook/react/uimanager/events/EventDispatcher;
|
||||
public static final fun getReactContext (Landroid/view/View;)Lcom/facebook/react/bridge/ReactContext;
|
||||
public static final fun getSurfaceId (Landroid/content/Context;)I
|
||||
public static final fun getSurfaceId (Landroid/view/View;)I
|
||||
public static final fun getUIManager (Lcom/facebook/react/bridge/ReactContext;I)Lcom/facebook/react/bridge/UIManager;
|
||||
public static final fun getUIManagerForReactTag (Lcom/facebook/react/bridge/ReactContext;I)Lcom/facebook/react/bridge/UIManager;
|
||||
public fun <init> ()V
|
||||
public static fun getDefaultTextInputPadding (Landroid/content/Context;)[F
|
||||
public static fun getEventDispatcher (Lcom/facebook/react/bridge/ReactContext;I)Lcom/facebook/react/uimanager/events/EventDispatcher;
|
||||
public static fun getEventDispatcherForReactTag (Lcom/facebook/react/bridge/ReactContext;I)Lcom/facebook/react/uimanager/events/EventDispatcher;
|
||||
public static fun getReactContext (Landroid/view/View;)Lcom/facebook/react/bridge/ReactContext;
|
||||
public static fun getSurfaceId (Landroid/content/Context;)I
|
||||
public static fun getSurfaceId (Landroid/view/View;)I
|
||||
public static fun getUIManager (Lcom/facebook/react/bridge/ReactContext;I)Lcom/facebook/react/bridge/UIManager;
|
||||
public static fun getUIManagerForReactTag (Lcom/facebook/react/bridge/ReactContext;I)Lcom/facebook/react/bridge/UIManager;
|
||||
}
|
||||
|
||||
public class com/facebook/react/uimanager/UIManagerModule : com/facebook/react/bridge/ReactContextBaseJavaModule, com/facebook/react/bridge/LifecycleEventListener, com/facebook/react/bridge/OnBatchCompleteListener, com/facebook/react/bridge/UIManager {
|
||||
@@ -4867,6 +4880,20 @@ public abstract interface class com/facebook/react/uimanager/events/EventDispatc
|
||||
public abstract fun removeListener (Lcom/facebook/react/uimanager/events/EventDispatcherListener;)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/uimanager/events/EventDispatcherImpl : com/facebook/react/bridge/LifecycleEventListener, com/facebook/react/uimanager/events/EventDispatcher {
|
||||
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;)V
|
||||
public fun addBatchEventDispatchedListener (Lcom/facebook/react/uimanager/events/BatchEventDispatchedListener;)V
|
||||
public fun addListener (Lcom/facebook/react/uimanager/events/EventDispatcherListener;)V
|
||||
public fun dispatchAllEvents ()V
|
||||
public fun dispatchEvent (Lcom/facebook/react/uimanager/events/Event;)V
|
||||
public fun onCatalystInstanceDestroyed ()V
|
||||
public fun onHostDestroy ()V
|
||||
public fun onHostPause ()V
|
||||
public fun onHostResume ()V
|
||||
public fun removeBatchEventDispatchedListener (Lcom/facebook/react/uimanager/events/BatchEventDispatchedListener;)V
|
||||
public fun removeListener (Lcom/facebook/react/uimanager/events/EventDispatcherListener;)V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/uimanager/events/EventDispatcherListener {
|
||||
public abstract fun onEventDispatch (Lcom/facebook/react/uimanager/events/Event;)V
|
||||
}
|
||||
@@ -4877,6 +4904,32 @@ public final class com/facebook/react/uimanager/events/NativeGestureUtil {
|
||||
public static final fun notifyNativeGestureStarted (Landroid/view/View;Landroid/view/MotionEvent;)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/uimanager/events/PointerEvent : com/facebook/react/uimanager/events/Event {
|
||||
public fun dispatch (Lcom/facebook/react/uimanager/events/RCTEventEmitter;)V
|
||||
public fun dispatchModern (Lcom/facebook/react/uimanager/events/RCTModernEventEmitter;)V
|
||||
public fun getCoalescingKey ()S
|
||||
public fun getEventAnimationDriverMatchSpec ()Lcom/facebook/react/uimanager/events/Event$EventAnimationDriverMatchSpec;
|
||||
public fun getEventName ()Ljava/lang/String;
|
||||
public static fun obtain (Ljava/lang/String;ILcom/facebook/react/uimanager/events/PointerEvent$PointerEventState;Landroid/view/MotionEvent;)Lcom/facebook/react/uimanager/events/PointerEvent;
|
||||
public static fun obtain (Ljava/lang/String;ILcom/facebook/react/uimanager/events/PointerEvent$PointerEventState;Landroid/view/MotionEvent;S)Lcom/facebook/react/uimanager/events/PointerEvent;
|
||||
public fun onDispose ()V
|
||||
}
|
||||
|
||||
public class com/facebook/react/uimanager/events/PointerEvent$PointerEventState {
|
||||
public fun <init> (IIIILjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Set;)V
|
||||
public fun getActivePointerId ()I
|
||||
public final fun getEventCoordinatesByPointerId ()Ljava/util/Map;
|
||||
public final fun getHitPathByPointerId ()Ljava/util/Map;
|
||||
public final fun getHitPathForActivePointer ()Ljava/util/List;
|
||||
public fun getHoveringPointerIds ()Ljava/util/Set;
|
||||
public fun getLastButtonState ()I
|
||||
public final fun getOffsetByPointerId ()Ljava/util/Map;
|
||||
public fun getPrimaryPointerId ()I
|
||||
public final fun getScreenCoordinatesByPointerId ()Ljava/util/Map;
|
||||
public fun getSurfaceId ()I
|
||||
public fun supportsHover (I)Z
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/uimanager/events/RCTEventEmitter : com/facebook/react/bridge/JavaScriptModule {
|
||||
public abstract fun receiveEvent (ILjava/lang/String;Lcom/facebook/react/bridge/WritableMap;)V
|
||||
public abstract fun receiveTouches (Ljava/lang/String;Lcom/facebook/react/bridge/WritableArray;Lcom/facebook/react/bridge/WritableArray;)V
|
||||
@@ -5283,16 +5336,6 @@ public abstract interface class com/facebook/react/viewmanagers/UnimplementedNat
|
||||
public abstract fun setName (Landroid/view/View;Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/viewmanagers/VirtualViewManagerDelegate : com/facebook/react/uimanager/BaseViewManagerDelegate {
|
||||
public fun <init> (Lcom/facebook/react/uimanager/BaseViewManager;)V
|
||||
public fun setProperty (Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/viewmanagers/VirtualViewManagerInterface : com/facebook/react/uimanager/ViewManagerWithGeneratedInterface {
|
||||
public abstract fun setInitialHidden (Landroid/view/View;Z)V
|
||||
public abstract fun setRenderState (Landroid/view/View;I)V
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/drawer/ReactDrawerLayout : androidx/drawerlayout/widget/DrawerLayout {
|
||||
public fun <init> (Lcom/facebook/react/bridge/ReactContext;)V
|
||||
public fun onInterceptTouchEvent (Landroid/view/MotionEvent;)Z
|
||||
@@ -6120,17 +6163,16 @@ public final class com/facebook/react/views/text/ReactFontManager$Companion {
|
||||
public final fun getInstance ()Lcom/facebook/react/views/text/ReactFontManager;
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/text/ReactTextShadowNode : com/facebook/react/views/text/ReactBaseTextShadowNode {
|
||||
public class com/facebook/react/views/text/ReactTextShadowNode : com/facebook/react/views/text/ReactBaseTextShadowNode {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lcom/facebook/react/views/text/ReactTextViewManagerCallback;)V
|
||||
public synthetic fun <init> (Lcom/facebook/react/views/text/ReactTextViewManagerCallback;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun calculateLayoutOnChildren ()Ljava/lang/Iterable;
|
||||
public fun hoistNativeChildren ()Z
|
||||
public fun isVirtualAnchor ()Z
|
||||
public fun markUpdated ()V
|
||||
public fun onBeforeLayout (Lcom/facebook/react/uimanager/NativeViewHierarchyOptimizer;)V
|
||||
public fun onCollectExtraUpdates (Lcom/facebook/react/uimanager/UIViewOperationQueue;)V
|
||||
public final fun setShouldNotifyOnTextLayout (Z)V
|
||||
public fun setShouldNotifyOnTextLayout (Z)V
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/text/ReactTextUpdate {
|
||||
|
||||
+3
-3
@@ -37,15 +37,15 @@ public class MemoryPressureRouter(context: Context) : ComponentCallbacks2 {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
public override fun onTrimMemory(level: Int) {
|
||||
override public fun onTrimMemory(level: Int) {
|
||||
dispatchMemoryPressure(level)
|
||||
}
|
||||
|
||||
public override fun onConfigurationChanged(newConfig: Configuration): Unit = Unit
|
||||
override public fun onConfigurationChanged(newConfig: Configuration): Unit = Unit
|
||||
|
||||
@Deprecated(
|
||||
"onLowMemory is deprecated, use onTrimMemory instead.", ReplaceWith("onTrimMemory(level)"))
|
||||
public override fun onLowMemory(): Unit = Unit
|
||||
override public fun onLowMemory(): Unit = Unit
|
||||
|
||||
private fun dispatchMemoryPressure(level: Int) {
|
||||
for (listener in listeners) {
|
||||
|
||||
+460
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.annotations.DeprecatedInNewArchitecture;
|
||||
import com.facebook.react.devsupport.DoubleTapReloadRecognizer;
|
||||
import com.facebook.react.devsupport.ReleaseDevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.interfaces.fabric.ReactSurface;
|
||||
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A delegate for handling React Application support. This delegate is unaware whether it is used in
|
||||
* an {@link Activity} or a {@link android.app.Fragment}.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactDelegate {
|
||||
|
||||
private final Activity mActivity;
|
||||
|
||||
@Nullable private ReactRootView mReactRootView;
|
||||
|
||||
@Nullable private final String mMainComponentName;
|
||||
|
||||
@Nullable private Bundle mLaunchOptions;
|
||||
|
||||
@Nullable private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;
|
||||
|
||||
@Nullable private ReactNativeHost mReactNativeHost;
|
||||
|
||||
@Nullable private ReactHost mReactHost;
|
||||
|
||||
@Nullable private ReactSurface mReactSurface;
|
||||
|
||||
private boolean mFabricEnabled = ReactNativeNewArchitectureFeatureFlags.enableFabricRenderer();
|
||||
|
||||
/**
|
||||
* Do not use this constructor as it's not accounting for New Architecture at all. You should use
|
||||
* {@link ReactDelegate#ReactDelegate(Activity, ReactNativeHost, String, Bundle, boolean)} as it's
|
||||
* the constructor used for New Architecture.
|
||||
*
|
||||
* @deprecated Use one of the other constructors instead to account for New Architecture.
|
||||
*/
|
||||
@Deprecated(since = "0.75.0")
|
||||
public ReactDelegate(
|
||||
Activity activity,
|
||||
@Nullable ReactNativeHost reactNativeHost,
|
||||
@Nullable String appKey,
|
||||
@Nullable Bundle launchOptions) {
|
||||
mActivity = activity;
|
||||
mMainComponentName = appKey;
|
||||
mLaunchOptions = launchOptions;
|
||||
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
|
||||
mReactNativeHost = reactNativeHost;
|
||||
}
|
||||
|
||||
public ReactDelegate(
|
||||
Activity activity,
|
||||
@Nullable ReactHost reactHost,
|
||||
@Nullable String appKey,
|
||||
@Nullable Bundle launchOptions) {
|
||||
mActivity = activity;
|
||||
mMainComponentName = appKey;
|
||||
mLaunchOptions = launchOptions;
|
||||
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
|
||||
mReactHost = reactHost;
|
||||
}
|
||||
|
||||
@Deprecated(since = "0.81.0")
|
||||
public ReactDelegate(
|
||||
Activity activity,
|
||||
@Nullable ReactNativeHost reactNativeHost,
|
||||
@Nullable String appKey,
|
||||
@Nullable Bundle launchOptions,
|
||||
boolean fabricEnabled) {
|
||||
mFabricEnabled = fabricEnabled;
|
||||
mActivity = activity;
|
||||
mMainComponentName = appKey;
|
||||
mLaunchOptions = launchOptions;
|
||||
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
|
||||
mReactNativeHost = reactNativeHost;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private DevSupportManager getDevSupportManager() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null
|
||||
&& mReactHost.getDevSupportManager() != null) {
|
||||
return mReactHost.getDevSupportManager();
|
||||
} else if (getReactNativeHost() != null
|
||||
&& getReactNativeHost().hasInstance()
|
||||
&& getReactNativeHost().getReactInstanceManager() != null) {
|
||||
return getReactNativeHost().getReactInstanceManager().getDevSupportManager();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void onHostResume() {
|
||||
if (!(mActivity instanceof DefaultHardwareBackBtnHandler)) {
|
||||
throw new ClassCastException(
|
||||
"Host Activity does not implement DefaultHardwareBackBtnHandler");
|
||||
}
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onHostResume(mActivity, (DefaultHardwareBackBtnHandler) mActivity);
|
||||
} else {
|
||||
ReactNativeHost reactNativeHost = getReactNativeHost();
|
||||
if (reactNativeHost != null && reactNativeHost.hasInstance()) {
|
||||
reactNativeHost
|
||||
.getReactInstanceManager()
|
||||
.onHostResume(mActivity, (DefaultHardwareBackBtnHandler) mActivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onUserLeaveHint() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onHostLeaveHint(mActivity);
|
||||
} else {
|
||||
ReactNativeHost reactNativeHost = getReactNativeHost();
|
||||
if (reactNativeHost != null && reactNativeHost.hasInstance()) {
|
||||
reactNativeHost.getReactInstanceManager().onUserLeaveHint(mActivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onHostPause() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onHostPause(mActivity);
|
||||
} else {
|
||||
ReactNativeHost reactNativeHost = getReactNativeHost();
|
||||
if (reactNativeHost != null && reactNativeHost.hasInstance()) {
|
||||
reactNativeHost.getReactInstanceManager().onHostPause(mActivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onHostDestroy() {
|
||||
unloadApp();
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onHostDestroy(mActivity);
|
||||
} else {
|
||||
ReactNativeHost reactNativeHost = getReactNativeHost();
|
||||
if (reactNativeHost != null && reactNativeHost.hasInstance()) {
|
||||
reactNativeHost.getReactInstanceManager().onHostDestroy(mActivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onBackPressed() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onBackPressed();
|
||||
return true;
|
||||
} else {
|
||||
ReactNativeHost reactNativeHost = getReactNativeHost();
|
||||
if (reactNativeHost != null && reactNativeHost.hasInstance()) {
|
||||
reactNativeHost.getReactInstanceManager().onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onNewIntent(Intent intent) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onNewIntent(intent);
|
||||
return true;
|
||||
} else {
|
||||
ReactNativeHost reactNativeHost = getReactNativeHost();
|
||||
if (reactNativeHost != null && reactNativeHost.hasInstance()) {
|
||||
reactNativeHost.getReactInstanceManager().onNewIntent(intent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onActivityResult(
|
||||
int requestCode,
|
||||
int resultCode,
|
||||
@Nullable Intent data,
|
||||
boolean shouldForwardToReactInstance) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onActivityResult(mActivity, requestCode, resultCode, data);
|
||||
} else {
|
||||
ReactNativeHost reactNativeHost = getReactNativeHost();
|
||||
if (reactNativeHost != null
|
||||
&& reactNativeHost.hasInstance()
|
||||
&& shouldForwardToReactInstance) {
|
||||
reactNativeHost
|
||||
.getReactInstanceManager()
|
||||
.onActivityResult(mActivity, requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onWindowFocusChange(hasFocus);
|
||||
} else {
|
||||
if (getReactNativeHost() != null && getReactNativeHost().hasInstance()) {
|
||||
getReactNativeHost().getReactInstanceManager().onWindowFocusChange(hasFocus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
mReactHost.onConfigurationChanged(Assertions.assertNotNull(mActivity));
|
||||
} else {
|
||||
if (getReactNativeHost() != null && getReactNativeHost().hasInstance()) {
|
||||
getReactInstanceManager()
|
||||
.onConfigurationChanged(Assertions.assertNotNull(mActivity), newConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
|
||||
&& ((ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null
|
||||
&& mReactHost.getDevSupportManager() != null)
|
||||
|| (getReactNativeHost() != null
|
||||
&& getReactNativeHost().hasInstance()
|
||||
&& getReactNativeHost().getUseDeveloperSupport()))) {
|
||||
event.startTracking();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onKeyLongPress(int keyCode) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()
|
||||
&& mReactHost != null) {
|
||||
DevSupportManager devSupportManager = mReactHost.getDevSupportManager();
|
||||
// onKeyLongPress is a Dev API and not supported in RELEASE mode.
|
||||
if (devSupportManager != null && !(devSupportManager instanceof ReleaseDevSupportManager)) {
|
||||
devSupportManager.showDevOptionsDialog();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
ReactNativeHost reactNativeHost = getReactNativeHost();
|
||||
if (reactNativeHost != null
|
||||
&& reactNativeHost.hasInstance()
|
||||
&& reactNativeHost.getUseDeveloperSupport()) {
|
||||
reactNativeHost.getReactInstanceManager().showDevOptionsDialog();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
DevSupportManager devSupportManager = getDevSupportManager();
|
||||
if (devSupportManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reload in RELEASE mode
|
||||
if (devSupportManager instanceof ReleaseDevSupportManager) {
|
||||
// Do not reload the bundle from JS as there is no bundler running in release mode.
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
if (mReactHost != null) {
|
||||
mReactHost.reload("ReactDelegate.reload()");
|
||||
}
|
||||
} else {
|
||||
UiThreadUtil.runOnUiThread(
|
||||
() -> {
|
||||
if (mReactNativeHost != null
|
||||
&& mReactNativeHost.hasInstance()
|
||||
&& mReactNativeHost.getReactInstanceManager() != null) {
|
||||
mReactNativeHost.getReactInstanceManager().recreateReactContextInBackground();
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Reload in DEBUG mode
|
||||
devSupportManager.handleReloadJS();
|
||||
}
|
||||
|
||||
/** Start the React surface with the app key supplied in the {@link ReactDelegate} constructor. */
|
||||
public void loadApp() {
|
||||
if (mMainComponentName == null) {
|
||||
throw new IllegalStateException("Cannot loadApp without a main component name.");
|
||||
} else {
|
||||
loadApp(mMainComponentName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the React surface for the given app key.
|
||||
*
|
||||
* @param appKey The ID of the app to load into the surface.
|
||||
*/
|
||||
public void loadApp(String appKey) {
|
||||
// With Bridgeless enabled, create and start the surface
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
if (mReactSurface == null && mReactHost != null) {
|
||||
mReactSurface = mReactHost.createSurface(mActivity, appKey, mLaunchOptions);
|
||||
}
|
||||
Objects.requireNonNull(mReactSurface).start();
|
||||
} else {
|
||||
if (mReactRootView != null) {
|
||||
throw new IllegalStateException("Cannot loadApp while app is already running.");
|
||||
}
|
||||
mReactRootView = createRootView();
|
||||
if (getReactNativeHost() != null) {
|
||||
mReactRootView.startReactApplication(
|
||||
getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop the React surface started with {@link ReactDelegate#loadApp()}. */
|
||||
public void unloadApp() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
if (mReactSurface != null) {
|
||||
mReactSurface.stop();
|
||||
mReactSurface = null;
|
||||
}
|
||||
} else {
|
||||
if (mReactRootView != null) {
|
||||
mReactRootView.unmountReactApplication();
|
||||
mReactRootView = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setReactSurface(ReactSurface reactSurface) {
|
||||
mReactSurface = reactSurface;
|
||||
}
|
||||
|
||||
public void setReactRootView(ReactRootView reactRootView) {
|
||||
mReactRootView = reactRootView;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ReactRootView getReactRootView() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
if (mReactSurface != null) {
|
||||
return (ReactRootView) mReactSurface.getView();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return mReactRootView;
|
||||
}
|
||||
}
|
||||
|
||||
// Not used in bridgeless
|
||||
protected ReactRootView createRootView() {
|
||||
ReactRootView reactRootView = new ReactRootView(mActivity);
|
||||
reactRootView.setIsFabric(isFabricEnabled());
|
||||
return reactRootView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles delegating the {@link Activity#onKeyUp(int, KeyEvent)} method to determine whether the
|
||||
* application should show the developer menu or should reload the React Application.
|
||||
*
|
||||
* @return true if we consume the event and either shoed the develop menu or reloaded the
|
||||
* application.
|
||||
*/
|
||||
public boolean shouldShowDevMenuOrReload(int keyCode, KeyEvent event) {
|
||||
DevSupportManager devSupportManager = getDevSupportManager();
|
||||
// shouldShowDevMenuOrReload is a Dev API and not supported in RELEASE mode.
|
||||
if (devSupportManager == null || devSupportManager instanceof ReleaseDevSupportManager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
devSupportManager.showDevOptionsDialog();
|
||||
return true;
|
||||
}
|
||||
boolean didDoubleTapR =
|
||||
Objects.requireNonNull(mDoubleTapReloadRecognizer)
|
||||
.didDoubleTapR(keyCode, mActivity.getCurrentFocus());
|
||||
if (didDoubleTapR) {
|
||||
devSupportManager.handleReloadJS();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Get the {@link ReactNativeHost} used by this app. */
|
||||
@DeprecatedInNewArchitecture(message = "Use getReactHost()")
|
||||
private @Nullable ReactNativeHost getReactNativeHost() {
|
||||
return mReactNativeHost;
|
||||
}
|
||||
|
||||
@DeprecatedInNewArchitecture(message = "Use getReactHost()")
|
||||
public ReactInstanceManager getReactInstanceManager() {
|
||||
if (getReactNativeHost() == null) {
|
||||
throw new IllegalStateException("Cannot get ReactInstanceManager without a ReactNativeHost.");
|
||||
}
|
||||
return getReactNativeHost().getReactInstanceManager();
|
||||
}
|
||||
|
||||
public @Nullable ReactHost getReactHost() {
|
||||
return mReactHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current {@link ReactContext} from ReactHost or ReactInstanceManager
|
||||
*
|
||||
* <p>Do not store a reference to this, if the React instance is reloaded or destroyed, this
|
||||
* context will no longer be valid.
|
||||
*/
|
||||
public @Nullable ReactContext getCurrentReactContext() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
if (mReactHost != null) {
|
||||
return mReactHost.getCurrentReactContext();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return getReactInstanceManager().getCurrentReactContext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method if you wish to selectively toggle Fabric for a specific surface. This will
|
||||
* also control if Concurrent Root (React 18) should be enabled or not.
|
||||
*
|
||||
* @return true if Fabric is enabled for this Activity, false otherwise.
|
||||
*/
|
||||
protected boolean isFabricEnabled() {
|
||||
return mFabricEnabled;
|
||||
}
|
||||
}
|
||||
@@ -1,410 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
import com.facebook.react.bridge.UiThreadUtil.runOnUiThread
|
||||
import com.facebook.react.common.annotations.DeprecatedInNewArchitecture
|
||||
import com.facebook.react.devsupport.DoubleTapReloadRecognizer
|
||||
import com.facebook.react.devsupport.ReleaseDevSupportManager
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager
|
||||
import com.facebook.react.interfaces.fabric.ReactSurface
|
||||
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler
|
||||
|
||||
/**
|
||||
* A delegate for handling React Application support. This delegate is unaware whether it is used in
|
||||
* an [Activity] or a [android.app.Fragment].
|
||||
*/
|
||||
public open class ReactDelegate {
|
||||
private val activity: Activity
|
||||
private var internalReactRootView: ReactRootView? = null
|
||||
private val mainComponentName: String?
|
||||
private var launchOptions: Bundle?
|
||||
private var doubleTapReloadRecognizer: DoubleTapReloadRecognizer?
|
||||
private var reactNativeHost: ReactNativeHost? = null
|
||||
public var reactHost: ReactHost? = null
|
||||
private set
|
||||
|
||||
private var reactSurface: ReactSurface? = null
|
||||
|
||||
/**
|
||||
* Override this method if you wish to selectively toggle Fabric for a specific surface. This will
|
||||
* also control if Concurrent Root (React 18) should be enabled or not.
|
||||
*
|
||||
* @return true if Fabric is enabled for this Activity, false otherwise.
|
||||
*/
|
||||
protected var isFabricEnabled: Boolean =
|
||||
ReactNativeNewArchitectureFeatureFlags.enableFabricRenderer()
|
||||
private set
|
||||
|
||||
/**
|
||||
* Do not use this constructor as it's not accounting for New Architecture at all. You should use
|
||||
* [ReactDelegate(Activity, ReactNativeHost, String, Bundle, boolean)] as it's the constructor
|
||||
* used for New Architecture.
|
||||
*/
|
||||
@Deprecated(
|
||||
"Use one of the other constructors instead to account for New Architecture. Deprecated since 0.75.0")
|
||||
public constructor(
|
||||
activity: Activity,
|
||||
reactNativeHost: ReactNativeHost?,
|
||||
appKey: String?,
|
||||
launchOptions: Bundle?
|
||||
) {
|
||||
this.activity = activity
|
||||
mainComponentName = appKey
|
||||
this.launchOptions = launchOptions
|
||||
doubleTapReloadRecognizer = DoubleTapReloadRecognizer()
|
||||
this.reactNativeHost = reactNativeHost
|
||||
}
|
||||
|
||||
public constructor(
|
||||
activity: Activity,
|
||||
reactHost: ReactHost?,
|
||||
appKey: String?,
|
||||
launchOptions: Bundle?
|
||||
) {
|
||||
this.activity = activity
|
||||
mainComponentName = appKey
|
||||
this.launchOptions = launchOptions
|
||||
doubleTapReloadRecognizer = DoubleTapReloadRecognizer()
|
||||
this.reactHost = reactHost
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated since 0.81.0, use one of the other constructors instead.")
|
||||
public constructor(
|
||||
activity: Activity,
|
||||
reactNativeHost: ReactNativeHost?,
|
||||
appKey: String?,
|
||||
launchOptions: Bundle?,
|
||||
fabricEnabled: Boolean
|
||||
) {
|
||||
isFabricEnabled = fabricEnabled
|
||||
this.activity = activity
|
||||
mainComponentName = appKey
|
||||
this.launchOptions = launchOptions
|
||||
doubleTapReloadRecognizer = DoubleTapReloadRecognizer()
|
||||
this.reactNativeHost = reactNativeHost
|
||||
}
|
||||
|
||||
private val devSupportManager: DevSupportManager?
|
||||
get() =
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost?.devSupportManager != null) {
|
||||
reactHost?.devSupportManager
|
||||
} else if (reactNativeHost?.hasInstance() == true &&
|
||||
reactNativeHost?.reactInstanceManager != null) {
|
||||
reactNativeHost?.reactInstanceManager?.devSupportManager
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
public fun onHostResume() {
|
||||
if (activity !is DefaultHardwareBackBtnHandler) {
|
||||
throw ClassCastException(
|
||||
"Host Activity `${activity.javaClass.simpleName}` does not implement DefaultHardwareBackBtnHandler")
|
||||
}
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
reactHost?.onHostResume(activity, activity as DefaultHardwareBackBtnHandler)
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true) {
|
||||
reactNativeHost
|
||||
?.reactInstanceManager
|
||||
?.onHostResume(activity, activity as DefaultHardwareBackBtnHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun onUserLeaveHint() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
reactHost?.onHostLeaveHint(activity)
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true) {
|
||||
reactNativeHost?.reactInstanceManager?.onUserLeaveHint(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun onHostPause() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
reactHost?.onHostPause(activity)
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true) {
|
||||
reactNativeHost?.reactInstanceManager?.onHostPause(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun onHostDestroy() {
|
||||
unloadApp()
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
reactHost?.onHostDestroy(activity)
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true) {
|
||||
reactNativeHost?.reactInstanceManager?.onHostDestroy(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun onBackPressed(): Boolean {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
reactHost?.onBackPressed()
|
||||
return true
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true) {
|
||||
reactNativeHost?.reactInstanceManager?.onBackPressed()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public fun onNewIntent(intent: Intent): Boolean {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
reactHost?.onNewIntent(intent)
|
||||
return true
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true) {
|
||||
reactNativeHost?.reactInstanceManager?.onNewIntent(intent)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public fun onActivityResult(
|
||||
requestCode: Int,
|
||||
resultCode: Int,
|
||||
data: Intent?,
|
||||
shouldForwardToReactInstance: Boolean
|
||||
) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null &&
|
||||
shouldForwardToReactInstance) {
|
||||
reactHost?.onActivityResult(activity, requestCode, resultCode, data)
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true && shouldForwardToReactInstance) {
|
||||
reactNativeHost
|
||||
?.reactInstanceManager
|
||||
?.onActivityResult(activity, requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
reactHost?.onWindowFocusChange(hasFocus)
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true) {
|
||||
reactNativeHost?.reactInstanceManager?.onWindowFocusChange(hasFocus)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun onConfigurationChanged(newConfig: Configuration?) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
reactHost?.onConfigurationChanged(checkNotNull(activity))
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true) {
|
||||
getReactInstanceManager().onConfigurationChanged(checkNotNull(activity), newConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD &&
|
||||
((ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost?.devSupportManager != null) ||
|
||||
(reactNativeHost?.hasInstance() == true &&
|
||||
reactNativeHost?.useDeveloperSupport == true))) {
|
||||
event.startTracking()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public fun onKeyLongPress(keyCode: Int): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture() &&
|
||||
reactHost != null) {
|
||||
val devSupportManager = reactHost?.devSupportManager
|
||||
// onKeyLongPress is a Dev API and not supported in RELEASE mode.
|
||||
if (devSupportManager != null && devSupportManager !is ReleaseDevSupportManager) {
|
||||
devSupportManager.showDevOptionsDialog()
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if (reactNativeHost?.hasInstance() == true &&
|
||||
reactNativeHost?.useDeveloperSupport == true) {
|
||||
reactNativeHost?.reactInstanceManager?.showDevOptionsDialog()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public fun reload() {
|
||||
val devSupportManager = devSupportManager ?: return
|
||||
|
||||
// Reload in RELEASE mode
|
||||
if (devSupportManager is ReleaseDevSupportManager) {
|
||||
// Do not reload the bundle from JS as there is no bundler running in release mode.
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
reactHost?.reload("ReactDelegate.reload()")
|
||||
} else {
|
||||
runOnUiThread {
|
||||
if (reactNativeHost?.hasInstance() == true &&
|
||||
reactNativeHost?.reactInstanceManager != null) {
|
||||
reactNativeHost?.reactInstanceManager?.recreateReactContextInBackground()
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Reload in DEBUG mode
|
||||
devSupportManager.handleReloadJS()
|
||||
}
|
||||
|
||||
/** Start the React surface with the app key supplied in the [ReactDelegate] constructor. */
|
||||
public fun loadApp() {
|
||||
val name = requireNotNull(mainComponentName) { "Cannot loadApp without a main component name." }
|
||||
loadApp(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the React surface for the given app key.
|
||||
*
|
||||
* @param appKey The ID of the app to load into the surface.
|
||||
*/
|
||||
public fun loadApp(appKey: String) {
|
||||
// With Bridgeless enabled, create and start the surface
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
val reactHost = reactHost
|
||||
if (reactSurface == null && reactHost != null) {
|
||||
reactSurface = reactHost.createSurface(activity, appKey, launchOptions)
|
||||
}
|
||||
reactSurface?.start()
|
||||
} else {
|
||||
check(internalReactRootView == null) { "Cannot loadApp while app is already running." }
|
||||
internalReactRootView = createRootView()
|
||||
if (reactNativeHost != null) {
|
||||
internalReactRootView?.startReactApplication(
|
||||
reactNativeHost?.reactInstanceManager, appKey, launchOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop the React surface started with [ReactDelegate.loadApp]. */
|
||||
public fun unloadApp() {
|
||||
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
reactSurface?.stop()
|
||||
reactSurface = null
|
||||
} else {
|
||||
if (internalReactRootView != null) {
|
||||
internalReactRootView?.unmountReactApplication()
|
||||
internalReactRootView = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun setReactSurface(reactSurface: ReactSurface?) {
|
||||
this.reactSurface = reactSurface
|
||||
}
|
||||
|
||||
public var reactRootView: ReactRootView?
|
||||
get() {
|
||||
return if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
if (reactSurface != null) {
|
||||
reactSurface?.view as ReactRootView?
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
internalReactRootView
|
||||
}
|
||||
}
|
||||
set(reactRootView) {
|
||||
internalReactRootView = reactRootView
|
||||
}
|
||||
|
||||
// Not used in bridgeless
|
||||
protected open fun createRootView(): ReactRootView? {
|
||||
val reactRootView = ReactRootView(activity)
|
||||
reactRootView.setIsFabric(isFabricEnabled)
|
||||
return reactRootView
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles delegating the [Activity.onKeyUp] method to determine whether the application should
|
||||
* show the developer menu or should reload the React Application.
|
||||
*
|
||||
* @return true if we consume the event and either show the develop menu or reloaded the
|
||||
* application.
|
||||
*/
|
||||
public fun shouldShowDevMenuOrReload(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
val devSupportManager = devSupportManager
|
||||
// shouldShowDevMenuOrReload is a Dev API and not supported in RELEASE mode.
|
||||
if (devSupportManager == null || devSupportManager is ReleaseDevSupportManager) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
devSupportManager.showDevOptionsDialog()
|
||||
return true
|
||||
}
|
||||
val didDoubleTapR = doubleTapReloadRecognizer?.didDoubleTapR(keyCode, activity.currentFocus)
|
||||
if (didDoubleTapR == true) {
|
||||
devSupportManager.handleReloadJS()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@DeprecatedInNewArchitecture(message = "Use reactHost")
|
||||
public fun getReactInstanceManager(): ReactInstanceManager {
|
||||
val nonNullReactNativeHost =
|
||||
checkNotNull(reactNativeHost) {
|
||||
"Cannot get ReactInstanceManager without a ReactNativeHost."
|
||||
}
|
||||
return nonNullReactNativeHost.reactInstanceManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current [ReactContext] from [ReactHost] or [ReactInstanceManager]
|
||||
*
|
||||
* Do not store a reference to this, if the React instance is reloaded or destroyed, this context
|
||||
* will no longer be valid.
|
||||
*/
|
||||
public val currentReactContext: ReactContext?
|
||||
get() {
|
||||
return if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
|
||||
if (reactHost != null) {
|
||||
reactHost?.currentReactContext
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
getReactInstanceManager().currentReactContext
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -74,6 +74,7 @@ import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.SurfaceDelegateFactory;
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
|
||||
@@ -1118,6 +1119,7 @@ public class ReactInstanceManager {
|
||||
/**
|
||||
* @return current ReactApplicationContext
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public @Nullable ReactContext getCurrentReactContext() {
|
||||
synchronized (mReactContextLock) {
|
||||
return mCurrentReactContext;
|
||||
|
||||
+59
-45
@@ -80,7 +80,7 @@ import kotlin.concurrent.Volatile
|
||||
*/
|
||||
@OptIn(UnstableReactNativeAPI::class)
|
||||
@ReactModule(name = NativeAnimatedModuleSpec.NAME)
|
||||
public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
public class NativeAnimatedModule(reactContext: ReactApplicationContext?) :
|
||||
NativeAnimatedModuleSpec(reactContext), LifecycleEventListener, UIManagerListener {
|
||||
|
||||
// For `queueAndExecuteBatchedOperations`
|
||||
@@ -163,13 +163,12 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
// Due to a race condition, we manually "carry-over" a polled item from previous batch
|
||||
// instead of peeking the queue itself for consistency.
|
||||
// TODO(T112522554): Clean up the queue access
|
||||
val peekedOperation = peekedOperation
|
||||
if (peekedOperation != null) {
|
||||
if (peekedOperation.batchNumber > maxBatchNumber) {
|
||||
if (checkNotNull(peekedOperation).batchNumber > maxBatchNumber) {
|
||||
break
|
||||
}
|
||||
operations.add(peekedOperation)
|
||||
this.peekedOperation = null
|
||||
operations.add(checkNotNull(peekedOperation))
|
||||
peekedOperation = null
|
||||
}
|
||||
|
||||
val polledOperation =
|
||||
@@ -180,7 +179,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (polledOperation.batchNumber > maxBatchNumber) {
|
||||
// Because the operation is already retrieved from the queue, there's no way of placing it
|
||||
// back as the head element, so we remember it manually here
|
||||
this.peekedOperation = polledOperation
|
||||
peekedOperation = polledOperation
|
||||
break
|
||||
}
|
||||
operations.add(polledOperation)
|
||||
@@ -190,7 +189,8 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
}
|
||||
}
|
||||
|
||||
private val reactChoreographer: ReactChoreographer = ReactChoreographer.getInstance()
|
||||
private val animatedFrameCallback: GuardedFrameCallback
|
||||
private val reactChoreographer: ReactChoreographer? = ReactChoreographer.getInstance()
|
||||
|
||||
private val operations = ConcurrentOperationQueue()
|
||||
private val preOperations = ConcurrentOperationQueue()
|
||||
@@ -205,6 +205,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
|
||||
private var initializedForFabric = false
|
||||
private var initializedForNonFabric = false
|
||||
private var enqueuedAnimationOnFrame = false
|
||||
|
||||
@UIManagerType private var uiManagerType = UIManagerType.LEGACY
|
||||
private var numFabricAnimations = 0
|
||||
@@ -301,8 +302,8 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
}
|
||||
}
|
||||
|
||||
preOperations.executeBatch(batchNumber, nodesManager)
|
||||
operations.executeBatch(batchNumber, nodesManager)
|
||||
checkNotNull(preOperations).executeBatch(batchNumber, nodesManager)
|
||||
checkNotNull(operations).executeBatch(batchNumber, nodesManager)
|
||||
}
|
||||
|
||||
// For non-FabricUIManager only
|
||||
@@ -321,9 +322,11 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
// might be stripped out.
|
||||
val frameNo = currentBatchNumber++
|
||||
|
||||
val preOperationsUIBlock = UIBlock { preOperations.executeBatch(frameNo, nodesManager) }
|
||||
val preOperationsUIBlock = UIBlock {
|
||||
checkNotNull(preOperations).executeBatch(frameNo, nodesManager)
|
||||
}
|
||||
|
||||
val operationsUIBlock = UIBlock { operations.executeBatch(frameNo, nodesManager) }
|
||||
val operationsUIBlock = UIBlock { checkNotNull(operations).executeBatch(frameNo, nodesManager) }
|
||||
|
||||
assert(uiManager is UIManagerModule)
|
||||
val uiManagerModule = uiManager as UIManagerModule
|
||||
@@ -363,34 +366,41 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
nodesManagerRef.set(nodesManager)
|
||||
}
|
||||
|
||||
private var enqueuedAnimationOnFrame = false
|
||||
private val animatedFrameCallback =
|
||||
object : GuardedFrameCallback(reactContext) {
|
||||
override fun doFrameGuarded(frameTimeNanos: Long) {
|
||||
try {
|
||||
enqueuedAnimationOnFrame = false
|
||||
val nodesManager = nodesManager ?: return
|
||||
if (nodesManager.hasActiveAnimations()) {
|
||||
nodesManager.runUpdates(frameTimeNanos)
|
||||
}
|
||||
init {
|
||||
animatedFrameCallback =
|
||||
object : GuardedFrameCallback(checkNotNull(reactContext)) {
|
||||
override fun doFrameGuarded(frameTimeNanos: Long) {
|
||||
try {
|
||||
enqueuedAnimationOnFrame = false
|
||||
val nodesManager = nodesManager
|
||||
if (nodesManager?.hasActiveAnimations() == true) {
|
||||
nodesManager.runUpdates(frameTimeNanos)
|
||||
}
|
||||
// This is very unlikely to ever be hit.
|
||||
if (nodesManager == null || reactChoreographer == null) {
|
||||
return
|
||||
}
|
||||
|
||||
enqueueFrameCallback()
|
||||
} catch (ex: Exception) {
|
||||
throw RuntimeException(ex)
|
||||
enqueueFrameCallback()
|
||||
} catch (ex: Exception) {
|
||||
throw RuntimeException(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearFrameCallback() {
|
||||
reactChoreographer.removeFrameCallback(
|
||||
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, animatedFrameCallback)
|
||||
checkNotNull(reactChoreographer)
|
||||
.removeFrameCallback(
|
||||
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, animatedFrameCallback)
|
||||
enqueuedAnimationOnFrame = false
|
||||
}
|
||||
|
||||
private fun enqueueFrameCallback() {
|
||||
if (!enqueuedAnimationOnFrame) {
|
||||
reactChoreographer.postFrameCallback(
|
||||
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, animatedFrameCallback)
|
||||
checkNotNull(reactChoreographer)
|
||||
.postFrameCallback(
|
||||
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, animatedFrameCallback)
|
||||
enqueuedAnimationOnFrame = true
|
||||
}
|
||||
}
|
||||
@@ -421,9 +431,8 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
}
|
||||
|
||||
// Subscribe to UIManager (Fabric or non-Fabric) lifecycle events if we haven't yet
|
||||
val initialized =
|
||||
if (uiManagerType == UIManagerType.FABRIC) initializedForFabric else initializedForNonFabric
|
||||
if (initialized) {
|
||||
if (if (uiManagerType == UIManagerType.FABRIC) initializedForFabric
|
||||
else initializedForNonFabric) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -485,14 +494,16 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
override fun createAnimatedNode(tagDouble: Double, config: ReadableMap) {
|
||||
val tag = tagDouble.toInt()
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(NAME, "queue createAnimatedNode: $tag config: ${config.toHashMap()}")
|
||||
FLog.d(NAME, "queue createAnimatedNode: ${tag} config: ${config.toHashMap().toString()}")
|
||||
}
|
||||
|
||||
addOperation(
|
||||
object : UIThreadOperation() {
|
||||
override fun execute(animatedNodesManager: NativeAnimatedNodesManager) {
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(NAME, ("execute createAnimatedNode: $tag config: ${config.toHashMap()}"))
|
||||
FLog.d(
|
||||
NAME,
|
||||
("execute createAnimatedNode: ${tag} config: ${config.toHashMap().toString()}"))
|
||||
}
|
||||
animatedNodesManager.createAnimatedNode(tag, config)
|
||||
}
|
||||
@@ -502,14 +513,17 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
override fun updateAnimatedNodeConfig(tagDouble: Double, config: ReadableMap) {
|
||||
val tag = tagDouble.toInt()
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(NAME, "queue updateAnimatedNodeConfig: $tag config: ${config.toHashMap()}")
|
||||
FLog.d(
|
||||
NAME, "queue updateAnimatedNodeConfig: ${tag} config: ${config.toHashMap().toString()}")
|
||||
}
|
||||
|
||||
addOperation(
|
||||
object : UIThreadOperation() {
|
||||
override fun execute(animatedNodesManager: NativeAnimatedNodesManager) {
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(NAME, ("execute updateAnimatedNodeConfig: $tag config: ${config.toHashMap()}"))
|
||||
FLog.d(
|
||||
NAME,
|
||||
("execute updateAnimatedNodeConfig: ${tag} config: ${config.toHashMap().toString()}"))
|
||||
}
|
||||
animatedNodesManager.updateAnimatedNodeConfig(tag, config)
|
||||
}
|
||||
@@ -700,7 +714,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("execute connectAnimatedNodes: parent: $parentNodeTag child: $childNodeTag"))
|
||||
("execute connectAnimatedNodes: parent: ${parentNodeTag} child: ${childNodeTag}"))
|
||||
}
|
||||
animatedNodesManager.connectAnimatedNodes(parentNodeTag, childNodeTag)
|
||||
}
|
||||
@@ -720,7 +734,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("execute disconnectAnimatedNodes: parent: $parentNodeTag child: $childNodeTag"))
|
||||
("execute disconnectAnimatedNodes: parent: ${parentNodeTag} child: ${childNodeTag}"))
|
||||
}
|
||||
animatedNodesManager.disconnectAnimatedNodes(parentNodeTag, childNodeTag)
|
||||
}
|
||||
@@ -733,7 +747,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("queue connectAnimatedNodeToView: animatedNodeTag: $animatedNodeTag viewTag: $viewTag"))
|
||||
("queue connectAnimatedNodeToView: animatedNodeTag: ${animatedNodeTag} viewTag: ${viewTag}"))
|
||||
}
|
||||
|
||||
initializeLifecycleEventListenersForViewTag(viewTag)
|
||||
@@ -744,7 +758,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("execute connectAnimatedNodeToView: animatedNodeTag: $animatedNodeTag viewTag: $viewTag"))
|
||||
("execute connectAnimatedNodeToView: animatedNodeTag: ${animatedNodeTag} viewTag: ${viewTag}"))
|
||||
}
|
||||
animatedNodesManager.connectAnimatedNodeToView(animatedNodeTag, viewTag)
|
||||
}
|
||||
@@ -769,7 +783,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("execute disconnectAnimatedNodeFromView: $animatedNodeTag viewTag: $viewTag"))
|
||||
("execute disconnectAnimatedNodeFromView: ${animatedNodeTag} viewTag: ${viewTag}"))
|
||||
}
|
||||
animatedNodesManager.disconnectAnimatedNodeFromView(animatedNodeTag, viewTag)
|
||||
}
|
||||
@@ -802,7 +816,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("queue addAnimatedEventToView: $viewTag eventName: $eventName eventMapping: ${eventMapping.toHashMap()}"))
|
||||
("queue addAnimatedEventToView: ${viewTag} eventName: ${eventName} eventMapping: ${eventMapping.toHashMap().toString()}"))
|
||||
}
|
||||
|
||||
initializeLifecycleEventListenersForViewTag(viewTag)
|
||||
@@ -813,7 +827,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("execute addAnimatedEventToView: $viewTag eventName: $eventName eventMapping: ${eventMapping.toHashMap()}"))
|
||||
("execute addAnimatedEventToView: ${viewTag} eventName: ${eventName} eventMapping: ${eventMapping.toHashMap().toString()}"))
|
||||
}
|
||||
animatedNodesManager.addAnimatedEventToView(viewTag, eventName, eventMapping)
|
||||
}
|
||||
@@ -830,7 +844,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("queue removeAnimatedEventFromView: viewTag: $viewTag eventName: $eventName animatedValueTag: $animatedValueTag"))
|
||||
("queue removeAnimatedEventFromView: viewTag: ${viewTag} eventName: ${eventName} animatedValueTag: ${animatedValueTag}"))
|
||||
}
|
||||
|
||||
decrementInFlightAnimationsForViewTag(viewTag)
|
||||
@@ -841,7 +855,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
("execute removeAnimatedEventFromView: viewTag: $viewTag eventName: $eventName animatedValueTag: $animatedValueTag"))
|
||||
("execute removeAnimatedEventFromView: viewTag: ${viewTag} eventName: ${eventName} animatedValueTag: ${animatedValueTag}"))
|
||||
}
|
||||
animatedNodesManager.removeAnimatedEventFromView(viewTag, eventName, animatedValueTag)
|
||||
}
|
||||
|
||||
+3
-3
@@ -381,7 +381,7 @@ public class NativeAnimatedNodesManager(
|
||||
("connectAnimatedNodeToView: Animated node connected to view [${viewTag}] should be of type ${PropsAnimatedNode::class.java.name}"))
|
||||
}
|
||||
checkNotNull(reactApplicationContext) {
|
||||
("connectAnimatedNodeToView: Animated node could not be connected, no ReactApplicationContext: $viewTag")
|
||||
("connectAnimatedNodeToView: Animated node could not be connected, no ReactApplicationContext: ${viewTag}")
|
||||
}
|
||||
|
||||
val uiManager = UIManagerHelper.getUIManagerForReactTag(reactApplicationContext, viewTag)
|
||||
@@ -389,7 +389,7 @@ public class NativeAnimatedNodesManager(
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG,
|
||||
ReactNoCrashSoftException(
|
||||
("connectAnimatedNodeToView: Animated node could not be connected to UIManager - uiManager disappeared for tag: $viewTag")))
|
||||
("connectAnimatedNodeToView: Animated node could not be connected to UIManager - uiManager disappeared for tag: ${viewTag}")))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -751,7 +751,7 @@ public class NativeAnimatedNodesManager(
|
||||
val reason = if (cyclesDetected > 0) ("cycles ($cyclesDetected)") else "disconnected regions"
|
||||
val ex =
|
||||
IllegalStateException(
|
||||
("Looks like animated nodes graph has ${reason}, there are $activeNodesCount but toposort visited only $updatedNodesCount"))
|
||||
("Looks like animated nodes graph has ${reason}, there are ${activeNodesCount} but toposort visited only ${updatedNodesCount}"))
|
||||
if (eventListenerInitializedForFabric && cyclesDetected == 0) {
|
||||
// TODO T71377544: investigate these SoftExceptions and see if we can remove entirely
|
||||
// or fix the root cause
|
||||
|
||||
+2
-2
@@ -18,12 +18,12 @@ public open class BaseActivityEventListener : ActivityEventListener {
|
||||
ReplaceWith("onActivityResult(activity, requestCode, resultCode, data)"))
|
||||
public open fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent): Unit = Unit
|
||||
|
||||
public override fun onActivityResult(
|
||||
override public fun onActivityResult(
|
||||
activity: Activity,
|
||||
requestCode: Int,
|
||||
resultCode: Int,
|
||||
data: Intent?
|
||||
): Unit = Unit
|
||||
|
||||
public override fun onNewIntent(intent: Intent): Unit = Unit
|
||||
override public fun onNewIntent(intent: Intent): Unit = Unit
|
||||
}
|
||||
|
||||
+3
-2
@@ -9,6 +9,7 @@ package com.facebook.react.bridge
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfiguration
|
||||
import com.facebook.react.common.annotations.VisibleForTesting
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.internal.turbomodule.core.interfaces.TurboModuleRegistry
|
||||
import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder
|
||||
@@ -52,7 +53,7 @@ public interface CatalystInstance : MemoryPressureListener, JSInstance, JSBundle
|
||||
public val isDestroyed: Boolean
|
||||
|
||||
/** Initialize all the native modules */
|
||||
public fun initialize()
|
||||
@VisibleForTesting public fun initialize()
|
||||
|
||||
public val reactQueueConfiguration: ReactQueueConfiguration
|
||||
|
||||
@@ -89,7 +90,7 @@ public interface CatalystInstance : MemoryPressureListener, JSInstance, JSBundle
|
||||
/** This method registers the file path of an additional JS segment by its ID. */
|
||||
public fun registerSegment(segmentId: Int, path: String)
|
||||
|
||||
public fun setGlobalVariable(propName: String, jsonValue: String)
|
||||
@VisibleForTesting public fun setGlobalVariable(propName: String, jsonValue: String)
|
||||
|
||||
/**
|
||||
* Do not use this anymore. Use [runtimeExecutor] instead. Get the C pointer (as a long) to the
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ protected constructor(private val exceptionHandler: JSExceptionHandler) :
|
||||
protected constructor(reactContext: ReactContext) : this(reactContext.exceptionHandler)
|
||||
|
||||
@Deprecated("AsyncTask is deprecated.")
|
||||
protected final override fun doInBackground(vararg params: Params): Void? {
|
||||
override protected final fun doInBackground(vararg params: Params): Void? {
|
||||
try {
|
||||
doInBackgroundGuarded(*params)
|
||||
} catch (e: RuntimeException) {
|
||||
|
||||
+9
-8
@@ -134,14 +134,15 @@ public class JavaOnlyArray : ReadableArray, WritableArray {
|
||||
|
||||
override fun toString(): String = backingList.toString()
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
if (this === other) {
|
||||
true
|
||||
} else if (other == null || javaClass != other.javaClass) {
|
||||
false
|
||||
} else {
|
||||
backingList == (other as JavaOnlyArray).backingList
|
||||
}
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) {
|
||||
return true
|
||||
} else if (other == null || javaClass != other.javaClass) {
|
||||
return false
|
||||
} else {
|
||||
return backingList == (other as JavaOnlyArray).backingList
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = backingList.hashCode()
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import android.content.Context;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/**
|
||||
* A context wrapper that always wraps Android Application {@link Context} and {@link
|
||||
* CatalystInstance} by extending {@link ReactContext}
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public abstract class ReactApplicationContext extends ReactContext {
|
||||
// We want to wrap ApplicationContext, since there is no easy way to verify that application
|
||||
// context is passed as a param, we use {@link Context#getApplicationContext} to ensure that
|
||||
// the context we're wrapping is in fact an application context.
|
||||
public ReactApplicationContext(Context context) {
|
||||
super(context.getApplicationContext());
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge
|
||||
|
||||
import android.content.Context
|
||||
|
||||
/**
|
||||
* A context wrapper that always wraps Android Application [Context] and [CatalystInstance] by
|
||||
* extending [ReactContext].
|
||||
*/
|
||||
public abstract class ReactApplicationContext(context: Context) :
|
||||
// We want to wrap ApplicationContext, since there is no easy way to verify that application
|
||||
// context is passed as a param, we use [Context.getApplicationContext] to ensure that
|
||||
// the context we're wrapping is in fact an application context.
|
||||
ReactContext(context.applicationContext)
|
||||
+3
-3
@@ -79,10 +79,10 @@ public open class ReadableNativeMap protected constructor() : NativeMap(), Reada
|
||||
|
||||
private inline fun <reified T> getNullableValue(name: String, type: Class<T>): T? {
|
||||
val res = getNullableValue(name)
|
||||
return if (res == null) {
|
||||
null
|
||||
if (res == null) {
|
||||
return null
|
||||
} else {
|
||||
checkInstance(name, res, type)
|
||||
return checkInstance(name, res, type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -36,9 +36,9 @@ private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
public companion object {
|
||||
@JvmStatic
|
||||
fun create(
|
||||
public fun create(
|
||||
spec: ReactQueueConfigurationSpec,
|
||||
exceptionHandler: QueueThreadExceptionHandler
|
||||
): ReactQueueConfigurationImpl {
|
||||
|
||||
+1
-2
@@ -12,7 +12,6 @@ import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.abs
|
||||
|
||||
/** Listens for the user shaking their phone. Allocation-less once it starts listening. */
|
||||
public class ShakeDetector
|
||||
@@ -64,7 +63,7 @@ constructor(private val shakeListener: ShakeListener, private val minNumShakes:
|
||||
* @return true if the magnitude of the force exceeds the minimum required amount of force. false
|
||||
* otherwise.
|
||||
*/
|
||||
private fun atLeastRequiredForce(a: Float): Boolean = abs(a) > REQUIRED_FORCE
|
||||
private fun atLeastRequiredForce(a: Float): Boolean = Math.abs(a) > REQUIRED_FORCE
|
||||
|
||||
/**
|
||||
* Save data about last shake
|
||||
|
||||
+3
-1
@@ -465,7 +465,9 @@ public abstract class DevSupportManagerBase(
|
||||
devOptionsDialog?.show()
|
||||
|
||||
val reactContext = currentReactContext
|
||||
reactContext?.getJSModule(RCTNativeAppEventEmitter::class.java)?.emit("RCTDevMenuShown", null)
|
||||
if (reactContext != null) {
|
||||
reactContext.getJSModule(RCTNativeAppEventEmitter::class.java).emit("RCTDevMenuShown", null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewReactContextCreated(reactContext: ReactContext) {
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ internal class PackagerStatusCheck {
|
||||
if (PACKAGER_OK_STATUS != bodyString) {
|
||||
FLog.e(
|
||||
ReactConstants.TAG,
|
||||
"Got unexpected response from packager when requesting status: $bodyString")
|
||||
"Got unexpected response from packager when requesting status: ${bodyString}")
|
||||
callback.onPackagerStatusFetched(false)
|
||||
return
|
||||
}
|
||||
|
||||
+2
-2
@@ -1317,7 +1317,7 @@ public class FabricUIManager
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
@Override
|
||||
public void willMountItems(@Nullable List<? extends MountItem> mountItems) {
|
||||
public void willMountItems(@Nullable List<MountItem> mountItems) {
|
||||
for (UIManagerListener listener : mListeners) {
|
||||
listener.willMountItems(FabricUIManager.this);
|
||||
}
|
||||
@@ -1326,7 +1326,7 @@ public class FabricUIManager
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
@Override
|
||||
public void didMountItems(@Nullable List<? extends MountItem> mountItems) {
|
||||
public void didMountItems(@Nullable List<MountItem> mountItems) {
|
||||
for (UIManagerListener listener : mListeners) {
|
||||
listener.didMountItems(FabricUIManager.this);
|
||||
}
|
||||
|
||||
+5
-6
@@ -37,12 +37,11 @@ internal class LongStreamingStats {
|
||||
}
|
||||
|
||||
len++
|
||||
average =
|
||||
if (len == 1) {
|
||||
n.toDouble()
|
||||
} else {
|
||||
(average / (len / (len - 1))) + (n / len)
|
||||
}
|
||||
if (len == 1) {
|
||||
average = n.toDouble()
|
||||
} else {
|
||||
average = (average / (len / (len - 1))) + (n / len)
|
||||
}
|
||||
|
||||
max = (if (n > max) n else max)
|
||||
}
|
||||
|
||||
+410
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.fabric.mounting;
|
||||
|
||||
import static com.facebook.infer.annotation.ThreadConfined.UI;
|
||||
import static com.facebook.react.fabric.FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.infer.annotation.ThreadConfined;
|
||||
import com.facebook.react.bridge.ReactIgnorableMountingException;
|
||||
import com.facebook.react.bridge.ReactNoCrashSoftException;
|
||||
import com.facebook.react.bridge.ReactSoftExceptionLogger;
|
||||
import com.facebook.react.bridge.RetryableMountingLayerException;
|
||||
import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem;
|
||||
import com.facebook.react.fabric.mounting.mountitems.MountItem;
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
|
||||
import com.facebook.systrace.Systrace;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class MountItemDispatcher {
|
||||
|
||||
private static final String TAG = "MountItemDispatcher";
|
||||
|
||||
private static final long FRAME_TIME_NS = 1_000_000_000 / 60;
|
||||
|
||||
private final MountingManager mMountingManager;
|
||||
private final ItemDispatchListener mItemDispatchListener;
|
||||
|
||||
private final ConcurrentLinkedQueue<DispatchCommandMountItem> mViewCommandMountItems =
|
||||
new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final ConcurrentLinkedQueue<MountItem> mMountItems = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final ConcurrentLinkedQueue<MountItem> mPreMountItems = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private boolean mInDispatch = false;
|
||||
private long mBatchedExecutionTime = 0L;
|
||||
private long mRunStartTime = 0L;
|
||||
|
||||
private long mLastFrameTimeNanos = 0L;
|
||||
|
||||
public MountItemDispatcher(MountingManager mountingManager, ItemDispatchListener listener) {
|
||||
mMountingManager = mountingManager;
|
||||
mItemDispatchListener = listener;
|
||||
}
|
||||
|
||||
public void addViewCommandMountItem(DispatchCommandMountItem mountItem) {
|
||||
mViewCommandMountItems.add(mountItem);
|
||||
}
|
||||
|
||||
public void addMountItem(MountItem mountItem) {
|
||||
mMountItems.add(mountItem);
|
||||
}
|
||||
|
||||
public void addPreAllocateMountItem(MountItem mountItem) {
|
||||
// We do this check only for PreAllocateViewMountItem - and not DispatchMountItem or regular
|
||||
// MountItem - because PreAllocateViewMountItems are not batched, and is relatively more
|
||||
// expensive
|
||||
// both to queue, to drain, and to execute.
|
||||
if (!mMountingManager.surfaceIsStopped(mountItem.getSurfaceId())) {
|
||||
mPreMountItems.add(mountItem);
|
||||
} else if (IS_DEVELOPMENT_ENVIRONMENT) {
|
||||
FLog.e(
|
||||
TAG,
|
||||
"Not queueing PreAllocateMountItem: surfaceId stopped: [%d] - %s",
|
||||
mountItem.getSurfaceId(),
|
||||
mountItem.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to dispatch MountItems. In case of the exception, we will retry 10 times before giving up.
|
||||
*/
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
public void tryDispatchMountItems() {
|
||||
// If we're already dispatching, don't reenter.
|
||||
// Reentrance can potentially happen a lot on Android in Fabric because
|
||||
// `updateState` from the
|
||||
// mounting layer causes mount items to be dispatched synchronously. We want to 1) make sure
|
||||
// we don't reenter in those cases, but 2) still execute those queued instructions
|
||||
// synchronously.
|
||||
// This is a pretty blunt tool, but we might not have better options since we really don't want
|
||||
// to execute anything out-of-order.
|
||||
if (mInDispatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
mInDispatch = true;
|
||||
|
||||
try {
|
||||
dispatchMountItems();
|
||||
} finally {
|
||||
// Clean up after running dispatchMountItems - even if an exception was thrown
|
||||
mInDispatch = false;
|
||||
}
|
||||
|
||||
// We call didDispatchMountItems regardless of whether we actually dispatched anything, since
|
||||
// NativeAnimatedModule relies on this for executing any animations that may have been
|
||||
// scheduled
|
||||
mItemDispatchListener.didDispatchMountItems();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
public void dispatchMountItems(Queue<MountItem> mountItems) {
|
||||
while (!mountItems.isEmpty()) {
|
||||
MountItem item = mountItems.poll();
|
||||
Assertions.assertNotNull(item);
|
||||
try {
|
||||
item.execute(mMountingManager);
|
||||
} catch (RetryableMountingLayerException e) {
|
||||
if (item instanceof DispatchCommandMountItem) {
|
||||
// Only DispatchCommandMountItem supports retries
|
||||
DispatchCommandMountItem mountItem = (DispatchCommandMountItem) item;
|
||||
// Retrying exactly once
|
||||
if (mountItem.getRetries() == 0) {
|
||||
mountItem.incrementRetries();
|
||||
// In case we haven't retried executing this item yet, execute in the next batch of
|
||||
// items
|
||||
addViewCommandMountItem(mountItem);
|
||||
}
|
||||
} else {
|
||||
printMountItem(
|
||||
item, "dispatchExternalMountItems: mounting failed with " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Executes view commands, pre mount items and mount items in the respective order:
|
||||
* 1. View commands.
|
||||
* 2. Pre mount items.
|
||||
* 3. Regular mount items.
|
||||
*
|
||||
* Does nothing if `viewCommandMountItemsToDispatch` and `mountItemsToDispatch` are empty.
|
||||
* Nothing should call this directly except for `tryDispatchMountItems`.
|
||||
*/
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
private void dispatchMountItems() {
|
||||
mBatchedExecutionTime = 0;
|
||||
|
||||
mRunStartTime = SystemClock.uptimeMillis();
|
||||
|
||||
List<DispatchCommandMountItem> viewCommandMountItemsToDispatch =
|
||||
getAndResetViewCommandMountItems();
|
||||
List<MountItem> mountItemsToDispatch = getAndResetMountItems();
|
||||
|
||||
if (mountItemsToDispatch == null && viewCommandMountItemsToDispatch == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mItemDispatchListener.willMountItems(mountItemsToDispatch);
|
||||
|
||||
// As an optimization, execute all ViewCommands first
|
||||
// This should be:
|
||||
// 1) Performant: ViewCommands are often a replacement for SetNativeProps, which we've always
|
||||
// wanted to be as "synchronous" as possible.
|
||||
// 2) Safer: ViewCommands are inherently disconnected from the tree commit/diff/mount process.
|
||||
// JS imperatively queues these commands.
|
||||
// If JS has queued a command, it's reasonable to assume that the more time passes, the more
|
||||
// likely it is that the view disappears.
|
||||
// Thus, by executing ViewCommands early, we should actually avoid a category of
|
||||
// errors/glitches.
|
||||
if (viewCommandMountItemsToDispatch != null) {
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT, "MountItemDispatcher::mountViews viewCommandMountItems");
|
||||
for (DispatchCommandMountItem command : viewCommandMountItemsToDispatch) {
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
printMountItem(command, "dispatchMountItems: Executing viewCommandMountItem");
|
||||
}
|
||||
try {
|
||||
executeOrEnqueue(command);
|
||||
} catch (RetryableMountingLayerException e) {
|
||||
// If the exception is marked as Retryable, we retry the viewcommand exactly once, after
|
||||
// the current batch of mount items has finished executing.
|
||||
if (command.getRetries() == 0) {
|
||||
command.incrementRetries();
|
||||
addViewCommandMountItem(command);
|
||||
} else {
|
||||
// It's very common for commands to be executed on views that no longer exist - for
|
||||
// example, a blur event on TextInput being fired because of a navigation event away
|
||||
// from the current screen. If the exception is marked as Retryable, we log a soft
|
||||
// exception but never crash in debug.
|
||||
// It's not clear that logging this is even useful, because these events are very
|
||||
// common, mundane, and there's not much we can do about them currently.
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG,
|
||||
new ReactNoCrashSoftException(
|
||||
"Caught exception executing ViewCommand: " + command.toString(), e));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Non-Retryable exceptions are logged as soft exceptions in prod, but crash in Debug.
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG,
|
||||
new RuntimeException(
|
||||
"Caught exception executing ViewCommand: " + command.toString(), e));
|
||||
}
|
||||
}
|
||||
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT);
|
||||
}
|
||||
|
||||
// If there are MountItems to dispatch, we make sure all the "pre mount items" are executed
|
||||
// first
|
||||
List<MountItem> preMountItemsToDispatch = getAndResetPreMountItems();
|
||||
if (preMountItemsToDispatch != null) {
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT, "MountItemDispatcher::mountViews preMountItems");
|
||||
for (MountItem preMountItem : preMountItemsToDispatch) {
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
printMountItem(preMountItem, "dispatchMountItems: Executing preMountItem");
|
||||
}
|
||||
executeOrEnqueue(preMountItem);
|
||||
}
|
||||
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT);
|
||||
}
|
||||
|
||||
if (mountItemsToDispatch != null) {
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT, "MountItemDispatcher::mountViews mountItems to execute");
|
||||
|
||||
long batchedExecutionStartTime = SystemClock.uptimeMillis();
|
||||
|
||||
for (MountItem mountItem : mountItemsToDispatch) {
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
printMountItem(mountItem, "dispatchMountItems: Executing mountItem");
|
||||
}
|
||||
|
||||
try {
|
||||
executeOrEnqueue(mountItem);
|
||||
} catch (Throwable e) {
|
||||
// If there's an exception, we want to log diagnostics in prod and rethrow.
|
||||
FLog.e(TAG, "dispatchMountItems: caught exception, displaying mount state", e);
|
||||
for (MountItem m : mountItemsToDispatch) {
|
||||
if (m == mountItem) {
|
||||
// We want to mark the mount item that caused exception
|
||||
FLog.e(TAG, "dispatchMountItems: mountItem: next mountItem triggered exception!");
|
||||
}
|
||||
printMountItem(m, "dispatchMountItems: mountItem");
|
||||
}
|
||||
if (mountItem.getSurfaceId() != View.NO_ID) {
|
||||
SurfaceMountingManager surfaceManager =
|
||||
mMountingManager.getSurfaceManager(mountItem.getSurfaceId());
|
||||
if (surfaceManager != null) {
|
||||
surfaceManager.printSurfaceState();
|
||||
}
|
||||
}
|
||||
|
||||
if (ReactIgnorableMountingException.isIgnorable(e)) {
|
||||
ReactSoftExceptionLogger.logSoftException(TAG, e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
mBatchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime;
|
||||
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT);
|
||||
}
|
||||
|
||||
mItemDispatchListener.didMountItems(mountItemsToDispatch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Executes pre mount items. Pre mount items are operations that can be executed before the mount items come. For example view preallocation.
|
||||
* This is a performance optimisation to do as much work ahead of time as possible.
|
||||
*
|
||||
* `tryDispatchMountItems` will also execute pre mount items, but only if there are mount items to be executed.
|
||||
*/
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
public void dispatchPreMountItems(long frameTimeNanos) {
|
||||
mLastFrameTimeNanos = frameTimeNanos;
|
||||
|
||||
if (mPreMountItems.isEmpty()) {
|
||||
// Avoid starting systrace if there are no pre mount items.
|
||||
return;
|
||||
}
|
||||
|
||||
long deadline = mLastFrameTimeNanos + FRAME_TIME_NS / 2;
|
||||
dispatchPreMountItemsImpl(deadline);
|
||||
}
|
||||
|
||||
private void dispatchPreMountItemsImpl(long deadline) {
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT, "MountItemDispatcher::premountViews");
|
||||
|
||||
// dispatchPreMountItems cannot be reentrant, but we want to prevent dispatchMountItems from
|
||||
// reentering during dispatchPreMountItems
|
||||
mInDispatch = true;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
if (System.nanoTime() > deadline) {
|
||||
break;
|
||||
}
|
||||
|
||||
MountItem preMountItemToDispatch = mPreMountItems.poll();
|
||||
// If list is empty, `poll` will return null, or var will never be set
|
||||
if (preMountItemToDispatch == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
printMountItem(preMountItemToDispatch, "dispatchPreMountItems");
|
||||
}
|
||||
executeOrEnqueue(preMountItemToDispatch);
|
||||
}
|
||||
} finally {
|
||||
mInDispatch = false;
|
||||
}
|
||||
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT);
|
||||
}
|
||||
|
||||
private void executeOrEnqueue(MountItem item) {
|
||||
if (mMountingManager.isWaitingForViewAttach(item.getSurfaceId())) {
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
FLog.e(
|
||||
TAG,
|
||||
"executeOrEnqueue: Item execution delayed, surface %s is not ready yet",
|
||||
item.getSurfaceId());
|
||||
}
|
||||
SurfaceMountingManager surfaceMountingManager =
|
||||
mMountingManager.getSurfaceManagerEnforced(
|
||||
item.getSurfaceId(), "MountItemDispatcher::executeOrEnqueue");
|
||||
surfaceMountingManager.scheduleMountItemOnViewAttach(item);
|
||||
} else {
|
||||
item.execute(mMountingManager);
|
||||
}
|
||||
}
|
||||
|
||||
private static <E> @Nullable List<E> drainConcurrentItemQueue(ConcurrentLinkedQueue<E> queue) {
|
||||
if (queue.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
List<E> result = new ArrayList<>();
|
||||
do {
|
||||
E item = queue.poll();
|
||||
if (item != null) {
|
||||
result.add(item);
|
||||
}
|
||||
} while (!queue.isEmpty());
|
||||
if (result.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
private @Nullable List<DispatchCommandMountItem> getAndResetViewCommandMountItems() {
|
||||
return drainConcurrentItemQueue(mViewCommandMountItems);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
private @Nullable List<MountItem> getAndResetMountItems() {
|
||||
return drainConcurrentItemQueue(mMountItems);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
private @Nullable List<MountItem> getAndResetPreMountItems() {
|
||||
return drainConcurrentItemQueue(mPreMountItems);
|
||||
}
|
||||
|
||||
public long getBatchedExecutionTime() {
|
||||
return mBatchedExecutionTime;
|
||||
}
|
||||
|
||||
public long getRunStartTime() {
|
||||
return mRunStartTime;
|
||||
}
|
||||
|
||||
private static void printMountItem(MountItem mountItem, String prefix) {
|
||||
// If a MountItem description is split across multiple lines, it's because it's a
|
||||
// compound MountItem. Log each line separately.
|
||||
String[] mountItemLines = mountItem.toString().split("\n");
|
||||
for (String m : mountItemLines) {
|
||||
FLog.e(TAG, prefix + ": " + m);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ItemDispatchListener {
|
||||
void willMountItems(@Nullable List<MountItem> mountItems);
|
||||
|
||||
void didMountItems(@Nullable List<MountItem> mountItems);
|
||||
|
||||
void didDispatchMountItems();
|
||||
}
|
||||
}
|
||||
-365
@@ -1,365 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.fabric.mounting
|
||||
|
||||
import android.os.SystemClock
|
||||
import android.view.View
|
||||
import androidx.annotation.UiThread
|
||||
import com.facebook.common.logging.FLog
|
||||
import com.facebook.infer.annotation.ThreadConfined
|
||||
import com.facebook.infer.annotation.ThreadConfined.UI
|
||||
import com.facebook.react.bridge.ReactIgnorableMountingException
|
||||
import com.facebook.react.bridge.ReactNoCrashSoftException
|
||||
import com.facebook.react.bridge.ReactSoftExceptionLogger
|
||||
import com.facebook.react.bridge.RetryableMountingLayerException
|
||||
import com.facebook.react.fabric.FabricUIManager
|
||||
import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem
|
||||
import com.facebook.react.fabric.mounting.mountitems.MountItem
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
||||
import com.facebook.systrace.Systrace
|
||||
import java.util.Queue
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
internal class MountItemDispatcher(
|
||||
private val mountingManager: MountingManager,
|
||||
private val itemDispatchListener: ItemDispatchListener
|
||||
) {
|
||||
private val viewCommandMountItems: Queue<DispatchCommandMountItem> = ConcurrentLinkedQueue()
|
||||
private val mountItems: Queue<MountItem> = ConcurrentLinkedQueue()
|
||||
private val preMountItems: Queue<MountItem> = ConcurrentLinkedQueue()
|
||||
|
||||
private var inDispatch: Boolean = false
|
||||
var batchedExecutionTime: Long = 0L
|
||||
private set
|
||||
|
||||
var runStartTime: Long = 0L
|
||||
private set
|
||||
|
||||
private var lastFrameTimeNanos: Long = 0L
|
||||
|
||||
fun addViewCommandMountItem(mountItem: DispatchCommandMountItem) {
|
||||
viewCommandMountItems.add(mountItem)
|
||||
}
|
||||
|
||||
fun addMountItem(mountItem: MountItem) {
|
||||
mountItems.add(mountItem)
|
||||
}
|
||||
|
||||
fun addPreAllocateMountItem(mountItem: MountItem) {
|
||||
// We do this check only for PreAllocateViewMountItem - and not DispatchMountItem or regular
|
||||
// MountItem - because PreAllocateViewMountItems are not batched, and is relatively more
|
||||
// expensive
|
||||
// both to queue, to drain, and to execute.
|
||||
if (!mountingManager.surfaceIsStopped(mountItem.getSurfaceId())) {
|
||||
preMountItems.add(mountItem)
|
||||
} else if (FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT) {
|
||||
FLog.e(
|
||||
TAG,
|
||||
"Not queueing PreAllocateMountItem: surfaceId stopped: [%d] - %s",
|
||||
mountItem.getSurfaceId(),
|
||||
mountItem.toString())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to dispatch MountItems. In case of the exception, we will retry 10 times before giving up.
|
||||
*/
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
fun tryDispatchMountItems() {
|
||||
// If we're already dispatching, don't reenter.
|
||||
// Reentrance can potentially happen a lot on Android in Fabric because `updateState` from the
|
||||
// mounting layer causes mount items to be dispatched synchronously. We want to 1) make sure we
|
||||
// don't reenter in those cases, but 2) still execute those queued instructions synchronously.
|
||||
// This is a pretty blunt tool, but we might not have better options since we really don't want
|
||||
// to execute anything out-of-order.
|
||||
if (inDispatch) {
|
||||
return
|
||||
}
|
||||
|
||||
inDispatch = true
|
||||
|
||||
try {
|
||||
dispatchMountItems()
|
||||
} finally {
|
||||
// Clean up after running dispatchMountItems - even if an exception was thrown
|
||||
inDispatch = false
|
||||
}
|
||||
|
||||
// We call didDispatchMountItems regardless of whether we actually dispatched anything, since
|
||||
// NativeAnimatedModule relies on this for executing any animations that may have been
|
||||
// scheduled
|
||||
itemDispatchListener.didDispatchMountItems()
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
fun dispatchMountItems(mountItems: Queue<MountItem?>) {
|
||||
while (!mountItems.isEmpty()) {
|
||||
val item = requireNotNull(mountItems.poll()) { "MountItem should not be null" }
|
||||
try {
|
||||
item.execute(mountingManager)
|
||||
} catch (e: RetryableMountingLayerException) {
|
||||
if (item is DispatchCommandMountItem) {
|
||||
// Only DispatchCommandMountItem supports retries
|
||||
val mountItem: DispatchCommandMountItem = item as DispatchCommandMountItem
|
||||
// Retrying exactly once
|
||||
if (mountItem.getRetries() == 0) {
|
||||
mountItem.incrementRetries()
|
||||
// In case we haven't retried executing this item yet, execute in the next batch of
|
||||
// items
|
||||
addViewCommandMountItem(mountItem)
|
||||
}
|
||||
} else {
|
||||
printMountItem(item, "dispatchExternalMountItems: mounting failed with ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Executes view commands, pre mount items and mount items in the respective order:
|
||||
* 1. View commands.
|
||||
* 2. Pre mount items.
|
||||
* 3. Regular mount items.
|
||||
*
|
||||
* Does nothing if `viewCommandMountItemsToDispatch` and `mountItemsToDispatch` are empty.
|
||||
* Nothing should call this directly except for `tryDispatchMountItems`.
|
||||
*/
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
private fun dispatchMountItems() {
|
||||
batchedExecutionTime = 0
|
||||
runStartTime = SystemClock.uptimeMillis()
|
||||
|
||||
val viewCommandMountItemsToDispatch = getAndResetViewCommandMountItems()
|
||||
val mountItemsToDispatch = getAndResetMountItems()
|
||||
|
||||
if (mountItemsToDispatch == null && viewCommandMountItemsToDispatch == null) {
|
||||
return
|
||||
}
|
||||
|
||||
itemDispatchListener.willMountItems(mountItemsToDispatch)
|
||||
|
||||
// As an optimization, execute all ViewCommands first
|
||||
// This should be:
|
||||
// 1) Performant: ViewCommands are often a replacement for SetNativeProps, which we've always
|
||||
// wanted to be as "synchronous" as possible.
|
||||
// 2) Safer: ViewCommands are inherently disconnected from the tree commit/diff/mount process.
|
||||
// JS imperatively queues these commands.
|
||||
// If JS has queued a command, it's reasonable to assume that the more time passes, the more
|
||||
// likely it is that the view disappears.
|
||||
// Thus, by executing ViewCommands early, we should actually avoid a category of
|
||||
// errors/glitches.
|
||||
viewCommandMountItemsToDispatch?.let { commands ->
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT, "MountItemDispatcher::mountViews viewCommandMountItems")
|
||||
|
||||
for (command in commands) {
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
printMountItem(command, "dispatchMountItems: Executing viewCommandMountItem")
|
||||
}
|
||||
try {
|
||||
executeOrEnqueue(command)
|
||||
} catch (e: RetryableMountingLayerException) {
|
||||
// If the exception is marked as Retryable, we retry the viewcommand exactly once, after
|
||||
// the current batch of mount items has finished executing.
|
||||
if (command.getRetries() == 0) {
|
||||
command.incrementRetries()
|
||||
addViewCommandMountItem(command)
|
||||
} else {
|
||||
// It's very common for commands to be executed on views that no longer exist - for
|
||||
// example, a blur event on TextInput being fired because of a navigation event away
|
||||
// from the current screen. If the exception is marked as Retryable, we log a soft
|
||||
// exception but never crash in debug.
|
||||
// It's not clear that logging this is even useful, because these events are very
|
||||
// common, mundane, and there's not much we can do about them currently.
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG,
|
||||
ReactNoCrashSoftException("Caught exception executing ViewCommand: $command", e))
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
// Non-retryable exceptions are logged as soft exceptions in prod, but crash in Debug.
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG, RuntimeException("Caught exception executing ViewCommand: $command", e))
|
||||
}
|
||||
}
|
||||
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT)
|
||||
}
|
||||
|
||||
// If there are MountItems to dispatch, we make sure all the "pre mount items" are executed
|
||||
// first
|
||||
getAndResetPreMountItems()?.let { preMountItems ->
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT, "MountItemDispatcher::mountViews preMountItems")
|
||||
for (preMountItem in preMountItems) {
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
printMountItem(preMountItem, "dispatchMountItems: Executing preMountItem")
|
||||
}
|
||||
executeOrEnqueue(preMountItem)
|
||||
}
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT)
|
||||
}
|
||||
|
||||
mountItemsToDispatch?.let { items ->
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT, "MountItemDispatcher::mountViews mountItems to execute")
|
||||
val batchedExecutionStartTime = SystemClock.uptimeMillis()
|
||||
|
||||
for (mountItem in items) {
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
printMountItem(mountItem, "dispatchMountItems: Executing mountItem")
|
||||
}
|
||||
|
||||
try {
|
||||
executeOrEnqueue(mountItem)
|
||||
} catch (e: Throwable) {
|
||||
// If there's an exception, we want to log diagnostics in prod and rethrow.
|
||||
FLog.e(TAG, "dispatchMountItems: caught exception, displaying mount state", e)
|
||||
for (m in items) {
|
||||
if (m === mountItem) {
|
||||
// We want to mark the mount item that caused exception
|
||||
FLog.e(TAG, "dispatchMountItems: mountItem: next mountItem triggered exception!")
|
||||
}
|
||||
printMountItem(m, "dispatchMountItems: mountItem")
|
||||
}
|
||||
|
||||
if (mountItem.getSurfaceId() != View.NO_ID) {
|
||||
mountingManager.getSurfaceManager(mountItem.getSurfaceId())?.printSurfaceState()
|
||||
}
|
||||
|
||||
if (ReactIgnorableMountingException.isIgnorable(e)) {
|
||||
ReactSoftExceptionLogger.logSoftException(TAG, e)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
batchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT)
|
||||
}
|
||||
|
||||
itemDispatchListener.didMountItems(mountItemsToDispatch)
|
||||
}
|
||||
|
||||
/*
|
||||
* Executes pre-mount items. Pre-mount items are operations that can be executed before the mount
|
||||
* items come, for example view pre-allocation. This is a performance optimisation to do as much
|
||||
* work ahead of time as possible.
|
||||
*
|
||||
* `tryDispatchMountItems` will also execute pre mount items, but only if there are mount items to be executed.
|
||||
*/
|
||||
@UiThread
|
||||
@ThreadConfined(UI)
|
||||
fun dispatchPreMountItems(frameTimeNanos: Long) {
|
||||
lastFrameTimeNanos = frameTimeNanos
|
||||
|
||||
if (preMountItems.isEmpty()) {
|
||||
// Avoid starting systrace if there are no pre mount items.
|
||||
return
|
||||
}
|
||||
|
||||
val deadline = lastFrameTimeNanos + FRAME_TIME_NS / 2
|
||||
dispatchPreMountItemsImpl(deadline)
|
||||
}
|
||||
|
||||
private fun dispatchPreMountItemsImpl(deadline: Long) {
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT, "MountItemDispatcher::premountViews")
|
||||
|
||||
// dispatchPreMountItems cannot be reentrant, but we want to prevent dispatchMountItems from
|
||||
// reentering during dispatchPreMountItems
|
||||
inDispatch = true
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
if (System.nanoTime() > deadline) {
|
||||
break
|
||||
}
|
||||
|
||||
// If list is empty, `poll` will return null, or var will never be set
|
||||
val preMountItemToDispatch = preMountItems.poll() ?: break
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
printMountItem(preMountItemToDispatch, "dispatchPreMountItems")
|
||||
}
|
||||
executeOrEnqueue(preMountItemToDispatch)
|
||||
}
|
||||
} finally {
|
||||
inDispatch = false
|
||||
}
|
||||
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT)
|
||||
}
|
||||
|
||||
private fun executeOrEnqueue(item: MountItem) {
|
||||
if (mountingManager.isWaitingForViewAttach(item.getSurfaceId())) {
|
||||
if (ReactNativeFeatureFlags.enableFabricLogs()) {
|
||||
FLog.e(
|
||||
TAG,
|
||||
"executeOrEnqueue: Item execution delayed, surface %s is not ready yet",
|
||||
item.getSurfaceId())
|
||||
}
|
||||
val surfaceMountingManager: SurfaceMountingManager =
|
||||
mountingManager.getSurfaceManagerEnforced(
|
||||
item.getSurfaceId(), "MountItemDispatcher::executeOrEnqueue")
|
||||
surfaceMountingManager.scheduleMountItemOnViewAttach(item)
|
||||
} else {
|
||||
item.execute(mountingManager)
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadConfined(UI)
|
||||
@UiThread
|
||||
private fun getAndResetViewCommandMountItems(): List<DispatchCommandMountItem>? =
|
||||
drainConcurrentItemQueue(viewCommandMountItems)
|
||||
|
||||
@ThreadConfined(UI)
|
||||
@UiThread
|
||||
private fun getAndResetMountItems(): List<MountItem>? = drainConcurrentItemQueue(mountItems)
|
||||
|
||||
@ThreadConfined(UI)
|
||||
@UiThread
|
||||
private fun getAndResetPreMountItems(): List<MountItem>? = drainConcurrentItemQueue(preMountItems)
|
||||
|
||||
interface ItemDispatchListener {
|
||||
fun willMountItems(mountItems: List<MountItem>?)
|
||||
|
||||
fun didMountItems(mountItems: List<MountItem>?)
|
||||
|
||||
fun didDispatchMountItems()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TAG: String = "MountItemDispatcher"
|
||||
|
||||
private const val FRAME_TIME_NS: Long = (1000000000 / 60).toLong()
|
||||
|
||||
private fun <E> drainConcurrentItemQueue(queue: Queue<E>): List<E>? {
|
||||
if (queue.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return buildList {
|
||||
do {
|
||||
queue.poll()?.let { add(it) }
|
||||
} while (queue.isNotEmpty())
|
||||
}
|
||||
.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
private fun printMountItem(mountItem: MountItem, prefix: String) {
|
||||
// If a MountItem description is split across multiple lines, it's because it's a
|
||||
// compound MountItem. Log each line separately.
|
||||
val mountItemLines = mountItem.toString().split("\n").dropLastWhile { it.isEmpty() }
|
||||
|
||||
for (line in mountItemLines) {
|
||||
FLog.e(TAG, "$prefix: $line")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
-49
@@ -21,7 +21,6 @@ import androidx.collection.SparseArrayCompat;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.infer.annotation.ThreadConfined;
|
||||
import com.facebook.react.bridge.GuardedRunnable;
|
||||
import com.facebook.react.bridge.ReactNoCrashSoftException;
|
||||
import com.facebook.react.bridge.ReactSoftExceptionLogger;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
@@ -190,55 +189,57 @@ public class SurfaceMountingManager {
|
||||
mTagToViewState.put(mSurfaceId, new ViewState(mSurfaceId, rootView, mRootViewManager, true));
|
||||
|
||||
Runnable runnable =
|
||||
new GuardedRunnable(Assertions.assertNotNull(mThemedReactContext)) {
|
||||
@Override
|
||||
public void runGuarded() {
|
||||
// The CPU has ticked since `addRootView` was called, so the surface could technically
|
||||
// have already stopped here.
|
||||
if (isStopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rootView.getId() == mSurfaceId) {
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG,
|
||||
new IllegalViewOperationException(
|
||||
"Race condition in addRootView detected. Trying to set an id of ["
|
||||
+ mSurfaceId
|
||||
+ "] on the RootView, but that id has already been set. "));
|
||||
} else if (rootView.getId() != View.NO_ID) {
|
||||
FLog.e(
|
||||
TAG,
|
||||
"Trying to add RootTag to RootView that already has a tag: existing tag: [%d] new"
|
||||
+ " tag: [%d]",
|
||||
rootView.getId(),
|
||||
mSurfaceId);
|
||||
// This behavior can not be guaranteed in hybrid apps that have a native android layer
|
||||
// over which reactRootViews are added and the native views need to have ids on them
|
||||
// in order to work. Hence this can cause unnecessary crashes at runtime for hybrid
|
||||
// apps. So converting this to a soft exception such that pure react-native devs can
|
||||
// still see the warning while hybrid apps continue to run without crashes
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG,
|
||||
new IllegalViewOperationException(
|
||||
"Trying to add a root view with an explicit id already set. React Native uses"
|
||||
+ " the id field to track react tags and will overwrite this field. If"
|
||||
+ " that is fine, explicitly overwrite the id field to View.NO_ID before"
|
||||
+ " calling addRootView."));
|
||||
}
|
||||
rootView.setId(mSurfaceId);
|
||||
|
||||
if (rootView instanceof ReactRoot) {
|
||||
((ReactRoot) rootView).setRootViewTag(mSurfaceId);
|
||||
}
|
||||
|
||||
executeMountItemsOnViewAttach();
|
||||
|
||||
// By doing this after `executeMountItemsOnViewAttach`, we ensure that any operations
|
||||
// scheduled while processing this queue are also added to the queue, instead of being
|
||||
// processed immediately through the queue in `MountItemDispatcher`.
|
||||
mRootViewAttached = true;
|
||||
() -> {
|
||||
// The CPU has ticked since `addRootView` was called, so the surface could technically
|
||||
// have already stopped here.
|
||||
if (isStopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rootView.getId() == mSurfaceId) {
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG,
|
||||
new IllegalViewOperationException(
|
||||
"Race condition in addRootView detected. Trying to set an id of ["
|
||||
+ mSurfaceId
|
||||
+ "] on the RootView, but that id has already been set. "));
|
||||
} else if (rootView.getId() != View.NO_ID) {
|
||||
FLog.e(
|
||||
TAG,
|
||||
"Trying to add RootTag to RootView that already has a tag: existing tag: [%d] new"
|
||||
+ " tag: [%d]",
|
||||
rootView.getId(),
|
||||
mSurfaceId);
|
||||
// This behavior can not be guaranteed in hybrid apps that have a native android layer
|
||||
// over
|
||||
// which reactRootViews are added and the native views need to have ids on them in order
|
||||
// to
|
||||
// work.
|
||||
// Hence this can cause unnecessary crashes at runtime for hybrid apps.
|
||||
// So converting this to a soft exception such that pure react-native devs can still see
|
||||
// the
|
||||
// warning while hybrid apps continue to run without crashes
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
TAG,
|
||||
new IllegalViewOperationException(
|
||||
"Trying to add a root view with an explicit id already set. React Native uses"
|
||||
+ " the id field to track react tags and will overwrite this field. If that"
|
||||
+ " is fine, explicitly overwrite the id field to View.NO_ID before calling"
|
||||
+ " addRootView."));
|
||||
}
|
||||
rootView.setId(mSurfaceId);
|
||||
|
||||
if (rootView instanceof ReactRoot) {
|
||||
((ReactRoot) rootView).setRootViewTag(mSurfaceId);
|
||||
}
|
||||
|
||||
executeMountItemsOnViewAttach();
|
||||
|
||||
// By doing this after `executeMountItemsOnViewAttach`, we ensure
|
||||
// that any operations scheduled while processing this queue are
|
||||
// also added to the queue, instead of being processed immediately
|
||||
// through the queue in `MountItemDispatcher`.
|
||||
mRootViewAttached = true;
|
||||
};
|
||||
|
||||
if (UiThreadUtil.isOnUiThread()) {
|
||||
|
||||
+7
-13
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<442cbf571b5654c5d322ca1b5542db7d>>
|
||||
* @generated SignedSource<<d8013c4b4ec45f241908e7f8f23f7dd1>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -156,6 +156,12 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun enableIOSViewClipToPaddingBox(): Boolean = accessor.enableIOSViewClipToPaddingBox()
|
||||
|
||||
/**
|
||||
* Integrates IntersectionObserver in the Event Loop in the new architecture, to dispatch the initial notifications for observations in the "Update the rendering" step.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun enableIntersectionObserverEventLoopIntegration(): Boolean = accessor.enableIntersectionObserverEventLoopIntegration()
|
||||
|
||||
/**
|
||||
* When enabled, LayoutAnimations API will animate state changes on Android.
|
||||
*/
|
||||
@@ -258,18 +264,6 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun enableVirtualViewDebugFeatures(): Boolean = accessor.enableVirtualViewDebugFeatures()
|
||||
|
||||
/**
|
||||
* Enables reading render state when dispatching VirtualView events.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun enableVirtualViewRenderState(): Boolean = accessor.enableVirtualViewRenderState()
|
||||
|
||||
/**
|
||||
* Enables window focus detection for prioritizing VirtualView events.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun enableVirtualViewWindowFocusDetection(): Boolean = accessor.enableVirtualViewWindowFocusDetection()
|
||||
|
||||
/**
|
||||
* Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React.
|
||||
*/
|
||||
|
||||
+11
-21
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<166a7cc18f83861c6c4d7f96a55c5843>>
|
||||
* @generated SignedSource<<15b001b69d9ea8bedbce2ce0f70bfa8e>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -41,6 +41,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var enableFontScaleChangesUpdatingLayoutCache: Boolean? = null
|
||||
private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null
|
||||
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
|
||||
private var enableIntersectionObserverEventLoopIntegrationCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
|
||||
private var enableMainQueueCoordinatorOnIOSCache: Boolean? = null
|
||||
@@ -58,8 +59,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var enableViewRecyclingForTextCache: Boolean? = null
|
||||
private var enableViewRecyclingForViewCache: Boolean? = null
|
||||
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
|
||||
private var enableVirtualViewRenderStateCache: Boolean? = null
|
||||
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
|
||||
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
|
||||
private var fuseboxEnabledReleaseCache: Boolean? = null
|
||||
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
||||
@@ -264,6 +263,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableIntersectionObserverEventLoopIntegration(): Boolean {
|
||||
var cached = enableIntersectionObserverEventLoopIntegrationCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.enableIntersectionObserverEventLoopIntegration()
|
||||
enableIntersectionObserverEventLoopIntegrationCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableLayoutAnimationsOnAndroid(): Boolean {
|
||||
var cached = enableLayoutAnimationsOnAndroidCache
|
||||
if (cached == null) {
|
||||
@@ -417,24 +425,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableVirtualViewRenderState(): Boolean {
|
||||
var cached = enableVirtualViewRenderStateCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.enableVirtualViewRenderState()
|
||||
enableVirtualViewRenderStateCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableVirtualViewWindowFocusDetection(): Boolean {
|
||||
var cached = enableVirtualViewWindowFocusDetectionCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.enableVirtualViewWindowFocusDetection()
|
||||
enableVirtualViewWindowFocusDetectionCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean {
|
||||
var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache
|
||||
if (cached == null) {
|
||||
|
||||
+3
-5
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<27e8fa8139901c1decaba5bfcbced221>>
|
||||
* @generated SignedSource<<dc8ac9241675deb1324d8ff0572f2fad>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -70,6 +70,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableIOSViewClipToPaddingBox(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableIntersectionObserverEventLoopIntegration(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnIOS(): Boolean
|
||||
@@ -104,10 +106,6 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableVirtualViewDebugFeatures(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableVirtualViewRenderState(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableVirtualViewWindowFocusDetection(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun fuseboxEnabledRelease(): Boolean
|
||||
|
||||
+3
-5
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<5efae3bf30e8acf69f0682372c39f7b2>>
|
||||
* @generated SignedSource<<56835f26710665a11a05879a0c90e577>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -65,6 +65,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun enableIOSViewClipToPaddingBox(): Boolean = false
|
||||
|
||||
override fun enableIntersectionObserverEventLoopIntegration(): Boolean = true
|
||||
|
||||
override fun enableLayoutAnimationsOnAndroid(): Boolean = false
|
||||
|
||||
override fun enableLayoutAnimationsOnIOS(): Boolean = true
|
||||
@@ -99,10 +101,6 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun enableVirtualViewDebugFeatures(): Boolean = false
|
||||
|
||||
override fun enableVirtualViewRenderState(): Boolean = false
|
||||
|
||||
override fun enableVirtualViewWindowFocusDetection(): Boolean = false
|
||||
|
||||
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false
|
||||
|
||||
override fun fuseboxEnabledRelease(): Boolean = false
|
||||
|
||||
+12
-23
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<498e9a51a9a0d0c0c4eb69c84bb33dd1>>
|
||||
* @generated SignedSource<<a6444cccfff813fe0e96c20855496560>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -45,6 +45,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var enableFontScaleChangesUpdatingLayoutCache: Boolean? = null
|
||||
private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null
|
||||
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
|
||||
private var enableIntersectionObserverEventLoopIntegrationCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
|
||||
private var enableMainQueueCoordinatorOnIOSCache: Boolean? = null
|
||||
@@ -62,8 +63,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var enableViewRecyclingForTextCache: Boolean? = null
|
||||
private var enableViewRecyclingForViewCache: Boolean? = null
|
||||
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
|
||||
private var enableVirtualViewRenderStateCache: Boolean? = null
|
||||
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
|
||||
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
|
||||
private var fuseboxEnabledReleaseCache: Boolean? = null
|
||||
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
||||
@@ -289,6 +288,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableIntersectionObserverEventLoopIntegration(): Boolean {
|
||||
var cached = enableIntersectionObserverEventLoopIntegrationCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.enableIntersectionObserverEventLoopIntegration()
|
||||
accessedFeatureFlags.add("enableIntersectionObserverEventLoopIntegration")
|
||||
enableIntersectionObserverEventLoopIntegrationCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableLayoutAnimationsOnAndroid(): Boolean {
|
||||
var cached = enableLayoutAnimationsOnAndroidCache
|
||||
if (cached == null) {
|
||||
@@ -459,26 +468,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableVirtualViewRenderState(): Boolean {
|
||||
var cached = enableVirtualViewRenderStateCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.enableVirtualViewRenderState()
|
||||
accessedFeatureFlags.add("enableVirtualViewRenderState")
|
||||
enableVirtualViewRenderStateCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableVirtualViewWindowFocusDetection(): Boolean {
|
||||
var cached = enableVirtualViewWindowFocusDetectionCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.enableVirtualViewWindowFocusDetection()
|
||||
accessedFeatureFlags.add("enableVirtualViewWindowFocusDetection")
|
||||
enableVirtualViewWindowFocusDetectionCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean {
|
||||
var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache
|
||||
if (cached == null) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user