Skip to content

feat: rewrite to ShadowNodes (again...) #331

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/example/src/Screens/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export function Article({
console.log(Platform.OS, ' Rendering Article');
return (
<ScrollView
onLayout={({ nativeEvent: { layout } }) => console.log(layout)}
ref={ref}
style={{ backgroundColor: '#fff' }}
contentContainerStyle={styles.content}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import android.util.Log
import android.util.Size
import android.util.TypedValue
import android.view.Choreographer
import android.view.Gravity
import android.view.HapticFeedbackConstants
import android.view.MenuItem
import android.view.View
Expand Down Expand Up @@ -72,16 +73,19 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {

addView(
layoutHolder, LayoutParams(
LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
0,
).apply { weight = 1f }
)
.apply { weight = 1f }
)
layoutHolder.isSaveEnabled = false

addView(bottomNavigation, LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
))
).apply {
gravity = Gravity.BOTTOM
})
uiModeConfiguration = resources.configuration.uiMode

post {
Expand Down Expand Up @@ -142,9 +146,11 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
return
}

val container = createContainer()
container.addView(child, params)
layoutHolder.addView(container, index)
// val container = createContainer()
// container.addView(child, params)
child.visibility = GONE
child.isEnabled = false
layoutHolder.addView(child, index)

val itemKey = items[index].key
if (selectedItem == itemKey) {
Expand All @@ -153,18 +159,18 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
}
}

private fun createContainer(): FrameLayout {
val container = FrameLayout(context).apply {
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
isSaveEnabled = false
visibility = GONE
isEnabled = false
}
return container
}
// private fun createContainer(): FrameLayout {
// val container = FrameLayout(context).apply {
// layoutParams = FrameLayout.LayoutParams(
// FrameLayout.LayoutParams.MATCH_PARENT,
// FrameLayout.LayoutParams.MATCH_PARENT
// )
// isSaveEnabled = false
// visibility = GONE
// isEnabled = false
// }
// return container
// }

private fun setSelectedIndex(itemId: Int) {
bottomNavigation.selectedItemId = itemId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class RCTTabViewPackage : ReactPackage {
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
val viewManagers: MutableList<ViewManager<*, *>> = ArrayList()
viewManagers.add(RCTTabViewManager(reactContext))
viewManagers.add(RCTTabViewScreenManager(reactContext))
return viewManagers
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE ON)

set(LIB_LITERAL RNCTabView)
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}
)

# 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
)

target_include_directories(
${CMAKE_PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <ReactCommon/JavaTurboModule.h>
#include <ReactCommon/TurboModule.h>
#include <jsi/jsi.h>
#include <react/renderer/components/RNCTabView/RNCTabViewScreenComponentDescriptor.h>

namespace facebook::react {
JSI_EXPORT
std::shared_ptr<TurboModule> RNCTabView_ModuleProvider(
const std::string &moduleName,
const JavaTurboModule::InitParams &params);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.rcttabview

import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.children
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.module.annotations.ReactModule
Expand All @@ -11,7 +13,6 @@ import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.ViewManagerDelegate
import com.facebook.react.viewmanagers.RNCTabViewManagerDelegate
import com.facebook.react.viewmanagers.RNCTabViewManagerInterface
import com.rcttabview.events.OnNativeLayoutEvent
import com.rcttabview.events.PageSelectedEvent
import com.rcttabview.events.TabLongPressEvent

Expand All @@ -36,9 +37,21 @@ class RCTTabViewManager(context: ReactApplicationContext) :
eventDispatcher?.dispatchEvent(TabLongPressEvent(viewTag = view.id, key))
}

view.onNativeLayoutListener = { width, height ->
eventDispatcher?.dispatchEvent(OnNativeLayoutEvent(viewTag = view.id, width, height))
}
// view.onNativeLayoutListener = { width, height ->
// val childCount = tabViewImpl.getChildCount(view)
// for (i in 0 until childCount) { // Use 'until' instead of '..' to exclude childCount
// val child = tabViewImpl.getChildAt(view, i)
//
// // Safe cast for FrameLayout
// if (child is RCTTabViewScreen) {
// child.updateFrame(width, height)
//
// Log.w("TAB_VIEW", "CHILD: ${child}")
// }
// }
//
//// eventDispatcher?.dispatchEvent(OnNativeLayoutEvent(viewTag = view.id, width, height))
// }
return view

}
Expand Down Expand Up @@ -72,9 +85,9 @@ class RCTTabViewManager(context: ReactApplicationContext) :
tabViewImpl.removeViewAt(parent, index)
}

