react-native-keyboard-controller 1.0.0-alpha.3 → 1.0.1

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 (46) hide show
  1. package/README.md +5 -56
  2. package/android/build.gradle +1 -1
  3. package/android/gradle.properties +2 -0
  4. package/android/src/main/java/com/reactnativekeyboardcontroller/EdgeToEdgeReactViewGroup.kt +2 -0
  5. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +6 -6
  6. package/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +15 -2
  7. package/android/src/main/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +95 -0
  8. package/android/src/main/java/com/reactnativekeyboardcontroller/TranslateDeferringInsetsAnimationCallback.kt +49 -43
  9. package/ios/.swift-version +1 -0
  10. package/ios/.swiftformat +5 -0
  11. package/ios/.swiftlint.yml +5 -0
  12. package/ios/KeyboardControllerModule.swift +17 -17
  13. package/ios/KeyboardControllerViewManager.swift +87 -59
  14. package/ios/KeyboardMoveEvent.swift +31 -27
  15. package/lib/commonjs/animated.js +14 -11
  16. package/lib/commonjs/animated.js.map +1 -1
  17. package/lib/commonjs/index.js +2 -0
  18. package/lib/commonjs/index.js.map +1 -1
  19. package/lib/commonjs/monkey-patch.js +44 -0
  20. package/lib/commonjs/monkey-patch.js.map +1 -0
  21. package/lib/module/animated.js +13 -12
  22. package/lib/module/animated.js.map +1 -1
  23. package/lib/module/index.js +1 -0
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/module/monkey-patch.js +36 -0
  26. package/lib/module/monkey-patch.js.map +1 -0
  27. package/lib/typescript/animated.d.ts +5 -0
  28. package/lib/typescript/index.d.ts +1 -0
  29. package/lib/typescript/monkey-patch.d.ts +1 -0
  30. package/package.json +9 -6
  31. package/src/animated.tsx +20 -16
  32. package/src/index.ts +2 -0
  33. package/src/monkey-patch.tsx +36 -0
  34. package/android/.gradle/6.8/executionHistory/executionHistory.lock +0 -0
  35. package/android/.gradle/6.8/fileChanges/last-build.bin +0 -0
  36. package/android/.gradle/6.8/fileHashes/fileHashes.lock +0 -0
  37. package/android/.gradle/6.8/gc.properties +0 -0
  38. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  39. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  40. package/android/.gradle/checksums/checksums.lock +0 -0
  41. package/android/.gradle/configuration-cache/gc.properties +0 -0
  42. package/android/.gradle/vcs-1/gc.properties +0 -0
  43. package/ios/KeyboardController.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  44. package/ios/KeyboardController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  45. package/ios/KeyboardController.xcodeproj/project.xcworkspace/xcuserdata/kiryl.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  46. package/ios/KeyboardController.xcodeproj/xcuserdata/kiryl.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
package/README.md CHANGED
@@ -2,14 +2,11 @@
2
2
 
3
3
  Keyboard manager which works in identical way on both iOS and Android.
4
4
 
5
- > **Note**: This library is still in development and in `alpha` stage. So most likely it has bugs/issues - don't hesitate to report if you find them 🙂.
6
-
7
5
  ## Demonstration
8
6
 
9
- <div>
10
- <img align="right" width="28.65%" style="margin-left: 20px" src="./gifs/ios.gif?raw=true">
11
- <img align="right" width="30%" style="margin-left: 20px" src="./gifs/android.gif?raw=true">
12
- </div>
7
+ <img src="./gifs/demo.gif?raw=true" width="60%">
8
+
9
+ ## Key features
13
10
 
14
11
  - mapping keyboard appearance to animated values 😎
15
12
  - missing `keyboardWillShow` / `keyboardWillHide` events are available on Android 😍
@@ -18,8 +15,6 @@ Keyboard manager which works in identical way on both iOS and Android.
18
15
  - interactive keyboard dismissing (planned) 👆📱
19
16
  - and more is coming... Stay tuned! 😊
20
17
 
21
- <br clear="right" />
22
-
23
18
  ## Installation
24
19
 
25
20
  Install `react-native-keyboard-controller` package from npm:
@@ -30,55 +25,9 @@ yarn add react-native-keyboard-controller
30
25
  # npm install react-native-keyboard-controller --save
