Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module.exports = {
'folders',
'filename-rules',
],
ignorePatterns: [".eslintrc.js"],
ignorePatterns: [".eslintrc.js", "*.config.js"],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
Expand Down
3 changes: 0 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@ android {
if (isNewArchitectureEnabled()) {
java.srcDirs += [
"src/newarch",
// Codegen specs
"generated/java",
"generated/jni"
]
} else {
java.srcDirs += ["src/oldarch"]
Expand Down
14 changes: 14 additions & 0 deletions android/src/main/java/com/multiplemodals/RNTModalShadowView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.multiplemodals

import com.facebook.react.uimanager.LayoutShadowNode
import com.facebook.react.uimanager.ReactShadowNodeImpl
import com.multiplemodals.library.ModalHostHelper

internal class RNTModalShadowView : LayoutShadowNode() {
override fun addChildAt(child: ReactShadowNodeImpl, i: Int) {
super.addChildAt(child, i)
val modalSize = ModalHostHelper.getModalHostSize(themedContext)
child.setStyleWidth(modalSize.x.toFloat())
child.setStyleHeight(modalSize.y.toFloat())
}
}
19 changes: 18 additions & 1 deletion android/src/main/java/com/multiplemodals/RNTModalView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewStructure
import android.view.accessibility.AccessibilityEvent
import android.widget.FrameLayout
import com.facebook.react.bridge.LifecycleEventListener
import com.facebook.react.bridge.UiThreadUtil
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
Expand All @@ -21,12 +23,25 @@ class RNTModalView(context: Context): ViewGroup(context), LifecycleEventListener
const val REACT_CLASS: String = "RNTModalView"
}

public var stateWrapper: StateWrapper?
get() = modalView.stateWrapper
public set(stateWrapper) {
modalView.stateWrapper = stateWrapper
}

private val surfaceId: Int get() = UIManagerHelper.getSurfaceId(this)

override fun setId(id: Int) {
super.setId(id)
// Id is passed to control shadow node size
modalView.id = id
}

private val reactContext: ThemedReactContext get() = context as ThemedReactContext
private val eventDispatcher: EventDispatcher
private val modalDialog: ModalDialog
private val modalView: ModalView
private val contentView: FrameLayout

init {
this.reactContext.addLifecycleEventListener(this)
Expand All @@ -37,6 +52,7 @@ class RNTModalView(context: Context): ViewGroup(context), LifecycleEventListener

modalDialog = ModalDialog(reactContext, R.style.Theme_FullScreenDialog)
modalView = ModalView(reactContext, eventDispatcher)
contentView = FrameLayout(context)

attackBackHandler()
} else {
Expand All @@ -45,6 +61,8 @@ class RNTModalView(context: Context): ViewGroup(context), LifecycleEventListener
}

fun show() {
contentView.addView(modalView)
modalDialog.addContent(contentView)
modalDialog.show()
}

Expand Down Expand Up @@ -93,7 +111,6 @@ class RNTModalView(context: Context): ViewGroup(context), LifecycleEventListener
}

modalView.addView(subview, atIndex)
modalDialog.addContent(modalView)
}

