react-native-keyboard-controller 1.13.3 → 1.14.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 (121) hide show
  1. package/README.md +1 -0
  2. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +5 -3
  3. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +19 -20
  4. package/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +22 -12
  5. package/android/src/fabric/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +40 -0
  6. package/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +7 -3
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +33 -27
  8. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputLayoutChangedEvent.kt +16 -15
  9. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputSelectionChangedEvent.kt +25 -24
  10. package/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt +4 -3
  11. package/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt +7 -6
  12. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/Context.kt +38 -0
  13. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt +82 -62
  14. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +9 -4
  15. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt +12 -5
  16. package/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt +12 -10
  17. package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/KeyboardAnimationController.kt +65 -60
  18. package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/Interpolator.kt +6 -1
  19. package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/IosInterpolator.kt +4 -2
  20. package/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/LinearInterpolator.kt +1 -3
  21. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt +62 -58
  22. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +52 -46
  23. package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +13 -7
  24. package/android/src/main/java/com/reactnativekeyboardcontroller/log/Logger.kt +28 -0
  25. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +35 -24
  26. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt +21 -8
  27. package/android/src/main/java/com/reactnativekeyboardcontroller/managers/OverKeyboardViewManagerImpl.kt +27 -0
  28. package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +15 -13
  29. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +8 -8
  30. package/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt +10 -5
  31. package/android/src/main/java/com/reactnativekeyboardcontroller/traversal/FocusedInputHolder.kt +1 -3
  32. package/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt +19 -13
  33. package/android/src/main/java/com/reactnativekeyboardcontroller/ui/FrameScheduler.kt +11 -8
  34. package/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +24 -19
  35. package/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardGestureAreaReactViewGroup.kt +23 -14
  36. package/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardHostShadowNode.kt +30 -0
  37. package/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardViewGroup.kt +185 -0
  38. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +3 -1
  39. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +19 -10
  40. package/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +21 -8
  41. package/android/src/paper/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +33 -0
  42. package/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +7 -3
  43. package/android/src/test/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigatorTest.kt +30 -21
  44. package/ios/KeyboardController-Bridging-Header.h +1 -0
  45. package/ios/extensions/UIResponder.swift +0 -3
  46. package/ios/extensions/UIWindow.swift +48 -0
  47. package/ios/views/OverKeyboardViewManager.h +29 -0
  48. package/ios/views/OverKeyboardViewManager.mm +220 -0
  49. package/jest/index.js +1 -0
  50. package/lib/commonjs/bindings.js +2 -1
  51. package/lib/commonjs/bindings.js.map +1 -1
  52. package/lib/commonjs/bindings.native.js +2 -1
  53. package/lib/commonjs/bindings.native.js.map +1 -1
  54. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +2 -1
  55. package/lib/commonjs/components/KeyboardAwareScrollView/index.js.map +1 -1
  56. package/lib/commonjs/components/KeyboardToolbar/index.js +5 -3
  57. package/lib/commonjs/components/KeyboardToolbar/index.js.map +1 -1
  58. package/lib/commonjs/hooks/index.js +2 -4
  59. package/lib/commonjs/hooks/index.js.map +1 -1
  60. package/lib/commonjs/index.js +9 -1
  61. package/lib/commonjs/index.js.map +1 -1
  62. package/lib/commonjs/internal.js +24 -12
  63. package/lib/commonjs/internal.js.map +1 -1
  64. package/lib/commonjs/specs/OverKeyboardViewNativeComponent.js +10 -0
  65. package/lib/commonjs/specs/OverKeyboardViewNativeComponent.js.map +1 -0
  66. package/lib/commonjs/types.js.map +1 -1
  67. package/lib/commonjs/views/OverKeyboardView/index.js +43 -0
  68. package/lib/commonjs/views/OverKeyboardView/index.js.map +1 -0
  69. package/lib/commonjs/views/index.js +14 -0
  70. package/lib/commonjs/views/index.js.map +1 -0
  71. package/lib/module/bindings.js +1 -0
  72. package/lib/module/bindings.js.map +1 -1
  73. package/lib/module/bindings.native.js +1 -0
  74. package/lib/module/bindings.native.js.map +1 -1
  75. package/lib/module/components/KeyboardAwareScrollView/index.js +2 -1
  76. package/lib/module/components/KeyboardAwareScrollView/index.js.map +1 -1
  77. package/lib/module/components/KeyboardToolbar/index.js +5 -3
  78. package/lib/module/components/KeyboardToolbar/index.js.map +1 -1
  79. package/lib/module/hooks/index.js +3 -4
  80. package/lib/module/hooks/index.js.map +1 -1
  81. package/lib/module/index.js +1 -0
  82. package/lib/module/index.js.map +1 -1
  83. package/lib/module/internal.js +24 -12
  84. package/lib/module/internal.js.map +1 -1
  85. package/lib/module/specs/OverKeyboardViewNativeComponent.js +3 -0
  86. package/lib/module/specs/OverKeyboardViewNativeComponent.js.map +1 -0
  87. package/lib/module/types.js.map +1 -1
  88. package/lib/module/views/OverKeyboardView/index.js +35 -0
  89. package/lib/module/views/OverKeyboardView/index.js.map +1 -0
  90. package/lib/module/views/index.js +2 -0
  91. package/lib/module/views/index.js.map +1 -0
  92. package/lib/typescript/bindings.d.ts +2 -1
  93. package/lib/typescript/bindings.native.d.ts +2 -1
  94. package/lib/typescript/components/KeyboardAwareScrollView/index.d.ts +4 -0
  95. package/lib/typescript/components/KeyboardToolbar/index.d.ts +2 -2
  96. package/lib/typescript/index.d.ts +1 -0
  97. package/lib/typescript/specs/OverKeyboardViewNativeComponent.d.ts +7 -0
  98. package/lib/typescript/types.d.ts +4 -1
  99. package/lib/typescript/views/OverKeyboardView/index.d.ts +5 -0
  100. package/lib/typescript/views/index.d.ts +1 -0
  101. package/package.json +8 -3
  102. package/src/bindings.native.ts +3 -0
  103. package/src/bindings.ts +3 -0
  104. package/src/components/KeyboardAwareScrollView/index.tsx +5 -2
  105. package/src/components/KeyboardToolbar/index.tsx +7 -3
  106. package/src/hooks/index.ts +3 -5
  107. package/src/index.ts +1 -0
  108. package/src/internal.ts +34 -15
  109. package/src/specs/OverKeyboardViewNativeComponent.ts +12 -0
  110. package/src/types.ts +4 -0
  111. package/src/views/OverKeyboardView/index.tsx +43 -0
  112. package/src/views/index.ts +1 -0
  113. package/ios/.clang-format +0 -90
  114. package/ios/.swiftformat +0 -5
  115. package/ios/.swiftlint.yml +0 -14
  116. package/lib/commonjs/hooks/useSyncEffect/index.js +0 -37
  117. package/lib/commonjs/hooks/useSyncEffect/index.js.map +0 -1
  118. package/lib/module/hooks/useSyncEffect/index.js +0 -31
  119. package/lib/module/hooks/useSyncEffect/index.js.map +0 -1
  120. package/lib/typescript/hooks/useSyncEffect/index.d.ts +0 -14
  121. package/src/hooks/useSyncEffect/index.ts +0 -36
