Skip to content
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

feat: OverKeyboardView with custom ShadowNode #863

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion .github/workflows/verify-android.yml
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ jobs:
curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.1/detekt-cli-1.23.1.zip
unzip detekt-cli-1.23.1.zip
- name: Run Detekt
run: ./detekt-cli-1.23.1/bin/detekt-cli
run: ./detekt-cli-1.23.1/bin/detekt-cli --config detekt.yml --build-upon-default-config
unit-tests:
name: 📖 Unit tests
runs-on: ubuntu-latest
4 changes: 3 additions & 1 deletion .github/workflows/verify-cpp.yml
Original file line number Diff line number Diff line change
@@ -7,10 +7,12 @@ on:
paths:
- ".github/workflows/verify-cpp.yml"
- "android/src/main/**"
- "common/cpp/**"
pull_request:
paths:
- ".github/workflows/verify-cpp.yml"
- "android/src/main/**"
- "common/cpp/**"

jobs:
lint:
@@ -33,4 +35,4 @@ jobs:
python -m pip install --upgrade pip
pip install cpplint
- name: Run cpplint
run: cpplint --linelength=230 --filter=-legal/copyright,-readability/todo,-build/namespaces,-whitespace/comments,-build/c++11,-runtime/int,-runtime/references --quiet --recursive android/src/main/
run: cpplint --linelength=230 --filter=-legal/copyright,-readability/todo,-build/namespaces,-whitespace/comments,-build/c++11,-runtime/int,-runtime/references,-whitespace/indent_namespace --quiet --recursive android/src/main/ common/cpp/
24 changes: 23 additions & 1 deletion FabricExample/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1283,6 +1283,28 @@ PODS:
- ReactCommon/turbomodule/core
- Yoga
- react-native-keyboard-controller (1.16.8):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2024.11.18.00)
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- react-native-keyboard-controller/common (= 1.16.8)
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-keyboard-controller/common (1.16.8):
- DoubleConversion
- glog
- hermes-engine
@@ -2164,7 +2186,7 @@ SPEC CHECKSUMS:
React-Mapbuffer: 0502faf46cab8fb89cfc7bf3e6c6109b6ef9b5de
React-microtasksnativemodule: 663bc64e3a96c5fc91081923ae7481adc1359a78
react-native-blur: b37343d4df1af48a17444156b674b26d5aec2425
react-native-keyboard-controller: b9280bc833465038d4805dbd4ca66660f7f0dcd3
react-native-keyboard-controller: ef23fc10134fc24ab13d331afe1fbc33374f185a
react-native-safe-area-context: 9c33120e9eac7741a5364cc2d9f74665049b76b3
React-NativeModulesApple: 16fbd5b040ff6c492dacc361d49e63cba7a6a7a1
React-perflogger: ab51b7592532a0ea45bf6eed7e6cae14a368b678
1 change: 1 addition & 0 deletions FabricExample/src/screens/Examples/Toolbar/index.tsx
Original file line number Diff line number Diff line change
@@ -231,6 +231,7 @@ const styles = StyleSheet.create({
right: 0,
},
header: {
color: "black",
marginRight: 12,
},
modal: {
3 changes: 3 additions & 0 deletions android/detekt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
complexity:
TooManyFunctions:
ignoreOverridden: true
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@ package com.reactnativekeyboardcontroller

import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.LayoutShadowNode
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
@@ -30,6 +32,15 @@ class OverKeyboardViewManager(

override fun getShadowNodeClass(): Class<out LayoutShadowNode> = OverKeyboardHostShadowNode::class.java

override fun updateState(
view: OverKeyboardHostView,
props: ReactStylesDiffMap,
stateWrapper: StateWrapper,
): Any? {
view.stateWrapper = stateWrapper
return null
}

@ReactProp(name = "visible")
override fun setVisible(
view: OverKeyboardHostView,
Original file line number Diff line number Diff line change
@@ -7,12 +7,17 @@ import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.bridge.WritableMap
import com.facebook.react.bridge.WritableNativeMap
import com.facebook.react.config.ReactFeatureFlags
import com.facebook.react.uimanager.JSTouchDispatcher
import com.facebook.react.uimanager.StateWrapper
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.uimanager.events.EventDispatcher
import com.facebook.react.views.view.ReactViewGroup
import com.reactnativekeyboardcontroller.extensions.dp
import com.reactnativekeyboardcontroller.extensions.getDisplaySize

@SuppressLint("ViewConstructor")
class OverKeyboardHostView(
@@ -22,6 +27,8 @@ class OverKeyboardHostView(
private var windowManager: WindowManager = reactContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private var hostView: OverKeyboardRootViewGroup = OverKeyboardRootViewGroup(reactContext)

internal var stateWrapper: StateWrapper? = null

init {
hostView.eventDispatcher = dispatcher
}
@@ -82,14 +89,24 @@ class OverKeyboardHostView(
PixelFormat.TRANSLUCENT,
)

stretchTo(fullScreen = true)
windowManager.addView(hostView, layoutParams)
}

fun hide() {
if (hostView.isAttached) {
windowManager.removeView(hostView)
stretchTo(fullScreen = false)
}
}

private fun stretchTo(fullScreen: Boolean) {
val displaySize = reactContext.getDisplaySize()
val newStateData: WritableMap = WritableNativeMap()
newStateData.putDouble("screenWidth", if (fullScreen) displaySize.x.toFloat().dp else 0.0)
newStateData.putDouble("screenHeight", if (fullScreen) displaySize.y.toFloat().dp else 0.0)
stateWrapper?.updateState(newStateData)
}
}

@SuppressLint("ViewConstructor")
85 changes: 85 additions & 0 deletions android/src/main/jni/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE ON)

set(LIB_LITERAL reactnativekeyboardcontroller)
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_COMMON_COMPONENTS_DIR ${LIB_COMMON_DIR}/react/renderer/components/${LIB_LITERAL})
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
-Wno-dollar-in-identifier-extension
)

file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS *.cpp ${LIB_COMMON_COMPONENTS_DIR}/*.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}
)

if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
target_link_libraries(
${LIB_TARGET_NAME}
ReactAndroid::reactnative
ReactAndroid::jsi
fbjni::fbjni
)
else()
target_link_libraries(
${LIB_TARGET_NAME}
fbjni
folly_runtime
glog
jsi
react_codegen_rncore
react_debug
react_nativemodule_core
react_render_core
react_render_debug
react_render_graphics
react_render_mapbuffer
react_render_componentregistry
react_utils
rrc_view
turbomodulejsijni
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}
)
23 changes: 23 additions & 0 deletions android/src/main/jni/reactnativekeyboardcontroller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <ReactCommon/JavaTurboModule.h>
#include <ReactCommon/TurboModule.h>
#include <jsi/jsi.h>

/**
* Note this import and that it is not present in autogenerated header file
* under android/build/generated/source/codegen/jni/reactnativekeyboardcontroller.h
*
* Here we are overriding autogenerated component descriptors by prioritizing our custom headers via include path setup.
*/
#include <react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardControllerViewComponentDescriptor.h>
#include <react/renderer/components/reactnativekeyboardcontroller/RNKCKeyboardGestureAreaComponentDescriptor.h>
#include <react/renderer/components/reactnativekeyboardcontroller/RNKCOverKeyboardViewComponentDescriptor.h>

#include <memory>
#include <string>

namespace facebook::react {
JSI_EXPORT
std::shared_ptr<TurboModule> reactnativekeyboardcontroller_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params);
} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "RNKCKeyboardControllerViewShadowNode.h"

