diff --git a/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt b/android/src/main/java/com/rcttabview/RCTTabViewImpl.kt similarity index 56% rename from android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt rename to android/src/main/java/com/rcttabview/RCTTabViewImpl.kt index ed374c85..b7951eec 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,12 +55,11 @@ 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) } @@ -80,15 +76,15 @@ class RCTTabViewViewManager : view.setRippleColor(color) } } - @ReactProp(name = "translucent") fun setTranslucentview(view: ReactBottomNavigationView, translucent: Boolean?) { } - - 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)) } @@ -96,69 +92,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/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/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..b8dc3a6f --- /dev/null +++ b/android/src/newarch/RCTTabViewManager.kt @@ -0,0 +1,123 @@ +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 contextInner: 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 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) + } + + 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) + } + + override fun setBarTintColor(view: ReactBottomNavigationView?, value: Int?) { + + } + + override fun setTranslucent(view: ReactBottomNavigationView?, value: Boolean) { + } + +} 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/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/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. 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, +});