@iternio/react-native-auto-play 0.3.7 → 0.3.8

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.
Files changed (45) hide show
  1. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoService.kt +5 -16
  2. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoSession.kt +21 -33
  3. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlay.kt +7 -0
  4. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridCluster.kt +6 -0
  5. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VirtualRenderer.kt +67 -64
  6. package/ios/hybrid/HybridAutoPlay.swift +7 -0
  7. package/ios/hybrid/HybridCluster.swift +22 -8
  8. package/lib/AutoPlayHeadlessJsTask.d.ts +2 -1
  9. package/lib/AutoPlayHeadlessJsTask.js +4 -5
  10. package/lib/components/SafeAreaInsetsContext.d.ts +1 -1
  11. package/lib/components/SafeAreaInsetsContext.js +1 -1
  12. package/lib/hooks/useAndroidAutoTelemetry.js +2 -1
  13. package/lib/hooks/useFocusedEffect.js +1 -1
  14. package/lib/hooks/useVoiceInput.d.ts +1 -1
  15. package/lib/hooks/useVoiceInput.js +1 -1
  16. package/lib/hybrid/HybridAndroidAutoTelemetry.android.d.ts +2 -0
  17. package/lib/hybrid/HybridAndroidAutoTelemetry.android.js +2 -0
  18. package/lib/hybrid/HybridAndroidAutoTelemetry.d.ts +2 -0
  19. package/lib/hybrid/HybridAndroidAutoTelemetry.js +1 -0
  20. package/lib/hybrid/HybridAutoPlay.d.ts +2 -0
  21. package/lib/hybrid/HybridAutoPlay.js +2 -0
  22. package/lib/index.d.ts +4 -4
  23. package/lib/index.js +5 -5
  24. package/lib/scenes/CarPlayDashboardScene.d.ts +3 -3
  25. package/lib/scenes/CarPlayDashboardScene.js +1 -1
  26. package/lib/templates/MapTemplate.d.ts +1 -1
  27. package/lib/templates/MapTemplate.js +1 -1
  28. package/lib/templates/MessageTemplate.d.ts +1 -1
  29. package/lib/templates/MessageTemplate.js +1 -1
  30. package/lib/templates/Template.js +1 -1
  31. package/package.json +6 -4
  32. package/src/AutoPlayHeadlessJsTask.ts +12 -9
  33. package/src/components/SafeAreaInsetsContext.tsx +2 -1
  34. package/src/hooks/useAndroidAutoTelemetry.ts +2 -1
  35. package/src/hooks/useFocusedEffect.ts +1 -1
  36. package/src/hooks/useVoiceInput.ts +2 -1
  37. package/src/hybrid/HybridAndroidAutoTelemetry.android.ts +5 -0
  38. package/src/hybrid/HybridAndroidAutoTelemetry.ts +3 -0
  39. package/src/hybrid/HybridAutoPlay.ts +4 -0
  40. package/src/index.ts +5 -9
  41. package/src/scenes/CarPlayDashboardScene.ts +1 -1
  42. package/src/templates/MapTemplate.ts +2 -1
  43. package/src/templates/MessageTemplate.ts +7 -7
  44. package/src/templates/Template.ts +1 -1
  45. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/utils/ReactContextResolver.kt +0 -36
@@ -23,17 +23,11 @@ import androidx.core.app.NotificationCompat
23
23
  import androidx.core.app.NotificationManagerCompat
24
24
  import androidx.lifecycle.DefaultLifecycleObserver
25
25
  import androidx.lifecycle.LifecycleOwner
26
- import com.facebook.react.ReactApplication
27
26
  import com.facebook.react.bridge.LifecycleEventListener
28
- import com.facebook.react.bridge.ReactContext
27
+ import com.margelo.nitro.NitroModules
29
28
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
30
- import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.ReactContextResolver
31
- import kotlinx.coroutines.CoroutineScope
32
- import kotlinx.coroutines.Dispatchers
33
- import kotlinx.coroutines.launch
34
29
 
