react-native-keyboard-controller 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/android/build.gradle +72 -3
  2. package/android/gradle.properties +1 -1
  3. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerComponentsRegistry.kt +31 -0
  4. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +25 -0
  5. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +32 -0
  6. package/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +25 -0
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardAnimationCallback.kt +188 -0
  8. package/android/src/main/java/com/reactnativekeyboardcontroller/{KeyboardControllerModule.kt → KeyboardControllerModuleImpl.kt} +5 -17
  9. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +5 -0
  10. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManagerImpl.kt +71 -0
  11. package/android/src/main/java/com/reactnativekeyboardcontroller/{StatusBarManagerCompatModule.kt → StatusBarManagerCompatImpl.kt} +10 -14
  12. package/android/src/main/jni/Android.mk +42 -0
  13. package/android/src/main/jni/KeyboardControllerComponentsRegistry.cpp +71 -0
  14. package/android/src/main/jni/KeyboardControllerComponentsRegistry.h +35 -0
  15. package/android/src/main/jni/OnLoad.cpp +9 -0
  16. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +31 -0
  17. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +26 -0
  18. package/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +34 -0
  19. package/ios/.clang-format +90 -0
  20. package/ios/KeyboardController.xcodeproj/project.pbxproj +22 -14
  21. package/ios/KeyboardControllerModule-Header.h +6 -2
  22. package/ios/KeyboardControllerModule.mm +105 -0
  23. package/ios/KeyboardControllerView.h +23 -0
  24. package/ios/KeyboardControllerView.mm +81 -0
  25. package/ios/{KeyboardControllerViewManager.m → KeyboardControllerViewManager.mm} +1 -1
  26. package/ios/KeyboardControllerViewManager.swift +13 -64
  27. package/ios/KeyboardMoveEvent.h +18 -0
  28. package/ios/KeyboardMoveEvent.m +74 -0
  29. package/ios/KeyboardMovementObserver.swift +90 -0
  30. package/lib/commonjs/KeyboardControllerViewNativeComponent.js +16 -0
  31. package/lib/commonjs/KeyboardControllerViewNativeComponent.js.map +1 -0
  32. package/lib/commonjs/NativeKeyboardController.js +13 -0
  33. package/lib/commonjs/NativeKeyboardController.js.map +1 -0
  34. package/lib/commonjs/NativeStatusBarManagerCompat.js +13 -0
  35. package/lib/commonjs/NativeStatusBarManagerCompat.js.map +1 -0
  36. package/lib/commonjs/animated.js.map +1 -1
  37. package/lib/commonjs/architecture.js +13 -0
  38. package/lib/commonjs/architecture.js.map +1 -0
  39. package/lib/commonjs/index.js.map +1 -1
  40. package/lib/commonjs/monkey-patch.js +3 -1
  41. package/lib/commonjs/monkey-patch.js.map +1 -1
  42. package/lib/commonjs/native.js +4 -2
  43. package/lib/commonjs/native.js.map +1 -1
  44. package/lib/commonjs/replicas.js.map +1 -1
  45. package/lib/module/KeyboardControllerViewNativeComponent.js +4 -0
  46. package/lib/module/KeyboardControllerViewNativeComponent.js.map +1 -0
  47. package/lib/module/NativeKeyboardController.js +3 -0
  48. package/lib/module/NativeKeyboardController.js.map +1 -0
  49. package/lib/module/NativeStatusBarManagerCompat.js +3 -0
  50. package/lib/module/NativeStatusBarManagerCompat.js.map +1 -0
  51. package/lib/module/animated.js.map +1 -1
  52. package/lib/module/architecture.js +5 -0
  53. package/lib/module/architecture.js.map +1 -0
  54. package/lib/module/index.js.map +1 -1
  55. package/lib/module/monkey-patch.js +2 -1
  56. package/lib/module/monkey-patch.js.map +1 -1
  57. package/lib/module/native.js +3 -2
  58. package/lib/module/native.js.map +1 -1
  59. package/lib/module/replicas.js.map +1 -1
  60. package/lib/typescript/KeyboardControllerViewNativeComponent.d.ts +13 -0
  61. package/lib/typescript/NativeKeyboardController.d.ts +10 -0
  62. package/lib/typescript/NativeStatusBarManagerCompat.d.ts +10 -0
  63. package/lib/typescript/architecture.d.ts +2 -0
  64. package/lib/typescript/native.d.ts +1 -1
  65. package/lib/typescript/replicas.d.ts +3 -5
  66. package/package.json +23 -6
  67. package/react-native-keyboard-controller.podspec +19 -0
  68. package/src/KeyboardControllerViewNativeComponent.ts +23 -0
  69. package/src/NativeKeyboardController.ts +16 -0
  70. package/src/NativeStatusBarManagerCompat.ts +13 -0
  71. package/src/architecture.ts +4 -0
  72. package/src/monkey-patch.tsx +5 -1
  73. package/src/native.ts +12 -7
  74. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +0 -77
  75. package/android/src/main/java/com/reactnativekeyboardcontroller/TranslateDeferringInsetsAnimationCallback.kt +0 -158
  76. package/ios/KeyboardControllerModule.m +0 -21
  77. package/ios/KeyboardControllerModule.swift +0 -53
  78. package/ios/KeyboardMoveEvent.swift +0 -41