31
26
  ```
32
27
 
33
- ## Usage
34
-
35
- For more comprehensive usage you can have a look on [example](https://github.com/kirillzyusko/react-native-keyboard-controller/tree/main/example).
36
-
37
- Below you can see a short overview of library API:
28
+ ## Documentation
38
29
 
39
- ```js
40
- import {
41
- KeyboardProvider,
42
- useKeyboardAnimation,
43
- } from 'react-native-keyboard-controller';
44
-
45
- // 1. wrap your app in Provider
46
- <KeyboardProvider>
47
- <AppContainer />
48
- </KeyboardProvider>
49
-
50
- // 2. get animation values where you need them
51
- const { height, progress } = useKeyboardAnimation();
52
-
53
- // 3. Animate any elements as you wish :)
54
- <Animated.View
55
- style={{
56
- width: 50,
57
- height: 50,
58
- backgroundColor: 'red',
59
- borderRadius: 25,
60
- // the element will move up with the keyboard
61
- transform: [{ translateY: height }],
62
- }}
63
- />
64
- <Animated.View
65
- style={{
66
- width: 50,
67
- height: 50,
68
- backgroundColor: 'green',
69
- borderRadius: 25,
70
- transform: [
71
- {
72
- // or use custom interpolation using `progress`
73
- translateX: progress.interpolate({
74
- inputRange: [0, 1],
75
- outputRange: [0, 100],
76
- }),
77
- },
78
- ],
79
- }}
80
- />
81
- ```
30
+ Check out our dedicated documentation page for info about this library, API reference and more: [https://kirillzyusko.github.io/react-native-keyboard-controller/](https://kirillzyusko.github.io/react-native-keyboard-controller/)
82
31
 
83
32
  ## Contributing
84
33
 
@@ -41,7 +41,7 @@ android {
41
41
  }
42
42
  }
43
43
  lintOptions {
44
- disable 'GradleCompatible'
44
+ warningsAsErrors true
45
45
  }
46
46
  compileOptions {
47
47
  sourceCompatibility JavaVersion.VERSION_1_8
@@ -1,3 +1,5 @@
1
1
  KeyboardController_kotlinVersion=1.3.50
2
2
  KeyboardController_compileSdkVersion=29
3
3
  KeyboardController_targetSdkVersion=29
4
+
5
+ android.useAndroidX=true
@@ -1,9 +1,11 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
+ import android.annotation.SuppressLint
3
4
  import androidx.core.view.WindowCompat
4
5
  import com.facebook.react.uimanager.ThemedReactContext
5
6
  import com.facebook.react.views.view.ReactViewGroup
6
7
 
8
+ @SuppressLint("ViewConstructor")
7
9
  class EdgeToEdgeReactViewGroup(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) {
8
10
  override fun onAttachedToWindow() {
9
11
  super.onAttachedToWindow()
@@ -6,11 +6,11 @@ import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.uimanager.ViewManager
7
7
 
8
8
  class KeyboardControllerPackage : ReactPackage {
9
- override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
- return listOf(KeyboardControllerModule(reactContext))
11
- }
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
+ return listOf(KeyboardControllerModule(reactContext), StatusBarManagerCompatModule(reactContext))
11
+ }
12
12
 
13
- override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
14
- return listOf(KeyboardControllerViewManager(reactContext))
15
- }
13
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
14
+ return listOf(KeyboardControllerViewManager(reactContext))
15
+ }
16
16
  }
@@ -1,7 +1,10 @@
1
1
  package com.reactnativekeyboardcontroller
2
2
 
3
+ import android.util.Log
3
4
  import androidx.appcompat.widget.FitWindowsLinearLayout
4
- import androidx.core.view.*
5
+ import androidx.core.view.ViewCompat
6
+ import androidx.core.view.WindowInsetsAnimationCompat
7
+ import androidx.core.view.WindowInsetsCompat
5
8
  import com.facebook.react.bridge.ReactApplicationContext
6
9
  import com.facebook.react.common.MapBuilder
7
10
  import com.facebook.react.uimanager.ThemedReactContext
@@ -11,6 +14,7 @@ import com.facebook.react.views.view.ReactViewManager
11
14
  import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
12
15
 
13
16
  class KeyboardControllerViewManager(reactContext: ReactApplicationContext) : ReactViewManager() {
17
+ private val TAG = KeyboardControllerViewManager::class.qualifiedName
14
18
  private var mReactContext = reactContext
15
19
  private var isStatusBarTranslucent = false
16
20
 
@@ -18,6 +22,15 @@ class KeyboardControllerViewManager(reactContext: ReactApplicationContext) : Rea
18
22
 
19
23
  override fun createViewInstance(reactContext: ThemedReactContext): ReactViewGroup {
20
24
  val view = EdgeToEdgeReactViewGroup(reactContext)
25
+ val activity = mReactContext.currentActivity
26
+
27
+ if (activity == null) {
28
+ Log.w(TAG, "Can not setup keyboard animation listener, since `currentActivity` is null")
29
+ return view
30
+ }
31
+
32
+ val window = activity.window
33
+ val decorView = window.decorView
21
34
 
22
35
  ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
23
36
  val content =
@@ -33,7 +46,7 @@ class KeyboardControllerViewManager(reactContext: ReactApplicationContext) : Rea
33
46
  }
34
47
 
35
48
  ViewCompat.setWindowInsetsAnimationCallback(
36
- reactContext.currentActivity!!.window!!.decorView,
49
+ decorView,
37
50
  TranslateDeferringInsetsAnimationCallback(
38
51
  view = view,
39
52
  persistentInsetTypes = WindowInsetsCompat.Type.systemBars(),
@@ -0,0 +1,95 @@
1
+ package com.reactnativekeyboardcontroller
2
+
3
+ import android.animation.ArgbEvaluator
4
+ import android.animation.ValueAnimator
5
+ import android.os.Build
6
+ import android.util.Log
7
+ import androidx.annotation.RequiresApi
8
+ import androidx.core.view.WindowInsetsCompat
9
+ import androidx.core.view.WindowInsetsControllerCompat
10
+ import com.facebook.react.bridge.ReactApplicationContext
11
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
12
+ import com.facebook.react.bridge.ReactMethod
13
+ import com.facebook.react.bridge.UiThreadUtil
14
+
15
+ class StatusBarManagerCompatModule(private val mReactContext: ReactApplicationContext) : ReactContextBaseJavaModule(mReactContext) {
16
+ private val TAG = StatusBarManagerCompatModule::class.qualifiedName
17
+ private var controller: WindowInsetsControllerCompat? = null
18
+
19
+ override fun getName(): String = "StatusBarManagerCompat"
20
+
21
+ @ReactMethod
22
+ private fun setHidden(hidden: Boolean) {
23
+ UiThreadUtil.runOnUiThread {
24
+ if (hidden) {
25
+ getController()?.hide(WindowInsetsCompat.Type.statusBars())
26
+ } else {
27
+ getController()?.show(WindowInsetsCompat.Type.statusBars())
28
+ }
29
+ }
30
+ }
31
+
32
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
33
+ @ReactMethod
34
+ private fun setColor(color: Int, animated: Boolean) {
35
+ val activity = mReactContext.currentActivity
36
+ if (activity == null) {
37
+ Log.w(TAG, "StatusBarManagerCompatModule: Ignored status bar change, current activity is null.")
38
+ return
39
+ }
40
+
41
+ UiThreadUtil.runOnUiThread {
42
+ val window = activity.window
43
+
44
+ if (animated) {
45
+ val curColor: Int = window.statusBarColor
46
+ val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), curColor, color)
47
+ colorAnimation.addUpdateListener { animator ->
48
+ window.statusBarColor = animator.animatedValue as Int
49
+ }
50
+ colorAnimation.setDuration(300).startDelay = 0
51
+ colorAnimation.start()
52
+ } else {
53
+ window.statusBarColor = color
54
+ }
55
+ }
56
+ }
57
+
58
+ @ReactMethod
59
+ private fun setTranslucent(translucent: Boolean) {
60
+ // the status bar is translucent by default (once you wrapped App in Provider,
61
+ // and EdgeToEdgeReactViewGroup has been mounted and called
62
+ // `setDecorFitsSystemWindows(window, false)`. By default this library applies default padding
63
+ // which equal to StatusBar height, so it will have a default RN app behavior. Though once you
64
+ // need to set StatusBar as translucent, you will need to use `statusBarTranslucent` prop on
65
+ // `KeyboardProvider` (it will preventing of applying additional padding, and status bar will be
66
+ // translucent. Though it's important to note, that this value is not reactive (i. e. if you change
67
+ // `statusBarTranslucent` in runtime it will not have any effect. Just theoretically I could make
68
+ // it reactive, but I know, that most of apps or don't use StatusBar translucency at all or they are
69
+ // specifying it for entire app, so I don't see a lot of sense to make it reactive as of now. If your
70
+ // app requires to dynamically manage it - just shoot an issue and I will try to add a support fot that.
71
+ }
72
+
73
+ @ReactMethod
74
+ private fun setStyle(style: String) {
75
+ UiThreadUtil.runOnUiThread {
76
+ getController()?.isAppearanceLightStatusBars = style == "dark-content"
77
+ }
78
+ }
79
+
80
+ private fun getController(): WindowInsetsControllerCompat? {
81
+ if (this.controller == null) {
82
+ val activity = mReactContext.currentActivity
83
+ if (activity == null) {
84
+ Log.w(TAG, "StatusBarManagerCompatModule: can not get `WindowInsetsControllerCompat` because current activity is null.")
85
+ return this.controller
86
+ }
87
+
88
+ val window = activity.window
89
+
90
+ this.controller = WindowInsetsControllerCompat(window, window.decorView)
91
+ }
92
+
93
+ return this.controller
94
+ }
95
+ }
@@ -31,7 +31,13 @@ import com.facebook.react.views.view.ReactViewGroup
31
31
  import com.reactnativekeyboardcontroller.events.KeyboardTransitionEvent
32
32
  import java.util.*
33
33
 
34
- fun toDp(px: Float, context: Context): Int = (px / context.resources.displayMetrics.density).toInt()
34
+ fun toDp(px: Float, context: Context?): Int {
35
+ if (context == null) {
36
+ return 0
37
+ }
38
+
39
+ return (px / context.resources.displayMetrics.density).toInt()
40
+ }
35
41
 
36
42
  /**
37
43
  * A [WindowInsetsAnimationCompat.Callback] which will translate/move the given view during any
@@ -61,10 +67,10 @@ class TranslateDeferringInsetsAnimationCallback(
61
67
  private var persistentKeyboardHeight = 0
62
68
 
63
69
  init {
64
- require(persistentInsetTypes and deferredInsetTypes == 0) {
65
- "persistentInsetTypes and deferredInsetTypes can not contain any of " +
66
- " same WindowInsetsCompat.Type values"
67
- }
70
+ require(persistentInsetTypes and deferredInsetTypes == 0) {
71
+ "persistentInsetTypes and deferredInsetTypes can not contain any of " +
72
+ " same WindowInsetsCompat.Type values"
73
+ }
68
74
  }
69
75
 
70
76
  override fun onStart(
@@ -81,9 +87,9 @@ class TranslateDeferringInsetsAnimationCallback(
81
87
 
82
88
  val params: WritableMap = Arguments.createMap()
83
89
  params.putInt("height", keyboardHeight)
84
- context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("KeyboardController::" + if(!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow", params)
90
+ context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("KeyboardController::" + if (!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow", params)
85
91
 
86
- Log.i(TAG, "KeyboardController::" + if(!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow")
92
+ Log.i(TAG, "KeyboardController::" + if (!isKeyboardVisible) "keyboardWillHide" else "keyboardWillShow")
87
93
  Log.i(TAG, "HEIGHT:: $keyboardHeight")
88
94
 
89
95
  return super.onStart(animation, bounds)
@@ -95,9 +101,9 @@ class TranslateDeferringInsetsAnimationCallback(
95
101
  val isKeyboardVisible = isKeyboardVisible()
96
102
 
97
103
  val params: WritableMap = Arguments.createMap()
98
- context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("KeyboardController::" + if(!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow", params)
104
+ context?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow", params)
99
105
 
100
- Log.i(TAG, "KeyboardController::" + if(!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow")
106
+ Log.i(TAG, "KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow")
101
107
  }
102
108
 
103
109
  private fun isKeyboardVisible(): Boolean {
@@ -112,41 +118,41 @@ class TranslateDeferringInsetsAnimationCallback(
112
118
  val navigationBar = insets?.getInsets(WindowInsetsCompat.Type.navigationBars())?.bottom ?: 0
113
119
 
114
120
  // on hide it will be negative value, so we are using max function
115
- return Math.max(toDp((keyboardHeight - navigationBar).toFloat(), context!!), 0)
121
+ return Math.max(toDp((keyboardHeight - navigationBar).toFloat(), context), 0)
116
122
  }
117
123
 
118
- override fun onProgress(
119
- insets: WindowInsetsCompat,
120
- runningAnimations: List<WindowInsetsAnimationCompat>
121
- ): WindowInsetsCompat {
122
- // onProgress() is called when any of the running animations progress...
123
-
124
- // First we get the insets which are potentially deferred
125
- val typesInset = insets.getInsets(deferredInsetTypes)
126
- // Then we get the persistent inset types which are applied as padding during layout
127
- val otherInset = insets.getInsets(persistentInsetTypes)
128
-
129
- // Now that we subtract the two insets, to calculate the difference. We also coerce
130
- // the insets to be >= 0, to make sure we don't use negative insets.
131
- val diff = Insets.subtract(typesInset, otherInset).let {
132
- Insets.max(it, Insets.NONE)
133
- }
134
- val diffY = (diff.top - diff.bottom).toFloat()
135
- val height = toDp(diffY, context!!)
136
-
137
- var progress = 0.0
138
- try {
139
- progress = Math.abs((height.toDouble() / persistentKeyboardHeight))
140
- } catch (e: ArithmeticException) {
141
- // do nothing, send progress as 0
142
- }
143
- Log.i(TAG, "DiffY: $diffY $height")
144
-
145
- context
146
- .getNativeModule(UIManagerModule::class.java)
147
- ?.eventDispatcher
148
- ?.dispatchEvent(KeyboardTransitionEvent(view.id, height, progress))
149
-
150
- return insets
124
+ override fun onProgress(
125
+ insets: WindowInsetsCompat,
126
+ runningAnimations: List<WindowInsetsAnimationCompat>
127
+ ): WindowInsetsCompat {
128
+ // onProgress() is called when any of the running animations progress...
129
+
130
+ // First we get the insets which are potentially deferred
131
+ val typesInset = insets.getInsets(deferredInsetTypes)
132
+ // Then we get the persistent inset types which are applied as padding during layout
133
+ val otherInset = insets.getInsets(persistentInsetTypes)
134
+
135
+ // Now that we subtract the two insets, to calculate the difference. We also coerce
136
+ // the insets to be >= 0, to make sure we don't use negative insets.
137
+ val diff = Insets.subtract(typesInset, otherInset).let {
138
+ Insets.max(it, Insets.NONE)
151
139
  }
140
+ val diffY = (diff.top - diff.bottom).toFloat()
141
+ val height = toDp(diffY, context)
142
+
143
+ var progress = 0.0
144
+ try {
145
+ progress = Math.abs((height.toDouble() / persistentKeyboardHeight))
146
+ } catch (e: ArithmeticException) {
147
+ // do nothing, send progress as 0
148
+ }
149
+ Log.i(TAG, "DiffY: $diffY $height")
150
+
151
+ context
152
+ ?.getNativeModule(UIManagerModule::class.java)
153
+ ?.eventDispatcher
154
+ ?.dispatchEvent(KeyboardTransitionEvent(view.id, height, progress))
155
+
156
+ return insets
157
+ }
152
158
  }
@@ -0,0 +1 @@
1
+ 5.6
@@ -0,0 +1,5 @@
1
+ --indent 2
2
+
3
+ --disable redundantReturn
4
+
5
+ --exclude Pods,Generated
@@ -0,0 +1,5 @@
1
+ disabled_rules:
2
+ - trailing_comma
3
+
4
+ excluded:
5
+ - Pods
@@ -6,15 +6,15 @@
6
6
  // Copyright © 2022 Facebook. All rights reserved.
7
7
  //
8
8
 
9
+ import AVFoundation
9
10
  import Foundation
10
11
  import UIKit
11
- import AVFoundation
12
12
 
13
13
  @objc(KeyboardController)
14
14
  class KeyboardController: RCTEventEmitter {
15
15
  public static var shared: KeyboardController?
16
16
  private var hasListeners = false
17
-
17
+
18
18
  override class func requiresMainQueueSetup() -> Bool {
19
19
  return false
20
20
  }
@@ -25,29 +25,29 @@ class KeyboardController: RCTEventEmitter {
25
25
  }
26
26
 
27
27
  // Android stubs
28
- @objc func setInputMode(_ mode: NSNumber!) {}
28
+ @objc func setInputMode(_: NSNumber!) {}
29
29
  @objc func setDefaultMode() {}
30
-
31
- @objc open override func supportedEvents() -> [String] {
30
+
31
+ @objc override open func supportedEvents() -> [String] {
32
32
  return [
33
- "KeyboardController::keyboardWillShow",
34
- "KeyboardController::keyboardDidShow",
35
- "KeyboardController::keyboardWillHide",
36
- "KeyboardController::keyboardDidHide"
33
+ "KeyboardController::keyboardWillShow",
34
+ "KeyboardController::keyboardDidShow",
35
+ "KeyboardController::keyboardWillHide",
36
+ "KeyboardController::keyboardDidHide",
37
37
  ]
38
38
  }
39
-
40
- @objc open override func startObserving() {
39
+
40
+ @objc override open func startObserving() {
41
41
  hasListeners = true
42
42
  }
43
-
44
- @objc open override func stopObserving() {
43
+
44
+ @objc override open func stopObserving() {
45
45
  hasListeners = false
46
46
  }
47
-
48
- @objc open override func sendEvent(withName name: String!, body: Any!) {
49
- if (hasListeners) {
50
- super.sendEvent(withName: name, body: body)
47
+
48
+ @objc override open func sendEvent(withName name: String!, body: Any!) {
49
+ if hasListeners {
50
+ super.sendEvent(withName: name, body: body)
51
51
  }
52
52
  }
53
53
  }
@@ -5,74 +5,102 @@ class KeyboardControllerViewManager: RCTViewManager {
5
5
  }
6
6
 
7
7
  override func view() -> (KeyboardControllerView) {
8
- return KeyboardControllerView(frame: CGRect.zero, eventDispatcher: self.bridge.eventDispatcher())
8
+ return KeyboardControllerView(frame: CGRect.zero, eventDispatcher: bridge.eventDispatcher())
9
9
  }
10
10
  }
11
11
 
12
- class KeyboardControllerView : UIView {
13
- private var eventDispatcher: RCTEventDispatcherProtocol
14
- @objc var onKeyboardMove: RCTDirectEventBlock?
15
-
16
- init(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) {
17
- self.eventDispatcher = eventDispatcher
18
- super.init(frame: frame)
19
- }
20
-
21
- required init?(coder: NSCoder) {
22
- fatalError("init(coder:) has not been implemented")
23
- }
24
-
25
- override func willMove(toWindow newWindow: UIWindow?) {
26
- if (newWindow == nil) {
27
- // Will be removed from a window
28
- NotificationCenter.default.removeObserver(self)
29
- }
30
- }
31
-
32
- override func didMoveToWindow() {
33
- if (self.window != nil) {
34
- // Added to a window
35
- NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear), name: UIResponder.keyboardWillHideNotification, object: nil)
36
- NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear), name: UIResponder.keyboardWillShowNotification, object: nil)
37
- NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidAppear), name: UIResponder.keyboardDidShowNotification, object: nil)
38
- NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidDisappear), name: UIResponder.keyboardDidHideNotification, object: nil)
39
- }
40
- }
12
+ class KeyboardControllerView: UIView {
13
+ private var eventDispatcher: RCTEventDispatcherProtocol
14
+ @objc var onKeyboardMove: RCTDirectEventBlock?
41
15
 
42
- @objc func keyboardWillAppear(_ notification: Notification) {
43
- if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
44
- let keyboardHeight = keyboardFrame.cgRectValue.size.height
16
+ init(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) {
17
+ self.eventDispatcher = eventDispatcher
18
+ super.init(frame: frame)
19
+ }
45
20
 
46
- self.eventDispatcher.send(KeyboardMoveEvent(reactTag: self.reactTag, height: -keyboardHeight as NSNumber, progress: 1))
21
+ @available(*, unavailable)
22
+ required init?(coder _: NSCoder) {
23
+ fatalError("init(coder:) has not been implemented")
24
+ }
47
25
 
48
- var data = [AnyHashable: Any]()
49
- data["height"] = keyboardHeight
50
- KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardWillShow", body: data)
51
- }
26
+ override func willMove(toWindow newWindow: UIWindow?) {
27
+ if newWindow == nil {
28
+ // Will be removed from a window
29
+ // swiftlint:disable notification_center_detachment
30
+ NotificationCenter.default.removeObserver(self)
52
31
  }
32
+ }
53
33
 
54
- @objc func keyboardWillDisappear() {
55
- self.eventDispatcher.send(KeyboardMoveEvent(reactTag: self.reactTag, height: 0, progress: 0))
56
-
57
- var data = [AnyHashable: Any]()
58
- data["height"] = 0
59
- KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardWillHide", body: data)
34
+ override func didMoveToWindow() {
35
+ if window != nil {
36
+ // Added to a window
37
+ NotificationCenter.default.addObserver(
38
+ self,
39
+ selector: #selector(keyboardWillDisappear),
40
+ name: UIResponder.keyboardWillHideNotification,
41
+ object: nil
42
+ )
43
+ NotificationCenter.default.addObserver(
44
+ self,
45
+ selector: #selector(keyboardWillAppear),
46
+ name: UIResponder.keyboardWillShowNotification,
47
+ object: nil
48
+ )
49
+ NotificationCenter.default.addObserver(
50
+ self,
51
+ selector: #selector(keyboardDidAppear),
52
+ name: UIResponder.keyboardDidShowNotification,
53
+ object: nil
54
+ )
55
+ NotificationCenter.default.addObserver(
56
+ self,
57
+ selector: #selector(keyboardDidDisappear),
58
+ name: UIResponder.keyboardDidHideNotification,
59
+ object: nil
60
+ )
60
61
  }
61
-
62
- @objc func keyboardDidAppear(_ notification: Notification) {
63
- if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
64
- let keyboardHeight = keyboardFrame.cgRectValue.size.height
65
-
66
- var data = [AnyHashable: Any]()
67
- data["height"] = keyboardHeight
68
-
69
- KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardDidShow", body: data)
70
- }
62
+ }
63
+
64
+ @objc func keyboardWillAppear(_ notification: Notification) {
65
+ if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
66
+ let keyboardHeight = keyboardFrame.cgRectValue.size.height
67
+
68
+ eventDispatcher.send(
69
+ KeyboardMoveEvent(
70
+ viewTag: reactTag,
71
+ height: -keyboardHeight as NSNumber,
72
+ progress: 1
73
+ )
74
+ )
75
+
76
+ var data = [AnyHashable: Any]()
77
+ data["height"] = keyboardHeight
78
+ KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardWillShow", body: data)
71
79
  }
72
-
73
- @objc func keyboardDidDisappear() {
74
- var data = [AnyHashable: Any]()
75
- data["height"] = 0
76
- KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardDidHide", body: data)
80
+ }
81
+
82
+ @objc func keyboardWillDisappear() {
83
+ eventDispatcher.send(KeyboardMoveEvent(viewTag: reactTag, height: 0, progress: 0))
84
+
85
+ var data = [AnyHashable: Any]()
86
+ data["height"] = 0
87
+ KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardWillHide", body: data)
88
+ }
89
+
90
+ @objc func keyboardDidAppear(_ notification: Notification) {
91
+ if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
92
+ let keyboardHeight = keyboardFrame.cgRectValue.size.height
93
+
94
+ var data = [AnyHashable: Any]()
95
+ data["height"] = keyboardHeight
96
+
97
+ KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardDidShow", body: data)
77
98
  }
99
+ }
100
+
101
+ @objc func keyboardDidDisappear() {
102
+ var data = [AnyHashable: Any]()
103
+ data["height"] = 0
104
+ KeyboardController.shared?.sendEvent(withName: "KeyboardController::keyboardDidHide", body: data)
105
+ }
78
106
  }