@momo-kits/calculator-keyboard 0.150.2-beta.2 → 0.150.2-beta.20-sp.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 +117 -46
- package/android/src/main/java/com/calculatorkeyboard/KeyboardOverplayHost.kt +232 -0
- package/android/src/main/java/com/calculatorkeyboard/RCTInputCalculator.kt +115 -104
- package/ios/CalculatorKeyboardView.h +30 -0
- package/ios/CalculatorKeyboardView.mm +231 -0
- package/ios/NativeInputCalculator.h +11 -0
- package/ios/NativeInputCalculator.mm +200 -0
- package/package.json +75 -183
- package/react-native-calculator-keyboard.podspec +4 -3
- package/src/NativeInputCalculatorNativeComponent.ts +56 -0
- package/src/index.tsx +71 -35
- package/ios/CalculatorKeyboardView.swift +0 -115
- package/ios/InputCalculator-Bridging-Header.h +0 -23
- package/ios/InputCalculator.m +0 -79
- package/ios/InputCalculator.swift +0 -138
- package/ios/extension.swift +0 -23
- package/lib/commonjs/index.js +0 -48
- package/lib/commonjs/index.js.map +0 -1
- package/lib/module/index.js +0 -44
- 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 -13
- 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 -13
- package/lib/typescript/module/src/index.d.ts.map +0 -1
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
package com.calculatorkeyboard
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
-
import android.
|
|
5
|
-
import android.graphics.
|
|
6
|
-
import android.graphics.drawable.ColorDrawable
|
|
7
|
-
import android.view.Gravity
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.graphics.Color
|
|
8
6
|
import android.view.KeyEvent
|
|
9
|
-
import android.view.
|
|
10
|
-
import android.view.WindowInsets
|
|
11
|
-
import android.view.WindowManager
|
|
12
|
-
import android.widget.PopupWindow
|
|
13
|
-
import androidx.constraintlayout.widget.ConstraintLayout
|
|
7
|
+
import android.view.inputmethod.InputMethodManager
|
|
14
8
|
import androidx.core.graphics.toColorInt
|
|
15
|
-
import
|
|
9
|
+
import androidx.core.view.ViewCompat
|
|
10
|
+
import androidx.core.view.WindowInsetsCompat
|
|
16
11
|
import com.facebook.react.bridge.UiThreadUtil
|
|
12
|
+
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
17
13
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
18
|
-
import com.facebook.react.uimanager.annotations.ReactProp
|
|
19
14
|
import com.facebook.react.views.textinput.ReactEditText
|
|
20
15
|
import com.facebook.react.views.textinput.ReactTextInputManager
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import
|
|
24
|
-
import
|
|
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
|
|
25
20
|
|
|
26
|
-
|
|
21
|
+
// Fabric-only manager with codegen name `NativeInputCalculator`
|
|
22
|
+
class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorManagerInterface<ReactEditText> {
|
|
27
23
|
|
|
28
|
-
private
|
|
29
|
-
private var calculatorHeight: Int = 290.dpToPx().toInt()
|
|
30
|
-
private var popup: PopupWindow? = null
|
|
31
|
-
private val animationDuration = 250L
|
|
24
|
+
private val mDelegate: ViewManagerDelegate<ReactEditText> = NativeInputCalculatorManagerDelegate(this)
|
|
32
25
|
|
|
26
|
+
private var keyboardView: CustomKeyboardView? = null
|
|
33
27
|
private lateinit var editText: CalculatorEditText
|
|
28
|
+
private lateinit var imm: InputMethodManager
|
|
29
|
+
|
|
30
|
+
private val overlayHost = KeyboardOverlayHost()
|
|
31
|
+
|
|
32
|
+
private var backListenerAttached = false
|
|
33
|
+
private var overlayShowing = false
|
|
34
34
|
|
|
35
35
|
override fun getName() = REACT_CLASS
|
|
36
36
|
|
|
37
37
|
companion object {
|
|
38
|
-
const val REACT_CLASS = "
|
|
38
|
+
const val REACT_CLASS = "NativeInputCalculator"
|
|
39
|
+
val calculatorHeight: Int = 240.dpToPx().toInt()
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
fun setValue(view: ReactEditText, value: String?) {
|
|
42
|
+
override fun setValue(view: ReactEditText, @Nullable value: String?) {
|
|
43
43
|
UiThreadUtil.runOnUiThread {
|
|
44
44
|
val e = view.editableText ?: run { view.setText(value ?: ""); return@runOnUiThread }
|
|
45
45
|
val newText = value ?: ""
|
|
@@ -47,24 +47,63 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
47
47
|
|
|
48
48
|
val wasFocused = view.hasFocus()
|
|
49
49
|
val atEnd = wasFocused && view.selectionStart == e.length && view.selectionEnd == e.length
|
|
50
|
-
|
|
51
50
|
e.replace(0, e.length, newText)
|
|
52
|
-
|
|
53
|
-
if (!wasFocused || atEnd) {
|
|
54
|
-
view.setSelection(newText.length)
|
|
55
|
-
}
|
|
51
|
+
if (!wasFocused || atEnd) view.setSelection(newText.length)
|
|
56
52
|
}
|
|
57
53
|
}
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
override fun setMode(view: ReactEditText, @Nullable mode: String?) {
|
|
56
|
+
keyboardView?.setMode(mode ?: "NumDefault")
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override fun setCustomKeyText(view: ReactEditText, @Nullable text: String?) {
|
|
60
|
+
keyboardView?.setCustomKeyText(text ?: "Tiếp")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
override fun setCustomKeyBackground(view: ReactEditText, @Nullable background: String?) {
|
|
64
|
+
keyboardView?.setCustomKeyBackground((background ?: "#d8d8d8").toColorInt())
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
override fun setCustomKeyTextColor(view: ReactEditText, @Nullable textColor: String?) {
|
|
68
|
+
keyboardView?.setCustomKeyTextColor(textColor?.toColorInt() ?: Color.BLACK)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override fun setCustomKeyState(view: ReactEditText, @Nullable state: String?) {
|
|
72
|
+
keyboardView?.setCustomKeyState(state ?: "default")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override fun setKeyboardColor(view: ReactEditText, @Nullable color: Int?) {
|
|
76
|
+
color?.let { keyboardView?.updateButtonColors(it) }
|
|
62
77
|
}
|
|
63
78
|
|
|
64
79
|
@SuppressLint("ClickableViewAccessibility")
|
|
65
80
|
override fun createViewInstance(context: ThemedReactContext): ReactEditText {
|
|
81
|
+
imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
82
|
+
|
|
66
83
|
editText = CalculatorEditText(context).apply {
|
|
67
84
|
showSoftInputOnFocus = false
|
|
85
|
+
isFocusableInTouchMode = true
|
|
86
|
+
setOnTouchListener { v, event ->
|
|
87
|
+
if (event.action == android.view.MotionEvent.ACTION_DOWN) {
|
|
88
|
+
showSoftInputOnFocus = false
|
|
89
|
+
ViewCompat.getWindowInsetsController(this)?.hide(WindowInsetsCompat.Type.ime())
|
|
90
|
+
imm.hideSoftInputFromWindow(windowToken, 0)
|
|
91
|
+
|
|
92
|
+
if (!isFocused) requestFocus()
|
|
93
|
+
|
|
94
|
+
val kb = keyboardView
|
|
95
|
+
if (kb != null && !overlayShowing) {
|
|
96
|
+
overlayHost.show(
|
|
97
|
+
anchorView = this,
|
|
98
|
+
keyboardView = kb,
|
|
99
|
+
heightPx = calculatorHeight
|
|
100
|
+
)
|
|
101
|
+
overlayShowing = true
|
|
102
|
+
}
|
|
103
|
+
return@setOnTouchListener true
|
|
104
|
+
}
|
|
105
|
+
false
|
|
106
|
+
}
|
|
68
107
|
}
|
|
69
108
|
|
|
70
109
|
keyboardView = CustomKeyboardView(context, editText).apply {
|
|
@@ -72,19 +111,34 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
72
111
|
elevation = 24f
|
|
73
112
|
}
|
|
74
113
|
|
|
114
|
+
if (!backListenerAttached) {
|
|
115
|
+
editText.setOnKeyListener { v, keyCode, event ->
|
|
116
|
+
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP && v.hasFocus()) {
|
|
117
|
+
v.clearFocus()
|
|
118
|
+
true
|
|
119
|
+
} else false
|
|
120
|
+
}
|
|
121
|
+
backListenerAttached = true
|
|
122
|
+
}
|
|
123
|
+
|
|
75
124
|
editText.onFocusListener = object : CalculatorEditText.OnFocusChangeListener {
|
|
76
125
|
override fun onFocusChange(view: CalculatorEditText, hasFocus: Boolean) {
|
|
77
126
|
UiThreadUtil.runOnUiThread {
|
|
78
127
|
if (hasFocus) {
|
|
79
|
-
|
|
128
|
+
disableSystemImeFor(view)
|
|
129
|
+
if (!overlayShowing) {
|
|
130
|
+
val kb = keyboardView ?: return@runOnUiThread
|
|
131
|
+
overlayHost.show(
|
|
132
|
+
anchorView = view,
|
|
133
|
+
keyboardView = kb,
|
|
134
|
+
heightPx = calculatorHeight
|
|
135
|
+
)
|
|
136
|
+
overlayShowing = true
|
|
137
|
+
}
|
|
80
138
|
} else {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (keyCode == KeyEvent.KEYCODE_BACK && hasFocus) {
|
|
85
|
-
v.clearFocus()
|
|
86
|
-
true
|
|
87
|
-
} else false
|
|
139
|
+
overlayHost.hide()
|
|
140
|
+
overlayShowing = false
|
|
141
|
+
enableSystemImeFor(view)
|
|
88
142
|
}
|
|
89
143
|
}
|
|
90
144
|
}
|
|
@@ -93,87 +147,44 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
93
147
|
return editText
|
|
94
148
|
}
|
|
95
149
|
|
|
96
|
-
override fun getCommandsMap(): Map<String, Int> {
|
|
97
|
-
return mapOf(
|
|
98
|
-
"blur" to 1,
|
|
99
|
-
"focus" to 2
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
150
|
|
|
103
|
-
override fun
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
151
|
+
override fun onDropViewInstance(view: ReactEditText) {
|
|
152
|
+
super.onDropViewInstance(view)
|
|
153
|
+
overlayHost.hide()
|
|
154
|
+
overlayHost.detach()
|
|
155
|
+
overlayShowing = false
|
|
156
|
+
|
|
108
157
|
}
|
|
109
158
|
|
|
110
|
-
private fun
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
popup = PopupWindow(
|
|
115
|
-
content,
|
|
116
|
-
WindowManager.LayoutParams.MATCH_PARENT,
|
|
117
|
-
calculatorHeight + bottomInsetFrom(editText.rootView),
|
|
118
|
-
false
|
|
119
|
-
).apply {
|
|
120
|
-
setBackgroundDrawable(android.graphics.Color.TRANSPARENT.toDrawable())
|
|
121
|
-
isOutsideTouchable = false
|
|
122
|
-
isClippingEnabled = false
|
|
123
|
-
softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
|
|
124
|
-
inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
|
|
159
|
+
private fun disableSystemImeFor(v: ReactEditText) {
|
|
160
|
+
v.showSoftInputOnFocus = false
|
|
161
|
+
if (android.os.Build.VERSION.SDK_INT >= 30) {
|
|
162
|
+
ViewCompat.getWindowInsetsController(v)?.hide(WindowInsetsCompat.Type.ime())
|
|
125
163
|
}
|
|
164
|
+
imm.hideSoftInputFromWindow(v.windowToken, 0)
|
|
126
165
|
}
|
|
127
166
|
|
|
128
|
-
private fun
|
|
129
|
-
|
|
130
|
-
val mask = WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.displayCutout()
|
|
131
|
-
return insets.getInsets(mask).bottom
|
|
167
|
+
private fun enableSystemImeFor(v: ReactEditText) {
|
|
168
|
+
v.showSoftInputOnFocus = true
|
|
132
169
|
}
|
|
133
170
|
|
|
134
|
-
|
|
135
|
-
ensurePopup()
|
|
136
|
-
val p = popup ?: return
|
|
137
|
-
if (p.isShowing) return
|
|
138
|
-
|
|
139
|
-
val root = keyboardView ?: return
|
|
140
|
-
|
|
141
|
-
root.translationY = calculatorHeight.toFloat()
|
|
142
|
-
p.showAtLocation(anchor.rootView, Gravity.BOTTOM or Gravity.START, 0, 0)
|
|
171
|
+
override fun getDelegate(): ViewManagerDelegate<ReactEditText> = mDelegate
|
|
143
172
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
?.setDuration(animationDuration)
|
|
147
|
-
?.start()
|
|
173
|
+
override fun focus(view: ReactEditText) {
|
|
174
|
+
UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
|
|
148
175
|
}
|
|
149
176
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (!p.isShowing) return
|
|
153
|
-
val root = keyboardView ?: return
|
|
154
|
-
|
|
155
|
-
root.animate()
|
|
156
|
-
.translationY(calculatorHeight.toFloat())
|
|
157
|
-
.setDuration(animationDuration)
|
|
158
|
-
.withEndAction {
|
|
159
|
-
try {
|
|
160
|
-
if (p.isShowing) p.dismiss()
|
|
161
|
-
} catch (_: Throwable) { }
|
|
162
|
-
}
|
|
163
|
-
.start()
|
|
164
|
-
|
|
165
|
-
popup = null
|
|
177
|
+
override fun blur(view: ReactEditText) {
|
|
178
|
+
UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
|
|
166
179
|
}
|
|
167
180
|
|
|
181
|
+
// Events are emitted from CustomKeyboardView using RCTEventEmitter.
|
|
182
|
+
|
|
168
183
|
private fun focus() {
|
|
169
|
-
UiThreadUtil.runOnUiThread {
|
|
170
|
-
if (!editText.isFocused) editText.requestFocus()
|
|
171
|
-
}
|
|
184
|
+
UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
|
|
172
185
|
}
|
|
173
186
|
|
|
174
187
|
private fun blur() {
|
|
175
|
-
UiThreadUtil.runOnUiThread {
|
|
176
|
-
if (editText.isFocused) editText.clearFocus()
|
|
177
|
-
}
|
|
188
|
+
UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
|
|
178
189
|
}
|
|
179
190
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
- (void)onBackSpace;
|
|
10
|
+
- (void)calculateResult;
|
|
11
|
+
- (void)emitCustomKey;
|
|
12
|
+
- (void)emitKeyPress:(NSString *)key;
|
|
13
|
+
|
|
14
|
+
@end
|
|
15
|
+
|
|
16
|
+
@interface CalculatorKeyboardView : UIView
|
|
17
|
+
|
|
18
|
+
@property (nonatomic, weak, nullable) id<CalculatorKeyboardInput> input;
|
|
19
|
+
@property (nonatomic, strong, nullable) NSString *keyboardMode;
|
|
20
|
+
@property (nonatomic, strong, nullable) NSString *customKeyText;
|
|
21
|
+
@property (nonatomic, strong, nullable) NSString *customKeyBackground;
|
|
22
|
+
@property (nonatomic, strong, nullable) NSString *customKeyTextColor;
|
|
23
|
+
@property (nonatomic, strong, nullable) NSString *customKeyState;
|
|
24
|
+
|
|
25
|
+
- (void)setKeyboardColor:(UIColor *)color;
|
|
26
|
+
|
|
27
|
+
@end
|
|
28
|
+
|
|
29
|
+
NS_ASSUME_NONNULL_END
|
|
30
|
+
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#import "CalculatorKeyboardView.h"
|
|
2
|
+
|
|
3
|
+
@interface CalculatorKeyboardView ()
|
|
4
|
+
@property (nonatomic, strong) NSArray<NSArray<NSString *> *> *numWithCTAKeys;
|
|
5
|
+
@property (nonatomic, strong) NSArray<NSArray<NSString *> *> *defaultKeys;
|
|
6
|
+
@property (nonatomic, strong) NSSet<NSString *> *specialKeys;
|
|
7
|
+
@property (nonatomic, weak) UIButton *customKeyButton;
|
|
8
|
+
@end
|
|
9
|
+
|
|
10
|
+
@implementation CalculatorKeyboardView {
|
|
11
|
+
CGFloat _separatorWidth;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
15
|
+
{
|
|
16
|
+
if (self = [super initWithFrame:frame]) {
|
|
17
|
+
_separatorWidth = 4.0;
|
|
18
|
+
|
|
19
|
+
_numWithCTAKeys = @[
|
|
20
|
+
@[@"1", @"2", @"3", @"÷", @"back"],
|
|
21
|
+
@[@"4", @"5", @"6", @"×", @"="],
|
|
22
|
+
@[@"7", @"8", @"9", @"-", @"Tiếp"],
|
|
23
|
+
@[@"000", @"0", @"+"]
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
_defaultKeys = @[
|
|
27
|
+
@[@"1", @"2", @"3", @"÷", @"AC"],
|
|
28
|
+
@[@"4", @"5", @"6", @"×", @"back"],
|
|
29
|
+
@[@"7", @"8", @"9", @"-", @"="],
|
|
30
|
+
@[@"000", @"0", @"+"]
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
_specialKeys = [NSSet setWithArray:@[@"=", @"-", @"×", @"÷", @"back", @"+", @"AC"]];
|
|
34
|
+
|
|
35
|
+
[self setup];
|
|
36
|
+
}
|
|
37
|
+
return self;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
- (void)setKeyboardMode:(NSString *)keyboardMode
|
|
41
|
+
{
|
|
42
|
+
if ([_keyboardMode isEqualToString:keyboardMode]) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
_keyboardMode = keyboardMode;
|
|
46
|
+
[self setup];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
- (void)setCustomKeyText:(NSString *)customKeyText
|
|
50
|
+
{
|
|
51
|
+
_customKeyText = customKeyText;
|
|
52
|
+
[self updateCustomKeyTitle];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
- (void)setCustomKeyBackground:(NSString *)customKeyBackground
|
|
56
|
+
{
|
|
57
|
+
_customKeyBackground = customKeyBackground;
|
|
58
|
+
[self updateCustomKeyBackground];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
- (void)setCustomKeyTextColor:(NSString *)customKeyTextColor
|
|
62
|
+
{
|
|
63
|
+
_customKeyTextColor = customKeyTextColor;
|
|
64
|
+
[self updateCustomKeyBackground];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (void)setCustomKeyState:(NSString *)customKeyState
|
|
68
|
+
{
|
|
69
|
+
_customKeyState = customKeyState;
|
|
70
|
+
[self updateCustomKeyBackground];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
- (void)setKeyboardColor:(UIColor *)color
|
|
74
|
+
{
|
|
75
|
+
[self setup];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
- (void)setup
|
|
79
|
+
{
|
|
80
|
+
// Remove all subviews
|
|
81
|
+
for (UIView *subview in self.subviews) {
|
|
82
|
+
[subview removeFromSuperview];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
self.backgroundColor = [self colorFromHex:@"#f2f2f6"];
|
|
86
|
+
|
|
87
|
+
CGFloat buttonWidth = (UIScreen.mainScreen.bounds.size.width - _separatorWidth * 2 - 4 * _separatorWidth) / 5;
|
|
88
|
+
CGFloat buttonHeight = (240 - _separatorWidth * 2 - 3 * _separatorWidth) / 4;
|
|
89
|
+
|
|
90
|
+
// Create content view
|
|
91
|
+
UIView *contentView = [[UIView alloc] init];
|
|
92
|
+
contentView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
93
|
+
[self addSubview:contentView];
|
|
94
|
+
|
|
95
|
+
// Set contentView constraints
|
|
96
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
97
|
+
[contentView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:_separatorWidth],
|
|
98
|
+
[contentView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-_separatorWidth],
|
|
99
|
+
[contentView.topAnchor constraintEqualToAnchor:self.topAnchor constant:_separatorWidth],
|
|
100
|
+
[contentView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-_separatorWidth]
|
|
101
|
+
]];
|
|
102
|
+
|
|
103
|
+
CGFloat yOffset = 0;
|
|
104
|
+
NSArray<NSArray<NSString *> *> *keys = [_keyboardMode isEqualToString:@"NumDefault"] ? _defaultKeys : _numWithCTAKeys;
|
|
105
|
+
|
|
106
|
+
for (NSInteger rowIndex = 0; rowIndex < keys.count; rowIndex++) {
|
|
107
|
+
NSArray<NSString *> *row = keys[rowIndex];
|
|
108
|
+
CGFloat xOffset = 0;
|
|
109
|
+
|
|
110
|
+
for (NSInteger colIndex = 0; colIndex < row.count; colIndex++) {
|
|
111
|
+
NSString *key = row[colIndex];
|
|
112
|
+
BOOL isMainKey = (colIndex == 4 && rowIndex == 2);
|
|
113
|
+
BOOL isMainCTAKey = isMainKey && [_keyboardMode isEqualToString:@"NumWithCTA"];
|
|
114
|
+
|
|
115
|
+
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
116
|
+
button.backgroundColor = UIColor.whiteColor;
|
|
117
|
+
button.layer.cornerRadius = 8;
|
|
118
|
+
|
|
119
|
+
NSString *title = isMainCTAKey ? (_customKeyText ?: key) : key;
|
|
120
|
+
[button setTitle:title forState:UIControlStateNormal];
|
|
121
|
+
[button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
|
|
122
|
+
button.titleLabel.font = [UIFont systemFontOfSize:isMainCTAKey ? 18 : 24 weight:UIFontWeightMedium];
|
|
123
|
+
button.accessibilityIdentifier = key;
|
|
124
|
+
button.tag = isMainCTAKey ? 1 : 0;
|
|
125
|
+
|
|
126
|
+
CGRect buttonFrame = CGRectMake(xOffset, yOffset, buttonWidth, buttonHeight);
|
|
127
|
+
if (isMainKey) {
|
|
128
|
+
buttonFrame.size.height = buttonHeight * 2 + _separatorWidth;
|
|
129
|
+
}
|
|
130
|
+
if ([key isEqualToString:@"000"]) {
|
|
131
|
+
buttonFrame.size.width = buttonWidth * 2 + _separatorWidth;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
button.frame = buttonFrame;
|
|
135
|
+
|
|
136
|
+
if ([key isEqualToString:@"back"]) {
|
|
137
|
+
[button setTitle:@"" forState:UIControlStateNormal];
|
|
138
|
+
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithWeight:UIImageSymbolWeightBold];
|
|
139
|
+
UIImage *image = [UIImage systemImageNamed:@"delete.backward" withConfiguration:config];
|
|
140
|
+
[button setImage:image forState:UIControlStateNormal];
|
|
141
|
+
button.tintColor = UIColor.blackColor;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if ([_specialKeys containsObject:key] || isMainKey) {
|
|
145
|
+
[button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
|
|
146
|
+
button.backgroundColor = [self colorFromHex:@"#d8d8d8"];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (isMainKey) {
|
|
150
|
+
self.customKeyButton = button;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
[button addTarget:self action:@selector(keyPressed:) forControlEvents:UIControlEventTouchUpInside];
|
|
154
|
+
[contentView addSubview:button];
|
|
155
|
+
|
|
156
|
+
xOffset += buttonFrame.size.width + _separatorWidth;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
yOffset += buttonHeight + _separatorWidth;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
- (void)updateCustomKeyTitle
|
|
164
|
+
{
|
|
165
|
+
if (!self.customKeyButton || !_customKeyText) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
[self.customKeyButton setTitle:_customKeyText forState:UIControlStateNormal];
|
|
169
|
+
[self.customKeyButton setImage:nil forState:UIControlStateNormal];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
- (void)updateCustomKeyBackground
|
|
173
|
+
{
|
|
174
|
+
if (!self.customKeyButton || !_keyboardMode || !_customKeyBackground || !_customKeyTextColor || !_customKeyState) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if ([_keyboardMode isEqualToString:@"numWithCTA"]) {
|
|
179
|
+
self.customKeyButton.enabled = ![_customKeyState isEqualToString:@"disable"];
|
|
180
|
+
} else {
|
|
181
|
+
self.customKeyButton.enabled = YES;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
self.customKeyButton.backgroundColor = [self colorFromHex:_customKeyBackground];
|
|
185
|
+
[self.customKeyButton setTitleColor:[self colorFromHex:_customKeyTextColor] forState:UIControlStateNormal];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
- (void)keyPressed:(UIButton *)sender
|
|
189
|
+
{
|
|
190
|
+
NSString *key = sender.accessibilityIdentifier;
|
|
191
|
+
if (!key) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
BOOL isCustomKeyCTA = (sender.tag == 1);
|
|
196
|
+
if (isCustomKeyCTA) {
|
|
197
|
+
[self.input emitCustomKey];
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
[self.input emitKeyPress:key];
|
|
202
|
+
|
|
203
|
+
if ([key isEqualToString:@"AC"]) {
|
|
204
|
+
[self.input clearText];
|
|
205
|
+
} else if ([key isEqualToString:@"back"]) {
|
|
206
|
+
[self.input onBackSpace];
|
|
207
|
+
} else if ([key isEqualToString:@"="]) {
|
|
208
|
+
[self.input calculateResult];
|
|
209
|
+
} else if ([key isEqualToString:@"+"] || [key isEqualToString:@"-"] ||
|
|
210
|
+
[key isEqualToString:@"÷"] || [key isEqualToString:@"×"]) {
|
|
211
|
+
[self.input keyDidPress:[NSString stringWithFormat:@" %@ ", key]];
|
|
212
|
+
} else {
|
|
213
|
+
[self.input keyDidPress:key];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
- (UIColor *)colorFromHex:(NSString *)hexString
|
|
218
|
+
{
|
|
219
|
+
unsigned rgbValue = 0;
|
|
220
|
+
NSString *cleanHex = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
|
|
221
|
+
NSScanner *scanner = [NSScanner scannerWithString:cleanHex];
|
|
222
|
+
[scanner scanHexInt:&rgbValue];
|
|
223
|
+
|
|
224
|
+
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0
|
|
225
|
+
green:((rgbValue & 0x00FF00) >> 8) / 255.0
|
|
226
|
+
blue:(rgbValue & 0x0000FF) / 255.0
|
|
227
|
+
alpha:1.0];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@end
|
|
231
|
+
|