@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.
@@ -3,20 +3,43 @@ 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.provider.Settings.Global.putString
9
+ import android.text.Editable
10
+ import android.text.TextWatcher
6
11
  import android.view.KeyEvent
7
12
  import android.view.inputmethod.InputMethodManager
8
13
  import androidx.core.graphics.toColorInt
9
14
  import androidx.core.view.ViewCompat
10
15
  import androidx.core.view.WindowInsetsCompat
16
+ import androidx.core.widget.addTextChangedListener
17
+ import com.facebook.react.bridge.Arguments
18
+ import com.facebook.react.bridge.ReactContext
11
19
  import com.facebook.react.bridge.ReadableArray
20
+ import com.facebook.react.bridge.ReadableMap
12
21
  import com.facebook.react.bridge.UiThreadUtil
22
+ import com.facebook.react.module.annotations.ReactModule
13
23
  import com.facebook.react.uimanager.PixelUtil.dpToPx
24
+ import com.facebook.react.uimanager.SimpleViewManager
14
25
  import com.facebook.react.uimanager.ThemedReactContext
26
+ import com.facebook.react.uimanager.UIManagerHelper
27
+ import com.facebook.react.uimanager.ViewManagerDelegate
15
28
  import com.facebook.react.uimanager.annotations.ReactProp
29
+ import com.facebook.react.uimanager.events.RCTEventEmitter
30
+ import com.facebook.react.viewmanagers.NativeInputCalculatorManagerDelegate
31
+ import com.facebook.react.viewmanagers.NativeInputCalculatorManagerInterface
16
32
  import com.facebook.react.views.textinput.ReactEditText
17
33
  import com.facebook.react.views.textinput.ReactTextInputManager
18
34
 
