@circle-fin/w3s-pw-react-native-sdk 1.1.5 → 2.0.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/BARE_REACT_NATIVE_GUIDE.md +397 -0
- package/LICENSE +1 -1
- package/README.md +196 -90
- package/android/build.gradle +43 -126
- package/android/src/main/AndroidManifest.xml +12 -16
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/ProgrammablewalletRnSdkModule.kt +414 -244
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/PromiseCallback.kt +76 -74
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/RecordsHelper.kt +602 -0
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/models/Records.kt +43 -0
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/pwcustom/RnImageSetter.kt +55 -33
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/pwcustom/RnLayoutProvider.kt +81 -79
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/pwcustom/RnViewSetterProvider.kt +93 -63
- package/app.json +8 -0
- package/build/ProgrammablewalletRnSdkModule.d.ts +44 -0
- package/build/ProgrammablewalletRnSdkModule.d.ts.map +1 -0
- package/build/ProgrammablewalletRnSdkModule.js +21 -0
- package/build/ProgrammablewalletRnSdkModule.js.map +1 -0
- package/build/WalletSdk.d.ts +20 -0
- package/build/WalletSdk.d.ts.map +1 -0
- package/build/WalletSdk.js +303 -0
- package/build/WalletSdk.js.map +1 -0
- package/build/bridgeSafe.d.ts +50 -0
- package/build/bridgeSafe.d.ts.map +1 -0
- package/build/bridgeSafe.js +136 -0
- package/build/bridgeSafe.js.map +1 -0
- package/build/index.d.ts +21 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +21 -0
- package/build/index.js.map +1 -0
- package/{lib/typescript/src → build}/types.d.ts +72 -43
- package/build/types.d.ts.map +1 -0
- package/build/types.js +331 -0
- package/build/types.js.map +1 -0
- package/build/utils/securityQuestionUtils.d.ts +43 -0
- package/build/utils/securityQuestionUtils.d.ts.map +1 -0
- package/build/utils/securityQuestionUtils.js +109 -0
- package/build/utils/securityQuestionUtils.js.map +1 -0
- package/expo-module.config.json +11 -0
- package/ios/Array+Extension.swift +17 -15
- package/ios/BridgeHelper.swift +71 -92
- package/ios/{RnWalletSdk+CustomizeAdapter.swift → CustomizeAdapter.swift} +19 -29
- package/ios/ProgrammablewalletRnSdk.podspec +30 -0
- package/ios/ProgrammablewalletRnSdkModule.swift +384 -0
- package/ios/TextConfig.swift +17 -15
- package/ios/TextKey.swift +17 -15
- package/ios/UIApplication+Extension.swift +26 -17
- package/ios/UIColor+Extension.swift +34 -28
- package/ios/UITextField+Extension.swift +31 -0
- package/ios/UIView+Extension.swift +24 -17
- package/package.json +70 -136
- package/plugins/apple-signin-entitlements.js +16 -0
- package/plugins/infoplist-config.js +77 -0
- package/plugins/infoplist-config.md +72 -0
- package/plugins/podfile-modifier.js +84 -0
- package/plugins/podfile-modifier.md +33 -0
- package/plugins/withCopyFiles.js +132 -0
- package/plugins/withCopyFiles.md +81 -0
- package/src/ProgrammablewalletRnSdkModule.ts +68 -38
- package/src/WalletSdk.ts +297 -155
- package/src/bridgeSafe.ts +156 -0
- package/src/index.ts +21 -0
- package/src/types.ts +133 -110
- package/src/utils/securityQuestionUtils.ts +121 -0
- package/COPYRIGHT +0 -10
- package/android/gradle.properties +0 -21
- package/android/src/main/AndroidManifestNew.xml +0 -22
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/BridgeHelper.kt +0 -399
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/ProgrammablewalletRnSdkPackage.kt +0 -49
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/PromiseCallback2.kt +0 -65
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/PromiseLogoutCallback.kt +0 -47
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/PromiseSocialCallback.kt +0 -53
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/TestHelper.kt +0 -37
- package/android/src/main/java/com/circlefin/programmablewalletrnsdk/annotation/ExcludeFromGeneratedCCReport.kt +0 -33
- package/android/src/newarch/ProgrammablewalletRnSdkSpec.kt +0 -29
- package/android/src/oldarch/ProgrammablewalletRnSdkSpec.kt +0 -76
- package/circlefin-w3s-pw-react-native-sdk.podspec +0 -41
- package/ios/EventEmitter.swift +0 -49
- package/ios/ProgrammablewalletRnSdk.h +0 -29
- package/ios/ProgrammablewalletRnSdk.mm +0 -162
- package/ios/ReactNativeEventEmitter.m +0 -27
- package/ios/ReactNativeEventEmitter.swift +0 -37
- package/ios/RnWalletSdk.swift +0 -385
- package/ios/programmablewallet-rn-sdk-Bridging-Header.h +0 -22
- package/lib/commonjs/NativeProgrammablewalletRnSdk.js +0 -24
- package/lib/commonjs/NativeProgrammablewalletRnSdk.js.map +0 -1
- package/lib/commonjs/ProgrammablewalletRnSdkModule.js +0 -38
- package/lib/commonjs/ProgrammablewalletRnSdkModule.js.map +0 -1
- package/lib/commonjs/WalletSdk.js +0 -206
- package/lib/commonjs/WalletSdk.js.map +0 -1
- package/lib/commonjs/index.js +0 -74
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/types.js +0 -342
- package/lib/commonjs/types.js.map +0 -1
- package/lib/module/NativeProgrammablewalletRnSdk.js +0 -19
- package/lib/module/NativeProgrammablewalletRnSdk.js.map +0 -1
- package/lib/module/ProgrammablewalletRnSdkModule.js +0 -31
- package/lib/module/ProgrammablewalletRnSdkModule.js.map +0 -1
- package/lib/module/WalletSdk.js +0 -198
- package/lib/module/WalletSdk.js.map +0 -1
- package/lib/module/index.js +0 -18
- package/lib/module/index.js.map +0 -1
- package/lib/module/types.js +0 -334
- package/lib/module/types.js.map +0 -1
- package/lib/typescript/src/NativeProgrammablewalletRnSdk.d.ts +0 -28
- package/lib/typescript/src/NativeProgrammablewalletRnSdk.d.ts.map +0 -1
- package/lib/typescript/src/ProgrammablewalletRnSdkModule.d.ts +0 -3
- package/lib/typescript/src/ProgrammablewalletRnSdkModule.d.ts.map +0 -1
- package/lib/typescript/src/WalletSdk.d.ts +0 -3
- package/lib/typescript/src/WalletSdk.d.ts.map +0 -1
- package/lib/typescript/src/index.d.ts +0 -4
- package/lib/typescript/src/index.d.ts.map +0 -1
- package/lib/typescript/src/types.d.ts.map +0 -1
- package/src/NativeProgrammablewalletRnSdk.ts +0 -77
- package/src/index.tsx +0 -29
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 Circle Internet Group, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
package com.circlefin.programmablewalletrnsdk
|
|
19
|
+
|
|
20
|
+
import android.content.Context
|
|
21
|
+
import android.graphics.Color
|
|
22
|
+
import android.graphics.Typeface
|
|
23
|
+
import android.text.TextUtils
|
|
24
|
+
import android.util.Log
|
|
25
|
+
import circle.programmablewallet.sdk.api.ApiError
|
|
26
|
+
import circle.programmablewallet.sdk.api.ExecuteWarning
|
|
27
|
+
import circle.programmablewallet.sdk.presentation.SecurityQuestion
|
|
28
|
+
import circle.programmablewallet.sdk.presentation.SettingsManagement
|
|
29
|
+
import circle.programmablewallet.sdk.presentation.TextConfig
|
|
30
|
+
import circle.programmablewallet.sdk.presentation.IconTextConfig
|
|
31
|
+
import com.circlefin.programmablewalletrnsdk.pwcustom.RnLayoutProvider
|
|
32
|
+
import circle.programmablewallet.sdk.presentation.Resource
|
|
33
|
+
import com.circlefin.programmablewalletrnsdk.pwcustom.RnImageSetter
|
|
34
|
+
import circle.programmablewallet.sdk.result.ExecuteResult
|
|
35
|
+
import circle.programmablewallet.sdk.result.LoginResult
|
|
36
|
+
import com.circlefin.programmablewalletrnsdk.models.ConfigurationRecord
|
|
37
|
+
import com.circlefin.programmablewalletrnsdk.models.SettingsManagementRecord
|
|
38
|
+
|
|
39
|
+
object RecordsHelper {
|
|
40
|
+
|
|
41
|
+
private const val INPUT_TYPE_TEXT = "text"
|
|
42
|
+
private const val INPUT_TYPE_DATE_PICKER = "datePicker"
|
|
43
|
+
|
|
44
|
+
private val typefaceMap = mutableMapOf<String, Typeface>()
|
|
45
|
+
fun convertJsSecurityQuestionsToNative(jsSecurityQuestions: Array<Any>): Array<SecurityQuestion?> {
|
|
46
|
+
return jsSecurityQuestions.mapIndexed { _, jsQuestion ->
|
|
47
|
+
try {
|
|
48
|
+
val (title, inputTypeValue) = extractSecurityQuestionData(jsQuestion)
|
|
49
|
+
|
|
50
|
+
val inputType = when (inputTypeValue) {
|
|
51
|
+
INPUT_TYPE_TEXT -> SecurityQuestion.InputType.text
|
|
52
|
+
INPUT_TYPE_DATE_PICKER -> SecurityQuestion.InputType.datePicker
|
|
53
|
+
else -> {
|
|
54
|
+
SecurityQuestion.InputType.text
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
val securityQuestion = SecurityQuestion(title, inputType)
|
|
59
|
+
securityQuestion
|
|
60
|
+
} catch (e: Exception) {
|
|
61
|
+
SecurityQuestion("", SecurityQuestion.InputType.text)
|
|
62
|
+
}
|
|
63
|
+
}.toTypedArray()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private fun extractSecurityQuestionData(jsQuestion: Any): Pair<String, String?> {
|
|
67
|
+
return when (jsQuestion) {
|
|
68
|
+
is Map<*, *> -> {
|
|
69
|
+
val title = (jsQuestion["title"] as? String) ?: ""
|
|
70
|
+
val inputType = jsQuestion["inputType"] as? String
|
|
71
|
+
Pair(title, inputType)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
is Array<*> -> {
|
|
75
|
+
if (jsQuestion.size >= 2) {
|
|
76
|
+
val title = (jsQuestion[0] as? String) ?: ""
|
|
77
|
+
val inputType = jsQuestion[1] as? String
|
|
78
|
+
Pair(title, inputType)
|
|
79
|
+
} else {
|
|
80
|
+
Pair("", null)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
else -> {
|
|
85
|
+
val title = tryExtractField(jsQuestion, "title") ?: ""
|
|
86
|
+
val inputType = tryExtractField(jsQuestion, "inputType")
|
|
87
|
+
Pair(title, inputType)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private fun tryExtractField(obj: Any, fieldName: String): String? {
|
|
93
|
+
return try {
|
|
94
|
+
/** Try direct field access */
|
|
95
|
+
val field = obj.javaClass.getDeclaredField(fieldName)
|
|
96
|
+
field.isAccessible = true
|
|
97
|
+
field.get(obj) as? String
|
|
98
|
+
} catch (e: Exception) {
|
|
99
|
+
try {
|
|
100
|
+
/** Try getter method */
|
|
101
|
+
val capitalizedName = fieldName.first().uppercaseChar() + fieldName.substring(1)
|
|
102
|
+
val getter = obj.javaClass.getMethod("get$capitalizedName")
|
|
103
|
+
getter.invoke(obj) as? String
|
|
104
|
+
} catch (e2: Exception) {
|
|
105
|
+
try {
|
|
106
|
+
/** Try public field */
|
|
107
|
+
val field = obj.javaClass.getField(fieldName)
|
|
108
|
+
field.get(obj) as? String
|
|
109
|
+
} catch (e3: Exception) {
|
|
110
|
+
null
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private fun toNativeSettingsManagement(record: SettingsManagementRecord): SettingsManagement {
|
|
117
|
+
return SettingsManagement(record.enableBiometricsPin)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fun prepareConfigurationData(record: ConfigurationRecord): Triple<String?, String?, SettingsManagement?> {
|
|
121
|
+
val endpoint = record.endpoint?.run {
|
|
122
|
+
if (this.endsWith("/")) this else "$this/"
|
|
123
|
+
}
|
|
124
|
+
val appId = record.appId
|
|
125
|
+
val settings = record.settingsManagement?.let { settingsRecord ->
|
|
126
|
+
toNativeSettingsManagement(settingsRecord)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return Triple(endpoint, appId, settings)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
fun convertToDismissOnCallbackMap(mapData: Map<String, Any>): Map<Int, Boolean> {
|
|
133
|
+
val result = mapData.mapNotNull { (key, value) ->
|
|
134
|
+
try {
|
|
135
|
+
val intKey = key.toInt()
|
|
136
|
+
val boolValue = when (value) {
|
|
137
|
+
is Boolean -> value
|
|
138
|
+
is String -> value.toBoolean()
|
|
139
|
+
is Number -> value.toInt() != 0
|
|
140
|
+
else -> false
|
|
141
|
+
}
|
|
142
|
+
intKey to boolValue
|
|
143
|
+
} catch (e: NumberFormatException) {
|
|
144
|
+
null
|
|
145
|
+
}
|
|
146
|
+
}.toMap()
|
|
147
|
+
return result
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
fun filterValidErrorCodeKeys(mapData: Map<String, Any>): Map<String, Any> {
|
|
151
|
+
return mapData.filter { (key, _) ->
|
|
152
|
+
// Check if key is a valid integer string or ErrorCode name
|
|
153
|
+
try {
|
|
154
|
+
key.toInt()
|
|
155
|
+
true
|
|
156
|
+
} catch (e: NumberFormatException) {
|
|
157
|
+
errorCodeStringToIntMap.containsKey(key)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
fun convertToErrorStringMap(mapData: Map<String, Any>): Map<Int, String> {
|
|
163
|
+
val result = mapData.map { (key, value) ->
|
|
164
|
+
// Convert key to Int (keys are pre-validated by filterValidErrorCodeKeys)
|
|
165
|
+
val intKey: Int = try {
|
|
166
|
+
key.toInt()
|
|
167
|
+
} catch (e: NumberFormatException) {
|
|
168
|
+
// If not an integer string, map from error code string
|
|
169
|
+
errorCodeStringToIntMap[key] ?: throw IllegalArgumentException("Invalid ErrorCode key: $key")
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
val stringValue = when (value) {
|
|
173
|
+
is String -> value
|
|
174
|
+
else -> value.toString()
|
|
175
|
+
}
|
|
176
|
+
intKey to stringValue
|
|
177
|
+
}.toMap()
|
|
178
|
+
return result
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private val errorCodeStringToIntMap = mapOf(
|
|
182
|
+
"unknown" to -1,
|
|
183
|
+
"success" to 0,
|
|
184
|
+
"apiParameterMissing" to 1,
|
|
185
|
+
"apiParameterInvalid" to 2,
|
|
186
|
+
"forbidden" to 3,
|
|
187
|
+
"unauthorized" to 4,
|
|
188
|
+
"retry" to 9,
|
|
189
|
+
"customerSuspended" to 10,
|
|
190
|
+
"pending" to 11,
|
|
191
|
+
"invalidSession" to 12,
|
|
192
|
+
"invalidPartnerId" to 13,
|
|
193
|
+
"invalidMessage" to 14,
|
|
194
|
+
"invalidPhone" to 15,
|
|
195
|
+
"walletIdNotFound" to 156001,
|
|
196
|
+
"tokenIdNotFound" to 156002,
|
|
197
|
+
"transactionIdNotFound" to 156003,
|
|
198
|
+
"walletSetIdNotFound" to 156004,
|
|
199
|
+
"notEnoughFounds" to 155201,
|
|
200
|
+
"notEnoughBalance" to 155202,
|
|
201
|
+
"exceedWithdrawLimit" to 155203,
|
|
202
|
+
"minimumFundsRequired" to 155204,
|
|
203
|
+
"invalidTransactionFee" to 155205,
|
|
204
|
+
"rejectedOnAmlScreening" to 155206,
|
|
205
|
+
"tagRequired" to 155207,
|
|
206
|
+
"gasLimitTooLow" to 155208,
|
|
207
|
+
"transactionDataNotEncodedProperly" to 155209,
|
|
208
|
+
"fullNodeReturnedError" to 155210,
|
|
209
|
+
"walletSetupRequired" to 155211,
|
|
210
|
+
"lowerThenMinimumAccountBalance" to 155212,
|
|
211
|
+
"rejectedByBlockchain" to 155213,
|
|
212
|
+
"droppedAsPartOfReorg" to 155214,
|
|
213
|
+
"operationNotSupport" to 155215,
|
|
214
|
+
"amountBelowMinimum" to 155216,
|
|
215
|
+
"wrongNftTokenIdNumber" to 155217,
|
|
216
|
+
"invalidDestinationAddress" to 155218,
|
|
217
|
+
"tokenWalletChainMismatch" to 155219,
|
|
218
|
+
"wrongAmountsNumber" to 155220,
|
|
219
|
+
"userAlreadyExisted" to 155101,
|
|
220
|
+
"userNotFound" to 155102,
|
|
221
|
+
"userTokenNotFound" to 155103,
|
|
222
|
+
"userTokenExpired" to 155104,
|
|
223
|
+
"invalidUserToken" to 155105,
|
|
224
|
+
"userWasInitialized" to 155106,
|
|
225
|
+
"userHasSetPin" to 155107,
|
|
226
|
+
"userHasSetSecurityQuestion" to 155108,
|
|
227
|
+
"userWasDisabled" to 155109,
|
|
228
|
+
"userDoesNotSetPinYet" to 155110,
|
|
229
|
+
"userDoesNotSetSecurityQuestionYet" to 155111,
|
|
230
|
+
"incorrectUserPin" to 155112,
|
|
231
|
+
"incorrectDeviceId" to 155113,
|
|
232
|
+
"incorrectAppId" to 155114,
|
|
233
|
+
"incorrectSecurityAnswers" to 155115,
|
|
234
|
+
"invalidChallengeId" to 155116,
|
|
235
|
+
"invalidApproveContent" to 155117,
|
|
236
|
+
"invalidEncryptionKey" to 155118,
|
|
237
|
+
"userPinLocked" to 155119,
|
|
238
|
+
"securityAnswersLocked" to 155120,
|
|
239
|
+
"walletIsFrozen" to 155501,
|
|
240
|
+
"maxWalletLimitReached" to 155502,
|
|
241
|
+
"walletSetIdMutuallyExclusive" to 155503,
|
|
242
|
+
"metadataUnmatched" to 155504,
|
|
243
|
+
"userCanceled" to 155701,
|
|
244
|
+
"launchUiFailed" to 155702,
|
|
245
|
+
"pinCodeNotMatched" to 155703,
|
|
246
|
+
"insecurePinCode" to 155704,
|
|
247
|
+
"hintsMatchAnswers" to 155705,
|
|
248
|
+
"networkError" to 155706,
|
|
249
|
+
"biometricsSettingNotEnabled" to 155708,
|
|
250
|
+
"deviceNotSupportBiometrics" to 155709,
|
|
251
|
+
"biometricsKeyPermanentlyInvalidated" to 155710,
|
|
252
|
+
"biometricsUserSkip" to 155711,
|
|
253
|
+
"biometricsUserDisableForPin" to 155712,
|
|
254
|
+
"biometricsUserLockout" to 155713,
|
|
255
|
+
"biometricsUserLockoutPermanent" to 155714,
|
|
256
|
+
"biometricsUserNotAllowPermission" to 155715,
|
|
257
|
+
"biometricsInternalError" to 155716,
|
|
258
|
+
"userSecretMissing" to 155717,
|
|
259
|
+
"invalidUserTokenFormat" to 155718,
|
|
260
|
+
"userTokenMismatch" to 155719,
|
|
261
|
+
"socialLoginFailed" to 155720,
|
|
262
|
+
"loginInfoMissing" to 155721
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
fun convertToImageMap(context: Context, mapData: Map<String, Any>): Map<String, String> {
|
|
266
|
+
val result = mapData.mapNotNull { (key, value) ->
|
|
267
|
+
try {
|
|
268
|
+
val imageUrl = when (value) {
|
|
269
|
+
is String -> value
|
|
270
|
+
else -> value.toString()
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Map TypeScript ImageKey enum values to their actual enum names
|
|
274
|
+
// Some ImageKey values use different names than expected
|
|
275
|
+
val mappedKey = when (key) {
|
|
276
|
+
"back" -> "back" // This maps to ToolbarIcon.back
|
|
277
|
+
"close" -> "close" // This maps to ToolbarIcon.close
|
|
278
|
+
else -> key // Most keys should match Resource.Icon enum names directly
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
mappedKey to imageUrl
|
|
282
|
+
} catch (e: Exception) {
|
|
283
|
+
Log.e("RecordsHelper", "Failed to process image map entry for key: '$key', value: '$value'", e)
|
|
284
|
+
null
|
|
285
|
+
}
|
|
286
|
+
}.toMap()
|
|
287
|
+
return result
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private fun convertExecuteResultToMap(result: ExecuteResult): Map<String, Any?> {
|
|
291
|
+
return mapOf(
|
|
292
|
+
"resultType" to result.resultType?.name,
|
|
293
|
+
"status" to result.status?.name,
|
|
294
|
+
"data" to result.data?.let { data ->
|
|
295
|
+
mapOf(
|
|
296
|
+
"signature" to data.signature,
|
|
297
|
+
"signedTransaction" to data.signedTransaction,
|
|
298
|
+
"txHash" to data.txHash
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
fun convertApiErrorToMap(error: ApiError): Map<String, Any?> {
|
|
305
|
+
// Check if there's a custom error message set via setErrorStringMap
|
|
306
|
+
val customMessage = RnLayoutProvider.getErrorString(error.code)
|
|
307
|
+
val messageToUse = customMessage ?: error.message
|
|
308
|
+
|
|
309
|
+
return mapOf(
|
|
310
|
+
"code" to error.code.value,
|
|
311
|
+
"message" to messageToUse
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
fun convertExecuteWarningToMap(warning: ExecuteWarning): Map<String, Any?> {
|
|
316
|
+
return mapOf(
|
|
317
|
+
"warningType" to warning.warningType,
|
|
318
|
+
"warningString" to warning.warningString
|
|
319
|
+
)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
fun convertResultToMap(result: Any?): Map<String, Any?> {
|
|
323
|
+
return when (result) {
|
|
324
|
+
null -> emptyMap()
|
|
325
|
+
is ExecuteResult -> convertExecuteResultToMap(result)
|
|
326
|
+
is LoginResult -> convertLoginResultToMap(result)
|
|
327
|
+
is Map<*, *> -> {
|
|
328
|
+
@Suppress("UNCHECKED_CAST")
|
|
329
|
+
result as Map<String, Any?>
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
else -> {
|
|
333
|
+
try {
|
|
334
|
+
mapOf("data" to result.toString())
|
|
335
|
+
} catch (e: Exception) {
|
|
336
|
+
mapOf("data" to result.toString())
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
private fun convertLoginResultToMap(loginResult: LoginResult): Map<String, Any?> {
|
|
343
|
+
val resultMap = mutableMapOf<String, Any?>()
|
|
344
|
+
|
|
345
|
+
loginResult.userToken?.let { resultMap["userToken"] = it }
|
|
346
|
+
loginResult.encryptionKey?.let { resultMap["encryptionKey"] = it }
|
|
347
|
+
loginResult.refreshToken?.let { resultMap["refreshToken"] = it }
|
|
348
|
+
|
|
349
|
+
loginResult.oauthInfo?.let { oauthInfo ->
|
|
350
|
+
val oauthMap = mutableMapOf<String, Any?>()
|
|
351
|
+
oauthInfo.provider?.let { oauthMap["provider"] = it }
|
|
352
|
+
oauthInfo.scope?.let { oauthMap["scope"] = it }
|
|
353
|
+
oauthInfo.socialUserUUID?.let { oauthMap["socialUserUUID"] = it }
|
|
354
|
+
|
|
355
|
+
oauthInfo.socialUserInfo?.let { userInfo ->
|
|
356
|
+
val userInfoMap = mutableMapOf<String, Any?>()
|
|
357
|
+
userInfo.name?.let { userInfoMap["name"] = it }
|
|
358
|
+
userInfo.email?.let { userInfoMap["email"] = it }
|
|
359
|
+
userInfo.phone?.let { userInfoMap["phone"] = it }
|
|
360
|
+
if (userInfoMap.isNotEmpty()) {
|
|
361
|
+
oauthMap["socialUserInfo"] = userInfoMap
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (oauthMap.isNotEmpty()) {
|
|
366
|
+
resultMap["oauthInfo"] = oauthMap
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return resultMap
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
fun convertToTextConfigsMap(context: Context, mapData: Map<String, Any>): Map<String, Array<TextConfig?>> {
|
|
374
|
+
val resultMap = mutableMapOf<String, Array<TextConfig?>>()
|
|
375
|
+
|
|
376
|
+
for ((key, value) in mapData) {
|
|
377
|
+
when (value) {
|
|
378
|
+
is List<*> -> {
|
|
379
|
+
val textConfigs = mutableListOf<TextConfig?>()
|
|
380
|
+
for (item in value) {
|
|
381
|
+
val textConfig = convertToTextConfig(context, item)
|
|
382
|
+
textConfigs.add(textConfig)
|
|
383
|
+
}
|
|
384
|
+
resultMap[key] = textConfigs.toTypedArray()
|
|
385
|
+
}
|
|
386
|
+
is Array<*> -> {
|
|
387
|
+
val textConfigs = mutableListOf<TextConfig?>()
|
|
388
|
+
for (item in value) {
|
|
389
|
+
val textConfig = convertToTextConfig(context, item)
|
|
390
|
+
textConfigs.add(textConfig)
|
|
391
|
+
}
|
|
392
|
+
resultMap[key] = textConfigs.toTypedArray()
|
|
393
|
+
}
|
|
394
|
+
else -> {
|
|
395
|
+
// If it's not a collection, treat it as a single TextConfig
|
|
396
|
+
val textConfig = convertToTextConfig(context, value)
|
|
397
|
+
resultMap[key] = arrayOf(textConfig)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return resultMap
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
fun convertToTextConfigMap(context: Context, mapData: Map<String, Any>): Map<String, TextConfig> {
|
|
406
|
+
val resultMap = mutableMapOf<String, TextConfig>()
|
|
407
|
+
|
|
408
|
+
for ((key, value) in mapData) {
|
|
409
|
+
val textConfig = convertToTextConfig(context, value)
|
|
410
|
+
textConfig?.let {
|
|
411
|
+
resultMap[key] = it
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return resultMap
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
fun convertToIconTextConfigsMap(context: Context, mapData: Map<String, Any>): Map<Resource.IconTextsKey, Array<IconTextConfig?>> {
|
|
419
|
+
val resultMap = mutableMapOf<Resource.IconTextsKey, Array<IconTextConfig?>>()
|
|
420
|
+
|
|
421
|
+
for ((key, value) in mapData) {
|
|
422
|
+
try {
|
|
423
|
+
val enumKey = Resource.IconTextsKey.valueOf(key)
|
|
424
|
+
|
|
425
|
+
when (value) {
|
|
426
|
+
is List<*> -> {
|
|
427
|
+
val iconTextConfigs = mutableListOf<IconTextConfig?>()
|
|
428
|
+
for (item in value) {
|
|
429
|
+
val iconTextConfig = createIconTextConfig(context, item)
|
|
430
|
+
iconTextConfigs.add(iconTextConfig)
|
|
431
|
+
}
|
|
432
|
+
resultMap[enumKey] = iconTextConfigs.toTypedArray()
|
|
433
|
+
}
|
|
434
|
+
is Array<*> -> {
|
|
435
|
+
val iconTextConfigs = mutableListOf<IconTextConfig?>()
|
|
436
|
+
for (item in value) {
|
|
437
|
+
val iconTextConfig = createIconTextConfig(context, item)
|
|
438
|
+
iconTextConfigs.add(iconTextConfig)
|
|
439
|
+
}
|
|
440
|
+
resultMap[enumKey] = iconTextConfigs.toTypedArray()
|
|
441
|
+
}
|
|
442
|
+
else -> {
|
|
443
|
+
val iconTextConfig = createIconTextConfig(context, value)
|
|
444
|
+
resultMap[enumKey] = arrayOf(iconTextConfig)
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
} catch (e: Exception) {
|
|
448
|
+
continue
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return resultMap
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Creates an IconTextConfig using the map data.
|
|
457
|
+
*
|
|
458
|
+
* @param context The Android context.
|
|
459
|
+
* @param data The input data, expected to be a map with the following structure:
|
|
460
|
+
* - "image": A string representing the image URL (optional).
|
|
461
|
+
* - "textConfig": An object that can be converted to a TextConfig instance (optional).
|
|
462
|
+
* If the input is not a map or does not contain these keys, the function will attempt
|
|
463
|
+
* to create a TextConfig from the data directly.
|
|
464
|
+
* @return An IconTextConfig instance if the input data is valid, or null otherwise.
|
|
465
|
+
*/
|
|
466
|
+
private fun createIconTextConfig(context: Context, data: Any?): IconTextConfig? {
|
|
467
|
+
if (data == null) return null
|
|
468
|
+
|
|
469
|
+
return when (data) {
|
|
470
|
+
is Map<*, *> -> {
|
|
471
|
+
@Suppress("UNCHECKED_CAST")
|
|
472
|
+
val dataMap = data as Map<String, Any?>
|
|
473
|
+
|
|
474
|
+
val imageUrl = dataMap["image"] as? String
|
|
475
|
+
|
|
476
|
+
val textConfigData = dataMap["textConfig"]
|
|
477
|
+
val textConfig = if (textConfigData != null) {
|
|
478
|
+
convertToTextConfig(context, textConfigData)
|
|
479
|
+
} else {
|
|
480
|
+
null
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
try {
|
|
484
|
+
val setter = if (imageUrl != null) {
|
|
485
|
+
RnImageSetter(imageUrl)
|
|
486
|
+
} else {
|
|
487
|
+
null
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
IconTextConfig(setter, textConfig)
|
|
491
|
+
} catch (e: Exception) {
|
|
492
|
+
null
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
else -> {
|
|
496
|
+
try {
|
|
497
|
+
val textConfig = convertToTextConfig(context, data)
|
|
498
|
+
IconTextConfig(null, textConfig)
|
|
499
|
+
} catch (e: Exception) {
|
|
500
|
+
null
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
private fun convertToTextConfig(context: Context, data: Any?): TextConfig? {
|
|
507
|
+
if (data == null) return null
|
|
508
|
+
|
|
509
|
+
return when (data) {
|
|
510
|
+
is Map<*, *> -> {
|
|
511
|
+
@Suppress("UNCHECKED_CAST")
|
|
512
|
+
val dataMap = data as Map<String, Any?>
|
|
513
|
+
|
|
514
|
+
val text = dataMap["text"] as? String
|
|
515
|
+
val gradientColors = convertToGradientColors(dataMap["gradientColors"])
|
|
516
|
+
val font = dataMap["font"] as? String
|
|
517
|
+
val textColor = dataMap["textColor"] as? String
|
|
518
|
+
|
|
519
|
+
val textConfig = TextConfig(text, gradientColors, getTypeface(context, font))
|
|
520
|
+
textConfig.textColor = getColor(textColor)
|
|
521
|
+
textConfig
|
|
522
|
+
}
|
|
523
|
+
is String -> {
|
|
524
|
+
TextConfig(data, null, null)
|
|
525
|
+
}
|
|
526
|
+
else -> {
|
|
527
|
+
try {
|
|
528
|
+
val stringValue = data.toString()
|
|
529
|
+
if (stringValue.isNotEmpty() && stringValue != "null") {
|
|
530
|
+
TextConfig(stringValue, null, null)
|
|
531
|
+
} else {
|
|
532
|
+
null
|
|
533
|
+
}
|
|
534
|
+
} catch (e: Exception) {
|
|
535
|
+
null
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
private fun convertToGradientColors(colorsData: Any?): IntArray? {
|
|
542
|
+
if (colorsData == null) return null
|
|
543
|
+
|
|
544
|
+
return when (colorsData) {
|
|
545
|
+
is List<*> -> {
|
|
546
|
+
colorsData.mapNotNull { colorStr ->
|
|
547
|
+
try {
|
|
548
|
+
getColor(colorStr as? String)
|
|
549
|
+
} catch (e: Exception) {
|
|
550
|
+
null
|
|
551
|
+
}
|
|
552
|
+
}.toIntArray()
|
|
553
|
+
}
|
|
554
|
+
is Array<*> -> {
|
|
555
|
+
colorsData.mapNotNull { colorStr ->
|
|
556
|
+
try {
|
|
557
|
+
getColor(colorStr as? String)
|
|
558
|
+
} catch (e: Exception) {
|
|
559
|
+
null
|
|
560
|
+
}
|
|
561
|
+
}.toIntArray()
|
|
562
|
+
}
|
|
563
|
+
else -> null
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private fun getColor(colorStr: String?): Int {
|
|
568
|
+
return try {
|
|
569
|
+
if (TextUtils.isEmpty(colorStr)) {
|
|
570
|
+
0
|
|
571
|
+
} else Color.parseColor(colorStr)
|
|
572
|
+
} catch (e: Exception) {
|
|
573
|
+
0
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
private fun getTypeface(context: Context, fontFamilyName: String?): Typeface? {
|
|
578
|
+
if (TextUtils.isEmpty(fontFamilyName)) {
|
|
579
|
+
return null
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (typefaceMap[fontFamilyName] != null) {
|
|
583
|
+
return typefaceMap[fontFamilyName]
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
val fileExtensions = arrayOf(".ttf", ".otf")
|
|
587
|
+
val fontsAssetPath = "fonts/"
|
|
588
|
+
|
|
589
|
+
for (fileExtension in fileExtensions) {
|
|
590
|
+
try {
|
|
591
|
+
val fileName = fontsAssetPath + fontFamilyName!! + fileExtension
|
|
592
|
+
val typeface = Typeface.createFromAsset(context.assets, fileName)
|
|
593
|
+
typefaceMap[fontFamilyName] = typeface
|
|
594
|
+
return typeface
|
|
595
|
+
} catch (e: Exception) {
|
|
596
|
+
// If the typeface asset does not exist, try another extension.
|
|
597
|
+
continue
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return null
|
|
601
|
+
}
|
|
602
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 Circle Internet Group, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
package com.circlefin.programmablewalletrnsdk.models
|
|
19
|
+
|
|
20
|
+
import expo.modules.kotlin.records.Field
|
|
21
|
+
import expo.modules.kotlin.records.Record
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Record for settings management configuration
|
|
25
|
+
*/
|
|
26
|
+
class SettingsManagementRecord : Record {
|
|
27
|
+
@Field
|
|
28
|
+
val enableBiometricsPin: Boolean = false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Record for wallet SDK configuration
|
|
33
|
+
*/
|
|
34
|
+
class ConfigurationRecord : Record {
|
|
35
|
+
@Field
|
|
36
|
+
val endpoint: String? = null
|
|
37
|
+
|
|
38
|
+
@Field
|
|
39
|
+
val appId: String? = null
|
|
40
|
+
|
|
41
|
+
@Field
|
|
42
|
+
val settingsManagement: SettingsManagementRecord? = null
|
|
43
|
+
}
|