override fun getChildCount(): Int {
Expand Down
16 changes: 16 additions & 0 deletions android/src/main/java/com/multiplemodals/RNTModalViewManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package com.multiplemodals

import com.facebook.react.common.MapBuilder
import com.facebook.react.module.annotations.ReactModule
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.multiplemodals.events.PressBackEvent

Expand All @@ -13,6 +16,10 @@ class RNTModalViewManager : RNTModalViewManagerSpec<RNTModalView>() {
return RNTModalView(reactContext)
}

override fun createShadowNodeInstance(): LayoutShadowNode {
return RNTModalShadowView()
}

override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
val buildOf = "registrationName"

Expand All @@ -30,4 +37,13 @@ class RNTModalViewManager : RNTModalViewManagerSpec<RNTModalView>() {
super.onAfterUpdateTransaction(view)
view.show()
}

override fun updateState(
view: RNTModalView,
props: ReactStylesDiffMap,
stateWrapper: StateWrapper
): Any? {
view.stateWrapper = stateWrapper
return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.multiplemodals.library
import android.app.Dialog
import android.os.Bundle
import android.view.WindowManager.LayoutParams
import android.widget.FrameLayout
import com.facebook.react.uimanager.ThemedReactContext

class ModalDialog(private val reactContext: ThemedReactContext, themeId: Int) : Dialog(reactContext, themeId) {
Expand All @@ -28,7 +29,7 @@ class ModalDialog(private val reactContext: ThemedReactContext, themeId: Int) :
}
}

fun addContent(view: ModalView) {
fun addContent(view: FrameLayout) {
setContentView(view)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.multiplemodals.library

import android.R
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Point
import android.view.WindowManager
import com.facebook.infer.annotation.Assertions

internal object ModalHostHelper {
private val MIN_POINT = Point()
private val MAX_POINT = Point()
private val SIZE_POINT = Point()

@SuppressLint("InternalInsetResource")
fun getModalHostSize(context: Context): Point {
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val display = Assertions.assertNotNull(wm).defaultDisplay
// getCurrentSizeRange will return the min and max width and height that the window can be
display.getCurrentSizeRange(MIN_POINT, MAX_POINT)
// getSize will return the dimensions of the screen in its current orientation
display.getSize(SIZE_POINT)

val attrs = intArrayOf(R.attr.windowFullscreen)
val theme = context.theme
val ta = theme.obtainStyledAttributes(attrs)
val windowFullscreen = ta.getBoolean(0, false)

// We need to add the status bar height to the height if we have a fullscreen window,
// because Display.getCurrentSizeRange doesn't include it.
val resources = context.resources
val statusBarId = resources.getIdentifier("status_bar_height", "dimen", "android")
var statusBarHeight = 0
if (windowFullscreen && statusBarId > 0) {
statusBarHeight = resources.getDimension(statusBarId).toInt()
}

return if (SIZE_POINT.x < SIZE_POINT.y) {
// If we are vertical the width value comes from min width and height comes from max height
Point(MIN_POINT.x, MAX_POINT.y + statusBarHeight)
} else {
// If we are horizontal the width value comes from max width and height comes from min height
Point(MAX_POINT.x, MIN_POINT.y + statusBarHeight)
}
}
}
44 changes: 44 additions & 0 deletions android/src/main/java/com/multiplemodals/library/ModalView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ package com.multiplemodals.library
import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
import androidx.annotation.UiThread
import com.facebook.react.bridge.GuardedRunnable
import com.facebook.react.bridge.WritableMap
import com.facebook.react.bridge.WritableNativeMap
import com.facebook.react.config.ReactFeatureFlags
import com.facebook.react.uimanager.JSPointerDispatcher
import com.facebook.react.uimanager.JSTouchDispatcher
import com.facebook.react.uimanager.PixelUtil
import com.facebook.react.uimanager.RootView
import com.facebook.react.uimanager.StateWrapper
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerModule
import com.facebook.react.uimanager.events.EventDispatcher
import com.facebook.react.views.view.ReactViewGroup

Expand All @@ -16,13 +23,50 @@ class ModalView(private val reactContext: ThemedReactContext,
private val eventDispatcher: EventDispatcher): ReactViewGroup(reactContext), RootView {
private val jSTouchDispatcher = JSTouchDispatcher(this)
private var jSPointerDispatcher: JSPointerDispatcher? = null
private var viewWidth = 0
private var viewHeight = 0
internal var stateWrapper: StateWrapper? = null

init {
if (ReactFeatureFlags.dispatchPointerEvents) {
this.jSPointerDispatcher = JSPointerDispatcher(this)
}
}

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
viewWidth = w
viewHeight = h

updateState(viewWidth, viewHeight)
}

@UiThread
public fun updateState(width: Int, height: Int) {
val realWidth: Float = PixelUtil.toDIPFromPixel(width.toFloat())
val realHeight: Float = PixelUtil.toDIPFromPixel(height.toFloat())

// TODO splint into different files
stateWrapper?.let { sw ->
// new architecture
val newStateData: WritableMap = WritableNativeMap()
newStateData.putDouble("screenWidth", realWidth.toDouble())
newStateData.putDouble("screenHeight", realHeight.toDouble())
sw.updateState(newStateData)
}
?: run {
// old architecture
reactContext.runOnNativeModulesQueueThread(
object : GuardedRunnable(reactContext) {
override fun runGuarded() {
reactContext.reactApplicationContext
.getNativeModule(UIManagerModule::class.java)
?.updateNodeSize(id, viewWidth, viewHeight)
}
})
}
}

override fun handleException(exception: Throwable?) {
val reactContext = context as ThemedReactContext
reactContext.reactApplicationContext.handleException(RuntimeException(exception))
Expand Down
83 changes: 83 additions & 0 deletions android/src/main/jni/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)

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

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}
)
15 changes: 15 additions & 0 deletions android/src/main/jni/multiplemodals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

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

#include <react/renderer/components/multiplemodals/RNTModalViewComponentDescriptor.h>

namespace facebook::react
{

JSI_EXPORT
std::shared_ptr<TurboModule> multiplemodals_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params);

} // namespace facebook
9 changes: 2 additions & 7 deletions android/src/newarch/RNTModalViewManagerSpec.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
package com.multiplemodals

import android.view.ViewGroup

import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.ViewManagerDelegate
import com.facebook.react.viewmanagers.RNTModalViewManagerDelegate
import com.facebook.react.viewmanagers.RNTModalViewManagerInterface

abstract class RNTModalViewManagerSpec<T : ViewGroup> : ViewGroupManager<T>(), RNTModalViewManagerInterface<T> {
private val mDelegate: ViewManagerDelegate<T>

init {
mDelegate = RNTModalViewManagerDelegate(this)
}
private val mDelegate: ViewManagerDelegate<T> = RNTModalViewManagerDelegate(this)

override fun getDelegate(): ViewManagerDelegate<T>? {
override fun getDelegate(): ViewManagerDelegate<T>? {
return mDelegate
}
}
Loading