Skip to content

Commit

Permalink
Update react-native-screens to 3.22.0 (expo#23022)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsapeta authored Jun 22, 2023
1 parent 64f1b87 commit 3f07b79
Show file tree
Hide file tree
Showing 73 changed files with 1,127 additions and 280 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
buildscript {
ext {
rnsDefaultTargetSdkVersion = 31
rnsDefaultCompileSdkVersion = 31
rnsDefaultMinSdkVersion = 21
rnsDefaultKotlinVersion = '1.6.21'
}
ext.safeExtGet = {prop, fallback ->
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
Expand All @@ -8,7 +14,7 @@ buildscript {
}
dependencies {
classpath('com.android.tools.build:gradle:4.2.2')
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '1.6.21')}"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', rnsDefaultKotlinVersion)}"
classpath "com.diffplug.spotless:spotless-plugin-gradle:5.15.0"
}
}
Expand Down Expand Up @@ -38,7 +44,11 @@ def reactNativeArchitectures() {
}

android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
compileSdkVersion safeExtGet('compileSdkVersion', rnsDefaultCompileSdkVersion)
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
namespace "com.swmansion.rnscreens"
}

// Used to override the NDK path/version on internal CI or by allowing
// users to customize the NDK path/version from their root project (e.g. for M1 support)
Expand All @@ -50,8 +60,8 @@ android {
}

defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 21)
targetSdkVersion safeExtGet('targetSdkVersion', 22)
minSdkVersion safeExtGet('minSdkVersion', rnsDefaultMinSdkVersion)
targetSdkVersion safeExtGet('targetSdkVersion', rnsDefaultTargetSdkVersion)
versionCode 1
versionName "1.0"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
Expand All @@ -68,12 +78,13 @@ android {
}
packagingOptions {
// For some reason gradle only complains about the duplicated version of libreact_render libraries
// while there are more libraries copied in intermediates folder of the lib build directory, we exlude
// while there are more libraries copied in intermediates folder of the lib build directory, we exclude
// only the ones that make the build fail (ideally we should only include librnscreens_modules but we
// are only allowed to specify exlude patterns)
// are only allowed to specify exclude patterns)
exclude "**/libreact_render*.so"
}
sourceSets.main {
ext.androidResDir = "src/main/res"
java {
if (isNewArchitectureEnabled()) {
srcDirs += [
Expand All @@ -87,6 +98,13 @@ android {
}

}
res {
if (safeExtGet('compileSdkVersion', rnsDefaultCompileSdkVersion) >= 33) {
srcDirs = ["${androidResDir}/base", "${androidResDir}/v33"]
} else {
srcDirs = ["${androidResDir}/base"]
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class CustomSearchView(context: Context, fragment: Fragment) : SearchView(contex
requestFocusFromTouch()
}

fun clearText() = setQuery("", false)

fun setText(text: String) = setQuery(text, false)

override fun setOnCloseListener(listener: OnCloseListener?) {
mCustomOnCloseListener = listener
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,29 +292,30 @@ class ScreenStack(context: Context?) : ScreenContainer<ScreenStackFragment>(cont
}

override fun drawChild(canvas: Canvas, child: View, drawingTime: Long): Boolean {
drawingOps.add(obtainDrawingOp().set(canvas, child, drawingTime))
drawingOps.add(
obtainDrawingOp().apply {
this.canvas = canvas
this.child = child
this.drawingTime = drawingTime
}
)
return true
}

private fun performDraw(op: DrawingOp) {
super.drawChild(op.canvas, op.child, op.drawingTime)
// Canvas parameter can not be null here https://developer.android.com/reference/android/view/ViewGroup#drawChild(android.graphics.Canvas,%20android.view.View,%20long)
// So if we are passing null here, we would crash anyway
super.drawChild(op.canvas!!, op.child, op.drawingTime)
}

private fun obtainDrawingOp(): DrawingOp =
if (drawingOpPool.isEmpty()) DrawingOp() else drawingOpPool.removeAt(drawingOpPool.size - 1)
if (drawingOpPool.isEmpty()) DrawingOp() else drawingOpPool.removeLast()

private inner class DrawingOp {
var canvas: Canvas? = null
var child: View? = null
var drawingTime: Long = 0

operator fun set(canvas: Canvas?, child: View?, drawingTime: Long): DrawingOp {
this.canvas = canvas
this.child = child
this.drawingTime = drawingTime
return this
}

fun draw() {
performDraw(this)
canvas = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import androidx.fragment.app.Fragment
import com.facebook.react.ReactApplication
import com.facebook.react.bridge.JSApplicationIllegalArgumentException
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.events.RCTEventEmitter
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.views.text.ReactTypefaceUtils
import com.swmansion.rnscreens.events.HeaderAttachedEvent
import com.swmansion.rnscreens.events.HeaderDetachedEvent

class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) {
private val mConfigSubviews = ArrayList<ScreenStackHeaderSubview>(3)
Expand Down Expand Up @@ -64,11 +65,6 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) {
}
}

private fun sendEvent(eventName: String, eventContent: WritableMap?) {
(context as ReactContext).getJSModule(RCTEventEmitter::class.java)
?.receiveEvent(id, eventName, eventContent)
}

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
// no-op
}
Expand All @@ -80,7 +76,8 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) {
override fun onAttachedToWindow() {
super.onAttachedToWindow()
mIsAttachedToWindow = true
sendEvent("onAttached", null)
UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id)
?.dispatchEvent(HeaderAttachedEvent(id))
// we want to save the top inset before the status bar can be hidden, which would resolve in
// inset being 0
if (headerTopInset == null) {
Expand All @@ -96,7 +93,8 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) {
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
mIsAttachedToWindow = false
sendEvent("onDetached", null)
UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id)
?.dispatchEvent(HeaderDetachedEvent(id))
}

private val screen: Screen?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import com.facebook.react.uimanager.ViewManagerDelegate
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.viewmanagers.RNSScreenStackHeaderConfigManagerDelegate
import com.facebook.react.viewmanagers.RNSScreenStackHeaderConfigManagerInterface
import com.swmansion.rnscreens.events.HeaderAttachedEvent
import com.swmansion.rnscreens.events.HeaderDetachedEvent
import javax.annotation.Nonnull

@ReactModule(name = ScreenStackHeaderConfigViewManager.REACT_CLASS)
Expand Down Expand Up @@ -133,10 +135,12 @@ class ScreenStackHeaderConfigViewManager : ViewGroupManager<ScreenStackHeaderCon
}

override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
return MapBuilder.builder<String, Any>()
.put("onAttached", MapBuilder.of("registrationName", "onAttached"))
.put("onDetached", MapBuilder.of("registrationName", "onDetached"))
.build()
return MapBuilder.of(
HeaderAttachedEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onAttached"),
HeaderDetachedEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onDetached"),
)
}

protected override fun getDelegate(): ViewManagerDelegate<ScreenStackHeaderConfig> = mDelegate
Expand All @@ -162,6 +166,10 @@ class ScreenStackHeaderConfigViewManager : ViewGroupManager<ScreenStackHeaderCon
logNotAvailable("backTitleFontSize")
}

override fun setBackTitleVisible(view: ScreenStackHeaderConfig?, value: Boolean) {
logNotAvailable("backTitleVisible")
}

override fun setLargeTitle(view: ScreenStackHeaderConfig?, value: Boolean) {
logNotAvailable("largeTitle")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,16 @@ class ScreenViewManager : ViewGroupManager<Screen>(), RNSScreenManagerInterface<

override fun setSwipeDirection(view: Screen?, value: String?) = Unit

override fun setSheetAllowedDetents(view: Screen, value: String?) = Unit

override fun setSheetLargestUndimmedDetent(view: Screen, value: String?) = Unit

override fun setSheetGrabberVisible(view: Screen?, value: Boolean) = Unit

override fun setSheetCornerRadius(view: Screen?, value: Float) = Unit

override fun setSheetExpandsWhenScrolledToEdge(view: Screen?, value: Boolean) = Unit

override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
return MapBuilder.of(
ScreenDismissedEvent.EVENT_NAME,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package com.swmansion.rnscreens

import com.facebook.react.bridge.JSApplicationIllegalArgumentException
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.common.MapBuilder
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.ViewGroupManager
import com.facebook.react.uimanager.annotations.ReactProp
import com.swmansion.rnscreens.events.SearchBarBlurEvent
import com.swmansion.rnscreens.events.SearchBarChangeTextEvent
import com.swmansion.rnscreens.events.SearchBarCloseEvent
import com.swmansion.rnscreens.events.SearchBarFocusEvent
import com.swmansion.rnscreens.events.SearchBarOpenEvent
import com.swmansion.rnscreens.events.SearchBarSearchButtonPressEvent

@ReactModule(name = SearchBarManager.REACT_CLASS)
class SearchBarManager : ViewGroupManager<SearchBarView>() {
Expand Down Expand Up @@ -90,15 +97,32 @@ class SearchBarManager : ViewGroupManager<SearchBarView>() {
view.shouldShowHintSearchIcon = shouldShowHintSearchIcon ?: true
}

override fun receiveCommand(root: SearchBarView, commandId: String?, args: ReadableArray?) {
when (commandId) {
"focus" -> root.handleFocusJsRequest()
"blur" -> root.handleBlurJsRequest()
"clearText" -> root.handleClearTextJsRequest()
"toggleCancelButton" -> root.handleToggleCancelButtonJsRequest(false) // just a dummy argument
"setText" -> root.handleSetTextJsRequest(args?.getString(0))
else -> throw JSApplicationIllegalArgumentException("Unsupported native command received: $commandId")
}
}

override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
return MapBuilder.builder<String, Any>()
.put("onChangeText", MapBuilder.of("registrationName", "onChangeText"))
.put("onSearchButtonPress", MapBuilder.of("registrationName", "onSearchButtonPress"))
.put("onFocus", MapBuilder.of("registrationName", "onFocus"))
.put("onBlur", MapBuilder.of("registrationName", "onBlur"))
.put("onClose", MapBuilder.of("registrationName", "onClose"))
.put("onOpen", MapBuilder.of("registrationName", "onOpen"))
.build()
return MapBuilder.of(
SearchBarBlurEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onBlur"),
SearchBarChangeTextEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onChangeText"),
SearchBarCloseEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onClose"),
SearchBarFocusEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onFocus"),
SearchBarOpenEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onOpen"),
SearchBarSearchButtonPressEvent.EVENT_NAME,
MapBuilder.of("registrationName", "onSearchButtonPress"),
)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ package com.swmansion.rnscreens
import android.annotation.SuppressLint
import android.text.InputType
import androidx.appcompat.widget.SearchView
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.events.RCTEventEmitter
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.uimanager.events.Event
import com.facebook.react.uimanager.events.EventDispatcher
import com.facebook.react.views.view.ReactViewGroup
import com.swmansion.rnscreens.events.SearchBarBlurEvent
import com.swmansion.rnscreens.events.SearchBarChangeTextEvent
import com.swmansion.rnscreens.events.SearchBarCloseEvent
import com.swmansion.rnscreens.events.SearchBarFocusEvent
import com.swmansion.rnscreens.events.SearchBarOpenEvent
import com.swmansion.rnscreens.events.SearchBarSearchButtonPressEvent

@SuppressLint("ViewConstructor")
class SearchBarView(reactContext: ReactContext?) : ReactViewGroup(reactContext) {
Expand Down Expand Up @@ -95,32 +101,47 @@ class SearchBarView(reactContext: ReactContext?) : ReactViewGroup(reactContext)
}

private fun handleTextChange(newText: String?) {
val event = Arguments.createMap()
event.putString("text", newText)
sendEvent("onChangeText", event)
sendEvent(SearchBarChangeTextEvent(id, newText))
}

private fun handleFocusChange(hasFocus: Boolean) {
sendEvent(if (hasFocus) "onFocus" else "onBlur", null)
sendEvent(if (hasFocus) SearchBarFocusEvent(id) else SearchBarBlurEvent(id))
}

private fun handleClose() {
sendEvent("onClose", null)
sendEvent(SearchBarCloseEvent(id))
}

private fun handleOpen() {
sendEvent("onOpen", null)
sendEvent(SearchBarOpenEvent(id))
}

private fun handleTextSubmit(newText: String?) {
val event = Arguments.createMap()
event.putString("text", newText)
sendEvent("onSearchButtonPress", event)
sendEvent(SearchBarSearchButtonPressEvent(id, newText))
}

private fun sendEvent(eventName: String, eventContent: WritableMap?) {
(context as ReactContext).getJSModule(RCTEventEmitter::class.java)
?.receiveEvent(id, eventName, eventContent)
private fun sendEvent(event: Event<*>) {
val eventDispatcher: EventDispatcher? =
UIManagerHelper.getEventDispatcherForReactTag(context as ReactContext, id)
eventDispatcher?.dispatchEvent(event)
}

fun handleClearTextJsRequest() {
screenStackFragment?.searchView?.clearText()
}

fun handleFocusJsRequest() {
screenStackFragment?.searchView?.focus()
}

fun handleBlurJsRequest() {
screenStackFragment?.searchView?.clearFocus()
}

fun handleToggleCancelButtonJsRequest(flag: Boolean) = Unit

fun handleSetTextJsRequest(text: String?) {
text?.let { screenStackFragment?.searchView?.setText(it) }
}

enum class SearchBarAutoCapitalize {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.swmansion.rnscreens.events

import com.facebook.react.bridge.Arguments
import com.facebook.react.uimanager.events.Event
import com.facebook.react.uimanager.events.RCTEventEmitter

class HeaderAttachedEvent(viewId: Int) : Event<ScreenAppearEvent>(viewId) {
override fun getEventName(): String {
return EVENT_NAME
}

override fun getCoalescingKey(): Short {
// All events for a given view can be coalesced.
return 0
}

override fun dispatch(rctEventEmitter: RCTEventEmitter) {
rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap())
}

companion object {
const val EVENT_NAME = "topAttached"
}
}
Loading

0 comments on commit 3f07b79

Please sign in to comment.