@momo-kits/calculator-keyboard 0.150.2-beta.20-sp.3 → 0.150.2-beta.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -45
- package/android/src/main/java/com/calculatorkeyboard/CalculatorKeyboardPackage.kt +1 -1
- package/android/src/main/java/com/calculatorkeyboard/CustomKeyboardView.kt +31 -43
- package/android/src/main/java/com/calculatorkeyboard/RCTInputCalculator.kt +34 -27
- package/ios/CalculatorKeyboardView.swift +153 -0
- package/ios/InputCalculator-Bridging-Header.h +23 -0
- package/ios/InputCalculator.m +85 -0
- package/ios/InputCalculator.swift +158 -0
- package/ios/extension.swift +23 -0
- package/package.json +64 -75
- package/react-native-calculator-keyboard.podspec +4 -5
- package/src/index.tsx +34 -25
- package/ios/CalculatorKeyboardView.h +0 -30
- package/ios/CalculatorKeyboardView.mm +0 -231
- package/ios/NativeInputCalculator.h +0 -11
- package/ios/NativeInputCalculator.mm +0 -200
- package/src/NativeInputCalculatorNativeComponent.ts +0 -56
package/README.md
CHANGED
|
@@ -10,57 +10,15 @@ npm install react-native-calculator-keyboard
|
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
|
+
|
|
13
14
|
```js
|
|
14
|
-
import
|
|
15
|
+
import { CalculatorKeyboardView } from "react-native-calculator-keyboard";
|
|
15
16
|
|
|
16
17
|
// ...
|
|
17
18
|
|
|
18
|
-
<
|
|
19
|
-
mode="NumDefault"
|
|
20
|
-
customKeyText="Next"
|
|
21
|
-
onCustomKeyEvent={() => console.log('Custom key pressed')}
|
|
22
|
-
/>;
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Requirements
|
|
26
|
-
|
|
27
|
-
**React Native 0.80+** with **Fabric (New Architecture) enabled**.
|
|
28
|
-
|
|
29
|
-
This library is **pure Fabric** implementation with:
|
|
30
|
-
|
|
31
|
-
- ✅ Zero RCTBridge dependencies
|
|
32
|
-
- ✅ Native C++ ComponentView on iOS
|
|
33
|
-
- ✅ Fabric ViewManager with codegen delegates on Android
|
|
34
|
-
- ✅ All Props, Events, Commands auto-generated by codegen
|
|
35
|
-
- ❌ No Paper (old architecture) support
|
|
36
|
-
|
|
37
|
-
### Android Setup
|
|
38
|
-
|
|
39
|
-
Add to your `gradle.properties`:
|
|
40
|
-
|
|
41
|
-
```properties
|
|
42
|
-
newArchEnabled=true
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Then rebuild:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
cd android && ./gradlew clean && cd ..
|
|
49
|
-
npx react-native run-android
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### iOS Setup
|
|
53
|
-
|
|
54
|
-
**Required**: Set the environment variable before installing pods:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
cd ios
|
|
58
|
-
RCT_NEW_ARCH_ENABLED=1 pod install
|
|
59
|
-
cd ..
|
|
60
|
-
npx react-native run-ios
|
|
19
|
+
<CalculatorKeyboardView color="tomato" />
|
|
61
20
|
```
|
|
62
21
|
|
|
63
|
-
**Note**: This library uses Fabric ComponentView (`.mm` files) and will not work without `RCT_NEW_ARCH_ENABLED=1`.
|
|
64
22
|
|
|
65
23
|
## Contributing
|
|
66
24
|
|
|
@@ -7,6 +7,7 @@ import android.graphics.drawable.GradientDrawable
|
|
|
7
7
|
import android.view.Gravity
|
|
8
8
|
import android.widget.Button
|
|
9
9
|
import android.widget.ImageButton
|
|
10
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
10
11
|
import androidx.constraintlayout.widget.ConstraintLayout
|
|
11
12
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
12
13
|
import org.mariuszgromada.math.mxparser.Expression
|
|
@@ -20,57 +21,53 @@ class CustomKeyboardView(
|
|
|
20
21
|
context: ThemedReactContext,
|
|
21
22
|
private val editText: CalculatorEditText
|
|
22
23
|
) : ConstraintLayout(context) {
|
|
23
|
-
private val
|
|
24
|
+
private val keys = listOf(
|
|
24
25
|
listOf("1", "2", "3", "÷", "back"),
|
|
25
26
|
listOf("4", "5", "6", "×", "="),
|
|
26
|
-
listOf("7", "8", "9", "-", "
|
|
27
|
+
listOf("7", "8", "9", "-", "Xong"),
|
|
27
28
|
listOf("000", "0", "+")
|
|
28
29
|
)
|
|
29
|
-
private val
|
|
30
|
-
listOf("1", "2", "3", "÷", "AC"),
|
|
31
|
-
listOf("4", "5", "6", "×", "back"),
|
|
32
|
-
listOf("7", "8", "9", "-", "="),
|
|
33
|
-
listOf("000", "0", "+")
|
|
34
|
-
)
|
|
35
|
-
private val specialKeys = listOf("=", "-", "×", "÷", "back", "+", "AC")
|
|
30
|
+
private val specialKeys = listOf("=", "-", "×", "÷", "back", "+")
|
|
36
31
|
private val separatorWidth = 8f
|
|
37
32
|
private var specialButtonColor: Int = "#D8D8D8".toColorInt()
|
|
38
33
|
|
|
39
|
-
private var keyboardMode: String = "NumDefault"
|
|
40
|
-
|
|
41
34
|
private var customKeyButton: Button? = null
|
|
42
35
|
private var customKeyButtonBackground: Int = "#D8D8D8".toColorInt()
|
|
43
36
|
private var customKeyButtonTextColor: Int = Color.BLACK
|
|
44
37
|
private var customKeyButtonState: String = "default"
|
|
45
38
|
|
|
46
39
|
init {
|
|
40
|
+
val activity = context.currentActivity as? AppCompatActivity
|
|
41
|
+
if (activity != null) {
|
|
42
|
+
val displayMetrics = resources.displayMetrics
|
|
43
|
+
val widthButton = (displayMetrics.widthPixels - separatorWidth * 2 - 4 * separatorWidth) / 5f
|
|
44
|
+
val heightButton = (calculatorHeight - separatorWidth * 2 - 3 * separatorWidth) / 4
|
|
45
|
+
|
|
47
46
|
isClickable = false
|
|
48
47
|
isFocusable = false
|
|
49
48
|
isFocusableInTouchMode = false
|
|
50
49
|
clipToPadding = false
|
|
51
50
|
clipChildren = false
|
|
52
|
-
}
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
renderUI(widthButton, heightButton)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
58
56
|
|
|
57
|
+
private fun renderUI(buttonWidth: Float, buttonHeight: Float) {
|
|
59
58
|
var yOffset = separatorWidth
|
|
60
|
-
val keys = if (keyboardMode == "NumWithCTA") numWithCTAKeys else defaultKeys
|
|
61
59
|
for ((rowIndex, row) in keys.withIndex()) {
|
|
62
60
|
var xOffset = separatorWidth
|
|
63
61
|
for ((colIndex, key) in row.withIndex()) {
|
|
64
|
-
val
|
|
65
|
-
val isMainCTAKey = isMainKey && keyboardMode == "NumWithCTA"
|
|
62
|
+
val isCustomKey = rowIndex == 2 && colIndex == 4
|
|
66
63
|
val width = if (key == "000") buttonWidth * 2 + separatorWidth else buttonWidth
|
|
67
|
-
val height = if (
|
|
64
|
+
val height = if (isCustomKey) buttonHeight * 2 + separatorWidth else buttonHeight
|
|
68
65
|
|
|
69
66
|
val button = if (key == "back") {
|
|
70
67
|
createImageButton(key, xOffset, yOffset, buttonWidth.toInt(), buttonHeight.toInt())
|
|
71
68
|
} else {
|
|
72
|
-
createButton(key, xOffset, yOffset, width.toInt(), height.toInt(),
|
|
73
|
-
if (
|
|
69
|
+
createButton(key, xOffset, yOffset, width.toInt(), height.toInt(), isCustomKey).also { b ->
|
|
70
|
+
if (isCustomKey) customKeyButton = b
|
|
74
71
|
}
|
|
75
72
|
}
|
|
76
73
|
|
|
@@ -88,8 +85,7 @@ class CustomKeyboardView(
|
|
|
88
85
|
yOffset: Float,
|
|
89
86
|
buttonWidth: Int,
|
|
90
87
|
buttonHeight: Int,
|
|
91
|
-
|
|
92
|
-
isMainCTAKey: Boolean
|
|
88
|
+
isCustomKey: Boolean
|
|
93
89
|
): Button {
|
|
94
90
|
return Button(context).apply {
|
|
95
91
|
val shapeInit = GradientDrawable().apply {
|
|
@@ -102,7 +98,7 @@ class CustomKeyboardView(
|
|
|
102
98
|
background = shapeInit
|
|
103
99
|
text = key
|
|
104
100
|
setTypeface(typeface)
|
|
105
|
-
textSize = (if (
|
|
101
|
+
textSize = (if (isCustomKey) 18 else 24).toFloat()
|
|
106
102
|
setTextColor(Color.BLACK)
|
|
107
103
|
stateListAnimator = null
|
|
108
104
|
maxLines = 1
|
|
@@ -114,7 +110,7 @@ class CustomKeyboardView(
|
|
|
114
110
|
constrainedWidth = false
|
|
115
111
|
}
|
|
116
112
|
|
|
117
|
-
if (specialKeys.contains(key)
|
|
113
|
+
if (specialKeys.contains(key)) {
|
|
118
114
|
background = GradientDrawable().apply {
|
|
119
115
|
shape = GradientDrawable.RECTANGLE
|
|
120
116
|
cornerRadius = 24f
|
|
@@ -129,7 +125,7 @@ class CustomKeyboardView(
|
|
|
129
125
|
|
|
130
126
|
translationX = xOffset.toInt().toFloat()
|
|
131
127
|
translationY = yOffset.toInt().toFloat()
|
|
132
|
-
setOnClickListener { onKeyPress(key,
|
|
128
|
+
setOnClickListener { onKeyPress(key, isCustomKey) }
|
|
133
129
|
}
|
|
134
130
|
}
|
|
135
131
|
|
|
@@ -199,15 +195,14 @@ class CustomKeyboardView(
|
|
|
199
195
|
}
|
|
200
196
|
}
|
|
201
197
|
|
|
202
|
-
private fun onKeyPress(key: String,
|
|
203
|
-
if (
|
|
198
|
+
private fun onKeyPress(key: String, isCustomKey: Boolean) {
|
|
199
|
+
if (isCustomKey) {
|
|
204
200
|
emitCustomKey()
|
|
205
201
|
return
|
|
206
202
|
}
|
|
207
203
|
|
|
208
204
|
emitKeyPress(key)
|
|
209
205
|
when (key) {
|
|
210
|
-
"AC" -> clearText()
|
|
211
206
|
"back" -> onBackSpace()
|
|
212
207
|
"=" -> calculateResult()
|
|
213
208
|
"×", "+", "-", "÷" -> keyDidPress(" $key ")
|
|
@@ -220,10 +215,6 @@ class CustomKeyboardView(
|
|
|
220
215
|
editText.text?.replace(editText.selectionStart, editText.selectionEnd, key)
|
|
221
216
|
}
|
|
222
217
|
|
|
223
|
-
private fun clearText() {
|
|
224
|
-
editText.text?.clear()
|
|
225
|
-
}
|
|
226
|
-
|
|
227
218
|
private fun onBackSpace() {
|
|
228
219
|
val start = editText.selectionStart
|
|
229
220
|
val end = editText.selectionEnd
|
|
@@ -279,29 +270,25 @@ class CustomKeyboardView(
|
|
|
279
270
|
customKeyButton?.text = text
|
|
280
271
|
}
|
|
281
272
|
|
|
282
|
-
fun setMode(mode: String) {
|
|
283
|
-
keyboardMode = mode
|
|
284
|
-
renderUI()
|
|
285
|
-
}
|
|
286
|
-
|
|
287
273
|
fun setCustomKeyBackground(background: Int) {
|
|
288
274
|
customKeyButtonBackground = background
|
|
289
|
-
updateCustomKeyUI(background, customKeyButtonTextColor)
|
|
275
|
+
updateCustomKeyUI(background, customKeyButtonTextColor, customKeyButtonState)
|
|
290
276
|
}
|
|
291
277
|
|
|
292
278
|
fun setCustomKeyTextColor(textColor: Int) {
|
|
293
279
|
customKeyButtonTextColor = textColor
|
|
294
|
-
updateCustomKeyUI(customKeyButtonBackground, textColor)
|
|
280
|
+
updateCustomKeyUI(customKeyButtonBackground, textColor, customKeyButtonState)
|
|
295
281
|
}
|
|
296
282
|
|
|
297
283
|
|
|
298
284
|
fun setCustomKeyState(state: String) {
|
|
299
285
|
customKeyButtonState = state
|
|
300
286
|
customKeyButton?.isEnabled = state != "disable"
|
|
301
|
-
updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor)
|
|
287
|
+
updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor, state)
|
|
302
288
|
}
|
|
303
289
|
|
|
304
|
-
private fun updateCustomKeyUI(background: Int, textColor: Int){
|
|
290
|
+
private fun updateCustomKeyUI(background: Int, textColor: Int, state: String){
|
|
291
|
+
|
|
305
292
|
customKeyButton?.background = GradientDrawable().apply {
|
|
306
293
|
shape = GradientDrawable.RECTANGLE
|
|
307
294
|
cornerRadius = 24f
|
|
@@ -310,4 +297,5 @@ class CustomKeyboardView(
|
|
|
310
297
|
customKeyButton?.setTextColor(textColor)
|
|
311
298
|
}
|
|
312
299
|
|
|
300
|
+
|
|
313
301
|
}
|
|
@@ -8,20 +8,15 @@ import android.view.inputmethod.InputMethodManager
|
|
|
8
8
|
import androidx.core.graphics.toColorInt
|
|
9
9
|
import androidx.core.view.ViewCompat
|
|
10
10
|
import androidx.core.view.WindowInsetsCompat
|
|
11
|
+
import com.facebook.react.bridge.ReadableArray
|
|
11
12
|
import com.facebook.react.bridge.UiThreadUtil
|
|
12
13
|
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
13
14
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
15
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
14
16
|
import com.facebook.react.views.textinput.ReactEditText
|
|
15
17
|
import com.facebook.react.views.textinput.ReactTextInputManager
|
|
16
|
-
import com.facebook.react.viewmanagers.NativeInputCalculatorManagerDelegate
|
|
17
|
-
import com.facebook.react.viewmanagers.NativeInputCalculatorManagerInterface
|
|
18
|
-
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
19
|
-
import androidx.annotation.Nullable
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorManagerInterface<ReactEditText> {
|
|
23
|
-
|
|
24
|
-
private val mDelegate: ViewManagerDelegate<ReactEditText> = NativeInputCalculatorManagerDelegate(this)
|
|
19
|
+
class RCTInputCalculator : ReactTextInputManager() {
|
|
25
20
|
|
|
26
21
|
private var keyboardView: CustomKeyboardView? = null
|
|
27
22
|
private lateinit var editText: CalculatorEditText
|
|
@@ -35,11 +30,12 @@ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorMan
|
|
|
35
30
|
override fun getName() = REACT_CLASS
|
|
36
31
|
|
|
37
32
|
companion object {
|
|
38
|
-
const val REACT_CLASS = "
|
|
33
|
+
const val REACT_CLASS = "RCTInputCalculator"
|
|
39
34
|
val calculatorHeight: Int = 240.dpToPx().toInt()
|
|
40
35
|
}
|
|
41
36
|
|
|
42
|
-
|
|
37
|
+
@ReactProp(name = "value")
|
|
38
|
+
fun setValue(view: ReactEditText, value: String?) {
|
|
43
39
|
UiThreadUtil.runOnUiThread {
|
|
44
40
|
val e = view.editableText ?: run { view.setText(value ?: ""); return@runOnUiThread }
|
|
45
41
|
val newText = value ?: ""
|
|
@@ -52,28 +48,29 @@ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorMan
|
|
|
52
48
|
}
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
override fun setCustomKeyText(view: ReactEditText, @Nullable text: String?) {
|
|
60
|
-
keyboardView?.setCustomKeyText(text ?: "Tiếp")
|
|
51
|
+
@ReactProp(name = "customKeyText")
|
|
52
|
+
fun setCustomKeyText(view: ReactEditText, text: String?) {
|
|
53
|
+
keyboardView?.setCustomKeyText(text ?: "Xong")
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
|
|
56
|
+
@ReactProp(name = "customKeyBackground")
|
|
57
|
+
fun setCustomKeyBackground(view: ReactEditText, background: String?) {
|
|
64
58
|
keyboardView?.setCustomKeyBackground((background ?: "#d8d8d8").toColorInt())
|
|
65
59
|
}
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
@ReactProp(name = "customKeyTextColor")
|
|
62
|
+
fun setCustomKeyTextColor(view: ReactEditText, textColor: String?) {
|
|
68
63
|
keyboardView?.setCustomKeyTextColor(textColor?.toColorInt() ?: Color.BLACK)
|
|
69
64
|
}
|
|
70
65
|
|
|
71
|
-
|
|
66
|
+
@ReactProp(name = "customKeyState")
|
|
67
|
+
fun setCustomKeyState(view: ReactEditText, state: String?) {
|
|
72
68
|
keyboardView?.setCustomKeyState(state ?: "default")
|
|
73
69
|
}
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
@ReactProp(name = "keyboardColor")
|
|
72
|
+
fun setKeyboardColor(view: ReactEditText, color: String) {
|
|
73
|
+
keyboardView?.updateButtonColors(color.toColorInt())
|
|
77
74
|
}
|
|
78
75
|
|
|
79
76
|
@SuppressLint("ClickableViewAccessibility")
|
|
@@ -168,17 +165,26 @@ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorMan
|
|
|
168
165
|
v.showSoftInputOnFocus = true
|
|
169
166
|
}
|
|
170
167
|
|
|
171
|
-
override fun
|
|
168
|
+
override fun getCommandsMap(): Map<String, Int> = mapOf("blur" to 1, "focus" to 2)
|
|
172
169
|
|
|
173
|
-
override fun
|
|
174
|
-
|
|
170
|
+
override fun receiveCommand(reactEditText: ReactEditText, commandId: Int, args: ReadableArray?) {
|
|
171
|
+
when (commandId) {
|
|
172
|
+
1 -> blur()
|
|
173
|
+
2 -> focus()
|
|
174
|
+
}
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
override fun
|
|
178
|
-
|
|
177
|
+
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
|
|
178
|
+
val base = super.getExportedCustomBubblingEventTypeConstants().toMutableMap()
|
|
179
|
+
base["onKeyPress"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onKeyPress"))
|
|
180
|
+
return base
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
|
|
183
|
+
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
|
|
184
|
+
val base = super.getExportedCustomDirectEventTypeConstants().toMutableMap()
|
|
185
|
+
base["onCustomKeyEvent"] = mapOf("registrationName" to "onCustomKeyEvent")
|
|
186
|
+
return base
|
|
187
|
+
}
|
|
182
188
|
|
|
183
189
|
private fun focus() {
|
|
184
190
|
UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
|
|
@@ -188,3 +194,4 @@ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorMan
|
|
|
188
194
|
UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
|
|
189
195
|
}
|
|
190
196
|
}
|
|
197
|
+
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import Foundation
|
|
3
|
+
|
|
4
|
+
import UIKit
|
|
5
|
+
import Foundation
|
|
6
|
+
|
|
7
|
+
class CalculatorKeyboardView: UIView {
|
|
8
|
+
weak var input: InputCalculator?
|
|
9
|
+
|
|
10
|
+
private let keys: [[String]] = [
|
|
11
|
+
["1", "2", "3", "÷", "back"],
|
|
12
|
+
["4", "5", "6", "×", "="],
|
|
13
|
+
["7", "8", "9", "-", "Xong"],
|
|
14
|
+
["000", "0", "+"],
|
|
15
|
+
]
|
|
16
|
+
private let SEPARATOR_WIDTH: CGFloat = 4
|
|
17
|
+
private let specialKeys: Set<String> = ["=", "-", "×", "÷", "back", "+"]
|
|
18
|
+
|
|
19
|
+
var customKeyText: String? { didSet { updateCustomKeyTitle() } }
|
|
20
|
+
var customKeyBackground: String? { didSet { updateCustomKeyBackground() } }
|
|
21
|
+
var customKeyTextColor: String? { didSet { updateCustomKeyBackground() } }
|
|
22
|
+
var customKeyState: String? { didSet { updateCustomKeyBackground() } }
|
|
23
|
+
private weak var customKeyButton: UIButton?
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
override init(frame: CGRect) {
|
|
27
|
+
super.init(frame: frame)
|
|
28
|
+
setup()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
required init?(coder aDecoder: NSCoder) {
|
|
32
|
+
fatalError("init(coder:) has not been implemented")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public func setKeyboardColor(_ color: UIColor) {
|
|
36
|
+
self.setup(color)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private func setup(_ color: UIColor = UIColor(hex: "#d8d8d8")) {
|
|
40
|
+
self.subviews.forEach { $0.removeFromSuperview() }
|
|
41
|
+
|
|
42
|
+
backgroundColor = UIColor(hex: "#f2f2f6")
|
|
43
|
+
let buttonWidth = (UIScreen.main.bounds.width - SEPARATOR_WIDTH * 2 - 4 * SEPARATOR_WIDTH) / 5
|
|
44
|
+
let buttonHeight: CGFloat = (240 - SEPARATOR_WIDTH * 2 - 3 * SEPARATOR_WIDTH) / 4
|
|
45
|
+
|
|
46
|
+
// Create a wrapper view
|
|
47
|
+
let contentView = UIView()
|
|
48
|
+
contentView.translatesAutoresizingMaskIntoConstraints = false
|
|
49
|
+
addSubview(contentView)
|
|
50
|
+
|
|
51
|
+
// Set contentView constraints
|
|
52
|
+
NSLayoutConstraint.activate([
|
|
53
|
+
contentView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: SEPARATOR_WIDTH),
|
|
54
|
+
contentView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -SEPARATOR_WIDTH),
|
|
55
|
+
contentView.topAnchor.constraint(equalTo: topAnchor, constant: SEPARATOR_WIDTH),
|
|
56
|
+
contentView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -SEPARATOR_WIDTH)
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
// Add buttons to the wrapper view
|
|
60
|
+
var yOffset: CGFloat = 0
|
|
61
|
+
for (rowIndex, row) in keys.enumerated() {
|
|
62
|
+
var xOffset: CGFloat = 0
|
|
63
|
+
for (colIndex, key) in row.enumerated() {
|
|
64
|
+
let isCustomKey = colIndex == 4 && rowIndex == 2
|
|
65
|
+
let button = UIButton(type: .system)
|
|
66
|
+
button.backgroundColor = UIColor.white
|
|
67
|
+
button.layer.cornerRadius = 8
|
|
68
|
+
let title = isCustomKey ? (customKeyText ?? key) : key
|
|
69
|
+
button.setTitle(title, for: .normal)
|
|
70
|
+
button.setTitleColor(.black, for: .normal)
|
|
71
|
+
button.titleLabel?.font = UIFont.systemFont(ofSize: isCustomKey ? 18 : 24, weight: .medium)
|
|
72
|
+
button.nativeID = key
|
|
73
|
+
button.tag = isCustomKey ? 1 : 0
|
|
74
|
+
|
|
75
|
+
var buttonFrame = CGRect(x: xOffset, y: yOffset, width: buttonWidth, height: buttonHeight)
|
|
76
|
+
if isCustomKey {
|
|
77
|
+
buttonFrame.size.height = buttonHeight * 2 + SEPARATOR_WIDTH
|
|
78
|
+
}
|
|
79
|
+
if key == "000" {
|
|
80
|
+
buttonFrame.size.width = buttonWidth * 2 + SEPARATOR_WIDTH
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
button.frame = buttonFrame
|
|
84
|
+
|
|
85
|
+
if key == "back" {
|
|
86
|
+
button.setTitle("", for: .normal)
|
|
87
|
+
let image = UIImage(systemName: "delete.backward", withConfiguration: UIImage.SymbolConfiguration(weight: .bold))
|
|
88
|
+
button.setImage(image, for: .normal)
|
|
89
|
+
button.tintColor = .black
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if specialKeys.contains(key) {
|
|
93
|
+
button.setTitleColor(.black, for: .normal)
|
|
94
|
+
button.backgroundColor = color
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if isCustomKey {
|
|
98
|
+
self.customKeyButton = button
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
button.addTarget(self, action: #selector(keyPressed(_:)), for: .touchUpInside)
|
|
102
|
+
contentView.addSubview(button)
|
|
103
|
+
|
|
104
|
+
// Adjust xOffset for the next button in the row
|
|
105
|
+
xOffset += buttonFrame.width + SEPARATOR_WIDTH
|
|
106
|
+
}
|
|
107
|
+
// Adjust yOffset for the next row
|
|
108
|
+
yOffset += buttonHeight + SEPARATOR_WIDTH
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private func updateCustomKeyTitle() {
|
|
113
|
+
guard let btn = customKeyButton, let title = customKeyText else { return }
|
|
114
|
+
btn.setTitle(title, for: .normal)
|
|
115
|
+
btn.setImage(nil, for: .normal)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private func updateCustomKeyBackground() {
|
|
119
|
+
guard let btn = customKeyButton,
|
|
120
|
+
let background = customKeyBackground,
|
|
121
|
+
let textColor = customKeyTextColor,
|
|
122
|
+
let state = customKeyState else { return }
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
btn.isEnabled = state != "disable"
|
|
127
|
+
btn.backgroundColor = UIColor(hex: background)
|
|
128
|
+
btn.setTitleColor(UIColor(hex: textColor), for: .normal)
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@objc private func keyPressed(_ sender: UIButton) {
|
|
134
|
+
guard let key = sender.nativeID else { return }
|
|
135
|
+
let isCustomKey = sender.tag == 1
|
|
136
|
+
if (isCustomKey) {
|
|
137
|
+
input?.emitCustomKey()
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
input?.emitKeyPress(key)
|
|
142
|
+
switch key {
|
|
143
|
+
case "back":
|
|
144
|
+
input?.onBackSpace()
|
|
145
|
+
case "=":
|
|
146
|
+
input?.calculateResult()
|
|
147
|
+
case "+", "-", "÷", "×":
|
|
148
|
+
input?.keyDidPress(" \(key) ")
|
|
149
|
+
default:
|
|
150
|
+
input?.keyDidPress(key)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTViewManager.h>
|
|
3
|
+
#import <React/RCTBaseTextInputViewManager.h>
|
|
4
|
+
#import <React/RCTSinglelineTextInputView.h>
|
|
5
|
+
#import <React/RCTUITextField.h>
|
|
6
|
+
#import <React/RCTBaseTextInputViewManager.h>
|
|
7
|
+
|
|
8
|
+
#import <React/RCTBridge.h>
|
|
9
|
+
#import <React/RCTConvert.h>
|
|
10
|
+
#import <React/RCTFont.h>
|
|
11
|
+
#import <React/RCTShadowView+Layout.h>
|
|
12
|
+
#import <React/RCTShadowView.h>
|
|
13
|
+
#import <React/RCTUIManager.h>
|
|
14
|
+
#import <React/RCTUIManagerObserverCoordinator.h>
|
|
15
|
+
#import <React/RCTUIManagerUtils.h>
|
|
16
|
+
|
|
17
|
+
#import <React/RCTBaseTextInputShadowView.h>
|
|
18
|
+
#import <React/RCTBaseTextInputView.h>
|
|
19
|
+
#import <React/RCTConvert+Text.h>
|
|
20
|
+
|
|
21
|
+
@interface Calculator : NSObject <RCTBridgeModule>
|
|
22
|
+
|
|
23
|
+
@end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#import <InputCalculator-Bridging-Header.h>
|
|
2
|
+
|
|
3
|
+
@implementation Calculator
|
|
4
|
+
|
|
5
|
+
- (dispatch_queue_t)methodQueue
|
|
6
|
+
{
|
|
7
|
+
return dispatch_get_main_queue();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
RCT_EXPORT_MODULE()
|
|
11
|
+
|
|
12
|
+
@end
|
|
13
|
+
|
|
14
|
+
@interface RCT_EXTERN_MODULE(RCTInputCalculator, RCTViewManager)
|
|
15
|
+
|
|
16
|
+
RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType)
|
|
17
|
+
RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType)
|
|
18
|
+
RCT_REMAP_VIEW_PROPERTY(contextMenuHidden, backedTextInputView.contextMenuHidden, BOOL)
|
|
19
|
+
RCT_REMAP_VIEW_PROPERTY(editable, backedTextInputView.editable, BOOL)
|
|
20
|
+
RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, backedTextInputView.enablesReturnKeyAutomatically, BOOL)
|
|
21
|
+
RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearance, UIKeyboardAppearance)
|
|
22
|
+
RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString)
|
|
23
|
+
RCT_REMAP_VIEW_PROPERTY(placeholderTextColor, backedTextInputView.placeholderColor, UIColor)
|
|
24
|
+
RCT_REMAP_VIEW_PROPERTY(returnKeyType, backedTextInputView.returnKeyType, UIReturnKeyType)
|
|
25
|
+
RCT_REMAP_VIEW_PROPERTY(selectionColor, backedTextInputView.tintColor, UIColor)
|
|
26
|
+
RCT_REMAP_VIEW_PROPERTY(spellCheck, backedTextInputView.spellCheckingType, UITextSpellCheckingType)
|
|
27
|
+
RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL)
|
|
28
|
+
RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode)
|
|
29
|
+
RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL)
|
|
30
|
+
RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL)
|
|
31
|
+
RCT_REMAP_VIEW_PROPERTY(smartInsertDelete, backedTextInputView.smartInsertDeleteType, UITextSmartInsertDeleteType)
|
|
32
|
+
|
|
33
|
+
RCT_EXPORT_VIEW_PROPERTY(autoFocus, BOOL)
|
|
34
|
+
RCT_EXPORT_VIEW_PROPERTY(submitBehavior, NSString)
|
|
35
|
+
RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
|
|
36
|
+
RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType)
|
|
37
|
+
RCT_EXPORT_VIEW_PROPERTY(showSoftInputOnFocus, BOOL)
|
|
38
|
+
RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
|
|
39
|
+
RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
|
|
40
|
+
RCT_EXPORT_VIEW_PROPERTY(selection, RCTTextSelection)
|
|
41
|
+
RCT_EXPORT_VIEW_PROPERTY(inputAccessoryViewID, NSString)
|
|
42
|
+
RCT_EXPORT_VIEW_PROPERTY(textContentType, NSString)
|
|
43
|
+
RCT_EXPORT_VIEW_PROPERTY(passwordRules, NSString)
|
|
44
|
+
|
|
45
|
+
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
|
|
46
|
+
RCT_EXPORT_VIEW_PROPERTY(onKeyPressSync, RCTDirectEventBlock)
|
|
47
|
+
RCT_EXPORT_VIEW_PROPERTY(onChangeSync, RCTDirectEventBlock)
|
|
48
|
+
RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock)
|
|
49
|
+
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
|
|
50
|
+
|
|
51
|
+
RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger)
|
|
52
|
+
|
|
53
|
+
RCT_EXPORT_SHADOW_PROPERTY(text, NSString)
|
|
54
|
+
RCT_EXPORT_SHADOW_PROPERTY(placeholder, NSString)
|
|
55
|
+
RCT_EXPORT_SHADOW_PROPERTY(onContentSizeChange, RCTDirectEventBlock)
|
|
56
|
+
RCT_EXPORT_VIEW_PROPERTY(value, NSString)
|
|
57
|
+
RCT_EXPORT_VIEW_PROPERTY(onFocus, RCTBubblingEventBlock)
|
|
58
|
+
RCT_EXPORT_VIEW_PROPERTY(onBlur, RCTBubblingEventBlock)
|
|
59
|
+
RCT_EXPORT_VIEW_PROPERTY(onKeyPress, RCTBubblingEventBlock)
|
|
60
|
+
RCT_EXPORT_VIEW_PROPERTY(onCustomKeyEvent, RCTDirectEventBlock)
|
|
61
|
+
|
|
62
|
+
RCT_EXPORT_METHOD(focus : (nonnull NSNumber *)viewTag)
|
|
63
|
+
{
|
|
64
|
+
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
65
|
+
UIView *view = viewRegistry[viewTag];
|
|
66
|
+
[view reactFocus];
|
|
67
|
+
}];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
RCT_EXPORT_METHOD(blur : (nonnull NSNumber *)viewTag)
|
|
71
|
+
{
|
|
72
|
+
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
73
|
+
UIView *view = viewRegistry[viewTag];
|
|
74
|
+
[view reactBlur];
|
|
75
|
+
}];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
RCT_EXPORT_VIEW_PROPERTY(keyboardColor, UIColor)
|
|
79
|
+
RCT_EXPORT_VIEW_PROPERTY(customKeyText, NSString)
|
|
80
|
+
RCT_EXPORT_VIEW_PROPERTY(customKeyBackground, NSString)
|
|
81
|
+
RCT_EXPORT_VIEW_PROPERTY(customKeyTextColor, NSString)
|
|
82
|
+
RCT_EXPORT_VIEW_PROPERTY(customKeyState, NSString)
|
|
83
|
+
|
|
84
|
+
@end
|
|
85
|
+
|