From d64508a74acf61695c665a9df9af482f271f4f3b Mon Sep 17 00:00:00 2001 From: Siddarth Kumar Date: Thu, 4 Jan 2024 17:09:24 +0530 Subject: [PATCH] chore: convert `RNSelectableTextInput` to Kotlin (#18320) ### Summary This commit adds `Kotlin` plugin to native module `react-native-status` and converts these files to `Kotlin` : - `modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.java` - `modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.java` ### Platforms - Android --- .../react-native-status/android/build.gradle | 1 + .../module/RNSelectableTextInputModule.java | 78 -------------- .../module/RNSelectableTextInputModule.kt | 72 +++++++++++++ .../RNSelectableTextInputViewManager.java | 102 ------------------ .../RNSelectableTextInputViewManager.kt | 85 +++++++++++++++ 5 files changed, 158 insertions(+), 180 deletions(-) delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.kt diff --git a/modules/react-native-status/android/build.gradle b/modules/react-native-status/android/build.gradle index f25a3cf7ba..112739ce87 100644 --- a/modules/react-native-status/android/build.gradle +++ b/modules/react-native-status/android/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.library' +apply plugin: "org.jetbrains.kotlin.android" def getStatusGoSHA1 = { -> def statusgoOverridePath = System.getenv("STATUS_GO_SRC_OVERRIDE") diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.java deleted file mode 100644 index dc1e8fd958..0000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.java +++ /dev/null @@ -1,78 +0,0 @@ -package im.status.ethereum.module; - -import android.view.ActionMode; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.uimanager.NativeViewHierarchyManager; -import com.facebook.react.uimanager.UIBlock; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.views.textinput.ReactEditText; -import javax.annotation.Nonnull; - -class RNSelectableTextInputModule extends ReactContextBaseJavaModule { - - private ActionMode lastActionMode; - - public RNSelectableTextInputModule(ReactApplicationContext reactContext) { - super(reactContext); - } - - @Nonnull - @Override - public String getName() { - return "RNSelectableTextInputManager"; - } - - @ReactMethod - public void setupMenuItems(final Integer selectableTextViewReactTag, final Integer textInputReactTag) { - ReactApplicationContext reactContext = this.getReactApplicationContext(); - UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class); - uiManager.addUIBlock(new UIBlock() { - public void execute (NativeViewHierarchyManager nvhm) { - RNSelectableTextInputViewManager rnSelectableTextManager = (RNSelectableTextInputViewManager) nvhm.resolveViewManager(selectableTextViewReactTag); - ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag); - rnSelectableTextManager.registerSelectionListener(reactTextView); - } - }); - } - - @ReactMethod - public void startActionMode(final Integer textInputReactTag) { - ReactApplicationContext reactContext = this.getReactApplicationContext(); - UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class); - uiManager.addUIBlock(new UIBlock() { - public void execute (NativeViewHierarchyManager nvhm) { - ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag); - lastActionMode = reactTextView.startActionMode(reactTextView.getCustomSelectionActionModeCallback(), ActionMode.TYPE_FLOATING); - } - }); - } - - @ReactMethod - public void hideLastActionMode(){ - ReactApplicationContext reactContext = this.getReactApplicationContext(); - UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class); - uiManager.addUIBlock(new UIBlock() { - public void execute (NativeViewHierarchyManager nvhm) { - if(lastActionMode!=null){ - lastActionMode.finish(); - lastActionMode = null; - } - } - }); - } - - @ReactMethod - public void setSelection(final Integer textInputReactTag, final Integer start, final Integer end){ - ReactApplicationContext reactContext = this.getReactApplicationContext(); - UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class); - uiManager.addUIBlock(new UIBlock() { - public void execute (NativeViewHierarchyManager nvhm) { - ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag); - reactTextView.setSelection(start, end); - } - }); - } - -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.kt new file mode 100644 index 0000000000..56b753ae6e --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputModule.kt @@ -0,0 +1,72 @@ +package im.status.ethereum.module + +import android.view.ActionMode +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReactMethod +import com.facebook.react.uimanager.NativeViewHierarchyManager +import com.facebook.react.uimanager.UIBlock +import com.facebook.react.uimanager.UIManagerModule +import com.facebook.react.views.textinput.ReactEditText + +class RNSelectableTextInputModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { + + private var lastActionMode: ActionMode? = null + + override fun getName(): String { + return "RNSelectableTextInputManager" + } + + @ReactMethod + fun setupMenuItems(selectableTextViewReactTag: Int?, textInputReactTag: Int?) { + val reactContext = reactApplicationContext + val uiManager = reactContext.getNativeModule(UIManagerModule::class.java) + selectableTextViewReactTag?.let { selectableTag -> + textInputReactTag?.let { inputTag -> + uiManager?.addUIBlock(UIBlock { nvhm: NativeViewHierarchyManager -> + val rnSelectableTextManager = nvhm.resolveViewManager(selectableTag) as RNSelectableTextInputViewManager + val reactTextView = nvhm.resolveView(inputTag) as ReactEditText + rnSelectableTextManager.registerSelectionListener(reactTextView) + }) + } + } + } + + @ReactMethod + fun startActionMode(textInputReactTag: Int?) { + val reactContext = reactApplicationContext + val uiManager = reactContext.getNativeModule(UIManagerModule::class.java) + textInputReactTag?.let { inputTag -> + uiManager?.addUIBlock(UIBlock { nvhm: NativeViewHierarchyManager -> + val reactTextView = nvhm.resolveView(inputTag) as ReactEditText + lastActionMode = reactTextView.startActionMode(reactTextView.customSelectionActionModeCallback, ActionMode.TYPE_FLOATING) + }) + } + } + + @ReactMethod + fun hideLastActionMode() { + val reactContext = reactApplicationContext + val uiManager = reactContext.getNativeModule(UIManagerModule::class.java) + uiManager?.addUIBlock(UIBlock { _ -> + lastActionMode?.finish() + lastActionMode = null + }) + } + + @ReactMethod + fun setSelection(textInputReactTag: Int?, start: Int?, end: Int?) { + val reactContext = reactApplicationContext + val uiManager = reactContext.getNativeModule(UIManagerModule::class.java) + textInputReactTag?.let { inputTag -> + start?.let { s -> + end?.let { e -> + uiManager?.addUIBlock(UIBlock { nvhm: NativeViewHierarchyManager -> + val reactTextView = nvhm.resolveView(inputTag) as ReactEditText + reactTextView.setSelection(s, e) + }) + } + } + } + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.java deleted file mode 100644 index 1716ccdb28..0000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.java +++ /dev/null @@ -1,102 +0,0 @@ -package im.status.ethereum.module; - -import android.view.ActionMode; -import android.view.ActionMode.Callback; -import android.view.Menu; -import android.view.MenuItem; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.events.RCTEventEmitter; -import com.facebook.react.views.textinput.ReactEditText; -import com.facebook.react.views.view.ReactViewGroup; -import com.facebook.react.views.view.ReactViewManager; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class RNSelectableTextInputViewManager extends ReactViewManager { - public static final String REACT_CLASS = "RNSelectableTextInput"; - private String[] _menuItems = new String[0]; - - @Override - public String getName() { - return REACT_CLASS; - } - - @Override - public ReactViewGroup createViewInstance(ThemedReactContext context) { - return new ReactViewGroup(context); - } - - @ReactProp(name = "menuItems") - public void setMenuItems(ReactViewGroup reactViewGroup, ReadableArray items) { - if(items != null) { - List result = new ArrayList(items.size()); - for (int i = 0; i < items.size(); i++) { - result.add(items.getString(i)); - } - this._menuItems = result.toArray(new String[items.size()]); - } - } - - public void registerSelectionListener(final ReactEditText view) { - view.setCustomSelectionActionModeCallback(new Callback() { - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - menu.clear(); - for (int i = 0; i < _menuItems.length; i++) { - menu.add(0, i, 0, _menuItems[i]); - } - return true; - } - - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - return true; - } - - @Override - public void onDestroyActionMode(ActionMode mode) { - } - - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - int selectionStart = view.getSelectionStart(); - int selectionEnd = view.getSelectionEnd(); - String selectedText = view.getText().toString().substring(selectionStart, selectionEnd); - - // Dispatch event - onSelectNativeEvent(view, item.getItemId(), selectedText, selectionStart, selectionEnd); - - mode.finish(); - - return true; - } - - }); - } - - public void onSelectNativeEvent(ReactEditText view, int eventType, String content, int selectionStart, int selectionEnd) { - WritableMap event = Arguments.createMap(); - event.putInt("eventType", eventType); - event.putString("content", content); - event.putInt("selectionStart", selectionStart); - event.putInt("selectionEnd", selectionEnd); - - // Dispatch - ReactContext reactContext = (ReactContext) view.getContext(); - reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(view.getId(), "topSelection", event); - } - - @Override - public Map getExportedCustomDirectEventTypeConstants() { - return MapBuilder.builder() - .put("topSelection", MapBuilder.of("registrationName","onSelection")) - .build(); - } -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.kt new file mode 100644 index 0000000000..6ffe4f54d4 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/RNSelectableTextInputViewManager.kt @@ -0,0 +1,85 @@ +package im.status.ethereum.module + +import android.view.ActionMode +import android.view.Menu +import android.view.MenuItem +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.WritableMap +import com.facebook.react.common.MapBuilder +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.uimanager.events.RCTEventEmitter +import com.facebook.react.views.textinput.ReactEditText +import com.facebook.react.views.view.ReactViewGroup +import com.facebook.react.views.view.ReactViewManager + +class RNSelectableTextInputViewManager : ReactViewManager() { + companion object { + const val REACT_CLASS = "RNSelectableTextInput" + } + + private var _menuItems = arrayOf() + + override fun getName(): String { + return REACT_CLASS + } + + override fun createViewInstance(context: ThemedReactContext): ReactViewGroup { + return ReactViewGroup(context) + } + + @ReactProp(name = "menuItems") + fun setMenuItems(reactViewGroup: ReactViewGroup, items: ReadableArray?) { + _menuItems = items?.let { + Array(items.size()) { i -> items.getString(i) } + } ?: arrayOf() + } + + fun registerSelectionListener(view: ReactEditText) { + view.customSelectionActionModeCallback = object : ActionMode.Callback { + override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { + menu.clear() + _menuItems.forEachIndexed { i, item -> + menu.add(0, i, 0, item) + } + return true + } + + override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { + return true + } + + override fun onDestroyActionMode(mode: ActionMode) {} + + override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { + val selectionStart = view.selectionStart + val selectionEnd = view.selectionEnd + val selectedText = view.text.toString().substring(selectionStart, selectionEnd) + + onSelectNativeEvent(view, item.itemId, selectedText, selectionStart, selectionEnd) + mode.finish() + return true + } + } + } + + private fun onSelectNativeEvent(view: ReactEditText, eventType: Int, content: String, selectionStart: Int, selectionEnd: Int) { + val event: WritableMap = Arguments.createMap().apply { + putInt("eventType", eventType) + putString("content", content) + putInt("selectionStart", selectionStart) + putInt("selectionEnd", selectionEnd) + } + + val reactContext = view.context as ReactContext + reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(view.id, "topSelection", event) + } + + override fun getExportedCustomDirectEventTypeConstants(): Map? { + return MapBuilder.builder() + .put("topSelection", MapBuilder.of("registrationName", "onSelection")) + .build() + } +}