override fun needsCustomLayoutForChildren(): Boolean {
return tabViewImpl.needsCustomLayoutForChildren()
}
// override fun needsCustomLayoutForChildren(): Boolean {
// return tabViewImpl.needsCustomLayoutForChildren()
// }

override fun setItems(view: ReactBottomNavigationView?, value: ReadableArray?) {
if (view != null && value != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.rcttabview

import android.content.Context
import android.os.Build
import android.util.Log
import android.view.View
import android.view.WindowInsets
import android.view.WindowManager
import android.widget.FrameLayout
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.ReactStylesDiffMap
import com.facebook.react.uimanager.StateWrapper
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.ViewManagerDelegate
import com.facebook.react.viewmanagers.RNCTabViewScreenManagerDelegate
import com.facebook.react.viewmanagers.RNCTabViewScreenManagerInterface
import com.facebook.react.views.view.ReactViewGroup

class RCTTabViewScreen(context: Context): ReactViewGroup(context) {
private var stateWrapper: StateWrapper? = null

public fun setStateWrapper(stateWrapper: StateWrapper?) {
this.stateWrapper = stateWrapper
}

init {
getSystemInsets(this) { left, top, right, bottom ->
Log.w("TAB_VIEW", "${left} ${top} ${right} ${bottom}")

stateWrapper?.updateState(Arguments.createMap().apply {
putDouble("width", Utils.convertPixelsToDp(context, width))
putDouble("height", Utils.convertPixelsToDp(context, height - bottom))
})
}
}

fun getSystemInsets(view: View, callback: (left: Int, top: Int, right: Int, bottom: Int) -> Unit) {
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
callback(
systemBars.left, // Left inset (for left-aligned Navigation Rail)
systemBars.top, // Top inset
systemBars.right, // Right inset (for right-aligned Navigation Rail)
systemBars.bottom // Bottom inset (for bottom navigation)
)
insets
}
// Ensure we request insets
if (view.isAttachedToWindow) {
ViewCompat.requestApplyInsets(view)
} else {
view.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
ViewCompat.requestApplyInsets(v)
v.removeOnAttachStateChangeListener(this)
}
override fun onViewDetachedFromWindow(v: View) = Unit
})
}
}
}


@ReactModule(name = "RNCTabViewScreen")
class RCTTabViewScreenManager(context: ReactApplicationContext) :
ViewGroupManager<RCTTabViewScreen>(),
RNCTabViewScreenManagerInterface<RCTTabViewScreen> {

private val delegate: RNCTabViewScreenManagerDelegate<RCTTabViewScreen, RCTTabViewScreenManager> =
RNCTabViewScreenManagerDelegate(this)


override fun createViewInstance(context: ThemedReactContext): RCTTabViewScreen {
return RCTTabViewScreen(context);
}

override fun updateState(
view: RCTTabViewScreen,
props: ReactStylesDiffMap?,
stateWrapper: StateWrapper?
): Any? {
view.setStateWrapper(stateWrapper)
return super.updateState(view, props, stateWrapper)
}

override fun getDelegate(): ViewManagerDelegate<RCTTabViewScreen> {
return delegate
}

override fun getName(): String {
return "RNCTabViewScreen"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifdef __cplusplus

#pragma once

#include <react/renderer/components/RNCTabView/RNCTabViewScreenShadowNode.h>
#include <react/renderer/core/ConcreteComponentDescriptor.h>

namespace facebook::react {

class RNCTabViewScreenComponentDescriptor final : public ConcreteComponentDescriptor<RNCTabViewScreenShadowNode>
{
public:
RNCTabViewScreenComponentDescriptor(const ComponentDescriptorParameters &parameters)
: ConcreteComponentDescriptor(parameters) {}


/**
Retrieve shadow node's state and update it's layout size accordingly.
This is needed because we need to accomodate for bottom bar / sidebar size.
*/
void adopt(ShadowNode &shadowNode) const override {
auto& layoutableShadowNode = static_cast<RNCTabViewScreenShadowNode&>(shadowNode);
auto& stateData = layoutableShadowNode.getStateData();

layoutableShadowNode.setSize(stateData.frameSize);

ConcreteComponentDescriptor::adopt(shadowNode);
}
};

}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "RNCTabViewScreenShadowNode.h"

namespace facebook::react {

extern const char RNCTabViewScreenComponentName[] = "RNCTabViewScreen";

}
Loading