19
- class RCTInputCalculator : ReactTextInputManager() {
35
+ @ReactModule(name = InputCalculatorViewManager.REACT_CLASS)
36
+ class InputCalculatorViewManager : SimpleViewManager<ReactEditText>(), NativeInputCalculatorManagerInterface<ReactEditText> {
37
+ private val delegate: NativeInputCalculatorManagerDelegate<ReactEditText, InputCalculatorViewManager> =
38
+ NativeInputCalculatorManagerDelegate(this)
39
+
40
+ override fun getDelegate(): ViewManagerDelegate<ReactEditText> = delegate
41
+
42
+ override fun getName() = REACT_CLASS
20
43
 
21
44
  private var keyboardView: CustomKeyboardView? = null
22
45
  private lateinit var editText: CalculatorEditText
@@ -27,15 +50,14 @@ class RCTInputCalculator : ReactTextInputManager() {
27
50
  private var backListenerAttached = false
28
51
  private var overlayShowing = false
29
52
 
30
- override fun getName() = REACT_CLASS
31
53
 
32
54
  companion object {
33
- const val REACT_CLASS = "RCTInputCalculator"
55
+ const val REACT_CLASS = "NativeInputCalculator"
34
56
  val calculatorHeight: Int = 240.dpToPx().toInt()
35
57
  }
36
58
 
37
59
  @ReactProp(name = "value")
38
- fun setValue(view: ReactEditText, value: String?) {
60
+ override fun setValue(view: ReactEditText, value: String?) {
39
61
  UiThreadUtil.runOnUiThread {
40
62
  val e = view.editableText ?: run { view.setText(value ?: ""); return@runOnUiThread }
41
63
  val newText = value ?: ""
@@ -48,29 +70,72 @@ class RCTInputCalculator : ReactTextInputManager() {
48
70
  }
49
71
  }
50
72
 
73
+ override fun setTextAttributes(view: ReactEditText?, value: ReadableMap?) {
74
+ val fontWeightStr = value?.getString("fontWeight")
75
+ val fontSize = value?.getDouble("fontSize")
76
+
77
+ fontWeightStr?.let { weightStr ->
78
+ val weight = when (weightStr) {
79
+ "100" -> 100
80
+ "200" -> 200
81
+ "300" -> 300
82
+ "400", "normal" -> 400
83
+ "500" -> 500
84
+ "600" -> 600
85
+ "700", "bold" -> 700
86
+ "800" -> 800
87
+ "900" -> 900
88
+ else -> 400
89
+ }
90
+
91
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
92
+ view?.typeface = Typeface.create(view.typeface, weight, false)
93
+ } else {
94
+ view?.typeface = if (weight >= 600) {
95
+ Typeface.create(view.typeface, Typeface.BOLD)
96
+ } else {
97
+ Typeface.create(view.typeface, Typeface.NORMAL)
98
+ }
99
+ }
100
+ }
101
+
102
+ fontSize?.let {
103
+ view?.textSize = it.toFloat()
104
+ }
105
+ }
106
+
107
+
108
+ @ReactProp(name = "mode")
109
+ override fun setMode(view: ReactEditText, mode: String?) {
110
+ keyboardView?.setMode(mode ?: "NumDefault")
111
+ }
112
+
51
113
  @ReactProp(name = "customKeyText")
52
- fun setCustomKeyText(view: ReactEditText, text: String?) {
53
- keyboardView?.setCustomKeyText(text ?: "Xong")
114
+ override fun setCustomKeyText(view: ReactEditText, text: String?) {
115
+ keyboardView?.setCustomKeyText(text ?: "Tiếp")
54
116
  }
55
117
 
56
118
  @ReactProp(name = "customKeyBackground")
57
- fun setCustomKeyBackground(view: ReactEditText, background: String?) {
119
+ override fun setCustomKeyBackground(view: ReactEditText, background: String?) {
58
120
  keyboardView?.setCustomKeyBackground((background ?: "#d8d8d8").toColorInt())
59
121
  }
60
122
 
61
123
  @ReactProp(name = "customKeyTextColor")
62
- fun setCustomKeyTextColor(view: ReactEditText, textColor: String?) {
124
+ override fun setCustomKeyTextColor(view: ReactEditText, textColor: String?) {
63
125
  keyboardView?.setCustomKeyTextColor(textColor?.toColorInt() ?: Color.BLACK)
64
126
  }
65
127
 
66
128
  @ReactProp(name = "customKeyState")
67
- fun setCustomKeyState(view: ReactEditText, state: String?) {
129
+ override fun setCustomKeyState(view: ReactEditText, state: String?) {
68
130
  keyboardView?.setCustomKeyState(state ?: "default")
69
131
  }
70
132
 
71
- @ReactProp(name = "keyboardColor")
72
- fun setKeyboardColor(view: ReactEditText, color: String) {
73
- keyboardView?.updateButtonColors(color.toColorInt())
133
+ override fun focus(view: ReactEditText?) {
134
+ UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
135
+ }
136
+
137
+ override fun blur(view: ReactEditText?) {
138
+ UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
74
139
  }
75
140
 
76
141
  @SuppressLint("ClickableViewAccessibility")
@@ -101,6 +166,16 @@ class RCTInputCalculator : ReactTextInputManager() {
101
166
  }
102
167
  false
103
168
  }
169
+ addTextChangedListener(object : TextWatcher{
170
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
171
+
172
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
173
+
174
+ override fun afterTextChanged(s: Editable?) {
175
+ emitOnChange(context, s.toString())
176
+ }
177
+
178
+ })
104
179
  }
105
180
 
106
181
  keyboardView = CustomKeyboardView(context, editText).apply {
@@ -165,33 +240,31 @@ class RCTInputCalculator : ReactTextInputManager() {
165
240
  v.showSoftInputOnFocus = true
166
241
  }
167
242
 
168
- override fun getCommandsMap(): Map<String, Int> = mapOf("blur" to 1, "focus" to 2)
243
+ private fun emitOnChange(context: Context, text: String) {
244
+ val reactContext = context as ReactContext
245
+ val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
246
+ val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, editText.id)
247
+ val payload =
248
+ Arguments.createMap().apply {
249
+ putString("text", text)
250
+ }
251
+ val event = OnChangeEvent(surfaceId, editText.id, payload)
169
252
 
170
- override fun receiveCommand(reactEditText: ReactEditText, commandId: Int, args: ReadableArray?) {
171
- when (commandId) {
172
- 1 -> blur()
173
- 2 -> focus()
174
- }
253
+ eventDispatcher?.dispatchEvent(event)
175
254
  }
176
255
 
177
256
  override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
178
- val base = super.getExportedCustomBubblingEventTypeConstants().toMutableMap()
257
+ val base = super.getExportedCustomBubblingEventTypeConstants()?.toMutableMap() ?: mutableMapOf()
179
258
  base["onKeyPress"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onKeyPress"))
259
+ base["onChange"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onChange"))
180
260
  return base
181
261
  }
182
262
 
183
263
  override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
184
- val base = super.getExportedCustomDirectEventTypeConstants().toMutableMap()
264
+ val base = super.getExportedCustomDirectEventTypeConstants()?.toMutableMap() ?: mutableMapOf()
185
265
  base["onCustomKeyEvent"] = mapOf("registrationName" to "onCustomKeyEvent")
186
266
  return base
187
267
  }
188
268
 
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
269
  }
197
270
 
@@ -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
+
@@ -0,0 +1,11 @@
1
+ #import <React/RCTViewComponentView.h>
2
+ #import <UIKit/UIKit.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @interface NativeInputCalculator : RCTViewComponentView
7
+
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END
11
+