#include <react/debug/react_native_assert.h>
#include <react/renderer/components/reactnativekeyboardcontroller/Props.h>
#include <react/renderer/core/ConcreteComponentDescriptor.h>

namespace facebook::react {

class KeyboardControllerViewComponentDescriptor final
: public ConcreteComponentDescriptor<KeyboardControllerViewShadowNode> {
public:
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
void adopt(ShadowNode &shadowNode) const override {
react_native_assert(dynamic_cast<KeyboardControllerViewShadowNode *>(&shadowNode));
ConcreteComponentDescriptor::adopt(shadowNode);
}
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "RNKCKeyboardControllerViewShadowNode.h"

namespace facebook::react {

extern const char KeyboardControllerViewComponentName[] = "KeyboardControllerView";

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "RNKCKeyboardControllerViewState.h"

#include <react/renderer/components/reactnativekeyboardcontroller/EventEmitters.h>
#include <react/renderer/components/reactnativekeyboardcontroller/Props.h>
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <jsi/jsi.h>

namespace facebook::react {

JSI_EXPORT extern const char KeyboardControllerViewComponentName[];

/*
* `ShadowNode` for <KeyboardControllerView> component.
*/
using KeyboardControllerViewShadowNode = ConcreteViewShadowNode<
KeyboardControllerViewComponentName,
KeyboardControllerViewProps,
KeyboardControllerViewEventEmitter,
KeyboardControllerViewState>;

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#ifdef ANDROID
#include <folly/dynamic.h>
#endif

namespace facebook::react {

class KeyboardControllerViewState {
public:
KeyboardControllerViewState() = default;

#ifdef ANDROID
KeyboardControllerViewState(KeyboardControllerViewState const &previousState, folly::dynamic data) {}
folly::dynamic getDynamic() const {
return {};
}
#endif
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include "RNKCKeyboardGestureAreaShadowNode.h"

#include <react/debug/react_native_assert.h>
#include <react/renderer/components/reactnativekeyboardcontroller/Props.h>
#include <react/renderer/core/ConcreteComponentDescriptor.h>

namespace facebook::react {
class KeyboardGestureAreaComponentDescriptor final
: public ConcreteComponentDescriptor<KeyboardGestureAreaShadowNode> {
public:
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
void adopt(ShadowNode &shadowNode) const override {
react_native_assert(dynamic_cast<KeyboardGestureAreaShadowNode *>(&shadowNode));
ConcreteComponentDescriptor::adopt(shadowNode);
}
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "RNKCKeyboardGestureAreaShadowNode.h"

namespace facebook::react {

extern const char KeyboardGestureAreaComponentName[] = "KeyboardGestureArea";

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "RNKCKeyboardGestureAreaState.h"

#include <react/renderer/components/reactnativekeyboardcontroller/EventEmitters.h>
#include <react/renderer/components/reactnativekeyboardcontroller/Props.h>
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
#include <jsi/jsi.h>

namespace facebook::react {

JSI_EXPORT extern const char KeyboardGestureAreaComponentName[];

/*
* `ShadowNode` for <KeyboardGestureArea> component.
*/
using KeyboardGestureAreaShadowNode = ConcreteViewShadowNode<
KeyboardGestureAreaComponentName,
KeyboardGestureAreaProps,
KeyboardGestureAreaEventEmitter,
KeyboardGestureAreaState>;

} // namespace facebook::react
Loading