From e5cc35260a694590eade281029be02fdef9ac783 Mon Sep 17 00:00:00 2001 From: sarthak-d11 Date: Sun, 20 Oct 2024 00:39:48 +0530 Subject: [PATCH 1/6] feat: new arch on android not working --- ...abViewViewManager.kt => RCTTabViewImpl.kt} | 87 +++++------------- .../java/com/rcttabview/RCTTabViewPackage.kt | 2 +- .../java/com/rcttabview/TabViewShadowNode.kt | 43 +++++++++ android/src/newarch/EventDispatcherWrapper.kt | 13 +++ android/src/newarch/RCTTabViewManager.kt | 86 ++++++++++++++++++ android/src/newarch/RCTTabViewViewManager.kt | 21 ----- android/src/oldarch/EventDispatcherWrapper.kt | 14 +++ android/src/oldarch/RCTTabViewManager.kt | 88 +++++++++++++++++++ example/android/gradle.properties | 2 +- 9 files changed, 268 insertions(+), 88 deletions(-) rename android/src/main/java/com/rcttabview/{RCTTabViewViewManager.kt => RCTTabViewImpl.kt} (52%) create mode 100644 android/src/main/java/com/rcttabview/TabViewShadowNode.kt create mode 100644 android/src/newarch/EventDispatcherWrapper.kt create mode 100644 android/src/newarch/RCTTabViewManager.kt delete mode 100644 android/src/newarch/RCTTabViewViewManager.kt create mode 100644 android/src/oldarch/EventDispatcherWrapper.kt create mode 100644 android/src/oldarch/RCTTabViewManager.kt diff --git a/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt b/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt similarity index 52% rename from android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt rename to android/src/main/java/com/rcttabview/RCTTabViewImpl.kt index df52033f..3fad1ee8 100644 --- a/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt +++ b/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt @@ -1,14 +1,13 @@ package com.rcttabview import android.content.res.ColorStateList -import android.graphics.Color +import android.util.Log import android.view.View.MeasureSpec import com.facebook.react.bridge.ReadableArray import com.facebook.react.common.MapBuilder -import com.facebook.react.module.annotations.ReactModule import com.facebook.react.uimanager.LayoutShadowNode -import com.facebook.react.uimanager.SimpleViewManager import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.UIManagerModule import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.uimanager.events.EventDispatcher @@ -24,16 +23,14 @@ data class TabInfo( val badge: String ) -@ReactModule(name = RCTTabViewViewManager.NAME) -class RCTTabViewViewManager : - SimpleViewManager() { - private lateinit var eventDispatcher: EventDispatcher +class RCTTabViewImpl { - override fun getName(): String { + private lateinit var eventDispatcher: EventDispatcherWrapper + private var tabView: ReactBottomNavigationView? = null + fun getName(): String { return NAME } - @ReactProp(name = "items") fun setItems(view: ReactBottomNavigationView, items: ReadableArray) { val itemsArray = mutableListOf() for (i in 0 until items.size()) { @@ -50,7 +47,7 @@ class RCTTabViewViewManager : view.updateItems(itemsArray) } - @ReactProp(name = "selectedPage") + fun setSelectedPage(view: ReactBottomNavigationView, key: String) { view.items?.indexOfFirst { it.key == key }?.let { view.selectedItemId = it @@ -58,17 +55,16 @@ class RCTTabViewViewManager : } - @ReactProp(name = "labeled") fun setLabeled(view: ReactBottomNavigationView, flag: Boolean?) { view.setLabeled(flag) } - @ReactProp(name = "icons") + fun setIcons(view: ReactBottomNavigationView, icons: ReadableArray?) { view.setIcons(icons) } - @ReactProp(name = "rippleColor") + fun setRippleColor(view: ReactBottomNavigationView, rippleColor: Int?) { if (rippleColor != null) { val color = ColorStateList.valueOf(rippleColor) @@ -76,10 +72,11 @@ class RCTTabViewViewManager : } } - public override fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { - eventDispatcher = context.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher + fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { val view = ReactBottomNavigationView(context) - view.onTabSelectedListener = { data -> + tabView = view + eventDispatcher = EventDispatcherWrapper(context) + view?.onTabSelectedListener = { data -> data.getString("key")?.let { eventDispatcher.dispatchEvent(PageSelectedEvent(viewTag = view.id, key = it)) } @@ -87,69 +84,29 @@ class RCTTabViewViewManager : return view } - - class TabViewShadowNode() : LayoutShadowNode(), - YogaMeasureFunction { - private var mWidth = 0 - private var mHeight = 0 - private var mMeasured = false - - init { - initMeasureFunction() - } - - private fun initMeasureFunction() { - setMeasureFunction(this) - } - - override fun measure( - node: YogaNode, - width: Float, - widthMode: YogaMeasureMode, - height: Float, - heightMode: YogaMeasureMode - ): Long { - if (mMeasured) { - return YogaMeasureOutput.make(mWidth, mHeight) - } - - val tabView = ReactBottomNavigationView(themedContext) - val spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) - tabView.measure(spec, spec) - this.mWidth = tabView.measuredWidth - this.mHeight = tabView.measuredHeight - this.mMeasured = true - - return YogaMeasureOutput.make(mWidth, mHeight) - } - } - - override fun createShadowNodeInstance(): LayoutShadowNode { - return TabViewShadowNode() + fun getViewInstance(): ReactBottomNavigationView? { + return if(tabView!=null) + tabView + else + null } companion object { const val NAME = "RCTTabView" } + // iOS Props - override fun getExportedCustomDirectEventTypeConstants(): MutableMap? { - return MapBuilder.of( - PageSelectedEvent.EVENT_NAME, - MapBuilder.of("registrationName", "onPageSelected"), - ) + fun setSidebarAdaptable(view: ReactBottomNavigationView, flag: Boolean) { } - // iOS Props + fun setScrollEdgeAppearance(view: ReactBottomNavigationView, value: String) { - @ReactProp(name = "sidebarAdaptable") - fun setSidebarAdaptable(view: ReactBottomNavigationView, flag: Boolean) { } - @ReactProp(name = "ignoresTopSafeArea") fun setIgnoresTopSafeArea(view: ReactBottomNavigationView, flag: Boolean) { } - @ReactProp(name = "disablePageAnimations") + fun setDisablePageAnimations(view: ReactBottomNavigationView, flag: Boolean) { } } diff --git a/android/src/main/java/com/rcttabview/RCTTabViewPackage.kt b/android/src/main/java/com/rcttabview/RCTTabViewPackage.kt index f3a2062a..54492e1b 100644 --- a/android/src/main/java/com/rcttabview/RCTTabViewPackage.kt +++ b/android/src/main/java/com/rcttabview/RCTTabViewPackage.kt @@ -9,7 +9,7 @@ import java.util.ArrayList class RCTTabViewPackage : ReactPackage { override fun createViewManagers(reactContext: ReactApplicationContext): List> { val viewManagers: MutableList> = ArrayList() - viewManagers.add(RCTTabViewViewManager()) + viewManagers.add(RCTTabViewManager(reactContext)) return viewManagers } diff --git a/android/src/main/java/com/rcttabview/TabViewShadowNode.kt b/android/src/main/java/com/rcttabview/TabViewShadowNode.kt new file mode 100644 index 00000000..e27773c2 --- /dev/null +++ b/android/src/main/java/com/rcttabview/TabViewShadowNode.kt @@ -0,0 +1,43 @@ +package com.rcttabview + +import android.view.View.MeasureSpec +import com.facebook.react.uimanager.LayoutShadowNode +import com.facebook.yoga.YogaMeasureFunction +import com.facebook.yoga.YogaMeasureMode +import com.facebook.yoga.YogaMeasureOutput +import com.facebook.yoga.YogaNode + +class TabViewShadowNode(tabview: ReactBottomNavigationView?) : LayoutShadowNode(), + YogaMeasureFunction { + private var mWidth = 0 + private var mHeight = 0 + private var mMeasured = false + private var mTabView = tabview + init { + initMeasureFunction() + } + + private fun initMeasureFunction() { + setMeasureFunction(this) + } + + override fun measure( + node: YogaNode, + width: Float, + widthMode: YogaMeasureMode, + height: Float, + heightMode: YogaMeasureMode + ): Long { + if (mMeasured) { + return YogaMeasureOutput.make(mWidth, mHeight) + } + val tempTabView = mTabView?: ReactBottomNavigationView(themedContext) + val spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) + tempTabView.measure(spec, spec) + this.mWidth = tempTabView.measuredWidth + this.mHeight = tempTabView.measuredHeight + this.mMeasured = true + + return YogaMeasureOutput.make(mWidth, mHeight) + } +} diff --git a/android/src/newarch/EventDispatcherWrapper.kt b/android/src/newarch/EventDispatcherWrapper.kt new file mode 100644 index 00000000..8295931f --- /dev/null +++ b/android/src/newarch/EventDispatcherWrapper.kt @@ -0,0 +1,13 @@ +package com.rcttabview + +import com.facebook.react.bridge.ReactContext +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.events.Event +import com.facebook.react.uimanager.events.EventDispatcher + +class EventDispatcherWrapper(context: ReactContext) { + var context: ReactContext = context + fun dispatchEvent(event: Event) { + UIManagerHelper.getEventDispatcherForReactTag(context, event.viewTag)?.dispatchEvent(event) + } +} diff --git a/android/src/newarch/RCTTabViewManager.kt b/android/src/newarch/RCTTabViewManager.kt new file mode 100644 index 00000000..c4f1d6d7 --- /dev/null +++ b/android/src/newarch/RCTTabViewManager.kt @@ -0,0 +1,86 @@ +package com.rcttabview + +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.common.MapBuilder +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.LayoutShadowNode +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.ViewManagerDelegate +import com.facebook.react.viewmanagers.TabViewManagerDelegate +import com.facebook.react.viewmanagers.TabViewManagerInterface + +@ReactModule(name = RCTTabViewManager.NAME) +class RCTTabViewManager(context: ReactApplicationContext) : + SimpleViewManager(), + TabViewManagerInterface { + private val context: ReactApplicationContext = context + private val delegate: TabViewManagerDelegate = + TabViewManagerDelegate(this) + private val tabViewImpl: RCTTabViewImpl = RCTTabViewImpl() + companion object { + const val NAME = "RCTTabView" + } + override fun getDelegate(): ViewManagerDelegate? { + return delegate + } + + override fun createViewInstance(p0: ThemedReactContext): ReactBottomNavigationView { + return tabViewImpl.createViewInstance(p0) + } + + override fun getName(): String { + return tabViewImpl.getName() + } + + override fun setItems(view: ReactBottomNavigationView?, value: ReadableArray?) { + if (view != null && value != null) + tabViewImpl.setItems(view, value) + } + + override fun setSelectedPage(view: ReactBottomNavigationView?, value: String?) { + if (view != null && value != null) + tabViewImpl.setSelectedPage(view, value) + } + + override fun setIcons(view: ReactBottomNavigationView?, value: ReadableArray?) { + if (view != null && value != null) + tabViewImpl.setIcons(view, value) + } + + override fun setLabeled(view: ReactBottomNavigationView?, value: Boolean) { + if (view != null && value != null) + tabViewImpl.setLabeled(view, value) + } + + override fun setSidebarAdaptable(view: ReactBottomNavigationView?, value: Boolean) { + if (view != null && value != null) + tabViewImpl.setSidebarAdaptable(view, value) + } + + override fun setScrollEdgeAppearance(view: ReactBottomNavigationView?, value: String?) { + if (view != null && value != null) + tabViewImpl.setScrollEdgeAppearance(view, value) + } + + override fun setRippleColor(view: ReactBottomNavigationView?, value: Int?) { + if (view != null && value != null) + tabViewImpl.setRippleColor(view, value) + } + + override fun createShadowNodeInstance(context: ReactApplicationContext): LayoutShadowNode { + return TabViewShadowNode(tabViewImpl.getViewInstance()) + } + override fun getExportedCustomDirectEventTypeConstants(): MutableMap? { + return MapBuilder.of( + PageSelectedEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onPageSelected"), + ) + } + + override fun addEventEmitters(reactContext: ThemedReactContext, view: ReactBottomNavigationView) { + super.addEventEmitters(reactContext, view) + } + +} diff --git a/android/src/newarch/RCTTabViewViewManager.kt b/android/src/newarch/RCTTabViewViewManager.kt deleted file mode 100644 index ecad49be..00000000 --- a/android/src/newarch/RCTTabViewViewManager.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.rcttabview - -import android.view.View - -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.uimanager.SimpleViewManager -import com.facebook.react.uimanager.ViewManagerDelegate -import com.facebook.react.viewmanagers.SwiftuiTabviewViewManagerDelegate -import com.facebook.react.viewmanagers.SwiftuiTabviewViewManagerInterface - -abstract class RCTTabViewViewManagerSpec : SimpleViewManager(), SwiftuiTabviewViewManagerInterface { - private val mDelegate: ViewManagerDelegate - - init { - mDelegate = SwiftuiTabviewViewManagerDelegate(this) - } - - override fun getDelegate(): ViewManagerDelegate? { - return mDelegate - } -} diff --git a/android/src/oldarch/EventDispatcherWrapper.kt b/android/src/oldarch/EventDispatcherWrapper.kt new file mode 100644 index 00000000..72421037 --- /dev/null +++ b/android/src/oldarch/EventDispatcherWrapper.kt @@ -0,0 +1,14 @@ +package com.rcttabview + +import com.facebook.react.bridge.ReactContext +import com.facebook.react.uimanager.UIManagerModule +import com.facebook.react.uimanager.events.Event +import com.facebook.react.uimanager.events.EventDispatcher + +class EventDispatcherWrapper(context: ReactContext) { + var eventDispatcher:EventDispatcher = context.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher + + fun dispatchEvent(event: Event){ + eventDispatcher.dispatchEvent(event) + } +} diff --git a/android/src/oldarch/RCTTabViewManager.kt b/android/src/oldarch/RCTTabViewManager.kt new file mode 100644 index 00000000..f700a0e2 --- /dev/null +++ b/android/src/oldarch/RCTTabViewManager.kt @@ -0,0 +1,88 @@ +package com.rcttabview + +import android.content.res.ColorStateList +import android.view.View.MeasureSpec +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.common.MapBuilder +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.LayoutShadowNode +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.UIManagerModule +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.uimanager.events.EventDispatcher +import com.facebook.yoga.YogaMeasureFunction +import com.facebook.yoga.YogaMeasureMode +import com.facebook.yoga.YogaMeasureOutput +import com.facebook.yoga.YogaNode +import com.facebook.react.bridge.ReactApplicationContext + + + +class RCTTabViewManager(context: ReactApplicationContext) : + SimpleViewManager() { + private lateinit var eventDispatcher: EventDispatcher + private var tabViewImpl = RCTTabViewImpl() + override fun getName(): String { + return NAME + } + + @ReactProp(name = "items") + fun setItems(view: ReactBottomNavigationView, items: ReadableArray) { + tabViewImpl.setItems(view, items) + } + + @ReactProp(name = "selectedPage") + fun setSelectedPage(view: ReactBottomNavigationView, key: String) { + tabViewImpl.setSelectedPage(view, key) + } + + + @ReactProp(name = "labeled") + fun setLabeled(view: ReactBottomNavigationView, flag: Boolean?) { + tabViewImpl.setLabeled(view, flag) + } + + @ReactProp(name = "icons") + fun setIcons(view: ReactBottomNavigationView, icons: ReadableArray?) { + tabViewImpl.setIcons(view, icons) + } + + @ReactProp(name = "rippleColor") + fun setRippleColor(view: ReactBottomNavigationView, rippleColor: Int?) { + tabViewImpl.setRippleColor(view, rippleColor) + } + + public override fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { + return tabViewImpl.createViewInstance(context) + } + + override fun createShadowNodeInstance(): LayoutShadowNode { + return TabViewShadowNode(tabViewImpl.getViewInstance()) + } + + companion object { + const val NAME = "RCTTabView" + } + + override fun getExportedCustomDirectEventTypeConstants(): MutableMap? { + return MapBuilder.of( + PageSelectedEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onPageSelected"), + ) + } + + // iOS Props + + @ReactProp(name = "sidebarAdaptable") + fun setSidebarAdaptable(view: ReactBottomNavigationView, flag: Boolean) { + } + + @ReactProp(name = "ignoresTopSafeArea") + fun setIgnoresTopSafeArea(view: ReactBottomNavigationView, flag: Boolean) { + } + + @ReactProp(name = "disablePageAnimations") + fun setDisablePageAnimations(view: ReactBottomNavigationView, flag: Boolean) { + } +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 6b9e8dcd..490e2deb 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -40,7 +40,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # to write custom TurboModules/Fabric components OR use libraries that # are providing them. # Note that this is incompatible with web debugging. -#newArchEnabled=true +newArchEnabled=true #bridgelessEnabled=true # Uncomment the line below to build React Native from source. From 2bc8d376769cb004fc86d369ddd9bb47dbdcb1fb Mon Sep 17 00:00:00 2001 From: sarthak-d11 Date: Wed, 23 Oct 2024 10:45:20 +0530 Subject: [PATCH 2/6] feat: cpp shadow node added --- android/src/main/jni/CMakeLists.txt | 79 +++++++++++++++++++ android/src/main/jni/RCTTabView.h | 19 +++++ android/src/newarch/RCTTabViewManager.kt | 39 ++++++++- .../RCTTabViewComponentDescriptor.h | 42 ++++++++++ .../RCTTabViewMeasurementsManager.cpp | 63 +++++++++++++++ .../RCTTabViewMeasurementsManager.h | 24 ++++++ .../RCTTabView/RCTTabViewShadowNode.cpp | 29 +++++++ .../RCTTabView/RCTTabViewShadowNode.h | 46 +++++++++++ .../components/RCTTabView/RCTTabViewState.h | 29 +++++++ package.json | 8 ++ react-native.config.js | 7 +- src/TabViewNativeComponent.ts | 4 +- 12 files changed, 383 insertions(+), 6 deletions(-) create mode 100644 android/src/main/jni/CMakeLists.txt create mode 100644 android/src/main/jni/RCTTabView.h create mode 100644 common/cpp/react/renderer/components/RCTTabView/RCTTabViewComponentDescriptor.h create mode 100644 common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.cpp create mode 100644 common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.h create mode 100644 common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.cpp create mode 100644 common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.h create mode 100644 common/cpp/react/renderer/components/RCTTabView/RCTTabViewState.h diff --git a/android/src/main/jni/CMakeLists.txt b/android/src/main/jni/CMakeLists.txt new file mode 100644 index 00000000..a29b4f32 --- /dev/null +++ b/android/src/main/jni/CMakeLists.txt @@ -0,0 +1,79 @@ +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE ON) + +set(LIB_LITERAL RCTTabView) +set(LIB_TARGET_NAME react_codegen_${LIB_LITERAL}) + +set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) +set(LIB_COMMON_DIR ${LIB_ANDROID_DIR}/../common/cpp) +set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni) +set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL}) + +add_compile_options( + -fexceptions + -frtti + -std=c++20 + -Wall + -Wpedantic + -Wno-gnu-zero-variadic-macro-arguments +) + +file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS *.cpp ${LIB_COMMON_DIR}/react/renderer/components/${LIB_LITERAL}/*.cpp) +file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_JNI_DIR}/*.cpp ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp) + +add_library( + ${LIB_TARGET_NAME} + SHARED + ${LIB_CUSTOM_SRCS} + ${LIB_CODEGEN_SRCS} +) + +target_include_directories( + ${LIB_TARGET_NAME} + PUBLIC + . + ${LIB_COMMON_DIR} + ${LIB_ANDROID_GENERATED_JNI_DIR} + ${LIB_ANDROID_GENERATED_COMPONENTS_DIR} +) + +target_link_libraries( + ${LIB_TARGET_NAME} + fbjni + folly_runtime + glog + jsi + react_codegen_rncore + react_debug + react_render_componentregistry + react_render_core + react_render_debug + react_render_graphics + react_render_imagemanager + react_render_mapbuffer + react_render_textlayoutmanager + react_utils + react_nativemodule_core + rrc_image + turbomodulejsijni + rrc_text + rrc_textinput + rrc_view + yoga +) + +target_compile_options( + ${LIB_TARGET_NAME} + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) + +target_include_directories( + ${CMAKE_PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/android/src/main/jni/RCTTabView.h b/android/src/main/jni/RCTTabView.h new file mode 100644 index 00000000..208df0d1 --- /dev/null +++ b/android/src/main/jni/RCTTabView.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include +#include + +namespace facebook +{ + namespace react + { + + JSI_EXPORT + std::shared_ptr RCTTabView_ModuleProvider( + const std::string &moduleName, + const JavaTurboModule::InitParams ¶ms); + + } // namespace react +} // namespace facebook diff --git a/android/src/newarch/RCTTabViewManager.kt b/android/src/newarch/RCTTabViewManager.kt index c4f1d6d7..b8dc3a6f 100644 --- a/android/src/newarch/RCTTabViewManager.kt +++ b/android/src/newarch/RCTTabViewManager.kt @@ -1,21 +1,29 @@ package com.rcttabview +import android.content.Context +import android.util.Log +import android.view.View import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray import com.facebook.react.common.MapBuilder +import com.facebook.react.common.mapbuffer.MapBuffer import com.facebook.react.module.annotations.ReactModule import com.facebook.react.uimanager.LayoutShadowNode +import com.facebook.react.uimanager.PixelUtil.toDIPFromPixel import com.facebook.react.uimanager.SimpleViewManager import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.ViewManagerDelegate import com.facebook.react.viewmanagers.TabViewManagerDelegate import com.facebook.react.viewmanagers.TabViewManagerInterface +import com.facebook.yoga.YogaMeasureMode +import com.facebook.yoga.YogaMeasureOutput + @ReactModule(name = RCTTabViewManager.NAME) class RCTTabViewManager(context: ReactApplicationContext) : SimpleViewManager(), TabViewManagerInterface { - private val context: ReactApplicationContext = context + private val contextInner: ReactApplicationContext = context private val delegate: TabViewManagerDelegate = TabViewManagerDelegate(this) private val tabViewImpl: RCTTabViewImpl = RCTTabViewImpl() @@ -26,6 +34,28 @@ class RCTTabViewManager(context: ReactApplicationContext) : return delegate } + override fun measure( + context: Context?, + localData: MapBuffer?, + props: MapBuffer?, + state: MapBuffer?, + width: Float, + widthMode: YogaMeasureMode?, + height: Float, + heightMode: YogaMeasureMode?, + attachmentsPositions: FloatArray? + ): Long { + val view = ReactBottomNavigationView(context?:contextInner) + val measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + view.measure(measureSpec, measureSpec) + Log.d("¸",view.getMeasuredWidth().toFloat().toString() ) + Log.d("bottomTabsH",view.getMeasuredHeight().toFloat().toString() ) + return YogaMeasureOutput.make( + toDIPFromPixel(view.getMeasuredWidth().toFloat()), + toDIPFromPixel(view.getMeasuredHeight().toFloat()) + ) + } + override fun createViewInstance(p0: ThemedReactContext): ReactBottomNavigationView { return tabViewImpl.createViewInstance(p0) } @@ -83,4 +113,11 @@ class RCTTabViewManager(context: ReactApplicationContext) : super.addEventEmitters(reactContext, view) } + override fun setBarTintColor(view: ReactBottomNavigationView?, value: Int?) { + + } + + override fun setTranslucent(view: ReactBottomNavigationView?, value: Boolean) { + } + } diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewComponentDescriptor.h b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewComponentDescriptor.h new file mode 100644 index 00000000..c9e693de --- /dev/null +++ b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewComponentDescriptor.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include "RCTTabViewMeasurementsManager.h" + +namespace facebook +{ + namespace react + { + + class RCTTabViewComponentDescriptor final + : public ConcreteComponentDescriptor + { + public: + RCTTabViewComponentDescriptor(const ComponentDescriptorParameters ¶meters) + : ConcreteComponentDescriptor(parameters), measurementsManager_( + std::make_shared(contextContainer_)) {} + + void adopt(ShadowNode &shadowNode) const override + { + ConcreteComponentDescriptor::adopt(shadowNode); + + auto &rctTabViewShadowNode = + static_cast(shadowNode); + + // `RCTTabViewShadowNode` uses `RCTTabViewMeasurementsManager` to + // provide measurements to Yoga. + rctTabViewShadowNode.setSliderMeasurementsManager( + measurementsManager_); + + // All `RCTTabViewShadowNode`s must have leaf Yoga nodes with properly + // setup measure function. + rctTabViewShadowNode.enableMeasurement(); + } + + private: + const std::shared_ptr measurementsManager_; + }; + + } +} \ No newline at end of file diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.cpp b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.cpp new file mode 100644 index 00000000..5c4430eb --- /dev/null +++ b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.cpp @@ -0,0 +1,63 @@ +#include "RCTTabViewMeasurementsManager.h" + +#include +#include +#include + +using namespace facebook::jni; + +namespace facebook::react +{ + + Size RCTTabViewMeasurementsManagerNew::measure( + SurfaceId surfaceId, + LayoutConstraints layoutConstraints) const + { + { + std::scoped_lock lock(mutex_); + if (hasBeenMeasured_) + { + return cachedMeasurement_; + } + } + + const jni::global_ref &fabricUIManager = + contextContainer_->at>("FabricUIManager"); + + static auto measure = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod("measure"); + + auto minimumSize = layoutConstraints.minimumSize; + auto maximumSize = layoutConstraints.maximumSize; + + local_ref componentName = make_jstring("RCTTabView"); + + auto measurement = yogaMeassureToSize(measure( + fabricUIManager, + surfaceId, + componentName.get(), + nullptr, + nullptr, + nullptr, + minimumSize.width, + maximumSize.width, + minimumSize.height, + maximumSize.height)); + + std::scoped_lock lock(mutex_); + cachedMeasurement_ = measurement; + hasBeenMeasured_ = true; + return measurement; + } + +} \ No newline at end of file diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.h b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.h new file mode 100644 index 00000000..1d6957bc --- /dev/null +++ b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include + +namespace facebook::react +{ + + class RCTTabViewMeasurementsManagerNew + { + public: + RCTTabViewMeasurementsManagerNew( + const ContextContainer::Shared &contextContainer) + : contextContainer_(contextContainer) {} + + Size measure(SurfaceId surfaceId, LayoutConstraints layoutConstraints) const; + + private: + const ContextContainer::Shared contextContainer_; + mutable std::mutex mutex_; + mutable bool hasBeenMeasured_ = false; + mutable Size cachedMeasurement_{}; + }; +} \ No newline at end of file diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.cpp b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.cpp new file mode 100644 index 00000000..a42a9e0b --- /dev/null +++ b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.cpp @@ -0,0 +1,29 @@ +#include "RCTTabViewShadowNode.h" +#include "RCTTabViewMeasurementsManager.h" + +namespace facebook +{ + namespace react + { + + extern const char RCTTabViewComponentName[] = "RCTTabView"; + + void RCTTabViewShadowNode::setSliderMeasurementsManager( + const std::shared_ptr & + measurementsManager) + { + ensureUnsealed(); + measurementsManager_ = measurementsManager; + } + +#pragma mark - LayoutableShadowNode + + Size RCTTabViewShadowNode::measureContent( + const LayoutContext & /*layoutContext*/, + const LayoutConstraints &layoutConstraints) const + { + return measurementsManager_->measure(getSurfaceId(), layoutConstraints); + } + + } +} \ No newline at end of file diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.h b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.h new file mode 100644 index 00000000..20aca8c4 --- /dev/null +++ b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "RCTTabViewMeasurementsManager.h" + +namespace facebook +{ + namespace react + { + + JSI_EXPORT extern const char RCTTabViewComponentName[]; + + /* + * `ShadowNode` for component. + */ + class JSI_EXPORT RCTTabViewShadowNode final + : public ConcreteViewShadowNode< + RCTTabViewComponentName, + RCTTabViewProps, + RCTTabViewEventEmitter, + RCTTabViewState> + { + public: + using ConcreteViewShadowNode::ConcreteViewShadowNode; + + void setSliderMeasurementsManager( + const std::shared_ptr &measurementsManager); + +#pragma mark - LayoutableShadowNode + + Size measureContent( + const LayoutContext &layoutContext, + const LayoutConstraints &layoutConstraints) const override; + + private: + std::shared_ptr measurementsManager_; + }; + + } +} \ No newline at end of file diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewState.h b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewState.h new file mode 100644 index 00000000..c3845888 --- /dev/null +++ b/common/cpp/react/renderer/components/RCTTabView/RCTTabViewState.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +namespace facebook +{ + namespace react + { + + class RCTTabViewState + { + public: + RCTTabViewState() = default; + + RCTTabViewState(RCTTabViewState const &previousState, folly::dynamic data) {}; + folly::dynamic getDynamic() const + { + return {}; + }; + MapBuffer getMapBuffer() const + { + return MapBufferBuilder::EMPTY(); + }; + }; + + } +} \ No newline at end of file diff --git a/package.json b/package.json index 4878f990..6540b792 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,14 @@ "example", "docs" ], + "codegenConfig": { + "name": "RCTTabView", + "type": "components", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.rcttabview" + } + }, "packageManager": "yarn@3.6.1", "jest": { "preset": "react-native", diff --git a/react-native.config.js b/react-native.config.js index 66211dab..ceadfbb5 100644 --- a/react-native.config.js +++ b/react-native.config.js @@ -1,11 +1,10 @@ -/** - * @type {import('@react-native-community/cli-types').UserDependencyConfig} - */ module.exports = { dependency: { platforms: { android: { - cmakeListsPath: 'build/generated/source/codegen/jni/CMakeLists.txt', + libraryName: 'RCTTabView', + componentDescriptors: ['RCTTabViewComponentDescriptor'], + cmakeListsPath: 'src/main/jni/CMakeLists.txt', }, }, }, diff --git a/src/TabViewNativeComponent.ts b/src/TabViewNativeComponent.ts index f7a44ee4..4401c517 100644 --- a/src/TabViewNativeComponent.ts +++ b/src/TabViewNativeComponent.ts @@ -28,4 +28,6 @@ export interface TabViewProps extends ViewProps { rippleColor?: ProcessedColorValue | null; } -export default codegenNativeComponent('RCTTabView'); +export default codegenNativeComponent('RCTTabView',{ + interfaceOnly: true, +}); From 1d6d289cb0e36ee95051a89c3d5146cb0e7feada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Sun, 27 Oct 2024 14:37:51 +0100 Subject: [PATCH 3/6] wip --- android/build.gradle | 2 +- .../java/com/rcttabview/RCTTabViewImpl.kt | 4 +- android/src/main/jni/CMakeLists.txt | 110 ++++++++++-------- android/src/newarch/RCTTabViewManager.kt | 28 ++++- android/src/oldarch/RCTTabViewManager.kt | 2 +- .../RCTTabViewComponentDescriptor.h | 2 +- .../RCTTabViewMeasurementsManager.cpp | 4 +- .../RCTTabViewMeasurementsManager.h | 0 .../RCTTabViewShadowNode.cpp | 0 .../RCTTabViewShadowNode.h | 0 .../RCTTabViewState.h | 0 ios/Fabric/RCTTabViewComponentView.mm | 46 ++++---- package.json | 13 +-- react-native-bottom-tabs.podspec | 10 +- react-native.config.js | 2 +- src/TabViewNativeComponent.ts | 2 +- 16 files changed, 126 insertions(+), 99 deletions(-) rename common/cpp/react/renderer/components/{RCTTabView => RNCTabViewSpec}/RCTTabViewComponentDescriptor.h (99%) rename common/cpp/react/renderer/components/{RCTTabView => RNCTabViewSpec}/RCTTabViewMeasurementsManager.cpp (96%) rename common/cpp/react/renderer/components/{RCTTabView => RNCTabViewSpec}/RCTTabViewMeasurementsManager.h (100%) rename common/cpp/react/renderer/components/{RCTTabView => RNCTabViewSpec}/RCTTabViewShadowNode.cpp (100%) rename common/cpp/react/renderer/components/{RCTTabView => RNCTabViewSpec}/RCTTabViewShadowNode.h (100%) rename common/cpp/react/renderer/components/{RCTTabView => RNCTabViewSpec}/RCTTabViewState.h (100%) diff --git a/android/build.gradle b/android/build.gradle index afa0f093..0fc108f8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -121,7 +121,7 @@ dependencies { if (isNewArchitectureEnabled()) { react { jsRootDir = file("../src/") - libraryName = "RCTTabView" + libraryName = "RNCTabView" codegenJavaPackageName = "com.rcttabview" } } diff --git a/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt b/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt index 37c5e275..92bed70a 100644 --- a/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt +++ b/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt @@ -88,7 +88,7 @@ class RCTTabViewImpl { fun setInactiveTintColor(view: ReactBottomNavigationView, color: Int?) { view.setInactiveTintColor(color) } - + fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { val view = ReactBottomNavigationView(context) tabView = view @@ -101,7 +101,7 @@ class RCTTabViewImpl { view.onTabLongPressedListener = { data -> data.getString("key")?.let { - eventDispatcher.dispatchEvent(TabLongPressEvent(viewTag = view.id, key = it)) +// eventDispatcher.dispatchEvent(TabLongPressEvent(viewTag = view.id, key = it)) } } diff --git a/android/src/main/jni/CMakeLists.txt b/android/src/main/jni/CMakeLists.txt index a29b4f32..71147d64 100644 --- a/android/src/main/jni/CMakeLists.txt +++ b/android/src/main/jni/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.13) set(CMAKE_VERBOSE_MAKEFILE ON) -set(LIB_LITERAL RCTTabView) +set(LIB_LITERAL RNCTabView) set(LIB_TARGET_NAME react_codegen_${LIB_LITERAL}) set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) @@ -10,70 +10,78 @@ set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/code set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL}) add_compile_options( - -fexceptions - -frtti - -std=c++20 - -Wall - -Wpedantic - -Wno-gnu-zero-variadic-macro-arguments + -fexceptions + -frtti + -std=c++20 + -Wall + -Wpedantic + -Wno-gnu-zero-variadic-macro-arguments ) file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS *.cpp ${LIB_COMMON_DIR}/react/renderer/components/${LIB_LITERAL}/*.cpp) file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_JNI_DIR}/*.cpp ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp) add_library( - ${LIB_TARGET_NAME} - SHARED - ${LIB_CUSTOM_SRCS} - ${LIB_CODEGEN_SRCS} + ${LIB_TARGET_NAME} + SHARED + ${LIB_CUSTOM_SRCS} + ${LIB_CODEGEN_SRCS} ) target_include_directories( - ${LIB_TARGET_NAME} - PUBLIC - . - ${LIB_COMMON_DIR} - ${LIB_ANDROID_GENERATED_JNI_DIR} - ${LIB_ANDROID_GENERATED_COMPONENTS_DIR} + ${LIB_TARGET_NAME} + PUBLIC + . + ${LIB_COMMON_DIR} + ${LIB_ANDROID_GENERATED_JNI_DIR} + ${LIB_ANDROID_GENERATED_COMPONENTS_DIR} ) -target_link_libraries( - ${LIB_TARGET_NAME} - fbjni - folly_runtime - glog - jsi - react_codegen_rncore - react_debug - react_render_componentregistry - react_render_core - react_render_debug - react_render_graphics - react_render_imagemanager - react_render_mapbuffer - react_render_textlayoutmanager - react_utils - react_nativemodule_core - rrc_image - turbomodulejsijni - rrc_text - rrc_textinput - rrc_view - yoga -) +# https://github.com/react-native-community/discussions-and-proposals/discussions/816 +# This if-then-else can be removed once this library does not support version below 0.76 +if (REACTNATIVE_MERGED_SO) + target_link_libraries( + ${LIB_TARGET_NAME} + fbjni + jsi + reactnative + ) +else() + target_link_libraries( + ${LIB_TARGET_NAME} + fbjni + folly_runtime + glog + jsi + react_codegen_rncore + react_debug + react_render_componentregistry + react_render_core + react_render_debug + react_render_graphics + react_render_imagemanager + react_render_mapbuffer + react_utils + react_nativemodule_core + rrc_image + turbomodulejsijni + rrc_view + yoga + ) +endif() target_compile_options( - ${LIB_TARGET_NAME} - PRIVATE - -DLOG_TAG=\"ReactNative\" - -fexceptions - -frtti - -std=c++20 - -Wall + ${LIB_TARGET_NAME} + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall ) target_include_directories( - ${CMAKE_PROJECT_NAME} - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/android/src/newarch/RCTTabViewManager.kt b/android/src/newarch/RCTTabViewManager.kt index b8dc3a6f..054c1b71 100644 --- a/android/src/newarch/RCTTabViewManager.kt +++ b/android/src/newarch/RCTTabViewManager.kt @@ -13,8 +13,8 @@ import com.facebook.react.uimanager.PixelUtil.toDIPFromPixel import com.facebook.react.uimanager.SimpleViewManager import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.ViewManagerDelegate -import com.facebook.react.viewmanagers.TabViewManagerDelegate -import com.facebook.react.viewmanagers.TabViewManagerInterface +import com.facebook.react.viewmanagers.RNCTabViewManagerDelegate +import com.facebook.react.viewmanagers.RNCTabViewManagerInterface import com.facebook.yoga.YogaMeasureMode import com.facebook.yoga.YogaMeasureOutput @@ -22,13 +22,13 @@ import com.facebook.yoga.YogaMeasureOutput @ReactModule(name = RCTTabViewManager.NAME) class RCTTabViewManager(context: ReactApplicationContext) : SimpleViewManager(), - TabViewManagerInterface { + RNCTabViewManagerInterface { private val contextInner: ReactApplicationContext = context - private val delegate: TabViewManagerDelegate = - TabViewManagerDelegate(this) + private val delegate: RNCTabViewManagerDelegate = + RNCTabViewManagerDelegate(this) private val tabViewImpl: RCTTabViewImpl = RCTTabViewImpl() companion object { - const val NAME = "RCTTabView" + const val NAME = "RNCTabView" } override fun getDelegate(): ViewManagerDelegate? { return delegate @@ -120,4 +120,20 @@ class RCTTabViewManager(context: ReactApplicationContext) : override fun setTranslucent(view: ReactBottomNavigationView?, value: Boolean) { } + override fun setActiveTintColor(view: ReactBottomNavigationView?, value: Int?) { + TODO("Not yet implemented") + } + + override fun setInactiveTintColor(view: ReactBottomNavigationView?, value: Int?) { + TODO("Not yet implemented") + } + + override fun setIgnoresTopSafeArea(view: ReactBottomNavigationView?, value: Boolean) { + TODO("Not yet implemented") + } + + override fun setDisablePageAnimations(view: ReactBottomNavigationView?, value: Boolean) { + TODO("Not yet implemented") + } + } diff --git a/android/src/oldarch/RCTTabViewManager.kt b/android/src/oldarch/RCTTabViewManager.kt index f700a0e2..6f5fa5a2 100644 --- a/android/src/oldarch/RCTTabViewManager.kt +++ b/android/src/oldarch/RCTTabViewManager.kt @@ -62,7 +62,7 @@ class RCTTabViewManager(context: ReactApplicationContext) : } companion object { - const val NAME = "RCTTabView" + const val NAME = "RNCTabView" } override fun getExportedCustomDirectEventTypeConstants(): MutableMap? { diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewComponentDescriptor.h b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewComponentDescriptor.h similarity index 99% rename from common/cpp/react/renderer/components/RCTTabView/RCTTabViewComponentDescriptor.h rename to common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewComponentDescriptor.h index c9e693de..1e560781 100644 --- a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewComponentDescriptor.h +++ b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewComponentDescriptor.h @@ -39,4 +39,4 @@ namespace facebook }; } -} \ No newline at end of file +} diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.cpp b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.cpp similarity index 96% rename from common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.cpp rename to common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.cpp index 5c4430eb..9b74fff1 100644 --- a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.cpp +++ b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.cpp @@ -40,7 +40,7 @@ namespace facebook::react auto minimumSize = layoutConstraints.minimumSize; auto maximumSize = layoutConstraints.maximumSize; - local_ref componentName = make_jstring("RCTTabView"); + local_ref componentName = make_jstring("RNCTabView"); auto measurement = yogaMeassureToSize(measure( fabricUIManager, @@ -60,4 +60,4 @@ namespace facebook::react return measurement; } -} \ No newline at end of file +} diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.h b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.h similarity index 100% rename from common/cpp/react/renderer/components/RCTTabView/RCTTabViewMeasurementsManager.h rename to common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.h diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.cpp b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.cpp similarity index 100% rename from common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.cpp rename to common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.cpp diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.h b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.h similarity index 100% rename from common/cpp/react/renderer/components/RCTTabView/RCTTabViewShadowNode.h rename to common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.h diff --git a/common/cpp/react/renderer/components/RCTTabView/RCTTabViewState.h b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewState.h similarity index 100% rename from common/cpp/react/renderer/components/RCTTabView/RCTTabViewState.h rename to common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewState.h diff --git a/ios/Fabric/RCTTabViewComponentView.mm b/ios/Fabric/RCTTabViewComponentView.mm index 104b0d03..b4d1e0fb 100644 --- a/ios/Fabric/RCTTabViewComponentView.mm +++ b/ios/Fabric/RCTTabViewComponentView.mm @@ -48,7 +48,7 @@ - (instancetype)initWithFrame:(CGRect)frame self.contentView = _tabViewProvider; _props = defaultProps; } - + return self; } @@ -75,7 +75,7 @@ - (void)mountChildComponentView:(UIView *)childCompone - (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { [_reactSubviews removeObjectAtIndex:index]; - + [childComponentView removeFromSuperview]; } @@ -83,65 +83,65 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & { const auto &oldViewProps = *std::static_pointer_cast(_props); const auto &newViewProps = *std::static_pointer_cast(props); - + if (haveTabItemsChanged(oldViewProps.items, newViewProps.items)) { _tabViewProvider.itemsData = convertItemsToArray(newViewProps.items); } - + if (oldViewProps.translucent != newViewProps.translucent) { _tabViewProvider.translucent = newViewProps.translucent; } - + if (oldViewProps.icons != newViewProps.icons) { auto iconsArray = [[NSMutableArray alloc] init]; for (auto &source: newViewProps.icons) { auto imageSource = [[RCTImageSource alloc] initWithURLRequest:NSURLRequestFromImageSource(source) size:CGSizeMake(source.size.width, source.size.height) scale:source.scale]; [iconsArray addObject:imageSource]; } - + _tabViewProvider.icons = iconsArray; } - + if (oldViewProps.sidebarAdaptable != newViewProps.sidebarAdaptable) { _tabViewProvider.sidebarAdaptable = newViewProps.sidebarAdaptable; } - + if (oldViewProps.disablePageAnimations != newViewProps.disablePageAnimations) { _tabViewProvider.disablePageAnimations = newViewProps.disablePageAnimations; } - + if (oldViewProps.labeled != newViewProps.labeled) { _tabViewProvider.labeled = newViewProps.labeled; } - + if (oldViewProps.ignoresTopSafeArea != newViewProps.ignoresTopSafeArea) { _tabViewProvider.ignoresTopSafeArea = newViewProps.ignoresTopSafeArea; } - + if (oldViewProps.selectedPage != newViewProps.selectedPage) { _tabViewProvider.selectedPage = RCTNSStringFromString(newViewProps.selectedPage); } - + if (oldViewProps.scrollEdgeAppearance != newViewProps.scrollEdgeAppearance) { _tabViewProvider.scrollEdgeAppearance = RCTNSStringFromString(newViewProps.scrollEdgeAppearance); } - + if (oldViewProps.labeled != newViewProps.labeled) { _tabViewProvider.labeled = newViewProps.labeled; } - + if (oldViewProps.barTintColor != newViewProps.barTintColor) { _tabViewProvider.barTintColor = RCTUIColorFromSharedColor(newViewProps.barTintColor); } - + if (oldViewProps.activeTintColor != newViewProps.activeTintColor) { _tabViewProvider.activeTintColor = RCTUIColorFromSharedColor(newViewProps.activeTintColor); } - + if (oldViewProps.inactiveTintColor != newViewProps.inactiveTintColor) { _tabViewProvider.inactiveTintColor = RCTUIColorFromSharedColor(newViewProps.inactiveTintColor); } - + [super updateProps:props oldProps:oldProps]; } @@ -155,29 +155,29 @@ bool areTabItemsEqual(const RNCTabViewItemsStruct& lhs, const RNCTabViewItemsStr bool haveTabItemsChanged(const std::vector& oldItems, const std::vector& newItems) { - + if (oldItems.size() != newItems.size()) { return true; } - + for (size_t i = 0; i < oldItems.size(); ++i) { if (!areTabItemsEqual(oldItems[i], newItems[i])) { return true; } } - + return false; } NSArray* convertItemsToArray(const std::vector& items) { NSMutableArray *result = [NSMutableArray array]; - + for (const auto& item : items) { auto tabInfo = [[TabInfo alloc] initWithKey:RCTNSStringFromString(item.key) title:RCTNSStringFromString(item.title) badge:RCTNSStringFromString(item.badge) sfSymbol:RCTNSStringFromString(item.sfSymbol) activeTintColor:RCTUIColorFromSharedColor(item.activeTintColor)]; - + [result addObject:tabInfo]; } - + return result; } diff --git a/package.json b/package.json index 6a763e6f..2dcb781e 100644 --- a/package.json +++ b/package.json @@ -114,14 +114,6 @@ "example", "docs" ], - "codegenConfig": { - "name": "RCTTabView", - "type": "components", - "jsSrcsDir": "src", - "android": { - "javaPackageName": "com.rcttabview" - } - }, "packageManager": "yarn@3.6.1", "jest": { "preset": "react-native", @@ -215,6 +207,9 @@ "codegenConfig": { "name": "RNCTabViewSpec", "type": "components", - "jsSrcsDir": "src" + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.rcttabview" + } } } diff --git a/react-native-bottom-tabs.podspec b/react-native-bottom-tabs.podspec index 13371f70..9b6d531e 100644 --- a/react-native-bottom-tabs.podspec +++ b/react-native-bottom-tabs.podspec @@ -2,6 +2,7 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' +new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' Pod::Spec.new do |s| s.name = "react-native-bottom-tabs" @@ -16,6 +17,13 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,cpp,swift}" + if new_arch_enabled + s.subspec "common" do |ss| + ss.source_files = "common/cpp/**/*.{cpp,h}" + ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\"" } + end + end + s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" } @@ -30,7 +38,7 @@ Pod::Spec.new do |s| s.dependency "React-Core" # Don't install the dependencies when we run `pod install` in the old architecture. - if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then + if new_arch_enabled then s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", diff --git a/react-native.config.js b/react-native.config.js index ceadfbb5..3a76e9a4 100644 --- a/react-native.config.js +++ b/react-native.config.js @@ -2,7 +2,7 @@ module.exports = { dependency: { platforms: { android: { - libraryName: 'RCTTabView', + libraryName: 'RNCTabViewSpec', componentDescriptors: ['RCTTabViewComponentDescriptor'], cmakeListsPath: 'src/main/jni/CMakeLists.txt', }, diff --git a/src/TabViewNativeComponent.ts b/src/TabViewNativeComponent.ts index 99c041e0..ce7bf364 100644 --- a/src/TabViewNativeComponent.ts +++ b/src/TabViewNativeComponent.ts @@ -34,6 +34,6 @@ export interface TabViewProps extends ViewProps { disablePageAnimations?: boolean; } -export default codegenNativeComponent('RCTTabView',{ +export default codegenNativeComponent('RNCTabView', { interfaceOnly: true, }); From a27ea6949129e1f0576173db49be5408d3f0e563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Sun, 27 Oct 2024 19:02:56 +0100 Subject: [PATCH 4/6] feat: make shadow node work, share the code between ios --- .../java/com/rcttabview/RCTTabViewImpl.kt | 81 ++---------- .../java/com/rcttabview/TabViewShadowNode.kt | 43 ------- android/src/main/jni/RCTTabView.h | 19 --- android/src/main/jni/RNCTabView.h | 13 ++ android/src/newarch/EventDispatcherWrapper.kt | 13 -- android/src/newarch/RCTTabViewManager.kt | 120 +++++++++--------- android/src/oldarch/EventDispatcherWrapper.kt | 14 -- android/src/oldarch/RCTTabViewManager.kt | 102 +++++++++++---- .../RNCTabViewComponentDescriptor.h | 47 +++++++ .../RNCTabViewMeasurementsManager.cpp | 65 ++++++++++ .../RNCTabViewMeasurementsManager.h} | 13 +- .../RNCTabView/RNCTabViewShadowNode.cpp | 28 ++++ .../RNCTabView/RNCTabViewShadowNode.h | 49 +++++++ .../components/RNCTabView/RNCTabViewState.h | 35 +++++ .../RCTTabViewComponentDescriptor.h | 42 ------ .../RCTTabViewMeasurementsManager.cpp | 63 --------- .../RNCTabViewSpec/RCTTabViewShadowNode.cpp | 29 ----- .../RNCTabViewSpec/RCTTabViewShadowNode.h | 46 ------- .../RNCTabViewSpec/RCTTabViewState.h | 29 ----- ios/Fabric/RCTTabViewComponentView.mm | 9 +- package.json | 2 +- react-native.config.js | 4 +- 22 files changed, 401 insertions(+), 465 deletions(-) delete mode 100644 android/src/main/java/com/rcttabview/TabViewShadowNode.kt delete mode 100644 android/src/main/jni/RCTTabView.h create mode 100644 android/src/main/jni/RNCTabView.h delete mode 100644 android/src/newarch/EventDispatcherWrapper.kt delete mode 100644 android/src/oldarch/EventDispatcherWrapper.kt create mode 100644 common/cpp/react/renderer/components/RNCTabView/RNCTabViewComponentDescriptor.h create mode 100644 common/cpp/react/renderer/components/RNCTabView/RNCTabViewMeasurementsManager.cpp rename common/cpp/react/renderer/components/{RNCTabViewSpec/RCTTabViewMeasurementsManager.h => RNCTabView/RNCTabViewMeasurementsManager.h} (82%) create mode 100644 common/cpp/react/renderer/components/RNCTabView/RNCTabViewShadowNode.cpp create mode 100644 common/cpp/react/renderer/components/RNCTabView/RNCTabViewShadowNode.h create mode 100644 common/cpp/react/renderer/components/RNCTabView/RNCTabViewState.h delete mode 100644 common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewComponentDescriptor.h delete mode 100644 common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.cpp delete mode 100644 common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.cpp delete mode 100644 common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.h delete mode 100644 common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewState.h diff --git a/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt b/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt index 92bed70a..35bc825d 100644 --- a/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt +++ b/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt @@ -1,21 +1,8 @@ package com.rcttabview import android.content.res.ColorStateList -import android.util.Log -import android.view.View.MeasureSpec import com.facebook.react.bridge.ReadableArray import com.facebook.react.common.MapBuilder -import com.facebook.react.uimanager.LayoutShadowNode -import com.facebook.react.uimanager.ThemedReactContext -import com.facebook.react.uimanager.UIManagerHelper -import com.facebook.react.uimanager.UIManagerModule -import com.facebook.react.uimanager.annotations.ReactProp -import com.facebook.react.uimanager.events.EventDispatcher -import com.facebook.yoga.YogaMeasureFunction -import com.facebook.yoga.YogaMeasureMode -import com.facebook.yoga.YogaMeasureOutput -import com.facebook.yoga.YogaNode - data class TabInfo( val key: String, @@ -25,13 +12,14 @@ data class TabInfo( ) class RCTTabViewImpl { - - private lateinit var eventDispatcher: EventDispatcherWrapper - private var tabView: ReactBottomNavigationView? = null fun getName(): String { return NAME } + companion object { + const val NAME = "RNCTabView" + } + fun setItems(view: ReactBottomNavigationView, items: ReadableArray) { val itemsArray = mutableListOf() for (i in 0 until items.size()) { @@ -49,29 +37,24 @@ class RCTTabViewImpl { view.updateItems(itemsArray) } - fun setSelectedPage(view: ReactBottomNavigationView, key: String) { view.items?.indexOfFirst { it.key == key }?.let { view.selectedItemId = it } } - fun setLabeled(view: ReactBottomNavigationView, flag: Boolean?) { view.setLabeled(flag) } - fun setIcons(view: ReactBottomNavigationView, icons: ReadableArray?) { view.setIcons(icons) } - @ReactProp(name = "barTintColor", customType = "Color") fun setBarTintColor(view: ReactBottomNavigationView, color: Int?) { view.setBarTintColor(color) } - @ReactProp(name = "rippleColor", customType = "Color") fun setRippleColor(view: ReactBottomNavigationView, rippleColor: Int?) { if (rippleColor != null) { val color = ColorStateList.valueOf(rippleColor) @@ -79,62 +62,20 @@ class RCTTabViewImpl { } } - @ReactProp(name = "activeTintColor", customType = "Color") fun setActiveTintColor(view: ReactBottomNavigationView, color: Int?) { view.setActiveTintColor(color) } - @ReactProp(name = "inactiveTintColor", customType = "Color") fun setInactiveTintColor(view: ReactBottomNavigationView, color: Int?) { view.setInactiveTintColor(color) } - fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { - val view = ReactBottomNavigationView(context) - tabView = view - eventDispatcher = EventDispatcherWrapper(context) - view?.onTabSelectedListener = { data -> - data.getString("key")?.let { - eventDispatcher.dispatchEvent(PageSelectedEvent(viewTag = view.id, key = it)) - } - } - - view.onTabLongPressedListener = { data -> - data.getString("key")?.let { -// eventDispatcher.dispatchEvent(TabLongPressEvent(viewTag = view.id, key = it)) - } - } - - return view - } - - fun getViewInstance(): ReactBottomNavigationView? { - return if(tabView!=null) - tabView - else - null - } - - companion object { - const val NAME = "RNCTabView" - } - // iOS Props - - fun setSidebarAdaptable(view: ReactBottomNavigationView, flag: Boolean) { - } - - fun setScrollEdgeAppearance(view: ReactBottomNavigationView, value: String) { - - } - - fun setIgnoresTopSafeArea(view: ReactBottomNavigationView, flag: Boolean) { - } - - - fun setDisablePageAnimations(view: ReactBottomNavigationView, flag: Boolean) { - } - - @ReactProp(name = "translucent") - fun setTranslucentview(view: ReactBottomNavigationView, translucent: Boolean?) { + fun getExportedCustomDirectEventTypeConstants(): MutableMap? { + return MapBuilder.of( + PageSelectedEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onPageSelected"), + TabLongPressEvent.EVENT_NAME, + MapBuilder.of("registrationName", "onTabLongPress") + ) } } diff --git a/android/src/main/java/com/rcttabview/TabViewShadowNode.kt b/android/src/main/java/com/rcttabview/TabViewShadowNode.kt deleted file mode 100644 index e27773c2..00000000 --- a/android/src/main/java/com/rcttabview/TabViewShadowNode.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.rcttabview - -import android.view.View.MeasureSpec -import com.facebook.react.uimanager.LayoutShadowNode -import com.facebook.yoga.YogaMeasureFunction -import com.facebook.yoga.YogaMeasureMode -import com.facebook.yoga.YogaMeasureOutput -import com.facebook.yoga.YogaNode - -class TabViewShadowNode(tabview: ReactBottomNavigationView?) : LayoutShadowNode(), - YogaMeasureFunction { - private var mWidth = 0 - private var mHeight = 0 - private var mMeasured = false - private var mTabView = tabview - init { - initMeasureFunction() - } - - private fun initMeasureFunction() { - setMeasureFunction(this) - } - - override fun measure( - node: YogaNode, - width: Float, - widthMode: YogaMeasureMode, - height: Float, - heightMode: YogaMeasureMode - ): Long { - if (mMeasured) { - return YogaMeasureOutput.make(mWidth, mHeight) - } - val tempTabView = mTabView?: ReactBottomNavigationView(themedContext) - val spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) - tempTabView.measure(spec, spec) - this.mWidth = tempTabView.measuredWidth - this.mHeight = tempTabView.measuredHeight - this.mMeasured = true - - return YogaMeasureOutput.make(mWidth, mHeight) - } -} diff --git a/android/src/main/jni/RCTTabView.h b/android/src/main/jni/RCTTabView.h deleted file mode 100644 index 208df0d1..00000000 --- a/android/src/main/jni/RCTTabView.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace facebook -{ - namespace react - { - - JSI_EXPORT - std::shared_ptr RCTTabView_ModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms); - - } // namespace react -} // namespace facebook diff --git a/android/src/main/jni/RNCTabView.h b/android/src/main/jni/RNCTabView.h new file mode 100644 index 00000000..f7a1fb25 --- /dev/null +++ b/android/src/main/jni/RNCTabView.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include +#include + +namespace facebook::react { +JSI_EXPORT +std::shared_ptr RNCTabView_ModuleProvider( + const std::string &moduleName, + const JavaTurboModule::InitParams ¶ms); +} diff --git a/android/src/newarch/EventDispatcherWrapper.kt b/android/src/newarch/EventDispatcherWrapper.kt deleted file mode 100644 index 8295931f..00000000 --- a/android/src/newarch/EventDispatcherWrapper.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.rcttabview - -import com.facebook.react.bridge.ReactContext -import com.facebook.react.uimanager.UIManagerHelper -import com.facebook.react.uimanager.events.Event -import com.facebook.react.uimanager.events.EventDispatcher - -class EventDispatcherWrapper(context: ReactContext) { - var context: ReactContext = context - fun dispatchEvent(event: Event) { - UIManagerHelper.getEventDispatcherForReactTag(context, event.viewTag)?.dispatchEvent(event) - } -} diff --git a/android/src/newarch/RCTTabViewManager.kt b/android/src/newarch/RCTTabViewManager.kt index 054c1b71..b71e9c0a 100644 --- a/android/src/newarch/RCTTabViewManager.kt +++ b/android/src/newarch/RCTTabViewManager.kt @@ -1,17 +1,15 @@ package com.rcttabview import android.content.Context -import android.util.Log import android.view.View import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray -import com.facebook.react.common.MapBuilder -import com.facebook.react.common.mapbuffer.MapBuffer +import com.facebook.react.bridge.ReadableMap import com.facebook.react.module.annotations.ReactModule -import com.facebook.react.uimanager.LayoutShadowNode import com.facebook.react.uimanager.PixelUtil.toDIPFromPixel import com.facebook.react.uimanager.SimpleViewManager import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.ViewManagerDelegate import com.facebook.react.viewmanagers.RNCTabViewManagerDelegate import com.facebook.react.viewmanagers.RNCTabViewManagerInterface @@ -19,45 +17,32 @@ import com.facebook.yoga.YogaMeasureMode import com.facebook.yoga.YogaMeasureOutput -@ReactModule(name = RCTTabViewManager.NAME) +@ReactModule(name = RCTTabViewImpl.NAME) class RCTTabViewManager(context: ReactApplicationContext) : SimpleViewManager(), RNCTabViewManagerInterface { - private val contextInner: ReactApplicationContext = context + + private val contextInner: ReactApplicationContext = context private val delegate: RNCTabViewManagerDelegate = RNCTabViewManagerDelegate(this) private val tabViewImpl: RCTTabViewImpl = RCTTabViewImpl() - companion object { - const val NAME = "RNCTabView" - } - override fun getDelegate(): ViewManagerDelegate? { - return delegate - } - override fun measure( - context: Context?, - localData: MapBuffer?, - props: MapBuffer?, - state: MapBuffer?, - width: Float, - widthMode: YogaMeasureMode?, - height: Float, - heightMode: YogaMeasureMode?, - attachmentsPositions: FloatArray? - ): Long { - val view = ReactBottomNavigationView(context?:contextInner) - val measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) - view.measure(measureSpec, measureSpec) - Log.d("¸",view.getMeasuredWidth().toFloat().toString() ) - Log.d("bottomTabsH",view.getMeasuredHeight().toFloat().toString() ) - return YogaMeasureOutput.make( - toDIPFromPixel(view.getMeasuredWidth().toFloat()), - toDIPFromPixel(view.getMeasuredHeight().toFloat()) - ) - } + override fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { + val view = ReactBottomNavigationView(context) + val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id) + view.onTabSelectedListener = { data -> + data.getString("key")?.let { + eventDispatcher?.dispatchEvent(PageSelectedEvent(viewTag = view.id, key = it)) + } + } + + view.onTabLongPressedListener = { data -> + data.getString("key")?.let { + eventDispatcher?.dispatchEvent(TabLongPressEvent(viewTag = view.id, key = it)) + } + } + return view - override fun createViewInstance(p0: ThemedReactContext): ReactBottomNavigationView { - return tabViewImpl.createViewInstance(p0) } override fun getName(): String { @@ -75,65 +60,74 @@ class RCTTabViewManager(context: ReactApplicationContext) : } override fun setIcons(view: ReactBottomNavigationView?, value: ReadableArray?) { - if (view != null && value != null) + if (view != null) tabViewImpl.setIcons(view, value) } override fun setLabeled(view: ReactBottomNavigationView?, value: Boolean) { - if (view != null && value != null) + if (view != null) tabViewImpl.setLabeled(view, value) } - override fun setSidebarAdaptable(view: ReactBottomNavigationView?, value: Boolean) { + override fun setRippleColor(view: ReactBottomNavigationView?, value: Int?) { if (view != null && value != null) - tabViewImpl.setSidebarAdaptable(view, value) + tabViewImpl.setRippleColor(view, value) } - override fun setScrollEdgeAppearance(view: ReactBottomNavigationView?, value: String?) { + override fun setBarTintColor(view: ReactBottomNavigationView?, value: Int?) { if (view != null && value != null) - tabViewImpl.setScrollEdgeAppearance(view, value) + tabViewImpl.setBarTintColor(view, value) } - override fun setRippleColor(view: ReactBottomNavigationView?, value: Int?) { + override fun setActiveTintColor(view: ReactBottomNavigationView?, value: Int?) { if (view != null && value != null) - tabViewImpl.setRippleColor(view, value) + tabViewImpl.setActiveTintColor(view, value) } - override fun createShadowNodeInstance(context: ReactApplicationContext): LayoutShadowNode { - return TabViewShadowNode(tabViewImpl.getViewInstance()) - } - override fun getExportedCustomDirectEventTypeConstants(): MutableMap? { - return MapBuilder.of( - PageSelectedEvent.EVENT_NAME, - MapBuilder.of("registrationName", "onPageSelected"), - ) + override fun setInactiveTintColor(view: ReactBottomNavigationView?, value: Int?) { + if (view != null && value != null) + tabViewImpl.setInactiveTintColor(view, value) } - override fun addEventEmitters(reactContext: ThemedReactContext, view: ReactBottomNavigationView) { - super.addEventEmitters(reactContext, view) + override fun getDelegate(): ViewManagerDelegate { + return delegate } - override fun setBarTintColor(view: ReactBottomNavigationView?, value: Int?) { + public override fun measure( + context: Context?, + localData: ReadableMap?, + props: ReadableMap?, + state: ReadableMap?, + width: Float, + widthMode: YogaMeasureMode?, + height: Float, + heightMode: YogaMeasureMode?, + attachmentsPositions: FloatArray? + ): Long { + val view = ReactBottomNavigationView(context ?: contextInner) + val measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + view.measure(measureSpec, measureSpec) + return YogaMeasureOutput.make( + toDIPFromPixel(view.measuredWidth.toFloat()), + toDIPFromPixel(view.measuredHeight.toFloat()) + ) } + // iOS Methods + override fun setTranslucent(view: ReactBottomNavigationView?, value: Boolean) { } - override fun setActiveTintColor(view: ReactBottomNavigationView?, value: Int?) { - TODO("Not yet implemented") + override fun setIgnoresTopSafeArea(view: ReactBottomNavigationView?, value: Boolean) { } - override fun setInactiveTintColor(view: ReactBottomNavigationView?, value: Int?) { - TODO("Not yet implemented") + override fun setDisablePageAnimations(view: ReactBottomNavigationView?, value: Boolean) { } - override fun setIgnoresTopSafeArea(view: ReactBottomNavigationView?, value: Boolean) { - TODO("Not yet implemented") + override fun setSidebarAdaptable(view: ReactBottomNavigationView?, value: Boolean) { } - override fun setDisablePageAnimations(view: ReactBottomNavigationView?, value: Boolean) { - TODO("Not yet implemented") + override fun setScrollEdgeAppearance(view: ReactBottomNavigationView?, value: String?) { } - } diff --git a/android/src/oldarch/EventDispatcherWrapper.kt b/android/src/oldarch/EventDispatcherWrapper.kt deleted file mode 100644 index 72421037..00000000 --- a/android/src/oldarch/EventDispatcherWrapper.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.rcttabview - -import com.facebook.react.bridge.ReactContext -import com.facebook.react.uimanager.UIManagerModule -import com.facebook.react.uimanager.events.Event -import com.facebook.react.uimanager.events.EventDispatcher - -class EventDispatcherWrapper(context: ReactContext) { - var eventDispatcher:EventDispatcher = context.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher - - fun dispatchEvent(event: Event){ - eventDispatcher.dispatchEvent(event) - } -} diff --git a/android/src/oldarch/RCTTabViewManager.kt b/android/src/oldarch/RCTTabViewManager.kt index 6f5fa5a2..41b582b1 100644 --- a/android/src/oldarch/RCTTabViewManager.kt +++ b/android/src/oldarch/RCTTabViewManager.kt @@ -1,14 +1,11 @@ package com.rcttabview -import android.content.res.ColorStateList import android.view.View.MeasureSpec import com.facebook.react.bridge.ReadableArray -import com.facebook.react.common.MapBuilder import com.facebook.react.module.annotations.ReactModule import com.facebook.react.uimanager.LayoutShadowNode import com.facebook.react.uimanager.SimpleViewManager import com.facebook.react.uimanager.ThemedReactContext -import com.facebook.react.uimanager.UIManagerModule import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.uimanager.events.EventDispatcher import com.facebook.yoga.YogaMeasureFunction @@ -16,15 +13,40 @@ import com.facebook.yoga.YogaMeasureMode import com.facebook.yoga.YogaMeasureOutput import com.facebook.yoga.YogaNode import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.uimanager.UIManagerModule - - -class RCTTabViewManager(context: ReactApplicationContext) : - SimpleViewManager() { +@ReactModule(name = RCTTabViewImpl.NAME) +class RCTTabViewManager(context: ReactApplicationContext) : SimpleViewManager() { private lateinit var eventDispatcher: EventDispatcher private var tabViewImpl = RCTTabViewImpl() + override fun getName(): String { - return NAME + return tabViewImpl.getName() + } + + public override fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { + eventDispatcher = context.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher + val view = ReactBottomNavigationView(context) + view.onTabSelectedListener = { data -> + data.getString("key")?.let { + eventDispatcher.dispatchEvent(PageSelectedEvent(viewTag = view.id, key = it)) + } + } + + view.onTabLongPressedListener = { data -> + data.getString("key")?.let { + eventDispatcher.dispatchEvent(TabLongPressEvent(viewTag = view.id, key = it)) + } + } + return view + } + + override fun createShadowNodeInstance(): LayoutShadowNode { + return TabViewShadowNode() + } + + override fun getExportedCustomDirectEventTypeConstants(): MutableMap? { + return tabViewImpl.getExportedCustomDirectEventTypeConstants() } @ReactProp(name = "items") @@ -48,28 +70,24 @@ class RCTTabViewManager(context: ReactApplicationContext) : tabViewImpl.setIcons(view, icons) } - @ReactProp(name = "rippleColor") - fun setRippleColor(view: ReactBottomNavigationView, rippleColor: Int?) { - tabViewImpl.setRippleColor(view, rippleColor) - } - - public override fun createViewInstance(context: ThemedReactContext): ReactBottomNavigationView { - return tabViewImpl.createViewInstance(context) + @ReactProp(name = "barTintColor", customType = "Color") + fun setBarTintColor(view: ReactBottomNavigationView, color: Int?) { + tabViewImpl.setBarTintColor(view, color) } - override fun createShadowNodeInstance(): LayoutShadowNode { - return TabViewShadowNode(tabViewImpl.getViewInstance()) + @ReactProp(name = "rippleColor", customType = "Color") + fun setRippleColor(view: ReactBottomNavigationView, rippleColor: Int?) { + tabViewImpl.setRippleColor(view, rippleColor) } - companion object { - const val NAME = "RNCTabView" + @ReactProp(name = "activeTintColor", customType = "Color") + fun setActiveTintColor(view: ReactBottomNavigationView, color: Int?) { + tabViewImpl.setActiveTintColor(view, color) } - override fun getExportedCustomDirectEventTypeConstants(): MutableMap? { - return MapBuilder.of( - PageSelectedEvent.EVENT_NAME, - MapBuilder.of("registrationName", "onPageSelected"), - ) + @ReactProp(name = "inactiveTintColor", customType = "Color") + fun setInactiveTintColor(view: ReactBottomNavigationView, color: Int?) { + tabViewImpl.setInactiveTintColor(view, color) } // iOS Props @@ -85,4 +103,40 @@ class RCTTabViewManager(context: ReactApplicationContext) : @ReactProp(name = "disablePageAnimations") fun setDisablePageAnimations(view: ReactBottomNavigationView, flag: Boolean) { } + + class TabViewShadowNode() : LayoutShadowNode(), + YogaMeasureFunction { + private var mWidth = 0 + private var mHeight = 0 + private var mMeasured = false + + init { + initMeasureFunction() + } + + private fun initMeasureFunction() { + setMeasureFunction(this) + } + + override fun measure( + node: YogaNode, + width: Float, + widthMode: YogaMeasureMode, + height: Float, + heightMode: YogaMeasureMode + ): Long { + if (mMeasured) { + return YogaMeasureOutput.make(mWidth, mHeight) + } + + val tabView = ReactBottomNavigationView(themedContext) + val spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) + tabView.measure(spec, spec) + this.mWidth = tabView.measuredWidth + this.mHeight = tabView.measuredHeight + this.mMeasured = true + + return YogaMeasureOutput.make(mWidth, mHeight) + } + } } diff --git a/common/cpp/react/renderer/components/RNCTabView/RNCTabViewComponentDescriptor.h b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewComponentDescriptor.h new file mode 100644 index 00000000..9e80b06b --- /dev/null +++ b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewComponentDescriptor.h @@ -0,0 +1,47 @@ +#ifdef __cplusplus + +#pragma once + +#include +#include + +namespace facebook::react { + +class RNCTabViewComponentDescriptor final : public ConcreteComponentDescriptor +{ +#ifdef ANDROID +public: + RNCTabViewComponentDescriptor(const ComponentDescriptorParameters ¶meters) + : ConcreteComponentDescriptor(parameters), measurementsManager_( + std::make_shared(contextContainer_)) {} + + void adopt(ShadowNode &shadowNode) const override + { + ConcreteComponentDescriptor::adopt(shadowNode); + + auto &rncTabViewShadowNode = + static_cast(shadowNode); + + // `RNCTabViewShadowNode` uses `RNCTabViewMeasurementsManager` to + // provide measurements to Yoga. + rncTabViewShadowNode.setSliderMeasurementsManager( + measurementsManager_); + + // All `RNCTabViewShadowNode`s must have leaf Yoga nodes with properly + // setup measure function. + rncTabViewShadowNode.enableMeasurement(); + } + +private: + const std::shared_ptr measurementsManager_; +#else +public: + RNCTabViewComponentDescriptor(const ComponentDescriptorParameters ¶meters) + : ConcreteComponentDescriptor(parameters) {} +#endif + +}; + +} + +#endif diff --git a/common/cpp/react/renderer/components/RNCTabView/RNCTabViewMeasurementsManager.cpp b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewMeasurementsManager.cpp new file mode 100644 index 00000000..996da9f4 --- /dev/null +++ b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewMeasurementsManager.cpp @@ -0,0 +1,65 @@ +#ifdef ANDROID +#include "RNCTabViewMeasurementsManager.h" + +#include +#include +#include + + +using namespace facebook::jni; + +namespace facebook::react +{ +Size RNCTabViewMeasurementsManager::measure( + SurfaceId surfaceId, + LayoutConstraints layoutConstraints) const +{ + { + std::scoped_lock lock(mutex_); + if (hasBeenMeasured_) + { + return cachedMeasurement_; + } + } + + const jni::global_ref& fabricUIManager = + contextContainer_->at>("FabricUIManager"); + + static auto measure = facebook::jni::findClassStatic( + "com/facebook/react/fabric/FabricUIManager") + ->getMethod("measure"); + + auto minimumSize = layoutConstraints.minimumSize; + auto maximumSize = layoutConstraints.maximumSize; + + local_ref componentName = make_jstring("RNCTabView"); + + auto measurement = yogaMeassureToSize(measure( + fabricUIManager, + surfaceId, + componentName.get(), + nullptr, + nullptr, + nullptr, + minimumSize.width, + maximumSize.width, + minimumSize.height, + maximumSize.height)); + + std::scoped_lock lock(mutex_); + cachedMeasurement_ = measurement; + hasBeenMeasured_ = true; + return measurement; +} +} + +#endif diff --git a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.h b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewMeasurementsManager.h similarity index 82% rename from common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.h rename to common/cpp/react/renderer/components/RNCTabView/RNCTabViewMeasurementsManager.h index 1d6957bc..1882ac43 100644 --- a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.h +++ b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewMeasurementsManager.h @@ -1,3 +1,6 @@ +#ifdef __cplusplus + +#ifdef ANDROID #pragma once #include #include @@ -6,10 +9,10 @@ namespace facebook::react { - class RCTTabViewMeasurementsManagerNew + class RNCTabViewMeasurementsManager { public: - RCTTabViewMeasurementsManagerNew( + RNCTabViewMeasurementsManager( const ContextContainer::Shared &contextContainer) : contextContainer_(contextContainer) {} @@ -21,4 +24,8 @@ namespace facebook::react mutable bool hasBeenMeasured_ = false; mutable Size cachedMeasurement_{}; }; -} \ No newline at end of file +} + +#endif + +#endif diff --git a/common/cpp/react/renderer/components/RNCTabView/RNCTabViewShadowNode.cpp b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewShadowNode.cpp new file mode 100644 index 00000000..47867419 --- /dev/null +++ b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewShadowNode.cpp @@ -0,0 +1,28 @@ +#include "RNCTabViewShadowNode.h" +#include "RNCTabViewMeasurementsManager.h" + +namespace facebook::react { + +extern const char RNCTabViewComponentName[] = "RNCTabView"; + +#ifdef ANDROID +void RNCTabViewShadowNode::setSliderMeasurementsManager( + const std::shared_ptr & + measurementsManager) +{ + ensureUnsealed(); + measurementsManager_ = measurementsManager; +} + +#pragma mark - LayoutableShadowNode + +Size RNCTabViewShadowNode::measureContent( + const LayoutContext & /*layoutContext*/, + const LayoutConstraints &layoutConstraints) const +{ + return measurementsManager_->measure(getSurfaceId(), layoutConstraints); +} + +#endif + +} diff --git a/common/cpp/react/renderer/components/RNCTabView/RNCTabViewShadowNode.h b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewShadowNode.h new file mode 100644 index 00000000..c195794f --- /dev/null +++ b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewShadowNode.h @@ -0,0 +1,49 @@ +#ifdef __cplusplus + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "RNCTabViewMeasurementsManager.h" + +namespace facebook::react { + +JSI_EXPORT extern const char RNCTabViewComponentName[]; + +/* +* `ShadowNode` for component. +*/ +class JSI_EXPORT RNCTabViewShadowNode final +: public ConcreteViewShadowNode< +RNCTabViewComponentName, +RNCTabViewProps, +RNCTabViewEventEmitter, +RNCTabViewState> +{ +public: + using ConcreteViewShadowNode::ConcreteViewShadowNode; + +#ifdef ANDROID + void setSliderMeasurementsManager( + const std::shared_ptr &measurementsManager); + + #pragma mark - LayoutableShadowNode + + Size measureContent( + const LayoutContext &layoutContext, + const LayoutConstraints &layoutConstraints) const override; + +private: + std::shared_ptr measurementsManager_; +#endif + +}; + +} + +#endif diff --git a/common/cpp/react/renderer/components/RNCTabView/RNCTabViewState.h b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewState.h new file mode 100644 index 00000000..cabea07e --- /dev/null +++ b/common/cpp/react/renderer/components/RNCTabView/RNCTabViewState.h @@ -0,0 +1,35 @@ +#ifdef __cplusplus + +#pragma once + +#ifdef ANDROID +#include +#include +#include +#endif + +namespace facebook::react { + +class RNCTabViewState +{ +public: + RNCTabViewState() = default; + +#ifdef ANDROID + RNCTabViewState(RNCTabViewState const &previousState, folly::dynamic data) {}; + + folly::dynamic getDynamic() const + { + return {}; + }; + + MapBuffer getMapBuffer() const + { + return MapBufferBuilder::EMPTY(); + }; +#endif +}; + +} + +#endif diff --git a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewComponentDescriptor.h b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewComponentDescriptor.h deleted file mode 100644 index 1e560781..00000000 --- a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewComponentDescriptor.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include -#include "RCTTabViewMeasurementsManager.h" - -namespace facebook -{ - namespace react - { - - class RCTTabViewComponentDescriptor final - : public ConcreteComponentDescriptor - { - public: - RCTTabViewComponentDescriptor(const ComponentDescriptorParameters ¶meters) - : ConcreteComponentDescriptor(parameters), measurementsManager_( - std::make_shared(contextContainer_)) {} - - void adopt(ShadowNode &shadowNode) const override - { - ConcreteComponentDescriptor::adopt(shadowNode); - - auto &rctTabViewShadowNode = - static_cast(shadowNode); - - // `RCTTabViewShadowNode` uses `RCTTabViewMeasurementsManager` to - // provide measurements to Yoga. - rctTabViewShadowNode.setSliderMeasurementsManager( - measurementsManager_); - - // All `RCTTabViewShadowNode`s must have leaf Yoga nodes with properly - // setup measure function. - rctTabViewShadowNode.enableMeasurement(); - } - - private: - const std::shared_ptr measurementsManager_; - }; - - } -} diff --git a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.cpp b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.cpp deleted file mode 100644 index 9b74fff1..00000000 --- a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewMeasurementsManager.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "RCTTabViewMeasurementsManager.h" - -#include -#include -#include - -using namespace facebook::jni; - -namespace facebook::react -{ - - Size RCTTabViewMeasurementsManagerNew::measure( - SurfaceId surfaceId, - LayoutConstraints layoutConstraints) const - { - { - std::scoped_lock lock(mutex_); - if (hasBeenMeasured_) - { - return cachedMeasurement_; - } - } - - const jni::global_ref &fabricUIManager = - contextContainer_->at>("FabricUIManager"); - - static auto measure = - jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") - ->getMethod("measure"); - - auto minimumSize = layoutConstraints.minimumSize; - auto maximumSize = layoutConstraints.maximumSize; - - local_ref componentName = make_jstring("RNCTabView"); - - auto measurement = yogaMeassureToSize(measure( - fabricUIManager, - surfaceId, - componentName.get(), - nullptr, - nullptr, - nullptr, - minimumSize.width, - maximumSize.width, - minimumSize.height, - maximumSize.height)); - - std::scoped_lock lock(mutex_); - cachedMeasurement_ = measurement; - hasBeenMeasured_ = true; - return measurement; - } - -} diff --git a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.cpp b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.cpp deleted file mode 100644 index a42a9e0b..00000000 --- a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "RCTTabViewShadowNode.h" -#include "RCTTabViewMeasurementsManager.h" - -namespace facebook -{ - namespace react - { - - extern const char RCTTabViewComponentName[] = "RCTTabView"; - - void RCTTabViewShadowNode::setSliderMeasurementsManager( - const std::shared_ptr & - measurementsManager) - { - ensureUnsealed(); - measurementsManager_ = measurementsManager; - } - -#pragma mark - LayoutableShadowNode - - Size RCTTabViewShadowNode::measureContent( - const LayoutContext & /*layoutContext*/, - const LayoutConstraints &layoutConstraints) const - { - return measurementsManager_->measure(getSurfaceId(), layoutConstraints); - } - - } -} \ No newline at end of file diff --git a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.h b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.h deleted file mode 100644 index 20aca8c4..00000000 --- a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewShadowNode.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "RCTTabViewMeasurementsManager.h" - -namespace facebook -{ - namespace react - { - - JSI_EXPORT extern const char RCTTabViewComponentName[]; - - /* - * `ShadowNode` for component. - */ - class JSI_EXPORT RCTTabViewShadowNode final - : public ConcreteViewShadowNode< - RCTTabViewComponentName, - RCTTabViewProps, - RCTTabViewEventEmitter, - RCTTabViewState> - { - public: - using ConcreteViewShadowNode::ConcreteViewShadowNode; - - void setSliderMeasurementsManager( - const std::shared_ptr &measurementsManager); - -#pragma mark - LayoutableShadowNode - - Size measureContent( - const LayoutContext &layoutContext, - const LayoutConstraints &layoutConstraints) const override; - - private: - std::shared_ptr measurementsManager_; - }; - - } -} \ No newline at end of file diff --git a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewState.h b/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewState.h deleted file mode 100644 index c3845888..00000000 --- a/common/cpp/react/renderer/components/RNCTabViewSpec/RCTTabViewState.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace facebook -{ - namespace react - { - - class RCTTabViewState - { - public: - RCTTabViewState() = default; - - RCTTabViewState(RCTTabViewState const &previousState, folly::dynamic data) {}; - folly::dynamic getDynamic() const - { - return {}; - }; - MapBuffer getMapBuffer() const - { - return MapBufferBuilder::EMPTY(); - }; - }; - - } -} \ No newline at end of file diff --git a/ios/Fabric/RCTTabViewComponentView.mm b/ios/Fabric/RCTTabViewComponentView.mm index b4d1e0fb..c24dbfb3 100644 --- a/ios/Fabric/RCTTabViewComponentView.mm +++ b/ios/Fabric/RCTTabViewComponentView.mm @@ -1,10 +1,11 @@ #ifdef RCT_NEW_ARCH_ENABLED #import "RCTTabViewComponentView.h" -#import -#import -#import -#import +#import +#import +#import +#import +#import #import diff --git a/package.json b/package.json index 2dcb781e..ead3ab7d 100644 --- a/package.json +++ b/package.json @@ -205,7 +205,7 @@ "use-latest-callback": "^0.2.1" }, "codegenConfig": { - "name": "RNCTabViewSpec", + "name": "RNCTabView", "type": "components", "jsSrcsDir": "src", "android": { diff --git a/react-native.config.js b/react-native.config.js index 3a76e9a4..b3ebd7d7 100644 --- a/react-native.config.js +++ b/react-native.config.js @@ -2,8 +2,8 @@ module.exports = { dependency: { platforms: { android: { - libraryName: 'RNCTabViewSpec', - componentDescriptors: ['RCTTabViewComponentDescriptor'], + libraryName: 'RNCTabView', + componentDescriptors: ['RNCTabViewComponentDescriptor'], cmakeListsPath: 'src/main/jni/CMakeLists.txt', }, }, From 82a173756bd8600b1a9aaf7ca41a45c8da8c7be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Sun, 27 Oct 2024 19:16:18 +0100 Subject: [PATCH 5/6] fix: albums example on new arch --- example/src/Screens/Albums.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/example/src/Screens/Albums.tsx b/example/src/Screens/Albums.tsx index 4cb7a381..cf87f64d 100644 --- a/example/src/Screens/Albums.tsx +++ b/example/src/Screens/Albums.tsx @@ -87,7 +87,6 @@ const styles = StyleSheet.create({ }), photo: { flex: 1, - paddingTop: '100%', height: 'auto', width: 'auto', }, From 305ad8c331c2a0ff152ec3e4f016102218e03857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Mon, 28 Oct 2024 09:44:08 +0100 Subject: [PATCH 6/6] ci: add new arch job --- .github/workflows/ci.yml | 56 +++++++++++++++++++++++++++++++ example/android/gradle.properties | 2 +- example/package.json | 1 + turbo.json | 16 +++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abccd9dd..c9b452e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,6 +107,62 @@ jobs: run: | yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" + build-android-newarch: + runs-on: ubuntu-latest + env: + TURBO_CACHE_DIR: .turbo/android-newarch + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup + uses: ./.github/actions/setup + + - name: Cache turborepo for Android new arch + uses: actions/cache@v3 + with: + path: ${{ env.TURBO_CACHE_DIR }} + key: ${{ runner.os }}-turborepo-android-newarch-${{ hashFiles('yarn.lock') }} + restore-keys: | + ${{ runner.os }}-turborepo-android-newarch- + + - name: Check turborepo cache for Android new arch + run: | + TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android:fabric --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android:fabric').cache.status") + + if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then + echo "turbo_cache_hit=1" >> $GITHUB_ENV + fi + + - name: Install JDK + if: env.turbo_cache_hit != 1 + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: '17' + + - name: Finalize Android SDK + if: env.turbo_cache_hit != 1 + run: | + /bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null" + + - name: Cache Gradle + if: env.turbo_cache_hit != 1 + uses: actions/cache@v3 + with: + path: | + ~/.gradle/wrapper + ~/.gradle/caches + key: ${{ runner.os }}-gradle-newarch-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle-newarch- + + - name: Build example for Android new arch + env: + JAVA_OPTS: "-XX:MaxHeapSize=6g" + run: | + yarn turbo run build:android:fabric --cache-dir="${{ env.TURBO_CACHE_DIR }}" + build-ios: runs-on: macos-15 env: diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 490e2deb..66ddb865 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -40,7 +40,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # to write custom TurboModules/Fabric components OR use libraries that # are providing them. # Note that this is incompatible with web debugging. -newArchEnabled=true +newArchEnabled=false #bridgelessEnabled=true # Uncomment the line below to build React Native from source. diff --git a/example/package.json b/example/package.json index 6e05fd86..9d3ad77a 100644 --- a/example/package.json +++ b/example/package.json @@ -5,6 +5,7 @@ "scripts": { "android": "react-native run-android", "build:android": "npm run mkdist && react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist && react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"", + "build:android:fabric": "npm run mkdist && react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist && react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a -PnewArchEnabled=true\"", "build:ios": "npm run mkdist && react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist && react-native build-ios --scheme ReactNativeBottomTabs --mode Debug --extra-params \"-sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO\"", "build:visionos": "npm run mkdist && react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.visionos.jsbundle --assets-dest dist", "ios": "react-native run-ios", diff --git a/turbo.json b/turbo.json index 405897ee..196b8aaa 100644 --- a/turbo.json +++ b/turbo.json @@ -17,6 +17,22 @@ ], "outputs": [] }, + "build:android:fabric": { + "env": ["ORG_GRADLE_PROJECT_newArchEnabled"], + "inputs": [ + "package.json", + "android", + "!android/build", + "src/*.ts", + "src/*.tsx", + "example/package.json", + "example/android", + "!example/android/.gradle", + "!example/android/build", + "!example/android/app/build" + ], + "outputs": [] + }, "build:ios": { "env": ["RCT_NEW_ARCH_ENABLED"], "inputs": [