@momo-kits/calculator-keyboard 0.150.2-phuc.15 → 0.151.1-beta.2
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 +242 -108
- package/android/src/main/java/com/calculatorkeyboard/Event.kt +129 -0
- package/android/src/main/java/com/calculatorkeyboard/{RCTInputCalculator.kt → InputCalculatorViewManager.kt} +105 -33
- package/ios/CalculatorKeyboardView.h +32 -0
- package/ios/CalculatorKeyboardView.mm +274 -0
- package/ios/NativeInputCalculator.h +11 -0
- package/ios/NativeInputCalculator.mm +500 -0
- package/ios/Utils.h +10 -0
- package/ios/Utils.mm +25 -0
- package/package.json +21 -131
- package/react-native-calculator-keyboard.podspec +5 -4
- package/src/InputCalculatorNativeComponent.ts +71 -0
- package/src/index.tsx +93 -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
|
@@ -3,20 +3,36 @@ package com.calculatorkeyboard
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.graphics.Color
|
|
6
|
+
import android.graphics.Typeface
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.text.Editable
|
|
9
|
+
import android.text.TextWatcher
|
|
6
10
|
import android.view.KeyEvent
|
|
7
11
|
import android.view.inputmethod.InputMethodManager
|
|
8
12
|
import androidx.core.graphics.toColorInt
|
|
9
13
|
import androidx.core.view.ViewCompat
|
|
10
14
|
import androidx.core.view.WindowInsetsCompat
|
|
11
|
-
import com.
|
|
15
|
+
import com.calculatorkeyboard.CustomKeyboardView.Companion.calculateResult
|
|
16
|
+
import com.facebook.react.bridge.ReadableMap
|
|
12
17
|
import com.facebook.react.bridge.UiThreadUtil
|
|
18
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
13
19
|
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
20
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
14
21
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
22
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
15
23
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
24
|
+
import com.facebook.react.viewmanagers.NativeInputCalculatorManagerDelegate
|
|
25
|
+
import com.facebook.react.viewmanagers.NativeInputCalculatorManagerInterface
|
|
16
26
|
import com.facebook.react.views.textinput.ReactEditText
|
|
17
|
-
import com.facebook.react.views.textinput.ReactTextInputManager
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
@ReactModule(name = InputCalculatorViewManager.REACT_CLASS)
|
|
29
|
+
class InputCalculatorViewManager : SimpleViewManager<ReactEditText>(), NativeInputCalculatorManagerInterface<ReactEditText> {
|
|
30
|
+
private val delegate: NativeInputCalculatorManagerDelegate<ReactEditText, InputCalculatorViewManager> =
|
|
31
|
+
NativeInputCalculatorManagerDelegate(this)
|
|
32
|
+
|
|
33
|
+
override fun getDelegate(): ViewManagerDelegate<ReactEditText> = delegate
|
|
34
|
+
|
|
35
|
+
override fun getName() = REACT_CLASS
|
|
20
36
|
|
|
21
37
|
private var keyboardView: CustomKeyboardView? = null
|
|
22
38
|
private lateinit var editText: CalculatorEditText
|
|
@@ -27,15 +43,14 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
27
43
|
private var backListenerAttached = false
|
|
28
44
|
private var overlayShowing = false
|
|
29
45
|
|
|
30
|
-
override fun getName() = REACT_CLASS
|
|
31
46
|
|
|
32
47
|
companion object {
|
|
33
|
-
const val REACT_CLASS = "
|
|
48
|
+
const val REACT_CLASS = "NativeInputCalculator"
|
|
34
49
|
val calculatorHeight: Int = 240.dpToPx().toInt()
|
|
35
50
|
}
|
|
36
51
|
|
|
37
52
|
@ReactProp(name = "value")
|
|
38
|
-
fun setValue(view: ReactEditText, value: String?) {
|
|
53
|
+
override fun setValue(view: ReactEditText, value: String?) {
|
|
39
54
|
UiThreadUtil.runOnUiThread {
|
|
40
55
|
val e = view.editableText ?: run { view.setText(value ?: ""); return@runOnUiThread }
|
|
41
56
|
val newText = value ?: ""
|
|
@@ -45,32 +60,84 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
45
60
|
val atEnd = wasFocused && view.selectionStart == e.length && view.selectionEnd == e.length
|
|
46
61
|
e.replace(0, e.length, newText)
|
|
47
62
|
if (!wasFocused || atEnd) view.setSelection(newText.length)
|
|
63
|
+
keyboardView?.reformatAndKeepSelection(editText)
|
|
48
64
|
}
|
|
49
65
|
}
|
|
50
66
|
|
|
67
|
+
override fun setTextAttributes(view: ReactEditText?, value: ReadableMap?) {
|
|
68
|
+
val fontWeightStr = value?.getString("fontWeight")
|
|
69
|
+
val fontSize = value?.getDouble("fontSize")
|
|
70
|
+
val placeHolder = value?.getString("placeholder")
|
|
71
|
+
val placeHolderTextColor = value?.getString("placeholderTextColor")
|
|
72
|
+
|
|
73
|
+
fontWeightStr?.let { weightStr ->
|
|
74
|
+
val weight = when (weightStr) {
|
|
75
|
+
"100" -> 100
|
|
76
|
+
"200" -> 200
|
|
77
|
+
"300" -> 300
|
|
78
|
+
"400", "normal" -> 400
|
|
79
|
+
"500" -> 500
|
|
80
|
+
"600" -> 600
|
|
81
|
+
"700", "bold" -> 700
|
|
82
|
+
"800" -> 800
|
|
83
|
+
"900" -> 900
|
|
84
|
+
else -> 400
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
88
|
+
view?.typeface = Typeface.create(view.typeface, weight, false)
|
|
89
|
+
} else {
|
|
90
|
+
view?.typeface = if (weight >= 600) {
|
|
91
|
+
Typeface.create(view.typeface, Typeface.BOLD)
|
|
92
|
+
} else {
|
|
93
|
+
Typeface.create(view.typeface, Typeface.NORMAL)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
fontSize?.let {
|
|
99
|
+
view?.textSize = it.toFloat()
|
|
100
|
+
}
|
|
101
|
+
placeHolder?.let {
|
|
102
|
+
view?.setPlaceholder(placeHolder)
|
|
103
|
+
}
|
|
104
|
+
placeHolderTextColor?.let {
|
|
105
|
+
view?.setHintTextColor(it.toColorInt())
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@ReactProp(name = "mode")
|
|
111
|
+
override fun setMode(view: ReactEditText, mode: String?) {
|
|
112
|
+
keyboardView?.setMode(mode ?: "NumDefault")
|
|
113
|
+
}
|
|
114
|
+
|
|
51
115
|
@ReactProp(name = "customKeyText")
|
|
52
|
-
fun setCustomKeyText(view: ReactEditText, text: String?) {
|
|
53
|
-
keyboardView?.setCustomKeyText(text ?: "
|
|
116
|
+
override fun setCustomKeyText(view: ReactEditText, text: String?) {
|
|
117
|
+
keyboardView?.setCustomKeyText(text ?: "Tiếp")
|
|
54
118
|
}
|
|
55
119
|
|
|
56
120
|
@ReactProp(name = "customKeyBackground")
|
|
57
|
-
fun setCustomKeyBackground(view: ReactEditText, background: String?) {
|
|
121
|
+
override fun setCustomKeyBackground(view: ReactEditText, background: String?) {
|
|
58
122
|
keyboardView?.setCustomKeyBackground((background ?: "#d8d8d8").toColorInt())
|
|
59
123
|
}
|
|
60
124
|
|
|
61
125
|
@ReactProp(name = "customKeyTextColor")
|
|
62
|
-
fun setCustomKeyTextColor(view: ReactEditText, textColor: String?) {
|
|
126
|
+
override fun setCustomKeyTextColor(view: ReactEditText, textColor: String?) {
|
|
63
127
|
keyboardView?.setCustomKeyTextColor(textColor?.toColorInt() ?: Color.BLACK)
|
|
64
128
|
}
|
|
65
129
|
|
|
66
130
|
@ReactProp(name = "customKeyState")
|
|
67
|
-
fun setCustomKeyState(view: ReactEditText, state: String?) {
|
|
131
|
+
override fun setCustomKeyState(view: ReactEditText, state: String?) {
|
|
68
132
|
keyboardView?.setCustomKeyState(state ?: "default")
|
|
69
133
|
}
|
|
70
134
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
135
|
+
override fun focus(view: ReactEditText?) {
|
|
136
|
+
UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override fun blur(view: ReactEditText?) {
|
|
140
|
+
UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
|
|
74
141
|
}
|
|
75
142
|
|
|
76
143
|
@SuppressLint("ClickableViewAccessibility")
|
|
@@ -80,6 +147,8 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
80
147
|
editText = CalculatorEditText(context).apply {
|
|
81
148
|
showSoftInputOnFocus = false
|
|
82
149
|
isFocusableInTouchMode = true
|
|
150
|
+
isSingleLine = true
|
|
151
|
+
|
|
83
152
|
setOnTouchListener { v, event ->
|
|
84
153
|
if (event.action == android.view.MotionEvent.ACTION_DOWN) {
|
|
85
154
|
showSoftInputOnFocus = false
|
|
@@ -101,6 +170,21 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
101
170
|
}
|
|
102
171
|
false
|
|
103
172
|
}
|
|
173
|
+
addTextChangedListener(object : TextWatcher{
|
|
174
|
+
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
|
175
|
+
|
|
176
|
+
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
|
177
|
+
|
|
178
|
+
override fun afterTextChanged(s: Editable?) {
|
|
179
|
+
Event.emitOnChange(context, editText.id, s.toString())
|
|
180
|
+
Event.emitOnResult(context, editText.id, editText.calculateResult())
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
setOnFocusChangeListener { view, hasFocus ->
|
|
186
|
+
Event.emitOnBlurFocus(context, editText.id, hasFocus)
|
|
187
|
+
}
|
|
104
188
|
}
|
|
105
189
|
|
|
106
190
|
keyboardView = CustomKeyboardView(context, editText).apply {
|
|
@@ -155,7 +239,7 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
155
239
|
|
|
156
240
|
private fun disableSystemImeFor(v: ReactEditText) {
|
|
157
241
|
v.showSoftInputOnFocus = false
|
|
158
|
-
if (
|
|
242
|
+
if (Build.VERSION.SDK_INT >= 30) {
|
|
159
243
|
ViewCompat.getWindowInsetsController(v)?.hide(WindowInsetsCompat.Type.ime())
|
|
160
244
|
}
|
|
161
245
|
imm.hideSoftInputFromWindow(v.windowToken, 0)
|
|
@@ -165,33 +249,21 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
165
249
|
v.showSoftInputOnFocus = true
|
|
166
250
|
}
|
|
167
251
|
|
|
168
|
-
override fun getCommandsMap(): Map<String, Int> = mapOf("blur" to 1, "focus" to 2)
|
|
169
|
-
|
|
170
|
-
override fun receiveCommand(reactEditText: ReactEditText, commandId: Int, args: ReadableArray?) {
|
|
171
|
-
when (commandId) {
|
|
172
|
-
1 -> blur()
|
|
173
|
-
2 -> focus()
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
252
|
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
|
|
178
|
-
val base = super.getExportedCustomBubblingEventTypeConstants()
|
|
253
|
+
val base = super.getExportedCustomBubblingEventTypeConstants()?.toMutableMap() ?: mutableMapOf()
|
|
179
254
|
base["onKeyPress"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onKeyPress"))
|
|
255
|
+
base["onChange"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onChange"))
|
|
256
|
+
base["onResult"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onResult"))
|
|
180
257
|
return base
|
|
181
258
|
}
|
|
182
259
|
|
|
183
260
|
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
|
|
184
|
-
val base = super.getExportedCustomDirectEventTypeConstants()
|
|
261
|
+
val base = super.getExportedCustomDirectEventTypeConstants()?.toMutableMap() ?: mutableMapOf()
|
|
262
|
+
base["onBlur"] = mapOf("registrationName" to "onBlur")
|
|
263
|
+
base["onFocus"] = mapOf("registrationName" to "onFocus")
|
|
185
264
|
base["onCustomKeyEvent"] = mapOf("registrationName" to "onCustomKeyEvent")
|
|
186
265
|
return base
|
|
187
266
|
}
|
|
188
267
|
|
|
189
|
-
private fun focus() {
|
|
190
|
-
UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
private fun blur() {
|
|
194
|
-
UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
|
|
195
|
-
}
|
|
196
268
|
}
|
|
197
269
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
@protocol CalculatorKeyboardInput <NSObject>
|
|
6
|
+
|
|
7
|
+
- (void)keyDidPress:(NSString *)key;
|
|
8
|
+
- (void)clearText;
|
|
9
|
+
- (NSString *)getText;
|
|
10
|
+
- (void)onBackSpace;
|
|
11
|
+
- (NSString *)calculate;
|
|
12
|
+
- (void)calculateResult;
|
|
13
|
+
- (void)emitCustomKey;
|
|
14
|
+
- (void)emitKeyPress:(NSString *)key;
|
|
15
|
+
|
|
16
|
+
@end
|
|
17
|
+
|
|
18
|
+
@interface CalculatorKeyboardView : UIView
|
|
19
|
+
|
|
20
|
+
@property (nonatomic, weak, nullable) id<CalculatorKeyboardInput> input;
|
|
21
|
+
@property (nonatomic, strong, nullable) NSString *keyboardMode;
|
|
22
|
+
@property (nonatomic, strong, nullable) NSString *customKeyText;
|
|
23
|
+
@property (nonatomic, strong, nullable) NSString *customKeyBackground;
|
|
24
|
+
@property (nonatomic, strong, nullable) NSString *customKeyTextColor;
|
|
25
|
+
@property (nonatomic, strong, nullable) NSString *customKeyState;
|
|
26
|
+
|
|
27
|
+
- (void)setKeyboardColor:(UIColor *)color;
|
|
28
|
+
|
|
29
|
+
@end
|
|
30
|
+
|
|
31
|
+
NS_ASSUME_NONNULL_END
|
|
32
|
+
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
#import "CalculatorKeyboardView.h"
|
|
2
|
+
#import "Utils.h"
|
|
3
|
+
|
|
4
|
+
@interface CalculatorKeyboardView ()
|
|
5
|
+
@property (nonatomic, strong) NSArray<NSArray<NSString *> *> *numWithCTAKeys;
|
|
6
|
+
@property (nonatomic, strong) NSArray<NSArray<NSString *> *> *defaultKeys;
|
|
7
|
+
@property (nonatomic, strong) NSSet<NSString *> *specialKeys;
|
|
8
|
+
@property (nonatomic, weak) UIButton *customKeyButton;
|
|
9
|
+
@end
|
|
10
|
+
|
|
11
|
+
@implementation CalculatorKeyboardView {
|
|
12
|
+
CGFloat _separatorWidth;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
16
|
+
{
|
|
17
|
+
if (self = [super initWithFrame:frame]) {
|
|
18
|
+
_separatorWidth = 4.0;
|
|
19
|
+
|
|
20
|
+
_numWithCTAKeys = @[
|
|
21
|
+
@[@"1", @"2", @"3", @"÷", @"back"],
|
|
22
|
+
@[@"4", @"5", @"6", @"×", @"="],
|
|
23
|
+
@[@"7", @"8", @"9", @"-", @"Tiếp"],
|
|
24
|
+
@[@"000", @"0", @"+"]
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
_defaultKeys = @[
|
|
28
|
+
@[@"1", @"2", @"3", @"÷", @"AC"],
|
|
29
|
+
@[@"4", @"5", @"6", @"×", @"back"],
|
|
30
|
+
@[@"7", @"8", @"9", @"-", @"="],
|
|
31
|
+
@[@"000", @"0", @"+"]
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
_specialKeys = [NSSet setWithArray:@[@"=", @"-", @"×", @"÷", @"back", @"+", @"AC"]];
|
|
35
|
+
|
|
36
|
+
[self setup];
|
|
37
|
+
}
|
|
38
|
+
return self;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
- (void)setKeyboardMode:(NSString *)keyboardMode
|
|
42
|
+
{
|
|
43
|
+
if ([_keyboardMode isEqualToString:keyboardMode]) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
_keyboardMode = keyboardMode;
|
|
47
|
+
[self setup];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
- (void)setCustomKeyText:(NSString *)customKeyText
|
|
51
|
+
{
|
|
52
|
+
_customKeyText = customKeyText;
|
|
53
|
+
[self updateCustomKeyTitle];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
- (void)setCustomKeyBackground:(NSString *)customKeyBackground
|
|
57
|
+
{
|
|
58
|
+
_customKeyBackground = customKeyBackground;
|
|
59
|
+
[self updateCustomKeyBackground];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
- (void)setCustomKeyTextColor:(NSString *)customKeyTextColor
|
|
63
|
+
{
|
|
64
|
+
_customKeyTextColor = customKeyTextColor;
|
|
65
|
+
[self updateCustomKeyBackground];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
- (void)setCustomKeyState:(NSString *)customKeyState
|
|
69
|
+
{
|
|
70
|
+
_customKeyState = customKeyState;
|
|
71
|
+
[self updateCustomKeyBackground];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
- (void)setKeyboardColor:(UIColor *)color
|
|
75
|
+
{
|
|
76
|
+
[self setup];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
- (void)setup
|
|
80
|
+
{
|
|
81
|
+
// Remove all subviews
|
|
82
|
+
for (UIView *subview in self.subviews) {
|
|
83
|
+
[subview removeFromSuperview];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
self.backgroundColor = [Utils colorFromHex:@"#f2f2f6"];
|
|
87
|
+
|
|
88
|
+
CGFloat buttonWidth = (UIScreen.mainScreen.bounds.size.width - _separatorWidth * 2 - 4 * _separatorWidth) / 5;
|
|
89
|
+
CGFloat buttonHeight = (240 - _separatorWidth * 2 - 3 * _separatorWidth) / 4;
|
|
90
|
+
|
|
91
|
+
// Create content view
|
|
92
|
+
UIView *contentView = [[UIView alloc] init];
|
|
93
|
+
contentView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
94
|
+
[self addSubview:contentView];
|
|
95
|
+
|
|
96
|
+
// Set contentView constraints
|
|
97
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
98
|
+
[contentView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:_separatorWidth],
|
|
99
|
+
[contentView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-_separatorWidth],
|
|
100
|
+
[contentView.topAnchor constraintEqualToAnchor:self.topAnchor constant:_separatorWidth],
|
|
101
|
+
[contentView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-_separatorWidth]
|
|
102
|
+
]];
|
|
103
|
+
|
|
104
|
+
CGFloat yOffset = 0;
|
|
105
|
+
NSArray<NSArray<NSString *> *> *keys = [_keyboardMode isEqualToString:@"NumDefault"] ? _defaultKeys : _numWithCTAKeys;
|
|
106
|
+
|
|
107
|
+
for (NSInteger rowIndex = 0; rowIndex < keys.count; rowIndex++) {
|
|
108
|
+
NSArray<NSString *> *row = keys[rowIndex];
|
|
109
|
+
CGFloat xOffset = 0;
|
|
110
|
+
|
|
111
|
+
for (NSInteger colIndex = 0; colIndex < row.count; colIndex++) {
|
|
112
|
+
NSString *key = row[colIndex];
|
|
113
|
+
BOOL isMainKey = (colIndex == 4 && rowIndex == 2);
|
|
114
|
+
BOOL isMainCTAKey = isMainKey && [_keyboardMode isEqualToString:@"NumWithCTA"];
|
|
115
|
+
|
|
116
|
+
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
117
|
+
button.backgroundColor = UIColor.whiteColor;
|
|
118
|
+
button.layer.cornerRadius = 8;
|
|
119
|
+
|
|
120
|
+
NSString *title = isMainCTAKey ? (_customKeyText ?: key) : key;
|
|
121
|
+
[button setTitle:title forState:UIControlStateNormal];
|
|
122
|
+
[button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
|
|
123
|
+
button.titleLabel.font = [UIFont systemFontOfSize:isMainCTAKey ? 18 : 24 weight:UIFontWeightMedium];
|
|
124
|
+
button.accessibilityIdentifier = key;
|
|
125
|
+
button.tag = isMainCTAKey ? 1 : 0;
|
|
126
|
+
|
|
127
|
+
CGRect buttonFrame = CGRectMake(xOffset, yOffset, buttonWidth, buttonHeight);
|
|
128
|
+
if (isMainKey) {
|
|
129
|
+
buttonFrame.size.height = buttonHeight * 2 + _separatorWidth;
|
|
130
|
+
}
|
|
131
|
+
if ([key isEqualToString:@"000"]) {
|
|
132
|
+
buttonFrame.size.width = buttonWidth * 2 + _separatorWidth;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
button.frame = buttonFrame;
|
|
136
|
+
|
|
137
|
+
if ([key isEqualToString:@"back"]) {
|
|
138
|
+
[button setTitle:@"" forState:UIControlStateNormal];
|
|
139
|
+
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithWeight:UIImageSymbolWeightBold];
|
|
140
|
+
UIImage *image = [UIImage systemImageNamed:@"delete.backward" withConfiguration:config];
|
|
141
|
+
[button setImage:image forState:UIControlStateNormal];
|
|
142
|
+
button.tintColor = UIColor.blackColor;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if ([_specialKeys containsObject:key] || isMainKey) {
|
|
146
|
+
[button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
|
|
147
|
+
button.backgroundColor = [Utils colorFromHex:@"#d8d8d8"];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (isMainKey) {
|
|
151
|
+
self.customKeyButton = button;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
[button addTarget:self action:@selector(keyPressed:) forControlEvents:UIControlEventTouchUpInside];
|
|
155
|
+
[contentView addSubview:button];
|
|
156
|
+
|
|
157
|
+
xOffset += buttonFrame.size.width + _separatorWidth;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
yOffset += buttonHeight + _separatorWidth;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
- (void)updateCustomKeyTitle
|
|
165
|
+
{
|
|
166
|
+
if (!self.customKeyButton || !_customKeyText) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
[self.customKeyButton setTitle:_customKeyText forState:UIControlStateNormal];
|
|
170
|
+
[self.customKeyButton setImage:nil forState:UIControlStateNormal];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
- (void)updateCustomKeyBackground
|
|
174
|
+
{
|
|
175
|
+
if (!self.customKeyButton || !_keyboardMode || !_customKeyBackground || !_customKeyTextColor || !_customKeyState) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if ([_keyboardMode isEqualToString:@"numWithCTA"]) {
|
|
180
|
+
self.customKeyButton.enabled = ![_customKeyState isEqualToString:@"disable"];
|
|
181
|
+
} else {
|
|
182
|
+
self.customKeyButton.enabled = YES;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
self.customKeyButton.backgroundColor = [Utils colorFromHex:_customKeyBackground];
|
|
186
|
+
[self.customKeyButton setTitleColor:[Utils colorFromHex:_customKeyTextColor] forState:UIControlStateNormal];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
- (void)keyPressed:(UIButton *)sender
|
|
190
|
+
{
|
|
191
|
+
NSString *key = sender.accessibilityIdentifier;
|
|
192
|
+
if (!key) return;
|
|
193
|
+
|
|
194
|
+
if (sender.tag == 1) {
|
|
195
|
+
[self.input emitCustomKey];
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
[self.input emitKeyPress:key];
|
|
200
|
+
|
|
201
|
+
NSString *text = self.input.getText ?: @"";
|
|
202
|
+
BOOL isEmpty = (text.length == 0);
|
|
203
|
+
BOOL isJustZero = [text isEqualToString:@"0"];
|
|
204
|
+
|
|
205
|
+
BOOL endsWithPlus = [text hasSuffix:@" + "];
|
|
206
|
+
BOOL endsWithMinus = [text hasSuffix:@" - "];
|
|
207
|
+
BOOL endsWithMul = [text hasSuffix:@" × "];
|
|
208
|
+
BOOL endsWithDiv = [text hasSuffix:@" ÷ "];
|
|
209
|
+
BOOL endsWithOperator = (endsWithPlus || endsWithMinus || endsWithMul || endsWithDiv);
|
|
210
|
+
|
|
211
|
+
BOOL endsWithSingleZeroAfterOp = [text hasSuffix:@" 0"];
|
|
212
|
+
|
|
213
|
+
BOOL (^isOpKey)(NSString *) = ^BOOL(NSString *k) {
|
|
214
|
+
return [k isEqualToString:@"+"] || [k isEqualToString:@"-"] ||
|
|
215
|
+
[k isEqualToString:@"×"] || [k isEqualToString:@"÷"];
|
|
216
|
+
};
|
|
217
|
+
void (^insert)(NSString *) = ^(NSString *s) { [self.input keyDidPress:s]; };
|
|
218
|
+
void (^replaceTrailingZeroWith)(NSString *) = ^(NSString *s) {
|
|
219
|
+
[self.input onBackSpace];
|
|
220
|
+
[self.input keyDidPress:s];
|
|
221
|
+
};
|
|
222
|
+
void (^replaceAllWith)(NSString *) = ^(NSString *s) {
|
|
223
|
+
[self.input clearText];
|
|
224
|
+
[self.input keyDidPress:s];
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
if ([key isEqualToString:@"AC"]) {
|
|
228
|
+
[self.input clearText];
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if ([key isEqualToString:@"back"]) {
|
|
233
|
+
[self.input onBackSpace];
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if ([key isEqualToString:@"="]) {
|
|
238
|
+
[self.input calculateResult];
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (isOpKey(key)) {
|
|
243
|
+
if (!isEmpty) {
|
|
244
|
+
insert([NSString stringWithFormat:@" %@ ", key]);
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if ([key isEqualToString:@"0"] || [key isEqualToString:@"000"]) {
|
|
250
|
+
if (isEmpty) return;
|
|
251
|
+
|
|
252
|
+
if ([key isEqualToString:@"000"] && endsWithOperator) {
|
|
253
|
+
insert(@"0");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (endsWithSingleZeroAfterOp || isJustZero) return;
|
|
258
|
+
|
|
259
|
+
insert(key);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (isJustZero) {
|
|
264
|
+
replaceAllWith(key);
|
|
265
|
+
} else if (endsWithSingleZeroAfterOp) {
|
|
266
|
+
replaceTrailingZeroWith(key);
|
|
267
|
+
} else {
|
|
268
|
+
insert(key);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@end
|
|
274
|
+
|