@momo-kits/calculator-keyboard 0.167.1-beta.88 → 0.167.1-duo.12
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,12 +3,9 @@ package com.momokits.calculatorkeyboard.native
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.content.res.ColorStateList
|
|
6
|
-
import android.graphics.Bitmap
|
|
7
|
-
import android.graphics.BitmapFactory
|
|
8
6
|
import android.graphics.Color
|
|
9
7
|
import android.graphics.drawable.GradientDrawable
|
|
10
8
|
import android.text.Editable
|
|
11
|
-
import android.util.DisplayMetrics
|
|
12
9
|
import android.view.Gravity
|
|
13
10
|
import android.view.MotionEvent
|
|
14
11
|
import android.widget.Button
|
|
@@ -20,8 +17,6 @@ import androidx.core.graphics.toColorInt
|
|
|
20
17
|
import com.momokits.calculatorkeyboard.native.utils.CalculatorEngine
|
|
21
18
|
import com.momokits.calculatorkeyboard.native.utils.CalculatorFormatter
|
|
22
19
|
import com.momokits.calculatorkeyboard.R
|
|
23
|
-
import java.net.URL
|
|
24
|
-
import kotlin.concurrent.thread
|
|
25
20
|
|
|
26
21
|
@SuppressLint("SetTextI18n", "ViewConstructor")
|
|
27
22
|
class CustomKeyboardView(
|
|
@@ -186,26 +181,6 @@ class CustomKeyboardView(
|
|
|
186
181
|
setImageTintList(ColorStateList.valueOf(Color.BLACK))
|
|
187
182
|
setOnClickListener { onKeyPress(key, false) }
|
|
188
183
|
applyImagePressedOpacity()
|
|
189
|
-
loadBackIcon()
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Swap the bundled fallback icon for the design-system icon once it's downloaded
|
|
194
|
-
private fun ImageButton.loadBackIcon() {
|
|
195
|
-
backIconCache?.let { return setImageBitmap(it) }
|
|
196
|
-
|
|
197
|
-
thread {
|
|
198
|
-
val bitmap = runCatching {
|
|
199
|
-
URL(BACK_ICON_URL).openConnection().apply {
|
|
200
|
-
connectTimeout = BACK_ICON_TIMEOUT_MS
|
|
201
|
-
readTimeout = BACK_ICON_TIMEOUT_MS
|
|
202
|
-
}.getInputStream().use(BitmapFactory::decodeStream)
|
|
203
|
-
}.getOrNull() ?: return@thread
|
|
204
|
-
|
|
205
|
-
// Density makes the drawable render at BACK_ICON_SIZE_DP without resampling the bitmap
|
|
206
|
-
bitmap.density = bitmap.width * DisplayMetrics.DENSITY_DEFAULT / BACK_ICON_SIZE_DP
|
|
207
|
-
backIconCache = bitmap
|
|
208
|
-
post { setImageBitmap(bitmap) }
|
|
209
184
|
}
|
|
210
185
|
}
|
|
211
186
|
|
|
@@ -425,13 +400,4 @@ class CustomKeyboardView(
|
|
|
425
400
|
}
|
|
426
401
|
customKeyButton?.setTextColor(textColor)
|
|
427
402
|
}
|
|
428
|
-
|
|
429
|
-
companion object {
|
|
430
|
-
private const val BACK_ICON_URL = "https://img.mservice.com.vn/app/img/kits/chat_back_space.png"
|
|
431
|
-
private const val BACK_ICON_SIZE_DP = 24
|
|
432
|
-
private const val BACK_ICON_TIMEOUT_MS = 10_000
|
|
433
|
-
|
|
434
|
-
@Volatile
|
|
435
|
-
private var backIconCache: Bitmap? = null
|
|
436
|
-
}
|
|
437
403
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
#import "CalculatorKeyboardView.h"
|
|
2
2
|
#import "Utils.h"
|
|
3
3
|
|
|
4
|
-
static NSString *const kBackIconURL = @"https://img.mservice.com.vn/app/img/kits/chat_back_space.png";
|
|
5
|
-
static const CGFloat kBackIconSize = 24;
|
|
6
|
-
static UIImage *sBackIcon;
|
|
7
|
-
|
|
8
4
|
@interface CalculatorKeyboardView ()
|
|
9
5
|
@property (nonatomic, strong) NSArray<NSArray<NSString *> *> *numWithCTAKeys;
|
|
10
6
|
@property (nonatomic, strong) NSArray<NSArray<NSString *> *> *defaultKeys;
|
|
@@ -14,6 +10,8 @@ static UIImage *sBackIcon;
|
|
|
14
10
|
|
|
15
11
|
@implementation CalculatorKeyboardView {
|
|
16
12
|
CGFloat _separatorWidth;
|
|
13
|
+
UIView *_contentView;
|
|
14
|
+
NSArray<NSArray<UIButton *> *> *_buttonRows;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
@@ -89,28 +87,26 @@ static UIImage *sBackIcon;
|
|
|
89
87
|
|
|
90
88
|
self.backgroundColor = [Utils colorFromHex:@"#f2f2f6"];
|
|
91
89
|
|
|
92
|
-
CGFloat buttonWidth = (UIScreen.mainScreen.bounds.size.width - _separatorWidth * 2 - 4 * _separatorWidth) / 5;
|
|
93
|
-
CGFloat buttonHeight = (240 - _separatorWidth * 2 - 3 * _separatorWidth) / 4;
|
|
94
|
-
|
|
95
90
|
// Create content view
|
|
96
91
|
UIView *contentView = [[UIView alloc] init];
|
|
97
92
|
contentView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
98
93
|
[self addSubview:contentView];
|
|
94
|
+
_contentView = contentView;
|
|
99
95
|
|
|
100
|
-
// Set contentView constraints
|
|
96
|
+
// Set contentView constraints, keeping clear of the side safe area (landscape, iPhone Duo)
|
|
101
97
|
[NSLayoutConstraint activateConstraints:@[
|
|
102
|
-
[contentView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:_separatorWidth],
|
|
103
|
-
[contentView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-_separatorWidth],
|
|
98
|
+
[contentView.leadingAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leadingAnchor constant:_separatorWidth],
|
|
99
|
+
[contentView.trailingAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.trailingAnchor constant:-_separatorWidth],
|
|
104
100
|
[contentView.topAnchor constraintEqualToAnchor:self.topAnchor constant:_separatorWidth],
|
|
105
101
|
[contentView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-_separatorWidth]
|
|
106
102
|
]];
|
|
107
103
|
|
|
108
|
-
|
|
104
|
+
NSMutableArray<NSArray<UIButton *> *> *buttonRows = [NSMutableArray array];
|
|
109
105
|
NSArray<NSArray<NSString *> *> *keys = [_keyboardMode isEqualToString:@"NumDefault"] ? _defaultKeys : _numWithCTAKeys;
|
|
110
106
|
|
|
111
107
|
for (NSInteger rowIndex = 0; rowIndex < keys.count; rowIndex++) {
|
|
112
108
|
NSArray<NSString *> *row = keys[rowIndex];
|
|
113
|
-
|
|
109
|
+
NSMutableArray<UIButton *> *buttonRow = [NSMutableArray array];
|
|
114
110
|
|
|
115
111
|
for (NSInteger colIndex = 0; colIndex < row.count; colIndex++) {
|
|
116
112
|
NSString *key = row[colIndex];
|
|
@@ -128,23 +124,12 @@ static UIImage *sBackIcon;
|
|
|
128
124
|
button.accessibilityIdentifier = key;
|
|
129
125
|
button.tag = isMainCTAKey ? 1 : 0;
|
|
130
126
|
|
|
131
|
-
CGRect buttonFrame = CGRectMake(xOffset, yOffset, buttonWidth, buttonHeight);
|
|
132
|
-
if (isMainKey) {
|
|
133
|
-
buttonFrame.size.height = buttonHeight * 2 + _separatorWidth;
|
|
134
|
-
}
|
|
135
|
-
if ([key isEqualToString:@"000"]) {
|
|
136
|
-
buttonFrame.size.width = buttonWidth * 2 + _separatorWidth;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
button.frame = buttonFrame;
|
|
140
|
-
|
|
141
127
|
if ([key isEqualToString:@"back"]) {
|
|
142
128
|
[button setTitle:@"" forState:UIControlStateNormal];
|
|
143
129
|
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:24 weight:UIImageSymbolWeightBold];
|
|
144
130
|
UIImage *image = [UIImage systemImageNamed:@"delete.backward" withConfiguration:config];
|
|
145
131
|
[button setImage:image forState:UIControlStateNormal];
|
|
146
132
|
button.tintColor = UIColor.blackColor;
|
|
147
|
-
[self loadBackIconForButton:button];
|
|
148
133
|
}
|
|
149
134
|
|
|
150
135
|
if ([_specialKeys containsObject:key] || isMainKey) {
|
|
@@ -158,38 +143,49 @@ static UIImage *sBackIcon;
|
|
|
158
143
|
|
|
159
144
|
[button addTarget:self action:@selector(keyPressed:) forControlEvents:UIControlEventTouchUpInside];
|
|
160
145
|
[contentView addSubview:button];
|
|
161
|
-
|
|
162
|
-
xOffset += buttonFrame.size.width + _separatorWidth;
|
|
146
|
+
[buttonRow addObject:button];
|
|
163
147
|
}
|
|
164
148
|
|
|
165
|
-
|
|
149
|
+
[buttonRows addObject:buttonRow];
|
|
166
150
|
}
|
|
151
|
+
|
|
152
|
+
_buttonRows = buttonRows;
|
|
153
|
+
[self setNeedsLayout];
|
|
167
154
|
}
|
|
168
155
|
|
|
169
|
-
|
|
156
|
+
// Size the keys from the live keyboard width, which follows the window through
|
|
157
|
+
// rotation, fold and unfold, instead of the screen width at setup
|
|
158
|
+
- (void)layoutSubviews
|
|
170
159
|
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
160
|
+
[super layoutSubviews];
|
|
161
|
+
|
|
162
|
+
CGFloat buttonWidth = (_contentView.bounds.size.width - 4 * _separatorWidth) / 5;
|
|
163
|
+
CGFloat buttonHeight = (240 - _separatorWidth * 2 - 3 * _separatorWidth) / 4;
|
|
164
|
+
CGFloat yOffset = 0;
|
|
165
|
+
|
|
166
|
+
for (NSInteger rowIndex = 0; rowIndex < _buttonRows.count; rowIndex++) {
|
|
167
|
+
NSArray<UIButton *> *row = _buttonRows[rowIndex];
|
|
168
|
+
CGFloat xOffset = 0;
|
|
169
|
+
|
|
170
|
+
for (NSInteger colIndex = 0; colIndex < row.count; colIndex++) {
|
|
171
|
+
UIButton *button = row[colIndex];
|
|
172
|
+
NSString *key = button.accessibilityIdentifier;
|
|
173
|
+
BOOL isMainKey = (colIndex == 4 && rowIndex == 2);
|
|
174
|
+
|
|
175
|
+
CGRect buttonFrame = CGRectMake(xOffset, yOffset, buttonWidth, buttonHeight);
|
|
176
|
+
if (isMainKey) {
|
|
177
|
+
buttonFrame.size.height = buttonHeight * 2 + _separatorWidth;
|
|
178
|
+
}
|
|
179
|
+
if ([key isEqualToString:@"000"]) {
|
|
180
|
+
buttonFrame.size.width = buttonWidth * 2 + _separatorWidth;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
button.frame = buttonFrame;
|
|
184
|
+
xOffset += buttonFrame.size.width + _separatorWidth;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
yOffset += buttonHeight + _separatorWidth;
|
|
174
188
|
}
|
|
175
|
-
|
|
176
|
-
__weak UIButton *weakButton = button;
|
|
177
|
-
[[NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:kBackIconURL]
|
|
178
|
-
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
179
|
-
CGImageRef cgImage = [UIImage imageWithData:data].CGImage;
|
|
180
|
-
if (!cgImage) return;
|
|
181
|
-
|
|
182
|
-
// Scale makes the image size kBackIconSize points without redrawing it
|
|
183
|
-
UIImage *icon = [[UIImage imageWithCGImage:cgImage
|
|
184
|
-
scale:CGImageGetWidth(cgImage) / kBackIconSize
|
|
185
|
-
orientation:UIImageOrientationUp]
|
|
186
|
-
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
|
187
|
-
|
|
188
|
-
dispatch_async(dispatch_get_main_queue(), ^{
|
|
189
|
-
sBackIcon = icon;
|
|
190
|
-
[weakButton setImage:icon forState:UIControlStateNormal];
|
|
191
|
-
});
|
|
192
|
-
}] resume];
|
|
193
189
|
}
|
|
194
190
|
|
|
195
191
|
- (void)updateCustomKeyTitle
|
package/ios/InputCalculator.mm
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
#import <React/RCTConversions.h>
|
|
5
5
|
#import <React/RCTFabricComponentsPlugins.h>
|
|
6
|
+
#import <React/RCTUtils.h>
|
|
6
7
|
#import <react/renderer/components/InputCalculatorSpec/InputCalculatorComponentDescriptor.h>
|
|
7
8
|
#import <react/renderer/components/InputCalculatorSpec/EventEmitters.h>
|
|
8
9
|
#import <react/renderer/components/InputCalculatorSpec/Props.h>
|
|
@@ -45,9 +46,13 @@ typedef struct {
|
|
|
45
46
|
_textField.delegate = (id<UITextFieldDelegate>)self;
|
|
46
47
|
|
|
47
48
|
// Create keyboard view
|
|
49
|
+
// UIKit sizes the input view to the keyboard width; the keys follow it in layoutSubviews
|
|
50
|
+
UIWindow *window = RCTKeyWindow();
|
|
51
|
+
CGFloat keyboardWidth = window ? window.bounds.size.width : UIScreen.mainScreen.bounds.size.width;
|
|
48
52
|
CGFloat bottomInset = [self getBottomInset];
|
|
49
|
-
CGRect keyboardFrame = CGRectMake(0, 0,
|
|
53
|
+
CGRect keyboardFrame = CGRectMake(0, 0, keyboardWidth, 240 + bottomInset);
|
|
50
54
|
_keyboardView = [[CalculatorKeyboardView alloc] initWithFrame:keyboardFrame];
|
|
55
|
+
_keyboardView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
|
51
56
|
_keyboardView.input = (id)self; // Bridge pattern
|
|
52
57
|
|
|
53
58
|
// Set custom keyboard
|
|
@@ -94,7 +99,8 @@ typedef struct {
|
|
|
94
99
|
|
|
95
100
|
- (CGFloat)getBottomInset
|
|
96
101
|
{
|
|
97
|
-
|
|
102
|
+
// key window of the active scene; windows.firstObject is unreliable with the UIScene life cycle
|
|
103
|
+
UIWindow *window = RCTKeyWindow();
|
|
98
104
|
CGFloat bottom = window.safeAreaInsets.bottom > 0 ? 21 : 0;
|
|
99
105
|
return bottom;
|
|
100
106
|
}
|