From 1d43a3263a4d2e9adddcbecfcf2b1e462dd7613c Mon Sep 17 00:00:00 2001 From: Kirill Zyusko Date: Fri, 27 Sep 2024 09:21:09 +0200 Subject: [PATCH] chore: update ktlint (#596) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📜 Description Updated `ktlint` to latest `1.3.1` version. ## 💡 Motivation and Context Updated `ktlint` to latest `1.3.1` version and formatted the code according to new rules. There was a conflict between `detekt` and `ktlint` (max-len 120 vs 140). To fix that I added `.editorconfig` where I overwrote default ktlint config and specified 120 characters as max-len. ## 📢 Changelog ### Android - apply new formatting to the code; ### JS - added `.editorconfig` to npmignore; ### CI - updated `ktlint` to `1.3.1` ## 🤔 How Has This Been Tested? Tested on CI. ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed --- .github/workflows/verify-android.yml | 2 +- android/.editorconfig | 2 + .../KeyboardControllerModule.kt | 8 +- .../KeyboardControllerViewManager.kt | 39 +++-- .../KeyboardGestureAreaViewManager.kt | 34 +++-- .../OverKeyboardViewManager.kt | 22 +-- .../StatusBarManagerCompatModule.kt | 10 +- .../KeyboardControllerPackage.kt | 56 ++++---- .../events/FocusedInputLayoutChangedEvent.kt | 31 ++-- .../FocusedInputSelectionChangedEvent.kt | 49 +++---- .../events/FocusedInputTextChangedEvent.kt | 7 +- .../events/KeyboardTransitionEvent.kt | 13 +- .../extensions/EditText.kt | 136 ++++++++++-------- .../extensions/ReactContext.kt | 13 +- .../extensions/ThemedReactContext.kt | 13 +- .../extensions/View.kt | 18 +-- .../KeyboardAnimationController.kt | 125 ++++++++-------- .../interactive/interpolators/Interpolator.kt | 7 +- .../interpolators/IosInterpolator.kt | 6 +- .../interpolators/LinearInterpolator.kt | 4 +- .../listeners/FocusedInputObserver.kt | 120 ++++++++-------- .../listeners/KeyboardAnimationCallback.kt | 88 ++++++------ .../listeners/WindowDimensionListener.kt | 20 ++- .../log/Logger.kt | 12 +- .../KeyboardControllerViewManagerImpl.kt | 59 ++++---- .../KeyboardGestureAreaViewManagerImpl.kt | 29 ++-- .../managers/OverKeyboardViewManagerImpl.kt | 14 +- .../modal/ModalAttachedWatcher.kt | 26 ++-- .../modules/KeyboardControllerModuleImpl.kt | 9 +- .../StatusBarManagerCompatModuleImpl.kt | 9 +- .../traversal/FocusedInputHolder.kt | 4 +- .../traversal/ViewHierarchyNavigator.kt | 32 +++-- .../ui/FrameScheduler.kt | 19 +-- .../views/EdgeToEdgeReactViewGroup.kt | 39 ++--- .../KeyboardGestureAreaReactViewGroup.kt | 37 +++-- .../overlay/OverKeyboardHostShadowNode.kt | 5 +- .../views/overlay/OverKeyboardViewGroup.kt | 51 +++++-- .../KeyboardControllerModule.kt | 4 +- .../KeyboardControllerViewManager.kt | 29 ++-- .../KeyboardGestureAreaViewManager.kt | 29 ++-- .../OverKeyboardViewManager.kt | 17 ++- .../StatusBarManagerCompatModule.kt | 10 +- .../traversal/ViewHierarchyNavigatorTest.kt | 51 ++++--- package.json | 1 + 44 files changed, 760 insertions(+), 549 deletions(-) create mode 100644 android/.editorconfig diff --git a/.github/workflows/verify-android.yml b/.github/workflows/verify-android.yml index 78292f4b1..d8822834e 100644 --- a/.github/workflows/verify-android.yml +++ b/.github/workflows/verify-android.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v4 - uses: touchlab-lab/ktlint-action-setup@1.0.0 with: - ktlint_version: 0.48.0 + ktlint_version: 1.3.1 - run: ktlint "android/src/**/*.kt" android-lint: runs-on: ubuntu-latest diff --git a/android/.editorconfig b/android/.editorconfig new file mode 100644 index 000000000..07bb82dc3 --- /dev/null +++ b/android/.editorconfig @@ -0,0 +1,2 @@ +[*.{kt,kts}] +max_line_length = 120 \ No newline at end of file diff --git a/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt b/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt index fff076c2d..c84ebced2 100644 --- a/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +++ b/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt @@ -3,7 +3,9 @@ package com.reactnativekeyboardcontroller import com.facebook.react.bridge.ReactApplicationContext import com.reactnativekeyboardcontroller.modules.KeyboardControllerModuleImpl -class KeyboardControllerModule(mReactContext: ReactApplicationContext) : NativeKeyboardControllerSpec(mReactContext) { +class KeyboardControllerModule( + mReactContext: ReactApplicationContext, +) : NativeKeyboardControllerSpec(mReactContext) { private val module = KeyboardControllerModuleImpl(mReactContext) override fun getName(): String = KeyboardControllerModuleImpl.NAME @@ -25,10 +27,10 @@ class KeyboardControllerModule(mReactContext: ReactApplicationContext) : NativeK } override fun addListener(eventName: String?) { - /* Required for RN built-in Event Emitter Calls. */ + // Required for RN built-in Event Emitter Calls. } override fun removeListeners(count: Double) { - /* Required for RN built-in Event Emitter Calls. */ + // Required for RN built-in Event Emitter Calls. } } diff --git a/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt b/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt index 9f897bb5c..ffbce2d7a 100644 --- a/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +++ b/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt @@ -11,38 +11,37 @@ import com.facebook.react.views.view.ReactViewManager import com.reactnativekeyboardcontroller.managers.KeyboardControllerViewManagerImpl import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup -class KeyboardControllerViewManager(mReactContext: ReactApplicationContext) : - ReactViewManager(), +class KeyboardControllerViewManager( + mReactContext: ReactApplicationContext, +) : ReactViewManager(), KeyboardControllerViewManagerInterface { private val manager = KeyboardControllerViewManagerImpl(mReactContext) private val mDelegate = KeyboardControllerViewManagerDelegate(this) - override fun getDelegate(): ViewManagerDelegate { - return mDelegate - } + override fun getDelegate(): ViewManagerDelegate = mDelegate override fun getName(): String = KeyboardControllerViewManagerImpl.NAME - override fun createViewInstance(context: ThemedReactContext): ReactViewGroup { - return manager.createViewInstance(context) - } + override fun createViewInstance(context: ThemedReactContext): ReactViewGroup = manager.createViewInstance(context) @ReactProp(name = "statusBarTranslucent") - override fun setStatusBarTranslucent(view: ReactViewGroup, value: Boolean) { - return manager.setStatusBarTranslucent(view as EdgeToEdgeReactViewGroup, value) - } + override fun setStatusBarTranslucent( + view: ReactViewGroup, + value: Boolean, + ) = manager.setStatusBarTranslucent(view as EdgeToEdgeReactViewGroup, value) @ReactProp(name = "navigationBarTranslucent") - override fun setNavigationBarTranslucent(view: ReactViewGroup, value: Boolean) { - return manager.setNavigationBarTranslucent(view as EdgeToEdgeReactViewGroup, value) - } + override fun setNavigationBarTranslucent( + view: ReactViewGroup, + value: Boolean, + ) = manager.setNavigationBarTranslucent(view as EdgeToEdgeReactViewGroup, value) @ReactProp(name = "enabled") - override fun setEnabled(view: ReactViewGroup, value: Boolean) { - return manager.setEnabled(view as EdgeToEdgeReactViewGroup, value) - } + override fun setEnabled( + view: ReactViewGroup, + value: Boolean, + ) = manager.setEnabled(view as EdgeToEdgeReactViewGroup, value) - override fun getExportedCustomDirectEventTypeConstants(): MutableMap { - return manager.getExportedCustomDirectEventTypeConstants() - } + override fun getExportedCustomDirectEventTypeConstants(): MutableMap = + manager.getExportedCustomDirectEventTypeConstants() } diff --git a/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt b/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt index a92c0ad84..aeaa64d73 100644 --- a/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +++ b/android/src/fabric/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt @@ -11,39 +11,49 @@ import com.facebook.react.views.view.ReactViewManager import com.reactnativekeyboardcontroller.managers.KeyboardGestureAreaViewManagerImpl import com.reactnativekeyboardcontroller.views.KeyboardGestureAreaReactViewGroup -class KeyboardGestureAreaViewManager(mReactContext: ReactApplicationContext) : - ReactViewManager(), +class KeyboardGestureAreaViewManager( + mReactContext: ReactApplicationContext, +) : ReactViewManager(), KeyboardGestureAreaManagerInterface { private val manager = KeyboardGestureAreaViewManagerImpl(mReactContext) private val mDelegate = KeyboardGestureAreaManagerDelegate(this) - override fun getDelegate(): ViewManagerDelegate { - return mDelegate - } + override fun getDelegate(): ViewManagerDelegate = mDelegate override fun getName(): String = KeyboardGestureAreaViewManagerImpl.NAME - override fun createViewInstance(context: ThemedReactContext): KeyboardGestureAreaReactViewGroup { - return manager.createViewInstance(context) - } + override fun createViewInstance(context: ThemedReactContext): KeyboardGestureAreaReactViewGroup = + manager.createViewInstance(context) @ReactProp(name = "offset") - override fun setOffset(view: ReactViewGroup, value: Double) { + override fun setOffset( + view: ReactViewGroup, + value: Double, + ) { manager.setOffset(view as KeyboardGestureAreaReactViewGroup, value) } @ReactProp(name = "interpolator") - override fun setInterpolator(view: ReactViewGroup, value: String?) { + override fun setInterpolator( + view: ReactViewGroup, + value: String?, + ) { manager.setInterpolator(view as KeyboardGestureAreaReactViewGroup, value ?: "linear") } @ReactProp(name = "showOnSwipeUp") - override fun setShowOnSwipeUp(view: ReactViewGroup, value: Boolean) { + override fun setShowOnSwipeUp( + view: ReactViewGroup, + value: Boolean, + ) { manager.setScrollKeyboardOnScreenWhenNotVisible(view as KeyboardGestureAreaReactViewGroup, value) } @ReactProp(name = "enableSwipeToDismiss") - override fun setEnableSwipeToDismiss(view: ReactViewGroup?, value: Boolean) { + override fun setEnableSwipeToDismiss( + view: ReactViewGroup?, + value: Boolean, + ) { manager.setScrollKeyboardOffScreenWhenVisible(view as KeyboardGestureAreaReactViewGroup, value) } } diff --git a/android/src/fabric/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt b/android/src/fabric/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt index 9fe64f8ef..b8679007a 100644 --- a/android/src/fabric/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +++ b/android/src/fabric/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt @@ -13,29 +13,29 @@ import com.reactnativekeyboardcontroller.managers.OverKeyboardViewManagerImpl import com.reactnativekeyboardcontroller.views.overlay.OverKeyboardHostShadowNode import com.reactnativekeyboardcontroller.views.overlay.OverKeyboardHostView -class OverKeyboardViewManager(mReactContext: ReactApplicationContext) : - ReactViewManager(), +class OverKeyboardViewManager( + mReactContext: ReactApplicationContext, +) : ReactViewManager(), OverKeyboardViewManagerInterface { private val manager = OverKeyboardViewManagerImpl(mReactContext) private val mDelegate = OverKeyboardViewManagerDelegate(this) - override fun getDelegate(): ViewManagerDelegate { - return mDelegate - } + override fun getDelegate(): ViewManagerDelegate = mDelegate override fun getName(): String = OverKeyboardViewManagerImpl.NAME - override fun createViewInstance(context: ThemedReactContext): OverKeyboardHostView { - return manager.createViewInstance(context) - } + override fun createViewInstance(context: ThemedReactContext): OverKeyboardHostView = + manager.createViewInstance(context) override fun createShadowNodeInstance(): LayoutShadowNode = OverKeyboardHostShadowNode() - override fun getShadowNodeClass(): Class = - OverKeyboardHostShadowNode::class.java + override fun getShadowNodeClass(): Class = OverKeyboardHostShadowNode::class.java @ReactProp(name = "visible") - override fun setVisible(view: ReactViewGroup?, value: Boolean) { + override fun setVisible( + view: ReactViewGroup?, + value: Boolean, + ) { manager.setVisible(view as OverKeyboardHostView, value) } } diff --git a/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt b/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt index f85ec4bbc..9715a53af 100644 --- a/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +++ b/android/src/fabric/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt @@ -3,8 +3,9 @@ package com.reactnativekeyboardcontroller import com.facebook.react.bridge.ReactApplicationContext import com.reactnativekeyboardcontroller.modules.StatusBarManagerCompatModuleImpl -class StatusBarManagerCompatModule(mReactContext: ReactApplicationContext) : - NativeStatusBarManagerCompatSpec(mReactContext) { +class StatusBarManagerCompatModule( + mReactContext: ReactApplicationContext, +) : NativeStatusBarManagerCompatSpec(mReactContext) { private val module = StatusBarManagerCompatModuleImpl(mReactContext) override fun getName(): String = StatusBarManagerCompatModuleImpl.NAME @@ -13,7 +14,10 @@ class StatusBarManagerCompatModule(mReactContext: ReactApplicationContext) : module.setHidden(hidden) } - override fun setColor(color: Double, animated: Boolean) { + override fun setColor( + color: Double, + animated: Boolean, + ) { module.setColor(color.toInt(), animated) } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt b/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt index d051ba892..36261ac7b 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt @@ -12,8 +12,11 @@ import com.reactnativekeyboardcontroller.modules.StatusBarManagerCompatModuleImp class KeyboardControllerPackage : TurboReactPackage() { @Nullable - override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { - return when (name) { + override fun getModule( + name: String, + reactContext: ReactApplicationContext, + ): NativeModule? = + when (name) { KeyboardControllerModuleImpl.NAME -> { KeyboardControllerModule(reactContext) } @@ -24,40 +27,39 @@ class KeyboardControllerPackage : TurboReactPackage() { null } } - } - override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { - return ReactModuleInfoProvider { + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = + ReactModuleInfoProvider { val moduleInfos: MutableMap = HashMap() val isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED - moduleInfos[KeyboardControllerModuleImpl.NAME] = ReactModuleInfo( - KeyboardControllerModuleImpl.NAME, - KeyboardControllerModuleImpl.NAME, - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - isTurboModule, // isTurboModule - ) - moduleInfos[StatusBarManagerCompatModuleImpl.NAME] = ReactModuleInfo( - StatusBarManagerCompatModuleImpl.NAME, - StatusBarManagerCompatModuleImpl.NAME, - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - isTurboModule, // isTurboModule - ) + moduleInfos[KeyboardControllerModuleImpl.NAME] = + ReactModuleInfo( + KeyboardControllerModuleImpl.NAME, + KeyboardControllerModuleImpl.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + isTurboModule, // isTurboModule + ) + moduleInfos[StatusBarManagerCompatModuleImpl.NAME] = + ReactModuleInfo( + StatusBarManagerCompatModuleImpl.NAME, + StatusBarManagerCompatModuleImpl.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + isTurboModule, // isTurboModule + ) moduleInfos } - } - override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return listOf( + override fun createViewManagers(reactContext: ReactApplicationContext): List> = + listOf( KeyboardControllerViewManager(reactContext), KeyboardGestureAreaViewManager(reactContext), OverKeyboardViewManager(reactContext), ) - } } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputLayoutChangedEvent.kt b/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputLayoutChangedEvent.kt index 258ddd0fe..e2219feee 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputLayoutChangedEvent.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputLayoutChangedEvent.kt @@ -25,19 +25,20 @@ class FocusedInputLayoutChangedEvent( // All events for a given view can be coalesced override fun getCoalescingKey(): Short = 0 - override fun getEventData(): WritableMap? = Arguments.createMap().apply { - putInt("target", event.target) - putInt("parentScrollViewTarget", event.parentScrollViewTarget) - putMap( - "layout", - Arguments.createMap().apply { - putDouble("x", event.x) - putDouble("y", event.y) - putDouble("width", event.width) - putDouble("height", event.height) - putDouble("absoluteX", event.absoluteX) - putDouble("absoluteY", event.absoluteY) - }, - ) - } + override fun getEventData(): WritableMap? = + Arguments.createMap().apply { + putInt("target", event.target) + putInt("parentScrollViewTarget", event.parentScrollViewTarget) + putMap( + "layout", + Arguments.createMap().apply { + putDouble("x", event.x) + putDouble("y", event.y) + putDouble("width", event.width) + putDouble("height", event.height) + putDouble("absoluteX", event.absoluteX) + putDouble("absoluteY", event.absoluteY) + }, + ) + } } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputSelectionChangedEvent.kt b/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputSelectionChangedEvent.kt index 0e9ad1288..fceceff92 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputSelectionChangedEvent.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputSelectionChangedEvent.kt @@ -24,28 +24,29 @@ class FocusedInputSelectionChangedEvent( // All events for a given view can be coalesced override fun getCoalescingKey(): Short = 0 - override fun getEventData(): WritableMap? = Arguments.createMap().apply { - putInt("target", event.target) - putMap( - "selection", - Arguments.createMap().apply { - putMap( - "start", - Arguments.createMap().apply { - putDouble("x", event.startX) - putDouble("y", event.startY) - putInt("position", event.start) - }, - ) - putMap( - "end", - Arguments.createMap().apply { - putDouble("x", event.endX) - putDouble("y", event.endY) - putInt("position", event.end) - }, - ) - }, - ) - } + override fun getEventData(): WritableMap? = + Arguments.createMap().apply { + putInt("target", event.target) + putMap( + "selection", + Arguments.createMap().apply { + putMap( + "start", + Arguments.createMap().apply { + putDouble("x", event.startX) + putDouble("y", event.startY) + putInt("position", event.start) + }, + ) + putMap( + "end", + Arguments.createMap().apply { + putDouble("x", event.endX) + putDouble("y", event.endY) + putInt("position", event.end) + }, + ) + }, + ) + } } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt b/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt index f46d88a60..aa77e5cc1 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/events/FocusedInputTextChangedEvent.kt @@ -14,7 +14,8 @@ class FocusedInputTextChangedEvent( // All events for a given view can be coalesced override fun getCoalescingKey(): Short = 0 - override fun getEventData(): WritableMap? = Arguments.createMap().apply { - putString("text", text) - } + override fun getEventData(): WritableMap? = + Arguments.createMap().apply { + putString("text", text) + } } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt b/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt index 192db3aaa..5973ecf29 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt @@ -19,10 +19,11 @@ class KeyboardTransitionEvent( // All events for a given view can be coalesced? override fun getCoalescingKey(): Short = 0 - override fun getEventData(): WritableMap? = Arguments.createMap().apply { - putDouble("progress", progress) - putDouble("height", height) - putInt("duration", duration) - putInt("target", target) - } + override fun getEventData(): WritableMap? = + Arguments.createMap().apply { + putDouble("progress", progress) + putDouble("height", height) + putInt("duration", duration) + putInt("target", target) + } } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt index 3967c90d9..f2dd54bd7 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/EditText.kt @@ -22,22 +22,33 @@ import kotlin.math.min fun EditText.addOnTextChangedListener(action: (String) -> Unit): TextWatcher { var lastText: String? = null - val listener = object : TextWatcher { - @Suppress("detekt:EmptyFunctionBlock") - override fun afterTextChanged(s: Editable?) {} - - @Suppress("detekt:EmptyFunctionBlock") - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - val currentText = s.toString() - - if (currentText != lastText) { - lastText = currentText - action(currentText) + val listener = + object : TextWatcher { + @Suppress("detekt:EmptyFunctionBlock") + override fun afterTextChanged(s: Editable?) = Unit + + @Suppress("detekt:EmptyFunctionBlock") + override fun beforeTextChanged( + s: CharSequence?, + start: Int, + count: Int, + after: Int, + ) = Unit + + override fun onTextChanged( + s: CharSequence?, + start: Int, + before: Int, + count: Int, + ) { + val currentText = s.toString() + + if (currentText != lastText) { + lastText = currentText + action(currentText) + } } } - } // we can not simply call `addTextChangedListener(listener)`, because the issue // https://github.com/kirillzyusko/react-native-keyboard-controller/issues/324 @@ -106,52 +117,61 @@ class KeyboardControllerSelectionWatcher( private var lastSelectionStart: Int = -1 private var lastSelectionEnd: Int = -1 - private val frameScheduler = FrameScheduler { - val start = editText.selectionStart - val end = editText.selectionEnd - - if (lastSelectionStart != start || lastSelectionEnd != end) { - lastSelectionStart = start - lastSelectionEnd = end - - val view = editText - val layout = view.layout - - if (layout === null) { - return@FrameScheduler + private val frameScheduler = + FrameScheduler { + val start = editText.selectionStart + val end = editText.selectionEnd + + if (lastSelectionStart != start || lastSelectionEnd != end) { + lastSelectionStart = start + lastSelectionEnd = end + + val view = editText + val layout = view.layout + + if (layout === null) { + return@FrameScheduler + } + + val cursorPositionStartX: Float + val cursorPositionStartY: Float + val cursorPositionEndX: Float + val cursorPositionEndY: Float + + val realStart = min(start, end) + val realEnd = max(start, end) + + val lineStart = layout.getLineForOffset(realStart) + val baselineStart = layout.getLineBaseline(lineStart) + val ascentStart = layout.getLineAscent(lineStart) + + cursorPositionStartX = layout.getPrimaryHorizontal(realStart) + cursorPositionStartY = (baselineStart + ascentStart).toFloat() + + val lineEnd = layout.getLineForOffset(realEnd) + + val right = layout.getPrimaryHorizontal(realEnd) + val bottom = layout.getLineBottom(lineEnd) + layout.getLineAscent(lineEnd) + val cursorWidth = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + view.textCursorDrawable?.intrinsicWidth ?: 0 + } else { + 0 + } + + cursorPositionEndX = right + cursorWidth + cursorPositionEndY = bottom.toFloat() + + action( + start, + end, + cursorPositionStartX.dp, + cursorPositionStartY.dp, + cursorPositionEndX.dp, + cursorPositionEndY.dp, + ) } - - val cursorPositionStartX: Float - val cursorPositionStartY: Float - val cursorPositionEndX: Float - val cursorPositionEndY: Float - - val realStart = min(start, end) - val realEnd = max(start, end) - - val lineStart = layout.getLineForOffset(realStart) - val baselineStart = layout.getLineBaseline(lineStart) - val ascentStart = layout.getLineAscent(lineStart) - - cursorPositionStartX = layout.getPrimaryHorizontal(realStart) - cursorPositionStartY = (baselineStart + ascentStart).toFloat() - - val lineEnd = layout.getLineForOffset(realEnd) - - val right = layout.getPrimaryHorizontal(realEnd) - val bottom = layout.getLineBottom(lineEnd) + layout.getLineAscent(lineEnd) - val cursorWidth = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - view.textCursorDrawable?.intrinsicWidth ?: 0 - } else { - 0 - } - - cursorPositionEndX = right + cursorWidth - cursorPositionEndY = bottom.toFloat() - - action(start, end, cursorPositionStartX.dp, cursorPositionStartY.dp, cursorPositionEndX.dp, cursorPositionEndY.dp) } - } fun setup() { frameScheduler.start() diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt index 0dac1b43e..a940750b2 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt @@ -5,9 +5,14 @@ import android.view.ViewGroup import com.facebook.react.bridge.ReactContext val ReactContext.rootView: View? - get() = this.currentActivity?.window?.decorView?.rootView + get() = + this.currentActivity + ?.window + ?.decorView + ?.rootView val ReactContext.content: ViewGroup? - get() = this.currentActivity?.window?.decorView?.rootView?.findViewById( - androidx.appcompat.R.id.action_bar_root, - ) + get() = + this.currentActivity?.window?.decorView?.rootView?.findViewById( + androidx.appcompat.R.id.action_bar_root, + ) diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt index d18de5f29..9842026ab 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt @@ -14,14 +14,21 @@ fun ThemedReactContext.setupWindowDimensionsListener() { WindowDimensionListener(this) } -fun ThemedReactContext?.dispatchEvent(viewId: Int, event: Event<*>) { +fun ThemedReactContext?.dispatchEvent( + viewId: Int, + event: Event<*>, +) { val eventDispatcher: EventDispatcher? = UIManagerHelper.getEventDispatcherForReactTag(this as ReactContext, viewId) eventDispatcher?.dispatchEvent(event) } -fun ThemedReactContext?.emitEvent(event: String, params: WritableMap) { - this?.reactApplicationContext +fun ThemedReactContext?.emitEvent( + event: String, + params: WritableMap, +) { + this + ?.reactApplicationContext ?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) ?.emit(event, params) diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt index d085d88c0..0c9043520 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt @@ -18,16 +18,18 @@ fun View.requestApplyInsetsWhenAttached() { requestApplyInsets() } else { // We're not attached to the hierarchy, add a listener to request when we are - addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { - override fun onViewAttachedToWindow(v: View) { - v.removeOnAttachStateChangeListener(this) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { - v.requestApplyInsets() + addOnAttachStateChangeListener( + object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) { + v.removeOnAttachStateChangeListener(this) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { + v.requestApplyInsets() + } } - } - override fun onViewDetachedFromWindow(v: View) = Unit - }) + override fun onViewDetachedFromWindow(v: View) = Unit + }, + ) } } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/interactive/KeyboardAnimationController.kt b/android/src/main/java/com/reactnativekeyboardcontroller/interactive/KeyboardAnimationController.kt index 7e753a205..071dfbb0b 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/interactive/KeyboardAnimationController.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/interactive/KeyboardAnimationController.kt @@ -73,7 +73,8 @@ internal class KeyboardAnimationController { } // Keep track of the IME insets, and the IME visibility, at the start of the request - isImeShownAtStart = ViewCompat.getRootWindowInsets(view) + isImeShownAtStart = ViewCompat + .getRootWindowInsets(view) ?.isVisible(WindowInsetsCompat.Type.ime()) == true // Create a cancellation signal, which we pass to controlWindowInsetsAnimation() below @@ -114,7 +115,10 @@ internal class KeyboardAnimationController { * @param view The view which is triggering this request * @param velocityY the velocity of the touch gesture which caused this call */ - fun startAndFling(view: View, velocityY: Float) = startControlRequest(view) { + fun startAndFling( + view: View, + velocityY: Float, + ) = startControlRequest(view) { animateToFinish(velocityY) } @@ -127,11 +131,12 @@ internal class KeyboardAnimationController { * @return the amount of [dy] consumed by the inset animation, in pixels */ fun insetBy(dy: Int): Int { - val controller = insetsAnimationController - ?: throw IllegalStateException( - "Current WindowInsetsAnimationController is null." + - "This should only be called if isAnimationInProgress() returns true", - ) + val controller = + insetsAnimationController + ?: throw IllegalStateException( + "Current WindowInsetsAnimationController is null." + + "This should only be called if isAnimationInProgress() returns true", + ) InteractiveKeyboardProvider.isInteractive = true // Call updateInsetTo() with the new inset value @@ -147,11 +152,12 @@ internal class KeyboardAnimationController { * @return the distance moved by the inset animation, in pixels */ fun insetTo(inset: Int): Int { - val controller = insetsAnimationController - ?: throw IllegalStateException( - "Current WindowInsetsAnimationController is null." + - "This should only be called if isAnimationInProgress() returns true", - ) + val controller = + insetsAnimationController + ?: throw IllegalStateException( + "Current WindowInsetsAnimationController is null." + + "This should only be called if isAnimationInProgress() returns true", + ) val hiddenBottom = controller.hiddenStateInsets.bottom val shownBottom = controller.shownStateInsets.bottom @@ -182,23 +188,17 @@ internal class KeyboardAnimationController { /** * Return `true` if an inset animation is in progress. */ - fun isInsetAnimationInProgress(): Boolean { - return insetsAnimationController != null - } + fun isInsetAnimationInProgress(): Boolean = insetsAnimationController != null /** * Return `true` if an inset animation is currently finishing. */ - fun isInsetAnimationFinishing(): Boolean { - return currentSpringAnimation != null - } + fun isInsetAnimationFinishing(): Boolean = currentSpringAnimation != null /** * Return `true` if a request to control an inset animation is in progress. */ - fun isInsetAnimationRequestPending(): Boolean { - return pendingRequestCancellationSignal != null - } + fun isInsetAnimationRequestPending(): Boolean = pendingRequestCancellationSignal != null /** * Cancel the current [WindowInsetsAnimationControllerCompat]. We immediately finish @@ -280,10 +280,11 @@ internal class KeyboardAnimationController { when { // If we have a velocity, we can use it's direction to determine // the visibility. Upwards == visible - velocityY != null -> animateImeToVisibility( - visible = velocityY < 0, - velocityY = velocityY, - ) + velocityY != null -> + animateImeToVisibility( + visible = velocityY < 0, + velocityY = velocityY, + ) // The current inset matches either the shown/hidden inset, finish() immediately current == shown -> { InteractiveKeyboardProvider.shown = true @@ -307,11 +308,12 @@ internal class KeyboardAnimationController { } fun getCurrentKeyboardHeight(): Int { - val controller = insetsAnimationController - ?: throw IllegalStateException( - "Current WindowInsetsAnimationController is null." + - "This should only be called if isAnimationInProgress() returns true", - ) + val controller = + insetsAnimationController + ?: throw IllegalStateException( + "Current WindowInsetsAnimationController is null." + + "This should only be called if isAnimationInProgress() returns true", + ) return controller.currentInsets.bottom } @@ -356,37 +358,40 @@ internal class KeyboardAnimationController { velocityY: Float? = null, ) { @Suppress("detekt:UseCheckOrError") - val controller = insetsAnimationController - ?: throw IllegalStateException("Controller should not be null") - - currentSpringAnimation = springAnimationOf( - setter = { - insetTo(it.roundToInt()) - }, - getter = { controller.currentInsets.bottom.toFloat() }, - finalPosition = when { - visible -> controller.shownStateInsets.bottom.toFloat() - else -> controller.hiddenStateInsets.bottom.toFloat() - }, - ).withSpringForceProperties { - // Tweak the damping value, to remove any bounciness. - dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY - // The stiffness value controls the strength of the spring animation, which - // controls the speed. Medium (the default) is a good value, but feel free to - // play around with this value. - stiffness = SpringForce.STIFFNESS_MEDIUM - }.apply { - if (velocityY != null) { - setStartVelocity(velocityY) - } - addEndListener { anim, _, _, _ -> - if (anim == currentSpringAnimation) { - currentSpringAnimation = null + val controller = + insetsAnimationController + ?: throw IllegalStateException("Controller should not be null") + + currentSpringAnimation = + springAnimationOf( + setter = { + insetTo(it.roundToInt()) + }, + getter = { controller.currentInsets.bottom.toFloat() }, + finalPosition = + when { + visible -> controller.shownStateInsets.bottom.toFloat() + else -> controller.hiddenStateInsets.bottom.toFloat() + }, + ).withSpringForceProperties { + // Tweak the damping value, to remove any bounciness. + dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY + // The stiffness value controls the strength of the spring animation, which + // controls the speed. Medium (the default) is a good value, but feel free to + // play around with this value. + stiffness = SpringForce.STIFFNESS_MEDIUM + }.apply { + if (velocityY != null) { + setStartVelocity(velocityY) } - // Once the animation has ended, finish the controller - finish() - } - }.also { it.start() } + addEndListener { anim, _, _, _ -> + if (anim == currentSpringAnimation) { + currentSpringAnimation = null + } + // Once the animation has ended, finish the controller + finish() + } + }.also { it.start() } } } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/Interpolator.kt b/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/Interpolator.kt index 2239f49fd..c5a6fb1e5 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/Interpolator.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/Interpolator.kt @@ -11,5 +11,10 @@ interface Interpolator { * @param offset extra space to the keyboard to activate a gesture * @return the distance the keyboard should be moved from its current location. */ - fun interpolate(dy: Int, absoluteFingerPosition: Int, keyboardPosition: Int, offset: Int): Int + fun interpolate( + dy: Int, + absoluteFingerPosition: Int, + keyboardPosition: Int, + offset: Int, + ): Int } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/IosInterpolator.kt b/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/IosInterpolator.kt index 39d61ba82..83ef6f6d3 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/IosInterpolator.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/IosInterpolator.kt @@ -8,8 +8,10 @@ class IosInterpolator : Interpolator { offset: Int, ): Int { if ( - absoluteFingerPosition <= keyboardPosition + offset || // user over scrolled keyboard - dy <= 0 // user scrolls up + // user over scrolled keyboard + absoluteFingerPosition <= keyboardPosition + offset || + // user scrolls up + dy <= 0 ) { return dy } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/LinearInterpolator.kt b/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/LinearInterpolator.kt index 24b1bb6ff..6fb49c5ab 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/LinearInterpolator.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/interactive/interpolators/LinearInterpolator.kt @@ -6,7 +6,5 @@ class LinearInterpolator : Interpolator { absoluteFingerPosition: Int, keyboardPosition: Int, offset: Int, - ): Int { - return dy - } + ): Int = dy } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt index ef2738e9f..45f58ce4d 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/FocusedInputObserver.kt @@ -25,16 +25,17 @@ import com.reactnativekeyboardcontroller.extensions.screenLocation import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator -val noFocusedInputEvent = FocusedInputLayoutChangedEventData( - x = 0.0, - y = 0.0, - width = 0.0, - height = 0.0, - absoluteX = 0.0, - absoluteY = 0.0, - target = -1, - parentScrollViewTarget = -1, -) +val noFocusedInputEvent = + FocusedInputLayoutChangedEventData( + x = 0.0, + y = 0.0, + width = 0.0, + height = 0.0, + absoluteX = 0.0, + absoluteY = 0.0, + target = -1, + parentScrollViewTarget = -1, + ) class FocusedInputObserver( val view: View, @@ -82,50 +83,52 @@ class FocusedInputObserver( FocusedInputSelectionChangedEvent( surfaceId, eventPropagationView.id, - event = FocusedInputSelectionChangedEventData( - target = input.id, - start = start, - end = end, - startX = startX, - startY = startY, - endX = endX, - endY = endY, - ), + event = + FocusedInputSelectionChangedEventData( + target = input.id, + start = start, + end = end, + startX = startX, + startY = startY, + endX = endX, + endY = endY, + ), ), ) } - private val focusListener = OnGlobalFocusChangeListener { oldFocus, newFocus -> - // unfocused or focus was changed - if (newFocus == null || oldFocus != null) { - lastFocusedInput?.removeOnLayoutChangeListener(layoutListener) - lastFocusedInput?.removeTextChangedListener(textWatcher) - selectionSubscription?.invoke() - lastFocusedInput = null - } - if (newFocus is ReactEditText) { - lastFocusedInput = newFocus - newFocus.addOnLayoutChangeListener(layoutListener) - this.syncUpLayout() - textWatcher = newFocus.addOnTextChangedListener(textListener) - selectionSubscription = newFocus.addOnSelectionChangedListener(selectionListener) - FocusedInputHolder.set(newFocus) + private val focusListener = + OnGlobalFocusChangeListener { oldFocus, newFocus -> + // unfocused or focus was changed + if (newFocus == null || oldFocus != null) { + lastFocusedInput?.removeOnLayoutChangeListener(layoutListener) + lastFocusedInput?.removeTextChangedListener(textWatcher) + selectionSubscription?.invoke() + lastFocusedInput = null + } + if (newFocus is ReactEditText) { + lastFocusedInput = newFocus + newFocus.addOnLayoutChangeListener(layoutListener) + this.syncUpLayout() + textWatcher = newFocus.addOnTextChangedListener(textListener) + selectionSubscription = newFocus.addOnSelectionChangedListener(selectionListener) + FocusedInputHolder.set(newFocus) - val allInputFields = ViewHierarchyNavigator.getAllInputFields(context?.rootView) - val currentIndex = allInputFields.indexOf(newFocus) + val allInputFields = ViewHierarchyNavigator.getAllInputFields(context?.rootView) + val currentIndex = allInputFields.indexOf(newFocus) - context.emitEvent( - "KeyboardController::focusDidSet", - Arguments.createMap().apply { - putInt("current", currentIndex) - putInt("count", allInputFields.size) - }, - ) + context.emitEvent( + "KeyboardController::focusDidSet", + Arguments.createMap().apply { + putInt("current", currentIndex) + putInt("count", allInputFields.size) + }, + ) + } + // unfocused + if (newFocus == null) { + dispatchEventToJS(noFocusedInputEvent) + } } - // unfocused - if (newFocus == null) { - dispatchEventToJS(noFocusedInputEvent) - } - } init { view.viewTreeObserver.addOnGlobalFocusChangeListener(focusListener) @@ -135,16 +138,17 @@ class FocusedInputObserver( val input = lastFocusedInput ?: return val (x, y) = input.screenLocation - val event = FocusedInputLayoutChangedEventData( - x = input.x.dp, - y = input.y.dp, - width = input.width.toFloat().dp, - height = input.height.toFloat().dp, - absoluteX = x.toFloat().dp, - absoluteY = y.toFloat().dp, - target = input.id, - parentScrollViewTarget = input.parentScrollViewTarget, - ) + val event = + FocusedInputLayoutChangedEventData( + x = input.x.dp, + y = input.y.dp, + width = input.width.toFloat().dp, + height = input.height.toFloat().dp, + absoluteX = x.toFloat().dp, + absoluteY = y.toFloat().dp, + target = input.id, + parentScrollViewTarget = input.parentScrollViewTarget, + ) dispatchEventToJS(event) } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt index 6c9169def..5c5c061cf 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt @@ -38,7 +38,8 @@ class KeyboardAnimationCallback( val view: View, val context: ThemedReactContext?, private val config: KeyboardAnimationCallbackConfig, -) : WindowInsetsAnimationCompat.Callback(config.dispatchMode), OnApplyWindowInsetsListener { +) : WindowInsetsAnimationCompat.Callback(config.dispatchMode), + OnApplyWindowInsetsListener { private val surfaceId = UIManagerHelper.getSurfaceId(eventPropagationView) // state variables @@ -51,46 +52,47 @@ class KeyboardAnimationCallback( private var animationsToSkip = hashSetOf() // listeners - private val focusListener = OnGlobalFocusChangeListener { oldFocus, newFocus -> - if (newFocus is ReactEditText) { - viewTagFocused = newFocus.id - - // keyboard is visible and focus has been changed - if (this.isKeyboardVisible && oldFocus !== null) { - // imitate iOS behavior and send two instant start/end events containing an info about new tag - // 1. onStart/onMove/onEnd can be still dispatched after, if keyboard change size (numeric -> alphabetic type) - // 2. event should be send only when keyboard is visible, since this event arrives earlier -> `tag` will be - // 100% included in onStart/onMove/onEnd life cycles, but triggering onStart/onEnd several time - // can bring breaking changes - context.dispatchEvent( - eventPropagationView.id, - KeyboardTransitionEvent( - surfaceId, + private val focusListener = + OnGlobalFocusChangeListener { oldFocus, newFocus -> + if (newFocus is ReactEditText) { + viewTagFocused = newFocus.id + + // keyboard is visible and focus has been changed + if (this.isKeyboardVisible && oldFocus !== null) { + // imitate iOS behavior and send two instant start/end events containing an info about new tag + // 1. onStart/onMove/onEnd can be still dispatched after, if keyboard change size (numeric -> alphabetic type) + // 2. event should be send only when keyboard is visible, since this event arrives earlier -> `tag` will be + // 100% included in onStart/onMove/onEnd life cycles, but triggering onStart/onEnd several time + // can bring breaking changes + context.dispatchEvent( eventPropagationView.id, - "topKeyboardMoveStart", - this.persistentKeyboardHeight, - 1.0, - 0, - viewTagFocused, - ), - ) - context.dispatchEvent( - eventPropagationView.id, - KeyboardTransitionEvent( - surfaceId, + KeyboardTransitionEvent( + surfaceId, + eventPropagationView.id, + "topKeyboardMoveStart", + this.persistentKeyboardHeight, + 1.0, + 0, + viewTagFocused, + ), + ) + context.dispatchEvent( eventPropagationView.id, - "topKeyboardMoveEnd", - this.persistentKeyboardHeight, - 1.0, - 0, - viewTagFocused, - ), - ) - context.emitEvent("KeyboardController::keyboardWillShow", getEventParams(this.persistentKeyboardHeight)) - context.emitEvent("KeyboardController::keyboardDidShow", getEventParams(this.persistentKeyboardHeight)) + KeyboardTransitionEvent( + surfaceId, + eventPropagationView.id, + "topKeyboardMoveEnd", + this.persistentKeyboardHeight, + 1.0, + 0, + viewTagFocused, + ), + ) + context.emitEvent("KeyboardController::keyboardWillShow", getEventParams(this.persistentKeyboardHeight)) + context.emitEvent("KeyboardController::keyboardDidShow", getEventParams(this.persistentKeyboardHeight)) + } } } - } private var layoutObserver: FocusedInputObserver? = null init { @@ -113,7 +115,10 @@ class KeyboardAnimationCallback( * have to implement `onApplyWindowInsets` listener and simulate onStart/onProgress/onEnd * events when keyboard changes its size. */ - override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat { + override fun onApplyWindowInsets( + v: View, + insets: WindowInsetsCompat, + ): WindowInsetsCompat { val keyboardHeight = getCurrentKeyboardHeight() // when keyboard appears values will be (false && true) // when keyboard disappears values will be (true && false) @@ -218,9 +223,10 @@ class KeyboardAnimationCallback( if (config.hasTranslucentNavigationBar) { otherInset = Insets.NONE } - val diff = Insets.subtract(typesInset, otherInset).let { - Insets.max(it, Insets.NONE) - } + val diff = + Insets.subtract(typesInset, otherInset).let { + Insets.max(it, Insets.NONE) + } val diffY = (diff.bottom - diff.top).toFloat() val height = diffY.dp diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt index 638af4972..aceb83848 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/listeners/WindowDimensionListener.kt @@ -8,9 +8,14 @@ import com.reactnativekeyboardcontroller.extensions.content import com.reactnativekeyboardcontroller.extensions.dp import com.reactnativekeyboardcontroller.extensions.emitEvent -data class Dimensions(val width: Double, val height: Double) - -class WindowDimensionListener(private val context: ThemedReactContext?) { +data class Dimensions( + val width: Double, + val height: Double, +) + +class WindowDimensionListener( + private val context: ThemedReactContext?, +) { private var lastDispatchedDimensions = Dimensions(0.0, 0.0) init { @@ -33,10 +38,11 @@ class WindowDimensionListener(private val context: ThemedReactContext?) { return } - val newDimensions = Dimensions( - content.width.toFloat().dp, - content.height.toFloat().dp + content.marginTop.toFloat().dp, - ) + val newDimensions = + Dimensions( + content.width.toFloat().dp, + content.height.toFloat().dp + content.marginTop.toFloat().dp, + ) if (newDimensions != lastDispatchedDimensions) { lastDispatchedDimensions = newDimensions diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/log/Logger.kt b/android/src/main/java/com/reactnativekeyboardcontroller/log/Logger.kt index 25d343cd4..263259751 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/log/Logger.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/log/Logger.kt @@ -6,13 +6,21 @@ import com.reactnativekeyboardcontroller.BuildConfig object Logger { private val enabled = BuildConfig.DEBUG - fun i(tag: String?, message: String, throwable: Throwable? = null) { + fun i( + tag: String?, + message: String, + throwable: Throwable? = null, + ) { if (enabled) { Log.i(tag, message, throwable) } } - fun w(tag: String?, message: String, throwable: Throwable? = null) { + fun w( + tag: String?, + message: String, + throwable: Throwable? = null, + ) { if (enabled) { Log.w(tag, message, throwable) } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt b/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt index 785ba5281..ab0effc57 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardControllerViewManagerImpl.kt @@ -6,40 +6,51 @@ import com.facebook.react.uimanager.ThemedReactContext import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup @Suppress("detekt:UnusedPrivateProperty") -class KeyboardControllerViewManagerImpl(mReactContext: ReactApplicationContext) { - fun createViewInstance(reactContext: ThemedReactContext): EdgeToEdgeReactViewGroup { - return EdgeToEdgeReactViewGroup(reactContext) - } - - fun setEnabled(view: EdgeToEdgeReactViewGroup, enabled: Boolean) { +class KeyboardControllerViewManagerImpl( + mReactContext: ReactApplicationContext, +) { + fun createViewInstance(reactContext: ThemedReactContext): EdgeToEdgeReactViewGroup = + EdgeToEdgeReactViewGroup(reactContext) + + fun setEnabled( + view: EdgeToEdgeReactViewGroup, + enabled: Boolean, + ) { view.setActive(enabled) } - fun setStatusBarTranslucent(view: EdgeToEdgeReactViewGroup, isStatusBarTranslucent: Boolean) { + fun setStatusBarTranslucent( + view: EdgeToEdgeReactViewGroup, + isStatusBarTranslucent: Boolean, + ) { view.setStatusBarTranslucent(isStatusBarTranslucent) } - fun setNavigationBarTranslucent(view: EdgeToEdgeReactViewGroup, isNavigationBarTranslucent: Boolean) { + fun setNavigationBarTranslucent( + view: EdgeToEdgeReactViewGroup, + isNavigationBarTranslucent: Boolean, + ) { view.setNavigationBarTranslucent(isNavigationBarTranslucent) } fun getExportedCustomDirectEventTypeConstants(): MutableMap { - val map: MutableMap = MapBuilder.of( - "topKeyboardMove", - MapBuilder.of("registrationName", "onKeyboardMove"), - "topKeyboardMoveStart", - MapBuilder.of("registrationName", "onKeyboardMoveStart"), - "topKeyboardMoveEnd", - MapBuilder.of("registrationName", "onKeyboardMoveEnd"), - "topKeyboardMoveInteractive", - MapBuilder.of("registrationName", "onKeyboardMoveInteractive"), - "topFocusedInputLayoutChanged", - MapBuilder.of("registrationName", "onFocusedInputLayoutChanged"), - "topFocusedInputTextChanged", - MapBuilder.of("registrationName", "onFocusedInputTextChanged"), - "topFocusedInputSelectionChanged", - MapBuilder.of("registrationName", "onFocusedInputSelectionChanged"), - ) + val map: MutableMap = + MapBuilder.of( + "topKeyboardMove", + MapBuilder.of("registrationName", "onKeyboardMove"), + "topKeyboardMoveStart", + MapBuilder.of("registrationName", "onKeyboardMoveStart"), + "topKeyboardMoveEnd", + MapBuilder.of("registrationName", "onKeyboardMoveEnd"), + "topKeyboardMoveInteractive", + MapBuilder.of("registrationName", "onKeyboardMoveInteractive"), + "topFocusedInputLayoutChanged", + MapBuilder.of("registrationName", "onFocusedInputLayoutChanged"), + "topFocusedInputTextChanged", + MapBuilder.of("registrationName", "onFocusedInputTextChanged"), + "topFocusedInputSelectionChanged", + MapBuilder.of("registrationName", "onFocusedInputSelectionChanged"), + ) return map } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt b/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt index af6fa8ecf..c80ac79b2 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardGestureAreaViewManagerImpl.kt @@ -5,24 +5,37 @@ import com.facebook.react.uimanager.ThemedReactContext import com.reactnativekeyboardcontroller.views.KeyboardGestureAreaReactViewGroup @Suppress("detekt:UnusedPrivateProperty") -class KeyboardGestureAreaViewManagerImpl(mReactContext: ReactApplicationContext) { - fun createViewInstance(reactContext: ThemedReactContext): KeyboardGestureAreaReactViewGroup { - return KeyboardGestureAreaReactViewGroup(reactContext) - } +class KeyboardGestureAreaViewManagerImpl( + mReactContext: ReactApplicationContext, +) { + fun createViewInstance(reactContext: ThemedReactContext): KeyboardGestureAreaReactViewGroup = + KeyboardGestureAreaReactViewGroup(reactContext) - fun setOffset(view: KeyboardGestureAreaReactViewGroup, offset: Double) { + fun setOffset( + view: KeyboardGestureAreaReactViewGroup, + offset: Double, + ) { view.setOffset(offset) } - fun setInterpolator(view: KeyboardGestureAreaReactViewGroup, interpolator: String) { + fun setInterpolator( + view: KeyboardGestureAreaReactViewGroup, + interpolator: String, + ) { view.setInterpolator(interpolator) } - fun setScrollKeyboardOffScreenWhenVisible(view: KeyboardGestureAreaReactViewGroup, value: Boolean) { + fun setScrollKeyboardOffScreenWhenVisible( + view: KeyboardGestureAreaReactViewGroup, + value: Boolean, + ) { view.setScrollKeyboardOffScreenWhenVisible(value) } - fun setScrollKeyboardOnScreenWhenNotVisible(view: KeyboardGestureAreaReactViewGroup, value: Boolean) { + fun setScrollKeyboardOnScreenWhenNotVisible( + view: KeyboardGestureAreaReactViewGroup, + value: Boolean, + ) { view.setScrollKeyboardOnScreenWhenNotVisible(value) } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/managers/OverKeyboardViewManagerImpl.kt b/android/src/main/java/com/reactnativekeyboardcontroller/managers/OverKeyboardViewManagerImpl.kt index 5198b85d0..0d5e5de89 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/managers/OverKeyboardViewManagerImpl.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/managers/OverKeyboardViewManagerImpl.kt @@ -5,13 +5,15 @@ import com.facebook.react.uimanager.ThemedReactContext import com.reactnativekeyboardcontroller.views.overlay.OverKeyboardHostView @Suppress("detekt:UnusedPrivateProperty") -class OverKeyboardViewManagerImpl(mReactContext: ReactApplicationContext) { +class OverKeyboardViewManagerImpl( + mReactContext: ReactApplicationContext, +) { + fun createViewInstance(reactContext: ThemedReactContext): OverKeyboardHostView = OverKeyboardHostView(reactContext) - fun createViewInstance(reactContext: ThemedReactContext): OverKeyboardHostView { - return OverKeyboardHostView(reactContext) - } - - fun setVisible(view: OverKeyboardHostView, value: Boolean) { + fun setVisible( + view: OverKeyboardHostView, + value: Boolean, + ) { if (value) { view.show() } else { diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt b/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt index 595b6a1fe..f913f7391 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt @@ -30,12 +30,13 @@ class ModalAttachedWatcher( return } - val modal = try { - uiManager?.resolveView(event.viewTag) as? ReactModalHostView - } catch (ignore: Exception) { - Logger.w(TAG, "Can not resolve view for Modal#${event.viewTag}", ignore) - null - } + val modal = + try { + uiManager?.resolveView(event.viewTag) as? ReactModalHostView + } catch (ignore: Exception) { + Logger.w(TAG, "Can not resolve view for Modal#${event.viewTag}", ignore) + null + } if (modal == null) { return @@ -46,12 +47,13 @@ class ModalAttachedWatcher( val rootView = window?.decorView?.rootView if (rootView != null) { - val callback = KeyboardAnimationCallback( - view = rootView, - eventPropagationView = view, - context = reactContext, - config = config(), - ) + val callback = + KeyboardAnimationCallback( + view = rootView, + eventPropagationView = view, + context = reactContext, + config = config(), + ) ViewCompat.setWindowInsetsAnimationCallback(rootView, callback) ViewCompat.setOnApplyWindowInsetsListener(rootView, callback) diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt b/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt index 4e69e2386..472ee09bb 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt @@ -9,7 +9,9 @@ import com.facebook.react.bridge.UiThreadUtil import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator -class KeyboardControllerModuleImpl(private val mReactContext: ReactApplicationContext) { +class KeyboardControllerModuleImpl( + private val mReactContext: ReactApplicationContext, +) { private val mDefaultMode: Int = getCurrentMode() fun setInputMode(mode: Int) { @@ -50,14 +52,13 @@ class KeyboardControllerModuleImpl(private val mReactContext: ReactApplicationCo } } - private fun getCurrentMode(): Int { - return mReactContext + private fun getCurrentMode(): Int = + mReactContext .currentActivity ?.window ?.attributes ?.softInputMode ?: WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED - } companion object { const val NAME = "KeyboardController" diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt b/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt index cdfab3489..6401f8e17 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/modules/StatusBarManagerCompatModuleImpl.kt @@ -14,7 +14,9 @@ import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup private val TAG = StatusBarManagerCompatModuleImpl::class.qualifiedName -class StatusBarManagerCompatModuleImpl(private val mReactContext: ReactApplicationContext) { +class StatusBarManagerCompatModuleImpl( + private val mReactContext: ReactApplicationContext, +) { private var controller: WindowInsetsControllerCompat? = null fun setHidden(hidden: Boolean) { @@ -28,7 +30,10 @@ class StatusBarManagerCompatModuleImpl(private val mReactContext: ReactApplicati } @RequiresApi(Build.VERSION_CODES.LOLLIPOP) - fun setColor(color: Int, animated: Boolean) { + fun setColor( + color: Int, + animated: Boolean, + ) { val activity = mReactContext.currentActivity if (activity == null) { Logger.w(TAG, "StatusBarManagerCompatModule: Ignored status bar change, current activity is null.") diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/traversal/FocusedInputHolder.kt b/android/src/main/java/com/reactnativekeyboardcontroller/traversal/FocusedInputHolder.kt index c31addd0b..942ea3417 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/traversal/FocusedInputHolder.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/traversal/FocusedInputHolder.kt @@ -11,9 +11,7 @@ object FocusedInputHolder { input = WeakReference(textInput) } - fun get(): EditText? { - return input?.get() - } + fun get(): EditText? = input?.get() fun focus() { input?.get()?.focus() diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt b/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt index ab3c69f14..8a0d6ec4e 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt @@ -7,7 +7,10 @@ import com.facebook.react.bridge.UiThreadUtil import com.reactnativekeyboardcontroller.extensions.focus object ViewHierarchyNavigator { - fun setFocusTo(direction: String, view: View) { + fun setFocusTo( + direction: String, + view: View, + ) { val input = if (direction == "next") findNextEditText(view) else findPreviousEditText(view) UiThreadUtil.runOnUiThread { @@ -35,16 +38,15 @@ object ViewHierarchyNavigator { return editTexts } - private fun findNextEditText(currentFocus: View): EditText? { - return findEditTextInDirection(currentFocus, 1) - } + private fun findNextEditText(currentFocus: View): EditText? = findEditTextInDirection(currentFocus, 1) - private fun findPreviousEditText(currentFocus: View): EditText? { - return findEditTextInDirection(currentFocus, -1) - } + private fun findPreviousEditText(currentFocus: View): EditText? = findEditTextInDirection(currentFocus, -1) @Suppress("detekt:ReturnCount") - private fun findEditTextInDirection(currentFocus: View, direction: Int): EditText? { + private fun findEditTextInDirection( + currentFocus: View, + direction: Int, + ): EditText? { // Attempt to find the parent view group, return null if not found or not a ViewGroup val parentViewGroup = currentFocus.parent as? ViewGroup ?: return null @@ -66,7 +68,10 @@ object ViewHierarchyNavigator { return findEditTextInDirection(parentViewGroup, direction) } - private fun findEditTextInHierarchy(viewGroup: ViewGroup, direction: Int): EditText? { + private fun findEditTextInHierarchy( + viewGroup: ViewGroup, + direction: Int, + ): EditText? { val range = if (direction > 0) 0 until viewGroup.childCount else viewGroup.childCount - 1 downTo 0 for (i in range) { @@ -78,7 +83,10 @@ object ViewHierarchyNavigator { return null } - private fun findEditTextOrGoDeeper(child: View, direction: Int): EditText? { + private fun findEditTextOrGoDeeper( + child: View, + direction: Int, + ): EditText? { var result: EditText? = null if (isValidTextInput(child)) { @@ -91,7 +99,5 @@ object ViewHierarchyNavigator { return result } - private fun isValidTextInput(view: View?): Boolean { - return view is EditText && view.isEnabled - } + private fun isValidTextInput(view: View?): Boolean = view is EditText && view.isEnabled } diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/ui/FrameScheduler.kt b/android/src/main/java/com/reactnativekeyboardcontroller/ui/FrameScheduler.kt index c8fb1221c..0b30a5e72 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/ui/FrameScheduler.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/ui/FrameScheduler.kt @@ -7,20 +7,23 @@ import android.view.Choreographer * * @property callback The function to be executed on each frame. */ -class FrameScheduler(private val callback: () -> Unit) { +class FrameScheduler( + private val callback: () -> Unit, +) { /** * A FrameCallback instance responsible for running the provided callback * on each frame and rescheduling itself for the next frame. */ - private val frameCallback = object : Choreographer.FrameCallback { - override fun doFrame(frameTimeNanoSeconds: Long) { - // Execute the callback - callback() + private val frameCallback = + object : Choreographer.FrameCallback { + override fun doFrame(frameTimeNanoSeconds: Long) { + // Execute the callback + callback() - // Re-post the callback to the next frame - Choreographer.getInstance().postFrameCallback(this) + // Re-post the callback to the next frame + Choreographer.getInstance().postFrameCallback(this) + } } - } /** * Starts the frame callback, which will continuously call the provided function diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt b/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt index 2db1f5c8e..7ef8b3651 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt @@ -25,7 +25,9 @@ private val TAG = EdgeToEdgeReactViewGroup::class.qualifiedName @Suppress("detekt:TooManyFunctions") @SuppressLint("ViewConstructor") -class EdgeToEdgeReactViewGroup(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) { +class EdgeToEdgeReactViewGroup( + private val reactContext: ThemedReactContext, +) : ReactViewGroup(reactContext) { // props private var isStatusBarTranslucent = false private var isNavigationBarTranslucent = false @@ -36,12 +38,13 @@ class EdgeToEdgeReactViewGroup(private val reactContext: ThemedReactContext) : R private var wasMounted = false private var callback: KeyboardAnimationCallback? = null private val config: KeyboardAnimationCallbackConfig - get() = KeyboardAnimationCallbackConfig( - persistentInsetTypes = WindowInsetsCompat.Type.systemBars(), - deferredInsetTypes = WindowInsetsCompat.Type.ime(), - dispatchMode = WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE, - hasTranslucentNavigationBar = isNavigationBarTranslucent, - ) + get() = + KeyboardAnimationCallbackConfig( + persistentInsetTypes = WindowInsetsCompat.Type.systemBars(), + deferredInsetTypes = WindowInsetsCompat.Type.ime(), + dispatchMode = WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE, + hasTranslucentNavigationBar = isNavigationBarTranslucent, + ) // managers/watchers private val modalAttachedWatcher = ModalAttachedWatcher(this, reactContext, ::config) @@ -81,10 +84,11 @@ class EdgeToEdgeReactViewGroup(private val reactContext: ThemedReactContext) : R if (rootView != null) { ViewCompat.setOnApplyWindowInsetsListener(rootView) { v, insets -> val content = reactContext.content - val params = FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT, - ) + val params = + FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT, + ) val shouldApplyZeroPaddingTop = !active || this.isStatusBarTranslucent val shouldApplyZeroPaddingBottom = !active || this.isNavigationBarTranslucent @@ -136,12 +140,13 @@ class EdgeToEdgeReactViewGroup(private val reactContext: ThemedReactContext) : R val root = reactContext.content root?.addView(eventView) - callback = KeyboardAnimationCallback( - view = this, - eventPropagationView = this, - context = reactContext, - config = config, - ) + callback = + KeyboardAnimationCallback( + view = this, + eventPropagationView = this, + context = reactContext, + config = config, + ) eventView?.let { ViewCompat.setWindowInsetsAnimationCallback(it, callback) diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardGestureAreaReactViewGroup.kt b/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardGestureAreaReactViewGroup.kt index 7c77e373b..577e5e2bf 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardGestureAreaReactViewGroup.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardGestureAreaReactViewGroup.kt @@ -20,14 +20,17 @@ import com.reactnativekeyboardcontroller.interactive.interpolators.LinearInterpo import kotlin.math.absoluteValue import kotlin.math.roundToInt -val interpolators = mapOf( - "linear" to LinearInterpolator(), - "ios" to IosInterpolator(), -) +val interpolators = + mapOf( + "linear" to LinearInterpolator(), + "ios" to IosInterpolator(), + ) @Suppress("detekt:TooManyFunctions") @SuppressLint("ViewConstructor") -class KeyboardGestureAreaReactViewGroup(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) { +class KeyboardGestureAreaReactViewGroup( + private val reactContext: ThemedReactContext, +) : ReactViewGroup(reactContext) { // internal state management private var isHandling = false private var lastTouchX = 0f @@ -127,12 +130,13 @@ class KeyboardGestureAreaReactViewGroup(private val reactContext: ThemedReactCon } // If we currently have control, we can update the IME insets to 'scroll' // the IME in - val moveBy = this.interpolator.interpolate( - dy.roundToInt(), - this.getWindowHeight() - event.rawY.toInt(), - controller.getCurrentKeyboardHeight(), - offset, - ) + val moveBy = + this.interpolator.interpolate( + dy.roundToInt(), + this.getWindowHeight() - event.rawY.toInt(), + controller.getCurrentKeyboardHeight(), + offset, + ) if (moveBy != 0) { controller.insetBy(moveBy) @@ -141,8 +145,10 @@ class KeyboardGestureAreaReactViewGroup(private val reactContext: ThemedReactCon !controller.isInsetAnimationRequestPending() && shouldStartRequest( dy = dy, - imeVisible = ViewCompat.getRootWindowInsets(this) - ?.isVisible(WindowInsetsCompat.Type.ime()) == true, + imeVisible = + ViewCompat + .getRootWindowInsets(this) + ?.isVisible(WindowInsetsCompat.Type.ime()) == true, ) ) { // If we don't currently have control (and a request isn't pending), @@ -210,7 +216,10 @@ class KeyboardGestureAreaReactViewGroup(private val reactContext: ThemedReactCon * Returns true if the given [dy], [IME visibility][imeVisible], and constructor options * support a IME animation request. */ - private fun shouldStartRequest(dy: Float, imeVisible: Boolean) = when { + private fun shouldStartRequest( + dy: Float, + imeVisible: Boolean, + ) = when { // If the user is scroll up, return true if scrollImeOnScreenWhenNotVisible is true, and // the IME is not currently visible dy < 0 -> !imeVisible && scrollKeyboardOnScreenWhenNotVisible diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardHostShadowNode.kt b/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardHostShadowNode.kt index d2f36c63c..99b785556 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardHostShadowNode.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardHostShadowNode.kt @@ -18,7 +18,10 @@ internal class OverKeyboardHostShadowNode : LayoutShadowNode() { * within the in OverKeyboardView.tsx. * This needs to fill the entire window. */ - override fun addChildAt(child: ReactShadowNodeImpl, i: Int) { + override fun addChildAt( + child: ReactShadowNodeImpl, + i: Int, + ) { super.addChildAt(child, i) val modalSize = themedContext.getDisplaySize() child.setStyleWidth(modalSize.x.toFloat()) diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardViewGroup.kt b/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardViewGroup.kt index 963341856..22cf53100 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardViewGroup.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/views/overlay/OverKeyboardViewGroup.kt @@ -17,7 +17,9 @@ import com.facebook.react.uimanager.events.EventDispatcher import com.facebook.react.views.view.ReactViewGroup @SuppressLint("ViewConstructor") -class OverKeyboardHostView(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) { +class OverKeyboardHostView( + private val reactContext: ThemedReactContext, +) : ReactViewGroup(reactContext) { private val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, this.id) private var windowManager: WindowManager = reactContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager private var hostView: OverKeyboardRootViewGroup = OverKeyboardRootViewGroup(reactContext) @@ -33,7 +35,10 @@ class OverKeyboardHostView(private val reactContext: ThemedReactContext) : React hide() } - override fun addView(child: View?, index: Int) { + override fun addView( + child: View?, + index: Int, + ) { UiThreadUtil.assertOnUiThread() hostView.addView(child, index) } @@ -56,21 +61,28 @@ class OverKeyboardHostView(private val reactContext: ThemedReactContext) : React hostView.removeView(child) } - override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + override fun onLayout( + changed: Boolean, + l: Int, + t: Int, + r: Int, + b: Int, + ) { // Do nothing as we are laid out by UIManager } // endregion fun show() { - val layoutParams = WindowManager.LayoutParams( - WindowManager.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.MATCH_PARENT, - // This type ensures it floats over other application windows but under system windows - WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, - // Ensures touches outside the view pass through to other windows - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, - PixelFormat.TRANSLUCENT, - ) + val layoutParams = + WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT, + // This type ensures it floats over other application windows but under system windows + WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, + // Ensures touches outside the view pass through to other windows + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, + PixelFormat.TRANSLUCENT, + ) windowManager.addView(hostView, layoutParams) } @@ -83,7 +95,10 @@ class OverKeyboardHostView(private val reactContext: ThemedReactContext) : React } @SuppressLint("ViewConstructor") -class OverKeyboardRootViewGroup(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext), RootView { +class OverKeyboardRootViewGroup( + private val reactContext: ThemedReactContext, +) : ReactViewGroup(reactContext), + RootView { private val jsTouchDispatcher: JSTouchDispatcher = JSTouchDispatcher(this) private var jsPointerDispatcher: JSPointerDispatcher? = null internal var eventDispatcher: EventDispatcher? = null @@ -145,14 +160,20 @@ class OverKeyboardRootViewGroup(private val reactContext: ThemedReactContext) : // endregion // region RootView methods - override fun onChildStartedNativeGesture(childView: View, ev: MotionEvent) { + override fun onChildStartedNativeGesture( + childView: View, + ev: MotionEvent, + ) { eventDispatcher?.let { eventDispatcher -> jsTouchDispatcher.onChildStartedNativeGesture(ev, eventDispatcher) jsPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher) } } - override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) { + override fun onChildEndedNativeGesture( + childView: View, + ev: MotionEvent, + ) { eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) } jsPointerDispatcher?.onChildEndedNativeGesture() } diff --git a/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt b/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt index 99d1780ef..42b0eca75 100644 --- a/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt +++ b/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerModule.kt @@ -5,7 +5,9 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.reactnativekeyboardcontroller.modules.KeyboardControllerModuleImpl -class KeyboardControllerModule(mReactContext: ReactApplicationContext) : ReactContextBaseJavaModule(mReactContext) { +class KeyboardControllerModule( + mReactContext: ReactApplicationContext, +) : ReactContextBaseJavaModule(mReactContext) { private val module = KeyboardControllerModuleImpl(mReactContext) override fun getName(): String = KeyboardControllerModuleImpl.NAME diff --git a/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt b/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt index e802c2e54..1d42fdc5e 100644 --- a/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt +++ b/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardControllerViewManager.kt @@ -7,31 +7,40 @@ import com.facebook.react.views.view.ReactViewManager import com.reactnativekeyboardcontroller.managers.KeyboardControllerViewManagerImpl import com.reactnativekeyboardcontroller.views.EdgeToEdgeReactViewGroup -class KeyboardControllerViewManager(mReactContext: ReactApplicationContext) : ReactViewManager() { +class KeyboardControllerViewManager( + mReactContext: ReactApplicationContext, +) : ReactViewManager() { private val manager = KeyboardControllerViewManagerImpl(mReactContext) override fun getName(): String = KeyboardControllerViewManagerImpl.NAME - override fun createViewInstance(reactContext: ThemedReactContext): EdgeToEdgeReactViewGroup { - return manager.createViewInstance(reactContext) - } + override fun createViewInstance(reactContext: ThemedReactContext): EdgeToEdgeReactViewGroup = + manager.createViewInstance(reactContext) @ReactProp(name = "enabled") - fun setEnabled(view: EdgeToEdgeReactViewGroup, enabled: Boolean) { + fun setEnabled( + view: EdgeToEdgeReactViewGroup, + enabled: Boolean, + ) { manager.setEnabled(view, enabled) } @ReactProp(name = "statusBarTranslucent") - fun setStatusBarTranslucent(view: EdgeToEdgeReactViewGroup, isStatusBarTranslucent: Boolean) { + fun setStatusBarTranslucent( + view: EdgeToEdgeReactViewGroup, + isStatusBarTranslucent: Boolean, + ) { manager.setStatusBarTranslucent(view, isStatusBarTranslucent) } @ReactProp(name = "navigationBarTranslucent") - fun setNavigationBarTranslucent(view: EdgeToEdgeReactViewGroup, isNavigationBarTranslucent: Boolean) { + fun setNavigationBarTranslucent( + view: EdgeToEdgeReactViewGroup, + isNavigationBarTranslucent: Boolean, + ) { manager.setNavigationBarTranslucent(view, isNavigationBarTranslucent) } - override fun getExportedCustomDirectEventTypeConstants(): MutableMap { - return manager.getExportedCustomDirectEventTypeConstants() - } + override fun getExportedCustomDirectEventTypeConstants(): MutableMap = + manager.getExportedCustomDirectEventTypeConstants() } diff --git a/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt b/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt index 1ddab3427..996485ac5 100644 --- a/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt +++ b/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardGestureAreaViewManager.kt @@ -7,32 +7,45 @@ import com.facebook.react.views.view.ReactViewManager import com.reactnativekeyboardcontroller.managers.KeyboardGestureAreaViewManagerImpl import com.reactnativekeyboardcontroller.views.KeyboardGestureAreaReactViewGroup -class KeyboardGestureAreaViewManager(mReactContext: ReactApplicationContext) : ReactViewManager() { +class KeyboardGestureAreaViewManager( + mReactContext: ReactApplicationContext, +) : ReactViewManager() { private val manager = KeyboardGestureAreaViewManagerImpl(mReactContext) override fun getName(): String = KeyboardGestureAreaViewManagerImpl.NAME - override fun createViewInstance(reactContext: ThemedReactContext): KeyboardGestureAreaReactViewGroup { - return manager.createViewInstance(reactContext) - } + override fun createViewInstance(reactContext: ThemedReactContext): KeyboardGestureAreaReactViewGroup = + manager.createViewInstance(reactContext) @ReactProp(name = "offset") - fun setInterpolator(view: KeyboardGestureAreaReactViewGroup, offset: Double) { + fun setInterpolator( + view: KeyboardGestureAreaReactViewGroup, + offset: Double, + ) { manager.setOffset(view, offset) } @ReactProp(name = "interpolator") - fun setInterpolator(view: KeyboardGestureAreaReactViewGroup, interpolator: String) { + fun setInterpolator( + view: KeyboardGestureAreaReactViewGroup, + interpolator: String, + ) { manager.setInterpolator(view, interpolator) } @ReactProp(name = "showOnSwipeUp") - fun setScrollKeyboardOnScreenWhenNotVisible(view: KeyboardGestureAreaReactViewGroup, value: Boolean) { + fun setScrollKeyboardOnScreenWhenNotVisible( + view: KeyboardGestureAreaReactViewGroup, + value: Boolean, + ) { manager.setScrollKeyboardOnScreenWhenNotVisible(view, value) } @ReactProp(name = "enableSwipeToDismiss") - fun setScrollKeyboardOffScreenWhenVisible(view: KeyboardGestureAreaReactViewGroup, value: Boolean) { + fun setScrollKeyboardOffScreenWhenVisible( + view: KeyboardGestureAreaReactViewGroup, + value: Boolean, + ) { manager.setScrollKeyboardOffScreenWhenVisible(view, value) } } diff --git a/android/src/paper/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt b/android/src/paper/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt index a24cbc247..b1f5b759d 100644 --- a/android/src/paper/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt +++ b/android/src/paper/java/com/reactnativekeyboardcontroller/OverKeyboardViewManager.kt @@ -9,22 +9,25 @@ import com.reactnativekeyboardcontroller.managers.OverKeyboardViewManagerImpl import com.reactnativekeyboardcontroller.views.overlay.OverKeyboardHostShadowNode import com.reactnativekeyboardcontroller.views.overlay.OverKeyboardHostView -class OverKeyboardViewManager(mReactContext: ReactApplicationContext) : ViewGroupManager() { +class OverKeyboardViewManager( + mReactContext: ReactApplicationContext, +) : ViewGroupManager() { private val manager = OverKeyboardViewManagerImpl(mReactContext) override fun getName(): String = OverKeyboardViewManagerImpl.NAME - override fun createViewInstance(reactContext: ThemedReactContext): OverKeyboardHostView { - return manager.createViewInstance(reactContext) - } + override fun createViewInstance(reactContext: ThemedReactContext): OverKeyboardHostView = + manager.createViewInstance(reactContext) override fun createShadowNodeInstance(): LayoutShadowNode = OverKeyboardHostShadowNode() - override fun getShadowNodeClass(): Class = - OverKeyboardHostShadowNode::class.java + override fun getShadowNodeClass(): Class = OverKeyboardHostShadowNode::class.java @ReactProp(name = "visible") - fun setVisible(view: OverKeyboardHostView, value: Boolean) { + fun setVisible( + view: OverKeyboardHostView, + value: Boolean, + ) { manager.setVisible(view, value) } } diff --git a/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt b/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt index 58601a1a2..3dd44469b 100644 --- a/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt +++ b/android/src/paper/java/com/reactnativekeyboardcontroller/StatusBarManagerCompatModule.kt @@ -7,8 +7,9 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.reactnativekeyboardcontroller.modules.StatusBarManagerCompatModuleImpl -class StatusBarManagerCompatModule(mReactContext: ReactApplicationContext) : - ReactContextBaseJavaModule(mReactContext) { +class StatusBarManagerCompatModule( + mReactContext: ReactApplicationContext, +) : ReactContextBaseJavaModule(mReactContext) { private val module = StatusBarManagerCompatModuleImpl(mReactContext) override fun getName(): String = StatusBarManagerCompatModuleImpl.NAME @@ -20,7 +21,10 @@ class StatusBarManagerCompatModule(mReactContext: ReactApplicationContext) : @ReactMethod @RequiresApi(Build.VERSION_CODES.LOLLIPOP) - private fun setColor(color: Int, animated: Boolean) { + private fun setColor( + color: Int, + animated: Boolean, + ) { module.setColor(color, animated) } diff --git a/android/src/test/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigatorTest.kt b/android/src/test/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigatorTest.kt index be3e97f4d..25c46b6c1 100644 --- a/android/src/test/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigatorTest.kt +++ b/android/src/test/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigatorTest.kt @@ -36,8 +36,16 @@ class ViewHierarchyNavigatorTest { editText1 = EditText(context).apply { id = 1 } editText2 = EditText(context).apply { id = 2 } - editText3 = EditText(context).apply { id = 3; isEnabled = false } - editText4 = EditText(context).apply { id = 4; isEnabled = false } + editText3 = + EditText(context).apply { + id = 3 + isEnabled = false + } + editText4 = + EditText(context).apply { + id = 4 + isEnabled = false + } editText5 = EditText(context).apply { id = 5 } editText6 = EditText(context).apply { id = 6 } editText7 = EditText(context).apply { id = 7 } @@ -48,25 +56,26 @@ class ViewHierarchyNavigatorTest { editText12 = EditText(context).apply { id = 12 } editText13 = EditText(context).apply { id = 13 } - layout = LinearLayout(context).apply { - addView(editText1) - addView(editText2) - addView(editText3) - addView(editText4) - addView( - LinearLayout(context).apply { - addView(editText5) - addView(editText6) - addView(editText7) - }, - ) - addView(editText8) - addView(editText9) - addView(editText10) - addView(editText11) - addView(editText12) - addView(editText13) - } + layout = + LinearLayout(context).apply { + addView(editText1) + addView(editText2) + addView(editText3) + addView(editText4) + addView( + LinearLayout(context).apply { + addView(editText5) + addView(editText6) + addView(editText7) + }, + ) + addView(editText8) + addView(editText9) + addView(editText10) + addView(editText11) + addView(editText12) + addView(editText13) + } } @Test diff --git a/package.json b/package.json index d8b49546f..bd3c6214a 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "!android/gradle", "!android/gradlew", "!android/gradlew.bat", + "!android/.editorconfig", "!ios/build", "!ios/KeyboardControllerNative", "!ios/.swiftlint.yml",