@momo-kits/calculator-keyboard 0.150.2-phuc.13 → 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 +184 -95
- package/android/src/main/java/com/calculatorkeyboard/Event.kt +36 -0
- package/android/src/main/java/com/calculatorkeyboard/InputCalculatorViewManager.kt +270 -0
- package/android/src/main/java/com/calculatorkeyboard/KeyboardOverplayHost.kt +232 -0
- 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 +124 -82
- package/android/src/main/java/com/calculatorkeyboard/RCTInputCalculator.kt +0 -339
- package/ios/CalculatorKeyboardView.swift +0 -165
- 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 -68
- 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 -31
- 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 -31
- 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,47 +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
|
-
private var customKeyButtonState:
|
|
47
|
+
private var customKeyButtonState: String = "default"
|
|
38
48
|
|
|
39
49
|
init {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
renderUI(widthButton, heightButton)
|
|
47
|
-
}
|
|
48
|
-
|
|
50
|
+
isClickable = false
|
|
51
|
+
isFocusable = false
|
|
52
|
+
isFocusableInTouchMode = false
|
|
53
|
+
clipToPadding = false
|
|
54
|
+
clipChildren = false
|
|
49
55
|
}
|
|
50
56
|
|
|
51
|
-
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
|
+
|
|
52
62
|
var yOffset = separatorWidth
|
|
63
|
+
val keys = if (keyboardMode == "NumWithCTA") numWithCTAKeys else defaultKeys
|
|
53
64
|
for ((rowIndex, row) in keys.withIndex()) {
|
|
54
65
|
var xOffset = separatorWidth
|
|
55
66
|
for ((colIndex, key) in row.withIndex()) {
|
|
56
|
-
val
|
|
67
|
+
val isMainKey = rowIndex == 2 && colIndex == 4
|
|
68
|
+
val isMainCTAKey = isMainKey && keyboardMode == "NumWithCTA"
|
|
57
69
|
val width = if (key == "000") buttonWidth * 2 + separatorWidth else buttonWidth
|
|
58
|
-
val height = if (
|
|
70
|
+
val height = if (isMainKey) buttonHeight * 2 + separatorWidth else buttonHeight
|
|
59
71
|
|
|
60
72
|
val button = if (key == "back") {
|
|
61
73
|
createImageButton(key, xOffset, yOffset, buttonWidth.toInt(), buttonHeight.toInt())
|
|
62
74
|
} else {
|
|
63
|
-
createButton(key, xOffset, yOffset, width.toInt(), height.toInt(),
|
|
64
|
-
if (
|
|
75
|
+
createButton(key, xOffset, yOffset, width.toInt(), height.toInt(), isMainKey, isMainCTAKey).also { b ->
|
|
76
|
+
if (isMainCTAKey) customKeyButton = b
|
|
65
77
|
}
|
|
66
78
|
}
|
|
67
79
|
|
|
@@ -79,7 +91,8 @@ class CustomKeyboardView(
|
|
|
79
91
|
yOffset: Float,
|
|
80
92
|
buttonWidth: Int,
|
|
81
93
|
buttonHeight: Int,
|
|
82
|
-
|
|
94
|
+
isMainKey: Boolean,
|
|
95
|
+
isMainCTAKey: Boolean
|
|
83
96
|
): Button {
|
|
84
97
|
return Button(context).apply {
|
|
85
98
|
val shapeInit = GradientDrawable().apply {
|
|
@@ -92,7 +105,7 @@ class CustomKeyboardView(
|
|
|
92
105
|
background = shapeInit
|
|
93
106
|
text = key
|
|
94
107
|
setTypeface(typeface)
|
|
95
|
-
textSize = (if (
|
|
108
|
+
textSize = (if (isMainCTAKey) 18 else 24).toFloat()
|
|
96
109
|
setTextColor(Color.BLACK)
|
|
97
110
|
stateListAnimator = null
|
|
98
111
|
maxLines = 1
|
|
@@ -104,7 +117,7 @@ class CustomKeyboardView(
|
|
|
104
117
|
constrainedWidth = false
|
|
105
118
|
}
|
|
106
119
|
|
|
107
|
-
if (specialKeys.contains(key)) {
|
|
120
|
+
if (specialKeys.contains(key) || isMainKey) {
|
|
108
121
|
background = GradientDrawable().apply {
|
|
109
122
|
shape = GradientDrawable.RECTANGLE
|
|
110
123
|
cornerRadius = 24f
|
|
@@ -113,10 +126,13 @@ class CustomKeyboardView(
|
|
|
113
126
|
setTextColor(Color.BLACK)
|
|
114
127
|
}
|
|
115
128
|
|
|
129
|
+
isClickable = true
|
|
130
|
+
isFocusable = false
|
|
131
|
+
isFocusableInTouchMode = false
|
|
116
132
|
|
|
117
133
|
translationX = xOffset.toInt().toFloat()
|
|
118
134
|
translationY = yOffset.toInt().toFloat()
|
|
119
|
-
setOnClickListener { onKeyPress(key,
|
|
135
|
+
setOnClickListener { onKeyPress(key, isMainCTAKey) }
|
|
120
136
|
}
|
|
121
137
|
}
|
|
122
138
|
|
|
@@ -141,6 +157,11 @@ class CustomKeyboardView(
|
|
|
141
157
|
).apply {
|
|
142
158
|
constrainedWidth = false
|
|
143
159
|
}
|
|
160
|
+
|
|
161
|
+
isClickable = true
|
|
162
|
+
isFocusable = false
|
|
163
|
+
isFocusableInTouchMode = false
|
|
164
|
+
|
|
144
165
|
translationX = xOffset
|
|
145
166
|
translationY = yOffset
|
|
146
167
|
setImageResource(android.R.drawable.ic_input_delete)
|
|
@@ -149,51 +170,22 @@ class CustomKeyboardView(
|
|
|
149
170
|
}
|
|
150
171
|
}
|
|
151
172
|
|
|
152
|
-
fun
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
val child = getChildAt(i)
|
|
156
|
-
if (child is Button) {
|
|
157
|
-
val key = child.text.toString()
|
|
158
|
-
if (specialKeys.contains(key)) {
|
|
159
|
-
if (key == "=") {
|
|
160
|
-
child.background = GradientDrawable().apply {
|
|
161
|
-
shape = GradientDrawable.RECTANGLE
|
|
162
|
-
cornerRadius = 24f
|
|
163
|
-
setColor(specialButtonColor)
|
|
164
|
-
}
|
|
165
|
-
} else {
|
|
166
|
-
child.background = GradientDrawable().apply {
|
|
167
|
-
shape = GradientDrawable.RECTANGLE
|
|
168
|
-
cornerRadius = 24f
|
|
169
|
-
setColor(specialButtonColor)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
child.setTextColor(Color.BLACK)
|
|
173
|
-
}
|
|
174
|
-
} else if (child is ImageButton) {
|
|
175
|
-
child.background = GradientDrawable().apply {
|
|
176
|
-
shape = GradientDrawable.RECTANGLE
|
|
177
|
-
cornerRadius = 24f
|
|
178
|
-
setColor(specialButtonColor)
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private fun onKeyPress(key: String, isCustomKey: Boolean) {
|
|
185
|
-
if (isCustomKey) {
|
|
186
|
-
emitCustomKey()
|
|
173
|
+
private fun onKeyPress(key: String, isMainCTAKey: Boolean) {
|
|
174
|
+
if (isMainCTAKey) {
|
|
175
|
+
emitCustomKey(context)
|
|
187
176
|
return
|
|
188
177
|
}
|
|
189
178
|
|
|
190
|
-
emitKeyPress(key)
|
|
179
|
+
emitKeyPress(context, key)
|
|
191
180
|
when (key) {
|
|
181
|
+
"AC" -> clearText()
|
|
192
182
|
"back" -> onBackSpace()
|
|
193
183
|
"=" -> calculateResult()
|
|
194
184
|
"×", "+", "-", "÷" -> keyDidPress(" $key ")
|
|
195
185
|
else -> editText.text?.insert(editText.selectionStart, key)
|
|
196
186
|
}
|
|
187
|
+
|
|
188
|
+
reformatAndKeepSelection(editText)
|
|
197
189
|
}
|
|
198
190
|
|
|
199
191
|
private fun keyDidPress(key: String) {
|
|
@@ -201,27 +193,44 @@ class CustomKeyboardView(
|
|
|
201
193
|
editText.text?.replace(editText.selectionStart, editText.selectionEnd, key)
|
|
202
194
|
}
|
|
203
195
|
|
|
196
|
+
private fun clearText() {
|
|
197
|
+
editText.text?.clear()
|
|
198
|
+
}
|
|
199
|
+
|
|
204
200
|
private fun onBackSpace() {
|
|
205
|
-
val
|
|
206
|
-
val
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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)
|
|
211
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))
|
|
212
218
|
}
|
|
213
219
|
|
|
220
|
+
|
|
214
221
|
private fun calculateResult() {
|
|
215
|
-
val
|
|
222
|
+
val raw = editText.text?.toString().orEmpty()
|
|
223
|
+
val normalized = raw.replace(".", "")
|
|
224
|
+
.replace("×", "*")
|
|
225
|
+
.replace("÷", "/")
|
|
226
|
+
|
|
216
227
|
val pattern = "^\\s*(-?\\d+(\\.\\d+)?\\s*[-+*/]\\s*)*-?\\d+(\\.\\d+)?\\s*$"
|
|
217
|
-
|
|
218
|
-
if (regex.matches(text)) {
|
|
228
|
+
if (Regex(pattern).matches(normalized)) {
|
|
219
229
|
try {
|
|
220
|
-
val result = eval(
|
|
221
|
-
editText.setTextKeepState(result)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
230
|
+
val result = eval(normalized)?.toString() ?: return
|
|
231
|
+
editText.setTextKeepState(formatNumberGroups(result))
|
|
232
|
+
editText.setSelection(editText.text?.length ?: 0)
|
|
233
|
+
} catch (_: Exception) { /* ignore */ }
|
|
225
234
|
} else {
|
|
226
235
|
println("Invalid expression")
|
|
227
236
|
}
|
|
@@ -237,52 +246,132 @@ class CustomKeyboardView(
|
|
|
237
246
|
}
|
|
238
247
|
}
|
|
239
248
|
|
|
240
|
-
private fun emitKeyPress(key: String) {
|
|
241
|
-
val reactContext = context as
|
|
242
|
-
val
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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)
|
|
247
260
|
}
|
|
248
261
|
|
|
249
|
-
private fun emitCustomKey() {
|
|
250
|
-
val reactContext = context as
|
|
251
|
-
|
|
252
|
-
|
|
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)
|
|
253
270
|
}
|
|
254
271
|
|
|
255
272
|
fun setCustomKeyText(text: String) {
|
|
256
273
|
customKeyButton?.text = text
|
|
257
274
|
}
|
|
258
275
|
|
|
276
|
+
fun setMode(mode: String) {
|
|
277
|
+
keyboardMode = mode
|
|
278
|
+
renderUI()
|
|
279
|
+
}
|
|
280
|
+
|
|
259
281
|
fun setCustomKeyBackground(background: Int) {
|
|
260
282
|
customKeyButtonBackground = background
|
|
261
|
-
updateCustomKeyUI(background, customKeyButtonTextColor
|
|
283
|
+
updateCustomKeyUI(background, customKeyButtonTextColor)
|
|
262
284
|
}
|
|
263
285
|
|
|
264
286
|
fun setCustomKeyTextColor(textColor: Int) {
|
|
265
287
|
customKeyButtonTextColor = textColor
|
|
266
|
-
updateCustomKeyUI(customKeyButtonBackground, textColor
|
|
288
|
+
updateCustomKeyUI(customKeyButtonBackground, textColor)
|
|
267
289
|
}
|
|
268
290
|
|
|
269
291
|
|
|
270
|
-
fun setCustomKeyState(state:
|
|
292
|
+
fun setCustomKeyState(state: String) {
|
|
271
293
|
customKeyButtonState = state
|
|
272
|
-
customKeyButton?.isEnabled = state
|
|
273
|
-
updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor
|
|
294
|
+
customKeyButton?.isEnabled = state != "disable"
|
|
295
|
+
updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor)
|
|
274
296
|
}
|
|
275
297
|
|
|
276
|
-
private fun updateCustomKeyUI(background: Int, textColor: Int
|
|
277
|
-
val backgroundColor = if(state == 1) "#EBEBF2".toColorInt() else background
|
|
278
|
-
val textColor = if (state == 1) Color.WHITE else textColor
|
|
279
|
-
|
|
298
|
+
private fun updateCustomKeyUI(background: Int, textColor: Int){
|
|
280
299
|
customKeyButton?.background = GradientDrawable().apply {
|
|
281
300
|
shape = GradientDrawable.RECTANGLE
|
|
282
301
|
cornerRadius = 24f
|
|
283
|
-
setColor(
|
|
302
|
+
setColor(background)
|
|
284
303
|
}
|
|
285
304
|
customKeyButton?.setTextColor(textColor)
|
|
286
305
|
}
|
|
287
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
|
+
}
|
|
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
|
+
}
|
|
288
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
|
+
|