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 | |
|---|---|---|---|
|
|
807ace64f6 |
@@ -1,128 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
|
||||
|
||||
import type {HostInstance} from 'react-native';
|
||||
|
||||
import * as Fantom from '@react-native/fantom';
|
||||
import * as React from 'react';
|
||||
import {createRef} from 'react';
|
||||
import {ImageBackground} from 'react-native';
|
||||
import ensureInstance from 'react-native/src/private/__tests__/utilities/ensureInstance';
|
||||
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
|
||||
describe('<ImageBackground>', () => {
|
||||
describe('props', () => {
|
||||
describe('ImageProps', () => {
|
||||
it('can have local source', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<ImageBackground source={require('./img/img1.png')} />);
|
||||
});
|
||||
|
||||
expect(root.getRenderedOutput({props: ['source']}).toJSX()).toEqual(
|
||||
<rn-image
|
||||
source-scale="1"
|
||||
source-size="{1, 1}"
|
||||
source-type="local"
|
||||
source-uri="file://drawable-mdpi/packages_reactnative_libraries_image___tests___img_img1.png"
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
it('can have remote source', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<ImageBackground
|
||||
source={{
|
||||
uri: 'https://reactnative.dev/img/tiny_logo.png',
|
||||
width: 100,
|
||||
height: 100,
|
||||
scale: 2,
|
||||
cache: 'only-if-cached',
|
||||
method: 'POST',
|
||||
body: 'name=React+Native',
|
||||
headers: {
|
||||
Authorization: 'Basic RandomString',
|
||||
},
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.getRenderedOutput({props: ['source']}).toJSX()).toEqual(
|
||||
<rn-image
|
||||
source-body="name=React+Native"
|
||||
source-cache="only-if-cached"
|
||||
source-header-Authorization="Basic RandomString"
|
||||
source-method="POST"
|
||||
source-scale="2"
|
||||
source-size="{100, 100}"
|
||||
source-type="remote"
|
||||
source-uri="https://reactnative.dev/img/tiny_logo.png"
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
it('can have srcSet', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<ImageBackground srcSet="https://reactnative.dev/img/tiny_logo.png 1x, https://reactnative.dev/img/header_logo.svg 2x" />,
|
||||
);
|
||||
});
|
||||
|
||||
expect(root.getRenderedOutput({props: ['source']}).toJSX()).toEqual(
|
||||
<rn-image
|
||||
source-1x-scale="1"
|
||||
source-1x-type="remote"
|
||||
source-1x-uri="https://reactnative.dev/img/tiny_logo.png"
|
||||
source-2x-scale="2"
|
||||
source-2x-type="remote"
|
||||
source-2x-uri="https://reactnative.dev/img/header_logo.svg"
|
||||
/>,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('style', () => {
|
||||
it('can be set', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<ImageBackground style={{width: 100, height: 100}} />);
|
||||
});
|
||||
|
||||
expect(
|
||||
root.getRenderedOutput({props: ['width|height']}).toJSX(),
|
||||
).toEqual(<rn-image width="100.000000" height="100.000000" />);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ref', () => {
|
||||
it('Allows to set a reference to the inner `Image` component', () => {
|
||||
const elementRef = createRef<HostInstance>();
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<ImageBackground imageRef={elementRef} />);
|
||||
});
|
||||
|
||||
const image = ensureInstance(elementRef.current, ReactNativeElement);
|
||||
expect(image.tagName).toBe('RN:Image');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,9 @@
|
||||
* @noformat
|
||||
* @nolint
|
||||
* @flow
|
||||
* @generated SignedSource<<cf323fc5ca893bab5669c7d321660412>>
|
||||
* @generated SignedSource<<16b364e89f43b8a47832b0dfb98af11e>>
|
||||
*
|
||||
* This file was sync'd from the facebook/react repository.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
* @noformat
|
||||
* @nolint
|
||||
* @flow strict-local
|
||||
* @generated SignedSource<<908f5fb85384725318e261f40e49d9a6>>
|
||||
* @generated SignedSource<<1dd9e9c3f20e37ae14e485fc6ee3d9e9>>
|
||||
*
|
||||
* This file was sync'd from the facebook/react repository.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
* @noformat
|
||||
* @nolint
|
||||
* @flow
|
||||
* @generated SignedSource<<8f46fdc9267fcc4fdc9e76842fe24066>>
|
||||
* @generated SignedSource<<e2c46705ed927302dbe9332dafba459d>>
|
||||
*
|
||||
* This file was sync'd from the facebook/react repository.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
||||
+3
-1
@@ -7,7 +7,9 @@
|
||||
* @noformat
|
||||
* @nolint
|
||||
* @flow strict-local
|
||||
* @generated SignedSource<<83073425aa3f71ced2c8c51f25a25938>>
|
||||
* @generated SignedSource<<e8dce0e82b831c91465d04b49fb48ab2>>
|
||||
*
|
||||
* This file was sync'd from the facebook/react repository.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
+3
-1
@@ -7,7 +7,9 @@
|
||||
* @noformat
|
||||
* @nolint
|
||||
* @flow strict-local
|
||||
* @generated SignedSource<<52163887de05f1cff05388145cf85b3b>>
|
||||
* @generated SignedSource<<556d1487de0b9e4a09cbc67dd130a884>>
|
||||
*
|
||||
* This file was sync'd from the facebook/react repository.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
-3
@@ -229,9 +229,6 @@ public class ReactInstanceManager {
|
||||
return new ReactInstanceManagerBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @noinspection deprecation
|
||||
*/
|
||||
/* package */ ReactInstanceManager(
|
||||
Context applicationContext,
|
||||
@Nullable Activity currentActivity,
|
||||
|
||||
-5
@@ -25,11 +25,6 @@ import com.facebook.react.packagerconnection.RequestHandler
|
||||
*/
|
||||
internal class DefaultDevSupportManagerFactory : DevSupportManagerFactory {
|
||||
|
||||
@Deprecated(
|
||||
"Use the other create() method with useDevSupport parameter for New Architecture. This method will be removed in a future release.",
|
||||
replaceWith =
|
||||
ReplaceWith(
|
||||
"create(applicationContext, reactInstanceManagerHelper, packagerPathForJSBundleName, enableOnCreate, redBoxHandler, devBundleDownloadListener, minNumShakes, customPackagerCommandHandlers, surfaceDelegateFactory, devLoadingViewManager, pausedInDebuggerOverlayManager)"))
|
||||
override fun create(
|
||||
applicationContext: Context,
|
||||
reactInstanceManagerHelper: ReactInstanceDevHelper,
|
||||
|
||||
-6
@@ -22,12 +22,6 @@ public interface DevSupportManagerFactory {
|
||||
* Factory used by the Old Architecture flow to create a [DevSupportManager] and a
|
||||
* [BridgeDevSupportManager]
|
||||
*/
|
||||
@Deprecated(
|
||||
message =
|
||||
"Use the other create() method with useDevSupport parameter for New Architecture. This method will be removed in a future release.",
|
||||
replaceWith =
|
||||
ReplaceWith(
|
||||
"create(applicationContext, reactInstanceManagerHelper, packagerPathForJSBundleName, enableOnCreate, redBoxHandler, devBundleDownloadListener, minNumShakes, customPackagerCommandHandlers, surfaceDelegateFactory, devLoadingViewManager, pausedInDebuggerOverlayManager)"))
|
||||
public fun create(
|
||||
applicationContext: Context,
|
||||
reactInstanceManagerHelper: ReactInstanceDevHelper,
|
||||
|
||||
+19
@@ -70,6 +70,7 @@ import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatur
|
||||
import com.facebook.react.internal.interop.InteropEventEmitter;
|
||||
import com.facebook.react.modules.core.ReactChoreographer;
|
||||
import com.facebook.react.modules.i18nmanager.I18nUtil;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.GuardedFrameCallback;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
@@ -97,6 +98,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
@@ -725,6 +727,23 @@ public class FabricUIManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to get the encoded screen size without vertical insets for a given surface.
|
||||
* It's used by the Modal component to determine the size of the screen without vertical insets.
|
||||
* The method is private as it's accessed via JNI from C++.
|
||||
*
|
||||
* @param surfaceId The surface ID of the surface for which the Modal is going to render.
|
||||
* @return The encoded screen size as a long (both width and height) are represented without
|
||||
* vertical insets.
|
||||
*/
|
||||
private long getEncodedScreenSizeWithoutVerticalInsets(int surfaceId) {
|
||||
SurfaceMountingManager surfaceMountingManager = mMountingManager.getSurfaceManager(surfaceId);
|
||||
Objects.requireNonNull(surfaceMountingManager);
|
||||
ThemedReactContext context = Objects.requireNonNull(surfaceMountingManager.getContext());
|
||||
return DisplayMetricsHolder.getEncodedScreenSizeWithoutVerticalInsets(
|
||||
context.getCurrentActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUIManagerEventListener(UIManagerListener listener) {
|
||||
mListeners.add(listener);
|
||||
|
||||
+30
@@ -16,6 +16,7 @@ import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.window.layout.WindowMetricsCalculator
|
||||
import com.facebook.react.bridge.WritableMap
|
||||
import com.facebook.react.bridge.WritableNativeMap
|
||||
import com.facebook.react.uimanager.PixelUtil.pxToDp
|
||||
import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn
|
||||
|
||||
/**
|
||||
@@ -140,4 +141,33 @@ public object DisplayMetricsHolder {
|
||||
WindowInsetsCompat.Type.displayCutout())
|
||||
.top
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoded screen size without vertical insets.
|
||||
*
|
||||
* This is needed to render components that needs to be correctly positioned on the screen on
|
||||
* their first frame. Modal is one of such components.
|
||||
*
|
||||
* @param activity the [Activity] to get the insets from.
|
||||
* @return the encoded screen size as a [Long] value, where the first 32 bits represent the width
|
||||
* and the last 32 bits represent the height in dp (density-independent pixels).
|
||||
*/
|
||||
// This annotation can be removed once FabricUIManager is migrated to Kotlin
|
||||
@JvmName("getEncodedScreenSizeWithoutVerticalInsets")
|
||||
@JvmStatic
|
||||
internal fun getEncodedScreenSizeWithoutVerticalInsets(activity: Activity?): Long {
|
||||
val windowInsets = activity?.window?.decorView?.let(ViewCompat::getRootWindowInsets) ?: return 0
|
||||
val insets =
|
||||
windowInsets.getInsets(
|
||||
WindowInsetsCompat.Type.statusBars() or
|
||||
WindowInsetsCompat.Type.navigationBars() or
|
||||
WindowInsetsCompat.Type.displayCutout())
|
||||
val verticalInsets = insets.top + insets.bottom
|
||||
return encodeFloatsToLong(
|
||||
(checkNotNull(screenDisplayMetrics).widthPixels).toFloat().pxToDp(),
|
||||
(checkNotNull(screenDisplayMetrics).heightPixels - verticalInsets).toFloat().pxToDp())
|
||||
}
|
||||
|
||||
private fun encodeFloatsToLong(width: Float, height: Float): Long =
|
||||
(width.toRawBits().toLong()) shl 32 or (height.toRawBits().toLong())
|
||||
}
|
||||
|
||||
-26
@@ -41,8 +41,6 @@ import com.facebook.react.common.annotations.UnstableReactNativeAPI
|
||||
import com.facebook.react.common.annotations.VisibleForTesting
|
||||
import com.facebook.react.common.build.ReactBuildConfig
|
||||
import com.facebook.react.config.ReactFeatureFlags
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder.getStatusBarHeightPx
|
||||
import com.facebook.react.uimanager.JSPointerDispatcher
|
||||
import com.facebook.react.uimanager.JSTouchDispatcher
|
||||
import com.facebook.react.uimanager.PixelUtil.pxToDp
|
||||
@@ -52,13 +50,11 @@ import com.facebook.react.uimanager.ThemedReactContext
|
||||
import com.facebook.react.uimanager.UIManagerModule
|
||||
import com.facebook.react.uimanager.events.EventDispatcher
|
||||
import com.facebook.react.views.common.ContextUtils
|
||||
import com.facebook.react.views.modal.ReactModalHostView.DialogRootViewGroup
|
||||
import com.facebook.react.views.view.ReactViewGroup
|
||||
import com.facebook.react.views.view.disableEdgeToEdge
|
||||
import com.facebook.react.views.view.enableEdgeToEdge
|
||||
import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn
|
||||
import com.facebook.react.views.view.setStatusBarTranslucency
|
||||
import com.facebook.yoga.annotations.DoNotStrip
|
||||
|
||||
/**
|
||||
* ReactModalHostView is a view that sits in the view hierarchy representing a Modal view.
|
||||
@@ -73,7 +69,6 @@ import com.facebook.yoga.annotations.DoNotStrip
|
||||
* addition and removal of views to the DialogRootViewGroup.
|
||||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
@DoNotStrip
|
||||
public class ReactModalHostView(context: ThemedReactContext) :
|
||||
ViewGroup(context), LifecycleEventListener {
|
||||
|
||||
@@ -132,7 +127,6 @@ public class ReactModalHostView(context: ThemedReactContext) :
|
||||
private var createNewDialog = false
|
||||
|
||||
init {
|
||||
initStatusBarHeight(context)
|
||||
dialogRootViewGroup = DialogRootViewGroup(context)
|
||||
}
|
||||
|
||||
@@ -485,26 +479,6 @@ public class ReactModalHostView(context: ThemedReactContext) :
|
||||
|
||||
private companion object {
|
||||
private const val TAG = "ReactModalHost"
|
||||
|
||||
// We store the status bar height to be able to properly position
|
||||
// the modal on the first render.
|
||||
private var statusBarHeight = 0
|
||||
|
||||
private fun initStatusBarHeight(reactContext: ReactContext) {
|
||||
statusBarHeight = getStatusBarHeightPx(reactContext.currentActivity)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@DoNotStrip
|
||||
private fun getScreenDisplayMetricsWithoutInsets(): Long {
|
||||
val displayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics()
|
||||
return encodeFloatsToLong(
|
||||
displayMetrics.widthPixels.toFloat().pxToDp(),
|
||||
(displayMetrics.heightPixels - statusBarHeight).toFloat().pxToDp())
|
||||
}
|
||||
|
||||
private fun encodeFloatsToLong(width: Float, height: Float): Long =
|
||||
(width.toRawBits().toLong()) shl 32 or (height.toRawBits().toLong())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.yoga;
|
||||
|
||||
public class YogaConstants {
|
||||
|
||||
public static final float UNDEFINED = Float.NaN;
|
||||
|
||||
public static boolean isUndefined(float value) {
|
||||
return Float.compare(value, UNDEFINED) == 0;
|
||||
}
|
||||
|
||||
public static boolean isUndefined(YogaValue value) {
|
||||
return value.unit == YogaUnit.UNDEFINED;
|
||||
}
|
||||
|
||||
public static float getUndefined() {
|
||||
return UNDEFINED;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.yoga
|
||||
|
||||
public object YogaConstants {
|
||||
@JvmField public val UNDEFINED: Float = Float.NaN
|
||||
|
||||
@JvmStatic public fun isUndefined(value: Float): Boolean = value.compareTo(UNDEFINED) == 0
|
||||
|
||||
@JvmStatic public fun isUndefined(value: YogaValue): Boolean = value.unit == YogaUnit.UNDEFINED
|
||||
|
||||
@JvmStatic public fun getUndefined(): Float = UNDEFINED
|
||||
}
|
||||
-22
@@ -11,18 +11,12 @@
|
||||
|
||||
package com.facebook.react.bridge
|
||||
|
||||
import android.app.Application
|
||||
import com.facebook.react.bridge.queue.MessageQueueThreadSpec
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfiguration
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfigurationImpl
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec
|
||||
import com.facebook.react.common.annotations.UnstableReactNativeAPI
|
||||
import com.facebook.react.runtime.BridgelessReactContext
|
||||
import com.facebook.react.runtime.ReactHostImpl
|
||||
import com.facebook.react.runtime.internal.bolts.Task
|
||||
import com.facebook.react.uimanager.UIManagerModule
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.whenever
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
|
||||
@@ -55,20 +49,4 @@ object ReactTestHelper {
|
||||
whenever(reactInstance.isDestroyed).thenReturn(false)
|
||||
return reactInstance
|
||||
}
|
||||
|
||||
@OptIn(UnstableReactNativeAPI::class)
|
||||
fun createTestReactApplicationContext(application: Application): ReactApplicationContext {
|
||||
val reactHost =
|
||||
spy(
|
||||
ReactHostImpl(
|
||||
RuntimeEnvironment.getApplication(),
|
||||
mock(),
|
||||
mock(),
|
||||
Task.Companion.IMMEDIATE_EXECUTOR,
|
||||
Task.Companion.IMMEDIATE_EXECUTOR,
|
||||
false /* allowPackagerServerAccess */,
|
||||
false /* useDevSupport */,
|
||||
))
|
||||
return BridgelessReactContext(application, reactHost)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-16
@@ -5,45 +5,36 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.modules.clipboard
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import com.facebook.react.bridge.ReactTestHelper.createTestReactApplicationContext
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsForTests
|
||||
import com.facebook.testutils.shadows.ShadowSoLoader
|
||||
import com.facebook.react.bridge.BridgeReactContext
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@SuppressLint("ClipboardManager", "DeprecatedClass")
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(shadows = [ShadowSoLoader::class])
|
||||
class ClipboardModuleTest {
|
||||
private lateinit var clipboardModule: ClipboardModule
|
||||
private lateinit var clipboardManager: ClipboardManager
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ReactNativeFeatureFlagsForTests.setUp()
|
||||
clipboardModule =
|
||||
ClipboardModule(createTestReactApplicationContext(RuntimeEnvironment.getApplication()))
|
||||
clipboardModule = ClipboardModule(BridgeReactContext(RuntimeEnvironment.getApplication()))
|
||||
clipboardManager =
|
||||
RuntimeEnvironment.getApplication().getSystemService(Context.CLIPBOARD_SERVICE)
|
||||
as ClipboardManager
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
ReactNativeFeatureFlags.dangerouslyReset()
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Test
|
||||
fun testSetString() {
|
||||
clipboardModule.setString(TEST_CONTENT)
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ModalHostViewComponentDescriptor.h"
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
#ifdef ANDROID
|
||||
State::Shared ModalHostViewComponentDescriptor::createInitialState(
|
||||
const Props::Shared& props,
|
||||
const ShadowNodeFamily::Shared& family) const {
|
||||
// For Android, we need to get the size of the screen without the vertical
|
||||
// insets to correctly position the modal on the first rendering.
|
||||
// For this reason we provide the `createInitialState` implementation
|
||||
// that will query FabricUIManager for the size of the screen without
|
||||
// vertical insets.
|
||||
|
||||
int surfaceId = family->getSurfaceId();
|
||||
|
||||
const jni::global_ref<jobject>& fabricUIManager =
|
||||
contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
|
||||
|
||||
static auto getEncodedScreenSizeWithoutVerticalInsets =
|
||||
jni::findClassStatic(UIManagerJavaDescriptor)
|
||||
->getMethod<jlong(jint)>("getEncodedScreenSizeWithoutVerticalInsets");
|
||||
|
||||
auto result =
|
||||
getEncodedScreenSizeWithoutVerticalInsets(fabricUIManager, surfaceId);
|
||||
|
||||
// Inspired from yogaMeasureToSize from conversions.h
|
||||
int32_t wBits = 0xFFFFFFFF & (result >> 32);
|
||||
int32_t hBits = 0xFFFFFFFF & result;
|
||||
|
||||
auto* measuredWidth = reinterpret_cast<float*>(&wBits);
|
||||
auto* measuredHeight = reinterpret_cast<float*>(&hBits);
|
||||
|
||||
return std::make_shared<ModalHostViewShadowNode::ConcreteState>(
|
||||
std::make_shared<const ModalHostViewState>(ModalHostViewState(
|
||||
Size{.width = *measuredWidth, .height = *measuredHeight})),
|
||||
family);
|
||||
}
|
||||
#endif // ANDROID
|
||||
|
||||
} // namespace facebook::react
|
||||
+10
@@ -37,6 +37,16 @@ class ModalHostViewComponentDescriptor final
|
||||
|
||||
ConcreteComponentDescriptor::adopt(shadowNode);
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
State::Shared createInitialState(
|
||||
const Props::Shared& props,
|
||||
const ShadowNodeFamily::Shared& family) const override;
|
||||
#endif // ANDROID
|
||||
|
||||
private:
|
||||
constexpr static auto UIManagerJavaDescriptor =
|
||||
"com/facebook/react/fabric/FabricUIManager";
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <react/renderer/graphics/Size.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class JReactModalHostView
|
||||
: public facebook::jni::JavaClass<JReactModalHostView> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor =
|
||||
"Lcom/facebook/react/views/modal/ReactModalHostView;";
|
||||
|
||||
static Size getDisplayMetrics() {
|
||||
static auto method =
|
||||
JReactModalHostView::javaClassStatic()->getStaticMethod<jlong()>(
|
||||
"getScreenDisplayMetricsWithoutInsets");
|
||||
auto result = method(javaClassStatic());
|
||||
|
||||
// Inspired from yogaMeassureToSize from conversions.h
|
||||
int32_t wBits = 0xFFFFFFFF & (result >> 32);
|
||||
int32_t hBits = 0xFFFFFFFF & result;
|
||||
|
||||
auto* measuredWidth = reinterpret_cast<float*>(&wBits);
|
||||
auto* measuredHeight = reinterpret_cast<float*>(&hBits);
|
||||
|
||||
return Size{.width = *measuredWidth, .height = *measuredHeight};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
+1
-2
@@ -7,12 +7,11 @@
|
||||
|
||||
#include <react/renderer/components/modal/ModalHostViewUtils.h>
|
||||
#include <react/renderer/graphics/Size.h>
|
||||
#include "JReactModalHostView.h"
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
Size ModalHostViewScreenSize() {
|
||||
return JReactModalHostView::getDisplayMetrics();
|
||||
return Size{0, 0};
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+22
-19
@@ -8,8 +8,6 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {markdownTable} from './utils';
|
||||
|
||||
type TestTaskTiming = {
|
||||
name: string,
|
||||
latency: {
|
||||
@@ -33,7 +31,7 @@ export const printBenchmarkResultsRanking = (
|
||||
testArtifact: mixed,
|
||||
}>,
|
||||
) => {
|
||||
const testTaskTimings: {[string]: {[string]: number}} = {};
|
||||
const testTaskTimings: {[string]: Array<[string, number]>} = {};
|
||||
let numTestVariants = 0;
|
||||
|
||||
for (const testResult of testResults) {
|
||||
@@ -51,9 +49,12 @@ export const printBenchmarkResultsRanking = (
|
||||
for (const taskTiming of testArtifact.timings) {
|
||||
const taskName = taskTiming.name;
|
||||
if (testTaskTimings[taskName] === undefined) {
|
||||
testTaskTimings[taskName] = {};
|
||||
testTaskTimings[taskName] = [];
|
||||
}
|
||||
testTaskTimings[taskName][testResult.title] = taskTiming.latency.p50;
|
||||
testTaskTimings[taskName].push([
|
||||
testResult.title,
|
||||
taskTiming.latency.p50,
|
||||
]);
|
||||
}
|
||||
}
|
||||
if (numTestVariants <= 1 || Object.keys(testTaskTimings).length === 0) {
|
||||
@@ -61,23 +62,25 @@ export const printBenchmarkResultsRanking = (
|
||||
return;
|
||||
}
|
||||
|
||||
// Find relative execution times for tasks
|
||||
const results: {[string]: {[string]: string}} = {};
|
||||
// Sort by each task's execution times
|
||||
for (const taskName in testTaskTimings) {
|
||||
const kv = Object.entries(testTaskTimings[taskName]);
|
||||
kv.sort((a, b) => a[1] - b[1]);
|
||||
const bestTiming = kv[0][1];
|
||||
results[taskName] = {};
|
||||
kv.forEach(([key, val]) => {
|
||||
results[taskName][key] =
|
||||
`${val.toFixed(3)}ms ${getTimingDelta(bestTiming, val)}`;
|
||||
});
|
||||
results[taskName][kv[0][0]] = `🏆 ${bestTiming.toFixed(3)}ms`;
|
||||
testTaskTimings[taskName].sort((a, b) => a[1] - b[1]);
|
||||
}
|
||||
|
||||
console.log('### Benchmark Times Comparison (p50): ###');
|
||||
console.log(markdownTable(results, 'Task name'));
|
||||
console.log('');
|
||||
// Print the rankings
|
||||
console.log('### Benchmark Results Ranking ###');
|
||||
for (const taskName in testTaskTimings) {
|
||||
console.log(`> ${taskName}:`);
|
||||
let lastTiming;
|
||||
for (const [i, [testVariationName, latency]] of testTaskTimings[
|
||||
taskName
|
||||
].entries()) {
|
||||
console.log(
|
||||
` ${i + 1}. ${testVariationName}: ${latency.toFixed(2)}ms ${getTimingDelta(lastTiming, latency)}`,
|
||||
);
|
||||
lastTiming = latency;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getTimingDelta(lastTiming: ?number, currentTiming: ?number): string {
|
||||
|
||||
-61
@@ -371,64 +371,3 @@ export function printConsoleLog(log: ConsoleLogMessage): void {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a markdown table corresponding to the given data, adopted from the RN console.table polyfill implementation
|
||||
export function markdownTable(
|
||||
data: {[string]: {[string]: string}},
|
||||
indexColumnName?: string = '',
|
||||
): string {
|
||||
const repeat = (element: string, n: number) =>
|
||||
Array.apply(null, Array(n)).map(() => element);
|
||||
|
||||
const rows = Object.keys(data).map((key: string) => ({
|
||||
[indexColumnName]: key,
|
||||
...data[key],
|
||||
}));
|
||||
|
||||
if (rows.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const columns = Array.from(
|
||||
rows.reduce((columnSet: Set<string>, row) => {
|
||||
Object.keys(row).forEach(key => columnSet.add(key));
|
||||
return columnSet;
|
||||
}, new Set()),
|
||||
);
|
||||
const stringRows: Array<Array<string>> = [];
|
||||
const columnWidths = [];
|
||||
|
||||
// Figure out max cell width for each column
|
||||
columns.forEach((k, i) => {
|
||||
columnWidths[i] = k.length;
|
||||
for (let j = 0; j < rows.length; j++) {
|
||||
const cellStr = rows[j][k];
|
||||
stringRows[j] = stringRows[j] || [];
|
||||
stringRows[j][i] = cellStr;
|
||||
columnWidths[i] = Math.max(columnWidths[i], cellStr.length);
|
||||
}
|
||||
});
|
||||
|
||||
// Join all elements in the row into a single string with | separators
|
||||
// (appends extra spaces to each cell to make separators | aligned)
|
||||
const joinRow = (row: Array<string>, space?: string = ' ') => {
|
||||
const cells = row.map((cell: string, i) => {
|
||||
const extraSpaces = repeat(' ', columnWidths[i] - cell.length).join('');
|
||||
return cell + extraSpaces;
|
||||
});
|
||||
return '| ' + cells.join(space + '|' + space) + ' |';
|
||||
};
|
||||
|
||||
const separators = columnWidths.map(columnWidth =>
|
||||
repeat('-', columnWidth).join(''),
|
||||
);
|
||||
const separatorRow = joinRow(separators);
|
||||
const header = joinRow(columns);
|
||||
const table = [header, separatorRow];
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
table.push(joinRow(stringRows[i]));
|
||||
}
|
||||
|
||||
return '\n' + table.join('\n');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user