diff --git a/.eslintrc.js b/.eslintrc.js index 26bb32beb3a..183615adfe7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,5 +5,6 @@ module.exports = { plugins: ['@typescript-eslint'], env: { jest: true, + 'jest/globals': true, }, }; diff --git a/babel.config.js b/babel.config.js index cdf7ebe6ab5..c05b94b830d 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,7 +1,7 @@ module.exports = function (api) { api && api.cache(false); return { - presets: ['module:metro-react-native-babel-preset'], + presets: ['module:@react-native/babel-preset'], plugins: [ '@babel/plugin-proposal-export-namespace-from', '@babel/plugin-proposal-export-default-from', diff --git a/e2e/StaticLifecycleEvents.test.js b/e2e/StaticLifecycleEvents.test.js index dddcbc36a4c..ffb7addff6c 100644 --- a/e2e/StaticLifecycleEvents.test.js +++ b/e2e/StaticLifecycleEvents.test.js @@ -1,7 +1,7 @@ import Utils from './Utils'; import TestIDs from '../playground/src/testIDs'; -const { elementByLabel, elementById } = Utils; +const { elementByLabel, elementById, sleep } = Utils; describe('static lifecycle events', () => { beforeEach(async () => { @@ -93,6 +93,7 @@ describe('static lifecycle events', () => { await elementById(TestIDs.SET_ROOT_BTN).tap(); await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); await elementById(TestIDs.SET_ROOT_BTN).tap(); + await sleep(10); await expect(elementByLabel('setRoot complete - previous root is unmounted')).toBeVisible(); }); diff --git a/e2e/assets/overlay_banner_padding.png b/e2e/assets/overlay_banner_padding.png index 9e4884a2a8a..2795b3ea6bb 100644 Binary files a/e2e/assets/overlay_banner_padding.png and b/e2e/assets/overlay_banner_padding.png differ diff --git a/lib/Mock/Components/ComponentScreen.tsx b/lib/Mock/Components/ComponentScreen.tsx index 40ba36a74cb..68ca7e06b66 100644 --- a/lib/Mock/Components/ComponentScreen.tsx +++ b/lib/Mock/Components/ComponentScreen.tsx @@ -1,6 +1,6 @@ import React, { Component } from 'react'; -import { View, Text, TouchableOpacity, Image, ImageURISource} from 'react-native'; -import { Navigation, ImageResource} from 'react-native-navigation'; +import { View, Text, TouchableOpacity, Image, ImageURISource } from 'react-native'; +import { Navigation, ImageResource } from 'react-native-navigation'; import { ComponentProps } from '../ComponentProps'; import { VISIBLE_SCREEN_TEST_ID } from '../constants'; import { LayoutStore } from '../Stores/LayoutStore'; @@ -10,8 +10,7 @@ import { events } from '../Stores/EventsStore'; import _ from 'lodash'; import { switchTabByIndex } from '../actions/layoutActions'; - -function isURISource(src: ImageResource| undefined): src is ImageURISource { +function isURISource(src: ImageResource | undefined): src is ImageURISource { return !!src && typeof src === 'object' && 'uri' in src; } @@ -36,12 +35,15 @@ export const ComponentScreen = connect( if (bottomTabsOptions?.visible === false) return null; const buttons = bottomTabs!.children!.map((child, i) => { const bottomTabOptions = child.resolveOptions().bottomTab; - const icon = (bottomTabs as any).selectedIndex === i ? bottomTabOptions?.selectedIcon : bottomTabOptions?.icon; + const icon = + (bottomTabs as any).selectedIndex === i + ? bottomTabOptions?.selectedIcon + : bottomTabOptions?.icon; const iconURI = isURISource(icon) ? icon.uri : undefined; return ( { events.invokeBottomTabPressed({ @@ -51,22 +53,34 @@ export const ComponentScreen = connect( switchTabByIndex(this.props.layoutNode.getBottomTabs(), i); }} > - - {bottomTabOptions?.badge} - {iconURI && } - {bottomTabOptions?.text || ''} - + + {bottomTabOptions?.badge} + {iconURI && ( + + )} + {bottomTabOptions?.text || ''} + ); }); return ( - + {buttons} - ); + + ); } render() { diff --git a/lib/Mock/Components/LayoutComponent.tsx b/lib/Mock/Components/LayoutComponent.tsx index 637e3ec9d56..b18df7200f8 100644 --- a/lib/Mock/Components/LayoutComponent.tsx +++ b/lib/Mock/Components/LayoutComponent.tsx @@ -19,8 +19,8 @@ export const LayoutComponent = class extends Component { return ; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { - const err = new Error( - `Error while trying to render layout ${this.props.layoutNode.nodeId} of type ${this.props.layoutNode.type}: ${error}\n${errorInfo?.componentStack}`, + const err = new Error( + `Error while trying to render layout ${this.props.layoutNode.nodeId} of type ${this.props.layoutNode.type}: ${error}\n${errorInfo?.componentStack}` ); (err as any).cause = error; throw err; diff --git a/lib/android/app/build.gradle b/lib/android/app/build.gradle index 3428f1a8820..cc7c1d061d6 100644 --- a/lib/android/app/build.gradle +++ b/lib/android/app/build.gradle @@ -20,6 +20,7 @@ def DEFAULT_KOTLIN_STDLIB = 'kotlin-stdlib-jdk8' def kotlinVersion = safeExtGet("RNNKotlinVersion", DEFAULT_KOTLIN_VERSION) def kotlinStdlib = safeExtGet('RNNKotlinStdlib',DEFAULT_KOTLIN_STDLIB ) def kotlinCoroutinesCore = safeExtGet('RNNKotlinCoroutinesCore', '1.5.2') + android { namespace 'com.reactnativenavigation' compileSdkVersion safeExtGetFallbackLowerBound('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) @@ -214,5 +215,7 @@ dependencies { testImplementation 'org.mockito:mockito-inline:3.4.0' testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0" testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion" + testImplementation "io.mockk:mockk:1.13.16" + } } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java b/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java index 0eced0fecf9..f009c4e7eeb 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java @@ -4,10 +4,12 @@ import com.facebook.react.ReactApplication; import com.facebook.react.ReactNativeHost; +import com.facebook.react.soloader.OpenSourceMergedSoMapping; import com.facebook.soloader.SoLoader; import com.reactnativenavigation.react.ReactGateway; import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentCreator; +import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -23,7 +25,11 @@ public abstract class NavigationApplication extends Application implements React public void onCreate() { super.onCreate(); instance = this; - SoLoader.init(this, false); + try { + SoLoader.init(this, OpenSourceMergedSoMapping.INSTANCE); + } catch (IOException e) { + throw new RuntimeException(e); + } reactGateway = createReactGateway(); } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java b/lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java index 90032dfd55d..81dcbab0d4b 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java @@ -9,6 +9,7 @@ import com.facebook.react.ReactRootView; import com.facebook.react.bridge.ReactContext; import com.facebook.react.config.ReactFeatureFlags; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.uimanager.JSTouchDispatcher; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.events.EventDispatcher; @@ -35,7 +36,7 @@ public ReactView(final Context context, ReactInstanceManager reactInstanceManage this.componentId = componentId; this.componentName = componentName; jsTouchDispatcher = new JSTouchDispatcher(this); - setIsFabric(ReactFeatureFlags.enableFabricRenderer); + setIsFabric(ReactNativeFeatureFlags.enableFabricRenderer()); } @Override diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalHostLayout.kt b/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalHostLayout.kt index 121aa6a09f7..88094c33b3a 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalHostLayout.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalHostLayout.kt @@ -34,7 +34,7 @@ open class ModalHostLayout(reactContext: ThemedReactContext) : ViewGroup(reactCo } @TargetApi(23) - override fun dispatchProvideStructure(structure: ViewStructure?) { + override fun dispatchProvideStructure(structure: ViewStructure) { mHostView.dispatchProvideStructure(structure) } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactTypefaceUtils.java b/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactTypefaceUtils.java index 834d734f154..962bf9ef53c 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactTypefaceUtils.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactTypefaceUtils.java @@ -18,6 +18,7 @@ import android.text.TextUtils; import androidx.annotation.Nullable; import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.common.ReactConstants; import com.facebook.react.views.text.ReactFontManager; import com.facebook.react.views.text.ReactTextShadowNode; import java.util.ArrayList; @@ -96,12 +97,12 @@ public static Typeface applyStyles( int want = 0; if ((weight == Typeface.BOLD) - || ((oldStyle & Typeface.BOLD) != 0 && weight == ReactTextShadowNode.UNSET)) { + || ((oldStyle & Typeface.BOLD) != 0 && weight == ReactConstants.UNSET)) { want |= Typeface.BOLD; } if ((style == Typeface.ITALIC) - || ((oldStyle & Typeface.ITALIC) != 0 && style == ReactTextShadowNode.UNSET)) { + || ((oldStyle & Typeface.ITALIC) != 0 && style == ReactConstants.UNSET)) { want |= Typeface.ITALIC; } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactViewGroup.kt b/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactViewGroup.kt index f92580c7a80..1053123e7da 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactViewGroup.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactViewGroup.kt @@ -1,7 +1,9 @@ package com.reactnativenavigation.utils -import com.facebook.react.views.view.ReactViewBackgroundDrawable +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable import com.facebook.react.views.view.ReactViewGroup +@OptIn(UnstableReactNativeAPI::class) val ReactViewGroup.borderRadius: Float - get() = (background as? ReactViewBackgroundDrawable)?.fullBorderRadius ?: 0f \ No newline at end of file + get() = (background as? CSSBackgroundDrawable)?.fullBorderWidth ?: 0f \ No newline at end of file diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java b/lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java index cdce75b8ab8..bbd4c392318 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java @@ -5,8 +5,6 @@ import android.view.ViewGroup; import android.view.ViewParent; -import com.facebook.react.views.view.ReactViewBackgroundDrawable; - import java.util.ArrayList; import java.util.List; @@ -14,6 +12,9 @@ import static com.reactnativenavigation.utils.ObjectUtils.perform; +import com.facebook.react.common.annotations.UnstableReactNativeAPI; +import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable; + public class ViewUtils { @Nullable public static T findChildByClass(ViewGroup root, Class clazz) { @@ -107,9 +108,10 @@ public static int getIndexInParent(View view) { return ((ViewGroup) parent).indexOfChild(view); } + @UnstableReactNativeAPI public static int getBackgroundColor(View view) { - if (view.getBackground() instanceof ReactViewBackgroundDrawable) { - return ((ReactViewBackgroundDrawable) view.getBackground()).getColor(); + if (view.getBackground() instanceof CSSBackgroundDrawable) { + return ((CSSBackgroundDrawable) view.getBackground()).getColor(); } throw new RuntimeException(view.getBackground().getClass().getSimpleName() + " is not ReactViewBackgroundDrawable"); } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/LayoutDirectionApplier.kt b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/LayoutDirectionApplier.kt index 89216ae0c6b..cdfc2e9e020 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/LayoutDirectionApplier.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/LayoutDirectionApplier.kt @@ -1,15 +1,19 @@ package com.reactnativenavigation.viewcontrollers.viewcontroller +import android.annotation.SuppressLint import com.facebook.react.ReactInstanceManager import com.facebook.react.modules.i18nmanager.I18nUtil import com.reactnativenavigation.options.Options class LayoutDirectionApplier { - fun apply(root: ViewController<*>, options: Options, instanceManager: ReactInstanceManager) { - if (options.layout.direction.hasValue() && instanceManager.currentReactContext != null) { + @SuppressLint("WrongConstant") + fun apply(root: ViewController<*>, options: Options) { + val currentContext = root.view?.context ?: return + + if (options.layout.direction.hasValue()) { root.activity.window.decorView.layoutDirection = options.layout.direction.get() - I18nUtil.getInstance().allowRTL(instanceManager.currentReactContext, options.layout.direction.isRtl) - I18nUtil.getInstance().forceRTL(instanceManager.currentReactContext, options.layout.direction.isRtl) + I18nUtil.instance.allowRTL(currentContext, options.layout.direction.isRtl) + I18nUtil.instance.forceRTL(currentContext, options.layout.direction.isRtl) } } } \ No newline at end of file diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/RootPresenter.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/RootPresenter.java index 17c81ad2298..f7a07c09824 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/RootPresenter.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/RootPresenter.java @@ -35,7 +35,7 @@ public RootPresenter(RootAnimator animator, LayoutDirectionApplier layoutDirecti } public void setRoot(ViewController appearingRoot, ViewController disappearingRoot, Options defaultOptions, CommandListener listener, ReactInstanceManager reactInstanceManager) { - layoutDirectionApplier.apply(appearingRoot, defaultOptions, reactInstanceManager); + layoutDirectionApplier.apply(appearingRoot, defaultOptions); rootLayout.addView(appearingRoot.getView(), matchParentWithBehaviour(new BehaviourDelegate(appearingRoot))); Options options = appearingRoot.resolveCurrentOptions(defaultOptions); AnimationOptions enter = options.animations.setRoot.getEnter(); diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorAnimator.kt b/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorAnimator.kt index 4ecc1a2bbe6..ab7ed30b21e 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorAnimator.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorAnimator.kt @@ -4,21 +4,23 @@ import android.animation.Animator import android.animation.ObjectAnimator import android.view.View import android.view.ViewGroup +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable import com.facebook.react.views.text.ReactTextView -import com.facebook.react.views.view.ReactViewBackgroundDrawable import com.reactnativenavigation.options.SharedElementTransitionOptions import com.reactnativenavigation.utils.* +@OptIn(UnstableReactNativeAPI::class) class BackgroundColorAnimator(from: View, to: View) : PropertyAnimatorCreator(from, to) { override fun shouldAnimateProperty(fromChild: ViewGroup, toChild: ViewGroup): Boolean { - return fromChild.background is ReactViewBackgroundDrawable && - toChild.background is ReactViewBackgroundDrawable && (fromChild.background as ReactViewBackgroundDrawable).color != (toChild.background as ReactViewBackgroundDrawable).color + return fromChild.background is CSSBackgroundDrawable && + toChild.background is CSSBackgroundDrawable && (fromChild.background as CSSBackgroundDrawable).color != (toChild.background as CSSBackgroundDrawable).color } override fun excludedViews() = listOf(ReactTextView::class.java) override fun create(options: SharedElementTransitionOptions): Animator { - val backgroundColorEvaluator = BackgroundColorEvaluator(to.background as ReactViewBackgroundDrawable) + val backgroundColorEvaluator = BackgroundColorEvaluator(to.background as CSSBackgroundDrawable) val fromColor = ColorUtils.colorToLAB(ViewUtils.getBackgroundColor(from)) val toColor = ColorUtils.colorToLAB(ViewUtils.getBackgroundColor(to)) diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorEvaluator.kt b/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorEvaluator.kt index 4480113dcfb..7ce0854f019 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorEvaluator.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorEvaluator.kt @@ -2,11 +2,13 @@ package com.reactnativenavigation.views.element.animators import android.animation.TypeEvaluator import androidx.core.graphics.ColorUtils -import com.facebook.react.views.view.ReactViewBackgroundDrawable +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable -class BackgroundColorEvaluator(private val background: ReactViewBackgroundDrawable) : TypeEvaluator { +class BackgroundColorEvaluator @OptIn(UnstableReactNativeAPI::class) constructor(private val background: CSSBackgroundDrawable) : TypeEvaluator { private val color = DoubleArray(3) + @OptIn(UnstableReactNativeAPI::class) override fun evaluate(ratio: Float, from: DoubleArray, to: DoubleArray): DoubleArray { ColorUtils.blendLAB(from, to, ratio.toDouble(), color) background.color = com.reactnativenavigation.utils.ColorUtils.labToColor(color) diff --git a/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt b/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt index ea8516fee7f..551f72b1ec4 100644 --- a/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt +++ b/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt @@ -49,17 +49,17 @@ class ModalContentLayout(context: Context?) : ReactViewGroup(context), RootView{ updateFirstChildView() } } - override fun onChildStartedNativeGesture(child: View, androidEvent: MotionEvent?) { + override fun onChildStartedNativeGesture(child: View, androidEvent: MotionEvent) { mJSTouchDispatcher.onChildStartedNativeGesture(androidEvent, this.getEventDispatcher()) } - override fun onChildStartedNativeGesture(androidEvent: MotionEvent?) { + override fun onChildStartedNativeGesture(androidEvent: MotionEvent) { mJSTouchDispatcher.onChildStartedNativeGesture(androidEvent, this.getEventDispatcher()) } - override fun onChildEndedNativeGesture(child: View, androidEvent: MotionEvent?) { + override fun onChildEndedNativeGesture(child: View, androidEvent: MotionEvent) { mJSTouchDispatcher.onChildEndedNativeGesture(androidEvent, this.getEventDispatcher()) } override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {} - private fun getEventDispatcher(): EventDispatcher? { + private fun getEventDispatcher(): EventDispatcher { val reactContext: ReactContext = this.getReactContext() return reactContext.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher } @@ -73,12 +73,12 @@ class ModalContentLayout(context: Context?) : ReactViewGroup(context), RootView{ return this.context as ReactContext } - override fun onInterceptTouchEvent(event: MotionEvent?): Boolean { + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher()) return super.onInterceptTouchEvent(event) } - override fun onTouchEvent(event: MotionEvent?): Boolean { + override fun onTouchEvent(event: MotionEvent): Boolean { mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher()) super.onTouchEvent(event) return true diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.java deleted file mode 100644 index 33ea5aeca4b..00000000000 --- a/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.reactnativenavigation; - -import static com.reactnativenavigation.utils.CollectionUtils.forEach; -import static org.assertj.core.api.Java6Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.app.Activity; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Handler; -import android.os.Looper; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.CallSuper; -import androidx.appcompat.app.AppCompatActivity; -import androidx.coordinatorlayout.widget.CoordinatorLayout; - -import com.reactnativenavigation.options.params.Bool; -import com.reactnativenavigation.utils.Functions; -import com.reactnativenavigation.utils.SystemUiUtils; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController; - -import org.junit.After; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.Shadows; -import org.robolectric.android.controller.ActivityController; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLooper; - -import java.util.Arrays; - -@RunWith(RobolectricTestRunner.class) -@Config(sdk = 28, application = TestApplication.class) -public abstract class BaseTest { - private final Handler handler = new Handler(Looper.getMainLooper()); - private final ShadowLooper shadowMainLooper = Shadows.shadowOf(Looper.getMainLooper()); - protected Configuration mockConfiguration; - - @Before - public void beforeEach() { - NavigationApplication.instance = Mockito.mock(NavigationApplication.class); - mockConfiguration = Mockito.mock(Configuration.class); - Resources res = mock(Resources.class); - mockConfiguration.uiMode = Configuration.UI_MODE_NIGHT_NO; - when(res.getConfiguration()).thenReturn(mockConfiguration); - when(NavigationApplication.instance.getResources()).thenReturn(res); - when(res.getColor(ArgumentMatchers.anyInt())).thenReturn(0x00000); - when(res.getColor(ArgumentMatchers.anyInt(),any())).thenReturn(0x00000); - } - - - public void mockSystemUiUtils(int statusBarHeight, int statusBarHeightDp, Functions.Func1> mockedBlock) { - try (MockedStatic theMock = Mockito.mockStatic(SystemUiUtils.class)) { - theMock.when(() -> { - SystemUiUtils.getStatusBarHeight(any()); - }).thenReturn(statusBarHeight); - theMock.when(() -> { - SystemUiUtils.getStatusBarHeightDp(any()); - }).thenReturn(statusBarHeightDp); - mockedBlock.run(theMock); - } - } - - @After - @CallSuper - public void afterEach() { - idleMainLooper(); - } - - public Activity newActivity() { - return Robolectric.setupActivity(AppCompatActivity.class); - } - - public ActivityController newActivityController(Class clazz) { - return Robolectric.buildActivity(clazz); - } - - public void assertIsChild(ViewGroup parent, ViewController... children) { - forEach(Arrays.asList(children), c -> assertIsChild(parent, c.getView())); - } - - public void assertIsChild(ViewGroup parent, View child) { - assertThat(parent).isNotNull(); - assertThat(child).isNotNull(); - assertThat(ViewUtils.isChildOf(parent, child)).isTrue(); - } - - public void assertNotChildOf(ViewGroup parent, ViewController... children) { - forEach(Arrays.asList(children), c -> assertNotChildOf(parent, c.getView())); - } - - public void assertNotChildOf(ViewGroup parent, View child) { - assertThat(parent).isNotNull(); - assertThat(child).isNotNull(); - assertThat(ViewUtils.isChildOf(parent, child)).isFalse(); - } - - public void assertMatchParent(View view) { - assertThat(view.getLayoutParams().width).isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT); - assertThat(view.getLayoutParams().height).isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT); - } - - protected void disablePushAnimation(ViewController... controllers) { - for (ViewController controller : controllers) { - controller.options.animations.push.enabled = new Bool(false); - } - } - - protected void disablePopAnimation(ViewController... controllers) { - for (ViewController controller : controllers) { - controller.options.animations.pop.enabled = new Bool(false); - } - } - - protected void disableModalAnimations(ViewController... modals) { - disableShowModalAnimation(modals); - disableDismissModalAnimation(modals); - } - - protected void disableShowModalAnimation(ViewController... modals) { - for (ViewController modal : modals) { - modal.options.animations.showModal.toggle(new Bool(false)); - } - } - - protected void disableDismissModalAnimation(ViewController... modals) { - for (ViewController modal : modals) { - modal.options.animations.dismissModal.toggle(new Bool(false)); - } - } - - protected void dispatchPreDraw(View view) { - view.getViewTreeObserver().dispatchOnPreDraw(); - } - - protected void dispatchOnGlobalLayout(View view) { - view.getViewTreeObserver().dispatchOnGlobalLayout(); - } - - protected void addToParent(Context context, ViewController... controllers) { - for (ViewController controller : controllers) { - new CoordinatorLayout(context).addView(controller.getView()); - } - } - - protected View mockView(Activity activity) { - View mock = Mockito.mock(View.class); - when(mock.getContext()).thenReturn(activity); - return mock; - } - - protected void assertVisible(View view) { - assertThat(view.getVisibility()).isEqualTo(View.VISIBLE); - } - - protected void assertGone(View view) { - assertThat(view.getVisibility()).isEqualTo(View.GONE); - } - - protected void post(Runnable runnable) { - handler.post(runnable); - } - - protected void idleMainLooper() { - shadowMainLooper.idle(); - } -} diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.kt new file mode 100644 index 00000000000..d155fc8568c --- /dev/null +++ b/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.kt @@ -0,0 +1,194 @@ +package com.reactnativenavigation + +import android.app.Activity +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import android.os.Handler +import android.os.Looper +import android.view.View +import android.view.ViewGroup +import androidx.annotation.CallSuper +import androidx.appcompat.app.AppCompatActivity +import androidx.coordinatorlayout.widget.CoordinatorLayout +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags +import com.reactnativenavigation.options.params.Bool +import com.reactnativenavigation.utils.CollectionUtils +import com.reactnativenavigation.utils.Functions +import com.reactnativenavigation.utils.SystemUiUtils +import com.reactnativenavigation.utils.SystemUiUtils.getStatusBarHeight +import com.reactnativenavigation.utils.SystemUiUtils.getStatusBarHeightDp +import com.reactnativenavigation.utils.ViewUtils +import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import org.assertj.core.api.Java6Assertions +import org.junit.After +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers +import org.mockito.MockedStatic +import org.mockito.Mockito +import org.mockito.Mockito.mockStatic +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.Shadows +import org.robolectric.android.controller.ActivityController +import org.robolectric.annotation.Config +import org.robolectric.shadows.ShadowLooper +import java.util.Arrays + +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [28], application = TestApplication::class) +abstract class BaseTest { + private val handler = Handler(Looper.getMainLooper()) + private val shadowMainLooper: ShadowLooper = Shadows.shadowOf(Looper.getMainLooper()) + + protected lateinit var mockConfiguration: Configuration + + private var mockReactNativeFeatureFlags: MockedStatic? = null + + @Before + open fun beforeEach() { + mockReactNativeFeatureFlags = mockStatic(ReactNativeFeatureFlags::class.java) + + NavigationApplication.instance = Mockito.mock(NavigationApplication::class.java) + mockConfiguration = Mockito.mock(Configuration::class.java) + val res = Mockito.mock(Resources::class.java) + mockConfiguration.uiMode = Configuration.UI_MODE_NIGHT_NO + Mockito.`when`(res.configuration).thenReturn(mockConfiguration) + Mockito.`when`(NavigationApplication.instance.resources).thenReturn(res) + Mockito.`when`(res.getColor(ArgumentMatchers.anyInt())).thenReturn(0x00000) + Mockito.`when`(res.getColor(ArgumentMatchers.anyInt(), ArgumentMatchers.any())) + .thenReturn(0x00000) + } + + + fun mockSystemUiUtils( + statusBarHeight: Int, + statusBarHeightDp: Int, + mockedBlock: Functions.Func1?> + ) { + Mockito.mockStatic(SystemUiUtils::class.java).use { theMock -> + theMock.`when` { + getStatusBarHeight(ArgumentMatchers.any()) + }.thenReturn(statusBarHeight) + theMock.`when` { + getStatusBarHeightDp(ArgumentMatchers.any()) + }.thenReturn(statusBarHeightDp) + mockedBlock.run(theMock) + } + } + + @After + @CallSuper + fun afterEach() { + idleMainLooper() + mockReactNativeFeatureFlags?.close() + } + + fun newActivity(): Activity { + return Robolectric.setupActivity(AppCompatActivity::class.java) + } + + fun newActivityController(clazz: Class): ActivityController { + return Robolectric.buildActivity(clazz) + } + + fun assertIsChild(parent: ViewGroup?, vararg children: ViewController<*>?) { + CollectionUtils.forEach( + Arrays.asList(*children) + ) { c: ViewController<*> -> assertIsChild(parent, c.view) } + } + + fun assertIsChild(parent: ViewGroup?, child: View) { + Java6Assertions.assertThat(parent).isNotNull() + Java6Assertions.assertThat(child).isNotNull() + Java6Assertions.assertThat(ViewUtils.isChildOf(parent, child)).isTrue() + } + + fun assertNotChildOf(parent: ViewGroup?, vararg children: ViewController<*>?) { + CollectionUtils.forEach( + Arrays.asList(*children) + ) { c: ViewController<*> -> assertNotChildOf(parent, c.view) } + } + + fun assertNotChildOf(parent: ViewGroup?, child: View) { + Java6Assertions.assertThat(parent).isNotNull() + Java6Assertions.assertThat(child).isNotNull() + Java6Assertions.assertThat(ViewUtils.isChildOf(parent, child)).isFalse() + } + + fun assertMatchParent(view: View) { + Java6Assertions.assertThat(view.layoutParams.width) + .isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT) + Java6Assertions.assertThat(view.layoutParams.height) + .isEqualTo(ViewGroup.LayoutParams.MATCH_PARENT) + } + + protected fun disablePushAnimation(vararg controllers: ViewController<*>) { + for (controller in controllers) { + controller.options.animations.push.enabled = Bool(false) + } + } + + protected fun disablePopAnimation(vararg controllers: ViewController<*>) { + for (controller in controllers) { + controller.options.animations.pop.enabled = Bool(false) + } + } + + protected fun disableModalAnimations(vararg modals: ViewController<*>) { + disableShowModalAnimation(*modals) + disableDismissModalAnimation(*modals) + } + + protected fun disableShowModalAnimation(vararg modals: ViewController<*>) { + for (modal in modals) { + modal.options.animations.showModal.toggle(Bool(false)) + } + } + + protected fun disableDismissModalAnimation(vararg modals: ViewController<*>) { + for (modal in modals) { + modal.options.animations.dismissModal.toggle(Bool(false)) + } + } + + protected fun dispatchPreDraw(view: View) { + view.viewTreeObserver.dispatchOnPreDraw() + } + + protected fun dispatchOnGlobalLayout(view: View) { + view.viewTreeObserver.dispatchOnGlobalLayout() + } + + protected fun addToParent(context: Context, vararg controllers: ViewController<*>) { + for (controller in controllers) { + CoordinatorLayout(context).addView(controller.view) + } + } + + protected fun mockView(activity: Activity): View { + val mock = Mockito.mock(View::class.java) + Mockito.`when`(mock.context).thenReturn(activity) + return mock + } + + protected fun assertVisible(view: View) { + Java6Assertions.assertThat(view.visibility).isEqualTo(View.VISIBLE) + } + + protected fun assertGone(view: View) { + Java6Assertions.assertThat(view.visibility).isEqualTo(View.GONE) + } + + protected fun post(runnable: Runnable) { + handler.post(runnable) + } + + protected fun idleMainLooper() { + shadowMainLooper.idle() + } +} diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/TestApplication.java b/lib/android/app/src/test/java/com/reactnativenavigation/TestApplication.java index b8381dab3bb..854638cd40b 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/TestApplication.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/TestApplication.java @@ -1,10 +1,12 @@ package com.reactnativenavigation; -import android.app.*; +import android.app.Application; import com.facebook.react.ReactApplication; +import com.facebook.react.ReactHost; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; +import com.facebook.react.defaults.DefaultReactHost; import java.util.Collections; import java.util.List; @@ -33,4 +35,9 @@ public void onCreate() { public ReactNativeHost getReactNativeHost() { return host; } + + @Override + public ReactHost getReactHost() { + return DefaultReactHost.getDefaultReactHost(this, getReactNativeHost()); + } } diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestReactView.java b/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestReactView.java index c0347caa6c9..bcfe37d1dfe 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestReactView.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestReactView.java @@ -20,7 +20,7 @@ public TestReactView(@NonNull Context context) { } @Override - public void startReactApplication(ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle initialProperties, @Nullable String initialUITemplate) { + public void startReactApplication(ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle initialProperties) { } diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt index 9c70ff25aa0..abc19305509 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt @@ -536,7 +536,7 @@ class BottomTabsControllerTest : BaseTest() { Mockito.`when`(child5.handleBack(any())).thenReturn(true) } - private fun spyOnStack(initialChild: ViewController<*>?): StackController { + private fun spyOnStack(initialChild: ViewController<*>): StackController { val build = TestUtils.newStackController(activity) .setInitialOptions(tabOptions) .build() diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.java index c4cb666303c..7d708a549e6 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.java @@ -40,6 +40,7 @@ public abstract class AttachModeTest extends BaseTest { @Override public void beforeEach() { + super.beforeEach(); activity = newActivity(); childRegistry = new ChildControllersRegistry(); parent = new CoordinatorLayout(activity); diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java index 500a4136110..c1df91ab7ed 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java @@ -23,6 +23,7 @@ public class ChildControllerTest extends BaseTest { @Override public void beforeEach() { + super.beforeEach(); childRegistry = spy(new ChildControllersRegistry()); presenter = Mockito.mock(Presenter.class); uut = new SimpleViewController(newActivity(), childRegistry, "childId", presenter, new Options()) { diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java index 6ba7b2266ef..68f04f0d17d 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java @@ -20,6 +20,7 @@ public class ChildControllersRegistryTest extends BaseTest { @Override public void beforeEach() { + super.beforeEach(); Activity activity = newActivity(); uut = new ChildControllersRegistry(); child1 = spy(new SimpleViewController(activity, uut, "child1", new Options())); diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalAnimatorTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalAnimatorTest.kt index 8b01f725c5c..3bf2497b657 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalAnimatorTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalAnimatorTest.kt @@ -23,6 +23,7 @@ class ModalAnimatorTest : BaseTest() { private lateinit var mockDefaultAnimation: StackAnimationOptions private lateinit var screenAnimationListener: ScreenAnimationListener override fun beforeEach() { + super.beforeEach() val mockTransitionAnimatorCreator = spy(TransitionAnimatorCreator()) val childRegistry = mock() val enter = spy(AnimationOptions()) diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/RootPresenterTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/RootPresenterTest.kt index 8c9879bbd6a..455c8d39701 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/RootPresenterTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/RootPresenterTest.kt @@ -38,6 +38,7 @@ class RootPresenterTest : BaseTest() { private lateinit var root1View: SimpleViewController.SimpleView private lateinit var root2View: SimpleViewController.SimpleView override fun beforeEach() { + super.beforeEach() activityController = newActivityController(TestActivity::class.java) activity = activityController.create().get() reactInstanceManager = Mockito.mock(ReactInstanceManager::class.java) @@ -221,7 +222,7 @@ class RootPresenterTest : BaseTest() { fun setRoot_appliesLayoutDirection() { val listener = Mockito.spy(CommandListenerAdapter()) uut.setRoot(root, null, defaultOptions, listener, reactInstanceManager) - Mockito.verify(layoutDirectionApplier).apply(root, defaultOptions, reactInstanceManager) + Mockito.verify(layoutDirectionApplier).apply(root, defaultOptions) } private fun createAnimator(): RootAnimator { diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/BackButtonHelperTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/BackButtonHelperTest.java index 8642fcf0966..10661de40d1 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/BackButtonHelperTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/BackButtonHelperTest.java @@ -29,6 +29,7 @@ public class BackButtonHelperTest extends BaseTest { @Override public void beforeEach() { + super.beforeEach(); uut = new BackButtonHelper(); Activity activity = newActivity(); ChildControllersRegistry childRegistry = new ChildControllersRegistry(); diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt index ffbae17532d..d09ceb8571a 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt @@ -25,6 +25,7 @@ class StackAnimatorTest : BaseTest() { private lateinit var commandAnimator: AnimatorSet override fun beforeEach() { + super.beforeEach() activity = newActivity() val transitionAnimatorCreator = mock { } uut = object : StackAnimator(activity, transitionAnimatorCreator) { diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TitleBarButtonControllerTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TitleBarButtonControllerTest.java index 04835e54038..e83abb7ac4c 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TitleBarButtonControllerTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TitleBarButtonControllerTest.java @@ -24,6 +24,7 @@ public class TitleBarButtonControllerTest extends BaseTest { @Override public void beforeEach() { + super.beforeEach(); Activity activity = newActivity(); titleBar = new ButtonBar(activity); diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TitleBarReactViewControllerTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TitleBarReactViewControllerTest.java index 26de282b4e8..e81b9d01f01 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TitleBarReactViewControllerTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TitleBarReactViewControllerTest.java @@ -22,6 +22,7 @@ public class TitleBarReactViewControllerTest extends BaseTest { @Override public void beforeEach() { + super.beforeEach(); viewCreator = spy(new TitleBarReactViewCreatorMock()); activity = newActivity(); component = createComponent(); diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarButtonControllerTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarButtonControllerTest.java index e446922a358..29d4859cf06 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarButtonControllerTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarButtonControllerTest.java @@ -40,6 +40,7 @@ public class TopBarButtonControllerTest extends BaseTest { @Override public void beforeEach() { + super.beforeEach(); button = new ButtonOptions(); final Activity activity = newActivity(); diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt index a1ba14f1bea..8a7a6fc12bd 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt @@ -38,6 +38,7 @@ class TopBarControllerTest : BaseTest() { get() = uut.view override fun beforeEach() { + super.beforeEach() activity = newActivity() animator = spy(TopBarAnimator()) uut = createTopBarController() diff --git a/lib/ios/RNNAppDelegate.mm b/lib/ios/RNNAppDelegate.mm index d74a8613a03..55e52f422e0 100644 --- a/lib/ios/RNNAppDelegate.mm +++ b/lib/ios/RNNAppDelegate.mm @@ -2,8 +2,7 @@ #import #if RCT_NEW_ARCH_ENABLED -#import "RCTAppSetupUtils.h" -#import "RCTLegacyInteropComponents.h" + #import #import #import diff --git a/lib/src/adapters/NativeEventsReceiver.ts b/lib/src/adapters/NativeEventsReceiver.ts index 9cba874c013..d6ddfc5d5a4 100644 --- a/lib/src/adapters/NativeEventsReceiver.ts +++ b/lib/src/adapters/NativeEventsReceiver.ts @@ -23,14 +23,14 @@ export class NativeEventsReceiver { constructor() { try { this.emitter = new NativeEventEmitter(NativeModules.RNNEventEmitter); - } catch (e) { - this.emitter = ({ + } catch { + this.emitter = { addListener: () => { return { remove: () => undefined, }; }, - } as any) as NativeEventEmitter; + } as any as NativeEventEmitter; } } diff --git a/lib/src/adapters/TouchablePreview.tsx b/lib/src/adapters/TouchablePreview.tsx index fb2e743501d..e515ffd489f 100644 --- a/lib/src/adapters/TouchablePreview.tsx +++ b/lib/src/adapters/TouchablePreview.tsx @@ -22,8 +22,8 @@ interface GestureResponderEventWithForce extends NativeSyntheticEvent { const Touchable = Platform.OS === 'ios' && touchableComponent instanceof TouchableNativeFeedback ? TouchableWithoutFeedback - : (touchableComponent as typeof React.Component); + : (touchableComponent as React.Component); // Wrap component with Touchable for handling platform touches // and a single react View for detecting force and timing. diff --git a/lib/src/components/ComponentWrapper.test.tsx b/lib/src/components/ComponentWrapper.test.tsx index 748a5e71e9e..b4f8c0990cf 100644 --- a/lib/src/components/ComponentWrapper.test.tsx +++ b/lib/src/components/ComponentWrapper.test.tsx @@ -5,6 +5,7 @@ import { ComponentWrapper } from './ComponentWrapper'; import { Store } from './Store'; import { mock, verify, instance } from 'ts-mockito'; import { ComponentEventsObserver } from '../events/ComponentEventsObserver'; +import { ReactTestRendererJSON } from 'react-test-renderer'; describe('ComponentWrapper', () => { const componentName = 'example.MyComponent'; @@ -75,7 +76,7 @@ describe('ComponentWrapper', () => { ); expect(NavigationComponent).not.toBeInstanceOf(MyComponent); const tree = renderer.create(); - expect(tree.toJSON()!.children).toEqual(['Hello, World!']); + expect((tree.toJSON() as ReactTestRendererJSON).children).toEqual(['Hello, World!']); }); it('injects props from wrapper into original component', () => { @@ -89,7 +90,7 @@ describe('ComponentWrapper', () => { const tree = renderer.create( ); - expect(tree.toJSON()!.children).toEqual(['yo']); + expect((tree.toJSON() as ReactTestRendererJSON).children).toEqual(['yo']); expect(renderCount).toHaveBeenCalledTimes(1); }); @@ -243,11 +244,12 @@ describe('ComponentWrapper', () => { }); it('renders HOC components correctly', () => { - const generator = () => (props: any) => ( - - - - ); + const generator = () => (props: any) => + ( + + + + ); uut = new ComponentWrapper(); const NavigationComponent = uut.wrap(componentName, generator, store, componentEventsObserver); const tree = renderer.create(); @@ -309,7 +311,7 @@ describe('ComponentWrapper', () => { reduxStore ); const tree = renderer.create(); - expect(tree.toJSON()!.children).toEqual(['it just works']); + expect((tree.toJSON() as ReactTestRendererJSON).children).toEqual(['it just works']); expect((NavigationComponent as any).options()).toEqual({ foo: 123 }); }); }); diff --git a/lib/src/events/EventsRegistry.test.tsx b/lib/src/events/EventsRegistry.test.tsx index e2233fb8aff..87aeef00a00 100644 --- a/lib/src/events/EventsRegistry.test.tsx +++ b/lib/src/events/EventsRegistry.test.tsx @@ -19,9 +19,9 @@ describe('EventsRegistry', () => { it('exposes appLaunched event', () => { const subscription = {}; const cb = jest.fn(); - (mockNativeEventsReceiver.registerAppLaunchedListener as jest.MockedFunction< - any - >).mockReturnValueOnce(subscription); + ( + mockNativeEventsReceiver.registerAppLaunchedListener as jest.MockedFunction + ).mockReturnValueOnce(subscription); const result = uut.registerAppLaunchedListener(cb); diff --git a/package.json b/package.json index baa5f8d936e..f29dcb6943c 100644 --- a/package.json +++ b/package.json @@ -64,40 +64,43 @@ "hoist-non-react-statics": "3.x.x", "lodash": "4.17.x", "prop-types": "15.x.x", - "react-lifecycles-compat": "2.0.0", + "react-lifecycles-compat": "^3.0.4", "tslib": "1.9.3" }, "devDependencies": { - "@babel/core": "7.22.9", + "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "7.10.1", "@babel/plugin-proposal-export-namespace-from": "7.10.1", - "@babel/runtime": "7.22.6", - "@babel/types": "7.22.5", - "@babel/preset-env": "^7.22.9", - "@react-native/metro-config": "^0.73.2", - "@react-native/babel-preset": "^0.73.18", - "@react-native/typescript-config": "^0.73.1", - "@react-native-community/blur": "^4.4.1", - "@react-native-community/datetimepicker": "^3.4.7", - "@react-native-community/eslint-config": "2.0.0", - "@react-native-community/netinfo": "^5.9.4", + "@babel/preset-env": "^7.25.3", + "@babel/runtime": "^7.25.0", + "@babel/types": "7.25.0", + "@react-native-community/cli": "15.0.1", + "@react-native-community/cli-platform-android": "15.0.1", + "@react-native-community/cli-platform-ios": "15.0.1", + "@react-native-community/datetimepicker": "^8.2.0", + "@react-native-community/eslint-config": "3.2.0", + "@react-native-community/netinfo": "^11.4.1", + "@react-native/babel-preset": "0.77.0", + "@react-native/eslint-config": "0.77.0", + "@react-native/metro-config": "0.77.0", + "@react-native/typescript-config": "0.77.0", "@testing-library/jest-native": "^5.4.2", - "@testing-library/react-native": "^12.0.1", - "@types/hoist-non-react-statics": "^3.0.1", + "@testing-library/react-native": "^13.0.1", + "@types/hoist-non-react-statics": "^3.3.6", "@types/jasmine": "3.5.10", "@types/jest": "27.0.2", "@types/lodash": "^4.14.149", - "@types/react": "16.9.41", - "@types/react-native": "0.63.1", - "@types/react-test-renderer": "16.9.2", - "@typescript-eslint/eslint-plugin": "4.33.0", - "@typescript-eslint/parser": "4.33.0", + "@types/react": "^18.2.6", + "@types/react-test-renderer": "^18.0.0", + "@typescript-eslint/eslint-plugin": "8.21.0", + "@typescript-eslint/parser": "8.21.0", "babel-jest": "^27.0.0", "clang-format": "^1.4.0", - "detox": "20.19.5", + "detox": "20.32.0", "detox-testing-library-rnn-adapter": "^2.0.3", - "eslint": "7.32.0", + "eslint": "^8.19.0", "eslint-config-prettier": "6.11.0", + "eslint-formatter-codeframe": "^7.32.1", "eslint-plugin-prettier": "3.1.4", "github-release-notes": "https://github.com/yogevbd/github-release-notes/tarball/e601b3dba72dcd6cba323c1286ea6dd0c0110b58", "husky": "4.2.5", @@ -107,22 +110,22 @@ "metro-react-native-babel-preset": "^0.76.2", "pixelmatch": "^5.2.1", "pngjs": "^6.0.0", - "prettier": "2.1.2", - "react": "18.2.0", - "react-native": "0.73.3", + "prettier": "2.8.8", + "react": "18.3.1", + "react-native": "0.77.0", "react-native-fast-image": "^8.6.3", - "react-native-gesture-handler": "2.14.1", - "react-native-reanimated": "3.16.1", + "react-native-gesture-handler": "^2.22.1", + "react-native-reanimated": "3.16.7", "react-native-ui-lib": "7.3.6", "react-redux": "5.x.x", - "react-test-renderer": "18.2.0", + "react-test-renderer": "18.3.1", "redux": "3.x.x", "remx": "3.x.x", "semver": "5.x.x", "shell-utils": "1.x.x", "ts-mockito": "^2.3.1", "typedoc": "0.x.x", - "typescript": "5.5.4" + "typescript": "5.0.4" }, "husky": { "hooks": { @@ -168,7 +171,7 @@ "emulator": { "type": "android.emulator", "device": { - "avdName": "Pixel_API_28" + "avdName": "Pixel_3a_API_34" } } }, @@ -188,7 +191,10 @@ "type": "android.apk", "binaryPath": "playground/android/app/build/outputs/apk/debug/app-debug.apk", "start": "npm start -- --e2e", - "build": "cd playground/android && ./gradlew app:assembleDebug app:assembleAndroidTest -DtestBuildType=debug" + "build": "cd playground/android && ./gradlew app:assembleDebug app:assembleAndroidTest -DtestBuildType=debug", + "reversePorts": [ + 8081 + ] }, "android.release": { "type": "android.apk", diff --git a/playground/android/app/build.gradle b/playground/android/app/build.gradle index 8624bb3cc60..0382536bb1b 100644 --- a/playground/android/app/build.gradle +++ b/playground/android/app/build.gradle @@ -5,6 +5,7 @@ react { root = file("../../../") reactNativeDir = file("../../../node_modules/react-native") codegenDir = file("../../../node_modules/@react-native/codegen") + autolinkLibrariesWithApp() } @@ -22,7 +23,7 @@ android { defaultConfig { applicationId "com.reactnativenavigation.playground" - minSdkVersion 21 + minSdkVersion rootProject.ext.get("minSdkVersion") targetSdkVersion rootProject.ext.get("targetSdkVersion") versionCode 1 versionName "1.0" @@ -49,8 +50,8 @@ android { } dependencies { - implementation 'com.google.android.material:material:1.4.0' - implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.12.0' + implementation 'androidx.appcompat:appcompat:1.7.0' implementation("com.facebook.react:react-android") @@ -61,15 +62,10 @@ dependencies { androidTestImplementation('com.wix:detox:+') { transitive = true } androidTestImplementation 'junit:junit:4.12' - if (hermesEnabled.toBoolean()) { + if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-android") - } else { - implementation jscFlavor - } - - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") - debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { - exclude group:'com.squareup.okhttp3', module:'okhttp' + } else { + implementation jscFlavor } } @@ -77,6 +73,3 @@ task copyDownloadableDepsToLibs(type: Copy) { from configurations.implementation into 'libs' } - -apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle") -applyNativeModulesAppBuildGradle(project) diff --git a/playground/android/app/src/main/java/com/reactnativenavigation/playground/MainApplication.java b/playground/android/app/src/main/java/com/reactnativenavigation/playground/MainApplication.java index 17497847a8b..f3ed98c6807 100644 --- a/playground/android/app/src/main/java/com/reactnativenavigation/playground/MainApplication.java +++ b/playground/android/app/src/main/java/com/reactnativenavigation/playground/MainApplication.java @@ -1,17 +1,15 @@ package com.reactnativenavigation.playground; -import android.content.Context; - import com.facebook.react.PackageList; -import com.facebook.react.ReactInstanceManager; +import com.facebook.react.ReactHost; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactHost; import com.reactnativenavigation.NavigationApplication; import com.reactnativenavigation.react.NavigationPackage; import com.reactnativenavigation.react.NavigationReactNativeHost; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; @@ -56,7 +54,6 @@ public void onCreate() { // If you opted-in for the New Architecture, we load the native entry point for this app. DefaultNewArchitectureEntryPoint.load(); } - initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); } @Override @@ -64,23 +61,8 @@ public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } - private static void initializeFlipper( - Context context, ReactInstanceManager reactInstanceManager) { - if (BuildConfig.DEBUG) { - try { - Class aClass = Class.forName("com.example.ReactNativeFlipper"); - aClass - .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) - .invoke(null, context, reactInstanceManager); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } + @Override + public ReactHost getReactHost() { + return DefaultReactHost.getDefaultReactHost(this, getReactNativeHost()); } } diff --git a/playground/android/build.gradle b/playground/android/build.gradle index 809412b1917..5a22330b745 100644 --- a/playground/android/build.gradle +++ b/playground/android/build.gradle @@ -2,15 +2,15 @@ buildscript { ext { - kotlinVersion = "1.8.10" + kotlinVersion = "2.0.21" RNNKotlinVersion = kotlinVersion detoxKotlinVersion = kotlinVersion - compileSdkVersion = 34 - buildToolsVersion = "34.0.0" - minSdkVersion = 21 - targetSdkVersion = 34 + compileSdkVersion = 35 + buildToolsVersion = "35.0.0" + minSdkVersion = 24 + targetSdkVersion = 35 // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. - ndkVersion = "23.1.7779620" + ndkVersion = "27.1.12297006" } repositories { diff --git a/playground/android/gradle.properties b/playground/android/gradle.properties index 3fb0cc5c8d0..a3d21529729 100644 --- a/playground/android/gradle.properties +++ b/playground/android/gradle.properties @@ -19,7 +19,6 @@ org.gradle.jvmargs=-Xmx2048m # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true android.useAndroidX=true -android.enableJetifier=true android.jetifier.ignorelist=bcprov hermesEnabled=true newArchEnabled=false diff --git a/playground/android/gradle/wrapper/gradle-wrapper.properties b/playground/android/gradle/wrapper/gradle-wrapper.properties index 5fe713fe642..c9faf848d3d 100644 --- a/playground/android/gradle/wrapper/gradle-wrapper.properties +++ b/playground/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Thu Jul 28 13:48:47 IDT 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/playground/android/settings.gradle b/playground/android/settings.gradle index 19af8ce1cec..2d808997909 100644 --- a/playground/android/settings.gradle +++ b/playground/android/settings.gradle @@ -1,6 +1,7 @@ +pluginManagement { includeBuild("../../node_modules/@react-native/gradle-plugin") } +plugins { id("com.facebook.react.settings") } +extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } rootProject.name = 'Playground' -apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle") -applyNativeModulesSettingsGradle(settings) include ':app' include ':react-native-navigation' project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../../lib/android/app/') diff --git a/playground/ios/Podfile b/playground/ios/Podfile index 90ea17f306d..1a972b8579d 100644 --- a/playground/ios/Podfile +++ b/playground/ios/Podfile @@ -7,8 +7,6 @@ require Pod::Executable.execute_command('node', ['-p', platform :ios, min_ios_version_supported prepare_react_native_project! -flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled - linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green @@ -25,7 +23,6 @@ def all_pods :path => "../../node_modules/react-native", :hermes_enabled => flags[:hermes_enabled], :fabric_enabled => flags[:fabric_enabled], - :flipper_configuration => FlipperConfiguration.enabled, # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/../.." ) @@ -35,41 +32,7 @@ def all_pods end post_install do |installer| - __apply_Xcode_15_3_flipper_post_install_workaround(installer) - react_native_post_install(installer, "../../node_modules/react-native", :mac_catalyst_enabled => false) - - __apply_Xcode_15_unary_binary_error_workaround(installer) - - # This is to resolve "'shared_timed_mutex' is unavailable: introduced in iOS 10.0" error - installer.pods_project.targets.each do |t| - t.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.4' - end - end -end - -def __apply_Xcode_15_3_flipper_post_install_workaround(installer) - installer.pods_project.targets.each do |target| - if target.name == 'Flipper' - file_path = 'Pods/Flipper/xplat/Flipper/FlipperTransportTypes.h' - contents = File.read(file_path) - unless contents.include?('#include ') - File.open(file_path, 'w') do |file| - file.puts('#include ') - file.puts(contents) - end - end - end - end -end - -def __apply_Xcode_15_unary_binary_error_workaround(installer) - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', '_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION'] - end - end end target 'playground' do diff --git a/playground/ios/PrivacyInfo.xcprivacy b/playground/ios/PrivacyInfo.xcprivacy new file mode 100644 index 00000000000..41b8317f065 --- /dev/null +++ b/playground/ios/PrivacyInfo.xcprivacy @@ -0,0 +1,37 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/playground/ios/playground.xcodeproj/project.pbxproj b/playground/ios/playground.xcodeproj/project.pbxproj index 195a51e534b..a675762cc93 100644 --- a/playground/ios/playground.xcodeproj/project.pbxproj +++ b/playground/ios/playground.xcodeproj/project.pbxproj @@ -79,6 +79,7 @@ E58D265F2385888C003F36BA /* RNNBasePresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E58D26422385888C003F36BA /* RNNBasePresenterTest.m */; }; E58D26602385888C003F36BA /* RNNModalManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E58D26432385888C003F36BA /* RNNModalManagerTest.m */; }; E58D26612385888C003F36BA /* RNNTestNoColor.m in Sources */ = {isa = PBXBuildFile; fileRef = E58D26452385888C003F36BA /* RNNTestNoColor.m */; }; + F37104B81B0A0360736BF06D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 323095228F740613FD9372D1 /* PrivacyInfo.xcprivacy */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -113,6 +114,7 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 18EFC85255DC04E4B557855F /* libPods-NavigationTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NavigationTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 323095228F740613FD9372D1 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = ../PrivacyInfo.xcprivacy; sourceTree = ""; }; 33BE713009EFB937EA4BF877 /* libPods-playground.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-playground.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 4259AF43A23D928FE78B4A3A /* Pods-NavigationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NavigationTests.debug.xcconfig"; path = "Target Support Files/Pods-NavigationTests/Pods-NavigationTests.debug.xcconfig"; sourceTree = ""; }; 4AE37ACF6BFBAB211EE8E7E9 /* Pods-NavigationIOS12Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NavigationIOS12Tests.release.xcconfig"; path = "Target Support Files/Pods-NavigationIOS12Tests/Pods-NavigationIOS12Tests.release.xcconfig"; sourceTree = ""; }; @@ -260,6 +262,7 @@ 13B07FB61A68108700A75B9A /* Info.plist */, 9F9A3A9525260DA900AAAF37 /* LaunchScreen.storyboard */, 13B07FB71A68108700A75B9A /* main.m */, + 323095228F740613FD9372D1 /* PrivacyInfo.xcprivacy */, ); path = playground; sourceTree = ""; @@ -606,6 +609,7 @@ files = ( 9F9A3A9625260DA900AAAF37 /* LaunchScreen.storyboard in Resources */, 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + F37104B81B0A0360736BF06D /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -677,16 +681,10 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-playground/Pods-playground-frameworks.sh", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; @@ -701,11 +699,19 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-playground/Pods-playground-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -763,16 +769,10 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-NavigationIOS12Tests/Pods-NavigationIOS12Tests-frameworks.sh", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; @@ -787,11 +787,19 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-NavigationTests/Pods-NavigationTests-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -805,16 +813,10 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-NavigationTests/Pods-NavigationTests-frameworks.sh", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; @@ -829,11 +831,19 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-SnapshotTests/Pods-SnapshotTests-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -869,16 +879,10 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-SnapshotTests/Pods-SnapshotTests-frameworks.sh", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); runOnlyForDeploymentPostprocessing = 0; @@ -893,11 +897,19 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-NavigationIOS12Tests/Pods-NavigationIOS12Tests-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1493,12 +1505,10 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native"; SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; USE_HERMES = true; }; name = Debug; @@ -1554,10 +1564,7 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; diff --git a/playground/src/components/PressableScale.tsx b/playground/src/components/PressableScale.tsx index a13adc5d394..5247ee1debe 100644 --- a/playground/src/components/PressableScale.tsx +++ b/playground/src/components/PressableScale.tsx @@ -24,9 +24,8 @@ export interface PressableScaleProps weight?: 'light' | 'medium' | 'heavy'; } -const ReanimatedTouchableWithoutFeedback = Reanimated.createAnimatedComponent( - TouchableWithoutFeedback -); +const ReanimatedTouchableWithoutFeedback = + Reanimated.createAnimatedComponent(TouchableWithoutFeedback); /** * A Pressable that scales down when pressed. Uses the JS Pressability API. diff --git a/playground/src/screens/OrientationScreen.tsx b/playground/src/screens/OrientationScreen.tsx index 70575377ca1..6a066d40004 100644 --- a/playground/src/screens/OrientationScreen.tsx +++ b/playground/src/screens/OrientationScreen.tsx @@ -5,11 +5,8 @@ import Button from '../components/Button'; import Screens from './Screens'; import testIDs from '../testIDs'; -const { - LANDSCAPE_PORTRAIT_ORIENTATION_BTN, - LANDSCAPE_ORIENTATION_BTN, - PORTRAIT_ORIENTATION_BTN, -} = testIDs; +const { LANDSCAPE_PORTRAIT_ORIENTATION_BTN, LANDSCAPE_ORIENTATION_BTN, PORTRAIT_ORIENTATION_BTN } = + testIDs; export default class OrientationScreen extends React.Component { render() { diff --git a/playground/src/screens/OverlayAlert.tsx b/playground/src/screens/OverlayAlert.tsx index a3ffcce8fe8..b1727d479f9 100644 --- a/playground/src/screens/OverlayAlert.tsx +++ b/playground/src/screens/OverlayAlert.tsx @@ -5,12 +5,8 @@ import { component } from '../commons/Layouts'; import Screens from './Screens'; import testIDs from '../testIDs'; -const { - OVERLAY_ALERT_HEADER, - DISMISS_BTN, - SET_INTERCEPT_TOUCH, - DISMISS_ALL_OVERLAYS_BUTTON, -} = testIDs; +const { OVERLAY_ALERT_HEADER, DISMISS_BTN, SET_INTERCEPT_TOUCH, DISMISS_ALL_OVERLAYS_BUTTON } = + testIDs; interface Props extends NavigationProps { incrementDismissedOverlays: any; diff --git a/playground/src/screens/PushedScreen.tsx b/playground/src/screens/PushedScreen.tsx index 96b51e9be00..b2d15b47bc0 100644 --- a/playground/src/screens/PushedScreen.tsx +++ b/playground/src/screens/PushedScreen.tsx @@ -12,6 +12,7 @@ import Root from '../components/Root'; import Navigation from '../services/Navigation'; import testIDs from '../testIDs'; import Screens from './Screens'; +import { NativeEventSubscription } from 'react-native/Libraries/EventEmitter/RCTNativeAppEventEmitter'; const { PUSHED_SCREEN_HEADER, @@ -37,6 +38,8 @@ interface Props extends NavigationProps { } export default class PushedScreen extends NavigationComponent { + backHandlerSubscription: NativeEventSubscription | null = null; + static options(): Options { return { topBar: { @@ -220,9 +223,14 @@ export default class PushedScreen extends NavigationComponent { }, ]); - addBackHandler = () => BackHandler.addEventListener('hardwareBackPress', this.backHandler); + addBackHandler = () => { + this.backHandlerSubscription = BackHandler.addEventListener( + 'hardwareBackPress', + this.backHandler + ); + }; - removeBackHandler = () => BackHandler.removeEventListener('hardwareBackPress', this.backHandler); + removeBackHandler = () => this.backHandlerSubscription?.remove(); backHandler = () => { this.setState({ diff --git a/playground/src/screens/SearchBar.tsx b/playground/src/screens/SearchBar.tsx index 32d170a1fe5..5ffc88e9f8c 100644 --- a/playground/src/screens/SearchBar.tsx +++ b/playground/src/screens/SearchBar.tsx @@ -6,13 +6,8 @@ import Button from '../components/Button'; import Navigation from '../services/Navigation'; import testIDs from '../testIDs'; -const { - HIDE_TOP_BAR_BTN, - SHOW_TOP_BAR_BTN, - SHOW_SEARCH_BAR_BTN, - HIDE_SEARCH_BAR_BTN, - TOP_BAR, -} = testIDs; +const { HIDE_TOP_BAR_BTN, SHOW_TOP_BAR_BTN, SHOW_SEARCH_BAR_BTN, HIDE_SEARCH_BAR_BTN, TOP_BAR } = + testIDs; interface Props extends NavigationProps {} diff --git a/playground/src/screens/StackCommandsScreen.tsx b/playground/src/screens/StackCommandsScreen.tsx index f6928655cb7..e8b0f26bc0e 100644 --- a/playground/src/screens/StackCommandsScreen.tsx +++ b/playground/src/screens/StackCommandsScreen.tsx @@ -42,9 +42,7 @@ export default class StackCommandsScreen extends NavigationComponent new Promise((resolve) => setTimeout(() => resolve(pushId), 100)) - ) + .then((pushId) => new Promise((resolve) => setTimeout(() => resolve(pushId), 100))) .then((pushId) => { this.setState({ pushPromiseResult: `push promise resolved with: ${pushId}`, diff --git a/playground/src/screens/index.tsx b/playground/src/screens/index.tsx index 0d9a4a6a43c..8c02aa71121 100644 --- a/playground/src/screens/index.tsx +++ b/playground/src/screens/index.tsx @@ -128,11 +128,12 @@ function registerScreens() { const ContextScreen = require('./ContextScreen').default; Navigation.registerComponent( Screens.ContextScreen, - () => (props) => ( - - - - ), + () => (props) => + ( + + + + ), () => ContextScreen ); diff --git a/playground/src/screens/sharedElementCarDealer/CarCard.tsx b/playground/src/screens/sharedElementCarDealer/CarCard.tsx index 5457f844553..8f0660886c4 100644 --- a/playground/src/screens/sharedElementCarDealer/CarCard.tsx +++ b/playground/src/screens/sharedElementCarDealer/CarCard.tsx @@ -1,4 +1,3 @@ -import { BlurView } from '@react-native-community/blur'; import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import { StyleSheet, Text, Dimensions, ViewProps, Platform } from 'react-native'; import Reanimated, { EasingNode, useValue } from 'react-native-reanimated'; @@ -77,7 +76,6 @@ export default function CarCard({ resizeMode="cover" /> - {Platform.OS === 'ios' && } -