mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04ae39e603 |
+1
-1
@@ -98,4 +98,4 @@ untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.285.0
|
||||
^0.281.0
|
||||
|
||||
@@ -17,9 +17,6 @@ runs:
|
||||
- name: Install node dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Set React Native Version
|
||||
# We don't want to set the version for stable branches, because this has been
|
||||
# already set from the 'create release' commits on the release branch.
|
||||
if: ${{ !endsWith(github.ref_name, '-stable') }}
|
||||
shell: bash
|
||||
run: node ./scripts/releases/set-rn-artifacts-version.js --build-type ${{ inputs.release-type }}
|
||||
- name: Setup gradle
|
||||
|
||||
@@ -383,7 +383,8 @@ jobs:
|
||||
runs-on: 8-core-ubuntu
|
||||
needs: [set_release_type]
|
||||
container:
|
||||
image: reactnativecommunity/react-native-android:latest
|
||||
# Version is pinned to v18.0 to unblock `run_fantom_tests` - see https://github.com/react-native-community/docker-android/pull/242#issuecomment-3280029122
|
||||
image: reactnativecommunity/react-native-android:v18.0
|
||||
env:
|
||||
TERM: "dumb"
|
||||
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
|
||||
|
||||
@@ -133,7 +133,6 @@ vendor/
|
||||
# Swift Package build folder
|
||||
/packages/react-native/.build
|
||||
/packages/react-native/.swiftpm
|
||||
/packages/react-native/React/includes/
|
||||
|
||||
# @react-native/codegen
|
||||
/packages/react-native/React/FBReactNativeSpec/
|
||||
|
||||
+2
-38
@@ -1,40 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## v0.81.4
|
||||
|
||||
### Fixed
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- Fix regression that skips artifacts code generation ([f6f5ea0b2e](https://github.com/facebook/react-native/commit/f6f5ea0b2eed894725d8f6e8bd045c99c3182026) by [@kitten](https://github.com/kitten))
|
||||
- Reapplied "Use autolinking-generated react-native-config output in second step of cocoapods linking that generates artifacts and generated source" ([bb73315a3f](https://github.com/facebook/react-native/commit/bb73315a3fd8cd203c4ddb3ffa10bfec307c7e92) by [@kitten](https://github.com/kitten))
|
||||
|
||||
## v0.82.0-rc.4
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Hermes V1:** Fixed coordinates for Hermes V1 artifacts ([674fb77d93](https://github.com/facebook/react-native/commit/674fb77d93dfe67a5fe90449dc71b195b1851e13) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- **Switch:** Fix Switch layout to work with iOS26 ([91d427fe52](https://github.com/facebook/react-native/commit/91d427fe52a307f9aa8579912ef956d61808dad2) by [@cipolleschi](https://github.com/cipolleschi))
|
||||
|
||||
## v0.82.0-rc.3
|
||||
|
||||
### Added
|
||||
|
||||
- **Hermes V1:** Added a dependency on hermes-compiler ([0caf8e70d5](https://github.com/facebook/react-native/commit/0caf8e70d53f611a73ad9b55879dfe0a5f036371) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
|
||||
### Fixed
|
||||
|
||||
#### Android specific
|
||||
|
||||
- **Hermes V1:** Changed the coordinates of hermes artifacts when using Hermes V1 ([d0fb33822d](https://github.com/facebook/react-native/commit/d0fb33822de38183895c8b3421f46966909beaf3) by [@j-piasecki](https://github.com/j-piasecki))
|
||||
|
||||
#### iOS specific
|
||||
|
||||
- **Codegen:** Fix regression that skips artifacts code generation ([f6f5ea0b2e](https://github.com/facebook/react-native/commit/f6f5ea0b2eed894725d8f6e8bd045c99c3182026) by [@kitten](https://github.com/kitten))
|
||||
|
||||
## v0.81.3
|
||||
|
||||
### Fixed
|
||||
@@ -101,7 +66,6 @@
|
||||
- **Error Handling:** Unhandled promises are now handled by ExceptionsManager.handleException, instead of being swallowed as Logbox Warnings. ([c4082c9ce2](https://github.com/facebook/react-native/commit/c4082c9ce208a324c2d011823ca2ba432411aafc) by [@krystofwoldrich](https://github.com/krystofwoldrich))
|
||||
- **`shouldEmitW3CPointerEvents`:** Migrate `shouldPressibilityUseW3CPointerEventsForHover` to common private feature flags and remove `shouldEmitW3CPointerEvents` flag. ([fb4587780e](https://github.com/facebook/react-native/commit/fb4587780e8d6111139d73598a9a26ff392dee28) by [@coado](https://github.com/coado))
|
||||
- **TurboModuleUtils:** Remove unused ReactCommon/TurboModuleUtils functions #deepCopyJSIObject and #deepCopyJSIArray ([ead669ade3](https://github.com/facebook/react-native/commit/ead669ade31ee703c407f96c0ce98d8f2991bdc8) by [@christophpurrer](https://github.com/christophpurrer))
|
||||
- **TurboModules:** Delete old location of CallbackWrapper.h / LongLivedObject.h by ([cb94e71](https://github.com/facebook/react-native/commit/cb94e71845259ae7fa823eb4d21cde74fccd7435) [@christophpurrer](https://github.com/christophpurrer))
|
||||
|
||||
#### Android specific
|
||||
|
||||
@@ -116,7 +80,7 @@
|
||||
|
||||
### Added
|
||||
|
||||
- **Animated:** `Animated.CompositeAnimation` is now exposed when using `"react-native-strict-api"` ([024d25794a](https://github.com/facebook/react-native/commit/024d25794a51c94c877c1dfa115a82ebbf559614) by [@huntie](https://github.com/huntie))
|
||||
- **Animated:** `Animated.CompositeAnomation` is now exposed when using `"react-native-strict-api"` ([024d25794a](https://github.com/facebook/react-native/commit/024d25794a51c94c877c1dfa115a82ebbf559614) by [@huntie](https://github.com/huntie))
|
||||
- **Animated:** Allow calling createAnimatedNode without batching ([d9d9a49e18](https://github.com/facebook/react-native/commit/d9d9a49e18f3c51caa18cf7da0a1fcd62f1ecf18) by [@zeyap](https://github.com/zeyap))
|
||||
- **Animated:** Allow filter usage with native animated driver. ([138d0eb01d](https://github.com/facebook/react-native/commit/138d0eb01dbe597261459a37d364d1780c3ef228) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
|
||||
- **API:** Expose NativeComponentRegistry API as JavaScript root export ([f936780cd5](https://github.com/facebook/react-native/commit/f936780cd5c0c17797f9d2bbc8f5cee81c2eefce) by [@zhongwuzw](https://github.com/zhongwuzw))
|
||||
@@ -153,7 +117,7 @@
|
||||
|
||||
- **AGP:** AGP to 8.12.0 ([742ef3d661](https://github.com/facebook/react-native/commit/742ef3d6615c8c1202e9f683e6127ac97d7a9e23) by [@cortinico](https://github.com/cortinico))
|
||||
- **DevSupportManager:** DevSupport `openDebugger()` methods now accept a `panel: String?` param. Frameworks directly implementing `DevSupportManager` will need to adjust call signatures. ([9dba7112cf](https://github.com/facebook/react-native/commit/9dba7112cfd09b02300869a77dba3dca16f49a28) by [@huntie](https://github.com/huntie))
|
||||
- **Kotlin:** Migrated TextAttributeProps to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([fa921b3c7b](https://github.com/facebook/react-native/commit/fa921b3c7b289800a79196468f993a0eb0bf693f) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- **Kotlin:**Migrated TextAttributeProps to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([fa921b3c7b](https://github.com/facebook/react-native/commit/fa921b3c7b289800a79196468f993a0eb0bf693f) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- **Kotlin:** Migrated ReactBaseTextShadowNode to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([8ccfff9a46](https://github.com/facebook/react-native/commit/8ccfff9a46f317fd78f478c8b3f180441535d1ca) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- **Kotlin:** Migrated com.facebook.react.bridge.Arguments to Kotlin. ([2534aeaddb](https://github.com/facebook/react-native/commit/2534aeaddb0490b69dfaba6b8d316616c7e10a9c) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
- **Kotlin:** Migrate `YogaConfig` to Kotlin ([4d5caef76b](https://github.com/facebook/react-native/commit/4d5caef76b83eb7e983364ecc81abb6027e5f98e) by [@mateoguzmana](https://github.com/mateoguzmana))
|
||||
|
||||
Vendored
+16
-19
@@ -3057,30 +3057,30 @@ type util$InspectOptions = {
|
||||
};
|
||||
|
||||
declare type util$ParseArgsOption =
|
||||
| $ReadOnly<{|
|
||||
| {|
|
||||
type: 'boolean',
|
||||
multiple?: false,
|
||||
short?: string,
|
||||
default?: boolean,
|
||||
|}>
|
||||
| $ReadOnly<{|
|
||||
|}
|
||||
| {|
|
||||
type: 'boolean',
|
||||
multiple: true,
|
||||
short?: string,
|
||||
default?: Array<boolean>,
|
||||
|}>
|
||||
| $ReadOnly<{|
|
||||
|}
|
||||
| {|
|
||||
type: 'string',
|
||||
multiple?: false,
|
||||
short?: string,
|
||||
default?: string,
|
||||
|}>
|
||||
| $ReadOnly<{|
|
||||
|}
|
||||
| {|
|
||||
type: 'string',
|
||||
multiple: true,
|
||||
short?: string,
|
||||
default?: Array<string>,
|
||||
|}>;
|
||||
|};
|
||||
|
||||
type util$ParseArgsOptionToValue<TOption> = TOption['type'] extends 'boolean'
|
||||
? TOption['multiple'] extends true
|
||||
@@ -3137,7 +3137,7 @@ declare module 'util' {
|
||||
declare function stripVTControlCharacters(str: string): string;
|
||||
|
||||
declare function parseArgs<
|
||||
TOptions: {+[string]: util$ParseArgsOption} = {||},
|
||||
TOptions: {[string]: util$ParseArgsOption} = {||},
|
||||
>(config: {|
|
||||
args?: Array<string>,
|
||||
options?: TOptions,
|
||||
@@ -3995,16 +3995,13 @@ declare class Process extends events$EventEmitter {
|
||||
initgroups?: (user: number | string, extra_group: number | string) => void;
|
||||
kill(pid: number, signal?: string | number): void;
|
||||
mainModule: Object;
|
||||
memoryUsage: {
|
||||
(): {
|
||||
arrayBuffers: number,
|
||||
rss: number,
|
||||
heapTotal: number,
|
||||
heapUsed: number,
|
||||
external: number,
|
||||
...
|
||||
},
|
||||
rss: () => number,
|
||||
memoryUsage(): {
|
||||
arrayBuffers: number,
|
||||
rss: number,
|
||||
heapTotal: number,
|
||||
heapUsed: number,
|
||||
external: number,
|
||||
...
|
||||
};
|
||||
nextTick: <T>(cb: (...T) => mixed, ...T) => void;
|
||||
pid: number;
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
declare module 'electron-store' {
|
||||
declare export type Schema = any;
|
||||
|
||||
declare export type Options = {
|
||||
+name?: string,
|
||||
defaults?: Object,
|
||||
schema?: any,
|
||||
migrations?: any,
|
||||
beforeEachMigration?: any,
|
||||
clearInvalidConfig?: boolean,
|
||||
serialize?: any,
|
||||
deserialize?: any,
|
||||
accessPropertiesByDotNotation?: boolean,
|
||||
watch?: boolean,
|
||||
encryptionKey?: string | Buffer | $ReadOnlyArray<number>,
|
||||
...
|
||||
};
|
||||
|
||||
declare class ElectronStore {
|
||||
constructor(options?: Options): this;
|
||||
get(key: string): any;
|
||||
get(key: string, defaultValue: any): any;
|
||||
set(key: string, value: any): void;
|
||||
set(object: Object): void;
|
||||
has(key: string): boolean;
|
||||
delete(key: string): void;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
declare module.exports: Class<ElectronStore>;
|
||||
}
|
||||
+1
-1
@@ -86,7 +86,7 @@
|
||||
"eslint-plugin-relay": "^1.8.3",
|
||||
"fb-dotslash": "0.5.8",
|
||||
"flow-api-translator": "0.32.0",
|
||||
"flow-bin": "^0.285.0",
|
||||
"flow-bin": "^0.281.0",
|
||||
"glob": "^7.1.1",
|
||||
"hermes-eslint": "0.32.0",
|
||||
"hermes-transform": "0.32.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@generated SignedSource<<d090ed9a9e781c82884f22944254ed65>>
|
||||
Git revision: 8b84a77b2c82c670886ef064dfc92d6bce83e579
|
||||
@generated SignedSource<<0b54f75686e4893a5444839bf621a317>>
|
||||
Git revision: 5a792db1225adda206313e9bf751198a1ca7851a
|
||||
Built with --nohooks: false
|
||||
Is local checkout: false
|
||||
Remote URL: https://github.com/facebook/react-native-devtools-frontend
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,71 +1,71 @@
|
||||
#!/usr/bin/env dotslash
|
||||
|
||||
// @generated SignedSource<<80974ea6ac4427cf5fd9f14f6779b5c6>>
|
||||
// @generated SignedSource<<9df662721aea6e3774a8677e2a6065e4>>
|
||||
|
||||
|
||||
{
|
||||
"name": "React Native DevTools",
|
||||
"platforms": {
|
||||
"linux-aarch64": {
|
||||
"size": 116072551,
|
||||
"size": 116056584,
|
||||
"hash": "sha256",
|
||||
"digest": "3fd69eff02f4a41818a7ecb252ab0de449fa1f88fe0dd1de474bd15dd2e63856",
|
||||
"digest": "fac3912f10e3c373c874be6c4696f11e05cbaa754c116db6ea72189afae5efe6",
|
||||
"providers": [
|
||||
{
|
||||
"type": "http",
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOBrLd2GhnOLBe4XfcroGD8Uh8odfhSuE5y5f6WSUCPAD93HJyyUbNxvU8rneUBXRi6SjftdBfU9ggRGlEdLVoTt3bp1bS8C370rWXH5oZIPkX87SovgSPmlCQygx8OQIUmShnoHVMSa3xArpSdXRdOvqNrwiOsmBkmxJXm_NycW502xfhcL6A6d38"
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPdlYV_w4y_wxd5Rs8c_F-soLMbY1zwXJjD-JM4TkOtOELyxZGyreTb6dTehp_X6e3qVFZUT05ETRs0MbvqYr4mqdb6dkG9DqNQEVv3TBoHwl7TYSygtHJEs3gXTAtMLYEKW9xXODJlVF-9II7fdTdHU7x7Pyf6NR6S3nv7sKUVD-zKpxF50L2TwUQ"
|
||||
}
|
||||
],
|
||||
"format": "tar.gz",
|
||||
"path": "React Native DevTools-linux-arm64/React Native DevTools"
|
||||
},
|
||||
"linux-x86_64": {
|
||||
"size": 115924495,
|
||||
"size": 115929093,
|
||||
"hash": "sha256",
|
||||
"digest": "d154ffed0d8a66849da78baebf78e1323ecb8bbeda30d27b82a9b507196266c1",
|
||||
"digest": "06bbaeb62ae2e0081d184eba42b9f15be0d0b3f4901142b08a8a1430ff83e722",
|
||||
"providers": [
|
||||
{
|
||||
"type": "http",
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPp7lTIJZPh1_Bz1ONneTDc_i5ScY8TLzgHe4DzvYz6e7z-QHdBKhUNbNVBInrYrJaPKPum8FOGcvFW9JsvPNpsdMiAbjivdKQPAEkGOZ-unSOqL1dPPjW-yZYSBGucXmcgQiXVaDhqG3Wcu04JLsFKlKb9QvAZZ-tyN72E8ndAQ0mgDyhzEhwB"
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPENbrxrg0RF_TiyxSY_YVYqC1UfRKj_bMfKb3qHUsIhBlya8n3FkbfJqTXTNdqL4riFRulXS5ecXZprtvk_9kao-zY59r3kiTRwobzF0jnjM507_9UOnEHWzG5ZJYzQyOtS3kQmT0HwZabVj9qw38OB9mk-MPVCZIPZay2PRnIThBzpKDoOOP9"
|
||||
}
|
||||
],
|
||||
"format": "tar.gz",
|
||||
"path": "React Native DevTools-linux-x64/React Native DevTools"
|
||||
},
|
||||
"macos-aarch64": {
|
||||
"size": 110891525,
|
||||
"size": 110891603,
|
||||
"hash": "sha256",
|
||||
"digest": "b05e1ae5528dcfcff5178d943d90128c9bf28ecd89da4dc303fd4ca748e5fc88",
|
||||
"digest": "eeb9cc1399c0c38c429848dbf622f1b46e88d7d97788dcdc4c30a9fcce37705c",
|
||||
"providers": [
|
||||
{
|
||||
"type": "http",
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQMfoVd8CCoqS0ETntAOKhks2FtIDsyoPEeJHLIc-bxPESxTSHf02xDSSM-vjCG9gBitObq3iZECz1LGwbYS9qrjqXdrf7oljIWzK-eszvQwDe0wzCsywqRXBtLlDBb5h8a1WxjA_scRqoGCDbvk7-XovnJNdmTX4vq0CFb8QUUcEz31sVQ_v5IRjDdF"
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN9bd7nbXi-uF_MooJEiUL2jJVifMqgQxZ236aqbSdiJe5Uzjud5ANf0LDAl8GDVVRShd6x4B-gsZ-qRowH0qJikoGatQIkBgyzp4i8ors52etGOIIwdAxdNIng5Vtp441j2_N__btkJqlHcMMbbqvO8fg9oeYTlhMpOx3MLLWXIlG7ix5IFUDiYChf"
|
||||
}
|
||||
],
|
||||
"format": "tar.gz",
|
||||
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
|
||||
},
|
||||
"macos-x86_64": {
|
||||
"size": 117767014,
|
||||
"size": 117770388,
|
||||
"hash": "sha256",
|
||||
"digest": "6aa15f6dc13bea46503fcad1b9ba93b3007ea659abb63a2f6bf9b34c3abf834a",
|
||||
"digest": "a65e446e526502b267cbe6800ae031e4e1b5b0aca21412152a66ffe1d3a29410",
|
||||
"providers": [
|
||||
{
|
||||
"type": "http",
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQM57KwrYx0XeV3M8JrX_StgCFVbMHB5L-ShQfzIdoG4jfz71Z7U7CtK5FZ72Uwzm9wmzx5n0-w_3P8DRd24gvMWUSaN8QNdyxIUxd1n0BqJRYsvsbc8w2YpNeWadcce701zV5dYgQg7PIjPzDSuhYWM_7ih_QtZIBIHUUjCtr0sJBUYZVaqBQag6Q"
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN29ukKLZS48QcCU-gms06YFnG-fxxDfrWTup-Z6KoIAP-QEu3sFzrpqeZz4g-jFsh3o-IIoHJsdbu4a2U7ROjPfWGguGJrPK8fdc3iV67Qw1_VAPU13dm0dI1DbSY50ah05wh43jdBG3LGCAYYJ-W8_mZMC3HqM2v-8KVd-DoPT4hOh1s9CCFgEQ"
|
||||
}
|
||||
],
|
||||
"format": "tar.gz",
|
||||
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
|
||||
},
|
||||
"windows-x86_64": {
|
||||
"size": 125530089,
|
||||
"size": 125526370,
|
||||
"hash": "sha256",
|
||||
"digest": "da1747672dd222b1389f6ad9e1c67778ea0bc4e8859ddee23222a92bcaaed48f",
|
||||
"digest": "26b190c0f85249dee91999e020b8fe7ffd5c007458a2103ed3822558861dbe87",
|
||||
"providers": [
|
||||
{
|
||||
"type": "http",
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN_2xTT04YUkfSPrA0LaBIHmjUTCCxBkiTgUpb3TUn02lpaFas2x3asL1LeHpZHlUmb_NiLE0PLZYg3T232fdIbmLaquPST7lQpsXDDMG-ykGK7-xxfK5CMU608Pd5Crw5YZBPF3O2PCtiIIcR85tWSqmyWYuoX-PnIhLnBWHjbpNcMcj9RkVqB"
|
||||
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQO0mdIJx1eYiSDJNiAZ2soaeECILayWnvOeiey-fpS4ydDTreAMfwL4QZ5GZo4-AsGwOXCSdF3hBMM2ufnvw6BDFg5UEiTc4DALJu7o6YBBG4wlVZbI-2kkaXd7u8RhBQPjmhsdcX3sDmCGmSr3WK9EkTRKStE2lb6ilOn-969h4dYWekwUUCSX"
|
||||
}
|
||||
],
|
||||
"format": "tar.gz",
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "37.2.6",
|
||||
"electron-store": "^8.2.0",
|
||||
"semver": "^7.1.3"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
|
||||
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
|
||||
const {BrowserWindow, Menu, app, shell, ipcMain} = require('electron') as any;
|
||||
const Store = require('electron-store');
|
||||
const path = require('path');
|
||||
const util = require('util');
|
||||
|
||||
const appSettings = new Store();
|
||||
const windowMetadata = new WeakMap<
|
||||
typeof BrowserWindow,
|
||||
$ReadOnly<{
|
||||
@@ -53,10 +55,11 @@ function handleLaunchArgs(argv: string[]) {
|
||||
}, 1000);
|
||||
}
|
||||
} else {
|
||||
// Create the browser window.
|
||||
frontendWindow = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 600,
|
||||
...(getSavedWindowPosition(windowKey) ?? {
|
||||
width: 1200,
|
||||
height: 600,
|
||||
}),
|
||||
webPreferences: {
|
||||
partition: 'persist:react-native-devtools',
|
||||
preload: require.resolve('./preload.js'),
|
||||
@@ -66,6 +69,8 @@ function handleLaunchArgs(argv: string[]) {
|
||||
});
|
||||
// Auto-hide the Windows/Linux menu bar
|
||||
frontendWindow.setMenuBarVisibility(false);
|
||||
// Observe and update saved window position
|
||||
setupWindowResizeListeners(frontendWindow, windowKey);
|
||||
}
|
||||
|
||||
// Open links in the default browser instead of in new Electron windows.
|
||||
@@ -119,6 +124,37 @@ function configureAppMenu() {
|
||||
Menu.setApplicationMenu(menu);
|
||||
}
|
||||
|
||||
function getSavedWindowPosition(
|
||||
windowKey: string,
|
||||
): ?{width: number, height: number, x?: number, y?: number} {
|
||||
return appSettings.get('windowArrangements', {})[windowKey];
|
||||
}
|
||||
|
||||
function saveWindowPosition(
|
||||
windowKey: string,
|
||||
position: {x: number, y: number, width: number, height: number},
|
||||
) {
|
||||
const windowArrangements = appSettings.get('windowArrangements', {});
|
||||
windowArrangements[windowKey] = position;
|
||||
appSettings.set('windowArrangements', windowArrangements);
|
||||
}
|
||||
|
||||
function setupWindowResizeListeners(
|
||||
browserWindow: typeof BrowserWindow,
|
||||
windowKey: string,
|
||||
) {
|
||||
const savePosition = () => {
|
||||
if (!browserWindow.isDestroyed()) {
|
||||
const [x, y] = browserWindow.getPosition();
|
||||
const [width, height] = browserWindow.getSize();
|
||||
saveWindowPosition(windowKey, {x, y, width, height});
|
||||
}
|
||||
};
|
||||
browserWindow.on('moved', savePosition);
|
||||
browserWindow.on('resized', savePosition);
|
||||
browserWindow.on('closed', savePosition);
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
handleLaunchArgs(process.argv.slice(app.isPackaged ? 1 : 2));
|
||||
configureAppMenu();
|
||||
|
||||
@@ -25,9 +25,7 @@ app.setVersion(pkg.version + '-' + buildInfo.revision);
|
||||
const {
|
||||
values: {version = false},
|
||||
} = util.parseArgs({
|
||||
options: {
|
||||
version: {type: 'boolean'},
|
||||
},
|
||||
options: {version: {type: 'boolean'}},
|
||||
args: process.argv.slice(app.isPackaged ? 1 : 2),
|
||||
strict: false,
|
||||
});
|
||||
|
||||
@@ -372,6 +372,12 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
|
||||
this.#devices.set(deviceId, newDevice);
|
||||
|
||||
this.#logger?.info(
|
||||
"Connection established to app='%s' on device='%s'.",
|
||||
appName,
|
||||
deviceName,
|
||||
);
|
||||
|
||||
debug(
|
||||
"Got new device connection: name='%s', app=%s, device=%s, via=%s",
|
||||
deviceName,
|
||||
@@ -444,7 +450,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
);
|
||||
|
||||
socket.on('close', (code: number, reason: string) => {
|
||||
debug(
|
||||
this.#logger?.info(
|
||||
"Connection closed to device='%s' for app='%s' with code='%s' and reason='%s'.",
|
||||
deviceName,
|
||||
appName,
|
||||
@@ -520,7 +526,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
throw new Error(INTERNAL_ERROR_MESSAGES.UNREGISTERED_DEVICE);
|
||||
}
|
||||
|
||||
debug(
|
||||
this.#logger?.info(
|
||||
"Connection established to DevTools for app='%s' on device='%s'.",
|
||||
device.getApp() || 'unknown',
|
||||
device.getName() || 'unknown',
|
||||
@@ -588,7 +594,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
});
|
||||
|
||||
socket.on('close', (code: number, reason: string) => {
|
||||
debug(
|
||||
this.#logger?.info(
|
||||
"Connection closed to DevTools for app='%s' on device='%s' with code='%s' and reason='%s'.",
|
||||
device.getApp() || 'unknown',
|
||||
device.getName() || 'unknown',
|
||||
|
||||
-8
@@ -191,14 +191,6 @@ internal object DependencyUtils {
|
||||
"The hermes-android dependency was modified to use the correct Maven group.",
|
||||
)
|
||||
)
|
||||
} else if (hermesV1Enabled) {
|
||||
dependencySubstitution.add(
|
||||
Triple(
|
||||
"com.facebook.react:hermes-android",
|
||||
hermesVersionString,
|
||||
"The hermes-android dependency was modified to use Hermes V1.",
|
||||
)
|
||||
)
|
||||
}
|
||||
return dependencySubstitution
|
||||
}
|
||||
|
||||
+1
-1
@@ -242,7 +242,7 @@ internal fun readPackageJsonFile(
|
||||
return packageJson?.let { JsonUtils.fromPackageJson(it) }
|
||||
}
|
||||
|
||||
private const val HERMES_COMPILER_NPM_DIR = "node_modules/hermes-compiler/hermesc/%OS-BIN%/"
|
||||
private const val HERMES_COMPILER_NPM_DIR = "node_modules/hermes-compiler/%OS-BIN%/"
|
||||
private const val HERMESC_IN_REACT_NATIVE_DIR = "node_modules/react-native/sdks/hermesc/%OS-BIN%/"
|
||||
private const val HERMESC_BUILT_FROM_SOURCE_DIR =
|
||||
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/"
|
||||
|
||||
+2
-2
@@ -165,8 +165,8 @@ class PathUtilsTest {
|
||||
@Test
|
||||
@WithOs(OS.MAC)
|
||||
fun detectOSAwareHermesCommand_withHermesV1Enabled() {
|
||||
tempFolder.newFolder("node_modules/hermes-compiler/hermesc/osx-bin/")
|
||||
val expected = tempFolder.newFile("node_modules/hermes-compiler/hermesc/osx-bin/hermesc")
|
||||
tempFolder.newFolder("node_modules/hermes-compiler/osx-bin/")
|
||||
val expected = tempFolder.newFile("node_modules/hermes-compiler/osx-bin/hermesc")
|
||||
|
||||
assertThat(detectOSAwareHermesCommand(tempFolder.root, "", hermesV1Enabled = true))
|
||||
.isEqualTo(expected.toString())
|
||||
|
||||
@@ -47,7 +47,7 @@ function combineSchemas(
|
||||
}
|
||||
return merged;
|
||||
},
|
||||
{modules: {} /*:: as SchemaType['modules'] */},
|
||||
{modules: {}},
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -540,7 +540,7 @@ function buildEventEmitterSchema(
|
||||
|
||||
return {
|
||||
name: eventemitterName,
|
||||
optional: Boolean(property.optional),
|
||||
optional: false,
|
||||
typeAnnotation: {
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: eventTypeAnnotation,
|
||||
|
||||
@@ -873,6 +873,56 @@ describe('Animated', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Animated Interactions', () => {
|
||||
let Animated; // eslint-disable-line no-shadow
|
||||
let InteractionManager;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.mock('../../Interaction/InteractionManager');
|
||||
Animated = require('../Animated').default;
|
||||
InteractionManager =
|
||||
require('../../Interaction/InteractionManager').default;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.unmock('../../Interaction/InteractionManager');
|
||||
});
|
||||
|
||||
it('registers an interaction by default', () => {
|
||||
// $FlowFixMe[prop-missing]
|
||||
InteractionManager.createInteractionHandle.mockReturnValue(777);
|
||||
|
||||
const value = new Animated.Value(0);
|
||||
const callback = jest.fn();
|
||||
Animated.timing(value, {
|
||||
toValue: 100,
|
||||
duration: 100,
|
||||
useNativeDriver: false,
|
||||
}).start(callback);
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(InteractionManager.createInteractionHandle).toBeCalled();
|
||||
expect(InteractionManager.clearInteractionHandle).toBeCalledWith(777);
|
||||
expect(callback).toBeCalledWith({finished: true});
|
||||
});
|
||||
|
||||
it('does not register an interaction when specified', () => {
|
||||
const value = new Animated.Value(0);
|
||||
const callback = jest.fn();
|
||||
Animated.timing(value, {
|
||||
toValue: 100,
|
||||
duration: 100,
|
||||
isInteraction: false,
|
||||
useNativeDriver: false,
|
||||
}).start(callback);
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(InteractionManager.createInteractionHandle).not.toBeCalled();
|
||||
expect(InteractionManager.clearInteractionHandle).not.toBeCalled();
|
||||
expect(callback).toBeCalledWith({finished: true});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Animated Tracking', () => {
|
||||
it('should track values', () => {
|
||||
const value1 = new Animated.Value(0);
|
||||
|
||||
@@ -14,10 +14,8 @@ import FlatList, {type FlatListProps} from '../../Lists/FlatList';
|
||||
import createAnimatedComponent from '../createAnimatedComponent';
|
||||
import * as React from 'react';
|
||||
|
||||
export default createAnimatedComponent(FlatList) as $FlowFixMe as component<
|
||||
// $FlowExpectedError[unclear-type]
|
||||
ItemT = any,
|
||||
>(
|
||||
// $FlowExpectedError[unclear-type]
|
||||
export default (createAnimatedComponent(FlatList): component<ItemT = any>(
|
||||
ref?: React.RefSetter<FlatList<ItemT>>,
|
||||
...props: AnimatedProps<FlatListProps<ItemT>>
|
||||
);
|
||||
));
|
||||
|
||||
@@ -14,10 +14,9 @@ import Image from '../../Image/Image';
|
||||
import createAnimatedComponent from '../createAnimatedComponent';
|
||||
import * as React from 'react';
|
||||
|
||||
export default (createAnimatedComponent<
|
||||
$FlowFixMe,
|
||||
React.ElementRef<typeof Image>,
|
||||
>((Image: $FlowFixMe)): AnimatedComponentType<
|
||||
export default (createAnimatedComponent(
|
||||
(Image: $FlowFixMe),
|
||||
): AnimatedComponentType<
|
||||
React.ElementConfig<typeof Image>,
|
||||
React.ElementRef<typeof Image>,
|
||||
>);
|
||||
|
||||
@@ -15,7 +15,7 @@ import createAnimatedComponent from '../createAnimatedComponent';
|
||||
import * as React from 'react';
|
||||
|
||||
// $FlowFixMe[incompatible-type]
|
||||
export default createAnimatedComponent(SectionList) as $FlowFixMe as component<
|
||||
export default (createAnimatedComponent(SectionList): component<
|
||||
// $FlowExpectedError[unclear-type]
|
||||
ItemT = any,
|
||||
// $FlowExpectedError[unclear-type]
|
||||
@@ -23,4 +23,4 @@ export default createAnimatedComponent(SectionList) as $FlowFixMe as component<
|
||||
>(
|
||||
ref?: React.RefSetter<SectionList<ItemT, SectionT>>,
|
||||
...props: AnimatedProps<SectionListProps<ItemT, SectionT>>
|
||||
);
|
||||
));
|
||||
|
||||
@@ -14,10 +14,6 @@ import Text, {type TextProps} from '../../Text/Text';
|
||||
import createAnimatedComponent from '../createAnimatedComponent';
|
||||
import * as React from 'react';
|
||||
|
||||
export default (createAnimatedComponent<
|
||||
$FlowFixMe,
|
||||
React.ElementRef<typeof Text>,
|
||||
>((Text: $FlowFixMe)): AnimatedComponentType<
|
||||
TextProps,
|
||||
React.ElementRef<typeof Text>,
|
||||
>);
|
||||
export default (createAnimatedComponent(
|
||||
(Text: $FlowFixMe),
|
||||
): AnimatedComponentType<TextProps, React.ElementRef<typeof Text>>);
|
||||
|
||||
@@ -15,8 +15,7 @@ import View from '../../Components/View/View';
|
||||
import createAnimatedComponent from '../createAnimatedComponent';
|
||||
import * as React from 'react';
|
||||
|
||||
// $FlowFixMe[incompatible-type]
|
||||
export default createAnimatedComponent(View) as AnimatedComponentType<
|
||||
export default (createAnimatedComponent(View): AnimatedComponentType<
|
||||
ViewProps,
|
||||
React.ElementRef<typeof View>,
|
||||
>;
|
||||
>);
|
||||
|
||||
@@ -63,29 +63,17 @@ type PassThroughProps = $ReadOnly<{
|
||||
passthroughAnimatedPropExplicitValues?: ViewProps | null,
|
||||
}>;
|
||||
|
||||
type LooseOmit<O: interface {}, K: $Keys<$FlowFixMe>> = Pick<
|
||||
O,
|
||||
Exclude<$Keys<O>, K>,
|
||||
>;
|
||||
export type AnimatedProps<Props: {...}> = {
|
||||
[K in keyof Props]: K extends NonAnimatedProps
|
||||
? Props[K]
|
||||
: WithAnimatedValue<Props[K]>,
|
||||
} & PassThroughProps;
|
||||
|
||||
export type AnimatedProps<Props: {...}> = LooseOmit<
|
||||
{
|
||||
[K in keyof Props]: K extends NonAnimatedProps
|
||||
? Props[K]
|
||||
: WithAnimatedValue<Props[K]>,
|
||||
},
|
||||
'ref',
|
||||
> &
|
||||
PassThroughProps;
|
||||
|
||||
export type AnimatedBaseProps<Props: {...}> = LooseOmit<
|
||||
{
|
||||
[K in keyof Props]: K extends NonAnimatedProps
|
||||
? Props[K]
|
||||
: WithAnimatedValue<Props[K]>,
|
||||
},
|
||||
'ref',
|
||||
>;
|
||||
export type AnimatedBaseProps<Props: {...}> = {
|
||||
[K in keyof Props]: K extends NonAnimatedProps
|
||||
? Props[K]
|
||||
: WithAnimatedValue<Props[K]>,
|
||||
};
|
||||
|
||||
export type AnimatedComponentType<Props: {...}, +Instance = mixed> = component(
|
||||
ref?: React.RefSetter<Instance>,
|
||||
|
||||
@@ -18,6 +18,7 @@ import type {AnimatedNodeConfig} from './AnimatedNode';
|
||||
import type AnimatedTracking from './AnimatedTracking';
|
||||
|
||||
import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
|
||||
import InteractionManager from '../../Interaction/InteractionManager';
|
||||
import AnimatedInterpolation from './AnimatedInterpolation';
|
||||
import AnimatedWithChildren from './AnimatedWithChildren';
|
||||
|
||||
@@ -311,6 +312,10 @@ export default class AnimatedValue extends AnimatedWithChildren {
|
||||
* See https://reactnative.dev/docs/animatedvalue#animate
|
||||
*/
|
||||
animate(animation: Animation, callback: ?EndCallback): void {
|
||||
let handle = null;
|
||||
if (animation.__isInteraction) {
|
||||
handle = InteractionManager.createInteractionHandle();
|
||||
}
|
||||
const previousAnimation = this._animation;
|
||||
this._animation && this._animation.stop();
|
||||
this._animation = animation;
|
||||
@@ -323,6 +328,9 @@ export default class AnimatedValue extends AnimatedWithChildren {
|
||||
},
|
||||
result => {
|
||||
this._animation = null;
|
||||
if (handle !== null) {
|
||||
InteractionManager.clearInteractionHandle(handle);
|
||||
}
|
||||
callback && callback(result);
|
||||
},
|
||||
previousAnimation,
|
||||
|
||||
@@ -1690,7 +1690,6 @@ class ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
|
||||
return (
|
||||
<StickyHeaderComponent
|
||||
key={key}
|
||||
/* $FlowFixMe[incompatible-type] */
|
||||
ref={ref => this._setStickyHeaderRef(key, ref)}
|
||||
nextHeaderLayoutY={this._headerLayoutYs.get(
|
||||
this._getKeyForIndex(nextIndex, children),
|
||||
|
||||
+6
-6
@@ -44,7 +44,7 @@ interface Instance extends React.ElementRef<typeof Animated.View> {
|
||||
}
|
||||
|
||||
const ScrollViewStickyHeader: component(
|
||||
ref?: React.RefSetter<Instance>,
|
||||
ref: React.RefSetter<Instance>,
|
||||
...props: ScrollViewStickyHeaderProps
|
||||
) = function ScrollViewStickyHeader({
|
||||
ref: forwardedRef,
|
||||
@@ -282,7 +282,7 @@ const ScrollViewStickyHeader: component(
|
||||
const passthroughAnimatedPropExplicitValues =
|
||||
isFabric && translateY != null
|
||||
? {
|
||||
style: {transform: [{translateY}]},
|
||||
style: {transform: [{translateY: translateY}]},
|
||||
}
|
||||
: null;
|
||||
|
||||
@@ -303,20 +303,20 @@ const ScrollViewStickyHeader: component(
|
||||
passthroughAnimatedPropExplicitValues
|
||||
}>
|
||||
{cloneElement(child, {
|
||||
onLayout: undefined, // we call this manually through our this._onLayout
|
||||
style: styles.fill, // We transfer the child style to the wrapper.
|
||||
onLayout: undefined, // we call this manually through our this._onLayout
|
||||
})}
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
fill: {
|
||||
flex: 1,
|
||||
},
|
||||
header: {
|
||||
zIndex: 10,
|
||||
},
|
||||
fill: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
export default ScrollViewStickyHeader;
|
||||
|
||||
@@ -47,14 +47,15 @@ class TouchableBounce extends React.Component<
|
||||
|
||||
_createPressabilityConfig(): PressabilityConfig {
|
||||
return {
|
||||
android_disableSound: this.props.touchSoundDisabled,
|
||||
cancelable: !this.props.rejectResponderTermination,
|
||||
disabled: this.props.disabled,
|
||||
hitSlop: this.props.hitSlop,
|
||||
delayLongPress: this.props.delayLongPress,
|
||||
delayPressIn: this.props.delayPressIn,
|
||||
delayPressOut: this.props.delayPressOut,
|
||||
disabled: this.props.disabled,
|
||||
hitSlop: this.props.hitSlop,
|
||||
minPressDuration: 0,
|
||||
pressRectOffset: this.props.pressRetentionOffset,
|
||||
android_disableSound: this.props.touchSoundDisabled,
|
||||
onBlur: event => {
|
||||
if (Platform.isTV) {
|
||||
this._bounceTo(1, 0.4, 0);
|
||||
@@ -112,7 +113,6 @@ class TouchableBounce extends React.Component<
|
||||
this.props.onPressOut(event);
|
||||
}
|
||||
},
|
||||
pressRectOffset: this.props.pressRetentionOffset,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -123,10 +123,10 @@ class TouchableBounce extends React.Component<
|
||||
callback?: ?() => void,
|
||||
) {
|
||||
Animated.spring(this.state.scale, {
|
||||
bounciness,
|
||||
toValue,
|
||||
useNativeDriver: true,
|
||||
velocity,
|
||||
bounciness,
|
||||
useNativeDriver: true,
|
||||
}).start(callback);
|
||||
}
|
||||
|
||||
@@ -230,6 +230,6 @@ export default (function TouchableBounceWrapper({
|
||||
}) {
|
||||
return <TouchableBounce {...props} hostRef={hostRef} />;
|
||||
} as component(
|
||||
ref?: React.RefSetter<mixed>,
|
||||
ref: React.RefSetter<mixed>,
|
||||
...props: $ReadOnly<Omit<TouchableBounceProps, 'hostRef'>>
|
||||
));
|
||||
|
||||
@@ -21,14 +21,12 @@ const ViewNativeComponent: HostComponent<Props> =
|
||||
}));
|
||||
|
||||
interface NativeCommands {
|
||||
+focus: () => void;
|
||||
+blur: () => void;
|
||||
+hotspotUpdate: (viewRef: HostInstance, x: number, y: number) => void;
|
||||
+setPressed: (viewRef: HostInstance, pressed: boolean) => void;
|
||||
}
|
||||
|
||||
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
|
||||
supportedCommands: ['focus', 'blur', 'hotspotUpdate', 'setPressed'],
|
||||
supportedCommands: ['hotspotUpdate', 'setPressed'],
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
+21
-21
@@ -39,24 +39,6 @@ function DebuggingOverlay({
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => ({
|
||||
clearElementsHighlight() {
|
||||
if (!isNativeComponentReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nativeComponentRef.current != null) {
|
||||
Commands.clearElementsHighlights(nativeComponentRef.current);
|
||||
}
|
||||
},
|
||||
highlightElements(elements) {
|
||||
if (!isNativeComponentReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nativeComponentRef.current != null) {
|
||||
Commands.highlightElements(nativeComponentRef.current, elements);
|
||||
}
|
||||
},
|
||||
highlightTraceUpdates(updates) {
|
||||
if (!isNativeComponentReady) {
|
||||
return;
|
||||
@@ -73,6 +55,24 @@ function DebuggingOverlay({
|
||||
);
|
||||
}
|
||||
},
|
||||
highlightElements(elements) {
|
||||
if (!isNativeComponentReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nativeComponentRef.current != null) {
|
||||
Commands.highlightElements(nativeComponentRef.current, elements);
|
||||
}
|
||||
},
|
||||
clearElementsHighlight() {
|
||||
if (!isNativeComponentReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nativeComponentRef.current != null) {
|
||||
Commands.clearElementsHighlights(nativeComponentRef.current);
|
||||
}
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
@@ -95,14 +95,14 @@ function DebuggingOverlay({
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
},
|
||||
});
|
||||
|
||||
export default DebuggingOverlay as component(
|
||||
ref?: React.RefSetter<DebuggingOverlayHandle>,
|
||||
ref: React.RefSetter<DebuggingOverlayHandle>,
|
||||
);
|
||||
|
||||
+6
-3
@@ -8,8 +8,11 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {HostInstance} from '../..';
|
||||
import type {AbstractImageAndroid, AbstractImageIOS} from './ImageTypes.flow';
|
||||
import type {
|
||||
AbstractImageAndroid,
|
||||
AbstractImageIOS,
|
||||
ImageType as ImageComponent,
|
||||
} from './ImageTypes.flow';
|
||||
|
||||
import useMergeRefs from '../Utilities/useMergeRefs';
|
||||
import * as React from 'react';
|
||||
@@ -30,7 +33,7 @@ export function unstable_getImageComponentDecorator(): ?ImageComponentDecorator
|
||||
return injectedImageComponentDecorator;
|
||||
}
|
||||
|
||||
type ImageInstance = HostInstance;
|
||||
type ImageInstance = React.ElementRef<ImageComponent>;
|
||||
|
||||
type ImageAttachedCallback = (
|
||||
imageInstance: ImageInstance,
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {HostInstance} from '../..';
|
||||
import type {RootTag} from '../Types/RootTagTypes';
|
||||
import type {ResolvedAssetSource} from './AssetSourceResolver';
|
||||
import type {ImageProps as ImagePropsType} from './ImageProps';
|
||||
import type {ImageSource} from './ImageSource';
|
||||
import typeof ImageViewNativeComponent from './ImageViewNativeComponent';
|
||||
import typeof TextInlineImageNativeComponent from './TextInlineImageNativeComponent';
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
@@ -66,14 +67,17 @@ type ImageComponentStaticsAndroid = $ReadOnly<{
|
||||
}>;
|
||||
|
||||
export type AbstractImageAndroid = component(
|
||||
ref?: React.RefSetter<HostInstance>,
|
||||
ref?: React.RefSetter<
|
||||
| React.ElementRef<TextInlineImageNativeComponent>
|
||||
| React.ElementRef<ImageViewNativeComponent>,
|
||||
>,
|
||||
...props: ImagePropsType
|
||||
);
|
||||
|
||||
export type ImageAndroid = AbstractImageAndroid & ImageComponentStaticsAndroid;
|
||||
|
||||
export type AbstractImageIOS = component(
|
||||
ref?: React.RefSetter<HostInstance>,
|
||||
ref?: React.RefSetter<React.ElementRef<ImageViewNativeComponent>>,
|
||||
...props: ImagePropsType
|
||||
);
|
||||
|
||||
|
||||
+51
-6
@@ -12,6 +12,7 @@
|
||||
|
||||
import type {GestureResponderEvent} from '../Types/CoreEventTypes';
|
||||
|
||||
const InteractionManager = require('./InteractionManager').default;
|
||||
const TouchHistoryMath = require('./TouchHistoryMath').default;
|
||||
|
||||
const currentCentroidXOfTouchesChangedAfter =
|
||||
@@ -30,6 +31,9 @@ const currentCentroidY = TouchHistoryMath.currentCentroidY;
|
||||
* single-touch gestures resilient to extra touches, and can be used to
|
||||
* recognize simple multi-touch gestures.
|
||||
*
|
||||
* By default, `PanResponder` holds an `InteractionManager` handle to block
|
||||
* long-running JS events from interrupting active gestures.
|
||||
*
|
||||
* It provides a predictable wrapper of the responder handlers provided by the
|
||||
* [gesture responder system](docs/gesture-responder-system.html).
|
||||
* For each handler, it provides a new `gestureState` object alongside the
|
||||
@@ -401,6 +405,9 @@ const PanResponder = {
|
||||
getInteractionHandle: () => ?number,
|
||||
panHandlers: GestureResponderHandlerMethods,
|
||||
} {
|
||||
const interactionState = {
|
||||
handle: (null: ?number),
|
||||
};
|
||||
const gestureState: PanResponderGestureState = {
|
||||
// Useful for debugging
|
||||
stateID: Math.random(),
|
||||
@@ -457,6 +464,10 @@ const PanResponder = {
|
||||
},
|
||||
|
||||
onResponderGrant(event: GestureResponderEvent): boolean {
|
||||
if (!interactionState.handle) {
|
||||
interactionState.handle =
|
||||
InteractionManager.createInteractionHandle();
|
||||
}
|
||||
gestureState.x0 = currentCentroidX(event.touchHistory);
|
||||
gestureState.y0 = currentCentroidY(event.touchHistory);
|
||||
gestureState.dx = 0;
|
||||
@@ -471,11 +482,21 @@ const PanResponder = {
|
||||
},
|
||||
|
||||
onResponderReject(event: GestureResponderEvent): void {
|
||||
config.onPanResponderReject?.call(undefined, event, gestureState);
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
config.onPanResponderReject,
|
||||
event,
|
||||
gestureState,
|
||||
);
|
||||
},
|
||||
|
||||
onResponderRelease(event: GestureResponderEvent): void {
|
||||
config.onPanResponderRelease?.call(undefined, event, gestureState);
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
config.onPanResponderRelease,
|
||||
event,
|
||||
gestureState,
|
||||
);
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
@@ -508,11 +529,21 @@ const PanResponder = {
|
||||
onResponderEnd(event: GestureResponderEvent): void {
|
||||
const touchHistory = event.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
config.onPanResponderEnd?.call(undefined, event, gestureState);
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
config.onPanResponderEnd,
|
||||
event,
|
||||
gestureState,
|
||||
);
|
||||
},
|
||||
|
||||
onResponderTerminate(event: GestureResponderEvent): void {
|
||||
config.onPanResponderTerminate?.call(undefined, event, gestureState);
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
config.onPanResponderTerminate,
|
||||
event,
|
||||
gestureState,
|
||||
);
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
@@ -525,13 +556,27 @@ const PanResponder = {
|
||||
return {
|
||||
panHandlers,
|
||||
getInteractionHandle(): ?number {
|
||||
// TODO: Deprecate and delete this method.
|
||||
return null;
|
||||
return interactionState.handle;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
function clearInteractionHandle(
|
||||
interactionState: {handle: ?number, ...},
|
||||
callback: ?(ActiveCallback | PassiveCallback),
|
||||
event: GestureResponderEvent,
|
||||
gestureState: PanResponderGestureState,
|
||||
) {
|
||||
if (interactionState.handle) {
|
||||
InteractionManager.clearInteractionHandle(interactionState.handle);
|
||||
interactionState.handle = null;
|
||||
}
|
||||
if (callback) {
|
||||
callback(event, gestureState);
|
||||
}
|
||||
}
|
||||
|
||||
export type PanResponderInstance = ReturnType<(typeof PanResponder)['create']>;
|
||||
|
||||
export default PanResponder;
|
||||
|
||||
@@ -129,13 +129,11 @@ export function getWithFallback_DEPRECATED<Config: {...}>(
|
||||
// `getRuntimeConfig == null` when static view configs are disabled
|
||||
// If `setRuntimeConfigProvider` is not configured, use native reflection.
|
||||
if (hasNativeViewConfig(name)) {
|
||||
/* $FlowFixMe[incompatible-type] Extra ref prop */
|
||||
return get<Config>(name, viewConfigProvider);
|
||||
}
|
||||
} else {
|
||||
// If there is no runtime config, then the native component is unavailable.
|
||||
if (getRuntimeConfig(name) != null) {
|
||||
/* $FlowFixMe[incompatible-type] Extra ref prop */
|
||||
return get<Config>(name, viewConfigProvider);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-15
@@ -14,37 +14,29 @@ import NativeDevLoadingView from './NativeDevLoadingView';
|
||||
|
||||
const COLOR_SCHEME = {
|
||||
dark: {
|
||||
refresh: {
|
||||
backgroundColor: '#2584e8',
|
||||
textColor: '#ffffff',
|
||||
},
|
||||
load: {
|
||||
backgroundColor: '#fafafa',
|
||||
textColor: '#242526',
|
||||
},
|
||||
refresh: {
|
||||
backgroundColor: '#2584e8',
|
||||
textColor: '#ffffff',
|
||||
},
|
||||
error: {
|
||||
backgroundColor: '#1065AF',
|
||||
textColor: '#ffffff',
|
||||
},
|
||||
},
|
||||
default: {
|
||||
load: {
|
||||
backgroundColor: '#404040',
|
||||
textColor: '#ffffff',
|
||||
},
|
||||
refresh: {
|
||||
backgroundColor: '#2584e8',
|
||||
textColor: '#ffffff',
|
||||
},
|
||||
error: {
|
||||
backgroundColor: '#1065AF',
|
||||
load: {
|
||||
backgroundColor: '#404040',
|
||||
textColor: '#ffffff',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
showMessage(message: string, type: 'load' | 'refresh' | 'error') {
|
||||
showMessage(message: string, type: 'load' | 'refresh') {
|
||||
if (NativeDevLoadingView) {
|
||||
const colorScheme =
|
||||
getColorScheme() === 'dark' ? COLOR_SCHEME.dark : COLOR_SCHEME.default;
|
||||
|
||||
+4
-7
@@ -232,6 +232,8 @@ Error: ${e.message}`;
|
||||
});
|
||||
|
||||
client.on('error', data => {
|
||||
DevLoadingView.hide();
|
||||
|
||||
if (data.type === 'GraphNotFoundError') {
|
||||
client.close();
|
||||
setHMRUnavailableReason(
|
||||
@@ -251,6 +253,8 @@ Error: ${e.message}`;
|
||||
});
|
||||
|
||||
client.on('close', closeEvent => {
|
||||
DevLoadingView.hide();
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
|
||||
// https://www.rfc-editor.org/rfc/rfc6455.html#section-7.1.5
|
||||
const isNormalOrUnsetCloseReason =
|
||||
@@ -292,17 +296,10 @@ function setHMRUnavailableReason(reason: string) {
|
||||
}
|
||||
hmrUnavailableReason = reason;
|
||||
|
||||
const DevLoadingView = require('./DevLoadingView').default;
|
||||
DevLoadingView.hide();
|
||||
|
||||
// We only want to show a warning if Fast Refresh is on *and* if we ever
|
||||
// previously managed to connect successfully. We don't want to show
|
||||
// the warning to native engineers who use cached bundles without Metro.
|
||||
if (hmrClient.isEnabled() && didConnect) {
|
||||
DevLoadingView.showMessage(
|
||||
'Fast Refresh disconnected. Reload app to reconnect.',
|
||||
'error',
|
||||
);
|
||||
console.warn(reason);
|
||||
// (Not using the `warning` module to prevent a Buck cycle.)
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ let reactJsInspectorTracing = RNTarget(
|
||||
name: .reactJsInspectorTracing,
|
||||
path: "ReactCommon/jsinspector-modern/tracing",
|
||||
excludedPaths: ["tests"],
|
||||
dependencies: [.reactNativeDependencies, .reactFeatureFlags, .reactJsInspectorNetwork, .jsi, .reactOSCompat]
|
||||
dependencies: [.reactNativeDependencies, .reactFeatureFlags, .jsi, .reactOSCompat]
|
||||
)
|
||||
|
||||
/// React-jsinspectornetwork.podspec
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#import <React/RCTEventEmitter.h>
|
||||
|
||||
RCT_EXTERN void RCTEnableAppearancePreference(BOOL enabled);
|
||||
RCT_EXTERN void RCTOverrideAppearancePreference(NSString *);
|
||||
RCT_EXTERN void RCTOverrideAppearancePreference(NSString *const);
|
||||
RCT_EXTERN void RCTUseKeyWindowForSystemStyle(BOOL useMainScreen);
|
||||
RCT_EXTERN NSString *RCTCurrentOverrideAppearancePreference(void);
|
||||
RCT_EXTERN NSString *RCTColorSchemePreference(UITraitCollection *traitCollection);
|
||||
|
||||
@@ -85,6 +85,14 @@ RCT_EXPORT_MODULE()
|
||||
dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), self->_initialMessageBlock);
|
||||
}
|
||||
|
||||
- (void)hideBannerAfter:(CGFloat)delay
|
||||
{
|
||||
// Cancel previous hide call after the delay.
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hide) object:nil];
|
||||
// Set new hide call after a delay.
|
||||
[self performSelector:@selector(hide) withObject:nil afterDelay:delay];
|
||||
}
|
||||
|
||||
- (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor
|
||||
{
|
||||
if (!RCTDevLoadingViewGetEnabled() || _hiding) {
|
||||
@@ -120,9 +128,6 @@ RCT_EXPORT_MODULE()
|
||||
self->_container = [[UIView alloc] init];
|
||||
self->_container.backgroundColor = backgroundColor;
|
||||
self->_container.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
|
||||
[self->_container addGestureRecognizer:tapGesture];
|
||||
self->_container.userInteractionEnabled = YES;
|
||||
|
||||
self->_label = [[UILabel alloc] init];
|
||||
self->_label.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
@@ -153,6 +158,8 @@ RCT_EXPORT_MODULE()
|
||||
[self->_label.centerXAnchor constraintEqualToAnchor:self->_container.centerXAnchor],
|
||||
[self->_label.bottomAnchor constraintEqualToAnchor:self->_container.bottomAnchor constant:-5],
|
||||
]];
|
||||
|
||||
[self hideBannerAfter:15.0];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -365,14 +365,11 @@ RCT_EXPORT_MODULE()
|
||||
handler:^(__unused UIAlertAction *action) {
|
||||
[weakSelf setDefaultJSBundle];
|
||||
}]];
|
||||
UIAlertAction *configCancelAction =
|
||||
[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(__unused UIAlertAction *action) {
|
||||
return;
|
||||
}];
|
||||
[configCancelAction setValue:[UIColor systemRedColor] forKey:@"titleTextColor"];
|
||||
[alertController addAction:configCancelAction];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(__unused UIAlertAction *action) {
|
||||
return;
|
||||
}]];
|
||||
[RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL];
|
||||
}]];
|
||||
|
||||
@@ -393,11 +390,6 @@ RCT_EXPORT_METHOD(show)
|
||||
|
||||
_actionSheet = [UIAlertController alertControllerWithTitle:@"React Native Dev Menu" message:nil preferredStyle:style];
|
||||
|
||||
NSAttributedString *title =
|
||||
[[NSAttributedString alloc] initWithString:@"React Native Dev Menu"
|
||||
attributes:@{NSFontAttributeName : [UIFont boldSystemFontOfSize:17]}];
|
||||
[_actionSheet setValue:title forKey:@"_attributedTitle"];
|
||||
|
||||
NSArray<RCTDevMenuItem *> *items = [self _menuItemsToPresent];
|
||||
for (RCTDevMenuItem *item in items) {
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:item.title
|
||||
@@ -407,11 +399,9 @@ RCT_EXPORT_METHOD(show)
|
||||
[_actionSheet addAction:action];
|
||||
}
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:[self alertActionHandlerForDevItem:nil]];
|
||||
[cancelAction setValue:[UIColor systemRedColor] forKey:@"titleTextColor"];
|
||||
[_actionSheet addAction:cancelAction];
|
||||
[_actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:[self alertActionHandlerForDevItem:nil]]];
|
||||
|
||||
_presentedItems = items;
|
||||
[RCTPresentedViewController() presentViewController:_actionSheet animated:YES completion:nil];
|
||||
|
||||
+4
-62
@@ -650,9 +650,7 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
||||
|
||||
BOOL isPointInside = [self pointInside:point withEvent:event];
|
||||
|
||||
UIView *currentContainerView = self.currentContainerView;
|
||||
|
||||
BOOL clipsToBounds = currentContainerView.clipsToBounds;
|
||||
BOOL clipsToBounds = self.currentContainerView.clipsToBounds;
|
||||
|
||||
clipsToBounds = clipsToBounds || _layoutMetrics.overflowInset == EdgeInsets{};
|
||||
|
||||
@@ -660,8 +658,8 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (UIView *subview = nullptr in [currentContainerView.subviews reverseObjectEnumerator]) {
|
||||
UIView *hitView = [subview hitTest:[subview convertPoint:point fromView:currentContainerView] withEvent:event];
|
||||
for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
|
||||
UIView *hitView = [subview hitTest:[subview convertPoint:point fromView:self] withEvent:event];
|
||||
if (hitView) {
|
||||
return hitView;
|
||||
}
|
||||
@@ -861,7 +859,7 @@ static RCTBorderStyle RCTBorderStyleFromOutlineStyle(OutlineStyle outlineStyle)
|
||||
|
||||
if (_useCustomContainerView) {
|
||||
if (!_containerView) {
|
||||
_containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
|
||||
_containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
|
||||
for (UIView *subview = nullptr in effectiveContentView.subviews) {
|
||||
[_containerView addSubview:subview];
|
||||
}
|
||||
@@ -1542,62 +1540,6 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
|
||||
{
|
||||
if ([commandName isEqualToString:@"focus"]) {
|
||||
[self focus];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([commandName isEqualToString:@"blur"]) {
|
||||
[self blur];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)focus
|
||||
{
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (void)blur
|
||||
{
|
||||
[self resignFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - Focus Events
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
if (![super becomeFirstResponder]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (_eventEmitter && ReactNativeFeatureFlags::enableImperativeFocus()) {
|
||||
_eventEmitter->onFocus();
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
if (![super resignFirstResponder]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (_eventEmitter && ReactNativeFeatureFlags::enableImperativeFocus()) {
|
||||
_eventEmitter->onBlur();
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -61,7 +61,7 @@ RCT_EXTERN CGPathRef RCTPathCreateWithRoundedRect(
|
||||
CGRect bounds,
|
||||
RCTCornerInsets cornerInsets,
|
||||
const CGAffineTransform *transform,
|
||||
BOOL inverted);
|
||||
const BOOL inverted);
|
||||
|
||||
/**
|
||||
* Draw a CSS-compliant border as an image. You can determine if it's scalable
|
||||
|
||||
@@ -1892,7 +1892,6 @@ public final class com/facebook/react/devsupport/DefaultDevLoadingViewImplementa
|
||||
public fun <init> (Lcom/facebook/react/devsupport/ReactInstanceDevHelper;)V
|
||||
public fun hide ()V
|
||||
public fun showMessage (Ljava/lang/String;)V
|
||||
public fun showMessage (Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Double;)V
|
||||
public fun updateProgress (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;)V
|
||||
}
|
||||
|
||||
@@ -2120,7 +2119,6 @@ public abstract interface class com/facebook/react/devsupport/interfaces/DevBund
|
||||
public abstract interface class com/facebook/react/devsupport/interfaces/DevLoadingViewManager {
|
||||
public abstract fun hide ()V
|
||||
public abstract fun showMessage (Ljava/lang/String;)V
|
||||
public abstract fun showMessage (Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Double;)V
|
||||
public abstract fun updateProgress (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;)V
|
||||
}
|
||||
|
||||
|
||||
-10
@@ -328,15 +328,6 @@ public class ReactInstanceManager {
|
||||
}
|
||||
|
||||
registerCxxErrorHandlerFunc();
|
||||
|
||||
// Using `if (true)` just to prevent tests / lint errors.
|
||||
if (true) {
|
||||
// Legacy architecture of React Native is deprecated and can't be initialized anymore.
|
||||
// More details on:
|
||||
// https://github.com/react-native-community/discussions-and-proposals/blob/nc/legacy-arch-removal/proposals/0929-legacy-architecture-removal.md
|
||||
throw new UnsupportedOperationException(
|
||||
"ReactInstanceManager.createReactContext is unsupported.");
|
||||
}
|
||||
}
|
||||
|
||||
private ReactInstanceDevHelper createDevHelperInterface() {
|
||||
@@ -1455,7 +1446,6 @@ public class ReactInstanceManager {
|
||||
*/
|
||||
private ReactApplicationContext createReactContext(
|
||||
JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
|
||||
|
||||
FLog.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
|
||||
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName());
|
||||
|
||||
|
||||
+19
-24
@@ -196,11 +196,9 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
|
||||
private val nodesManagerRef = AtomicReference<NativeAnimatedNodesManager?>()
|
||||
|
||||
private var batchingControlledByJS = false // TODO T71377544: delete
|
||||
@Volatile private var currentFrameNumber: Long = 0
|
||||
|
||||
@Volatile private var currentFrameNumber: Long = 0 // TODO T71377544: delete
|
||||
|
||||
@Volatile private var currentBatchNumber: Long = 0
|
||||
@Volatile private var currentBatchNumber: Long = 0 // frame number at last operations dispatch
|
||||
|
||||
private var initializedForFabric = false
|
||||
private var initializedForNonFabric = false
|
||||
@@ -282,22 +280,19 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
|
||||
var batchNumber = currentBatchNumber - 1
|
||||
|
||||
// TODO T71377544: delete this when the JS method is confirmed safe
|
||||
if (!batchingControlledByJS) {
|
||||
// The problem we're trying to solve here: we could be in the middle of queueing
|
||||
// a batch of related animation operations when Fabric flushes a batch of MountItems.
|
||||
// It's visually bad if we execute half of the animation ops and then wait another frame
|
||||
// (or more) to execute the rest.
|
||||
// See mFrameNumber. If the dispatchedFrameNumber drifts too far - that
|
||||
// is, if no MountItems are scheduled for a while, which can happen if a tree
|
||||
// is committed but there are no changes - bring these counts back in sync and
|
||||
// execute any queued operations. This number is arbitrary, but we want it low
|
||||
// enough that the user shouldn't be able to see this delay in most cases.
|
||||
currentFrameNumber++
|
||||
if ((currentFrameNumber - currentBatchNumber) > 2) {
|
||||
currentBatchNumber = currentFrameNumber
|
||||
batchNumber = currentBatchNumber
|
||||
}
|
||||
// The problem we're trying to solve here: we could be in the middle of queueing
|
||||
// a batch of related animation operations when Fabric flushes a batch of MountItems.
|
||||
// It's visually bad if we execute half of the animation ops and then wait another frame
|
||||
// (or more) to execute the rest.
|
||||
// See mFrameNumber. If the dispatchedFrameNumber drifts too far - that
|
||||
// is, if no MountItems are scheduled for a while, which can happen if a tree
|
||||
// is committed but there are no changes - bring these counts back in sync and
|
||||
// execute any queued operations. This number is arbitrary, but we want it low
|
||||
// enough that the user shouldn't be able to see this delay in most cases.
|
||||
currentFrameNumber++
|
||||
if ((currentFrameNumber - currentBatchNumber) > 2) {
|
||||
currentBatchNumber = currentFrameNumber
|
||||
batchNumber = currentBatchNumber
|
||||
}
|
||||
|
||||
preOperations.executeBatch(batchNumber, nodesManager)
|
||||
@@ -484,14 +479,14 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun startOperationBatch() {
|
||||
batchingControlledByJS = true
|
||||
currentBatchNumber++
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
override fun finishOperationBatch() {
|
||||
batchingControlledByJS = false
|
||||
currentBatchNumber++
|
||||
// no-op
|
||||
}
|
||||
|
||||
override fun createAnimatedNode(tagDouble: Double, config: ReadableMap) {
|
||||
|
||||
-4
@@ -774,12 +774,8 @@ public class NativeAnimatedNodesManager(
|
||||
("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
|
||||
ReactSoftExceptionLogger.logSoftException(TAG, ReactNoCrashSoftException(ex))
|
||||
} else if (eventListenerInitializedForFabric) {
|
||||
// TODO T71377544: investigate these SoftExceptions and see if we can remove entirely
|
||||
// or fix the root cause
|
||||
ReactSoftExceptionLogger.logSoftException(TAG, ReactNoCrashSoftException(ex))
|
||||
} else {
|
||||
throw ex
|
||||
|
||||
+15
-19
@@ -98,7 +98,13 @@ public object DefaultNewArchitectureEntryPoint {
|
||||
ReactNativeFeatureFlags.override(ReactNativeFeatureFlagsOverrides_RNOSS_Canary_Android())
|
||||
}
|
||||
ReleaseLevel.STABLE -> {
|
||||
ReactNativeFeatureFlags.override(ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android())
|
||||
ReactNativeFeatureFlags.override(
|
||||
ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android(
|
||||
fabricEnabled,
|
||||
bridgelessEnabled,
|
||||
turboModulesEnabled,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,16 +125,6 @@ public object DefaultNewArchitectureEntryPoint {
|
||||
privateConcurrentReactEnabled = featureFlags.enableFabricRenderer()
|
||||
privateBridgelessEnabled = featureFlags.enableBridgelessArchitecture()
|
||||
|
||||
val (isValid, errorMessage) =
|
||||
isConfigurationValid(
|
||||
privateTurboModulesEnabled,
|
||||
privateFabricEnabled,
|
||||
privateBridgelessEnabled,
|
||||
)
|
||||
if (!isValid) {
|
||||
error(errorMessage)
|
||||
}
|
||||
|
||||
DefaultSoLoader.maybeLoadSoLibrary()
|
||||
}
|
||||
|
||||
@@ -162,13 +158,13 @@ public object DefaultNewArchitectureEntryPoint {
|
||||
fabricEnabled: Boolean,
|
||||
bridgelessEnabled: Boolean,
|
||||
): Pair<Boolean, String> =
|
||||
if (!turboModulesEnabled || !fabricEnabled || !bridgelessEnabled) {
|
||||
false to
|
||||
"You cannot load React Native with the New Architecture disabled. " +
|
||||
"Please use DefaultNewArchitectureEntryPoint.load() instead of " +
|
||||
"DefaultNewArchitectureEntryPoint.load(turboModulesEnabled=$turboModulesEnabled, " +
|
||||
"fabricEnabled=$fabricEnabled, bridgelessEnabled=$bridgelessEnabled)"
|
||||
} else {
|
||||
true to ""
|
||||
when {
|
||||
fabricEnabled && !turboModulesEnabled ->
|
||||
false to
|
||||
"fabricEnabled=true requires turboModulesEnabled=true (is now false) - Please update your DefaultNewArchitectureEntryPoint.load() parameters."
|
||||
bridgelessEnabled && (!turboModulesEnabled || !fabricEnabled) ->
|
||||
false to
|
||||
"bridgelessEnabled=true requires (turboModulesEnabled=true AND fabricEnabled=true) - Please update your DefaultNewArchitectureEntryPoint.load() parameters."
|
||||
else -> true to ""
|
||||
}
|
||||
}
|
||||
|
||||
+3
-13
@@ -33,14 +33,10 @@ public class DefaultDevLoadingViewImplementation(
|
||||
private var devLoadingPopup: PopupWindow? = null
|
||||
|
||||
override fun showMessage(message: String) {
|
||||
showMessage(message, color = null, backgroundColor = null)
|
||||
}
|
||||
|
||||
override fun showMessage(message: String, color: Double?, backgroundColor: Double?) {
|
||||
if (!isEnabled) {
|
||||
return
|
||||
}
|
||||
UiThreadUtil.runOnUiThread { showInternal(message, color, backgroundColor) }
|
||||
UiThreadUtil.runOnUiThread { showInternal(message) }
|
||||
}
|
||||
|
||||
override fun updateProgress(status: String?, done: Int?, total: Int?) {
|
||||
@@ -63,7 +59,7 @@ public class DefaultDevLoadingViewImplementation(
|
||||
}
|
||||
}
|
||||
|
||||
private fun showInternal(message: String, color: Double?, backgroundColor: Double?) {
|
||||
private fun showInternal(message: String) {
|
||||
if (devLoadingPopup?.isShowing == true) {
|
||||
// already showing
|
||||
return
|
||||
@@ -88,19 +84,13 @@ public class DefaultDevLoadingViewImplementation(
|
||||
currentActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
val view = inflater.inflate(R.layout.dev_loading_view, null) as TextView
|
||||
view.text = message
|
||||
if (color != null) {
|
||||
view.setTextColor(color.toInt())
|
||||
}
|
||||
if (backgroundColor != null) {
|
||||
view.setBackgroundColor(backgroundColor.toInt())
|
||||
}
|
||||
view.setOnClickListener { hideInternal() }
|
||||
val popup =
|
||||
PopupWindow(
|
||||
view,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
)
|
||||
popup.isTouchable = false
|
||||
popup.showAtLocation(currentActivity.window.decorView, Gravity.NO_GRAVITY, 0, topOffset)
|
||||
devLoadingView = view
|
||||
devLoadingPopup = popup
|
||||
|
||||
-2
@@ -11,8 +11,6 @@ package com.facebook.react.devsupport.interfaces
|
||||
public interface DevLoadingViewManager {
|
||||
public fun showMessage(message: String)
|
||||
|
||||
public fun showMessage(message: String, color: Double?, backgroundColor: Double?)
|
||||
|
||||
public fun updateProgress(status: String?, done: Int?, total: Int?)
|
||||
|
||||
public fun hide()
|
||||
|
||||
-3
@@ -821,9 +821,6 @@ public class SurfaceMountingManager {
|
||||
@UnstableReactNativeAPI
|
||||
public void experimental_prefetchResources(
|
||||
int surfaceId, String componentName, MapBuffer params) {
|
||||
if (isStopped()) {
|
||||
return;
|
||||
}
|
||||
mViewManagerRegistry
|
||||
.get(componentName)
|
||||
.experimental_prefetchResources(
|
||||
|
||||
+1
-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<<6b632ac7553ae149fa42a67efde5acfa>>
|
||||
* @generated SignedSource<<f089964c958dfcac00f83c3371ccbefc>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -180,12 +180,6 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun enableImagePrefetchingAndroid(): Boolean = accessor.enableImagePrefetchingAndroid()
|
||||
|
||||
/**
|
||||
* When enabled, Android will build and initiate image prefetch requests on ImageShadowNode::layout and batch them together in a single JNI call
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun enableImagePrefetchingJNIBatchingAndroid(): Boolean = accessor.enableImagePrefetchingJNIBatchingAndroid()
|
||||
|
||||
/**
|
||||
* When enabled, Android will initiate image prefetch requested on ImageShadowNode::layout on the UI thread
|
||||
*/
|
||||
@@ -198,12 +192,6 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean = accessor.enableImmediateUpdateModeForContentOffsetChanges()
|
||||
|
||||
/**
|
||||
* Enable ref.focus() and ref.blur() for all views, not just TextInput.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun enableImperativeFocus(): Boolean = accessor.enableImperativeFocus()
|
||||
|
||||
/**
|
||||
* This is to fix the issue with interop view manager where component descriptor lookup is causing ViewManager to preload.
|
||||
*/
|
||||
|
||||
+1
-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<<c228bdbf6120b4715f49e03c04918a7c>>
|
||||
* @generated SignedSource<<912dec895495052328e7e52b94a6738a>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -45,10 +45,8 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null
|
||||
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
|
||||
private var enableImagePrefetchingAndroidCache: Boolean? = null
|
||||
private var enableImagePrefetchingJNIBatchingAndroidCache: Boolean? = null
|
||||
private var enableImagePrefetchingOnUiThreadAndroidCache: Boolean? = null
|
||||
private var enableImmediateUpdateModeForContentOffsetChangesCache: Boolean? = null
|
||||
private var enableImperativeFocusCache: Boolean? = null
|
||||
private var enableInteropViewManagerClassLookUpOptimizationIOSCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
|
||||
@@ -321,15 +319,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableImagePrefetchingJNIBatchingAndroid(): Boolean {
|
||||
var cached = enableImagePrefetchingJNIBatchingAndroidCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.enableImagePrefetchingJNIBatchingAndroid()
|
||||
enableImagePrefetchingJNIBatchingAndroidCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableImagePrefetchingOnUiThreadAndroid(): Boolean {
|
||||
var cached = enableImagePrefetchingOnUiThreadAndroidCache
|
||||
if (cached == null) {
|
||||
@@ -348,15 +337,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableImperativeFocus(): Boolean {
|
||||
var cached = enableImperativeFocusCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.enableImperativeFocus()
|
||||
enableImperativeFocusCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean {
|
||||
var cached = enableInteropViewManagerClassLookUpOptimizationIOSCache
|
||||
if (cached == null) {
|
||||
|
||||
+1
-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<<26dce1945df5641ab84cbca9eaf2b10f>>
|
||||
* @generated SignedSource<<ba1e53d93b9fdaf298a034543bc44a57>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -78,14 +78,10 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableImagePrefetchingAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableImagePrefetchingJNIBatchingAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableImagePrefetchingOnUiThreadAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableImperativeFocus(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnAndroid(): Boolean
|
||||
|
||||
+1
-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<<11051ece1b61fd4bf4ca003a3b7fc4f9>>
|
||||
* @generated SignedSource<<7601cbcde75ff19ef0fe67f6faef2549>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -73,14 +73,10 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun enableImagePrefetchingAndroid(): Boolean = false
|
||||
|
||||
override fun enableImagePrefetchingJNIBatchingAndroid(): Boolean = false
|
||||
|
||||
override fun enableImagePrefetchingOnUiThreadAndroid(): Boolean = false
|
||||
|
||||
override fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean = false
|
||||
|
||||
override fun enableImperativeFocus(): Boolean = false
|
||||
|
||||
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean = false
|
||||
|
||||
override fun enableLayoutAnimationsOnAndroid(): Boolean = false
|
||||
|
||||
+1
-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<<66fa583c37021750123a483ab0ccb030>>
|
||||
* @generated SignedSource<<3a13f8e35423b634ed4ef46fbac3c1e9>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -49,10 +49,8 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null
|
||||
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
|
||||
private var enableImagePrefetchingAndroidCache: Boolean? = null
|
||||
private var enableImagePrefetchingJNIBatchingAndroidCache: Boolean? = null
|
||||
private var enableImagePrefetchingOnUiThreadAndroidCache: Boolean? = null
|
||||
private var enableImmediateUpdateModeForContentOffsetChangesCache: Boolean? = null
|
||||
private var enableImperativeFocusCache: Boolean? = null
|
||||
private var enableInteropViewManagerClassLookUpOptimizationIOSCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
|
||||
@@ -350,16 +348,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableImagePrefetchingJNIBatchingAndroid(): Boolean {
|
||||
var cached = enableImagePrefetchingJNIBatchingAndroidCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.enableImagePrefetchingJNIBatchingAndroid()
|
||||
accessedFeatureFlags.add("enableImagePrefetchingJNIBatchingAndroid")
|
||||
enableImagePrefetchingJNIBatchingAndroidCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableImagePrefetchingOnUiThreadAndroid(): Boolean {
|
||||
var cached = enableImagePrefetchingOnUiThreadAndroidCache
|
||||
if (cached == null) {
|
||||
@@ -380,16 +368,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableImperativeFocus(): Boolean {
|
||||
var cached = enableImperativeFocusCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.enableImperativeFocus()
|
||||
accessedFeatureFlags.add("enableImperativeFocus")
|
||||
enableImperativeFocusCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean {
|
||||
var cached = enableInteropViewManagerClassLookUpOptimizationIOSCache
|
||||
if (cached == null) {
|
||||
|
||||
+1
-3
@@ -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<<dffc5db0f80501f6246f9d6087c6fb4a>>
|
||||
* @generated SignedSource<<4feeb3c1789d8169dd93bee7ae1ff1ac>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -25,7 +25,5 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android :
|
||||
|
||||
override fun enableAccessibilityOrder(): Boolean = true
|
||||
|
||||
override fun enableSwiftUIBasedFilters(): Boolean = true
|
||||
|
||||
override fun preventShadowTreeCommitExhaustion(): Boolean = true
|
||||
}
|
||||
|
||||
+9
-3
@@ -7,10 +7,16 @@
|
||||
|
||||
package com.facebook.react.internal.featureflags
|
||||
|
||||
public class ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android() :
|
||||
ReactNativeNewArchitectureFeatureFlagsDefaults() {
|
||||
public class ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android(
|
||||
private val fabricEnabled: Boolean,
|
||||
private val bridgelessEnabled: Boolean,
|
||||
private val turboModulesEnabled: Boolean,
|
||||
) : ReactNativeNewArchitectureFeatureFlagsDefaults(bridgelessEnabled) {
|
||||
override fun useFabricInterop(): Boolean = bridgelessEnabled || fabricEnabled
|
||||
|
||||
override fun useFabricInterop(): Boolean = true
|
||||
override fun enableFabricRenderer(): Boolean = bridgelessEnabled || fabricEnabled
|
||||
|
||||
override fun useTurboModules(): Boolean = bridgelessEnabled || turboModulesEnabled
|
||||
|
||||
override fun useShadowNodeStateOnClone(): Boolean = true
|
||||
}
|
||||
|
||||
+1
-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<<f26998daf87c8b90c2ec822c8316b134>>
|
||||
* @generated SignedSource<<143b568248e68033efaefc3f178ff6db>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -73,14 +73,10 @@ public interface ReactNativeFeatureFlagsProvider {
|
||||
|
||||
@DoNotStrip public fun enableImagePrefetchingAndroid(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableImagePrefetchingJNIBatchingAndroid(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableImagePrefetchingOnUiThreadAndroid(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableImperativeFocus(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableLayoutAnimationsOnAndroid(): Boolean
|
||||
|
||||
+3
-5
@@ -20,11 +20,9 @@ package com.facebook.react.internal.featureflags
|
||||
* When the new architecture is enabled, we want to set the default values of the flags for Fabric,
|
||||
* TurboModules and Bridgeless as enabled by default.
|
||||
*/
|
||||
public open class ReactNativeNewArchitectureFeatureFlagsDefaults() :
|
||||
ReactNativeFeatureFlagsDefaults() {
|
||||
|
||||
private val newArchitectureEnabled: Boolean = true
|
||||
|
||||
public open class ReactNativeNewArchitectureFeatureFlagsDefaults(
|
||||
private val newArchitectureEnabled: Boolean = true
|
||||
) : ReactNativeFeatureFlagsDefaults() {
|
||||
override fun enableBridgelessArchitecture(): Boolean = newArchitectureEnabled
|
||||
|
||||
override fun enableFabricRenderer(): Boolean = newArchitectureEnabled
|
||||
|
||||
+1
-3
@@ -31,9 +31,7 @@ internal class DevLoadingModule(reactContext: ReactApplicationContext) :
|
||||
}
|
||||
|
||||
override fun showMessage(message: String, color: Double?, backgroundColor: Double?) {
|
||||
UiThreadUtil.runOnUiThread {
|
||||
devLoadingViewManager?.showMessage(message, color, backgroundColor)
|
||||
}
|
||||
UiThreadUtil.runOnUiThread { devLoadingViewManager?.showMessage(message) }
|
||||
}
|
||||
|
||||
override fun hide() {
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.view.View
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import android.view.animation.AccelerateInterpolator
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.BaseInterpolator
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.view.animation.Interpolator
|
||||
import android.view.animation.LinearInterpolator
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
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
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException
|
||||
|
||||
/**
|
||||
* Class responsible for parsing and converting layout animation data into native [Animation] in
|
||||
* order to animate layout when a valid configuration has been supplied by the application.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal abstract class AbstractLayoutAnimation {
|
||||
var interpolator: Interpolator? = null
|
||||
var delayMs: Int = 0
|
||||
var animatedProperty: AnimatedPropertyType? = null
|
||||
var durationMs: Int = 0
|
||||
|
||||
internal abstract fun isValid(): Boolean
|
||||
|
||||
/**
|
||||
* Create an animation object for the current animation type, based on the view and final screen
|
||||
* coordinates. If the application-supplied configuration does not specify an animation definition
|
||||
* for this types, or if the animation definition is invalid, returns null.
|
||||
*/
|
||||
internal abstract fun createAnimationImpl(
|
||||
view: View,
|
||||
x: Int,
|
||||
y: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
): Animation?
|
||||
|
||||
fun reset() {
|
||||
animatedProperty = null
|
||||
durationMs = 0
|
||||
delayMs = 0
|
||||
interpolator = null
|
||||
}
|
||||
|
||||
fun initializeFromConfig(data: ReadableMap, globalDuration: Int) {
|
||||
animatedProperty =
|
||||
if (data.hasKey("property")) {
|
||||
AnimatedPropertyType.fromString(data.getString("property").orEmpty())
|
||||
} else {
|
||||
null
|
||||
}
|
||||
durationMs = if (data.hasKey("duration")) data.getInt("duration") else globalDuration
|
||||
delayMs = if (data.hasKey("delay")) data.getInt("delay") else 0
|
||||
require(data.hasKey("type")) { "Missing interpolation type." }
|
||||
|
||||
interpolator =
|
||||
getInterpolator(InterpolatorType.fromString(data.getString("type").orEmpty()), data)
|
||||
|
||||
if (!isValid()) {
|
||||
throw IllegalViewOperationException("Invalid layout animation : $data")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an animation object to be used to animate the view, based on the animation config
|
||||
* supplied at initialization time and the new view position and size.
|
||||
*
|
||||
* @param view the view to create the animation for
|
||||
* @param x the new X position for the view
|
||||
* @param y the new Y position for the view
|
||||
* @param width the new width value for the view
|
||||
* @param height the new height value for the view
|
||||
*/
|
||||
fun createAnimation(view: View, x: Int, y: Int, width: Int, height: Int): Animation? {
|
||||
if (!isValid()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return createAnimationImpl(view, x, y, width, height)?.apply {
|
||||
val slowdownFactor = if (SLOWDOWN_ANIMATION_MODE) 10 else 1
|
||||
duration = (durationMs * slowdownFactor).toLong()
|
||||
startOffset = (delayMs * slowdownFactor).toLong()
|
||||
interpolator = this@AbstractLayoutAnimation.interpolator
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"AbstractLayoutAnimation",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
|
||||
// Forces animation to be playing 10x slower, used for debug purposes.
|
||||
private const val SLOWDOWN_ANIMATION_MODE = false
|
||||
|
||||
private val INTERPOLATOR: Map<InterpolatorType, BaseInterpolator> =
|
||||
mapOf(
|
||||
InterpolatorType.LINEAR to LinearInterpolator(),
|
||||
InterpolatorType.EASE_IN to AccelerateInterpolator(),
|
||||
InterpolatorType.EASE_OUT to DecelerateInterpolator(),
|
||||
InterpolatorType.EASE_IN_EASE_OUT to AccelerateDecelerateInterpolator(),
|
||||
)
|
||||
|
||||
@VisibleForTesting
|
||||
fun getInterpolator(type: InterpolatorType, params: ReadableMap): Interpolator {
|
||||
val interpolator =
|
||||
if (type == InterpolatorType.SPRING) {
|
||||
SimpleSpringInterpolator(SimpleSpringInterpolator.getSpringDamping(params))
|
||||
} else {
|
||||
INTERPOLATOR[type]
|
||||
}
|
||||
requireNotNull(interpolator) { "Missing interpolator for type : $type" }
|
||||
return interpolator
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
|
||||
/**
|
||||
* Enum representing the different view properties that can be used when animating layout for view
|
||||
* creation.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal enum class AnimatedPropertyType {
|
||||
OPACITY,
|
||||
SCALE_X,
|
||||
SCALE_Y,
|
||||
SCALE_XY;
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromString(name: String): AnimatedPropertyType {
|
||||
return when (name) {
|
||||
"opacity" -> OPACITY
|
||||
"scaleX" -> SCALE_X
|
||||
"scaleY" -> SCALE_Y
|
||||
"scaleXY" -> SCALE_XY
|
||||
else -> throw IllegalArgumentException("Unsupported animated property: $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.ScaleAnimation
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException
|
||||
|
||||
/** Class responsible for default layout animation, i.e animation of view creation and deletion. */
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal abstract class BaseLayoutAnimation : AbstractLayoutAnimation() {
|
||||
abstract fun isReverse(): Boolean
|
||||
|
||||
override fun isValid(): Boolean = durationMs > 0 && animatedProperty != null
|
||||
|
||||
override fun createAnimationImpl(view: View, x: Int, y: Int, width: Int, height: Int): Animation {
|
||||
animatedProperty?.let {
|
||||
return when (it) {
|
||||
AnimatedPropertyType.OPACITY -> {
|
||||
val fromValue = if (isReverse()) view.alpha else 0.0f
|
||||
val toValue = if (isReverse()) 0.0f else view.alpha
|
||||
OpacityAnimation(view, fromValue, toValue)
|
||||
}
|
||||
|
||||
AnimatedPropertyType.SCALE_XY -> {
|
||||
val fromValue = if (isReverse()) 1.0f else 0.0f
|
||||
val toValue = if (isReverse()) 0.0f else 1.0f
|
||||
ScaleAnimation(
|
||||
fromValue,
|
||||
toValue,
|
||||
fromValue,
|
||||
toValue,
|
||||
Animation.RELATIVE_TO_SELF,
|
||||
.5f,
|
||||
Animation.RELATIVE_TO_SELF,
|
||||
.5f,
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedPropertyType.SCALE_X -> {
|
||||
val fromValue = if (isReverse()) 1.0f else 0.0f
|
||||
val toValue = if (isReverse()) 0.0f else 1.0f
|
||||
ScaleAnimation(
|
||||
fromValue,
|
||||
toValue,
|
||||
1f,
|
||||
1f,
|
||||
Animation.RELATIVE_TO_SELF,
|
||||
.5f,
|
||||
Animation.RELATIVE_TO_SELF,
|
||||
0f,
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedPropertyType.SCALE_Y -> {
|
||||
val fromValue = if (isReverse()) 1.0f else 0.0f
|
||||
val toValue = if (isReverse()) 0.0f else 1.0f
|
||||
ScaleAnimation(
|
||||
1f,
|
||||
1f,
|
||||
fromValue,
|
||||
toValue,
|
||||
Animation.RELATIVE_TO_SELF,
|
||||
0f,
|
||||
Animation.RELATIVE_TO_SELF,
|
||||
.5f,
|
||||
)
|
||||
}
|
||||
}
|
||||
} ?: throw IllegalViewOperationException("Missing animated property from animation config")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"BaseLayoutAnimation",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
|
||||
/**
|
||||
* Enum representing the different interpolators that can be used in layout animation configuration.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal enum class InterpolatorType {
|
||||
LINEAR,
|
||||
EASE_IN,
|
||||
EASE_OUT,
|
||||
EASE_IN_EASE_OUT,
|
||||
SPRING;
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromString(name: String): InterpolatorType {
|
||||
return when (name.lowercase()) {
|
||||
"linear" -> LINEAR
|
||||
"easein" -> EASE_IN
|
||||
"easeout" -> EASE_OUT
|
||||
"easeineaseout" -> EASE_IN_EASE_OUT
|
||||
"spring" -> SPRING
|
||||
else -> throw IllegalArgumentException("Unsupported interpolation type : $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+174
-22
@@ -9,12 +9,19 @@
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.util.SparseArray
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.Animation.AnimationListener
|
||||
import com.facebook.react.bridge.Callback
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.bridge.UiThreadUtil.assertOnUiThread
|
||||
import com.facebook.react.bridge.UiThreadUtil.getUiThreadHandler
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger.assertLegacyArchitecture
|
||||
import com.facebook.react.uimanager.layoutanimation.LayoutAnimationType.Companion.toString
|
||||
import javax.annotation.concurrent.NotThreadSafe
|
||||
|
||||
/**
|
||||
@@ -29,27 +36,75 @@ import javax.annotation.concurrent.NotThreadSafe
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
public open class LayoutAnimationController {
|
||||
private val layoutCreateAnimation: AbstractLayoutAnimation = LayoutCreateAnimation()
|
||||
private val layoutUpdateAnimation: AbstractLayoutAnimation = LayoutUpdateAnimation()
|
||||
private val layoutDeleteAnimation: AbstractLayoutAnimation = LayoutDeleteAnimation()
|
||||
private val layoutHandlers = SparseArray<LayoutHandlingAnimation?>(0)
|
||||
|
||||
private var shouldAnimateLayout = false
|
||||
private var maxAnimationDuration: Long = -1
|
||||
private var completionRunnable: Runnable? = null
|
||||
|
||||
public fun initializeFromConfig(config: ReadableMap?, completionCallback: Callback?) {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutAnimationController",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
if (config == null) {
|
||||
reset()
|
||||
return
|
||||
}
|
||||
|
||||
shouldAnimateLayout = false
|
||||
val globalDuration = if (config.hasKey("duration")) config.getInt("duration") else 0
|
||||
if (config.hasKey(toString(LayoutAnimationType.CREATE))) {
|
||||
layoutCreateAnimation.initializeFromConfig(
|
||||
config.getMap(toString(LayoutAnimationType.CREATE))!!,
|
||||
globalDuration,
|
||||
)
|
||||
shouldAnimateLayout = true
|
||||
}
|
||||
if (config.hasKey(toString(LayoutAnimationType.UPDATE))) {
|
||||
layoutUpdateAnimation.initializeFromConfig(
|
||||
config.getMap(toString(LayoutAnimationType.UPDATE))!!,
|
||||
globalDuration,
|
||||
)
|
||||
shouldAnimateLayout = true
|
||||
}
|
||||
if (config.hasKey(toString(LayoutAnimationType.DELETE))) {
|
||||
layoutDeleteAnimation.initializeFromConfig(
|
||||
config.getMap(toString(LayoutAnimationType.DELETE))!!,
|
||||
globalDuration,
|
||||
)
|
||||
shouldAnimateLayout = true
|
||||
}
|
||||
|
||||
if (shouldAnimateLayout && completionCallback != null) {
|
||||
completionRunnable = Runnable { completionCallback.invoke(java.lang.Boolean.TRUE) }
|
||||
}
|
||||
}
|
||||
|
||||
public open fun reset() {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutAnimationController",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
layoutCreateAnimation.reset()
|
||||
layoutUpdateAnimation.reset()
|
||||
layoutDeleteAnimation.reset()
|
||||
completionRunnable = null
|
||||
shouldAnimateLayout = false
|
||||
maxAnimationDuration = -1
|
||||
for (i in layoutHandlers.size() - 1 downTo 0) {
|
||||
val animation = layoutHandlers.valueAt(i)
|
||||
if (!animation!!.isValid()) {
|
||||
layoutHandlers.removeAt(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public open fun shouldAnimateLayout(viewToAnimate: View?): Boolean {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutAnimationController",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
return false
|
||||
// if view parent is null, skip animation: view have been clipped, we don't want animation to
|
||||
// resume when view is re-attached to parent, which is the standard android animation behavior.
|
||||
// If there's a layout handling animation going on, it should be animated nonetheless since the
|
||||
// ongoing animation needs to be updated.
|
||||
if (viewToAnimate == null) {
|
||||
return false
|
||||
}
|
||||
return ((shouldAnimateLayout && viewToAnimate.parent != null) ||
|
||||
layoutHandlers[viewToAnimate.id] != null)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,10 +119,57 @@ public open class LayoutAnimationController {
|
||||
* @param height the new height value for the view
|
||||
*/
|
||||
public open fun applyLayoutUpdate(view: View, x: Int, y: Int, width: Int, height: Int) {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutAnimationController",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
assertOnUiThread()
|
||||
|
||||
val reactTag = view.id
|
||||
|
||||
// Update an ongoing animation if possible, otherwise the layout update would be ignored as
|
||||
// the existing animation would still animate to the old layout.
|
||||
val existingAnimation = layoutHandlers[reactTag]
|
||||
if (existingAnimation != null) {
|
||||
if (!existingAnimation.isValid()) {
|
||||
layoutHandlers.remove(reactTag)
|
||||
} else {
|
||||
existingAnimation.onLayoutUpdate(x, y, width, height)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which animation to use : if view is initially invisible, use create animation,
|
||||
// otherwise use update animation. This approach is easier than maintaining a list of tags
|
||||
// for recently created views.
|
||||
val layoutAnimation =
|
||||
if ((view.width == 0 || view.height == 0)) layoutCreateAnimation else layoutUpdateAnimation
|
||||
|
||||
val animation = layoutAnimation.createAnimation(view, x, y, width, height)
|
||||
|
||||
if (animation is LayoutHandlingAnimation) {
|
||||
animation.setAnimationListener(
|
||||
object : AnimationListener {
|
||||
override fun onAnimationStart(animation: Animation) {
|
||||
layoutHandlers.put(reactTag, animation as LayoutHandlingAnimation)
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
layoutHandlers.remove(reactTag)
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animation) = Unit
|
||||
}
|
||||
)
|
||||
} else {
|
||||
view.layout(x, y, x + width, y + height)
|
||||
}
|
||||
|
||||
if (animation != null) {
|
||||
val animationDuration = animation.duration
|
||||
if (animationDuration > maxAnimationDuration) {
|
||||
maxAnimationDuration = animationDuration
|
||||
scheduleCompletionCallback(animationDuration)
|
||||
}
|
||||
|
||||
view.startAnimation(animation)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,9 +181,59 @@ public open class LayoutAnimationController {
|
||||
* view.
|
||||
*/
|
||||
public open fun deleteView(view: View, listener: LayoutAnimationListener) {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutAnimationController",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
assertOnUiThread()
|
||||
|
||||
val animation =
|
||||
layoutDeleteAnimation.createAnimation(view, view.left, view.top, view.width, view.height)
|
||||
|
||||
if (animation != null) {
|
||||
disableUserInteractions(view)
|
||||
|
||||
animation.setAnimationListener(
|
||||
object : AnimationListener {
|
||||
override fun onAnimationStart(anim: Animation) = Unit
|
||||
|
||||
override fun onAnimationRepeat(anim: Animation) = Unit
|
||||
|
||||
override fun onAnimationEnd(anim: Animation) {
|
||||
listener.onAnimationEnd()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val animationDuration = animation.duration
|
||||
if (animationDuration > maxAnimationDuration) {
|
||||
scheduleCompletionCallback(animationDuration)
|
||||
maxAnimationDuration = animationDuration
|
||||
}
|
||||
|
||||
view.startAnimation(animation)
|
||||
} else {
|
||||
listener.onAnimationEnd()
|
||||
}
|
||||
}
|
||||
|
||||
/** Disables user interactions for a view and all it's subviews. */
|
||||
private fun disableUserInteractions(view: View) {
|
||||
view.isClickable = false
|
||||
if (view is ViewGroup) {
|
||||
for (i in 0 until view.childCount) {
|
||||
disableUserInteractions(view.getChildAt(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun scheduleCompletionCallback(delayMillis: Long) {
|
||||
if (completionRunnable != null) {
|
||||
val completionHandler = getUiThreadHandler()
|
||||
completionHandler.removeCallbacks(completionRunnable!!)
|
||||
completionHandler.postDelayed(completionRunnable!!, delayMillis)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
init {
|
||||
assertLegacyArchitecture("LayoutAnimationController", LegacyArchitectureLogLevel.ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
|
||||
/**
|
||||
* Enum representing the different animation type that can be specified in layout animation config.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal enum class LayoutAnimationType {
|
||||
CREATE,
|
||||
UPDATE,
|
||||
DELETE;
|
||||
|
||||
companion object {
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutAnimationType",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun toString(type: LayoutAnimationType): String {
|
||||
return when (type) {
|
||||
CREATE -> "create"
|
||||
UPDATE -> "update"
|
||||
DELETE -> "delete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
|
||||
/**
|
||||
* Class responsible for handling layout view creation animation, applied to view whenever a valid
|
||||
* config was supplied for the layout animation of CREATE type.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
internal class LayoutCreateAnimation : BaseLayoutAnimation() {
|
||||
|
||||
override fun isReverse(): Boolean = false
|
||||
|
||||
private companion object {
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutCreateAnimation",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
|
||||
/**
|
||||
* Class responsible for handling layout view deletion animation, applied to view whenever a valid
|
||||
* config was supplied for the layout animation of DELETE type.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal class LayoutDeleteAnimation : BaseLayoutAnimation() {
|
||||
|
||||
override fun isReverse(): Boolean = true
|
||||
|
||||
private companion object {
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutDeleteAnimation",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
|
||||
/** Interface for an animation type that takes care of updating the view layout. */
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal interface LayoutHandlingAnimation {
|
||||
/**
|
||||
* Notifies the animation of a layout update in case one occurs during the animation. This avoids
|
||||
* animating the view to the old layout since it's no longer correct; instead the animation should
|
||||
* update and do whatever it can so that the final layout is correct.
|
||||
*
|
||||
* @param x the new X position for the view
|
||||
* @param y the new Y position for the view
|
||||
* @param width the new width value for the view
|
||||
* @param height the new height value for the view
|
||||
*/
|
||||
fun onLayoutUpdate(x: Int, y: Int, width: Int, height: Int)
|
||||
|
||||
/**
|
||||
* Returns whether the animation is valid and should be used. Because layout animations generally
|
||||
* hold {@link java.lang.ref.WeakReference<android.view.View>} objects, it's possible that the
|
||||
* view has been garbage collected. In this case, the animation should not be used.
|
||||
*
|
||||
* @return true if the animation is valid and can be used, false otherwise
|
||||
*/
|
||||
fun isValid(): Boolean
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.TranslateAnimation
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
|
||||
/**
|
||||
* Class responsible for handling layout update animation, applied to view whenever a valid config
|
||||
* was supplied for the layout animation of UPDATE type.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal class LayoutUpdateAnimation : AbstractLayoutAnimation() {
|
||||
|
||||
override fun isValid(): Boolean = durationMs > 0
|
||||
|
||||
override fun createAnimationImpl(
|
||||
view: View,
|
||||
x: Int,
|
||||
y: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
): Animation? {
|
||||
val animateLocation = view.x.toInt() != x || view.y.toInt() != y
|
||||
val animateSize = view.width != width || view.height != height
|
||||
return if (!animateLocation && !animateSize) {
|
||||
null
|
||||
} else if (animateLocation && !animateSize && USE_TRANSLATE_ANIMATION) {
|
||||
// Use GPU-accelerated animation, however we loose the ability to resume interrupted
|
||||
// animation where it was left off. We may be able to listen to animation interruption
|
||||
// and set the layout manually in this case, so that next animation kicks off smoothly.
|
||||
TranslateAnimation(view.x - x, 0f, view.y - y, 0f)
|
||||
} else {
|
||||
// Animation is sub-optimal for perf, but scale transformation can't be use in this case.
|
||||
PositionAndSizeAnimation(view, x, y, width, height)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
// We are currently not enabling translation GPU-accelerated animated, as it creates odd
|
||||
// artifacts with native react scrollview. This needs to be investigated.
|
||||
private const val USE_TRANSLATE_ANIMATION = false
|
||||
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"LayoutUpdateAnimation",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.Transformation
|
||||
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
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* Animation responsible for updating opacity of a view. It should ideally use hardware texture to
|
||||
* optimize rendering performances.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal class OpacityAnimation(view: View, private val startOpacity: Float, endOpacity: Float) :
|
||||
Animation() {
|
||||
private val viewRef = WeakReference(view)
|
||||
private val deltaOpacity = endOpacity - startOpacity
|
||||
|
||||
init {
|
||||
setAnimationListener(OpacityAnimationListener(view))
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"OpacityAnimation",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
|
||||
class OpacityAnimationListener(view: View) : Animation.AnimationListener {
|
||||
private val viewRef = WeakReference(view)
|
||||
private var layerTypeChanged = false
|
||||
|
||||
override fun onAnimationStart(animation: Animation) {
|
||||
viewRef.get()?.let { view ->
|
||||
if (view.hasOverlappingRendering() && view.layerType == View.LAYER_TYPE_NONE) {
|
||||
layerTypeChanged = true
|
||||
view.setLayerType(View.LAYER_TYPE_HARDWARE, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
viewRef.get()?.let { view ->
|
||||
if (layerTypeChanged) {
|
||||
view.setLayerType(View.LAYER_TYPE_NONE, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animation) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
|
||||
viewRef.get()?.let { view -> view.alpha = startOpacity + deltaOpacity * interpolatedTime }
|
||||
}
|
||||
|
||||
override fun willChangeBounds(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.Transformation
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* Animation responsible for updating size and position of a view. We can't use scaling as view
|
||||
* content may not necessarily stretch. As a result, this approach is inefficient because of layout
|
||||
* passes occurring on every frame. What we might want to try to do instead is use a combined
|
||||
* ScaleAnimation and TranslateAnimation.
|
||||
*/
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal class PositionAndSizeAnimation(view: View, x: Int, y: Int, width: Int, height: Int) :
|
||||
Animation(), LayoutHandlingAnimation {
|
||||
private val viewRef = WeakReference(view)
|
||||
private var startX = 0f
|
||||
private var startY = 0f
|
||||
private var deltaX = 0f
|
||||
private var deltaY = 0f
|
||||
private var startWidth = 0
|
||||
private var startHeight = 0
|
||||
private var deltaWidth = 0
|
||||
private var deltaHeight = 0
|
||||
|
||||
init {
|
||||
calculateAnimation(x, y, width, height)
|
||||
}
|
||||
|
||||
override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
|
||||
viewRef.get()?.let { view ->
|
||||
val newX = startX + deltaX * interpolatedTime
|
||||
val newY = startY + deltaY * interpolatedTime
|
||||
val newWidth = startWidth + deltaWidth * interpolatedTime
|
||||
val newHeight = startHeight + deltaHeight * interpolatedTime
|
||||
view.layout(
|
||||
Math.round(newX),
|
||||
Math.round(newY),
|
||||
Math.round(newX + newWidth),
|
||||
Math.round(newY + newHeight),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLayoutUpdate(x: Int, y: Int, width: Int, height: Int) {
|
||||
// Layout changed during the animation, we should update our values so that the final layout
|
||||
// is correct.
|
||||
calculateAnimation(x, y, width, height)
|
||||
}
|
||||
|
||||
override fun isValid(): Boolean {
|
||||
return viewRef.get() != null
|
||||
}
|
||||
|
||||
override fun willChangeBounds(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun calculateAnimation(x: Int, y: Int, width: Int, height: Int) {
|
||||
viewRef.get()?.let { view ->
|
||||
startX = view.x - view.translationX
|
||||
startY = view.y - view.translationY
|
||||
startWidth = view.width
|
||||
startHeight = view.height
|
||||
|
||||
deltaX = x - startX
|
||||
deltaY = y - startY
|
||||
deltaWidth = width - startWidth
|
||||
deltaHeight = height - startHeight
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"PositionAndSizeAnimation",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.view.animation.Interpolator
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.bridge.ReadableType
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
|
||||
/** Simple spring interpolator */
|
||||
// TODO(7613736): Improve spring interpolator with friction and damping variable support
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal class SimpleSpringInterpolator @JvmOverloads constructor(springDamping: Float = FACTOR) :
|
||||
Interpolator {
|
||||
private val _springDamping: Float = springDamping
|
||||
|
||||
override fun getInterpolation(input: Float): Float =
|
||||
// Using mSpringDamping in this equation is not really the exact mathematical springDamping,
|
||||
// but a good approximation
|
||||
// We need to replace this equation with the right Factor that accounts for damping and
|
||||
// friction
|
||||
(1 +
|
||||
2.0.pow((-10 * input).toDouble()) *
|
||||
sin((input - _springDamping / 4) * Math.PI * 2 / _springDamping))
|
||||
.toFloat()
|
||||
|
||||
companion object {
|
||||
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"SimpleSpringInterpolator",
|
||||
LegacyArchitectureLogLevel.ERROR,
|
||||
)
|
||||
}
|
||||
|
||||
private const val FACTOR = 0.5f
|
||||
const val PARAM_SPRING_DAMPING: String = "springDamping"
|
||||
|
||||
@JvmStatic
|
||||
fun getSpringDamping(params: ReadableMap): Float =
|
||||
if (params.getType(PARAM_SPRING_DAMPING) == ReadableType.Number) {
|
||||
params.getDouble(PARAM_SPRING_DAMPING).toFloat()
|
||||
} else {
|
||||
FACTOR
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-12
@@ -158,12 +158,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
mOverflowInset = new Rect();
|
||||
mActivelyScrolling = false;
|
||||
mClippingRect = null;
|
||||
// The default value for `overflow` is set to `Visible` in the Yoga style props.
|
||||
mOverflow =
|
||||
ReactNativeFeatureFlags.enablePropsUpdateReconciliationAndroid()
|
||||
? Overflow.VISIBLE
|
||||
: Overflow.SCROLL;
|
||||
|
||||
mOverflow = Overflow.SCROLL;
|
||||
mDragging = false;
|
||||
mPagingEnabled = false;
|
||||
mPostTouchRunnable = null;
|
||||
@@ -386,12 +381,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
mOverflow = Overflow.SCROLL;
|
||||
} else {
|
||||
@Nullable Overflow parsedOverflow = Overflow.fromString(overflow);
|
||||
mOverflow =
|
||||
parsedOverflow == null
|
||||
? (ReactNativeFeatureFlags.enablePropsUpdateReconciliationAndroid()
|
||||
? Overflow.VISIBLE
|
||||
: Overflow.SCROLL)
|
||||
: parsedOverflow;
|
||||
mOverflow = parsedOverflow == null ? Overflow.SCROLL : parsedOverflow;
|
||||
}
|
||||
|
||||
invalidate();
|
||||
|
||||
+3
-13
@@ -159,19 +159,14 @@ public class ReactScrollView extends ScrollView
|
||||
mVirtualViewContainerState = null;
|
||||
mActivelyScrolling = false;
|
||||
mClippingRect = null;
|
||||
|
||||
// The default value for `overflow` is set to `Visible` in the Yoga style props.
|
||||
mOverflow =
|
||||
ReactNativeFeatureFlags.enablePropsUpdateReconciliationAndroid()
|
||||
? Overflow.VISIBLE
|
||||
: Overflow.SCROLL;
|
||||
|
||||
mOverflow = Overflow.SCROLL;
|
||||
mDragging = false;
|
||||
mPagingEnabled = false;
|
||||
mPostTouchRunnable = null;
|
||||
mRemoveClippedSubviews = false;
|
||||
mScrollEnabled = true;
|
||||
mSendMomentumEvents = false;
|
||||
mFpsListener = null;
|
||||
mScrollPerfTag = null;
|
||||
mEndBackground = null;
|
||||
mEndFillColor = Color.TRANSPARENT;
|
||||
@@ -368,12 +363,7 @@ public class ReactScrollView extends ScrollView
|
||||
mOverflow = Overflow.SCROLL;
|
||||
} else {
|
||||
@Nullable Overflow parsedOverflow = Overflow.fromString(overflow);
|
||||
mOverflow =
|
||||
parsedOverflow == null
|
||||
? (ReactNativeFeatureFlags.enablePropsUpdateReconciliationAndroid()
|
||||
? Overflow.VISIBLE
|
||||
: Overflow.SCROLL)
|
||||
: parsedOverflow;
|
||||
mOverflow = parsedOverflow == null ? Overflow.SCROLL : parsedOverflow;
|
||||
}
|
||||
|
||||
invalidate();
|
||||
|
||||
+2
-2
@@ -34,6 +34,7 @@ import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle
|
||||
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariant
|
||||
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
|
||||
import com.facebook.react.views.text.TextTransform.Companion.apply
|
||||
import com.facebook.react.views.text.internal.ReactTextInlineImageShadowNode
|
||||
import com.facebook.react.views.text.internal.span.CustomLetterSpacingSpan
|
||||
import com.facebook.react.views.text.internal.span.CustomLineHeightSpan
|
||||
import com.facebook.react.views.text.internal.span.CustomStyleSpan
|
||||
@@ -522,7 +523,6 @@ public constructor(
|
||||
while (i < length) {
|
||||
val child: ReactShadowNode<*> = textShadowNode.getChildAt(i)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
if (child is ReactRawTextShadowNode) {
|
||||
child.text?.let { sb.append(apply(it, textAttributes.textTransform)) }
|
||||
} else if (child is ReactBaseTextShadowNode) {
|
||||
@@ -535,7 +535,7 @@ public constructor(
|
||||
inlineViews,
|
||||
sb.length,
|
||||
)
|
||||
} else if (child is com.facebook.react.views.text.internal.ReactTextInlineImageShadowNode) {
|
||||
} else if (child is ReactTextInlineImageShadowNode) {
|
||||
// We make the image take up 1 character in the span and put a corresponding character
|
||||
// into the text so that the image doesn't run over any following text.
|
||||
sb.append(INLINE_VIEW_PLACEHOLDER)
|
||||
|
||||
-2
@@ -5,8 +5,6 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.views.text.frescosupport
|
||||
|
||||
import android.content.Context
|
||||
|
||||
-7
@@ -9,18 +9,11 @@
|
||||
|
||||
package com.facebook.react.views.text.internal
|
||||
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.uimanager.LayoutShadowNode
|
||||
import com.facebook.react.views.text.internal.span.TextInlineImageSpan
|
||||
import com.facebook.yoga.YogaNode
|
||||
|
||||
/** Base class for [YogaNode]s that represent inline images. */
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
@Deprecated(
|
||||
message = "This class is part of Legacy Architecture and will be removed in a future release",
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
internal abstract class ReactTextInlineImageShadowNode : LayoutShadowNode() {
|
||||
/**
|
||||
* Build a [TextInlineImageSpan] from this node. This will be added to the TextView in place of
|
||||
|
||||
-8
@@ -416,14 +416,6 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
||||
updateClippingToRect(clippingRect, excludedViews)
|
||||
}
|
||||
|
||||
internal fun requestFocusFromJS() {
|
||||
super.requestFocus(FOCUS_DOWN, null)
|
||||
}
|
||||
|
||||
internal fun clearFocusFromJS() {
|
||||
super.clearFocus()
|
||||
}
|
||||
|
||||
override fun endViewTransition(view: View) {
|
||||
super.endViewTransition(view)
|
||||
childrenRemovedWhileTransitioning?.remove(view.id)
|
||||
|
||||
-14
@@ -404,8 +404,6 @@ public open class ReactViewManager : ReactClippingViewManager<ReactViewGroup>()
|
||||
when (commandId) {
|
||||
HOTSPOT_UPDATE_KEY -> handleHotspotUpdate(root, args)
|
||||
"setPressed" -> handleSetPressed(root, args)
|
||||
"focus" -> handleFocus(root)
|
||||
"blur" -> handleBlur(root)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@@ -430,16 +428,4 @@ public open class ReactViewManager : ReactClippingViewManager<ReactViewGroup>()
|
||||
val y = args.getDouble(1).dpToPx()
|
||||
root.drawableHotspotChanged(x, y)
|
||||
}
|
||||
|
||||
private fun handleFocus(root: ReactViewGroup) {
|
||||
if (ReactNativeFeatureFlags.enableImperativeFocus()) {
|
||||
root.requestFocusFromJS()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBlur(root: ReactViewGroup) {
|
||||
if (ReactNativeFeatureFlags.enableImperativeFocus()) {
|
||||
root.clearFocusFromJS()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-29
@@ -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<<8e1821e9a153a4b725890cb4a7f262ee>>
|
||||
* @generated SignedSource<<92c9aa29df580c6d12faa14e60b00e4f>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -189,12 +189,6 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableImagePrefetchingJNIBatchingAndroid() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableImagePrefetchingJNIBatchingAndroid");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableImagePrefetchingOnUiThreadAndroid() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableImagePrefetchingOnUiThreadAndroid");
|
||||
@@ -207,12 +201,6 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableImperativeFocus() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableImperativeFocus");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableInteropViewManagerClassLookUpOptimizationIOS() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableInteropViewManagerClassLookUpOptimizationIOS");
|
||||
@@ -618,11 +606,6 @@ bool JReactNativeFeatureFlagsCxxInterop::enableImagePrefetchingAndroid(
|
||||
return ReactNativeFeatureFlags::enableImagePrefetchingAndroid();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableImagePrefetchingJNIBatchingAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableImagePrefetchingJNIBatchingAndroid();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableImagePrefetchingOnUiThreadAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableImagePrefetchingOnUiThreadAndroid();
|
||||
@@ -633,11 +616,6 @@ bool JReactNativeFeatureFlagsCxxInterop::enableImmediateUpdateModeForContentOffs
|
||||
return ReactNativeFeatureFlags::enableImmediateUpdateModeForContentOffsetChanges();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableImperativeFocus(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableImperativeFocus();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableInteropViewManagerClassLookUpOptimizationIOS(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
@@ -974,18 +952,12 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
|
||||
makeNativeMethod(
|
||||
"enableImagePrefetchingAndroid",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableImagePrefetchingAndroid),
|
||||
makeNativeMethod(
|
||||
"enableImagePrefetchingJNIBatchingAndroid",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableImagePrefetchingJNIBatchingAndroid),
|
||||
makeNativeMethod(
|
||||
"enableImagePrefetchingOnUiThreadAndroid",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableImagePrefetchingOnUiThreadAndroid),
|
||||
makeNativeMethod(
|
||||
"enableImmediateUpdateModeForContentOffsetChanges",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableImmediateUpdateModeForContentOffsetChanges),
|
||||
makeNativeMethod(
|
||||
"enableImperativeFocus",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableImperativeFocus),
|
||||
makeNativeMethod(
|
||||
"enableInteropViewManagerClassLookUpOptimizationIOS",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableInteropViewManagerClassLookUpOptimizationIOS),
|
||||
|
||||
+1
-7
@@ -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<<5be2ec52bda638a1eac837c402149b9f>>
|
||||
* @generated SignedSource<<124d1378990fdd09a4d97f9103f81a6a>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -105,18 +105,12 @@ class JReactNativeFeatureFlagsCxxInterop
|
||||
static bool enableImagePrefetchingAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableImagePrefetchingJNIBatchingAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableImagePrefetchingOnUiThreadAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableImmediateUpdateModeForContentOffsetChanges(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableImperativeFocus(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableInteropViewManagerClassLookUpOptimizationIOS(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
|
||||
@@ -24,18 +24,20 @@ class JReactMarker : public facebook::jni::JavaClass<JReactMarker> {
|
||||
private:
|
||||
static void logMarker(const std::string& marker);
|
||||
static void logMarker(const std::string& marker, const std::string& tag);
|
||||
static void
|
||||
logMarker(const std::string& marker, const std::string& tag, int instanceKey);
|
||||
static void logMarker(
|
||||
const std::string& marker,
|
||||
const std::string& tag,
|
||||
const int instanceKey);
|
||||
static void logPerfMarker(
|
||||
ReactMarker::ReactMarkerId markerId,
|
||||
const ReactMarker::ReactMarkerId markerId,
|
||||
const char* tag);
|
||||
static void logPerfMarkerBridgeless(
|
||||
ReactMarker::ReactMarkerId markerId,
|
||||
const ReactMarker::ReactMarkerId markerId,
|
||||
const char* tag);
|
||||
static void logPerfMarkerWithInstanceKey(
|
||||
ReactMarker::ReactMarkerId markerId,
|
||||
const ReactMarker::ReactMarkerId markerId,
|
||||
const char* tag,
|
||||
int instanceKey);
|
||||
const int instanceKey);
|
||||
static void nativeLogMarker(
|
||||
jni::alias_ref<jclass> /* unused */,
|
||||
const std::string& markerNameStr,
|
||||
|
||||
+12
-24
@@ -13,48 +13,36 @@ import org.junit.Test
|
||||
class DefaultNewArchitectureEntryPointTest {
|
||||
|
||||
@Test
|
||||
fun isConfigurationValid_withEverythingOff_returnsFalse() {
|
||||
val (isValid, errorMessage) =
|
||||
fun isConfigurationValid_withEverythingOff_returnsTrue() {
|
||||
val (isValid, _) =
|
||||
DefaultNewArchitectureEntryPoint.isConfigurationValid(
|
||||
turboModulesEnabled = false,
|
||||
fabricEnabled = false,
|
||||
bridgelessEnabled = false,
|
||||
)
|
||||
assertThat(isValid).isFalse()
|
||||
assertThat(errorMessage)
|
||||
.isEqualTo(
|
||||
"You cannot load React Native with the New Architecture disabled. Please use DefaultNewArchitectureEntryPoint.load() instead of DefaultNewArchitectureEntryPoint.load(turboModulesEnabled=false, fabricEnabled=false, bridgelessEnabled=false)"
|
||||
)
|
||||
assertThat(isValid).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isConfigurationValid_withNewArchOnlyOn_returnsFalse() {
|
||||
val (isValid, errorMessage) =
|
||||
fun isConfigurationValid_withNewArchOn_returnsTrue() {
|
||||
val (isValid, _) =
|
||||
DefaultNewArchitectureEntryPoint.isConfigurationValid(
|
||||
turboModulesEnabled = true,
|
||||
fabricEnabled = true,
|
||||
bridgelessEnabled = false,
|
||||
)
|
||||
assertThat(isValid).isFalse()
|
||||
assertThat(errorMessage)
|
||||
.isEqualTo(
|
||||
"You cannot load React Native with the New Architecture disabled. Please use DefaultNewArchitectureEntryPoint.load() instead of DefaultNewArchitectureEntryPoint.load(turboModulesEnabled=true, fabricEnabled=true, bridgelessEnabled=false)"
|
||||
)
|
||||
assertThat(isValid).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isConfigurationValid_withTurboModulesOnlyOn_returnsFalse() {
|
||||
val (isValid, errorMessage) =
|
||||
fun isConfigurationValid_withTurboModulesOnlyOn_returnsTrue() {
|
||||
val (isValid, _) =
|
||||
DefaultNewArchitectureEntryPoint.isConfigurationValid(
|
||||
turboModulesEnabled = true,
|
||||
fabricEnabled = false,
|
||||
bridgelessEnabled = false,
|
||||
)
|
||||
assertThat(isValid).isFalse()
|
||||
assertThat(errorMessage)
|
||||
.isEqualTo(
|
||||
"You cannot load React Native with the New Architecture disabled. Please use DefaultNewArchitectureEntryPoint.load() instead of DefaultNewArchitectureEntryPoint.load(turboModulesEnabled=true, fabricEnabled=false, bridgelessEnabled=false)"
|
||||
)
|
||||
assertThat(isValid).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,7 +67,7 @@ class DefaultNewArchitectureEntryPointTest {
|
||||
assertThat(isValid).isFalse()
|
||||
assertThat(errorMessage)
|
||||
.isEqualTo(
|
||||
"You cannot load React Native with the New Architecture disabled. Please use DefaultNewArchitectureEntryPoint.load() instead of DefaultNewArchitectureEntryPoint.load(turboModulesEnabled=false, fabricEnabled=true, bridgelessEnabled=false)"
|
||||
"fabricEnabled=true requires turboModulesEnabled=true (is now false) - Please update your DefaultNewArchitectureEntryPoint.load() parameters."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -94,7 +82,7 @@ class DefaultNewArchitectureEntryPointTest {
|
||||
assertThat(isValid).isFalse()
|
||||
assertThat(errorMessage)
|
||||
.isEqualTo(
|
||||
"You cannot load React Native with the New Architecture disabled. Please use DefaultNewArchitectureEntryPoint.load() instead of DefaultNewArchitectureEntryPoint.load(turboModulesEnabled=false, fabricEnabled=true, bridgelessEnabled=true)"
|
||||
"fabricEnabled=true requires turboModulesEnabled=true (is now false) - Please update your DefaultNewArchitectureEntryPoint.load() parameters."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -109,7 +97,7 @@ class DefaultNewArchitectureEntryPointTest {
|
||||
assertThat(isValid).isFalse()
|
||||
assertThat(errorMessage)
|
||||
.isEqualTo(
|
||||
"You cannot load React Native with the New Architecture disabled. Please use DefaultNewArchitectureEntryPoint.load() instead of DefaultNewArchitectureEntryPoint.load(turboModulesEnabled=true, fabricEnabled=false, bridgelessEnabled=true)"
|
||||
"bridgelessEnabled=true requires (turboModulesEnabled=true AND fabricEnabled=true) - Please update your DefaultNewArchitectureEntryPoint.load() parameters."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.view.View
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import android.view.animation.AccelerateInterpolator
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.view.animation.LinearInterpolator
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.mockConstruction
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
class AbstractLayoutAnimationTest {
|
||||
private lateinit var view: View
|
||||
private lateinit var config: ReadableMap
|
||||
private lateinit var animation: AbstractLayoutAnimation
|
||||
private lateinit var mockedConstructors: List<AutoCloseable>
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
view = mock()
|
||||
config = mock()
|
||||
|
||||
mockedConstructors =
|
||||
listOf(
|
||||
mockConstruction(LinearInterpolator::class.java),
|
||||
mockConstruction(AccelerateInterpolator::class.java),
|
||||
mockConstruction(DecelerateInterpolator::class.java),
|
||||
mockConstruction(AccelerateDecelerateInterpolator::class.java),
|
||||
)
|
||||
|
||||
animation =
|
||||
object : AbstractLayoutAnimation() {
|
||||
override fun isValid(): Boolean = true
|
||||
|
||||
override fun createAnimationImpl(
|
||||
view: View,
|
||||
x: Int,
|
||||
y: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
): Animation = mock()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockedConstructors.forEach { it.close() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reset_clearsAnimationProperties() {
|
||||
animation.reset()
|
||||
assertThat(animation.animatedProperty).isNull()
|
||||
assertThat(animation.durationMs).isEqualTo(0)
|
||||
assertThat(animation.delayMs).isEqualTo(0)
|
||||
assertThat(animation.interpolator).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createAnimation_returnsValidAnimation() {
|
||||
val result = animation.createAnimation(view, 0, 0, 100, 100)
|
||||
assertThat(result).isNotNull
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initializeFromConfig_throwsIfTypeMissing() {
|
||||
whenever(config.hasKey("type")).thenReturn(false)
|
||||
|
||||
val exception =
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
animation.initializeFromConfig(config, 300)
|
||||
}
|
||||
assertThat(exception.message).isEqualTo("Missing interpolation type.")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createAnimation_returnsNullWhenInvalid() {
|
||||
val invalidAnimation =
|
||||
object : AbstractLayoutAnimation() {
|
||||
override fun isValid(): Boolean = false
|
||||
|
||||
override fun createAnimationImpl(
|
||||
view: View,
|
||||
x: Int,
|
||||
y: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
): Animation = mock()
|
||||
}
|
||||
|
||||
val result = invalidAnimation.createAnimation(view, 0, 0, 100, 100)
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initializeFromConfig_throwsIfInvalidAnimation() {
|
||||
whenever(config.hasKey("type")).thenReturn(true)
|
||||
whenever(config.getString("type")).thenReturn("linear")
|
||||
whenever(config.hasKey("duration")).thenReturn(true)
|
||||
whenever(config.getInt("duration")).thenReturn(300)
|
||||
|
||||
val invalidAnimation =
|
||||
object : AbstractLayoutAnimation() {
|
||||
override fun isValid(): Boolean = false
|
||||
|
||||
override fun createAnimationImpl(
|
||||
view: View,
|
||||
x: Int,
|
||||
y: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
): Animation = mock()
|
||||
}
|
||||
|
||||
assertThatThrownBy { invalidAnimation.initializeFromConfig(config, 300) }
|
||||
.isInstanceOf(IllegalViewOperationException::class.java)
|
||||
.hasMessageContaining("Invalid layout animation")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getInterpolator_returnsSimpleSpringInterpolator() {
|
||||
val type = InterpolatorType.SPRING
|
||||
val params = mock<ReadableMap>()
|
||||
whenever(params.hasKey("damping")).thenReturn(true)
|
||||
whenever(params.getDouble("damping")).thenReturn(0.5)
|
||||
|
||||
val interpolator = AbstractLayoutAnimation.getInterpolator(type, params)
|
||||
assertThat(interpolator).isInstanceOf(SimpleSpringInterpolator::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getInterpolator_returnsDefaultInterpolator() {
|
||||
val type = InterpolatorType.LINEAR
|
||||
val params = mock<ReadableMap>()
|
||||
|
||||
val interpolator = AbstractLayoutAnimation.getInterpolator(type, params)
|
||||
assertThat(interpolator).isInstanceOf(LinearInterpolator::class.java)
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import java.util.Locale
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class InterpolatorTypeTest {
|
||||
@Test
|
||||
fun testCamelCase() {
|
||||
assertThat(InterpolatorType.fromString("linear")).isEqualTo(InterpolatorType.LINEAR)
|
||||
assertThat(InterpolatorType.fromString("easeIn")).isEqualTo(InterpolatorType.EASE_IN)
|
||||
assertThat(InterpolatorType.fromString("easeOut")).isEqualTo(InterpolatorType.EASE_OUT)
|
||||
assertThat(InterpolatorType.fromString("easeInEaseOut"))
|
||||
.isEqualTo(InterpolatorType.EASE_IN_EASE_OUT)
|
||||
assertThat(InterpolatorType.fromString("spring")).isEqualTo(InterpolatorType.SPRING)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOtherCases() {
|
||||
assertThat(InterpolatorType.fromString("EASEIN")).isEqualTo(InterpolatorType.EASE_IN)
|
||||
assertThat(InterpolatorType.fromString("easeout")).isEqualTo(InterpolatorType.EASE_OUT)
|
||||
assertThat(InterpolatorType.fromString("easeineaseout"))
|
||||
.isEqualTo(InterpolatorType.EASE_IN_EASE_OUT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLocales() {
|
||||
Locale.setDefault(Locale.forLanguageTag("tr-TR"))
|
||||
assertThat(InterpolatorType.fromString("easeInEaseOut"))
|
||||
.isEqualTo(InterpolatorType.EASE_IN_EASE_OUT)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun testInvalidInterpolatorTypes() {
|
||||
InterpolatorType.fromString("ease_in_ease_out")
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.uimanager.layoutanimation
|
||||
|
||||
import android.view.View
|
||||
import android.view.animation.Transformation
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.never
|
||||
import org.mockito.kotlin.verify
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class OpacityAnimationTest {
|
||||
private lateinit var view: View
|
||||
private lateinit var animation: OpacityAnimation
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
view = View(RuntimeEnvironment.getApplication())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun applyTransformation_updatesAlphaCorrectly() {
|
||||
val startOpacity = 0.5f
|
||||
val endOpacity = 1.0f
|
||||
animation = OpacityAnimation(view, startOpacity, endOpacity)
|
||||
|
||||
val transformation = Transformation()
|
||||
animation.applyTransformation(0.0f, transformation)
|
||||
assertThat(view.alpha).isEqualTo(0.5f)
|
||||
|
||||
animation.applyTransformation(0.5f, transformation)
|
||||
assertThat(view.alpha).isEqualTo(0.75f)
|
||||
|
||||
animation.applyTransformation(1.0f, transformation)
|
||||
assertThat(view.alpha).isEqualTo(1.0f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun willChangeBounds_returnsFalse() {
|
||||
animation = OpacityAnimation(view, 0.5f, 1.0f)
|
||||
assertThat(animation.willChangeBounds()).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAnimationStart_setsLayerTypeHardwareIfOverlappingRendering() {
|
||||
val spyView: View = mock {
|
||||
on { hasOverlappingRendering() } doReturn true
|
||||
on { layerType } doReturn View.LAYER_TYPE_NONE
|
||||
}
|
||||
|
||||
val listener = OpacityAnimation.OpacityAnimationListener(spyView)
|
||||
listener.onAnimationStart(mock())
|
||||
|
||||
verify(spyView).setLayerType(View.LAYER_TYPE_HARDWARE, null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAnimationStart_doesNotChangeLayerTypeIfAlreadySet() {
|
||||
val spyView: View = mock {
|
||||
on { hasOverlappingRendering() } doReturn true
|
||||
on { layerType } doReturn View.LAYER_TYPE_HARDWARE
|
||||
}
|
||||
|
||||
val listener = OpacityAnimation.OpacityAnimationListener(spyView)
|
||||
listener.onAnimationStart(mock())
|
||||
|
||||
verify(spyView, never()).setLayerType(View.LAYER_TYPE_HARDWARE, null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAnimationEnd_resetsLayerTypeIfChanged() {
|
||||
val spyView: View = mock {
|
||||
on { hasOverlappingRendering() } doReturn true
|
||||
on { layerType } doReturn View.LAYER_TYPE_NONE
|
||||
}
|
||||
|
||||
val listener = OpacityAnimation.OpacityAnimationListener(spyView)
|
||||
listener.onAnimationStart(mock())
|
||||
listener.onAnimationEnd(mock())
|
||||
|
||||
verify(spyView).setLayerType(View.LAYER_TYPE_NONE, null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onAnimationRepeat_doesNothing() {
|
||||
val listener = OpacityAnimation.OpacityAnimationListener(mock())
|
||||
listener.onAnimationRepeat(mock())
|
||||
|
||||
// No assertions needed, just verifying it runs without errors
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ class RN_EXPORT [[deprecated(
|
||||
* necessary native modules methods.
|
||||
*/
|
||||
virtual void invokeCallback(
|
||||
double callbackId,
|
||||
const double callbackId,
|
||||
const folly::dynamic& arguments) = 0;
|
||||
|
||||
virtual void setGlobalVariable(
|
||||
|
||||
@@ -61,12 +61,12 @@ class RN_EXPORT [[deprecated(
|
||||
};
|
||||
|
||||
void init();
|
||||
std::string getModuleCode(uint32_t id) const;
|
||||
void readBundle(char* buffer, std::streamsize bytes) const;
|
||||
std::string getModuleCode(const uint32_t id) const;
|
||||
void readBundle(char* buffer, const std::streamsize bytes) const;
|
||||
void readBundle(
|
||||
char* buffer,
|
||||
std::streamsize bytes,
|
||||
std::istream::pos_type position) const;
|
||||
const std::streamsize bytes,
|
||||
const std::istream::pos_type position) const;
|
||||
|
||||
mutable std::unique_ptr<std::istream> m_bundle;
|
||||
ModuleTable m_table;
|
||||
|
||||
@@ -57,13 +57,13 @@ extern RN_EXPORT std::shared_mutex logTaggedMarkerImplMutex;
|
||||
extern RN_EXPORT LogTaggedMarker logTaggedMarkerImpl;
|
||||
extern RN_EXPORT LogTaggedMarker logTaggedMarkerBridgelessImpl;
|
||||
|
||||
extern RN_EXPORT void logMarker(ReactMarkerId markerId); // Bridge only
|
||||
extern RN_EXPORT void logMarker(const ReactMarkerId markerId); // Bridge only
|
||||
extern RN_EXPORT void logTaggedMarker(
|
||||
ReactMarkerId markerId,
|
||||
const ReactMarkerId markerId,
|
||||
const char* tag); // Bridge only
|
||||
extern RN_EXPORT void logMarkerBridgeless(ReactMarkerId markerId);
|
||||
extern RN_EXPORT void logMarkerBridgeless(const ReactMarkerId markerId);
|
||||
extern RN_EXPORT void logTaggedMarkerBridgeless(
|
||||
ReactMarkerId markerId,
|
||||
const ReactMarkerId markerId,
|
||||
const char* tag);
|
||||
|
||||
struct ReactMarkerEvent {
|
||||
@@ -76,7 +76,7 @@ class RN_EXPORT StartupLogger {
|
||||
public:
|
||||
static StartupLogger& getInstance();
|
||||
|
||||
void logStartupEvent(ReactMarkerId markerId, double markerTime);
|
||||
void logStartupEvent(const ReactMarkerId markerId, double markerTime);
|
||||
void reset();
|
||||
double getAppStartupStartTime();
|
||||
double getInitReactRuntimeStartTime();
|
||||
@@ -101,6 +101,8 @@ class RN_EXPORT StartupLogger {
|
||||
// When the marker got logged from the platform, it will notify here. This is
|
||||
// used to collect react markers that are logged in the platform instead of in
|
||||
// C++.
|
||||
extern RN_EXPORT void logMarkerDone(ReactMarkerId markerId, double markerTime);
|
||||
extern RN_EXPORT void logMarkerDone(
|
||||
const ReactMarkerId markerId,
|
||||
double markerTime);
|
||||
|
||||
} // namespace facebook::react::ReactMarker
|
||||
|
||||
@@ -141,10 +141,10 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
}
|
||||
std::string description() override {
|
||||
return plain().description();
|
||||
}
|
||||
};
|
||||
bool isInspectable() override {
|
||||
return plain().isInspectable();
|
||||
}
|
||||
};
|
||||
Instrumentation& instrumentation() override {
|
||||
return *this;
|
||||
}
|
||||
@@ -160,45 +160,45 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
|
||||
Runtime::PointerValue* cloneSymbol(const Runtime::PointerValue* pv) override {
|
||||
return plain_.cloneSymbol(pv);
|
||||
}
|
||||
};
|
||||
Runtime::PointerValue* cloneBigInt(const Runtime::PointerValue* pv) override {
|
||||
return plain_.cloneBigInt(pv);
|
||||
}
|
||||
};
|
||||
Runtime::PointerValue* cloneString(const Runtime::PointerValue* pv) override {
|
||||
return plain_.cloneString(pv);
|
||||
}
|
||||
};
|
||||
Runtime::PointerValue* cloneObject(const Runtime::PointerValue* pv) override {
|
||||
return plain_.cloneObject(pv);
|
||||
}
|
||||
};
|
||||
Runtime::PointerValue* clonePropNameID(
|
||||
const Runtime::PointerValue* pv) override {
|
||||
return plain_.clonePropNameID(pv);
|
||||
}
|
||||
};
|
||||
|
||||
PropNameID createPropNameIDFromAscii(const char* str, size_t length)
|
||||
override {
|
||||
return plain_.createPropNameIDFromAscii(str, length);
|
||||
}
|
||||
};
|
||||
PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length)
|
||||
override {
|
||||
return plain_.createPropNameIDFromUtf8(utf8, length);
|
||||
}
|
||||
};
|
||||
PropNameID createPropNameIDFromString(const String& str) override {
|
||||
return plain_.createPropNameIDFromString(str);
|
||||
}
|
||||
};
|
||||
PropNameID createPropNameIDFromUtf16(const char16_t* utf16, size_t length)
|
||||
override {
|
||||
return plain_.createPropNameIDFromUtf16(utf16, length);
|
||||
}
|
||||
PropNameID createPropNameIDFromSymbol(const Symbol& sym) override {
|
||||
return plain_.createPropNameIDFromSymbol(sym);
|
||||
}
|
||||
};
|
||||
std::string utf8(const PropNameID& id) override {
|
||||
return plain_.utf8(id);
|
||||
}
|
||||
};
|
||||
bool compare(const PropNameID& a, const PropNameID& b) override {
|
||||
return plain_.compare(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
std::string symbolToString(const Symbol& sym) override {
|
||||
return plain_.symbolToString(sym);
|
||||
@@ -225,10 +225,10 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
|
||||
String createStringFromAscii(const char* str, size_t length) override {
|
||||
return plain_.createStringFromAscii(str, length);
|
||||
}
|
||||
};
|
||||
String createStringFromUtf8(const uint8_t* utf8, size_t length) override {
|
||||
return plain_.createStringFromUtf8(utf8, length);
|
||||
}
|
||||
};
|
||||
String createStringFromUtf16(const char16_t* utf16, size_t length) override {
|
||||
return plain_.createStringFromUtf16(utf16, length);
|
||||
}
|
||||
@@ -265,22 +265,22 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
|
||||
Object createObject() override {
|
||||
return plain_.createObject();
|
||||
}
|
||||
};
|
||||
|
||||
Object createObject(std::shared_ptr<HostObject> ho) override {
|
||||
return plain_.createObject(
|
||||
std::make_shared<DecoratedHostObject>(*this, std::move(ho)));
|
||||
}
|
||||
};
|
||||
std::shared_ptr<HostObject> getHostObject(const jsi::Object& o) override {
|
||||
std::shared_ptr<HostObject> dho = plain_.getHostObject(o);
|
||||
return static_cast<DecoratedHostObject&>(*dho).plainHO_;
|
||||
}
|
||||
};
|
||||
HostFunctionType& getHostFunction(const jsi::Function& f) override {
|
||||
HostFunctionType& dhf = plain_.getHostFunction(f);
|
||||
// This will fail if a cpp file including this header is not compiled
|
||||
// with RTTI.
|
||||
return dhf.target<DecoratedHostFunction>()->plainHF_;
|
||||
}
|
||||
};
|
||||
|
||||
bool hasNativeState(const Object& o) override {
|
||||
return plain_.hasNativeState(o);
|
||||
@@ -307,19 +307,19 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
|
||||
Value getProperty(const Object& o, const PropNameID& name) override {
|
||||
return plain_.getProperty(o, name);
|
||||
}
|
||||
};
|
||||
Value getProperty(const Object& o, const String& name) override {
|
||||
return plain_.getProperty(o, name);
|
||||
}
|
||||
};
|
||||
Value getProperty(const Object& o, const Value& name) override {
|
||||
return plain_.getProperty(o, name);
|
||||
}
|
||||
bool hasProperty(const Object& o, const PropNameID& name) override {
|
||||
return plain_.hasProperty(o, name);
|
||||
}
|
||||
};
|
||||
bool hasProperty(const Object& o, const String& name) override {
|
||||
return plain_.hasProperty(o, name);
|
||||
}
|
||||
};
|
||||
bool hasProperty(const Object& o, const Value& name) override {
|
||||
return plain_.hasProperty(o, name);
|
||||
}
|
||||
@@ -328,11 +328,11 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
const PropNameID& name,
|
||||
const Value& value) override {
|
||||
plain_.setPropertyValue(o, name, value);
|
||||
}
|
||||
};
|
||||
void setPropertyValue(const Object& o, const String& name, const Value& value)
|
||||
override {
|
||||
plain_.setPropertyValue(o, name, value);
|
||||
}
|
||||
};
|
||||
void setPropertyValue(const Object& o, const Value& name, const Value& value)
|
||||
override {
|
||||
plain_.setPropertyValue(o, name, value);
|
||||
@@ -352,53 +352,53 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
|
||||
bool isArray(const Object& o) const override {
|
||||
return plain_.isArray(o);
|
||||
}
|
||||
};
|
||||
bool isArrayBuffer(const Object& o) const override {
|
||||
return plain_.isArrayBuffer(o);
|
||||
}
|
||||
};
|
||||
bool isFunction(const Object& o) const override {
|
||||
return plain_.isFunction(o);
|
||||
}
|
||||
};
|
||||
bool isHostObject(const jsi::Object& o) const override {
|
||||
return plain_.isHostObject(o);
|
||||
}
|
||||
};
|
||||
bool isHostFunction(const jsi::Function& f) const override {
|
||||
return plain_.isHostFunction(f);
|
||||
}
|
||||
};
|
||||
Array getPropertyNames(const Object& o) override {
|
||||
return plain_.getPropertyNames(o);
|
||||
}
|
||||
};
|
||||
|
||||
WeakObject createWeakObject(const Object& o) override {
|
||||
return plain_.createWeakObject(o);
|
||||
}
|
||||
};
|
||||
Value lockWeakObject(const WeakObject& wo) override {
|
||||
return plain_.lockWeakObject(wo);
|
||||
}
|
||||
};
|
||||
|
||||
Array createArray(size_t length) override {
|
||||
return plain_.createArray(length);
|
||||
}
|
||||
};
|
||||
ArrayBuffer createArrayBuffer(
|
||||
std::shared_ptr<MutableBuffer> buffer) override {
|
||||
return plain_.createArrayBuffer(std::move(buffer));
|
||||
}
|
||||
};
|
||||
size_t size(const Array& a) override {
|
||||
return plain_.size(a);
|
||||
}
|
||||
};
|
||||
size_t size(const ArrayBuffer& ab) override {
|
||||
return plain_.size(ab);
|
||||
}
|
||||
};
|
||||
uint8_t* data(const ArrayBuffer& ab) override {
|
||||
return plain_.data(ab);
|
||||
}
|
||||
};
|
||||
Value getValueAtIndex(const Array& a, size_t i) override {
|
||||
return plain_.getValueAtIndex(a, i);
|
||||
}
|
||||
};
|
||||
void setValueAtIndexImpl(const Array& a, size_t i, const Value& value)
|
||||
override {
|
||||
plain_.setValueAtIndexImpl(a, i, value);
|
||||
}
|
||||
};
|
||||
|
||||
Function createFunctionFromHostFunction(
|
||||
const PropNameID& name,
|
||||
@@ -406,18 +406,18 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
HostFunctionType func) override {
|
||||
return plain_.createFunctionFromHostFunction(
|
||||
name, paramCount, DecoratedHostFunction(*this, std::move(func)));
|
||||
}
|
||||
};
|
||||
Value call(
|
||||
const Function& f,
|
||||
const Value& jsThis,
|
||||
const Value* args,
|
||||
size_t count) override {
|
||||
return plain_.call(f, jsThis, args, count);
|
||||
}
|
||||
};
|
||||
Value callAsConstructor(const Function& f, const Value* args, size_t count)
|
||||
override {
|
||||
return plain_.callAsConstructor(f, args, count);
|
||||
}
|
||||
};
|
||||
|
||||
void setRuntimeDataImpl(
|
||||
const UUID& uuid,
|
||||
@@ -440,20 +440,20 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
|
||||
bool strictEquals(const Symbol& a, const Symbol& b) const override {
|
||||
return plain_.strictEquals(a, b);
|
||||
}
|
||||
};
|
||||
bool strictEquals(const BigInt& a, const BigInt& b) const override {
|
||||
return plain_.strictEquals(a, b);
|
||||
}
|
||||
};
|
||||
bool strictEquals(const String& a, const String& b) const override {
|
||||
return plain_.strictEquals(a, b);
|
||||
}
|
||||
};
|
||||
bool strictEquals(const Object& a, const Object& b) const override {
|
||||
return plain_.strictEquals(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
bool instanceOf(const Object& o, const Function& f) override {
|
||||
return plain_.instanceOf(o, f);
|
||||
}
|
||||
};
|
||||
|
||||
// jsi::Instrumentation methods
|
||||
|
||||
@@ -654,11 +654,11 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
std::string description() override {
|
||||
Around around{with_};
|
||||
return RD::description();
|
||||
}
|
||||
};
|
||||
bool isInspectable() override {
|
||||
Around around{with_};
|
||||
return RD::isInspectable();
|
||||
}
|
||||
};
|
||||
|
||||
// The jsi:: prefix is necessary because MSVC compiler complains C2247:
|
||||
// Instrumentation is not accessible because RuntimeDecorator uses private
|
||||
@@ -673,35 +673,35 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
Runtime::PointerValue* cloneSymbol(const Runtime::PointerValue* pv) override {
|
||||
Around around{with_};
|
||||
return RD::cloneSymbol(pv);
|
||||
}
|
||||
};
|
||||
Runtime::PointerValue* cloneBigInt(const Runtime::PointerValue* pv) override {
|
||||
Around around{with_};
|
||||
return RD::cloneBigInt(pv);
|
||||
}
|
||||
};
|
||||
Runtime::PointerValue* cloneString(const Runtime::PointerValue* pv) override {
|
||||
Around around{with_};
|
||||
return RD::cloneString(pv);
|
||||
}
|
||||
};
|
||||
Runtime::PointerValue* cloneObject(const Runtime::PointerValue* pv) override {
|
||||
Around around{with_};
|
||||
return RD::cloneObject(pv);
|
||||
}
|
||||
};
|
||||
Runtime::PointerValue* clonePropNameID(
|
||||
const Runtime::PointerValue* pv) override {
|
||||
Around around{with_};
|
||||
return RD::clonePropNameID(pv);
|
||||
}
|
||||
};
|
||||
|
||||
PropNameID createPropNameIDFromAscii(const char* str, size_t length)
|
||||
override {
|
||||
Around around{with_};
|
||||
return RD::createPropNameIDFromAscii(str, length);
|
||||
}
|
||||
};
|
||||
PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length)
|
||||
override {
|
||||
Around around{with_};
|
||||
return RD::createPropNameIDFromUtf8(utf8, length);
|
||||
}
|
||||
};
|
||||
PropNameID createPropNameIDFromUtf16(const char16_t* utf16, size_t length)
|
||||
override {
|
||||
Around around{with_};
|
||||
@@ -710,58 +710,58 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
PropNameID createPropNameIDFromString(const String& str) override {
|
||||
Around around{with_};
|
||||
return RD::createPropNameIDFromString(str);
|
||||
}
|
||||
};
|
||||
PropNameID createPropNameIDFromSymbol(const Symbol& sym) override {
|
||||
Around around{with_};
|
||||
return RD::createPropNameIDFromSymbol(sym);
|
||||
}
|
||||
};
|
||||
std::string utf8(const PropNameID& id) override {
|
||||
Around around{with_};
|
||||
return RD::utf8(id);
|
||||
}
|
||||
};
|
||||
bool compare(const PropNameID& a, const PropNameID& b) override {
|
||||
Around around{with_};
|
||||
return RD::compare(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
std::string symbolToString(const Symbol& sym) override {
|
||||
Around around{with_};
|
||||
return RD::symbolToString(sym);
|
||||
}
|
||||
};
|
||||
|
||||
BigInt createBigIntFromInt64(int64_t i) override {
|
||||
Around around{with_};
|
||||
return RD::createBigIntFromInt64(i);
|
||||
}
|
||||
};
|
||||
BigInt createBigIntFromUint64(uint64_t i) override {
|
||||
Around around{with_};
|
||||
return RD::createBigIntFromUint64(i);
|
||||
}
|
||||
};
|
||||
bool bigintIsInt64(const BigInt& bi) override {
|
||||
Around around{with_};
|
||||
return RD::bigintIsInt64(bi);
|
||||
}
|
||||
};
|
||||
bool bigintIsUint64(const BigInt& bi) override {
|
||||
Around around{with_};
|
||||
return RD::bigintIsUint64(bi);
|
||||
}
|
||||
};
|
||||
uint64_t truncate(const BigInt& bi) override {
|
||||
Around around{with_};
|
||||
return RD::truncate(bi);
|
||||
}
|
||||
};
|
||||
String bigintToString(const BigInt& bi, int i) override {
|
||||
Around around{with_};
|
||||
return RD::bigintToString(bi, i);
|
||||
}
|
||||
};
|
||||
|
||||
String createStringFromAscii(const char* str, size_t length) override {
|
||||
Around around{with_};
|
||||
return RD::createStringFromAscii(str, length);
|
||||
}
|
||||
};
|
||||
String createStringFromUtf8(const uint8_t* utf8, size_t length) override {
|
||||
Around around{with_};
|
||||
return RD::createStringFromUtf8(utf8, length);
|
||||
}
|
||||
};
|
||||
String createStringFromUtf16(const char16_t* utf16, size_t length) override {
|
||||
Around around{with_};
|
||||
return RD::createStringFromUtf16(utf16, length);
|
||||
@@ -801,7 +801,7 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
Value createValueFromJsonUtf8(const uint8_t* json, size_t length) override {
|
||||
Around around{with_};
|
||||
return RD::createValueFromJsonUtf8(json, length);
|
||||
}
|
||||
};
|
||||
|
||||
Object createObjectWithPrototype(const Value& prototype) override {
|
||||
Around around{with_};
|
||||
@@ -811,33 +811,33 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
Object createObject() override {
|
||||
Around around{with_};
|
||||
return RD::createObject();
|
||||
}
|
||||
};
|
||||
Object createObject(std::shared_ptr<HostObject> ho) override {
|
||||
Around around{with_};
|
||||
return RD::createObject(std::move(ho));
|
||||
}
|
||||
};
|
||||
std::shared_ptr<HostObject> getHostObject(const jsi::Object& o) override {
|
||||
Around around{with_};
|
||||
return RD::getHostObject(o);
|
||||
}
|
||||
};
|
||||
HostFunctionType& getHostFunction(const jsi::Function& f) override {
|
||||
Around around{with_};
|
||||
return RD::getHostFunction(f);
|
||||
}
|
||||
};
|
||||
|
||||
bool hasNativeState(const Object& o) override {
|
||||
Around around{with_};
|
||||
return RD::hasNativeState(o);
|
||||
}
|
||||
};
|
||||
std::shared_ptr<NativeState> getNativeState(const Object& o) override {
|
||||
Around around{with_};
|
||||
return RD::getNativeState(o);
|
||||
}
|
||||
};
|
||||
void setNativeState(const Object& o, std::shared_ptr<NativeState> state)
|
||||
override {
|
||||
Around around{with_};
|
||||
RD::setNativeState(o, state);
|
||||
}
|
||||
};
|
||||
|
||||
void setPrototypeOf(const Object& object, const Value& prototype) override {
|
||||
Around around{with_};
|
||||
@@ -852,11 +852,11 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
Value getProperty(const Object& o, const PropNameID& name) override {
|
||||
Around around{with_};
|
||||
return RD::getProperty(o, name);
|
||||
}
|
||||
};
|
||||
Value getProperty(const Object& o, const String& name) override {
|
||||
Around around{with_};
|
||||
return RD::getProperty(o, name);
|
||||
}
|
||||
};
|
||||
Value getProperty(const Object& o, const Value& name) override {
|
||||
Around around{with_};
|
||||
return RD::getProperty(o, name);
|
||||
@@ -864,11 +864,11 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
bool hasProperty(const Object& o, const PropNameID& name) override {
|
||||
Around around{with_};
|
||||
return RD::hasProperty(o, name);
|
||||
}
|
||||
};
|
||||
bool hasProperty(const Object& o, const String& name) override {
|
||||
Around around{with_};
|
||||
return RD::hasProperty(o, name);
|
||||
}
|
||||
};
|
||||
bool hasProperty(const Object& o, const Value& name) override {
|
||||
Around around{with_};
|
||||
return RD::hasProperty(o, name);
|
||||
@@ -879,12 +879,12 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
const Value& value) override {
|
||||
Around around{with_};
|
||||
RD::setPropertyValue(o, name, value);
|
||||
}
|
||||
};
|
||||
void setPropertyValue(const Object& o, const String& name, const Value& value)
|
||||
override {
|
||||
Around around{with_};
|
||||
RD::setPropertyValue(o, name, value);
|
||||
}
|
||||
};
|
||||
void setPropertyValue(const Object& o, const Value& name, const Value& value)
|
||||
override {
|
||||
Around around{with_};
|
||||
@@ -909,66 +909,66 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
bool isArray(const Object& o) const override {
|
||||
Around around{with_};
|
||||
return RD::isArray(o);
|
||||
}
|
||||
};
|
||||
bool isArrayBuffer(const Object& o) const override {
|
||||
Around around{with_};
|
||||
return RD::isArrayBuffer(o);
|
||||
}
|
||||
};
|
||||
bool isFunction(const Object& o) const override {
|
||||
Around around{with_};
|
||||
return RD::isFunction(o);
|
||||
}
|
||||
};
|
||||
bool isHostObject(const jsi::Object& o) const override {
|
||||
Around around{with_};
|
||||
return RD::isHostObject(o);
|
||||
}
|
||||
};
|
||||
bool isHostFunction(const jsi::Function& f) const override {
|
||||
Around around{with_};
|
||||
return RD::isHostFunction(f);
|
||||
}
|
||||
};
|
||||
Array getPropertyNames(const Object& o) override {
|
||||
Around around{with_};
|
||||
return RD::getPropertyNames(o);
|
||||
}
|
||||
};
|
||||
|
||||
WeakObject createWeakObject(const Object& o) override {
|
||||
Around around{with_};
|
||||
return RD::createWeakObject(o);
|
||||
}
|
||||
};
|
||||
Value lockWeakObject(const WeakObject& wo) override {
|
||||
Around around{with_};
|
||||
return RD::lockWeakObject(wo);
|
||||
}
|
||||
};
|
||||
|
||||
Array createArray(size_t length) override {
|
||||
Around around{with_};
|
||||
return RD::createArray(length);
|
||||
}
|
||||
};
|
||||
ArrayBuffer createArrayBuffer(
|
||||
std::shared_ptr<MutableBuffer> buffer) override {
|
||||
return RD::createArrayBuffer(std::move(buffer));
|
||||
}
|
||||
};
|
||||
size_t size(const Array& a) override {
|
||||
Around around{with_};
|
||||
return RD::size(a);
|
||||
}
|
||||
};
|
||||
size_t size(const ArrayBuffer& ab) override {
|
||||
Around around{with_};
|
||||
return RD::size(ab);
|
||||
}
|
||||
};
|
||||
uint8_t* data(const ArrayBuffer& ab) override {
|
||||
Around around{with_};
|
||||
return RD::data(ab);
|
||||
}
|
||||
};
|
||||
Value getValueAtIndex(const Array& a, size_t i) override {
|
||||
Around around{with_};
|
||||
return RD::getValueAtIndex(a, i);
|
||||
}
|
||||
};
|
||||
void setValueAtIndexImpl(const Array& a, size_t i, const Value& value)
|
||||
override {
|
||||
Around around{with_};
|
||||
RD::setValueAtIndexImpl(a, i, value);
|
||||
}
|
||||
};
|
||||
|
||||
Function createFunctionFromHostFunction(
|
||||
const PropNameID& name,
|
||||
@@ -977,7 +977,7 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
Around around{with_};
|
||||
return RD::createFunctionFromHostFunction(
|
||||
name, paramCount, std::move(func));
|
||||
}
|
||||
};
|
||||
Value call(
|
||||
const Function& f,
|
||||
const Value& jsThis,
|
||||
@@ -985,12 +985,12 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
size_t count) override {
|
||||
Around around{with_};
|
||||
return RD::call(f, jsThis, args, count);
|
||||
}
|
||||
};
|
||||
Value callAsConstructor(const Function& f, const Value* args, size_t count)
|
||||
override {
|
||||
Around around{with_};
|
||||
return RD::callAsConstructor(f, args, count);
|
||||
}
|
||||
};
|
||||
|
||||
// Private data for managing scopes.
|
||||
Runtime::ScopeState* pushScope() override {
|
||||
@@ -1005,31 +1005,31 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
bool strictEquals(const Symbol& a, const Symbol& b) const override {
|
||||
Around around{with_};
|
||||
return RD::strictEquals(a, b);
|
||||
}
|
||||
};
|
||||
bool strictEquals(const BigInt& a, const BigInt& b) const override {
|
||||
Around around{with_};
|
||||
return RD::strictEquals(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
bool strictEquals(const String& a, const String& b) const override {
|
||||
Around around{with_};
|
||||
return RD::strictEquals(a, b);
|
||||
}
|
||||
};
|
||||
bool strictEquals(const Object& a, const Object& b) const override {
|
||||
Around around{with_};
|
||||
return RD::strictEquals(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
bool instanceOf(const Object& o, const Function& f) override {
|
||||
Around around{with_};
|
||||
return RD::instanceOf(o, f);
|
||||
}
|
||||
};
|
||||
|
||||
void setExternalMemoryPressure(const jsi::Object& obj, size_t amount)
|
||||
override {
|
||||
Around around{with_};
|
||||
RD::setExternalMemoryPressure(obj, amount);
|
||||
}
|
||||
};
|
||||
|
||||
void setRuntimeDataImpl(
|
||||
const UUID& uuid,
|
||||
|
||||
@@ -91,7 +91,7 @@ class [[deprecated(
|
||||
const std::string& moduleId,
|
||||
const std::string& methodId,
|
||||
const folly::dynamic& arguments) override;
|
||||
void invokeCallback(double callbackId, const folly::dynamic& arguments)
|
||||
void invokeCallback(const double callbackId, const folly::dynamic& arguments)
|
||||
override;
|
||||
void setGlobalVariable(
|
||||
std::string propName,
|
||||
|
||||
@@ -13,11 +13,13 @@ namespace facebook::react::jsinspector_modern::cdp::network {
|
||||
|
||||
namespace {
|
||||
|
||||
folly::dynamic headersToDynamic(const Headers& headers) {
|
||||
folly::dynamic headersToDynamic(const std::optional<Headers>& headers) {
|
||||
folly::dynamic result = folly::dynamic::object;
|
||||
|
||||
for (const auto& [key, value] : headers) {
|
||||
result[key] = value;
|
||||
if (headers) {
|
||||
for (const auto& [key, value] : *headers) {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -39,14 +41,14 @@ folly::dynamic Request::toDynamic() const {
|
||||
/* static */ Response Response::fromInputParams(
|
||||
const std::string& url,
|
||||
uint16_t status,
|
||||
const Headers& headers,
|
||||
const std::optional<Headers>& headers,
|
||||
int encodedDataLength) {
|
||||
return {
|
||||
.url = url,
|
||||
.status = status,
|
||||
.statusText = httpReasonPhrase(status),
|
||||
.headers = headers,
|
||||
.mimeType = mimeTypeFromHeaders(headers),
|
||||
.mimeType = mimeTypeFromHeaders(headers.value_or(Headers())),
|
||||
.encodedDataLength = encodedDataLength,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ using Headers = std::map<std::string, std::string>;
|
||||
struct Request {
|
||||
std::string url;
|
||||
std::string method;
|
||||
Headers headers;
|
||||
std::optional<Headers> headers;
|
||||
std::optional<std::string> postData;
|
||||
|
||||
folly::dynamic toDynamic() const;
|
||||
@@ -37,7 +37,7 @@ struct Response {
|
||||
std::string url;
|
||||
uint16_t status;
|
||||
std::string statusText;
|
||||
Headers headers;
|
||||
std::optional<Headers> headers;
|
||||
std::string mimeType;
|
||||
int encodedDataLength;
|
||||
|
||||
@@ -48,7 +48,7 @@ struct Response {
|
||||
static Response fromInputParams(
|
||||
const std::string& url,
|
||||
uint16_t status,
|
||||
const Headers& headers,
|
||||
const std::optional<Headers>& headers,
|
||||
int encodedDataLength);
|
||||
|
||||
folly::dynamic toDynamic() const;
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
using Headers = std::map<std::string, std::string>;
|
||||
|
||||
/**
|
||||
* Get the HTTP reason phrase for a given status code (RFC 9110).
|
||||
*/
|
||||
@@ -23,6 +21,7 @@ std::string httpReasonPhrase(uint16_t status);
|
||||
* Get the MIME type for a response based on the 'Content-Type' header. If
|
||||
* the header is not present, returns 'application/octet-stream'.
|
||||
*/
|
||||
std::string mimeTypeFromHeaders(const Headers& headers);
|
||||
std::string mimeTypeFromHeaders(
|
||||
const std::map<std::string, std::string>& headers);
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
|
||||
@@ -18,7 +18,6 @@ target_include_directories(jsinspector_tracing PUBLIC ${REACT_COMMON_DIR})
|
||||
|
||||
target_link_libraries(jsinspector_tracing
|
||||
folly_runtime
|
||||
jsinspector_network
|
||||
oscompat
|
||||
react_timing
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user