react-native-klarna-inapp-sdk 2.4.10 → 2.5.0
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 +2 -1
- package/android/build.gradle +3 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackage.java +5 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/checkout/KlarnaCheckoutViewManager.java +4 -10
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/WebViewResizeObserver.java +28 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/ComponentEventSender.java +5 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/ResizeObserverWrapperView.java +2 -2
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/WrapperView.java +2 -2
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/YogaLayoutHelper.java +39 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewCallback.kt +30 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewEventSender.kt +80 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewManager.java +544 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventHandler.java +30 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventSender.java +64 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewManager.java +356 -0
- package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaExpressCheckoutViewSpec.java +31 -0
- package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaOSMViewSpec.java +31 -0
- package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaExpressCheckoutViewSpec.java +36 -0
- package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaOSMViewSpec.java +32 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackageTest.java +5 -1
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/ui/YogaLayoutHelperTest.java +79 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewManagerTest.java +259 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventHandlerTest.java +136 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventSenderTest.java +184 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewManagerTest.java +385 -0
- package/ios/RNKlarnaMobileSDK.xcodeproj/project.pbxproj +55 -1
- package/ios/Sources/KlarnaExpressCheckoutViewManager.h +5 -0
- package/ios/Sources/KlarnaExpressCheckoutViewManager.mm +39 -0
- package/ios/Sources/KlarnaOSMViewManager.h +5 -0
- package/ios/Sources/KlarnaOSMViewManager.mm +59 -0
- package/ios/Sources/view/KlarnaExpressCheckoutButtonDelegateProxy.swift +145 -0
- package/ios/Sources/view/KlarnaExpressCheckoutViewWrapper.h +41 -0
- package/ios/Sources/view/KlarnaOSMViewWrapper.h +48 -0
- package/ios/Sources/view/newarch/KlarnaExpressCheckoutViewWrapper.mm +228 -0
- package/ios/Sources/view/newarch/KlarnaOSMViewWrapper.mm +294 -0
- package/ios/Sources/view/newarch/KlarnaStandaloneWebViewWrapper.mm +20 -13
- package/ios/Sources/view/oldarch/KlarnaExpressCheckoutViewWrapper.mm +222 -0
- package/ios/Sources/view/oldarch/KlarnaOSMViewWrapper.mm +273 -0
- package/ios/Sources/view/oldarch/KlarnaStandaloneWebViewWrapper.mm +11 -13
- package/ios/Tests/KlarnaExpressCheckoutViewWrapperTests.m +391 -0
- package/ios/Tests/KlarnaOSMViewWrapperTests.m +450 -0
- package/ios/Tests/KlarnaStandaloneWebViewWrapperTests.m +105 -0
- package/lib/commonjs/KlarnaExpressCheckoutView.js +75 -0
- package/lib/commonjs/KlarnaExpressCheckoutView.js.map +1 -0
- package/lib/commonjs/KlarnaOSMView.js +94 -0
- package/lib/commonjs/KlarnaOSMView.js.map +1 -0
- package/lib/commonjs/index.js +99 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/KlarnaExpressCheckoutViewNativeComponent.js +11 -0
- package/lib/commonjs/specs/KlarnaExpressCheckoutViewNativeComponent.js.map +1 -0
- package/lib/commonjs/specs/KlarnaOSMViewNativeComponent.js +16 -0
- package/lib/commonjs/specs/KlarnaOSMViewNativeComponent.js.map +1 -0
- package/lib/commonjs/types/button/KlarnaButtonShape.js +14 -0
- package/lib/commonjs/types/button/KlarnaButtonShape.js.map +1 -0
- package/lib/commonjs/types/button/KlarnaButtonStyle.js +13 -0
- package/lib/commonjs/types/button/KlarnaButtonStyle.js.map +1 -0
- package/lib/commonjs/types/button/KlarnaButtonTheme.js +14 -0
- package/lib/commonjs/types/button/KlarnaButtonTheme.js.map +1 -0
- package/lib/commonjs/types/common/KlarnaExpressCheckoutSessionOptions.js +9 -0
- package/lib/commonjs/types/common/KlarnaExpressCheckoutSessionOptions.js.map +1 -0
- package/lib/commonjs/types/common/KlarnaOSMPlacementKey.js +2 -0
- package/lib/commonjs/types/common/KlarnaOSMPlacementKey.js.map +1 -0
- package/lib/commonjs/types/common/KlarnaTheme.js +14 -0
- package/lib/commonjs/types/common/KlarnaTheme.js.map +1 -0
- package/lib/module/KlarnaExpressCheckoutView.js +64 -0
- package/lib/module/KlarnaExpressCheckoutView.js.map +1 -0
- package/lib/module/KlarnaOSMView.js +84 -0
- package/lib/module/KlarnaOSMView.js.map +1 -0
- package/lib/module/index.js +9 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/KlarnaExpressCheckoutViewNativeComponent.js +3 -0
- package/lib/module/specs/KlarnaExpressCheckoutViewNativeComponent.js.map +1 -0
- package/lib/module/specs/KlarnaOSMViewNativeComponent.js +7 -0
- package/lib/module/specs/KlarnaOSMViewNativeComponent.js.map +1 -0
- package/lib/module/types/button/KlarnaButtonShape.js +7 -0
- package/lib/module/types/button/KlarnaButtonShape.js.map +1 -0
- package/lib/module/types/button/KlarnaButtonStyle.js +6 -0
- package/lib/module/types/button/KlarnaButtonStyle.js.map +1 -0
- package/lib/module/types/button/KlarnaButtonTheme.js +7 -0
- package/lib/module/types/button/KlarnaButtonTheme.js.map +1 -0
- package/lib/module/types/common/KlarnaExpressCheckoutSessionOptions.js +2 -0
- package/lib/module/types/common/KlarnaExpressCheckoutSessionOptions.js.map +1 -0
- package/lib/module/types/common/KlarnaOSMPlacementKey.js +2 -0
- package/lib/module/types/common/KlarnaOSMPlacementKey.js.map +1 -0
- package/lib/module/types/common/KlarnaTheme.js +7 -0
- package/lib/module/types/common/KlarnaTheme.js.map +1 -0
- package/lib/typescript/KlarnaExpressCheckoutView.d.ts +47 -0
- package/lib/typescript/KlarnaExpressCheckoutView.d.ts.map +1 -0
- package/lib/typescript/KlarnaOSMView.d.ts +36 -0
- package/lib/typescript/KlarnaOSMView.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +9 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/specs/KlarnaExpressCheckoutViewNativeComponent.d.ts +45 -0
- package/lib/typescript/specs/KlarnaExpressCheckoutViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/specs/KlarnaOSMViewNativeComponent.d.ts +35 -0
- package/lib/typescript/specs/KlarnaOSMViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/types/button/KlarnaButtonShape.d.ts +6 -0
- package/lib/typescript/types/button/KlarnaButtonShape.d.ts.map +1 -0
- package/lib/typescript/types/button/KlarnaButtonStyle.d.ts +5 -0
- package/lib/typescript/types/button/KlarnaButtonStyle.d.ts.map +1 -0
- package/lib/typescript/types/button/KlarnaButtonTheme.d.ts +6 -0
- package/lib/typescript/types/button/KlarnaButtonTheme.d.ts.map +1 -0
- package/lib/typescript/types/common/KlarnaExpressCheckoutSessionOptions.d.ts +10 -0
- package/lib/typescript/types/common/KlarnaExpressCheckoutSessionOptions.d.ts.map +1 -0
- package/lib/typescript/types/common/KlarnaOSMPlacementKey.d.ts +2 -0
- package/lib/typescript/types/common/KlarnaOSMPlacementKey.d.ts.map +1 -0
- package/lib/typescript/types/common/KlarnaTheme.d.ts +6 -0
- package/lib/typescript/types/common/KlarnaTheme.d.ts.map +1 -0
- package/package.json +5 -3
- package/react-native-klarna-inapp-sdk.podspec +2 -1
- package/src/KlarnaExpressCheckoutView.tsx +169 -0
- package/src/KlarnaOSMView.tsx +157 -0
- package/src/index.tsx +9 -0
- package/src/specs/KlarnaExpressCheckoutViewNativeComponent.ts +66 -0
- package/src/specs/KlarnaOSMViewNativeComponent.ts +50 -0
- package/src/types/button/KlarnaButtonShape.ts +5 -0
- package/src/types/button/KlarnaButtonStyle.ts +4 -0
- package/src/types/button/KlarnaButtonTheme.ts +5 -0
- package/src/types/common/KlarnaExpressCheckoutSessionOptions.ts +13 -0
- package/src/types/common/KlarnaOSMPlacementKey.ts +3 -0
- package/src/types/common/KlarnaTheme.ts +5 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.osm;
|
|
2
|
+
|
|
3
|
+
import android.app.Activity;
|
|
4
|
+
import android.view.View;
|
|
5
|
+
import android.view.ViewTreeObserver;
|
|
6
|
+
|
|
7
|
+
import androidx.annotation.NonNull;
|
|
8
|
+
import androidx.annotation.Nullable;
|
|
9
|
+
|
|
10
|
+
import com.facebook.react.bridge.ReactContext;
|
|
11
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
12
|
+
import com.facebook.react.uimanager.ThemedReactContext;
|
|
13
|
+
import com.facebook.react.uimanager.UIManagerHelper;
|
|
14
|
+
import com.facebook.react.uimanager.annotations.ReactProp;
|
|
15
|
+
import com.facebook.react.uimanager.events.EventDispatcher;
|
|
16
|
+
import com.klarna.mobile.sdk.api.osm.KlarnaOSMView;
|
|
17
|
+
import com.klarna.mobile.sdk.KlarnaMobileSDKError;
|
|
18
|
+
import com.klarna.mobile.sdk.reactnative.common.ui.WrapperView;
|
|
19
|
+
import com.klarna.mobile.sdk.reactnative.common.ui.YogaLayoutHelper;
|
|
20
|
+
import com.klarna.mobile.sdk.reactnative.spec.RNKlarnaOSMViewSpec;
|
|
21
|
+
import com.klarna.mobile.sdk.api.KlarnaRegion;
|
|
22
|
+
import com.klarna.mobile.sdk.api.KlarnaEnvironment;
|
|
23
|
+
import com.klarna.mobile.sdk.api.KlarnaTextStyleConfiguration;
|
|
24
|
+
import com.klarna.mobile.sdk.api.KlarnaTheme;
|
|
25
|
+
import com.klarna.mobile.sdk.api.osm.KlarnaOSMStyleConfiguration;
|
|
26
|
+
|
|
27
|
+
import com.facebook.react.uimanager.PixelUtil;
|
|
28
|
+
|
|
29
|
+
import java.util.Map;
|
|
30
|
+
import java.util.WeakHashMap;
|
|
31
|
+
|
|
32
|
+
public class KlarnaOSMViewManager extends RNKlarnaOSMViewSpec<WrapperView<KlarnaOSMView>> {
|
|
33
|
+
|
|
34
|
+
public static final String KLARNA_OSM_VIEW_REACT_CLASS = "RNKlarnaOSMView";
|
|
35
|
+
public static final String COMMAND_RENDER_OSM = "render";
|
|
36
|
+
|
|
37
|
+
private final Map<WrapperView<KlarnaOSMView>, EventDispatcher> viewToDispatcher;
|
|
38
|
+
private final KlarnaOSMViewEventSender eventSender;
|
|
39
|
+
private final KlarnaOSMViewEventHandler eventHandler;
|
|
40
|
+
private final Map<KlarnaOSMView, ViewTreeObserver.OnGlobalLayoutListener> layoutListeners = new WeakHashMap<>();
|
|
41
|
+
private final Map<KlarnaOSMView, String> pendingBackgroundColor = new WeakHashMap<>();
|
|
42
|
+
private final Map<KlarnaOSMView, String> pendingTextColor = new WeakHashMap<>();
|
|
43
|
+
|
|
44
|
+
public KlarnaOSMViewManager() {
|
|
45
|
+
super();
|
|
46
|
+
viewToDispatcher = new WeakHashMap<>();
|
|
47
|
+
eventSender = new KlarnaOSMViewEventSender(viewToDispatcher);
|
|
48
|
+
eventHandler = new KlarnaOSMViewEventHandler(eventSender);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@NonNull
|
|
52
|
+
@Override
|
|
53
|
+
public String getName() {
|
|
54
|
+
return KLARNA_OSM_VIEW_REACT_CLASS;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@NonNull
|
|
58
|
+
@Override
|
|
59
|
+
protected WrapperView<KlarnaOSMView> createViewInstance(@NonNull ThemedReactContext themedReactContext) {
|
|
60
|
+
Activity activity = themedReactContext.getCurrentActivity();
|
|
61
|
+
KlarnaOSMView osmView = new KlarnaOSMView(activity != null ? activity : themedReactContext);
|
|
62
|
+
osmView.setEventHandler(eventHandler);
|
|
63
|
+
if (activity != null) {
|
|
64
|
+
osmView.setHostActivity(activity);
|
|
65
|
+
}
|
|
66
|
+
WrapperView<KlarnaOSMView> view = new WrapperView<>(themedReactContext, null, osmView);
|
|
67
|
+
|
|
68
|
+
EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag((ReactContext) view.getContext(), view.getId());
|
|
69
|
+
viewToDispatcher.put(view, eventDispatcher);
|
|
70
|
+
|
|
71
|
+
view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
|
72
|
+
@Override
|
|
73
|
+
public void onViewAttachedToWindow(@NonNull View v) {
|
|
74
|
+
eventSender.sendOnOSMViewReadyEvent(osmView);
|
|
75
|
+
v.removeOnAttachStateChangeListener(this);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@Override
|
|
79
|
+
public void onViewDetachedFromWindow(@NonNull View v) {
|
|
80
|
+
removeLayoutListener(osmView);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return view;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Override
|
|
88
|
+
public void onDropViewInstance(@NonNull WrapperView<KlarnaOSMView> view) {
|
|
89
|
+
removeLayoutListener(view.getView());
|
|
90
|
+
viewToDispatcher.remove(view);
|
|
91
|
+
super.onDropViewInstance(view);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private void removeLayoutListener(@Nullable KlarnaOSMView osmView) {
|
|
95
|
+
if (osmView == null) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
ViewTreeObserver.OnGlobalLayoutListener listener = layoutListeners.remove(osmView);
|
|
99
|
+
if (listener != null) {
|
|
100
|
+
osmView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@Nullable
|
|
105
|
+
@Override
|
|
106
|
+
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
|
|
107
|
+
return eventSender.getExportedCustomDirectEventTypeConstants();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@Override
|
|
111
|
+
public void receiveCommand(@NonNull WrapperView<KlarnaOSMView> root, String commandId, @Nullable ReadableArray args) {
|
|
112
|
+
if (COMMAND_RENDER_OSM.equals(commandId)) {
|
|
113
|
+
render(root);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@ReactProp(name = "clientId")
|
|
118
|
+
@Override
|
|
119
|
+
public void setClientId(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
120
|
+
KlarnaOSMView osmView = view.getView();
|
|
121
|
+
if (osmView != null && value != null && !value.isEmpty()) {
|
|
122
|
+
osmView.setClientId(value);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@ReactProp(name = "placementKey")
|
|
127
|
+
@Override
|
|
128
|
+
public void setPlacementKey(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
129
|
+
KlarnaOSMView osmView = view.getView();
|
|
130
|
+
if (osmView != null && value != null && !value.isEmpty()) {
|
|
131
|
+
osmView.setPlacementKey(value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@ReactProp(name = "locale")
|
|
136
|
+
@Override
|
|
137
|
+
public void setLocale(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
138
|
+
KlarnaOSMView osmView = view.getView();
|
|
139
|
+
if (osmView != null && value != null && !value.isEmpty()) {
|
|
140
|
+
osmView.setLocale(value);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@ReactProp(name = "purchaseAmount")
|
|
145
|
+
@Override
|
|
146
|
+
public void setPurchaseAmount(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
147
|
+
KlarnaOSMView osmView = view.getView();
|
|
148
|
+
if (osmView != null && value != null && !value.isEmpty()) {
|
|
149
|
+
try {
|
|
150
|
+
long amount = Long.parseLong(value);
|
|
151
|
+
osmView.setPurchaseAmount(amount);
|
|
152
|
+
} catch (NumberFormatException e) {
|
|
153
|
+
eventSender.sendError(osmView, "InvalidPurchaseAmount",
|
|
154
|
+
"Invalid purchaseAmount: '" + value + "'. Expected a numeric string.", false);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@ReactProp(name = "environment")
|
|
160
|
+
@Override
|
|
161
|
+
public void setEnvironment(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
162
|
+
KlarnaOSMView osmView = view.getView();
|
|
163
|
+
if (osmView != null && value != null && !value.isEmpty()) {
|
|
164
|
+
switch (value) {
|
|
165
|
+
case "playground":
|
|
166
|
+
osmView.setEnvironment(KlarnaEnvironment.PLAYGROUND);
|
|
167
|
+
break;
|
|
168
|
+
case "production":
|
|
169
|
+
osmView.setEnvironment(KlarnaEnvironment.PRODUCTION);
|
|
170
|
+
break;
|
|
171
|
+
case "staging":
|
|
172
|
+
osmView.setEnvironment(KlarnaEnvironment.STAGING);
|
|
173
|
+
break;
|
|
174
|
+
default:
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
@ReactProp(name = "region")
|
|
181
|
+
@Override
|
|
182
|
+
public void setRegion(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
183
|
+
KlarnaOSMView osmView = view.getView();
|
|
184
|
+
if (osmView != null && value != null && !value.isEmpty()) {
|
|
185
|
+
switch (value) {
|
|
186
|
+
case "eu":
|
|
187
|
+
osmView.setRegion(KlarnaRegion.EU);
|
|
188
|
+
break;
|
|
189
|
+
case "na":
|
|
190
|
+
osmView.setRegion(KlarnaRegion.NA);
|
|
191
|
+
break;
|
|
192
|
+
case "oc":
|
|
193
|
+
osmView.setRegion(KlarnaRegion.OC);
|
|
194
|
+
break;
|
|
195
|
+
default:
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@ReactProp(name = "theme")
|
|
202
|
+
@Override
|
|
203
|
+
public void setTheme(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
204
|
+
KlarnaOSMView osmView = view.getView();
|
|
205
|
+
if (osmView != null && value != null && !value.isEmpty()) {
|
|
206
|
+
switch (value) {
|
|
207
|
+
case "light":
|
|
208
|
+
osmView.setTheme(KlarnaTheme.LIGHT);
|
|
209
|
+
break;
|
|
210
|
+
case "dark":
|
|
211
|
+
osmView.setTheme(KlarnaTheme.DARK);
|
|
212
|
+
break;
|
|
213
|
+
case "automatic":
|
|
214
|
+
osmView.setTheme(KlarnaTheme.AUTOMATIC);
|
|
215
|
+
break;
|
|
216
|
+
default:
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@ReactProp(name = "backgroundColor")
|
|
223
|
+
@Override
|
|
224
|
+
public void setBackgroundColor(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
225
|
+
KlarnaOSMView osmView = view.getView();
|
|
226
|
+
if (osmView != null) {
|
|
227
|
+
pendingBackgroundColor.put(osmView, value);
|
|
228
|
+
updateStyleConfiguration(osmView);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@ReactProp(name = "textColor")
|
|
233
|
+
@Override
|
|
234
|
+
public void setTextColor(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
235
|
+
KlarnaOSMView osmView = view.getView();
|
|
236
|
+
if (osmView != null) {
|
|
237
|
+
pendingTextColor.put(osmView, value);
|
|
238
|
+
updateStyleConfiguration(osmView);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@ReactProp(name = "returnUrl")
|
|
243
|
+
@Override
|
|
244
|
+
public void setReturnUrl(WrapperView<KlarnaOSMView> view, @Nullable String value) {
|
|
245
|
+
// No need to do anything here because KlarnaOSMView ignores the return URL set by merchant and uses an internally created return URL.
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@Override
|
|
249
|
+
public void render(WrapperView<KlarnaOSMView> view) {
|
|
250
|
+
KlarnaOSMView osmView = view.getView();
|
|
251
|
+
if (osmView != null) {
|
|
252
|
+
ReactContext reactContext = (ReactContext) view.getContext();
|
|
253
|
+
Activity activity = reactContext.getCurrentActivity();
|
|
254
|
+
if (activity != null) {
|
|
255
|
+
osmView.setHostActivity(activity);
|
|
256
|
+
}
|
|
257
|
+
osmView.render(error -> {
|
|
258
|
+
if (error != null) {
|
|
259
|
+
eventSender.sendKlarnaMobileSDKError(osmView, error);
|
|
260
|
+
} else {
|
|
261
|
+
removeLayoutListener(osmView);
|
|
262
|
+
addLayoutListenerForMeasure(osmView, view);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private boolean tryMeasureContent(KlarnaOSMView osmView, WrapperView<KlarnaOSMView> wrapperView) {
|
|
269
|
+
if (osmView.getChildCount() > 0 && wrapperView.getWidth() > 0) {
|
|
270
|
+
View child = osmView.getChildAt(0);
|
|
271
|
+
YogaLayoutHelper.measureAndLayout(wrapperView, child);
|
|
272
|
+
int contentHeight = child.getMeasuredHeight();
|
|
273
|
+
if (contentHeight > 0) {
|
|
274
|
+
int contentHeightDp = Math.round(PixelUtil.toDIPFromPixel(contentHeight));
|
|
275
|
+
eventSender.sendOnResizedEvent(osmView, contentHeightDp);
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private void updateStyleConfiguration(KlarnaOSMView osmView) {
|
|
283
|
+
String bgColorStr = pendingBackgroundColor.get(osmView);
|
|
284
|
+
String txtColorStr = pendingTextColor.get(osmView);
|
|
285
|
+
|
|
286
|
+
Integer bgColor = parseColor(bgColorStr);
|
|
287
|
+
Integer txtColor = parseColor(txtColorStr);
|
|
288
|
+
|
|
289
|
+
if (bgColor != null || txtColor != null) {
|
|
290
|
+
KlarnaOSMStyleConfiguration.Builder builder = new KlarnaOSMStyleConfiguration.Builder();
|
|
291
|
+
if (bgColor != null) {
|
|
292
|
+
builder.setBackgroundColor(bgColor);
|
|
293
|
+
}
|
|
294
|
+
if (txtColor != null) {
|
|
295
|
+
KlarnaTextStyleConfiguration textStyle = new KlarnaTextStyleConfiguration.Builder()
|
|
296
|
+
.setTextColor(txtColor)
|
|
297
|
+
.build();
|
|
298
|
+
builder.setTextStyle(textStyle);
|
|
299
|
+
}
|
|
300
|
+
osmView.setStyleConfiguration(builder.build());
|
|
301
|
+
} else {
|
|
302
|
+
osmView.setStyleConfiguration(null);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@Nullable
|
|
307
|
+
private Integer parseColor(@Nullable String colorString) {
|
|
308
|
+
if (colorString == null || colorString.isEmpty()) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
return android.graphics.Color.parseColor(colorString.startsWith("#") ? colorString : "#" + colorString);
|
|
313
|
+
} catch (IllegalArgumentException e) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Adds a ViewTreeObserver listener to measure content when layout is ready.
|
|
320
|
+
* The listener automatically removes itself after successful measurement.
|
|
321
|
+
*/
|
|
322
|
+
private void addLayoutListenerForMeasure(KlarnaOSMView osmView, WrapperView<KlarnaOSMView> wrapperView) {
|
|
323
|
+
// Try measuring on the next frame — content may already be ready and no further
|
|
324
|
+
// layout event would fire, so the ViewTreeObserver alone is not sufficient.
|
|
325
|
+
osmView.post(() -> {
|
|
326
|
+
if (!osmView.isAttachedToWindow()) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (tryMeasureContent(osmView, wrapperView)) {
|
|
330
|
+
removeLayoutListener(osmView);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
|
|
335
|
+
@Override
|
|
336
|
+
public void onGlobalLayout() {
|
|
337
|
+
if (!osmView.isAttachedToWindow()) {
|
|
338
|
+
removeThisListener();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (tryMeasureContent(osmView, wrapperView)) {
|
|
343
|
+
removeThisListener();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private void removeThisListener() {
|
|
348
|
+
layoutListeners.remove(osmView);
|
|
349
|
+
osmView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
layoutListeners.put(osmView, listener);
|
|
354
|
+
osmView.getViewTreeObserver().addOnGlobalLayoutListener(listener);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.spec;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
9
|
+
import com.facebook.react.uimanager.SimpleViewManager;
|
|
10
|
+
import com.facebook.react.uimanager.ViewManagerDelegate;
|
|
11
|
+
import com.facebook.react.viewmanagers.RNKlarnaExpressCheckoutViewManagerDelegate;
|
|
12
|
+
import com.facebook.react.viewmanagers.RNKlarnaExpressCheckoutViewManagerInterface;
|
|
13
|
+
|
|
14
|
+
public abstract class RNKlarnaExpressCheckoutViewSpec<T extends View> extends SimpleViewManager<T> implements RNKlarnaExpressCheckoutViewManagerInterface<T> {
|
|
15
|
+
private final ViewManagerDelegate<T> mDelegate;
|
|
16
|
+
|
|
17
|
+
public RNKlarnaExpressCheckoutViewSpec() {
|
|
18
|
+
mDelegate = new RNKlarnaExpressCheckoutViewManagerDelegate<>(this);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@Nullable
|
|
22
|
+
@Override
|
|
23
|
+
protected ViewManagerDelegate<T> getDelegate() {
|
|
24
|
+
return mDelegate;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Override
|
|
28
|
+
public void receiveCommand(@NonNull T root, String commandId, @Nullable ReadableArray args) {
|
|
29
|
+
mDelegate.receiveCommand(root, commandId, args);
|
|
30
|
+
}
|
|
31
|
+
}
|
package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaOSMViewSpec.java
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.spec;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
9
|
+
import com.facebook.react.uimanager.SimpleViewManager;
|
|
10
|
+
import com.facebook.react.uimanager.ViewManagerDelegate;
|
|
11
|
+
import com.facebook.react.viewmanagers.RNKlarnaOSMViewManagerDelegate;
|
|
12
|
+
import com.facebook.react.viewmanagers.RNKlarnaOSMViewManagerInterface;
|
|
13
|
+
|
|
14
|
+
public abstract class RNKlarnaOSMViewSpec<T extends View> extends SimpleViewManager<T> implements RNKlarnaOSMViewManagerInterface<T> {
|
|
15
|
+
private final ViewManagerDelegate<T> mDelegate;
|
|
16
|
+
|
|
17
|
+
public RNKlarnaOSMViewSpec() {
|
|
18
|
+
mDelegate = new RNKlarnaOSMViewManagerDelegate<>(this);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@Nullable
|
|
22
|
+
@Override
|
|
23
|
+
protected ViewManagerDelegate<T> getDelegate() {
|
|
24
|
+
return mDelegate;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Override
|
|
28
|
+
public void receiveCommand(@NonNull T root, String commandId, @Nullable ReadableArray args) {
|
|
29
|
+
mDelegate.receiveCommand(root, commandId, args);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.spec;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.Nullable;
|
|
6
|
+
|
|
7
|
+
import com.facebook.react.uimanager.SimpleViewManager;
|
|
8
|
+
|
|
9
|
+
public abstract class RNKlarnaExpressCheckoutViewSpec<T extends View> extends SimpleViewManager<T> {
|
|
10
|
+
|
|
11
|
+
public abstract void setSessionType(T view, @Nullable String value);
|
|
12
|
+
|
|
13
|
+
public abstract void setClientId(T view, @Nullable String value);
|
|
14
|
+
|
|
15
|
+
public abstract void setClientToken(T view, @Nullable String value);
|
|
16
|
+
|
|
17
|
+
public abstract void setLocale(T view, @Nullable String value);
|
|
18
|
+
|
|
19
|
+
public abstract void setEnvironment(T view, @Nullable String value);
|
|
20
|
+
|
|
21
|
+
public abstract void setRegion(T view, @Nullable String value);
|
|
22
|
+
|
|
23
|
+
public abstract void setReturnUrl(T view, @Nullable String value);
|
|
24
|
+
|
|
25
|
+
public abstract void setTheme(T view, @Nullable String value);
|
|
26
|
+
|
|
27
|
+
public abstract void setShape(T view, @Nullable String value);
|
|
28
|
+
|
|
29
|
+
public abstract void setButtonStyle(T view, @Nullable String value);
|
|
30
|
+
|
|
31
|
+
public abstract void setAutoFinalize(T view, boolean value);
|
|
32
|
+
|
|
33
|
+
public abstract void setCollectShippingAddress(T view, boolean value);
|
|
34
|
+
|
|
35
|
+
public abstract void setSessionData(T view, @Nullable String value);
|
|
36
|
+
}
|
package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaOSMViewSpec.java
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.spec;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.Nullable;
|
|
6
|
+
|
|
7
|
+
import com.facebook.react.uimanager.SimpleViewManager;
|
|
8
|
+
|
|
9
|
+
public abstract class RNKlarnaOSMViewSpec<T extends View> extends SimpleViewManager<T> {
|
|
10
|
+
|
|
11
|
+
public abstract void setClientId(T view, @Nullable String value);
|
|
12
|
+
|
|
13
|
+
public abstract void setPlacementKey(T view, @Nullable String value);
|
|
14
|
+
|
|
15
|
+
public abstract void setLocale(T view, @Nullable String value);
|
|
16
|
+
|
|
17
|
+
public abstract void setPurchaseAmount(T view, @Nullable String value);
|
|
18
|
+
|
|
19
|
+
public abstract void setEnvironment(T view, @Nullable String value);
|
|
20
|
+
|
|
21
|
+
public abstract void setRegion(T view, @Nullable String value);
|
|
22
|
+
|
|
23
|
+
public abstract void setTheme(T view, @Nullable String value);
|
|
24
|
+
|
|
25
|
+
public abstract void setBackgroundColor(T view, @Nullable String value);
|
|
26
|
+
|
|
27
|
+
public abstract void setTextColor(T view, @Nullable String value);
|
|
28
|
+
|
|
29
|
+
public abstract void setReturnUrl(T view, @Nullable String value);
|
|
30
|
+
|
|
31
|
+
public abstract void render(T view);
|
|
32
|
+
}
|
package/android/src/test/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackageTest.java
CHANGED
|
@@ -8,9 +8,11 @@ import com.facebook.react.bridge.NativeModule;
|
|
|
8
8
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
9
9
|
import com.facebook.react.uimanager.ViewManager;
|
|
10
10
|
import com.klarna.mobile.sdk.reactnative.checkout.KlarnaCheckoutViewManager;
|
|
11
|
+
import com.klarna.mobile.sdk.reactnative.expresscheckout.KlarnaExpressCheckoutViewManager;
|
|
11
12
|
import com.klarna.mobile.sdk.reactnative.payments.KlarnaPaymentViewManager;
|
|
12
13
|
import com.klarna.mobile.sdk.reactnative.spec.RNKlarnaSignInModuleSpec;
|
|
13
14
|
import com.klarna.mobile.sdk.reactnative.standalonewebview.KlarnaStandaloneWebViewManager;
|
|
15
|
+
import com.klarna.mobile.sdk.reactnative.osm.KlarnaOSMViewManager;
|
|
14
16
|
|
|
15
17
|
import org.junit.Assert;
|
|
16
18
|
import org.junit.Before;
|
|
@@ -48,9 +50,11 @@ public class KlarnaMobileSDKPackageTest {
|
|
|
48
50
|
List<ViewManager> nativeModules = paymentViewPackage.createViewManagers(reactContext);
|
|
49
51
|
Assert.assertNotNull(nativeModules);
|
|
50
52
|
Assert.assertFalse(nativeModules.isEmpty());
|
|
51
|
-
Assert.assertEquals(
|
|
53
|
+
Assert.assertEquals(5, nativeModules.size());
|
|
52
54
|
Assert.assertTrue(nativeModules.get(0) instanceof KlarnaPaymentViewManager);
|
|
53
55
|
Assert.assertTrue(nativeModules.get(1) instanceof KlarnaStandaloneWebViewManager);
|
|
54
56
|
Assert.assertTrue(nativeModules.get(2) instanceof KlarnaCheckoutViewManager);
|
|
57
|
+
Assert.assertTrue(nativeModules.get(3) instanceof KlarnaExpressCheckoutViewManager);
|
|
58
|
+
Assert.assertTrue(nativeModules.get(4) instanceof KlarnaOSMViewManager);
|
|
55
59
|
}
|
|
56
60
|
}
|
package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/ui/YogaLayoutHelperTest.java
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.common.ui;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
import android.view.ViewGroup;
|
|
5
|
+
|
|
6
|
+
import org.junit.Test;
|
|
7
|
+
import org.junit.runner.RunWith;
|
|
8
|
+
import org.mockito.Mockito;
|
|
9
|
+
import org.robolectric.RobolectricTestRunner;
|
|
10
|
+
|
|
11
|
+
@RunWith(RobolectricTestRunner.class)
|
|
12
|
+
public class YogaLayoutHelperTest {
|
|
13
|
+
|
|
14
|
+
// region measureAndLayout
|
|
15
|
+
|
|
16
|
+
@Test
|
|
17
|
+
public void testMeasureAndLayout_measuresChildWithExactWidthAndUnspecifiedHeight() {
|
|
18
|
+
ViewGroup wrapper = Mockito.mock(ViewGroup.class);
|
|
19
|
+
View child = Mockito.mock(View.class);
|
|
20
|
+
|
|
21
|
+
Mockito.when(wrapper.getMeasuredWidth()).thenReturn(400);
|
|
22
|
+
Mockito.when(child.getMeasuredHeight()).thenReturn(120);
|
|
23
|
+
|
|
24
|
+
YogaLayoutHelper.measureAndLayout(wrapper, child);
|
|
25
|
+
|
|
26
|
+
Mockito.verify(child).measure(
|
|
27
|
+
View.MeasureSpec.makeMeasureSpec(400, View.MeasureSpec.EXACTLY),
|
|
28
|
+
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
|
|
29
|
+
);
|
|
30
|
+
Mockito.verify(child).layout(0, 0, 400, 120);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Test
|
|
34
|
+
public void testMeasureAndLayout_skipsWhenWrapperWidthIsZero() {
|
|
35
|
+
ViewGroup wrapper = Mockito.mock(ViewGroup.class);
|
|
36
|
+
View child = Mockito.mock(View.class);
|
|
37
|
+
|
|
38
|
+
Mockito.when(wrapper.getMeasuredWidth()).thenReturn(0);
|
|
39
|
+
|
|
40
|
+
YogaLayoutHelper.measureAndLayout(wrapper, child);
|
|
41
|
+
|
|
42
|
+
Mockito.verify(child, Mockito.never()).measure(Mockito.anyInt(), Mockito.anyInt());
|
|
43
|
+
Mockito.verify(child, Mockito.never()).layout(
|
|
44
|
+
Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@Test
|
|
48
|
+
public void testMeasureAndLayout_skipsWhenWrapperWidthIsNegative() {
|
|
49
|
+
ViewGroup wrapper = Mockito.mock(ViewGroup.class);
|
|
50
|
+
View child = Mockito.mock(View.class);
|
|
51
|
+
|
|
52
|
+
Mockito.when(wrapper.getMeasuredWidth()).thenReturn(-1);
|
|
53
|
+
|
|
54
|
+
YogaLayoutHelper.measureAndLayout(wrapper, child);
|
|
55
|
+
|
|
56
|
+
Mockito.verify(child, Mockito.never()).measure(Mockito.anyInt(), Mockito.anyInt());
|
|
57
|
+
Mockito.verify(child, Mockito.never()).layout(
|
|
58
|
+
Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Test
|
|
62
|
+
public void testMeasureAndLayout_handlesZeroChildHeight() {
|
|
63
|
+
ViewGroup wrapper = Mockito.mock(ViewGroup.class);
|
|
64
|
+
View child = Mockito.mock(View.class);
|
|
65
|
+
|
|
66
|
+
Mockito.when(wrapper.getMeasuredWidth()).thenReturn(300);
|
|
67
|
+
Mockito.when(child.getMeasuredHeight()).thenReturn(0);
|
|
68
|
+
|
|
69
|
+
YogaLayoutHelper.measureAndLayout(wrapper, child);
|
|
70
|
+
|
|
71
|
+
Mockito.verify(child).measure(
|
|
72
|
+
View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY),
|
|
73
|
+
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
|
|
74
|
+
);
|
|
75
|
+
Mockito.verify(child).layout(0, 0, 300, 0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// endregion
|
|
79
|
+
}
|