35
30
  class AndroidAutoService : CarAppService() {
36
- private lateinit var reactContext: ReactContext
37
31
  private lateinit var notificationManager: NotificationManager
38
32
 
39
33
  private var isServiceBound = false
@@ -54,10 +48,7 @@ class AndroidAutoService : CarAppService() {
54
48
  super.onCreate()
55
49
  instance = this
56
50
 
57
- CoroutineScope(Dispatchers.Main).launch {
58
- reactContext = ReactContextResolver.getReactContext(application as ReactApplication)
59
- reactContext.addLifecycleEventListener(reactLifecycleObserver)
60
- }
51
+ NitroModules.applicationContext?.addLifecycleEventListener(reactLifecycleObserver)
61
52
 
62
53
  notificationManager = getSystemService(NotificationManager::class.java)
63
54
  val appLabel = AppInfo.getApplicationLabel(this)
@@ -72,7 +63,7 @@ class AndroidAutoService : CarAppService() {
72
63
  }
73
64
 
74
65
  override fun onCreateSession(sessionInfo: SessionInfo): Session {
75
- val session = AndroidAutoSession(sessionInfo, application as ReactApplication)
66
+ val session = AndroidAutoSession(sessionInfo)
76
67
 
77
68
  if (sessionInfo.displayType == SessionInfo.DISPLAY_TYPE_CLUSTER) {
78
69
  return session
@@ -89,11 +80,9 @@ class AndroidAutoService : CarAppService() {
89
80
 
90
81
  stopForeground(STOP_FOREGROUND_REMOVE)
91
82
 
92
- if (!this::reactContext.isInitialized) {
93
- return
94
- }
83
+ NitroModules.applicationContext?.removeLifecycleEventListener(reactLifecycleObserver)
95
84
 
96
- reactContext.removeLifecycleEventListener(reactLifecycleObserver)
85
+ VirtualRenderer.remove()
97
86
  }
98
87
 
99
88
  private val reactLifecycleObserver = object : LifecycleEventListener {
@@ -12,21 +12,16 @@ import androidx.car.app.model.MessageTemplate
12
12
  import androidx.car.app.model.Template
13
13
  import androidx.lifecycle.DefaultLifecycleObserver
14
14
  import androidx.lifecycle.LifecycleOwner
15
- import com.facebook.react.ReactApplication
16
15
  import com.facebook.react.bridge.LifecycleEventListener
17
- import com.facebook.react.bridge.ReactContext
16
+ import com.margelo.nitro.NitroModules
18
17
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.template.AndroidAutoTemplate
19
18
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.template.MapTemplate
20
19
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
21
- import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.ReactContextResolver
22
- import kotlinx.coroutines.CoroutineScope
23
- import kotlinx.coroutines.Dispatchers
24
- import kotlinx.coroutines.launch
25
20
  import java.util.UUID
26
21
  import java.util.concurrent.ConcurrentHashMap
27
22
  import java.util.concurrent.CopyOnWriteArrayList
28
23
 
29
- class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication: ReactApplication) :
24
+ class AndroidAutoSession(sessionInfo: SessionInfo) :
30
25
  Session() {
31
26
 
32
27
  private val isCluster = sessionInfo.displayType == SessionInfo.DISPLAY_TYPE_CLUSTER
@@ -89,34 +84,29 @@ class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication:
89
84
  }
90
85
 
91
86
  lifecycle.addObserver(sessionLifecycleObserver)
87
+ NitroModules.applicationContext?.addLifecycleEventListener(reactLifecycleObserver)
92
88
 
93
- CoroutineScope(Dispatchers.Main).launch {
94
- reactContext = ReactContextResolver.getReactContext(reactApplication)
95
- reactContext.addLifecycleEventListener(reactLifecycleObserver)
96
-
97
- // TODO this is not required for templates that host a component, check if we need this for non-rendering templates
98
- /*
99
- val appRegistry = reactContext.getJSModule(AppRegistry::class.java)
100
- ?: throw ClassNotFoundException("could not get AppRegistry instance")
101
- val jsAppModuleName = if (isCluster) "AndroidAutoCluster" else "AndroidAuto"
102
- val appParams = WritableNativeMap().apply {
103
- putMap("initialProps", Arguments.createMap().apply {
104
- putString("id", clusterTemplateId)
105
- })
106
- }
107
-
108
- appRegistry.runApplication(jsAppModuleName, appParams)
109
- */
110
-
111
- if (clusterId != null) {
112
- HybridCluster.emit(ClusterEventName.DIDCONNECTWITHWINDOW, clusterId)
113
- return@launch
114
- }
115
-
89
+ if (clusterId == null) {
116
90
  HybridAutoPlay.emit(EventName.DIDCONNECT)
91
+ } else {
92
+ HybridCluster.emit(ClusterEventName.DIDCONNECTWITHWINDOW, clusterId)
117
93
  }
118
94
 
119
95
  return screen
96
+
97
+ // TODO this is not required for templates that host a component, check if we need this for non-rendering templates
98
+ /*
99
+ val appRegistry = reactContext.getJSModule(AppRegistry::class.java)
100
+ ?: throw ClassNotFoundException("could not get AppRegistry instance")
101
+ val jsAppModuleName = if (isCluster) "AndroidAutoCluster" else "AndroidAuto"
102
+ val appParams = WritableNativeMap().apply {
103
+ putMap("initialProps", Arguments.createMap().apply {
104
+ putString("id", clusterTemplateId)
105
+ })
106
+ }
107
+
108
+ appRegistry.runApplication(jsAppModuleName, appParams)
109
+ */
120
110
  }
121
111
 
122
112
  override fun onCarConfigurationChanged(configuration: Configuration) {
@@ -129,7 +119,7 @@ class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication:
129
119
  }
130
120
 
131
121
  val marker = AndroidAutoScreen.getScreen(ROOT_SESSION)?.marker ?: return
132
- val config = AndroidAutoTemplate.getConfig(marker) as MapTemplateConfig? ?: return
122
+ val config = AndroidAutoTemplate.getConfig(marker) as? MapTemplateConfig? ?: return
133
123
 
134
124
  if (config.onAppearanceDidChange != null) {
135
125
  config.onAppearanceDidChange(colorScheme)
@@ -218,7 +208,6 @@ class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication:
218
208
 
219
209
  override fun onDestroy(owner: LifecycleOwner) {
220
210
  sessions.remove(moduleName)
221
- VirtualRenderer.removeRenderer(moduleName)
222
211
  clusterId?.let {
223
212
  HybridCluster.emit(ClusterEventName.DIDDISCONNECT, clusterId)
224
213
  clusterSessions.remove(it)
@@ -247,7 +236,6 @@ class AndroidAutoSession(sessionInfo: SessionInfo, private val reactApplication:
247
236
  const val TAG = "AndroidAutoSession"
248
237
  const val ROOT_SESSION = "AutoPlayRoot"
249
238
 
250
- private lateinit var reactContext: ReactContext
251
239
  private val sessions = ConcurrentHashMap<String, ScreenContext>()
252
240
 
253
241
  private val clusterSessions = CopyOnWriteArrayList<String>()
@@ -9,6 +9,13 @@ import java.util.concurrent.ConcurrentHashMap
9
9
  import java.util.concurrent.CopyOnWriteArrayList
10
10
 
11
11
  class HybridAutoPlay : HybridAutoPlaySpec() {
12
+ init {
13
+ listeners.clear()
14
+ renderStateListeners.clear()
15
+ voiceInputListeners.clear()
16
+ safeAreaInsetsListeners.clear()
17
+ }
18
+
12
19
  override fun addListener(
13
20
  eventType: EventName, callback: () -> Unit
14
21
  ): () -> Unit {
@@ -6,6 +6,12 @@ import java.util.concurrent.ConcurrentHashMap
6
6
  import java.util.concurrent.CopyOnWriteArrayList
7
7
 
8
8
  class HybridCluster : HybridClusterSpec() {
9
+ init {
10
+ listeners.clear()
11
+ eventQueue.clear()
12
+ colorSchemeListeners.clear()
13
+ }
14
+
9
15
  override fun addListener(
10
16
  eventType: ClusterEventName, callback: (String) -> Unit
11
17
  ): () -> Unit {
@@ -2,12 +2,11 @@ package com.margelo.nitro.swe.iternio.reactnativeautoplay
2
2
 
3
3
  import android.app.Presentation
4
4
  import android.content.Context
5
- import android.view.ContextThemeWrapper
6
5
  import android.graphics.Color
7
6
  import android.graphics.Rect
8
7
  import android.hardware.display.DisplayManager
8
+ import android.hardware.display.VirtualDisplay
9
9
  import android.os.Bundle
10
- import android.util.Log
11
10
  import android.view.Display
12
11
  import android.view.LayoutInflater
13
12
  import android.view.View
@@ -15,11 +14,11 @@ import android.view.ViewGroup
15
14
  import android.view.ViewTreeObserver
16
15
  import android.widget.FrameLayout
17
16
  import android.widget.TextView
17
+ import androidx.annotation.MainThread
18
18
  import androidx.car.app.AppManager
19
19
  import androidx.car.app.CarContext
20
20
  import androidx.car.app.SurfaceCallback
21
21
  import androidx.car.app.SurfaceContainer
22
- import com.facebook.react.ReactApplication
23
22
  import com.facebook.react.bridge.Arguments
24
23
  import com.facebook.react.bridge.ReactContext
25
24
  import com.facebook.react.fabric.FabricUIManager
@@ -28,13 +27,11 @@ import com.facebook.react.runtime.ReactSurfaceView
28
27
  import com.facebook.react.uimanager.DisplayMetricsHolder
29
28
  import com.facebook.react.uimanager.UIManagerHelper
30
29
  import com.facebook.react.uimanager.common.UIManagerType
30
+ import com.margelo.nitro.NitroModules
31
31
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.template.AndroidAutoTemplate
32
32
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
33
33
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.Debouncer
34
- import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.ReactContextResolver
35
- import kotlinx.coroutines.CoroutineScope
36
- import kotlinx.coroutines.Dispatchers
37
- import kotlinx.coroutines.launch
34
+ import java.util.concurrent.ConcurrentHashMap
38
35
  import kotlin.math.floor
39
36
 
40
37
  class VirtualRenderer(
@@ -42,14 +39,7 @@ class VirtualRenderer(
42
39
  private val moduleName: String,
43
40
  private val isCluster: Boolean = false
44
41
  ) {
45
- private lateinit var fabricUiManager: FabricUIManager
46
-
47
- private fun isUiManagerInitialized(): Boolean {
48
- return ::fabricUiManager.isInitialized
49
- }
50
-
51
- private lateinit var display: Display
52
- private lateinit var reactContext: ReactContext
42
+ private var virtualDisplay: VirtualDisplay? = null
53
43
 
54
44
  private lateinit var reactSurfaceImpl: ReactSurfaceImpl
55
45
  private var reactSurfaceView: ReactSurfaceView? = null
@@ -66,20 +56,13 @@ class VirtualRenderer(
66
56
  private val virtualScreenDensity = context.resources.displayMetrics.density
67
57
  val scale = BuildConfig.SCALE_FACTOR * virtualScreenDensity
68
58
 
59
+ private fun isSurfaceReady(surfaceContainer: SurfaceContainer): Boolean {
60
+ return surfaceContainer.surface != null && surfaceContainer.dpi != 0 && surfaceContainer.height != 0 && surfaceContainer.width != 0
61
+ }
62
+
69
63
  init {
70
64
  virtualRenderer[moduleName] = this
71
65
 
72
- CoroutineScope(Dispatchers.Main).launch {
73
- reactContext =
74
- ReactContextResolver.getReactContext(context.applicationContext as ReactApplication)
75
-
76
- fabricUiManager = UIManagerHelper.getUIManager(
77
- reactContext, UIManagerType.FABRIC
78
- ) as FabricUIManager
79
-
80
- initRenderer()
81
- }
82
-
83
66
  context.getCarService(AppManager::class.java).setSurfaceCallback(object : SurfaceCallback {
84
67
  val areaDebouncer = Debouncer(200)
85
68
 
@@ -90,13 +73,14 @@ class VirtualRenderer(
90
73
  var visibleArea = Rect(0, 0, 0, 0)
91
74
 
92
75
  override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) {
93
- if (surfaceContainer.surface == null) {
94
- Log.w(TAG, "surface is null")
76
+ if (!isSurfaceReady(surfaceContainer)) {
95
77
  return
96
78
  }
97
79
 
80
+ virtualDisplay?.release() // in case this is called multiple times release the old instance
81
+
98
82
  val manager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
99
- val virtualDisplay = manager.createVirtualDisplay(
83
+ virtualDisplay = manager.createVirtualDisplay(
100
84
  moduleName,
101
85
  surfaceContainer.width,
102
86
  surfaceContainer.height,
@@ -105,11 +89,15 @@ class VirtualRenderer(
105
89
  DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION,
106
90
  )
107
91
 
108
- display = virtualDisplay.display
92
+ val display = virtualDisplay?.display ?: return
109
93
  height = surfaceContainer.height
110
94
  width = surfaceContainer.width
111
95
 
112
- initRenderer()
96
+ initRenderer(display)
97
+ }
98
+
99
+ override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) {
100
+ stop()
113
101
  }
114
102
 
115
103
  override fun onScroll(distanceX: Float, distanceY: Float) {
@@ -247,10 +235,12 @@ class VirtualRenderer(
247
235
  return AndroidAutoTemplate.getTypedConfig<MapTemplateConfig>(marker)
248
236
  }
249
237
 
250
- private fun initRenderer() {
251
- if (!this::display.isInitialized) {
252
- return
253
- }
238
+ private fun initRenderer(display: Display) {
239
+ val reactContext = NitroModules.applicationContext ?: return
240
+
241
+ val fabricUiManager = UIManagerHelper.getUIManager(
242
+ reactContext, UIManagerType.FABRIC
243
+ ) as? FabricUIManager? ?: return
254
244
 
255
245
  val initialProperties = Bundle().apply {
256
246
  putString("id", moduleName)
@@ -270,20 +260,21 @@ class VirtualRenderer(
270
260
  val mainScreenDensity = DisplayMetricsHolder.getScreenDisplayMetrics().density
271
261
  val reactNativeScale = virtualScreenDensity / mainScreenDensity * BuildConfig.SCALE_FACTOR
272
262
 
273
- if (!isUiManagerInitialized()) {
274
- // this makes sure we have all required instances
275
- // no matter if the app is launched on the phone or AA first
276
- return
277
- }
278
-
279
263
  FabricMapPresentation(
280
- context, display, height, width, initialProperties, reactNativeScale
264
+ reactContext,
265
+ display,
266
+ fabricUiManager,
267
+ height,
268
+ width,
269
+ initialProperties,
270
+ reactNativeScale
281
271
  ).show()
282
272
  }
283
273
 
284
274
  inner class FabricMapPresentation(
285
- private val context: CarContext,
275
+ private val context: ReactContext,
286
276
  display: Display,
277
+ private val fabricUiManager: FabricUIManager,
287
278
  private val height: Int,
288
279
  private val width: Int,
289
280
  private val initialProperties: Bundle,
@@ -292,11 +283,8 @@ class VirtualRenderer(
292
283
  override fun onCreate(savedInstanceState: Bundle?) {
293
284
  super.onCreate(savedInstanceState)
294
285
 
295
- val appTheme = context.applicationContext.applicationInfo.theme
296
- val themedContext = ContextThemeWrapper(context.applicationContext, appTheme)
297
-
298
286
  if (!this@VirtualRenderer::reactSurfaceImpl.isInitialized) {
299
- reactSurfaceImpl = ReactSurfaceImpl(themedContext, moduleName, initialProperties)
287
+ reactSurfaceImpl = ReactSurfaceImpl(context, moduleName, initialProperties)
300
288
  }
301
289
 
302
290
  var splashScreenView: View? = null
@@ -305,9 +293,9 @@ class VirtualRenderer(
305
293
  (it.parent as ViewGroup).removeView(it)
306
294
  } ?: run {
307
295
  splashScreenView =
308
- if (isCluster) getClusterSplashScreen(themedContext, height, width) else null
296
+ if (isCluster) getClusterSplashScreen(context, height, width) else null
309
297
 
310
- val surfaceView = ReactSurfaceView(themedContext, reactSurfaceImpl).apply {
298
+ val surfaceView = ReactSurfaceView(context, reactSurfaceImpl).apply {
311
299
  layoutParams = FrameLayout.LayoutParams(
312
300
  (width / reactNativeScale).toInt(), (height / reactNativeScale).toInt()
313
301
  )
@@ -335,7 +323,7 @@ class VirtualRenderer(
335
323
  )
336
324
 
337
325
  // remove ui-managers lifecycle listener to not stop rendering when app is not in foreground/phone screen is off
338
- reactContext.removeLifecycleEventListener(fabricUiManager)
326
+ context.removeLifecycleEventListener(fabricUiManager)
339
327
  // trigger ui-managers onHostResume to make sure the surface is rendered properly even when AA only is starting without the phone app
340
328
  fabricUiManager.onHostResume()
341
329
 
@@ -343,7 +331,7 @@ class VirtualRenderer(
343
331
  }
344
332
 
345
333
 
346
- val rootContainer = FrameLayout(themedContext).apply {
334
+ val rootContainer = FrameLayout(context).apply {
347
335
  layoutParams = FrameLayout.LayoutParams(
348
336
  FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT
349
337
  )
@@ -365,8 +353,7 @@ class VirtualRenderer(
365
353
  ): View {
366
354
  val root = FrameLayout(context).apply {
367
355
  layoutParams = ViewGroup.LayoutParams(
368
- ViewGroup.LayoutParams.MATCH_PARENT,
369
- ViewGroup.LayoutParams.MATCH_PARENT
356
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
370
357
  )
371
358
  }
372
359
 
@@ -407,25 +394,41 @@ class VirtualRenderer(
407
394
  })
408
395
  }
409
396
 
397
+ @MainThread
398
+ private fun stop() {
399
+ virtualDisplay?.release()
400
+ virtualDisplay = null
401
+
402
+ val uiManager = NitroModules.applicationContext?.let {
403
+ UIManagerHelper.getUIManager(
404
+ it, UIManagerType.FABRIC
405
+ ) as? FabricUIManager?
406
+ }
407
+
408
+ try {
409
+ reactSurfaceId?.let {
410
+ uiManager?.stopSurface(it)
411
+ }
412
+ } catch (_: AssertionError) {
413
+ // Fabric already invalidated
414
+ } finally {
415
+ reactSurfaceId = null
416
+ virtualRenderer.remove(moduleName)
417
+ }
418
+ }
419
+
410
420
  companion object {
411
421
  const val TAG = "VirtualRenderer"
412
422
 
413
- private val virtualRenderer = mutableMapOf<String, VirtualRenderer>()
423
+ private val virtualRenderer = ConcurrentHashMap<String, VirtualRenderer>()
414
424
 
415
425
  fun hasRenderer(moduleId: String): Boolean {
416
426
  return virtualRenderer.contains(moduleId)
417
427
  }
418
428
 
419
- fun removeRenderer(moduleId: String) {
420
- val renderer = virtualRenderer[moduleId]
421
-
422
- if (renderer?.isUiManagerInitialized() == true) {
423
- renderer.reactSurfaceId?.let {
424
- renderer.fabricUiManager.stopSurface(it)
425
- }
426
- }
427
-
428
- virtualRenderer.remove(moduleId)
429
+ fun remove() {
430
+ virtualRenderer.forEach { (_, renderer) -> renderer.stop() }
431
+ virtualRenderer.clear()
429
432
  }
430
433
  }
431
434
  }
@@ -21,6 +21,13 @@ class HybridAutoPlay: HybridAutoPlaySpec {
21
21
  private static var renderStateListeners = [String: [RenderStateListener]]()
22
22
  private static var safeAreaInsetsListeners = [String: [SafeAreaListener]]()
23
23
 
24
+ override init() {
25
+ HybridAutoPlay.listeners.removeAll()
26
+ HybridAutoPlay.renderStateListeners.removeAll()
27
+ HybridAutoPlay.safeAreaInsetsListeners.removeAll()
28
+ super.init()
29
+ }
30
+
24
31
  func addListener(eventType: EventName, callback: @escaping () -> Void)
25
32
  throws -> () -> Void
26
33
  {
@@ -31,6 +31,16 @@ class HybridCluster: HybridClusterSpec {
31
31
  String: (_: String, _: Bool) -> Void
32
32
  ]()
33
33
 
34
+ override init() {
35
+ HybridCluster.listeners.removeAll()
36
+ HybridCluster.eventQueue.removeAll()
37
+ HybridCluster.colorSchemeListeners.removeAll()
38
+ HybridCluster.zoomListeners.removeAll()
39
+ HybridCluster.compassListeners.removeAll()
40
+ HybridCluster.speedLimitListeners.removeAll()
41
+ super.init()
42
+ }
43
+
34
44
  func addListener(
35
45
  eventType: ClusterEventName,
36
46
  callback: @escaping (_ clusterId: String) -> Void
@@ -57,12 +67,14 @@ class HybridCluster: HybridClusterSpec {
57
67
  return Promise.async {
58
68
  if #available(iOS 15.4, *) {
59
69
  try await MainActor.run {
60
- guard let scene = SceneStore.getClusterScene(
61
- clusterId: clusterId
62
- ) else {
70
+ guard
71
+ let scene = SceneStore.getClusterScene(
72
+ clusterId: clusterId
73
+ )
74
+ else {
63
75
  return
64
76
  }
65
-
77
+
66
78
  try scene.initRootView()
67
79
  }
68
80
  }
@@ -80,12 +92,14 @@ class HybridCluster: HybridClusterSpec {
80
92
  [NitroAttributedString]
81
93
  ) throws {
82
94
  if #available(iOS 15.4, *) {
83
- guard let scene = SceneStore.getClusterScene(
84
- clusterId: clusterId
85
- ) else {
95
+ guard
96
+ let scene = SceneStore.getClusterScene(
97
+ clusterId: clusterId
98
+ )
99
+ else {
86
100
  return
87
101
  }
88
-
102
+
89
103
  scene.setAttributedInactiveDescriptionVariants(
90
104
  attributedInactiveDescriptionVariants:
91
105
  attributedInactiveDescriptionVariants
@@ -1,4 +1,5 @@
1
+ import type { AutoPlay as NitroAutoPlay } from './specs/AutoPlay.nitro';
1
2
  declare const _default: {
2
- registerHeadlessTask: () => void;
3
+ registerHeadlessTask: (hybridAutoPlay: NitroAutoPlay) => void;
3
4
  };
4
5
  export default _default;
@@ -1,15 +1,14 @@
1
1
  import { AppRegistry, Platform } from 'react-native';
2
- import { HybridAutoPlay } from '.';
3
- const taskProvider = () => () => new Promise((resolve) => {
4
- const remove = HybridAutoPlay.addListener('didDisconnect', () => {
2
+ const createTaskProvider = (hybridAutoPlay) => () => () => new Promise((resolve) => {
3
+ const remove = hybridAutoPlay.addListener('didDisconnect', () => {
5
4
  resolve();
6
5
  remove();
7
6
  });
8
7
  });
9
- const registerHeadlessTask = () => {
8
+ const registerHeadlessTask = (hybridAutoPlay) => {
10
9
  if (Platform.OS !== 'android') {
11
10
  return;
12
11
  }
13
- AppRegistry.registerHeadlessTask('AndroidAutoHeadlessJsTask', taskProvider);
12
+ AppRegistry.registerHeadlessTask('AndroidAutoHeadlessJsTask', createTaskProvider(hybridAutoPlay));
14
13
  };
15
14
  export default { registerHeadlessTask };
@@ -1,5 +1,5 @@
1
1
  import type React from 'react';
2
- import { type SafeAreaInsets } from '..';
2
+ import type { SafeAreaInsets } from '..';
3
3
  export declare const SafeAreaInsetsContext: React.Context<SafeAreaInsets>;
4
4
  export declare function SafeAreaInsetsProvider({ children, moduleName, }: {
5
5
  children: React.ReactNode;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useEffect, useState } from 'react';
3
- import { HybridAutoPlay } from '..';
3
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
4
4
  const DEFAULT = { top: 0, bottom: 0, left: 0, right: 0 };
5
5
  export const SafeAreaInsetsContext = createContext(DEFAULT);
6
6
  export function SafeAreaInsetsProvider({ children, moduleName, }) {
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useState } from 'react';
2
2
  import { PermissionsAndroid } from 'react-native';
3
- import { HybridAndroidAutoTelemetry, HybridAutoPlay } from '..';
3
+ import { HybridAndroidAutoTelemetry } from '../hybrid/HybridAndroidAutoTelemetry';
4
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
4
5
  /**
5
6
  * Hook to check if the telemetry permissions are granted. If the permissions are not granted, it will request them from the user.
6
7
  *
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useRef, useState } from 'react';
2
- import { HybridAutoPlay } from '..';
2
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
3
3
  /**
4
4
  * An effect hook that only runs when the CarPlay/Android Auto screen is visible to the user and dependencies have changed.
5
5
  * It behaves like `useEffect`, but the effect function is only executed if the screen is visible.
@@ -1,4 +1,4 @@
1
- import { type Location } from '..';
1
+ import type { Location } from '..';
2
2
  export declare const useVoiceInput: () => {
3
3
  voiceInputResult: {
4
4
  coordinates: Location | undefined;
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useEffect, useState } from 'react';
2
- import { HybridAutoPlay } from '..';
2
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
3
3
  export const useVoiceInput = () => {
4
4
  const [isConnected, setIsConnected] = useState(false);
5
5
  const [voiceInputResult, setVoiceInputResult] = useState();
@@ -0,0 +1,2 @@
1
+ import type { AndroidAutoTelemetry } from '../specs/AndroidAutoTelemetry.nitro';
2
+ export declare const HybridAndroidAutoTelemetry: AndroidAutoTelemetry;
@@ -0,0 +1,2 @@
1
+ import { NitroModules } from 'react-native-nitro-modules';
2
+ export const HybridAndroidAutoTelemetry = NitroModules.createHybridObject('AndroidAutoTelemetry');
@@ -0,0 +1,2 @@
1
+ import type { AndroidAutoTelemetry } from '../specs/AndroidAutoTelemetry.nitro';
2
+ export declare const HybridAndroidAutoTelemetry: AndroidAutoTelemetry | null;
@@ -0,0 +1 @@
1
+ export const HybridAndroidAutoTelemetry = null;
@@ -0,0 +1,2 @@
1
+ import type { AutoPlay } from '../specs/AutoPlay.nitro';
2
+ export declare const HybridAutoPlay: AutoPlay;
@@ -0,0 +1,2 @@
1
+ import { NitroModules } from 'react-native-nitro-modules';
2
+ export const HybridAutoPlay = NitroModules.createHybridObject('AutoPlay');
package/lib/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
+ import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
2
+ import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
1
3
  import type { AndroidAutomotive } from './specs/AndroidAutomotive.nitro';
2
- import type { AndroidAutoTelemetry as NitroAndroidAutoTelemetry } from './specs/AndroidAutoTelemetry.nitro';
3
- import type { AutoPlay as NitroAutoPlay } from './specs/AutoPlay.nitro';
4
- export declare const HybridAutoPlay: NitroAutoPlay;
5
- export declare const HybridAndroidAutoTelemetry: NitroAndroidAutoTelemetry | null;
4
+ export { HybridAutoPlay };
5
+ export { HybridAndroidAutoTelemetry };
6
6
  export declare const HybridAndroidAutomotive: AndroidAutomotive | null;
7
7
  /**
8
8
  * These are the static module names for the app running on the mobile device, head unit screen and the CarPlay dashboard.
package/lib/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { Platform } from 'react-native';
2
2
  import { NitroModules } from 'react-native-nitro-modules';
3
3
  import AutoPlayHeadlessJsTask from './AutoPlayHeadlessJsTask';
4
- AutoPlayHeadlessJsTask.registerHeadlessTask();
5
- export const HybridAutoPlay = NitroModules.createHybridObject('AutoPlay');
6
- export const HybridAndroidAutoTelemetry = Platform.OS === 'android'
7
- ? NitroModules.createHybridObject('AndroidAutoTelemetry')
8
- : null;
4
+ import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
5
+ import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
6
+ AutoPlayHeadlessJsTask.registerHeadlessTask(HybridAutoPlay);
7
+ export { HybridAutoPlay };
8
+ export { HybridAndroidAutoTelemetry };
9
9
  export const HybridAndroidAutomotive = Platform.OS === 'android'
10
10
  ? NitroModules.createHybridObject('AndroidAutomotive')
11
11
  : null;
@@ -27,9 +27,9 @@ declare class Dashboard {
27
27
  * @param eventType generic events
28
28
  * @returns callback to remove the listener
29
29
  */
30
- addListener(event: EventName, callback: () => void): import("..").CleanupCallback;
31
- addListenerRenderState(callback: (payload: VisibilityState) => void): import("..").CleanupCallback;
32
- addListenerColorScheme(callback: (payload: ColorScheme) => void): import("..").CleanupCallback;
30
+ addListener(event: EventName, callback: () => void): import("../types/Event").CleanupCallback;
31
+ addListenerRenderState(callback: (payload: VisibilityState) => void): import("../types/Event").CleanupCallback;
32
+ addListenerColorScheme(callback: (payload: ColorScheme) => void): import("../types/Event").CleanupCallback;
33
33
  }
34
34
  export declare const CarPlayDashboard: Dashboard;
35
35
  export {};
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  import { AppRegistry, Platform } from 'react-native';
3
3
  import { NitroModules } from 'react-native-nitro-modules';
4
- import { HybridAutoPlay } from '..';
5
4
  import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
5
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
6
6
  import { NitroImageUtil } from '../utils/NitroImage';
7
7
  const HybridCarPlayDashboard = Platform.OS === 'ios'
8
8
  ? NitroModules.createHybridObject('CarPlayDashboard')
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { type AutoText } from '..';
2
+ import type { AutoText } from '..';
3
3
  import type { ActionButtonAndroid, MapButton, MapPanButton } from '../types/Button';
4
4
  import type { AutoManeuver } from '../types/Maneuver';
5
5
  import type { ColorScheme, RootComponentInitialProps } from '../types/RootComponent';
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
2
  import { AppRegistry, Platform } from 'react-native';
3
3
  import { NitroModules } from 'react-native-nitro-modules';
4
- import { HybridAutoPlay } from '..';
5
4
  import { MapTemplateProvider } from '../components/MapTemplateContext';
6
5
  import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
6
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
7
7
  import { NitroActionUtil } from '../utils/NitroAction';
8
8
  import { NitroAlertUtil } from '../utils/NitroAlert';
9
9
  import { NitroManeuverUtil } from '../utils/NitroManeuver';
@@ -1,4 +1,4 @@
1
- import { type AutoImage, type BaseMapTemplateConfig, type CustomActionButtonAndroid, type HeaderActionsAndroid, type TextButton } from '..';
1
+ import type { AutoImage, BaseMapTemplateConfig, CustomActionButtonAndroid, HeaderActionsAndroid, TextButton } from '..';
2
2
  import type { AutoText } from '../types/Text';
3
3
  import { type NitroAction } from '../utils/NitroAction';
4
4
  import { type NitroImage } from '../utils/NitroImage';
@@ -1,7 +1,7 @@
1
1
  import { Platform } from 'react-native';
2
2
  import { NitroModules } from 'react-native-nitro-modules';
3
3
  import uuid from 'react-native-uuid';
4
- import { HybridAutoPlay, } from '..';
4
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
5
5
  import { NitroActionUtil } from '../utils/NitroAction';
6
6
  import { NitroImageUtil } from '../utils/NitroImage';
7
7
  import { NitroMapButton } from '../utils/NitroMapButton';
@@ -1,5 +1,5 @@
1
1
  import uuid from 'react-native-uuid';
2
- import { HybridAutoPlay } from '..';
2
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
3
3
  import { NitroActionUtil } from '../utils/NitroAction';
4
4
  export class Template {
5
5
  id;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iternio/react-native-auto-play",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "Android Auto and Apple CarPlay for react-native",
5
5
  "main": "lib/index",
6
6
  "module": "lib/index",
@@ -36,8 +36,9 @@
36
36
  "typescript": "tsc",
37
37
  "generate:fonts": "node ./assets/symbolFont/bundleAsset.js",
38
38
  "specs": "nitrogen --logLevel=\"debug\"",
39
- "prepare": "tsc && nitrogen && npm run generate:fonts",
40
- "swift:format": "swift-format format ./ios --in-place --recursive"
39
+ "prepare": "yarn circular && tsc && nitrogen && npm run generate:fonts",
40
+ "swift:format": "swift-format format ./ios --in-place --recursive",
41
+ "circular": "dpdm ./src/* --circular --exit-code circular:1 --no-tree --warning=false --transform"
41
42
  },
42
43
  "keywords": [
43
44
  "react-native",
@@ -59,7 +60,8 @@
59
60
  },
60
61
  "devDependencies": {
61
62
  "@types/jest": "^29.5.12",
62
- "@types/react": "^19.1.03",
63
+ "@types/react": "~19.2.0",
64
+ "dpdm": "^4.0.1",
63
65
  "nitrogen": "^0.35.3",
64
66
  "typescript": "^5.8.3"
65
67
  },
@@ -1,19 +1,22 @@
1
1
  import { AppRegistry, Platform, type Task, type TaskProvider } from 'react-native';
2
- import { HybridAutoPlay } from '.';
2
+ import type { AutoPlay as NitroAutoPlay } from './specs/AutoPlay.nitro';
3
3
 
4
- const taskProvider: TaskProvider = (): Task => () =>
5
- new Promise((resolve) => {
6
- const remove = HybridAutoPlay.addListener('didDisconnect', () => {
7
- resolve();
8
- remove();
4
+ const createTaskProvider =
5
+ (hybridAutoPlay: NitroAutoPlay): TaskProvider =>
6
+ (): Task =>
7
+ () =>
8
+ new Promise((resolve) => {
9
+ const remove = hybridAutoPlay.addListener('didDisconnect', () => {
10
+ resolve();
11
+ remove();
12
+ });
9
13
  });
10
- });
11
14
 
12
- const registerHeadlessTask = () => {
15
+ const registerHeadlessTask = (hybridAutoPlay: NitroAutoPlay) => {
13
16
  if (Platform.OS !== 'android') {
14
17
  return;
15
18
  }
16
- AppRegistry.registerHeadlessTask('AndroidAutoHeadlessJsTask', taskProvider);
19
+ AppRegistry.registerHeadlessTask('AndroidAutoHeadlessJsTask', createTaskProvider(hybridAutoPlay));
17
20
  };
18
21
 
19
22
  export default { registerHeadlessTask };
@@ -1,6 +1,7 @@
1
1
  import type React from 'react';
2
2
  import { createContext, useEffect, useState } from 'react';
3
- import { HybridAutoPlay, type SafeAreaInsets } from '..';
3
+ import type { SafeAreaInsets } from '..';
4
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
4
5
 
5
6
  const DEFAULT: SafeAreaInsets = { top: 0, bottom: 0, left: 0, right: 0 };
6
7
 
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useState } from 'react';
2
2
  import { type Permission, PermissionsAndroid } from 'react-native';
3
- import { HybridAndroidAutoTelemetry, HybridAutoPlay } from '..';
3
+ import { HybridAndroidAutoTelemetry } from '../hybrid/HybridAndroidAutoTelemetry';
4
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
4
5
 
5
6
  import type { AndroidAutoPermissions, Telemetry } from '../types/Telemetry';
6
7
 
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useRef, useState } from 'react';
2
- import { HybridAutoPlay } from '..';
2
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
3
3
 
4
4
  /**
5
5
  * An effect hook that only runs when the CarPlay/Android Auto screen is visible to the user and dependencies have changed.
@@ -1,5 +1,6 @@
1
1
  import { useCallback, useEffect, useState } from 'react';
2
- import { HybridAutoPlay, type Location } from '..';
2
+ import type { Location } from '..';
3
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
3
4
 
4
5
  export const useVoiceInput = () => {
5
6
  const [isConnected, setIsConnected] = useState(false);
@@ -0,0 +1,5 @@
1
+ import { NitroModules } from 'react-native-nitro-modules';
2
+ import type { AndroidAutoTelemetry } from '../specs/AndroidAutoTelemetry.nitro';
3
+
4
+ export const HybridAndroidAutoTelemetry =
5
+ NitroModules.createHybridObject<AndroidAutoTelemetry>('AndroidAutoTelemetry');
@@ -0,0 +1,3 @@
1
+ import type { AndroidAutoTelemetry } from '../specs/AndroidAutoTelemetry.nitro';
2
+
3
+ export const HybridAndroidAutoTelemetry: AndroidAutoTelemetry | null = null;
@@ -0,0 +1,4 @@
1
+ import { NitroModules } from 'react-native-nitro-modules';
2
+ import type { AutoPlay } from '../specs/AutoPlay.nitro';
3
+
4
+ export const HybridAutoPlay = NitroModules.createHybridObject<AutoPlay>('AutoPlay');
package/src/index.ts CHANGED
@@ -1,18 +1,14 @@
1
1
  import { Platform } from 'react-native';
2
2
  import { NitroModules } from 'react-native-nitro-modules';
3
3
  import AutoPlayHeadlessJsTask from './AutoPlayHeadlessJsTask';
4
+ import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
5
+ import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
4
6
  import type { AndroidAutomotive } from './specs/AndroidAutomotive.nitro';
5
- import type { AndroidAutoTelemetry as NitroAndroidAutoTelemetry } from './specs/AndroidAutoTelemetry.nitro';
6
- import type { AutoPlay as NitroAutoPlay } from './specs/AutoPlay.nitro';
7
7
 
8
- AutoPlayHeadlessJsTask.registerHeadlessTask();
8
+ AutoPlayHeadlessJsTask.registerHeadlessTask(HybridAutoPlay);
9
9
 
10
- export const HybridAutoPlay = NitroModules.createHybridObject<NitroAutoPlay>('AutoPlay');
11
-
12
- export const HybridAndroidAutoTelemetry =
13
- Platform.OS === 'android'
14
- ? NitroModules.createHybridObject<NitroAndroidAutoTelemetry>('AndroidAutoTelemetry')
15
- : null;
10
+ export { HybridAutoPlay };
11
+ export { HybridAndroidAutoTelemetry };
16
12
 
17
13
  export const HybridAndroidAutomotive =
18
14
  Platform.OS === 'android'
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  import { AppRegistry, Platform } from 'react-native';
3
3
  import { NitroModules } from 'react-native-nitro-modules';
4
- import { HybridAutoPlay } from '..';
5
4
  import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
5
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
6
6
  import type {
7
7
  BaseCarPlayDashboardButton,
8
8
  CarPlayDashboard as NitroCarPlayDashboard,
@@ -1,9 +1,10 @@
1
1
  import React from 'react';
2
2
  import { AppRegistry, Platform } from 'react-native';
3
3
  import { NitroModules } from 'react-native-nitro-modules';
4
- import { type AutoText, HybridAutoPlay } from '..';
4
+ import type { AutoText } from '..';
5
5
  import { MapTemplateProvider } from '../components/MapTemplateContext';
6
6
  import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
7
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
7
8
  import type { MapTemplate as NitroMapTemplate } from '../specs/MapTemplate.nitro';
8
9
  import type { ActionButtonAndroid, MapButton, MapPanButton } from '../types/Button';
9
10
  import type { AutoManeuver } from '../types/Maneuver';
@@ -1,14 +1,14 @@
1
1
  import { Platform } from 'react-native';
2
2
  import { NitroModules } from 'react-native-nitro-modules';
3
3
  import uuid from 'react-native-uuid';
4
- import {
5
- type AutoImage,
6
- type BaseMapTemplateConfig,
7
- type CustomActionButtonAndroid,
8
- type HeaderActionsAndroid,
9
- HybridAutoPlay,
10
- type TextButton,
4
+ import type {
5
+ AutoImage,
6
+ BaseMapTemplateConfig,
7
+ CustomActionButtonAndroid,
8
+ HeaderActionsAndroid,
9
+ TextButton,
11
10
  } from '..';
11
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
12
12
  import type { MessageTemplate as NitroMessageTemplate } from '../specs/MessageTemplate.nitro';
13
13
  import type { AutoText } from '../types/Text';
14
14
  import { type NitroAction, NitroActionUtil } from '../utils/NitroAction';
@@ -1,5 +1,5 @@
1
1
  import uuid from 'react-native-uuid';
2
- import { HybridAutoPlay } from '..';
2
+ import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
3
3
  import type { ActionButtonAndroid, ActionButtonIos, AppButton, BackButton } from '../types/Button';
4
4
  import { type NitroAction, NitroActionUtil } from '../utils/NitroAction';
5
5
  import type { NitroMapButton } from '../utils/NitroMapButton';
@@ -1,36 +0,0 @@
1
- package com.margelo.nitro.swe.iternio.reactnativeautoplay.utils
2
-
3
- import com.facebook.react.ReactApplication
4
- import com.facebook.react.ReactInstanceEventListener
5
- import com.facebook.react.bridge.ReactContext
6
- import kotlinx.coroutines.suspendCancellableCoroutine
7
- import kotlin.coroutines.resume
8
-
9
- object ReactContextResolver {
10
- suspend fun getReactContext(application: ReactApplication): ReactContext {
11
- val host =
12
- application.reactHost ?: throw IllegalArgumentException("application host null")
13
-
14
- return suspendCancellableCoroutine { continuation ->
15
- host.currentReactContext?.let {
16
- continuation.resume(it)
17
- return@suspendCancellableCoroutine
18
- }
19
-
20
- val listener = object : ReactInstanceEventListener {
21
- override fun onReactContextInitialized(context: ReactContext) {
22
- host.removeReactInstanceEventListener(this)
23
- continuation.resume(context)
24
- }
25
- }
26
- host.addReactInstanceEventListener(listener)
27
-
28
- continuation.invokeOnCancellation {
29
- host.removeReactInstanceEventListener(listener)
30
- }
31
-
32
- host.start()
33
- }
34
-
35
- }
36
- }