@@ -14,9 +14,6 @@ buildscript {
14
14
  }
15
15
  }
16
16
 
17
- apply plugin: 'com.android.library'
18
- apply plugin: 'kotlin-android'
19
-
20
17
  def getExtOrDefault(name) {
21
18
  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['KeyboardController_' + name]
22
19
  }
@@ -25,6 +22,22 @@ def getExtOrIntegerDefault(name) {
25
22
  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['KeyboardController_' + name]).toInteger()
26
23
  }
27
24
 
25
+ def isNewArchitectureEnabled() {
26
+ return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
27
+ }
28
+
29
+ def reactNativeArchitectures() {
30
+ def value = project.getProperties().get("reactNativeArchitectures")
31
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
32
+ }
33
+
34
+ apply plugin: 'com.android.library'
35
+ apply plugin: 'kotlin-android'
36
+
37
+ if (isNewArchitectureEnabled()) {
38
+ apply plugin: 'com.facebook.react'
39
+ }
40
+
28
41
  android {
29
42
  compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
30
43
  defaultConfig {
@@ -32,7 +45,53 @@ android {
32
45
  targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
33
46
  versionCode 1
34
47
  versionName "1.0"
48
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
49
+ if (isNewArchitectureEnabled()) {
50
+ var appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
51
+ externalNativeBuild {
52
+ ndkBuild {
53
+ arguments "APP_PLATFORM=android-21",
54
+ "APP_STL=c++_shared",
55
+ "NDK_TOOLCHAIN_VERSION=clang",
56
+ "GENERATED_SRC_DIR=${appProject.buildDir}/generated/source",
57
+ "PROJECT_BUILD_DIR=${appProject.buildDir}",
58
+ "REACT_ANDROID_DIR=${appProject.rootDir}/../node_modules/react-native/ReactAndroid",
59
+ "REACT_ANDROID_BUILD_DIR=${appProject.rootDir}/../node_modules/react-native/ReactAndroid/build"
60
+ cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
61
+ cppFlags "-std=c++17"
62
+ targets "reactnativekeyboardcontroller_modules"
63
+ }
64
+ }
65
+ }
66
+ ndk {
67
+ abiFilters (*reactNativeArchitectures())
68
+ }
69
+ }
35
70
 
71
+ if (isNewArchitectureEnabled()) {
72
+ externalNativeBuild {
73
+ ndkBuild {
74
+ path "src/main/jni/Android.mk"
75
+ }
76
+ }
77
+
78
+ packagingOptions {
79
+ exclude "**/libreact_render_*.so"
80
+ exclude "**/librrc_root.so"
81
+ }
82
+ }
83
+
84
+ sourceSets {
85
+ main {
86
+ if (isNewArchitectureEnabled()) {
87
+ java.srcDirs += [
88
+ 'src/fabric',
89
+ 'build/generated/source/codegen/java'
90
+ ]
91
+ } else {
92
+ java.srcDirs += ['src/paper']
93
+ }
94
+ }
36
95
  }
37
96
 
38
97
  buildTypes {
@@ -127,3 +186,13 @@ dependencies {
127
186
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
128
187
  implementation 'androidx.core:core-ktx:1.5.0-beta03'
129
188
  }
189
+
190
+ if (isNewArchitectureEnabled()) {
191
+ react {
192
+ reactNativeDir = rootProject.file("../node_modules/react-native/")
193
+ jsRootDir = file("../src/")
194
+ codegenDir = rootProject.file("../node_modules/react-native-codegen/")
195
+ libraryName = "reactnativekeyboardcontroller"
196
+ codegenJavaPackageName = "com.reactnativekeyboardcontroller"
197
+ }
198
+ }
@@ -1,4 +1,4 @@
1
- KeyboardController_kotlinVersion=1.3.50
1
+ KeyboardController_kotlinVersion=1.6.21
2
2
  KeyboardController_compileSdkVersion=29
3
3
  KeyboardController_targetSdkVersion=29
4
4
 
@@ -0,0 +1,31 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import com.facebook.jni.HybridData
4
+ import com.facebook.proguard.annotations.DoNotStrip
5
+ import com.facebook.react.fabric.ComponentFactory
6
+ import com.facebook.soloader.SoLoader
7
+
8
+ @DoNotStrip
9
+ class KeyboardControllerComponentsRegistry @DoNotStrip private constructor(componentFactory: ComponentFactory) {
10
+ companion object {
11
+ @DoNotStrip
12
+ fun register(componentFactory: ComponentFactory): KeyboardControllerComponentsRegistry {
13
+ return KeyboardControllerComponentsRegistry(componentFactory)
14
+ }
15
+
16
+ init {
17
+ SoLoader.loadLibrary("fabricjni")
18
+ SoLoader.loadLibrary("reactnativekeyboardcontroller_modules")
19
+ }
20
+ }
21
+
22
+ @DoNotStrip
23
+ private val mHybridData: HybridData
24
+
25
+ @DoNotStrip
26
+ private external fun initHybrid(componentFactory: ComponentFactory): HybridData
27
+
28
+ init {
29
+ mHybridData = initHybrid(componentFactory)
30
+ }
31
+ }
@@ -0,0 +1,25 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+
5
+ class KeyboardControllerModule(mReactContext: ReactApplicationContext) : NativeKeyboardControllerSpec(mReactContext) {
6
+ private val module = KeyboardControllerModuleImpl(mReactContext)
7
+
8
+ override fun getName(): String = KeyboardControllerModuleImpl.NAME
9
+
10
+ override fun setInputMode(mode: Double) {
11
+ module.setInputMode(mode.toInt())
12
+ }
13
+
14
+ override fun setDefaultMode() {
15
+ module.setDefaultMode()
16
+ }
17
+
18
+ override fun addListener(eventName: String?) {
19
+ /* Required for RN built-in Event Emitter Calls. */
20
+ }
21
+
22
+ override fun removeListeners(count: Double) {
23
+ /* Required for RN built-in Event Emitter Calls. */
24
+ }
25
+ }
@@ -0,0 +1,32 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.uimanager.ThemedReactContext
5
+ import com.facebook.react.uimanager.ViewManagerDelegate
6
+ import com.facebook.react.viewmanagers.KeyboardControllerViewManagerDelegate
7
+ import com.facebook.react.viewmanagers.KeyboardControllerViewManagerInterface
8
+ import com.facebook.react.views.view.ReactViewGroup
9
+ import com.facebook.react.views.view.ReactViewManager
10
+
11
+ class KeyboardControllerViewManager(mReactContext: ReactApplicationContext) : ReactViewManager(), KeyboardControllerViewManagerInterface<ReactViewGroup> {
12
+ private val manager = KeyboardControllerViewManagerImpl(mReactContext)
13
+ private val mDelegate = KeyboardControllerViewManagerDelegate(this)
14
+
15
+ override fun getDelegate(): ViewManagerDelegate<ReactViewGroup?> {
16
+ return mDelegate
17
+ }
18
+
19
+ override fun getName(): String = KeyboardControllerViewManagerImpl.NAME
20
+
21
+ override fun createViewInstance(context: ThemedReactContext): ReactViewGroup {
22
+ return manager.createViewInstance(context)
23
+ }
24
+
25
+ override fun setStatusBarTranslucent(view: ReactViewGroup, value: Boolean) {
26
+ return manager.setStatusBarTranslucent(view, value)
27
+ }
28
+
29
+ override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
30
+ return manager.getExportedCustomDirectEventTypeConstants()
31
+ }
32
+ }
@@ -0,0 +1,25 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+
5
+ class StatusBarManagerCompatModule(private val mReactContext: ReactApplicationContext) : NativeStatusBarManagerCompatSpec(mReactContext) {
6
+ private val module = StatusBarManagerCompatImpl(mReactContext)
7
+
8
+ override fun getName(): String = StatusBarManagerCompatImpl.NAME
9
+
10
+ override fun setHidden(hidden: Boolean) {
11
+ module.setHidden(hidden)
12
+ }
13
+
14
+ override fun setColor(color: Double, animated: Boolean) {
15
+ module.setColor(color.toInt(), animated)
16
+ }
17
+
18
+ override fun setTranslucent(translucent: Boolean) {
19
+ module.setTranslucent(translucent)
20
+ }
21
+
22
+ override fun setStyle(style: String) {
23
+ module.setStyle(style)
24
+ }
25
+ }
@@ -0,0 +1,188 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import android.animation.ValueAnimator
4
+ import android.content.Context
5
+ import android.os.Build
6
+ import android.util.Log
7
+ import android.view.View
8
+ import androidx.core.animation.doOnEnd
9
+ import androidx.core.graphics.Insets
10
+ import androidx.core.view.OnApplyWindowInsetsListener
11
+ import androidx.core.view.ViewCompat
12
+ import androidx.core.view.WindowInsetsAnimationCompat
13
+ import androidx.core.view.WindowInsetsCompat
14
+ import com.facebook.react.bridge.Arguments
15
+ import com.facebook.react.bridge.ReactApplicationContext
16
+ import com.facebook.react.bridge.WritableMap
17
+ import com.facebook.react.modules.core.DeviceEventManagerModule
18
+ import com.facebook.react.uimanager.UIManagerHelper
19
+ import com.facebook.react.uimanager.events.Event
20
+ import com.facebook.react.uimanager.events.EventDispatcher
21
+ import com.facebook.react.views.view.ReactViewGroup
22
+ import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
23
+
24
+ fun toDp(px: Float, context: Context?): Int {
25
+ if (context == null) {
26
+ return 0
27
+ }
28
+
29
+ return (px / context.resources.displayMetrics.density).toInt()
30
+ }
31
+
32
+ class KeyboardAnimationCallback(
33
+ val view: ReactViewGroup,
34
+ val persistentInsetTypes: Int,
35
+ val deferredInsetTypes: Int,
36
+ dispatchMode: Int = DISPATCH_MODE_STOP,
37
+ val context: ReactApplicationContext?,
38
+ val onApplyWindowInsetsListener: OnApplyWindowInsetsListener
39
+ ) : WindowInsetsAnimationCompat.Callback(dispatchMode), OnApplyWindowInsetsListener {
40
+ private val TAG = KeyboardAnimationCallback::class.qualifiedName
41
+ private var persistentKeyboardHeight = 0
42
+ private var isKeyboardVisible = false
43
+ private var isTransitioning = false
44
+
45
+ init {
46
+ require(persistentInsetTypes and deferredInsetTypes == 0) {
47
+ "persistentInsetTypes and deferredInsetTypes can not contain any of " +
48
+ " same WindowInsetsCompat.Type values"
49
+ }
50
+ }
51
+
52
+ /**
53
+ * When keyboard changes its size we have different behavior per APIs.
54
+ * On 21<=API<30 - WindowInsetsAnimationCompat dispatches onStart/onProgress/onEnd events.
55
+ * On API>=30 - WindowInsetsAnimationCompat doesn't dispatch anything. As a result behavior
56
+ * between different Android versions is not consistent. On old Android versions we have a
57
+ * reaction, on newer versions - not. In my understanding it's a bug in core library and the
58
+ * behavior should be consistent across all versions of platform. To level the difference we
59
+ * have to implement `onApplyWindowInsets` listener and simulate onStart/onProgress/onEnd
60
+ * events when keyboard changes its size.
61
+ * In the method below we fully recreate the logic that is implemented on old android versions:
62
+ * - we dispatch `keyboardWillShow` (onStart);
63
+ * - we dispatch change height/progress as animated values (onProgress);
64
+ * - we dispatch `keyboardDidShow` (onEnd).
65
+ */
66
+ override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
67
+ // when keyboard appears values will be (false && true)
68
+ // when keyboard disappears values will be (true && false)
69
+ // `!isTransitioning` check is needed to avoid calls of `onApplyWindowInsets` during keyboard animation
70
+ // having such check allows us not to dispatch unnecessary incorrect events
71
+ // the condition will be executed only when keyboard is opened and changes its size
72
+ // (for example it happens when user changes keyboard type from 'text' to 'emoji' input
73
+ if (isKeyboardVisible && isKeyboardVisible() && !isTransitioning && Build.VERSION.SDK_INT >= 30) {
74
+ val keyboardHeight = getCurrentKeyboardHeight()
75
+
76
+ this.emitEvent("KeyboardController::keyboardWillShow", getEventParams(keyboardHeight))
77
+
78
+ val animation = ValueAnimator.ofInt(-this.persistentKeyboardHeight, -keyboardHeight)
79
+ animation.addUpdateListener { animator ->
80
+ val toValue = animator.animatedValue as Int
81
+ this.sendEventToJS(KeyboardTransitionEvent(view.id, toValue, -toValue.toDouble() / keyboardHeight))
82
+ }
83
+ animation.doOnEnd {
84
+ this.emitEvent("KeyboardController::keyboardDidShow", getEventParams(keyboardHeight))
85
+ }
86
+ animation.setDuration(250).startDelay = 0
87
+ animation.start()
88
+
89
+ this.persistentKeyboardHeight = keyboardHeight
90
+ }
91
+
92
+ return onApplyWindowInsetsListener.onApplyWindowInsets(v, insets)
93
+ }
94
+
95
+ override fun onStart(
96
+ animation: WindowInsetsAnimationCompat,
97
+ bounds: WindowInsetsAnimationCompat.BoundsCompat
98
+ ): WindowInsetsAnimationCompat.BoundsCompat {
99
+ isTransitioning = true
100
+ isKeyboardVisible = isKeyboardVisible()
101
+ val keyboardHeight = getCurrentKeyboardHeight()
102
+
103
+ if (isKeyboardVisible) {
104
+ // do not update it on hide, since back progress will be invalid
105
+ this.persistentKeyboardHeight = keyboardHeight
106
+ }
107
+
108
+ this.emitEvent("KeyboardController::" + if (!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow", getEventParams(keyboardHeight))
109
+
110
+ Log.i(TAG, "HEIGHT:: $keyboardHeight")
111
+
112
+ return super.onStart(animation, bounds)
113
+ }
114
+
115
+ override fun onProgress(
116
+ insets: WindowInsetsCompat,
117
+ runningAnimations: List<WindowInsetsAnimationCompat>
118
+ ): WindowInsetsCompat {
119
+ // onProgress() is called when any of the running animations progress...
120
+
121
+ // First we get the insets which are potentially deferred
122
+ val typesInset = insets.getInsets(deferredInsetTypes)
123
+ // Then we get the persistent inset types which are applied as padding during layout
124
+ val otherInset = insets.getInsets(persistentInsetTypes)
125
+
126
+ // Now that we subtract the two insets, to calculate the difference. We also coerce
127
+ // the insets to be >= 0, to make sure we don't use negative insets.
128
+ val diff = Insets.subtract(typesInset, otherInset).let {
129
+ Insets.max(it, Insets.NONE)
130
+ }
131
+ val diffY = (diff.top - diff.bottom).toFloat()
132
+ val height = toDp(diffY, context)
133
+
134
+ var progress = 0.0
135
+ try {
136
+ progress = Math.abs((height.toDouble() / persistentKeyboardHeight)).let { if (it.isNaN()) 0.0 else it }
137
+ } catch (e: ArithmeticException) {
138
+ // do nothing, send progress as 0
139
+ }
140
+ Log.i(TAG, "DiffY: $diffY $height $progress")
141
+
142
+ this.sendEventToJS(KeyboardTransitionEvent(view.id, height, progress))
143
+
144
+ return insets
145
+ }
146
+
147
+ override fun onEnd(animation: WindowInsetsAnimationCompat) {
148
+ super.onEnd(animation)
149
+
150
+ isTransitioning = false
151
+ this.persistentKeyboardHeight = getCurrentKeyboardHeight()
152
+ this.emitEvent("KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow", getEventParams(this.persistentKeyboardHeight))
153
+ }
154
+
155
+ private fun isKeyboardVisible(): Boolean {
156
+ val insets = ViewCompat.getRootWindowInsets(view)
157
+
158
+ return insets?.isVisible(WindowInsetsCompat.Type.ime()) ?: false
159
+ }
160
+
161
+ private fun getCurrentKeyboardHeight(): Int {
162
+ val insets = ViewCompat.getRootWindowInsets(view)
163
+ val keyboardHeight = insets?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
164
+ val navigationBar = insets?.getInsets(WindowInsetsCompat.Type.navigationBars())?.bottom ?: 0
165
+
166
+ // on hide it will be negative value, so we are using max function
167
+ return Math.max(toDp((keyboardHeight - navigationBar).toFloat(), context), 0)
168
+ }
169
+
170
+ private fun sendEventToJS(event: Event<*>) {
171
+ val eventDispatcher: EventDispatcher? =
172
+ UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
173
+ eventDispatcher?.dispatchEvent(event)
174
+ }
175
+
176
+ private fun emitEvent(event: String, params: WritableMap) {
177
+ context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit(event, params)
178
+
179
+ Log.i(TAG, event)
180
+ }
181
+
182
+ private fun getEventParams(height: Int): WritableMap {
183
+ val params: WritableMap = Arguments.createMap()
184
+ params.putInt("height", height)
185
+
186
+ return params
187
+ }
188
+ }
@@ -2,38 +2,26 @@ package com.reactnativekeyboardcontroller
2
2
 
3
3
  import android.view.WindowManager
4
4
  import com.facebook.react.bridge.ReactApplicationContext
5
- import com.facebook.react.bridge.ReactContextBaseJavaModule
6
- import com.facebook.react.bridge.ReactMethod
7
5
  import com.facebook.react.bridge.UiThreadUtil
8
6
 
9
- class KeyboardControllerModule(private val mReactContext: ReactApplicationContext) : ReactContextBaseJavaModule(mReactContext) {
7
+ class KeyboardControllerModuleImpl(private val mReactContext: ReactApplicationContext) {
10
8
  private val mDefaultMode: Int = mReactContext.currentActivity?.window?.attributes?.softInputMode ?: WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
11
9
 
12
- override fun getName(): String = "KeyboardController"
13
-
14
- @ReactMethod(isBlockingSynchronousMethod = true)
15
10
  fun setInputMode(mode: Int) {
16
11
  setSoftInputMode(mode)
17
12
  }
18
13
 
19
- @ReactMethod(isBlockingSynchronousMethod = true)
20
14
  fun setDefaultMode() {
21
15
  setSoftInputMode(mDefaultMode)
22
16
  }
23
17
 
24
- @ReactMethod
25
- fun addListener(eventName: String?) {
26
- /* Required for RN built-in Event Emitter Calls. */
27
- }
28
-
29
- @ReactMethod
30
- fun removeListeners(count: Int?) {
31
- /* Required for RN built-in Event Emitter Calls. */
32
- }
33
-
34
18
  private fun setSoftInputMode(mode: Int) {
35
19
  UiThreadUtil.runOnUiThread {
36
20
  mReactContext.currentActivity?.window?.setSoftInputMode(mode)
37
21
  }
38
22
  }
23
+
24
+ companion object {
25
+ const val NAME = "KeyboardController"
26
+ }
39
27
  }
@@ -4,6 +4,7 @@ import com.facebook.react.ReactPackage
4
4
  import com.facebook.react.bridge.NativeModule
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.uimanager.ViewManager
7
+ import com.facebook.soloader.SoLoader
7
8
 
8
9
  class KeyboardControllerPackage : ReactPackage {
9
10
  override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
@@ -11,6 +12,10 @@ class KeyboardControllerPackage : ReactPackage {
11
12
  }
12
13
 
13
14
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
16
+ SoLoader.loadLibrary("reactnativekeyboardcontroller_modules")
17
+ }
18
+
14
19
  return listOf(KeyboardControllerViewManager(reactContext))
15
20
  }
16
21
  }
@@ -0,0 +1,71 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import android.util.Log
4
+ import androidx.appcompat.widget.FitWindowsLinearLayout
5
+ import androidx.core.view.ViewCompat
6
+ import androidx.core.view.WindowInsetsAnimationCompat
7
+ import androidx.core.view.WindowInsetsCompat
8
+ import com.facebook.react.bridge.ReactApplicationContext
9
+ import com.facebook.react.common.MapBuilder
10
+ import com.facebook.react.uimanager.ThemedReactContext
11
+ import com.facebook.react.views.view.ReactViewGroup
12
+ import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
13
+
14
+ class KeyboardControllerViewManagerImpl(reactContext: ReactApplicationContext) {
15
+ private val TAG = KeyboardControllerViewManagerImpl::class.qualifiedName
16
+ private var mReactContext = reactContext
17
+ private var isStatusBarTranslucent = false
18
+
19
+ fun createViewInstance(reactContext: ThemedReactContext): ReactViewGroup {
20
+ val view = EdgeToEdgeReactViewGroup(reactContext)
21
+ val activity = mReactContext.currentActivity
22
+
23
+ if (activity == null) {
24
+ Log.w(TAG, "Can not setup keyboard animation listener, since `currentActivity` is null")
25
+ return view
26
+ }
27
+
28
+ val callback = KeyboardAnimationCallback(
29
+ view = view,
30
+ persistentInsetTypes = WindowInsetsCompat.Type.systemBars(),
31
+ deferredInsetTypes = WindowInsetsCompat.Type.ime(),
32
+ // We explicitly allow dispatch to continue down to binding.messageHolder's
33
+ // child views, so that step 2.5 below receives the call
34
+ dispatchMode = WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE,
35
+ context = mReactContext,
36
+ onApplyWindowInsetsListener = { v, insets ->
37
+ val content =
38
+ mReactContext.currentActivity?.window?.decorView?.rootView?.findViewById<FitWindowsLinearLayout>(
39
+ R.id.action_bar_root
40
+ )
41
+ content?.setPadding(
42
+ 0, if (this.isStatusBarTranslucent) 0 else insets?.getInsets(WindowInsetsCompat.Type.systemBars())?.top ?: 0, 0,
43
+ insets?.getInsets(WindowInsetsCompat.Type.navigationBars())?.bottom ?: 0
44
+ )
45
+
46
+ insets
47
+ }
48
+ )
49
+ ViewCompat.setWindowInsetsAnimationCallback(view, callback)
50
+ ViewCompat.setOnApplyWindowInsetsListener(view, callback)
51
+
52
+ return view
53
+ }
54
+
55
+ fun setStatusBarTranslucent(view: ReactViewGroup, isStatusBarTranslucent: Boolean) {
56
+ this.isStatusBarTranslucent = isStatusBarTranslucent
57
+ }
58
+
59
+ fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
60
+ val map: MutableMap<String, Any> = MapBuilder.of(
61
+ KeyboardTransitionEvent.EVENT_NAME,
62
+ MapBuilder.of("registrationName", "onKeyboardMove")
63
+ )
64
+
65
+ return map
66
+ }
67
+
68
+ companion object {
69
+ const val NAME = "KeyboardControllerView"
70
+ }
71
+ }
@@ -8,18 +8,13 @@ import androidx.annotation.RequiresApi
8
8
  import androidx.core.view.WindowInsetsCompat
9
9
  import androidx.core.view.WindowInsetsControllerCompat
10
10
  import com.facebook.react.bridge.ReactApplicationContext
11
- import com.facebook.react.bridge.ReactContextBaseJavaModule
12
- import com.facebook.react.bridge.ReactMethod
13
11
  import com.facebook.react.bridge.UiThreadUtil
14
12
 
15
- class StatusBarManagerCompatModule(private val mReactContext: ReactApplicationContext) : ReactContextBaseJavaModule(mReactContext) {
16
- private val TAG = StatusBarManagerCompatModule::class.qualifiedName
13
+ class StatusBarManagerCompatImpl(private val mReactContext: ReactApplicationContext) {
14
+ private val TAG = StatusBarManagerCompatImpl::class.qualifiedName
17
15
  private var controller: WindowInsetsControllerCompat? = null
18
16
 
19
- override fun getName(): String = "StatusBarManagerCompat"
20
-
21
- @ReactMethod
22
- private fun setHidden(hidden: Boolean) {
17
+ fun setHidden(hidden: Boolean) {
23
18
  UiThreadUtil.runOnUiThread {
24
19
  if (hidden) {
25
20
  getController()?.hide(WindowInsetsCompat.Type.statusBars())
@@ -30,8 +25,7 @@ class StatusBarManagerCompatModule(private val mReactContext: ReactApplicationCo
30
25
  }
31
26
 
32
27
  @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
33
- @ReactMethod
34
- private fun setColor(color: Int, animated: Boolean) {
28
+ fun setColor(color: Int, animated: Boolean) {
35
29
  val activity = mReactContext.currentActivity
36
30
  if (activity == null) {
37
31
  Log.w(TAG, "StatusBarManagerCompatModule: Ignored status bar change, current activity is null.")
@@ -55,8 +49,7 @@ class StatusBarManagerCompatModule(private val mReactContext: ReactApplicationCo
55
49
  }
56
50
  }
57
51
 
58
- @ReactMethod
59
- private fun setTranslucent(translucent: Boolean) {
52
+ fun setTranslucent(translucent: Boolean) {
60
53
  // the status bar is translucent by default (once you wrapped App in Provider,
61
54
  // and EdgeToEdgeReactViewGroup has been mounted and called
62
55
  // `setDecorFitsSystemWindows(window, false)`. By default this library applies default padding
@@ -70,8 +63,7 @@ class StatusBarManagerCompatModule(private val mReactContext: ReactApplicationCo
70
63
  // app requires to dynamically manage it - just shoot an issue and I will try to add a support fot that.
71
64
  }
72
65
 
73
- @ReactMethod
74
- private fun setStyle(style: String) {
66
+ fun setStyle(style: String) {
75
67
  UiThreadUtil.runOnUiThread {
76
68
  getController()?.isAppearanceLightStatusBars = style == "dark-content"
77
69
  }
@@ -92,4 +84,8 @@ class StatusBarManagerCompatModule(private val mReactContext: ReactApplicationCo
92
84
 
93
85
  return this.controller
94
86
  }
87
+
88
+ companion object {
89
+ const val NAME = "StatusBarManagerCompat"
90
+ }
95
91
  }
@@ -0,0 +1,42 @@
1
+ KEYBOARD_CONTROLLER_MAIN_THIS_DIR := $(call my-dir)
2
+
3
+ include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
4
+
5
+ include $(KEYBOARD_CONTROLLER_MAIN_THIS_DIR)/../../../build/generated/source/codegen/jni/Android.mk
6
+
7
+ include $(CLEAR_VARS)
8
+
9
+ LOCAL_PATH := $(KEYBOARD_CONTROLLER_MAIN_THIS_DIR)
10
+ LOCAL_MODULE := reactnativekeyboardcontroller_modules
11
+
12
+ LOCAL_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni
13
+ LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
14
+ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni
15
+
16
+ # Please note as one of the library listed is libreact_codegen_samplelibrary
17
+ # This name will be generated as libreact_codegen_<library-name>
18
+ # where <library-name> is the one you specified in the Gradle configuration
19
+ LOCAL_SHARED_LIBRARIES := libjsi \
20
+ libfbjni \
21
+ libglog \
22
+ libfolly_runtime \
23
+ libyoga \
24
+ libreact_nativemodule_core \
25
+ libturbomodulejsijni \
26
+ librrc_view \
27
+ libreact_render_core \
28
+ libreact_render_graphics \
29
+ libfabricjni \
30
+ libreact_debug \
31
+ libreact_render_componentregistry \
32
+ libreact_render_debug \
33
+ libruntimeexecutor \
34
+ libreact_render_mapbuffer \
35
+ libreact_codegen_rncore \
36
+ libreact_codegen_reactnativekeyboardcontroller
37
+
38
+ LOCAL_CFLAGS := \
39
+ -DLOG_TAG=\"ReactNative\"
40
+ LOCAL_CFLAGS += -fexceptions -frtti -std=c++17 -Wall
41
+
42
+ include $(BUILD_SHARED_LIBRARY)