expo-modules-core 1.11.10 β†’ 1.11.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,19 @@
10
10
 
11
11
  ### πŸ’‘ Others
12
12
 
13
+ ## 1.11.12 β€” 2024-03-13
14
+
15
+ ### πŸŽ‰ New features
16
+
17
+ - Add iOS support for `PlatformColor` and `DynamicColorIOS` color props. ([#26724](https://github.com/expo/expo/pull/26724) by [@dlindenkreuz](https://github.com/dlindenkreuz))
18
+
19
+ ## 1.11.11 β€” 2024-03-11
20
+
21
+ ### πŸ› Bug fixes
22
+
23
+ - [Android] Ensured that `onCreate` before `OnActivityEntersForeground` event. ([#26944](https://github.com/expo/expo/pull/26944) by [@lukmccall](https://github.com/lukmccall))
24
+ - [Android] Fixed activity contract registration after host destruction. ([#26881](https://github.com/expo/expo/pull/26881) by [@lukmccall](https://github.com/lukmccall))
25
+
13
26
  ## 1.11.10 β€” 2024-03-06
14
27
 
15
28
  ### πŸ› Bug fixes
@@ -21,8 +34,6 @@
21
34
  ### πŸŽ‰ New features
22
35
 
23
36
  - Add timer capability to Logger. ([#26454](https://github.com/expo/expo/pull/26454), [#26477](https://github.com/expo/expo/pull/26477) by [@wschurman](https://github.com/wschurman))
24
- - Add iOS support for `PlatformColor` and `DynamicColorIOS` color props. ([#26724](https://github.com/expo/expo/pull/26724) by [@dlindenkreuz](https://github.com/dlindenkreuz))
25
- - `BarCodeScannerResult` interface now declares an additional `raw` field corresponding to the barcode value as it was encoded in the barcode without parsing. Will always be undefined on iOS. ([#25391](https://github.com/expo/expo/pull/25391) by [@ajacquierbret](https://github.com/ajacquierbret))
26
37
 
27
38
  ## 1.11.8 β€” 2024-01-23
28
39
 
@@ -5,7 +5,7 @@ apply plugin: 'kotlin-android'
5
5
  apply plugin: 'maven-publish'
6
6
 
7
7
  group = 'host.exp.exponent'
8
- version = '1.11.10'
8
+ version = '1.11.12'
9
9
 
10
10
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
11
11
  if (expoModulesCorePlugin.exists()) {
@@ -143,7 +143,7 @@ android {
143
143
  defaultConfig {
144
144
  consumerProguardFiles 'proguard-rules.pro'
145
145
  versionCode 1
146
- versionName "1.11.10"
146
+ versionName "1.11.12"
147
147
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled.toString()
148
148
 
149
149
  testInstrumentationRunner "expo.modules.TestRunner"
@@ -64,6 +64,8 @@ class AppContext(
64
64
  // We postpone creating the `JSIInteropModuleRegistry` to not load so files in unit tests.
65
65
  internal lateinit var jsiInterop: JSIInteropModuleRegistry
66
66
 
67
+ private var hostWasDestroyed = false
68
+
67
69
  /**
68
70
  * The core module that defines the `expo` object in the global scope of the JS runtime.
69
71
  *
@@ -132,9 +134,7 @@ class AppContext(
132
134
  }
133
135
 
134
136
  fun onCreate() = trace("AppContext.onCreate") {
135
- registry.readyForPostingEvents()
136
- registry.post(EventName.MODULE_CREATE)
137
- registry.flushTheEventQueue()
137
+ registry.postOnCreate()
138
138
  }
139
139
 
140
140
  /**
@@ -314,6 +314,12 @@ class AppContext(
314
314
  "Current Activity is of incorrect class, expected AppCompatActivity, received ${currentActivity?.localClassName}"
315
315
  }
316
316
 
317
+ // We need to re-register activity contracts when reusing AppContext with new Activity after host destruction.
318
+ if (hostWasDestroyed) {
319
+ hostWasDestroyed = false
320
+ registry.registerActivityContracts()
321
+ }
322
+
317
323
  activityResultsManager.onHostResume(activity)
318
324
  registry.post(EventName.ACTIVITY_ENTERS_FOREGROUND)
319
325
  }
@@ -331,6 +337,10 @@ class AppContext(
331
337
  activityResultsManager.onHostDestroy(it)
332
338
  }
333
339
  registry.post(EventName.ACTIVITY_DESTROYS)
340
+
341
+ // The host (Activity) was destroyed, but it doesn't mean that modules will be destroyed too.
342
+ // So we save that information, and we will re-register activity contracts when the host will be resumed with new Activity.
343
+ hostWasDestroyed = true
334
344
  }
335
345
 
336
346
  internal fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
@@ -33,10 +33,6 @@ class ModuleRegistry(
33
33
  )
34
34
  }
35
35
 
36
- holder.apply {
37
- registerContracts()
38
- }
39
-
40
36
  registry[holder.name] = holder
41
37
  }
42
38
 
@@ -112,14 +108,32 @@ class ModuleRegistry(
112
108
  logger.info("βœ… ModuleRegistry was destroyed")
113
109
  }
114
110
 
111
+ /**
112
+ * Post onCreate event to all modules. It has its own method to ensure that it’s called first.
113
+ */
114
+ fun postOnCreate() {
115
+ forEach {
116
+ it.post(EventName.MODULE_CREATE)
117
+ }
118
+ registerActivityContracts()
119
+ readyForPostingEvents()
120
+ flushTheEventQueue()
121
+ }
122
+
123
+ internal fun registerActivityContracts() {
124
+ forEach { holder ->
125
+ holder.registerContracts()
126
+ }
127
+ }
128
+
115
129
  /**
116
130
  * Tell the modules registry it can handle events as they come, without adding them to the event queue.
117
131
  */
118
- fun readyForPostingEvents() = synchronized(this) {
132
+ private fun readyForPostingEvents() = synchronized(this) {
119
133
  isReadyForPostingEvents = true
120
134
  }
121
135
 
122
- fun flushTheEventQueue() = synchronized(this) {
136
+ private fun flushTheEventQueue() = synchronized(this) {
123
137
  eventQueue.forEach { event ->
124
138
  forEach {
125
139
  event.post(it)
@@ -15,6 +15,42 @@ extension UIColor: Convertible {
15
15
  if let value = value as? Int {
16
16
  return try Conversions.toColor(argb: UInt64(value)) as! Self
17
17
  }
18
+
19
+ // Handle `PlatformColor` and `DynamicColorIOS`
20
+ if let opaqueValue = value as? [String: Any] {
21
+ if let semanticName = opaqueValue["semantic"] as? String,
22
+ let color = resolveNamedColor(name: semanticName) {
23
+ return color as! Self
24
+ }
25
+ if let semanticArray = opaqueValue["semantic"] as? [String] {
26
+ for semanticName in semanticArray {
27
+ if let color = resolveNamedColor(name: semanticName) {
28
+ return color as! Self
29
+ }
30
+ }
31
+ }
32
+ if let appearances = opaqueValue["dynamic"] as? [String: Any],
33
+ let lightColor = try appearances["light"].map({ try UIColor.convert(from: $0, appContext: appContext) }),
34
+ let darkColor = try appearances["dark"].map({ try UIColor.convert(from: $0, appContext: appContext) }) {
35
+ let highContrastLightColor = try appearances["highContrastLight"].map({ try UIColor.convert(from: $0, appContext: appContext) })
36
+ let highContrastDarkColor = try appearances["highContrastDark"].map({ try UIColor.convert(from: $0, appContext: appContext) })
37
+
38
+ let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
39
+ if traitCollection.userInterfaceStyle == .dark {
40
+ if traitCollection.accessibilityContrast == .high, let highContrastDarkColor {
41
+ return highContrastDarkColor
42
+ }
43
+ return darkColor
44
+ }
45
+
46
+ if traitCollection.accessibilityContrast == .high, let highContrastLightColor {
47
+ return highContrastLightColor
48
+ }
49
+ return lightColor
50
+ }
51
+ return color as! Self
52
+ }
53
+ }
18
54
  throw Conversions.ConvertingException<UIColor>(value)
19
55
  // swiftlint:enable force_cast
20
56
  }
@@ -33,6 +69,24 @@ extension CGColor: Convertible {
33
69
  }
34
70
  }
35
71
 
72
+ private func resolveNamedColor(name: String) -> UIColor? {
73
+ return UIColor(named: name) ?? uiColorFromSemanticName(name: name)
74
+ }
75
+
76
+ private func uiColorFromSemanticName(name: String) -> UIColor? {
77
+ let selector: Selector
78
+ if name.hasSuffix("Color") {
79
+ selector = Selector(name)
80
+ } else {
81
+ selector = Selector("\(name)Color")
82
+ }
83
+ guard UIColor.responds(to: selector) else {
84
+ return nil
85
+ }
86
+
87
+ return UIColor.perform(selector).takeUnretainedValue() as? UIColor
88
+ }
89
+
36
90
  private func uiColorWithComponents(_ components: [Double]) -> UIColor {
37
91
  let alpha = components.count > 3 ? components[3] : 1.0
38
92
  return UIColor(red: components[0], green: components[1], blue: components[2], alpha: alpha)
@@ -363,6 +363,22 @@ class ConvertiblesSpec: ExpoSpec {
363
363
  let transparent = try CGColor.convert(from: "transparent", appContext: appContext)
364
364
  expect(transparent.alpha) == .zero
365
365
  }
366
+
367
+ it("converts from PlatformColor") {
368
+ let color = try CGColor.convert(from: ["semantic": ["invalid_color", "systemRed", "systemBlue"]], appContext: appContext)
369
+ expect(color) == UIColor.systemRed.cgColor
370
+ }
371
+
372
+ it("converts from DynamicColorIOS") {
373
+ let color = try CGColor.convert(from: ["dynamic": ["light": "#000", "dark": ["semantic": "systemGray"]]], appContext: appContext)
374
+ testColorComponents(color, 0x00, 0x00, 0x00, 0xFF)
375
+ }
376
+
377
+ it("converts from DynamicColorIOS with traits") {
378
+ let color = try UIColor.convert(from: ["dynamic": ["light": "#000", "dark": ["semantic": "systemGray"]]], appContext: appContext)
379
+ let traits = UITraitCollection(userInterfaceStyle: .dark)
380
+ expect(color.resolvedColor(with: traits)) == UIColor.systemGray.resolvedColor(with: traits)
381
+ }
366
382
 
367
383
  it("throws when string is invalid") {
368
384
  testInvalidHexColor("")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-core",
3
- "version": "1.11.10",
3
+ "version": "1.11.12",
4
4
  "description": "The core of Expo Modules architecture",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -44,5 +44,5 @@
44
44
  "@testing-library/react-hooks": "^7.0.1",
45
45
  "expo-module-scripts": "^3.0.0"
46
46
  },
47
- "gitHead": "407d15c8c4930e7b03804ffbfc5a068708679a57"
47
+ "gitHead": "d846eb40fc384b9e4b21260af2a990dfe79cf461"
48
48
  }