@@ -5,9 +5,14 @@ import android.view.ViewGroup
5
5
  import com.facebook.react.bridge.ReactContext
6
6
 
7
7
  val ReactContext.rootView: View?
8
- get() = this.currentActivity?.window?.decorView?.rootView
8
+ get() =
9
+ this.currentActivity
10
+ ?.window
11
+ ?.decorView
12
+ ?.rootView
9
13
 
10
14
  val ReactContext.content: ViewGroup?
11
- get() = this.currentActivity?.window?.decorView?.rootView?.findViewById(
12
- androidx.appcompat.R.id.action_bar_root,
13
- )
15
+ get() =
16
+ this.currentActivity?.window?.decorView?.rootView?.findViewById(
17
+ androidx.appcompat.R.id.action_bar_root,
18
+ )
@@ -1,6 +1,5 @@
1
1
  package com.reactnativekeyboardcontroller.extensions
2
2
 
3
- import android.util.Log
4
3
  import com.facebook.react.bridge.ReactContext
5
4
  import com.facebook.react.bridge.WritableMap
6
5
  import com.facebook.react.modules.core.DeviceEventManagerModule
@@ -9,21 +8,29 @@ import com.facebook.react.uimanager.UIManagerHelper
9
8
  import com.facebook.react.uimanager.events.Event
10
9
  import com.facebook.react.uimanager.events.EventDispatcher
11
10
  import com.reactnativekeyboardcontroller.listeners.WindowDimensionListener
11
+ import com.reactnativekeyboardcontroller.log.Logger
12
12
 
13
13
  fun ThemedReactContext.setupWindowDimensionsListener() {
14
14
  WindowDimensionListener(this)
15
15
  }
