expo-modules-core 2.3.12 → 2.4.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/CHANGELOG.md +26 -0
- package/android/build.gradle +2 -2
- package/android/src/main/cpp/JSharedObject.cpp +1 -1
- package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +22 -11
- package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +9 -1
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +6 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +28 -24
- package/android/src/main/java/expo/modules/kotlin/jni/ExpectedType.kt +122 -5
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +6 -1
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleConvertersBuilder.kt +50 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +31 -7
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +28 -30
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +15 -0
- package/android/src/main/java/expo/modules/kotlin/traits/SavableTrait.kt +57 -0
- package/android/src/main/java/expo/modules/kotlin/traits/Trait.kt +8 -0
- package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +9 -0
- package/android/src/main/java/expo/modules/kotlin/types/EitherTypeConverter.kt +3 -3
- package/android/src/main/java/expo/modules/kotlin/types/ExpoDynamic.kt +57 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterCollection.kt +81 -0
- package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +18 -3
- package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +40 -25
- package/ios/Api/Factories/ViewFactories.swift +16 -0
- package/ios/Core/Conversions.swift +51 -7
- package/ios/Core/Convertibles/Convertibles+Color.swift +1 -1
- package/ios/Core/DynamicTypes/DynamicSharedObjectType.swift +25 -14
- package/ios/Core/Functions/AsyncFunctionDefinition.swift +1 -1
- package/ios/Core/Promise.swift +0 -11
- package/ios/Core/Views/ConcreteViewProp.swift +16 -0
- package/ios/Core/Views/SwiftUI/Convertibles+SwiftUI.swift +62 -0
- package/ios/Core/Views/SwiftUI/SwiftUIHostingView.swift +7 -0
- package/ios/DevTools/ExpoRequestInterceptorProtocol.swift +40 -0
- package/ios/DevTools/ModuleDefinitionEncoder.swift +182 -0
- package/ios/DevTools/URLSessionSessionDelegateProxy.swift +17 -0
- package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
- package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +1 -1
- package/ios/Tests/FunctionSpec.swift +27 -1
- package/package.json +3 -3
|
@@ -19,6 +19,7 @@ import expo.modules.kotlin.functions.AsyncFunctionWithPromiseComponent
|
|
|
19
19
|
import expo.modules.kotlin.functions.Queues
|
|
20
20
|
import expo.modules.kotlin.functions.createAsyncFunctionComponent
|
|
21
21
|
import expo.modules.kotlin.modules.DefinitionMarker
|
|
22
|
+
import expo.modules.kotlin.types.TypeConverterProvider
|
|
22
23
|
import expo.modules.kotlin.types.enforceType
|
|
23
24
|
import expo.modules.kotlin.types.toAnyType
|
|
24
25
|
import expo.modules.kotlin.types.toArgsArray
|
|
@@ -28,7 +29,8 @@ import kotlin.reflect.KType
|
|
|
28
29
|
@DefinitionMarker
|
|
29
30
|
class ViewDefinitionBuilder<T : View>(
|
|
30
31
|
@PublishedApi internal val viewClass: KClass<T>,
|
|
31
|
-
@PublishedApi internal val viewType: KType
|
|
32
|
+
@PublishedApi internal val viewType: KType,
|
|
33
|
+
@PublishedApi internal val converters: TypeConverterProvider? = null
|
|
32
34
|
) {
|
|
33
35
|
@PublishedApi
|
|
34
36
|
internal var name = viewClass.simpleName
|
|
@@ -144,6 +146,23 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
144
146
|
)
|
|
145
147
|
}
|
|
146
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Creates a view prop that defines its name, default value and setter.
|
|
151
|
+
*/
|
|
152
|
+
@JvmName("PropGeneric")
|
|
153
|
+
inline fun <reified ViewType : View, reified PropType> Prop(
|
|
154
|
+
name: String,
|
|
155
|
+
defaultValue: PropType,
|
|
156
|
+
noinline body: (view: ViewType, prop: PropType) -> Unit
|
|
157
|
+
) {
|
|
158
|
+
props[name] = ConcreteViewPropWithDefault(
|
|
159
|
+
name,
|
|
160
|
+
toAnyType<PropType>(),
|
|
161
|
+
body,
|
|
162
|
+
defaultValue
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
147
166
|
inline fun <reified ViewType : View, reified PropType, reified CustomValueType> PropGroup(
|
|
148
167
|
vararg props: Pair<String, CustomValueType>,
|
|
149
168
|
noinline body: (view: ViewType, value: CustomValueType, prop: PropType) -> Unit
|
|
@@ -229,7 +248,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
229
248
|
name: String,
|
|
230
249
|
crossinline body: (p0: P0, p1: P1) -> R
|
|
231
250
|
): AsyncFunctionComponent {
|
|
232
|
-
return createAsyncFunctionComponent(name, toArgsArray<P0, P1>()) { (p0, p1) ->
|
|
251
|
+
return createAsyncFunctionComponent(name, toArgsArray<P0, P1>(converterProvider = converters)) { (p0, p1) ->
|
|
233
252
|
enforceType<P0, P1>(p0, p1)
|
|
234
253
|
body(p0, p1)
|
|
235
254
|
}.also {
|
|
@@ -242,7 +261,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
242
261
|
name: String,
|
|
243
262
|
crossinline body: (p0: P0, p1: Promise) -> R
|
|
244
263
|
): AsyncFunctionComponent {
|
|
245
|
-
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0>()) { (p0), promise ->
|
|
264
|
+
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0>(converterProvider = converters)) { (p0), promise ->
|
|
246
265
|
enforceType<P0>(p0)
|
|
247
266
|
body(p0, promise)
|
|
248
267
|
}.also {
|
|
@@ -254,7 +273,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
254
273
|
name: String,
|
|
255
274
|
crossinline body: (p0: P0, p1: P1, p2: P2) -> R
|
|
256
275
|
): AsyncFunctionComponent {
|
|
257
|
-
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2) ->
|
|
276
|
+
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2>(converterProvider = converters)) { (p0, p1, p2) ->
|
|
258
277
|
enforceType<P0, P1, P2>(p0, p1, p2)
|
|
259
278
|
body(p0, p1, p2)
|
|
260
279
|
}.also {
|
|
@@ -267,7 +286,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
267
286
|
name: String,
|
|
268
287
|
crossinline body: (p0: P0, p1: P1, p2: Promise) -> R
|
|
269
288
|
): AsyncFunctionComponent {
|
|
270
|
-
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1>()) { (p0, p1), promise ->
|
|
289
|
+
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1>(converterProvider = converters)) { (p0, p1), promise ->
|
|
271
290
|
enforceType<P0, P1>(p0, p1)
|
|
272
291
|
body(p0, p1, promise)
|
|
273
292
|
}.also {
|
|
@@ -279,7 +298,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
279
298
|
name: String,
|
|
280
299
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R
|
|
281
300
|
): AsyncFunctionComponent {
|
|
282
|
-
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3) ->
|
|
301
|
+
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>(converterProvider = converters)) { (p0, p1, p2, p3) ->
|
|
283
302
|
enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
|
|
284
303
|
body(p0, p1, p2, p3)
|
|
285
304
|
}.also {
|
|
@@ -292,7 +311,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
292
311
|
name: String,
|
|
293
312
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: Promise) -> R
|
|
294
313
|
): AsyncFunctionComponent {
|
|
295
|
-
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2), promise ->
|
|
314
|
+
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2>(converterProvider = converters)) { (p0, p1, p2), promise ->
|
|
296
315
|
enforceType<P0, P1, P2>(p0, p1, p2)
|
|
297
316
|
body(p0, p1, p2, promise)
|
|
298
317
|
}.also {
|
|
@@ -304,7 +323,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
304
323
|
name: String,
|
|
305
324
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R
|
|
306
325
|
): AsyncFunctionComponent {
|
|
307
|
-
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4) ->
|
|
326
|
+
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>(converterProvider = converters)) { (p0, p1, p2, p3, p4) ->
|
|
308
327
|
enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
|
|
309
328
|
body(p0, p1, p2, p3, p4)
|
|
310
329
|
}.also {
|
|
@@ -317,7 +336,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
317
336
|
name: String,
|
|
318
337
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: Promise) -> R
|
|
319
338
|
): AsyncFunctionComponent {
|
|
320
|
-
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3), promise ->
|
|
339
|
+
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3>(converterProvider = converters)) { (p0, p1, p2, p3), promise ->
|
|
321
340
|
enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
|
|
322
341
|
body(p0, p1, p2, p3, promise)
|
|
323
342
|
}.also {
|
|
@@ -329,7 +348,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
329
348
|
name: String,
|
|
330
349
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R
|
|
331
350
|
): AsyncFunctionComponent {
|
|
332
|
-
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5) ->
|
|
351
|
+
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5) ->
|
|
333
352
|
enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
|
|
334
353
|
body(p0, p1, p2, p3, p4, p5)
|
|
335
354
|
}.also {
|
|
@@ -342,7 +361,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
342
361
|
name: String,
|
|
343
362
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: Promise) -> R
|
|
344
363
|
): AsyncFunctionComponent {
|
|
345
|
-
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4), promise ->
|
|
364
|
+
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4>(converterProvider = converters)) { (p0, p1, p2, p3, p4), promise ->
|
|
346
365
|
enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
|
|
347
366
|
body(p0, p1, p2, p3, p4, promise)
|
|
348
367
|
}.also {
|
|
@@ -354,7 +373,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
354
373
|
name: String,
|
|
355
374
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R
|
|
356
375
|
): AsyncFunctionComponent {
|
|
357
|
-
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6) ->
|
|
376
|
+
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5, p6) ->
|
|
358
377
|
enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
|
|
359
378
|
body(p0, p1, p2, p3, p4, p5, p6)
|
|
360
379
|
}.also {
|
|
@@ -367,7 +386,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
367
386
|
name: String,
|
|
368
387
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: Promise) -> R
|
|
369
388
|
): AsyncFunctionComponent {
|
|
370
|
-
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5), promise ->
|
|
389
|
+
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5), promise ->
|
|
371
390
|
enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
|
|
372
391
|
body(p0, p1, p2, p3, p4, p5, promise)
|
|
373
392
|
}.also {
|
|
@@ -379,7 +398,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
379
398
|
name: String,
|
|
380
399
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R
|
|
381
400
|
): AsyncFunctionComponent {
|
|
382
|
-
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>()) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
|
|
401
|
+
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
|
|
383
402
|
enforceType<P0, P1, P2, P3, P4, P5, P6, P7>(p0, p1, p2, p3, p4, p5, p6, p7)
|
|
384
403
|
body(p0, p1, p2, p3, p4, p5, p6, p7)
|
|
385
404
|
}.also {
|
|
@@ -392,7 +411,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
392
411
|
name: String,
|
|
393
412
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: Promise) -> R
|
|
394
413
|
): AsyncFunctionComponent {
|
|
395
|
-
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6), promise ->
|
|
414
|
+
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>(converterProvider = converters)) { (p0, p1, p2, p3, p4, p5, p6), promise ->
|
|
396
415
|
enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
|
|
397
416
|
body(p0, p1, p2, p3, p4, p5, p6, promise)
|
|
398
417
|
}.also {
|
|
@@ -402,14 +421,14 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
402
421
|
|
|
403
422
|
fun AsyncFunction(
|
|
404
423
|
name: String
|
|
405
|
-
) = AsyncFunctionBuilder(name).also { functionBuilders[name] = it }
|
|
424
|
+
) = AsyncFunctionBuilder(name, converters).also { functionBuilders[name] = it }
|
|
406
425
|
|
|
407
426
|
private fun createViewFactory(): (Context, AppContext) -> View =
|
|
408
427
|
viewFactory@{ context: Context, appContext: AppContext ->
|
|
409
428
|
val fullConstructor = try {
|
|
410
429
|
// Try to use constructor with two arguments
|
|
411
430
|
viewClass.java.getConstructor(Context::class.java, AppContext::class.java)
|
|
412
|
-
} catch (
|
|
431
|
+
} catch (_: NoSuchMethodException) {
|
|
413
432
|
null
|
|
414
433
|
}
|
|
415
434
|
|
|
@@ -424,7 +443,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
424
443
|
val contextConstructor = try {
|
|
425
444
|
// Try to use constructor that use Android's context
|
|
426
445
|
viewClass.java.getConstructor(Context::class.java)
|
|
427
|
-
} catch (
|
|
446
|
+
} catch (_: NoSuchMethodException) {
|
|
428
447
|
null
|
|
429
448
|
}
|
|
430
449
|
|
|
@@ -439,15 +458,11 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
439
458
|
throw IllegalStateException("Didn't find a correct constructor for $viewClass")
|
|
440
459
|
}
|
|
441
460
|
|
|
442
|
-
private fun handleFailureDuringViewCreation(context: Context, appContext: AppContext,
|
|
443
|
-
Log.e("ExpoModulesCore", "Couldn't create view of type $viewClass",
|
|
461
|
+
private fun handleFailureDuringViewCreation(context: Context, appContext: AppContext, error: Throwable): View {
|
|
462
|
+
Log.e("ExpoModulesCore", "Couldn't create view of type $viewClass", error)
|
|
444
463
|
|
|
445
464
|
appContext.errorManager?.reportExceptionToLogBox(
|
|
446
|
-
|
|
447
|
-
e
|
|
448
|
-
} else {
|
|
449
|
-
UnexpectedException(e)
|
|
450
|
-
}
|
|
465
|
+
error as? CodedException ?: UnexpectedException(error)
|
|
451
466
|
)
|
|
452
467
|
|
|
453
468
|
return if (ViewGroup::class.java.isAssignableFrom(viewClass.java)) {
|
|
@@ -46,6 +46,22 @@ public func Prop<ViewType: UIView, PropType: AnyArgument>(
|
|
|
46
46
|
)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
Creates a view prop that defines its name, default value and setter.
|
|
51
|
+
*/
|
|
52
|
+
public func Prop<ViewType: UIView, PropType: AnyArgument>(
|
|
53
|
+
_ name: String,
|
|
54
|
+
_ defaultValue: PropType,
|
|
55
|
+
@_implicitSelfCapture _ setter: @escaping (ViewType, PropType) -> Void
|
|
56
|
+
) -> ConcreteViewProp<ViewType, PropType> {
|
|
57
|
+
return ConcreteViewProp(
|
|
58
|
+
name: name,
|
|
59
|
+
propType: ~PropType.self,
|
|
60
|
+
defaultValue: defaultValue,
|
|
61
|
+
setter: setter
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
// MARK: - View lifecycle
|
|
50
66
|
|
|
51
67
|
/**
|
|
@@ -77,11 +77,17 @@ public struct Conversions {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
Converts
|
|
80
|
+
Converts color string to `UIColor` or throws an exception if the string is corrupted.
|
|
81
81
|
*/
|
|
82
|
-
static func toColor(
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
static func toColor(colorString: String) throws -> UIColor {
|
|
83
|
+
let input = colorString.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
84
|
+
|
|
85
|
+
// Handle RGB format
|
|
86
|
+
if input.hasPrefix("rgb") {
|
|
87
|
+
return try fromRGBString(input)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
var hexStr = input
|
|
85
91
|
.replacingOccurrences(of: "#", with: "")
|
|
86
92
|
|
|
87
93
|
// If just RGB, set alpha to maximum
|
|
@@ -103,11 +109,33 @@ public struct Conversions {
|
|
|
103
109
|
|
|
104
110
|
guard hexStr.range(of: #"^[0-9a-fA-F]{8}$"#, options: .regularExpression) != nil,
|
|
105
111
|
Scanner(string: hexStr).scanHexInt64(&rgba) else {
|
|
106
|
-
throw InvalidHexColorException(
|
|
112
|
+
throw InvalidHexColorException(input)
|
|
107
113
|
}
|
|
108
114
|
return try toColor(rgba: rgba)
|
|
109
115
|
}
|
|
110
116
|
|
|
117
|
+
private static func fromRGBString(_ rgbString: String) throws -> UIColor {
|
|
118
|
+
let components = rgbString
|
|
119
|
+
.replacingOccurrences(of: "rgba(", with: "")
|
|
120
|
+
.replacingOccurrences(of: "rgb(", with: "")
|
|
121
|
+
.replacingOccurrences(of: ")", with: "")
|
|
122
|
+
.split(separator: ",")
|
|
123
|
+
.compactMap { Double($0.trimmingCharacters(in: .whitespaces)) }
|
|
124
|
+
|
|
125
|
+
guard components.count >= 3,
|
|
126
|
+
components[0] >= 0 && components[0] <= 255,
|
|
127
|
+
components[1] >= 0 && components[1] <= 255,
|
|
128
|
+
components[2] >= 0 && components[2] <= 255 else {
|
|
129
|
+
throw InvalidRGBColorException(rgbString)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let alpha = components.count > 3 ? Double(components[3]) : 1.0
|
|
133
|
+
return UIColor(
|
|
134
|
+
red: CGFloat(components[0]) / 255.0,
|
|
135
|
+
green: CGFloat(components[1]) / 255.0,
|
|
136
|
+
blue: CGFloat(components[2]) / 255.0,
|
|
137
|
+
alpha: alpha)
|
|
138
|
+
}
|
|
111
139
|
/**
|
|
112
140
|
Converts an integer for ARGB color to `UIColor`. Since the alpha channel is represented by first 8 bits,
|
|
113
141
|
it's optional out of the box. React Native converts colors to such format.
|
|
@@ -156,8 +184,15 @@ public struct Conversions {
|
|
|
156
184
|
appContext: AppContext? = nil,
|
|
157
185
|
dynamicType: AnyDynamicType? = nil
|
|
158
186
|
) -> Any {
|
|
159
|
-
if let appContext
|
|
160
|
-
|
|
187
|
+
if let appContext {
|
|
188
|
+
// Dynamic type is provided
|
|
189
|
+
if dynamicType as? DynamicVoidType == nil, let result = try? dynamicType?.convertResult(value as Any, appContext: appContext) {
|
|
190
|
+
return result
|
|
191
|
+
}
|
|
192
|
+
// Dynamic type can be obtained from the value
|
|
193
|
+
if let value = value as? AnyArgument, let result = try? type(of: value).getDynamicType().convertResult(value as Any, appContext: appContext) {
|
|
194
|
+
return result
|
|
195
|
+
}
|
|
161
196
|
}
|
|
162
197
|
return convertFunctionResultInRuntime(value, appContext: appContext)
|
|
163
198
|
}
|
|
@@ -281,6 +316,15 @@ public struct Conversions {
|
|
|
281
316
|
}
|
|
282
317
|
}
|
|
283
318
|
|
|
319
|
+
/**
|
|
320
|
+
An exception used when the rgb color string is invalid.
|
|
321
|
+
*/
|
|
322
|
+
internal class InvalidRGBColorException: GenericException<String> {
|
|
323
|
+
override var reason: String {
|
|
324
|
+
"Provided rgb color string '\(param)' is invalid"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
284
328
|
/**
|
|
285
329
|
An exception used when the integer value of the color would result in an overflow of `UInt32`.
|
|
286
330
|
*/
|
|
@@ -7,7 +7,7 @@ extension UIColor: Convertible {
|
|
|
7
7
|
if let namedColorComponents = namedColors[value] {
|
|
8
8
|
return uiColorWithComponents(namedColorComponents.map { $0 / 255 }) as! Self
|
|
9
9
|
}
|
|
10
|
-
return try Conversions.toColor(
|
|
10
|
+
return try Conversions.toColor(colorString: value) as! Self
|
|
11
11
|
}
|
|
12
12
|
if let components = value as? [Double] {
|
|
13
13
|
return uiColorWithComponents(components) as! Self
|
|
@@ -59,28 +59,39 @@ internal struct DynamicSharedObjectType: AnyDynamicType {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
func convertResult<ResultType>(_ result: ResultType, appContext: AppContext) throws -> Any {
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
// If the
|
|
65
|
-
if let
|
|
66
|
-
return
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
// Postpone object creation to execute on the JS thread.
|
|
63
|
+
JavaScriptSharedObjectBinding.init {
|
|
64
|
+
// If the result is a native shared object, create its JS representation and add the pair to the registry of shared objects.
|
|
65
|
+
if let sharedObject = result as? SharedObject {
|
|
66
|
+
// If the JS object already exists, just return it.
|
|
67
|
+
if let jsObject = sharedObject.getJavaScriptObject() {
|
|
68
|
+
return jsObject
|
|
69
|
+
}
|
|
70
|
+
guard let jsObject = try? appContext.newObject(nativeClassId: typeIdentifier) else {
|
|
71
|
+
// Throwing is not possible here due to swift-objC interop.
|
|
72
|
+
log.warn("Unable to create a JS object for \(description)")
|
|
73
|
+
return JavaScriptObject()
|
|
74
|
+
}
|
|
72
75
|
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
// Add newly created objects to the registry.
|
|
77
|
+
appContext.sharedObjectRegistry.add(native: sharedObject, javaScript: jsObject)
|
|
75
78
|
|
|
76
|
-
|
|
79
|
+
return jsObject
|
|
80
|
+
}
|
|
81
|
+
return JavaScriptObject()
|
|
77
82
|
}
|
|
78
|
-
return result
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
var description: String {
|
|
82
86
|
return "SharedObject<\(innerType)>"
|
|
83
87
|
}
|
|
88
|
+
|
|
89
|
+
func castToJS<ValueType>(_ value: ValueType, appContext: AppContext) throws -> JavaScriptValue {
|
|
90
|
+
if let value = value as? JavaScriptSharedObjectBinding {
|
|
91
|
+
return try JavaScriptValue.from(value.get(), runtime: appContext.runtime)
|
|
92
|
+
}
|
|
93
|
+
throw NativeSharedObjectNotFoundException()
|
|
94
|
+
}
|
|
84
95
|
}
|
|
85
96
|
|
|
86
97
|
internal final class NativeSharedObjectNotFoundException: Exception {
|
|
@@ -65,7 +65,7 @@ public final class AsyncFunctionDefinition<Args, FirstArgType, ReturnType>: AnyA
|
|
|
65
65
|
|
|
66
66
|
func call(by owner: AnyObject?, withArguments args: [Any], appContext: AppContext, callback: @escaping (FunctionCallResult) -> ()) {
|
|
67
67
|
let promise = Promise(appContext: appContext) { value in
|
|
68
|
-
callback(.success(Conversions.convertFunctionResult(value, appContext: appContext)))
|
|
68
|
+
callback(.success(Conversions.convertFunctionResult(value, appContext: appContext, dynamicType: ~ReturnType.self)))
|
|
69
69
|
} rejecter: { exception in
|
|
70
70
|
callback(.failure(exception))
|
|
71
71
|
}
|
package/ios/Core/Promise.swift
CHANGED
|
@@ -19,17 +19,6 @@ public struct Promise: AnyArgument {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
public func resolve(_ value: Any? = nil) {
|
|
22
|
-
if let value = value as? AnySharedObject {
|
|
23
|
-
resolver(JavaScriptSharedObjectBinding.init {
|
|
24
|
-
return Conversions.convertFunctionResult(
|
|
25
|
-
value,
|
|
26
|
-
appContext: appContext,
|
|
27
|
-
dynamicType: type(of: value).getDynamicType()
|
|
28
|
-
// swiftlint:disable:next force_cast
|
|
29
|
-
) as! JavaScriptObject
|
|
30
|
-
})
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
22
|
resolver(value)
|
|
34
23
|
}
|
|
35
24
|
|
|
@@ -16,6 +16,11 @@ public final class ConcreteViewProp<ViewType: UIView, PropType: AnyArgument>: An
|
|
|
16
16
|
*/
|
|
17
17
|
private let propType: AnyDynamicType
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
Default prop value
|
|
21
|
+
*/
|
|
22
|
+
private let defaultValue: PropType?
|
|
23
|
+
|
|
19
24
|
/**
|
|
20
25
|
Closure to call to set the actual property on the given view.
|
|
21
26
|
*/
|
|
@@ -24,6 +29,14 @@ public final class ConcreteViewProp<ViewType: UIView, PropType: AnyArgument>: An
|
|
|
24
29
|
internal init(name: String, propType: AnyDynamicType, setter: @escaping SetterType) {
|
|
25
30
|
self.name = name
|
|
26
31
|
self.propType = propType
|
|
32
|
+
self.defaultValue = nil
|
|
33
|
+
self.setter = setter
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
internal init(name: String, propType: AnyDynamicType, defaultValue: PropType, setter: @escaping SetterType) {
|
|
37
|
+
self.name = name
|
|
38
|
+
self.propType = propType
|
|
39
|
+
self.defaultValue = defaultValue
|
|
27
40
|
self.setter = setter
|
|
28
41
|
}
|
|
29
42
|
|
|
@@ -36,6 +49,9 @@ public final class ConcreteViewProp<ViewType: UIView, PropType: AnyArgument>: An
|
|
|
36
49
|
guard let view = view as? ViewType else {
|
|
37
50
|
throw IncompatibleViewException((propName: name, viewType: ViewType.self))
|
|
38
51
|
}
|
|
52
|
+
if Optional.isNil(value), let defaultValue {
|
|
53
|
+
return setter(view, defaultValue)
|
|
54
|
+
}
|
|
39
55
|
guard let value = try propType.cast(value, appContext: appContext) as? PropType else {
|
|
40
56
|
throw Conversions.CastingException<PropType>(value)
|
|
41
57
|
}
|
|
@@ -8,8 +8,70 @@ extension Color: Convertible {
|
|
|
8
8
|
if let uiColor = try? UIColor.convert(from: value, appContext: appContext) {
|
|
9
9
|
return Color(uiColor)
|
|
10
10
|
}
|
|
11
|
+
// Context-dependent colors
|
|
12
|
+
if let stringValue = value as? String, let color = colorFromName(stringValue) {
|
|
13
|
+
return color
|
|
14
|
+
}
|
|
11
15
|
throw Conversions.ConvertingException<Color>(value)
|
|
12
16
|
}
|
|
17
|
+
|
|
18
|
+
private static func colorFromName(_ name: String) -> Color? {
|
|
19
|
+
switch name {
|
|
20
|
+
case "primary":
|
|
21
|
+
return .primary
|
|
22
|
+
case "secondary":
|
|
23
|
+
return .secondary
|
|
24
|
+
case "red":
|
|
25
|
+
return .red
|
|
26
|
+
case "orange":
|
|
27
|
+
return .orange
|
|
28
|
+
case "yellow":
|
|
29
|
+
return .yellow
|
|
30
|
+
case "green":
|
|
31
|
+
return .green
|
|
32
|
+
case "blue":
|
|
33
|
+
return .blue
|
|
34
|
+
case "purple":
|
|
35
|
+
return .purple
|
|
36
|
+
case "pink":
|
|
37
|
+
return .pink
|
|
38
|
+
case "white":
|
|
39
|
+
return .white
|
|
40
|
+
case "gray":
|
|
41
|
+
return .gray
|
|
42
|
+
case "black":
|
|
43
|
+
return .black
|
|
44
|
+
case "clear":
|
|
45
|
+
return .clear
|
|
46
|
+
case "mint":
|
|
47
|
+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
|
|
48
|
+
return .mint
|
|
49
|
+
}
|
|
50
|
+
return nil
|
|
51
|
+
case "teal":
|
|
52
|
+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
|
|
53
|
+
return .teal
|
|
54
|
+
}
|
|
55
|
+
return nil
|
|
56
|
+
case "cyan":
|
|
57
|
+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
|
|
58
|
+
return .cyan
|
|
59
|
+
}
|
|
60
|
+
return nil
|
|
61
|
+
case "indigo":
|
|
62
|
+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
|
|
63
|
+
return .indigo
|
|
64
|
+
}
|
|
65
|
+
return nil
|
|
66
|
+
case "brown":
|
|
67
|
+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
|
|
68
|
+
return .brown
|
|
69
|
+
}
|
|
70
|
+
return nil
|
|
71
|
+
default:
|
|
72
|
+
return nil
|
|
73
|
+
}
|
|
74
|
+
}
|
|
13
75
|
}
|
|
14
76
|
|
|
15
77
|
extension UnitPoint: Convertible {
|
|
@@ -12,6 +12,13 @@ internal protocol AnyExpoSwiftUIHostingView {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
extension ExpoSwiftUI {
|
|
15
|
+
/**
|
|
16
|
+
Checks if the child view is wrapped by a `UIViewHost` and matches the specified SwiftUI view type.
|
|
17
|
+
*/
|
|
18
|
+
public static func isHostingView(_ view: any AnyChild) -> Bool {
|
|
19
|
+
return view is UIViewHost
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
/**
|
|
16
23
|
Checks if the child view is wrapped by a `UIViewHost` and matches the specified SwiftUI view type.
|
|
17
24
|
*/
|
|
@@ -149,6 +149,46 @@ public final class ExpoRequestInterceptorProtocol: URLProtocol, URLSessionDataDe
|
|
|
149
149
|
client?.urlProtocol(self, didReceive: challengeWithSender)
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
public func urlSession(
|
|
153
|
+
_ session: URLSession,
|
|
154
|
+
task: URLSessionTask,
|
|
155
|
+
didSendBodyData bytesSent: Int64,
|
|
156
|
+
totalBytesSent: Int64,
|
|
157
|
+
totalBytesExpectedToSend: Int64
|
|
158
|
+
) {
|
|
159
|
+
// swiftlint:disable line_length
|
|
160
|
+
// Apple does not support sending upload progress from URLProtocol back to URLProtocolClient.
|
|
161
|
+
// > Similarly, there is no way for your NSURLProtocol subclass to call the NSURLConnection delegate's -connection:needNewBodyStream: or -connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite: methods (<rdar://problem/9226155> and <rdar://problem/9226157>). The latter is not a serious concern--it just means that your clients don't get upload progress--but the former is a real issue. If you're in a situation where you might need a second copy of a request body, you will need your own logic to make that copy, including the case where the body is a stream.
|
|
162
|
+
// See: https://developer.apple.com/library/archive/samplecode/CustomHTTPProtocol/Listings/Read_Me_About_CustomHTTPProtocol_txt.html
|
|
163
|
+
//
|
|
164
|
+
// Workaround to get the original task's URLSessionDelegate through the internal property and send upload process
|
|
165
|
+
// Fixes https://github.com/expo/expo/issues/28269
|
|
166
|
+
// swiftlint:enable line_length
|
|
167
|
+
guard let dataTask = dataTask_ else {
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Prevent recursive delegate calls
|
|
172
|
+
if task === dataTask {
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if #available(iOS 15.0, tvOS 15.0, macOS 12.0, *), let delegate = dataTask.delegate {
|
|
177
|
+
// For the case if the task has a dedicated delegate than the default delegate from its URLSession
|
|
178
|
+
delegate.urlSession?(
|
|
179
|
+
session, task: dataTask, didSendBodyData: bytesSent, totalBytesSent: totalBytesSent, totalBytesExpectedToSend: totalBytesExpectedToSend
|
|
180
|
+
)
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
guard let session = task.value(forKey: "session") as? URLSession,
|
|
184
|
+
let delegate = session.delegate as? URLSessionTaskDelegate else {
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
delegate.urlSession?(
|
|
188
|
+
session, task: dataTask, didSendBodyData: bytesSent, totalBytesSent: totalBytesSent, totalBytesExpectedToSend: totalBytesExpectedToSend
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
152
192
|
/**
|
|
153
193
|
Data structure to save the response for redirection
|
|
154
194
|
*/
|