@momo-kits/calculator-keyboard 0.150.2-phuc.15 → 0.151.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -3
- package/android/src/main/java/com/calculatorkeyboard/CalculatorKeyboardPackage.kt +1 -1
- package/android/src/main/java/com/calculatorkeyboard/CustomKeyboardView.kt +166 -90
- package/android/src/main/java/com/calculatorkeyboard/Event.kt +36 -0
- package/android/src/main/java/com/calculatorkeyboard/{RCTInputCalculator.kt → InputCalculatorViewManager.kt} +100 -27
- package/ios/CalculatorKeyboardView.h +30 -0
- package/ios/CalculatorKeyboardView.mm +231 -0
- package/ios/NativeInputCalculator.h +11 -0
- package/ios/NativeInputCalculator.mm +369 -0
- package/package.json +21 -131
- package/react-native-calculator-keyboard.podspec +5 -4
- package/src/InputCalculatorNativeComponent.ts +62 -0
- package/src/index.tsx +77 -43
- package/ios/CalculatorKeyboardView.swift +0 -153
- package/ios/InputCalculator-Bridging-Header.h +0 -23
- package/ios/InputCalculator.m +0 -85
- package/ios/InputCalculator.swift +0 -158
- package/ios/extension.swift +0 -23
- package/lib/commonjs/index.js +0 -72
- package/lib/commonjs/index.js.map +0 -1
- package/lib/module/index.js +0 -67
- package/lib/module/index.js.map +0 -1
- package/lib/typescript/commonjs/package.json +0 -1
- package/lib/typescript/commonjs/src/index.d.ts +0 -23
- package/lib/typescript/commonjs/src/index.d.ts.map +0 -1
- package/lib/typescript/module/package.json +0 -1
- package/lib/typescript/module/src/index.d.ts +0 -23
- package/lib/typescript/module/src/index.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -10,15 +10,57 @@ npm install react-native-calculator-keyboard
|
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
```js
|
|
15
|
-
import
|
|
14
|
+
import InputCalculator from '@momo-kits/calculator-keyboard';
|
|
16
15
|
|
|
17
16
|
// ...
|
|
18
17
|
|
|
19
|
-
<
|
|
18
|
+
<InputCalculator
|
|
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
|
|
20
61
|
```
|
|
21
62
|
|
|
63
|
+
**Note**: This library uses Fabric ComponentView (`.mm` files) and will not work without `RCT_NEW_ARCH_ENABLED=1`.
|
|
22
64
|
|
|
23
65
|
## Contributing
|
|
24
66
|
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
package com.calculatorkeyboard
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
4
5
|
import android.content.res.ColorStateList
|
|
5
6
|
import android.graphics.Color
|
|
6
7
|
import android.graphics.drawable.GradientDrawable
|
|
7
8
|
import android.view.Gravity
|
|
8
9
|
import android.widget.Button
|
|
9
10
|
import android.widget.ImageButton
|
|
10
|
-
import androidx.appcompat.app.AppCompatActivity
|
|
11
11
|
import androidx.constraintlayout.widget.ConstraintLayout
|
|
12
12
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
13
13
|
import org.mariuszgromada.math.mxparser.Expression
|
|
14
14
|
import androidx.core.graphics.toColorInt
|
|
15
|
-
import com.calculatorkeyboard.
|
|
15
|
+
import com.calculatorkeyboard.InputCalculatorViewManager.Companion.calculatorHeight
|
|
16
16
|
import com.facebook.react.bridge.Arguments
|
|
17
|
+
import com.facebook.react.bridge.ReactContext
|
|
18
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
17
19
|
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
18
20
|
|
|
19
21
|
@SuppressLint("SetTextI18n", "ViewConstructor")
|
|
@@ -21,53 +23,57 @@ class CustomKeyboardView(
|
|
|
21
23
|
context: ThemedReactContext,
|
|
22
24
|
private val editText: CalculatorEditText
|
|
23
25
|
) : ConstraintLayout(context) {
|
|
24
|
-
private val
|
|
26
|
+
private val numWithCTAKeys = listOf(
|
|
25
27
|
listOf("1", "2", "3", "÷", "back"),
|
|
26
28
|
listOf("4", "5", "6", "×", "="),
|
|
27
|
-
listOf("7", "8", "9", "-", "
|
|
29
|
+
listOf("7", "8", "9", "-", "Tiếp"),
|
|
28
30
|
listOf("000", "0", "+")
|
|
29
31
|
)
|
|
30
|
-
private val
|
|
32
|
+
private val defaultKeys = listOf(
|
|
33
|
+
listOf("1", "2", "3", "÷", "AC"),
|
|
34
|
+
listOf("4", "5", "6", "×", "back"),
|
|
35
|
+
listOf("7", "8", "9", "-", "="),
|
|
36
|
+
listOf("000", "0", "+")
|
|
37
|
+
)
|
|
38
|
+
private val specialKeys = listOf("=", "-", "×", "÷", "back", "+", "AC")
|
|
31
39
|
private val separatorWidth = 8f
|
|
32
40
|
private var specialButtonColor: Int = "#D8D8D8".toColorInt()
|
|
33
41
|
|
|
42
|
+
private var keyboardMode: String = "NumDefault"
|
|
43
|
+
|
|
34
44
|
private var customKeyButton: Button? = null
|
|
35
45
|
private var customKeyButtonBackground: Int = "#D8D8D8".toColorInt()
|
|
36
46
|
private var customKeyButtonTextColor: Int = Color.BLACK
|
|
37
47
|
private var customKeyButtonState: String = "default"
|
|
38
48
|
|
|
39
49
|
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
|
-
|
|
46
50
|
isClickable = false
|
|
47
51
|
isFocusable = false
|
|
48
52
|
isFocusableInTouchMode = false
|
|
49
53
|
clipToPadding = false
|
|
50
54
|
clipChildren = false
|
|
51
|
-
|
|
52
|
-
renderUI(widthButton, heightButton)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
private fun renderUI(
|
|
57
|
+
private fun renderUI() {
|
|
58
|
+
val displayMetrics = resources.displayMetrics
|
|
59
|
+
val buttonWidth = (displayMetrics.widthPixels - separatorWidth * 2 - 4 * separatorWidth) / 5f
|
|
60
|
+
val buttonHeight = (calculatorHeight - separatorWidth * 2 - 3 * separatorWidth) / 4
|
|
61
|
+
|
|
58
62
|
var yOffset = separatorWidth
|
|
63
|
+
val keys = if (keyboardMode == "NumWithCTA") numWithCTAKeys else defaultKeys
|
|
59
64
|
for ((rowIndex, row) in keys.withIndex()) {
|
|
60
65
|
var xOffset = separatorWidth
|
|
61
66
|
for ((colIndex, key) in row.withIndex()) {
|
|
62
|
-
val
|
|
67
|
+
val isMainKey = rowIndex == 2 && colIndex == 4
|
|
68
|
+
val isMainCTAKey = isMainKey && keyboardMode == "NumWithCTA"
|
|
63
69
|
val width = if (key == "000") buttonWidth * 2 + separatorWidth else buttonWidth
|
|
64
|
-
val height = if (
|
|
70
|
+
val height = if (isMainKey) buttonHeight * 2 + separatorWidth else buttonHeight
|
|
65
71
|
|
|
66
72
|
val button = if (key == "back") {
|
|
67
73
|
createImageButton(key, xOffset, yOffset, buttonWidth.toInt(), buttonHeight.toInt())
|
|
68
74
|
} else {
|
|
69
|
-
createButton(key, xOffset, yOffset, width.toInt(), height.toInt(),
|
|
70
|
-
if (
|
|
75
|
+
createButton(key, xOffset, yOffset, width.toInt(), height.toInt(), isMainKey, isMainCTAKey).also { b ->
|
|
76
|
+
if (isMainCTAKey) customKeyButton = b
|
|
71
77
|
}
|
|
72
78
|
}
|
|
73
79
|
|
|
@@ -85,7 +91,8 @@ class CustomKeyboardView(
|
|
|
85
91
|
yOffset: Float,
|
|
86
92
|
buttonWidth: Int,
|
|
87
93
|
buttonHeight: Int,
|
|
88
|
-
|
|
94
|
+
isMainKey: Boolean,
|
|
95
|
+
isMainCTAKey: Boolean
|
|
89
96
|
): Button {
|
|
90
97
|
return Button(context).apply {
|
|
91
98
|
val shapeInit = GradientDrawable().apply {
|
|
@@ -98,7 +105,7 @@ class CustomKeyboardView(
|
|
|
98
105
|
background = shapeInit
|
|
99
106
|
text = key
|
|
100
107
|
setTypeface(typeface)
|
|
101
|
-
textSize = (if (
|
|
108
|
+
textSize = (if (isMainCTAKey) 18 else 24).toFloat()
|
|
102
109
|
setTextColor(Color.BLACK)
|
|
103
110
|
stateListAnimator = null
|
|
104
111
|
maxLines = 1
|
|
@@ -110,7 +117,7 @@ class CustomKeyboardView(
|
|
|
110
117
|
constrainedWidth = false
|
|
111
118
|
}
|
|
112
119
|
|
|
113
|
-
if (specialKeys.contains(key)) {
|
|
120
|
+
if (specialKeys.contains(key) || isMainKey) {
|
|
114
121
|
background = GradientDrawable().apply {
|
|
115
122
|
shape = GradientDrawable.RECTANGLE
|
|
116
123
|
cornerRadius = 24f
|
|
@@ -125,7 +132,7 @@ class CustomKeyboardView(
|
|
|
125
132
|
|
|
126
133
|
translationX = xOffset.toInt().toFloat()
|
|
127
134
|
translationY = yOffset.toInt().toFloat()
|
|
128
|
-
setOnClickListener { onKeyPress(key,
|
|
135
|
+
setOnClickListener { onKeyPress(key, isMainCTAKey) }
|
|
129
136
|
}
|
|
130
137
|
}
|
|
131
138
|
|
|
@@ -163,51 +170,22 @@ class CustomKeyboardView(
|
|
|
163
170
|
}
|
|
164
171
|
}
|
|
165
172
|
|
|
166
|
-
fun
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
val child = getChildAt(i)
|
|
170
|
-
if (child is Button) {
|
|
171
|
-
val key = child.text.toString()
|
|
172
|
-
if (specialKeys.contains(key)) {
|
|
173
|
-
if (key == "=") {
|
|
174
|
-
child.background = GradientDrawable().apply {
|
|
175
|
-
shape = GradientDrawable.RECTANGLE
|
|
176
|
-
cornerRadius = 24f
|
|
177
|
-
setColor(specialButtonColor)
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
child.background = GradientDrawable().apply {
|
|
181
|
-
shape = GradientDrawable.RECTANGLE
|
|
182
|
-
cornerRadius = 24f
|
|
183
|
-
setColor(specialButtonColor)
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
child.setTextColor(Color.BLACK)
|
|
187
|
-
}
|
|
188
|
-
} else if (child is ImageButton) {
|
|
189
|
-
child.background = GradientDrawable().apply {
|
|
190
|
-
shape = GradientDrawable.RECTANGLE
|
|
191
|
-
cornerRadius = 24f
|
|
192
|
-
setColor(specialButtonColor)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
private fun onKeyPress(key: String, isCustomKey: Boolean) {
|
|
199
|
-
if (isCustomKey) {
|
|
200
|
-
emitCustomKey()
|
|
173
|
+
private fun onKeyPress(key: String, isMainCTAKey: Boolean) {
|
|
174
|
+
if (isMainCTAKey) {
|
|
175
|
+
emitCustomKey(context)
|
|
201
176
|
return
|
|
202
177
|
}
|
|
203
178
|
|
|
204
|
-
emitKeyPress(key)
|
|
179
|
+
emitKeyPress(context, key)
|
|
205
180
|
when (key) {
|
|
181
|
+
"AC" -> clearText()
|
|
206
182
|
"back" -> onBackSpace()
|
|
207
183
|
"=" -> calculateResult()
|
|
208
184
|
"×", "+", "-", "÷" -> keyDidPress(" $key ")
|
|
209
185
|
else -> editText.text?.insert(editText.selectionStart, key)
|
|
210
186
|
}
|
|
187
|
+
|
|
188
|
+
reformatAndKeepSelection(editText)
|
|
211
189
|
}
|
|
212
190
|
|
|
213
191
|
private fun keyDidPress(key: String) {
|
|
@@ -215,27 +193,44 @@ class CustomKeyboardView(
|
|
|
215
193
|
editText.text?.replace(editText.selectionStart, editText.selectionEnd, key)
|
|
216
194
|
}
|
|
217
195
|
|
|
196
|
+
private fun clearText() {
|
|
197
|
+
editText.text?.clear()
|
|
198
|
+
}
|
|
199
|
+
|
|
218
200
|
private fun onBackSpace() {
|
|
219
|
-
val
|
|
220
|
-
val
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
201
|
+
val formatted = editText.text?.toString().orEmpty()
|
|
202
|
+
val caretFmt = editText.selectionStart.coerceAtLeast(0)
|
|
203
|
+
|
|
204
|
+
val rawBefore = stripGroupDots(formatted)
|
|
205
|
+
val caretRaw = formattedCaretToRaw(formatted, caretFmt)
|
|
206
|
+
|
|
207
|
+
if (caretRaw <= 0) return
|
|
208
|
+
|
|
209
|
+
val rawAfter = buildString(rawBefore.length - 1) {
|
|
210
|
+
append(rawBefore, 0, caretRaw - 1)
|
|
211
|
+
append(rawBefore, caretRaw, rawBefore.length)
|
|
225
212
|
}
|
|
213
|
+
|
|
214
|
+
val formattedAfter = formatNumberGroups(rawAfter)
|
|
215
|
+
editText.setText(formattedAfter)
|
|
216
|
+
val newCaretFmt = rawCaretToFormatted(caretRaw - 1, formattedAfter)
|
|
217
|
+
editText.setSelection(newCaretFmt.coerceIn(0, formattedAfter.length))
|
|
226
218
|
}
|
|
227
219
|
|
|
220
|
+
|
|
228
221
|
private fun calculateResult() {
|
|
229
|
-
val
|
|
222
|
+
val raw = editText.text?.toString().orEmpty()
|
|
223
|
+
val normalized = raw.replace(".", "")
|
|
224
|
+
.replace("×", "*")
|
|
225
|
+
.replace("÷", "/")
|
|
226
|
+
|
|
230
227
|
val pattern = "^\\s*(-?\\d+(\\.\\d+)?\\s*[-+*/]\\s*)*-?\\d+(\\.\\d+)?\\s*$"
|
|
231
|
-
|
|
232
|
-
if (regex.matches(text)) {
|
|
228
|
+
if (Regex(pattern).matches(normalized)) {
|
|
233
229
|
try {
|
|
234
|
-
val result = eval(
|
|
235
|
-
editText.setTextKeepState(result)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
230
|
+
val result = eval(normalized)?.toString() ?: return
|
|
231
|
+
editText.setTextKeepState(formatNumberGroups(result))
|
|
232
|
+
editText.setSelection(editText.text?.length ?: 0)
|
|
233
|
+
} catch (_: Exception) { /* ignore */ }
|
|
239
234
|
} else {
|
|
240
235
|
println("Invalid expression")
|
|
241
236
|
}
|
|
@@ -251,44 +246,56 @@ class CustomKeyboardView(
|
|
|
251
246
|
}
|
|
252
247
|
}
|
|
253
248
|
|
|
254
|
-
private fun emitKeyPress(key: String) {
|
|
255
|
-
val reactContext = context as
|
|
256
|
-
val
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
249
|
+
private fun emitKeyPress(context: Context, key: String) {
|
|
250
|
+
val reactContext = context as ReactContext
|
|
251
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
252
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, editText.id)
|
|
253
|
+
val payload =
|
|
254
|
+
Arguments.createMap().apply {
|
|
255
|
+
putString("key", key)
|
|
256
|
+
}
|
|
257
|
+
val event = OnKeyPressEvent(surfaceId, editText.id, payload)
|
|
258
|
+
|
|
259
|
+
eventDispatcher?.dispatchEvent(event)
|
|
261
260
|
}
|
|
262
261
|
|
|
263
|
-
private fun emitCustomKey() {
|
|
264
|
-
val reactContext = context as
|
|
265
|
-
|
|
266
|
-
|
|
262
|
+
private fun emitCustomKey(context: Context) {
|
|
263
|
+
val reactContext = context as ReactContext
|
|
264
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
265
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, editText.id)
|
|
266
|
+
|
|
267
|
+
val event = OnCustomKeyPressEvent(surfaceId, editText.id)
|
|
268
|
+
|
|
269
|
+
eventDispatcher?.dispatchEvent(event)
|
|
267
270
|
}
|
|
268
271
|
|
|
269
272
|
fun setCustomKeyText(text: String) {
|
|
270
273
|
customKeyButton?.text = text
|
|
271
274
|
}
|
|
272
275
|
|
|
276
|
+
fun setMode(mode: String) {
|
|
277
|
+
keyboardMode = mode
|
|
278
|
+
renderUI()
|
|
279
|
+
}
|
|
280
|
+
|
|
273
281
|
fun setCustomKeyBackground(background: Int) {
|
|
274
282
|
customKeyButtonBackground = background
|
|
275
|
-
updateCustomKeyUI(background, customKeyButtonTextColor
|
|
283
|
+
updateCustomKeyUI(background, customKeyButtonTextColor)
|
|
276
284
|
}
|
|
277
285
|
|
|
278
286
|
fun setCustomKeyTextColor(textColor: Int) {
|
|
279
287
|
customKeyButtonTextColor = textColor
|
|
280
|
-
updateCustomKeyUI(customKeyButtonBackground, textColor
|
|
288
|
+
updateCustomKeyUI(customKeyButtonBackground, textColor)
|
|
281
289
|
}
|
|
282
290
|
|
|
283
291
|
|
|
284
292
|
fun setCustomKeyState(state: String) {
|
|
285
293
|
customKeyButtonState = state
|
|
286
294
|
customKeyButton?.isEnabled = state != "disable"
|
|
287
|
-
updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor
|
|
295
|
+
updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor)
|
|
288
296
|
}
|
|
289
297
|
|
|
290
|
-
private fun updateCustomKeyUI(background: Int, textColor: Int
|
|
291
|
-
|
|
298
|
+
private fun updateCustomKeyUI(background: Int, textColor: Int){
|
|
292
299
|
customKeyButton?.background = GradientDrawable().apply {
|
|
293
300
|
shape = GradientDrawable.RECTANGLE
|
|
294
301
|
cornerRadius = 24f
|
|
@@ -297,5 +304,74 @@ class CustomKeyboardView(
|
|
|
297
304
|
customKeyButton?.setTextColor(textColor)
|
|
298
305
|
}
|
|
299
306
|
|
|
307
|
+
private fun reformatAndKeepSelection(editText: CalculatorEditText) {
|
|
308
|
+
val formattedBefore = editText.text?.toString() ?: return
|
|
309
|
+
val caretFmtBefore = editText.selectionStart.coerceAtLeast(0)
|
|
310
|
+
|
|
311
|
+
val caretRaw = formattedCaretToRaw(formattedBefore, caretFmtBefore)
|
|
312
|
+
|
|
313
|
+
val formattedAfter = formatNumberGroups(formattedBefore)
|
|
314
|
+
|
|
315
|
+
if (formattedAfter != formattedBefore) {
|
|
316
|
+
editText.setText(formattedAfter)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
val caretFmtAfter = rawCaretToFormatted(caretRaw, formattedAfter)
|
|
320
|
+
editText.setSelection(caretFmtAfter.coerceIn(0, formattedAfter.length))
|
|
321
|
+
}
|
|
322
|
+
private fun stripGroupDots(input: String): String {
|
|
323
|
+
val out = StringBuilder(input.length)
|
|
324
|
+
for (i in input.indices) {
|
|
325
|
+
val c = input[i]
|
|
326
|
+
if (c == '.' && isGroupDotAt(input, i)) {
|
|
327
|
+
} else {
|
|
328
|
+
out.append(c)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return out.toString()
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
private fun formatNumberGroups(input: String): String {
|
|
335
|
+
val noSep = stripGroupDots(input)
|
|
336
|
+
return Regex("\\d+").replace(noSep) { m ->
|
|
337
|
+
val s = m.value
|
|
338
|
+
val rev = s.reversed().chunked(3).joinToString(".")
|
|
339
|
+
rev.reversed()
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
private fun isGroupDotAt(s: String, i: Int): Boolean {
|
|
344
|
+
if (i < 0 || i >= s.length) return false
|
|
345
|
+
if (s[i] != '.') return false
|
|
346
|
+
val leftIsDigit = i - 1 >= 0 && s[i - 1].isDigit()
|
|
347
|
+
val rightIsDigit = i + 1 < s.length && s[i + 1].isDigit()
|
|
348
|
+
return leftIsDigit && rightIsDigit
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
private fun formattedCaretToRaw(formatted: String, caretFmt: Int): Int {
|
|
352
|
+
var rawIdx = 0
|
|
353
|
+
var i = 0
|
|
354
|
+
while (i < caretFmt && i < formatted.length) {
|
|
355
|
+
val c = formatted[i]
|
|
356
|
+
if (!(c == '.' && isGroupDotAt(formatted, i))) {
|
|
357
|
+
rawIdx++
|
|
358
|
+
}
|
|
359
|
+
i++
|
|
360
|
+
}
|
|
361
|
+
return rawIdx
|
|
362
|
+
}
|
|
300
363
|
|
|
364
|
+
private fun rawCaretToFormatted(rawCaret: Int, formatted: String): Int {
|
|
365
|
+
var rawSeen = 0
|
|
366
|
+
var i = 0
|
|
367
|
+
while (i < formatted.length) {
|
|
368
|
+
val c = formatted[i]
|
|
369
|
+
if (!(c == '.' && isGroupDotAt(formatted, i))) {
|
|
370
|
+
if (rawSeen == rawCaret) return i
|
|
371
|
+
rawSeen++
|
|
372
|
+
}
|
|
373
|
+
i++
|
|
374
|
+
}
|
|
375
|
+
return formatted.length
|
|
376
|
+
}
|
|
301
377
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.calculatorkeyboard
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.WritableMap
|
|
4
|
+
import com.facebook.react.uimanager.events.Event
|
|
5
|
+
|
|
6
|
+
class OnChangeEvent(
|
|
7
|
+
surfaceId: Int,
|
|
8
|
+
viewId: Int,
|
|
9
|
+
private val payload: WritableMap
|
|
10
|
+
) : Event<OnChangeEvent>(surfaceId, viewId) {
|
|
11
|
+
override fun getEventName() = "onChange"
|
|
12
|
+
|
|
13
|
+
override fun getEventData() = payload
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class OnKeyPressEvent(
|
|
17
|
+
surfaceId: Int,
|
|
18
|
+
viewId: Int,
|
|
19
|
+
private val payload: WritableMap
|
|
20
|
+
) : Event<OnChangeEvent>(surfaceId, viewId) {
|
|
21
|
+
override fun getEventName() = "onKeyPress"
|
|
22
|
+
|
|
23
|
+
override fun getEventData() = payload
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class OnCustomKeyPressEvent(
|
|
27
|
+
surfaceId: Int,
|
|
28
|
+
viewId: Int
|
|
29
|
+
) : Event<OnChangeEvent>(surfaceId, viewId) {
|
|
30
|
+
override fun getEventName() = "onCustomKeyEvent"
|
|
31
|
+
|
|
32
|
+
override fun getEventData() = null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|