16
16
 
17
- fun ThemedReactContext?.dispatchEvent(viewId: Int, event: Event<*>) {
17
+ fun ThemedReactContext?.dispatchEvent(
18
+ viewId: Int,
19
+ event: Event<*>,
20
+ ) {
18
21
  val eventDispatcher: EventDispatcher? =
19
22
  UIManagerHelper.getEventDispatcherForReactTag(this as ReactContext, viewId)
20
23
  eventDispatcher?.dispatchEvent(event)
21
24
  }
22
25
 
23
- fun ThemedReactContext?.emitEvent(event: String, params: WritableMap) {
24
- this?.reactApplicationContext
26
+ fun ThemedReactContext?.emitEvent(
27
+ event: String,
28
+ params: WritableMap,
29
+ ) {
30
+ this
31
+ ?.reactApplicationContext
25
32
  ?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
26
33
  ?.emit(event, params)
27
34
 
28
- Log.i("ThemedReactContext", event)
35
+ Logger.i("ThemedReactContext", event)
29
36
  }
@@ -2,9 +2,9 @@ package com.reactnativekeyboardcontroller.extensions
2
2
 
3
3
  import android.graphics.Rect
4
4
  import android.os.Build
5
- import android.util.Log
6
5
  import android.view.View
7
6
  import androidx.annotation.RequiresApi
7
+ import com.reactnativekeyboardcontroller.log.Logger
8
8
 
9
9
  /**
10
10
  * Call this every time when using [ViewCompat.setOnApplyWindowInsetsListener]
@@ -18,16 +18,18 @@ fun View.requestApplyInsetsWhenAttached() {
18
18
  requestApplyInsets()
19
19
  } else {
20
20
  // We're not attached to the hierarchy, add a listener to request when we are
21
- addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
22
- override fun onViewAttachedToWindow(v: View) {
23
- v.removeOnAttachStateChangeListener(this)
24
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
25
- v.requestApplyInsets()
21
+ addOnAttachStateChangeListener(
22
+ object : View.OnAttachStateChangeListener {
23
+ override fun onViewAttachedToWindow(v: View) {
24
+ v.removeOnAttachStateChangeListener(this)
25
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
26
+ v.requestApplyInsets()
27
+ }
26
28
  }
27
- }
28
29
 
29
- override fun onViewDetachedFromWindow(v: View) = Unit
30
- })
30
+ override fun onViewDetachedFromWindow(v: View) = Unit
31
+ },
32
+ )
31
33
  }
32
34
  }
33
35
 
@@ -43,7 +45,7 @@ fun View.copyBoundsInWindow(rect: Rect) {
43
45
  getLocationInWindow(tmpIntArr)
44
46
  rect.offset(tmpIntArr[0], tmpIntArr[1])
45
47
  } else {
46
- Log.w("View.copyBoundsInWindow", "Can not copy bounds as view is not attached to window")
48
+ Logger.w("View.copyBoundsInWindow", "Can not copy bounds as view is not attached to window")
47
49
  }
48
50
  }
49
51
 
@@ -73,7 +73,8 @@ internal class KeyboardAnimationController {
73
73
  }
74
74
 
75
75
  // Keep track of the IME insets, and the IME visibility, at the start of the request
76
- isImeShownAtStart = ViewCompat.getRootWindowInsets(view)
76
+ isImeShownAtStart = ViewCompat
77
+ .getRootWindowInsets(view)
77
78
  ?.isVisible(WindowInsetsCompat.Type.ime()) == true
78
79
 
79
80
  // Create a cancellation signal, which we pass to controlWindowInsetsAnimation() below
@@ -114,7 +115,10 @@ internal class KeyboardAnimationController {
114
115
  * @param view The view which is triggering this request
115
116
  * @param velocityY the velocity of the touch gesture which caused this call
116
117
  */
117
- fun startAndFling(view: View, velocityY: Float) = startControlRequest(view) {
118
+ fun startAndFling(
119
+ view: View,
120
+ velocityY: Float,
121
+ ) = startControlRequest(view) {
118
122
  animateToFinish(velocityY)
119
123
  }
120
124
 
@@ -127,11 +131,12 @@ internal class KeyboardAnimationController {
127
131
  * @return the amount of [dy] consumed by the inset animation, in pixels
128
132
  */
129
133
  fun insetBy(dy: Int): Int {
130
- val controller = insetsAnimationController
131
- ?: throw IllegalStateException(
132
- "Current WindowInsetsAnimationController is null." +
133
- "This should only be called if isAnimationInProgress() returns true",
134
- )
134
+ val controller =
135
+ insetsAnimationController
136
+ ?: throw IllegalStateException(
137
+ "Current WindowInsetsAnimationController is null." +
138
+ "This should only be called if isAnimationInProgress() returns true",
139
+ )
135
140
 
136
141
  InteractiveKeyboardProvider.isInteractive = true
137
142
  // Call updateInsetTo() with the new inset value
@@ -147,11 +152,12 @@ internal class KeyboardAnimationController {
147
152
  * @return the distance moved by the inset animation, in pixels
148
153
  */
149
154
  fun insetTo(inset: Int): Int {
150
- val controller = insetsAnimationController
151
- ?: throw IllegalStateException(
152
- "Current WindowInsetsAnimationController is null." +
153
- "This should only be called if isAnimationInProgress() returns true",
154
- )
155
+ val controller =
156
+ insetsAnimationController
157
+ ?: throw IllegalStateException(
158
+ "Current WindowInsetsAnimationController is null." +
159
+ "This should only be called if isAnimationInProgress() returns true",
160
+ )
155
161
 
156
162
  val hiddenBottom = controller.hiddenStateInsets.bottom
157
163
  val shownBottom = controller.shownStateInsets.bottom
@@ -182,23 +188,17 @@ internal class KeyboardAnimationController {
182
188
  /**
183
189
  * Return `true` if an inset animation is in progress.
184
190
  */
185
- fun isInsetAnimationInProgress(): Boolean {
186
- return insetsAnimationController != null
187
- }
191
+ fun isInsetAnimationInProgress(): Boolean = insetsAnimationController != null
188
192
 
189
193
  /**
190
194
  * Return `true` if an inset animation is currently finishing.
191
195
  */
192
- fun isInsetAnimationFinishing(): Boolean {
193
- return currentSpringAnimation != null
194
- }
196
+ fun isInsetAnimationFinishing(): Boolean = currentSpringAnimation != null
195
197
 
196
198
  /**
197
199
  * Return `true` if a request to control an inset animation is in progress.
198
200
  */
199
- fun isInsetAnimationRequestPending(): Boolean {
200
- return pendingRequestCancellationSignal != null
201
- }
201
+ fun isInsetAnimationRequestPending(): Boolean = pendingRequestCancellationSignal != null
202
202
 
203
203
  /**
204
204
  * Cancel the current [WindowInsetsAnimationControllerCompat]. We immediately finish
@@ -280,10 +280,11 @@ internal class KeyboardAnimationController {
280
280
  when {
281
281
  // If we have a velocity, we can use it's direction to determine
282
282
  // the visibility. Upwards == visible
283
- velocityY != null -> animateImeToVisibility(
284
- visible = velocityY < 0,
285
- velocityY = velocityY,
286
- )
283
+ velocityY != null ->
284
+ animateImeToVisibility(
285
+ visible = velocityY < 0,
286
+ velocityY = velocityY,
287
+ )
287
288
  // The current inset matches either the shown/hidden inset, finish() immediately
288
289
  current == shown -> {
289
290
  InteractiveKeyboardProvider.shown = true
@@ -307,11 +308,12 @@ internal class KeyboardAnimationController {
307
308
  }
308
309
 
309
310
  fun getCurrentKeyboardHeight(): Int {
310
- val controller = insetsAnimationController
311
- ?: throw IllegalStateException(
312
- "Current WindowInsetsAnimationController is null." +
313
- "This should only be called if isAnimationInProgress() returns true",
314
- )
311
+ val controller =
312
+ insetsAnimationController
313
+ ?: throw IllegalStateException(
314
+ "Current WindowInsetsAnimationController is null." +
315
+ "This should only be called if isAnimationInProgress() returns true",
316
+ )
315
317
 
316
318
  return controller.currentInsets.bottom
317
319
  }
@@ -356,37 +358,40 @@ internal class KeyboardAnimationController {
356
358
  velocityY: Float? = null,
357
359
  ) {
358
360
  @Suppress("detekt:UseCheckOrError")
359
- val controller = insetsAnimationController
360
- ?: throw IllegalStateException("Controller should not be null")
361
-
362
- currentSpringAnimation = springAnimationOf(
363
- setter = {
364
- insetTo(it.roundToInt())
365
- },
366
- getter = { controller.currentInsets.bottom.toFloat() },
367
- finalPosition = when {
368
- visible -> controller.shownStateInsets.bottom.toFloat()
369
- else -> controller.hiddenStateInsets.bottom.toFloat()
370
- },
371
- ).withSpringForceProperties {
372
- // Tweak the damping value, to remove any bounciness.
373
- dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
374
- // The stiffness value controls the strength of the spring animation, which
375
- // controls the speed. Medium (the default) is a good value, but feel free to
376
- // play around with this value.
377
- stiffness = SpringForce.STIFFNESS_MEDIUM
378
- }.apply {
379
- if (velocityY != null) {
380
- setStartVelocity(velocityY)
381
- }
382
- addEndListener { anim, _, _, _ ->
383
- if (anim == currentSpringAnimation) {
384
- currentSpringAnimation = null
361
+ val controller =
362
+ insetsAnimationController
363
+ ?: throw IllegalStateException("Controller should not be null")
364
+
365
+ currentSpringAnimation =
366
+ springAnimationOf(
367
+ setter = {
368
+ insetTo(it.roundToInt())
369
+ },
370
+ getter = { controller.currentInsets.bottom.toFloat() },
371
+ finalPosition =
372
+ when {
373
+ visible -> controller.shownStateInsets.bottom.toFloat()
374
+ else -> controller.hiddenStateInsets.bottom.toFloat()
375
+ },
376
+ ).withSpringForceProperties {
377
+ // Tweak the damping value, to remove any bounciness.
378
+ dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
379
+ // The stiffness value controls the strength of the spring animation, which
380
+ // controls the speed. Medium (the default) is a good value, but feel free to
381
+ // play around with this value.
382
+ stiffness = SpringForce.STIFFNESS_MEDIUM
383
+ }.apply {
384
+ if (velocityY != null) {
385
+ setStartVelocity(velocityY)
385
386
  }
386
- // Once the animation has ended, finish the controller
387
- finish()
388
- }
389
- }.also { it.start() }
387
+ addEndListener { anim, _, _, _ ->
388
+ if (anim == currentSpringAnimation) {
389
+ currentSpringAnimation = null
390
+ }
391
+ // Once the animation has ended, finish the controller
392
+ finish()
393
+ }
394
+ }.also { it.start() }
390
395
  }
391
396
  }
392
397
 
@@ -11,5 +11,10 @@ interface Interpolator {
11
11
  * @param offset extra space to the keyboard to activate a gesture
12
12
  * @return the distance the keyboard should be moved from its current location.
13
13
  */
14
- fun interpolate(dy: Int, absoluteFingerPosition: Int, keyboardPosition: Int, offset: Int): Int
14
+ fun interpolate(
15
+ dy: Int,
16
+ absoluteFingerPosition: Int,
17
+ keyboardPosition: Int,
18
+ offset: Int,
19
+ ): Int
15
20
  }
@@ -8,8 +8,10 @@ class IosInterpolator : Interpolator {
8
8
  offset: Int,
9
9
  ): Int {
10
10
  if (
11
- absoluteFingerPosition <= keyboardPosition + offset || // user over scrolled keyboard
12
- dy <= 0 // user scrolls up
11
+ // user over scrolled keyboard
12
+ absoluteFingerPosition <= keyboardPosition + offset ||
13
+ // user scrolls up
14
+ dy <= 0
13
15
  ) {
14
16
  return dy
15
17
  }
@@ -6,7 +6,5 @@ class LinearInterpolator : Interpolator {
6
6
  absoluteFingerPosition: Int,
7
7
  keyboardPosition: Int,
8
8
  offset: Int,
9
- ): Int {
10
- return dy
11
- }
9
+ ): Int = dy
12
10
  }
@@ -25,16 +25,17 @@ import com.reactnativekeyboardcontroller.extensions.screenLocation
25
25
  import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder
26
26
  import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator
27
27
 
28
- val noFocusedInputEvent = FocusedInputLayoutChangedEventData(
29
- x = 0.0,
30
- y = 0.0,
31
- width = 0.0,
32
- height = 0.0,
33
- absoluteX = 0.0,
34
- absoluteY = 0.0,
35
- target = -1,
36
- parentScrollViewTarget = -1,
37
- )
28
+ val noFocusedInputEvent =
29
+ FocusedInputLayoutChangedEventData(
30
+ x = 0.0,
31
+ y = 0.0,
32
+ width = 0.0,
33
+ height = 0.0,
34
+ absoluteX = 0.0,
35
+ absoluteY = 0.0,
36
+ target = -1,
37
+ parentScrollViewTarget = -1,
38
+ )
38
39
 
39
40
  class FocusedInputObserver(
40
41
  val view: View,
@@ -82,50 +83,52 @@ class FocusedInputObserver(
82
83
  FocusedInputSelectionChangedEvent(
83
84
  surfaceId,
84
85
  eventPropagationView.id,
85
- event = FocusedInputSelectionChangedEventData(
86
- target = input.id,
87
- start = start,
88
- end = end,
89
- startX = startX,
90
- startY = startY,
91
- endX = endX,
92
- endY = endY,
93
- ),
86
+ event =
87
+ FocusedInputSelectionChangedEventData(
88
+ target = input.id,
89
+ start = start,
90
+ end = end,
91
+ startX = startX,
92
+ startY = startY,
93
+ endX = endX,
94
+ endY = endY,
95
+ ),
94
96
  ),
95
97
  )
96
98
  }
97
- private val focusListener = OnGlobalFocusChangeListener { oldFocus, newFocus ->
98
- // unfocused or focus was changed
99
- if (newFocus == null || oldFocus != null) {
100
- lastFocusedInput?.removeOnLayoutChangeListener(layoutListener)
101
- lastFocusedInput?.removeTextChangedListener(textWatcher)
102
- selectionSubscription?.invoke()
103
- lastFocusedInput = null
104
- }
105
- if (newFocus is ReactEditText) {
106
- lastFocusedInput = newFocus
107
- newFocus.addOnLayoutChangeListener(layoutListener)
108
- this.syncUpLayout()
109
- textWatcher = newFocus.addOnTextChangedListener(textListener)
110
- selectionSubscription = newFocus.addOnSelectionChangedListener(selectionListener)
111
- FocusedInputHolder.set(newFocus)
99
+ private val focusListener =
100
+ OnGlobalFocusChangeListener { oldFocus, newFocus ->
101
+ // unfocused or focus was changed
102
+ if (newFocus == null || oldFocus != null) {
103
+ lastFocusedInput?.removeOnLayoutChangeListener(layoutListener)
104
+ lastFocusedInput?.removeTextChangedListener(textWatcher)
105
+ selectionSubscription?.invoke()
106
+ lastFocusedInput = null
107
+ }
108
+ if (newFocus is ReactEditText) {
109
+ lastFocusedInput = newFocus
110
+ newFocus.addOnLayoutChangeListener(layoutListener)
111
+ this.syncUpLayout()
112
+ textWatcher = newFocus.addOnTextChangedListener(textListener)
113
+ selectionSubscription = newFocus.addOnSelectionChangedListener(selectionListener)
114
+ FocusedInputHolder.set(newFocus)
112
115
 
113
- val allInputFields = ViewHierarchyNavigator.getAllInputFields(context?.rootView)
114
- val currentIndex = allInputFields.indexOf(newFocus)
116
+ val allInputFields = ViewHierarchyNavigator.getAllInputFields(context?.rootView)
117
+ val currentIndex = allInputFields.indexOf(newFocus)
115
118
 
116
- context.emitEvent(
117
- "KeyboardController::focusDidSet",
118
- Arguments.createMap().apply {
119
- putInt("current", currentIndex)
120
- putInt("count", allInputFields.size)
121
- },
122
- )
119
+ context.emitEvent(
120
+ "KeyboardController::focusDidSet",
121
+ Arguments.createMap().apply {
122
+ putInt("current", currentIndex)
123
+ putInt("count", allInputFields.size)
124
+ },
125
+ )
126
+ }
127
+ // unfocused
128
+ if (newFocus == null) {
129
+ dispatchEventToJS(noFocusedInputEvent)
130
+ }
123
131
  }
124
- // unfocused
125
- if (newFocus == null) {
126
- dispatchEventToJS(noFocusedInputEvent)
127
- }
128
- }
129
132
 
130
133
  init {
131
134
  view.viewTreeObserver.addOnGlobalFocusChangeListener(focusListener)
@@ -135,16 +138,17 @@ class FocusedInputObserver(
135
138
  val input = lastFocusedInput ?: return
136
139
 
137
140
  val (x, y) = input.screenLocation
138
- val event = FocusedInputLayoutChangedEventData(
139
- x = input.x.dp,
140
- y = input.y.dp,
141
- width = input.width.toFloat().dp,
142
- height = input.height.toFloat().dp,
143
- absoluteX = x.toFloat().dp,
144
- absoluteY = y.toFloat().dp,
145
- target = input.id,
146
- parentScrollViewTarget = input.parentScrollViewTarget,
147
- )
141
+ val event =
142
+ FocusedInputLayoutChangedEventData(
143
+ x = input.x.dp,
144
+ y = input.y.dp,
145
+ width = input.width.toFloat().dp,
146
+ height = input.height.toFloat().dp,
147
+ absoluteX = x.toFloat().dp,
148
+ absoluteY = y.toFloat().dp,
149
+ target = input.id,
150
+ parentScrollViewTarget = input.parentScrollViewTarget,
151
+ )
148
152
 
149
153
  dispatchEventToJS(event)
150
154
  }
@@ -1,7 +1,6 @@
1
1
  package com.reactnativekeyboardcontroller.listeners
2
2
 
3
3
  import android.os.Build
4
- import android.util.Log
5
4
  import android.view.View
6
5
  import android.view.ViewTreeObserver.OnGlobalFocusChangeListener
7
6
  import androidx.core.graphics.Insets
@@ -21,6 +20,7 @@ import com.reactnativekeyboardcontroller.extensions.dp
21
20
  import com.reactnativekeyboardcontroller.extensions.emitEvent
22
21
  import com.reactnativekeyboardcontroller.extensions.isKeyboardAnimation
23
22
  import com.reactnativekeyboardcontroller.interactive.InteractiveKeyboardProvider
23
+ import com.reactnativekeyboardcontroller.log.Logger
24
24
  import kotlin.math.abs
25
25
 
26
26
  private val TAG = KeyboardAnimationCallback::class.qualifiedName
@@ -38,7 +38,8 @@ class KeyboardAnimationCallback(
38
38
  val view: View,
39
39
  val context: ThemedReactContext?,
40
40
  private val config: KeyboardAnimationCallbackConfig,
41
- ) : WindowInsetsAnimationCompat.Callback(config.dispatchMode), OnApplyWindowInsetsListener {
41
+ ) : WindowInsetsAnimationCompat.Callback(config.dispatchMode),
42
+ OnApplyWindowInsetsListener {
42
43
  private val surfaceId = UIManagerHelper.getSurfaceId(eventPropagationView)
43
44
 
44
45
  // state variables
@@ -51,46 +52,47 @@ class KeyboardAnimationCallback(
51
52
  private var animationsToSkip = hashSetOf<WindowInsetsAnimationCompat>()
52
53
 
53
54
  // listeners
54
- private val focusListener = OnGlobalFocusChangeListener { oldFocus, newFocus ->
55
- if (newFocus is ReactEditText) {
56
- viewTagFocused = newFocus.id
57
-
58
- // keyboard is visible and focus has been changed
59
- if (this.isKeyboardVisible && oldFocus !== null) {
60
- // imitate iOS behavior and send two instant start/end events containing an info about new tag
61
- // 1. onStart/onMove/onEnd can be still dispatched after, if keyboard change size (numeric -> alphabetic type)
62
- // 2. event should be send only when keyboard is visible, since this event arrives earlier -> `tag` will be
63
- // 100% included in onStart/onMove/onEnd life cycles, but triggering onStart/onEnd several time
64
- // can bring breaking changes
65
- context.dispatchEvent(
66
- eventPropagationView.id,
67
- KeyboardTransitionEvent(
68
- surfaceId,
55
+ private val focusListener =
56
+ OnGlobalFocusChangeListener { oldFocus, newFocus ->
57
+ if (newFocus is ReactEditText) {
58
+ viewTagFocused = newFocus.id
59
+
60
+ // keyboard is visible and focus has been changed
61
+ if (this.isKeyboardVisible && oldFocus !== null) {
62
+ // imitate iOS behavior and send two instant start/end events containing an info about new tag
63
+ // 1. onStart/onMove/onEnd can be still dispatched after, if keyboard change size (numeric -> alphabetic type)
64
+ // 2. event should be send only when keyboard is visible, since this event arrives earlier -> `tag` will be
65
+ // 100% included in onStart/onMove/onEnd life cycles, but triggering onStart/onEnd several time
66
+ // can bring breaking changes
67
+ context.dispatchEvent(
69
68
  eventPropagationView.id,
70
- "topKeyboardMoveStart",
71
- this.persistentKeyboardHeight,
72
- 1.0,
73
- 0,
74
- viewTagFocused,
75
- ),
76
- )
77
- context.dispatchEvent(
78
- eventPropagationView.id,
79
- KeyboardTransitionEvent(
80
- surfaceId,
69
+ KeyboardTransitionEvent(
70
+ surfaceId,
71
+ eventPropagationView.id,
72
+ "topKeyboardMoveStart",
73
+ this.persistentKeyboardHeight,
74
+ 1.0,
75
+ 0,
76
+ viewTagFocused,
77
+ ),
78
+ )
79
+ context.dispatchEvent(
81
80
  eventPropagationView.id,
82
- "topKeyboardMoveEnd",
83
- this.persistentKeyboardHeight,
84
- 1.0,
85
- 0,
86
- viewTagFocused,
87
- ),
88
- )
89
- context.emitEvent("KeyboardController::keyboardWillShow", getEventParams(this.persistentKeyboardHeight))
90
- context.emitEvent("KeyboardController::keyboardDidShow", getEventParams(this.persistentKeyboardHeight))
81
+ KeyboardTransitionEvent(
82
+ surfaceId,
83
+ eventPropagationView.id,
84
+ "topKeyboardMoveEnd",
85
+ this.persistentKeyboardHeight,
86
+ 1.0,
87
+ 0,
88
+ viewTagFocused,
89
+ ),
90
+ )
91
+ context.emitEvent("KeyboardController::keyboardWillShow", getEventParams(this.persistentKeyboardHeight))
92
+ context.emitEvent("KeyboardController::keyboardDidShow", getEventParams(this.persistentKeyboardHeight))
93
+ }
91
94
  }
92
95
  }
93
- }
94
96
  private var layoutObserver: FocusedInputObserver? = null
95
97
 
96
98
  init {
@@ -113,7 +115,10 @@ class KeyboardAnimationCallback(
113
115
  * have to implement `onApplyWindowInsets` listener and simulate onStart/onProgress/onEnd
114
116
  * events when keyboard changes its size.
115
117
  */
116
- override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
118
+ override fun onApplyWindowInsets(
119
+ v: View,
120
+ insets: WindowInsetsCompat,
121
+ ): WindowInsetsCompat {
117
122
  val keyboardHeight = getCurrentKeyboardHeight()
118
123
  // when keyboard appears values will be (false && true)
119
124
  // when keyboard disappears values will be (true && false)
@@ -137,7 +142,7 @@ class KeyboardAnimationCallback(
137
142
  val isKeyboardSizeEqual = this.persistentKeyboardHeight == keyboardHeight
138
143
 
139
144
  if (isKeyboardFullyVisible && !isKeyboardSizeEqual && !isResizeHandledInCallbackMethods) {
140
- Log.i(TAG, "onApplyWindowInsets: ${this.persistentKeyboardHeight} -> $keyboardHeight")
145
+ Logger.i(TAG, "onApplyWindowInsets: ${this.persistentKeyboardHeight} -> $keyboardHeight")
141
146
  layoutObserver?.syncUpLayout()
142
147
  this.onKeyboardResized(keyboardHeight)
143
148
  }
@@ -182,7 +187,7 @@ class KeyboardAnimationCallback(
182
187
  getEventParams(keyboardHeight),
183
188
  )
184
189
 
185
- Log.i(TAG, "HEIGHT:: $keyboardHeight TAG:: $viewTagFocused")
190
+ Logger.i(TAG, "HEIGHT:: $keyboardHeight TAG:: $viewTagFocused")
186
191
  context.dispatchEvent(
187
192
  eventPropagationView.id,
188
193
  KeyboardTransitionEvent(
@@ -218,9 +223,10 @@ class KeyboardAnimationCallback(
218
223
  if (config.hasTranslucentNavigationBar) {
219
224
  otherInset = Insets.NONE
220
225
  }
221
- val diff = Insets.subtract(typesInset, otherInset).let {
222
- Insets.max(it, Insets.NONE)
223
- }
226
+ val diff =
227
+ Insets.subtract(typesInset, otherInset).let {
228
+ Insets.max(it, Insets.NONE)
229
+ }
224
230
  val diffY = (diff.bottom - diff.top).toFloat()
225
231
  val height = diffY.dp
226
232
 
@@ -229,9 +235,9 @@ class KeyboardAnimationCallback(
229
235
  progress = abs((height / persistentKeyboardHeight)).let { if (it.isNaN()) 0.0 else it }
230
236
  } catch (e: ArithmeticException) {
231
237
  // do nothing, just log an exception send progress as 0
232
- Log.w(TAG, "Caught arithmetic exception during `progress` calculation: $e")
238
+ Logger.w(TAG, "Caught arithmetic exception during `progress` calculation: $e")
233
239
  }
234
- Log.i(
240
+ Logger.i(
235
241
  TAG,
236
242
  "DiffY: $diffY $height $progress ${InteractiveKeyboardProvider.isInteractive} $viewTagFocused",
237
243
  )