@iternio/react-native-auto-play 0.5.14-beta.1 → 0.6.1

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 (201) hide show
  1. package/README.md +270 -36
  2. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoSession.kt +5 -0
  3. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplate.kt +9 -2
  4. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/NativeBackdrop.kt +40 -0
  5. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VirtualRenderer.kt +52 -0
  6. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/GridTemplate.kt +47 -13
  7. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/Parser.kt +69 -15
  8. package/ios/Types.swift +3 -0
  9. package/ios/extensions/UIImage+Toggle.swift +5 -2
  10. package/ios/hybrid/HybridAutoPlay.swift +28 -16
  11. package/ios/hybrid/HybridMapTemplate.swift +22 -5
  12. package/ios/scenes/AutoPlayInterfaceController.swift +261 -72
  13. package/ios/templates/AutoPlayMapPanelDelegate.swift +190 -0
  14. package/ios/templates/AutoPlayTemplate.swift +24 -2
  15. package/ios/templates/GridTemplate.swift +57 -57
  16. package/ios/templates/InformationTemplate.swift +84 -9
  17. package/ios/templates/ListTemplate.swift +66 -11
  18. package/ios/templates/MapTemplate.swift +83 -68
  19. package/ios/templates/MessageTemplate.swift +72 -6
  20. package/ios/templates/Parser.swift +564 -69
  21. package/ios/templates/SearchTemplate.swift +1 -1
  22. package/ios/templates/TemplateStore.swift +5 -15
  23. package/ios/utils/SymbolFont.swift +13 -28
  24. package/jest.js +2 -0
  25. package/lib/Constants.d.ts +4 -0
  26. package/lib/Constants.js +6 -0
  27. package/lib/index.d.ts +1 -0
  28. package/lib/index.js +1 -0
  29. package/lib/index.web.d.ts +73 -0
  30. package/lib/index.web.js +72 -1
  31. package/lib/specs/MapTemplate.nitro.d.ts +3 -1
  32. package/lib/templates/GridTemplate.d.ts +23 -3
  33. package/lib/templates/GridTemplate.js +8 -0
  34. package/lib/templates/InformationTemplate.d.ts +38 -12
  35. package/lib/templates/ListTemplate.d.ts +16 -47
  36. package/lib/templates/MapTemplate.d.ts +26 -2
  37. package/lib/templates/MapTemplate.js +16 -2
  38. package/lib/templates/MessageTemplate.d.ts +52 -11
  39. package/lib/templates/MessageTemplate.js +1 -1
  40. package/lib/types/Image.d.ts +6 -1
  41. package/lib/utils/NitroColor.d.ts +1 -0
  42. package/lib/utils/NitroColor.js +8 -0
  43. package/lib/utils/NitroImage.js +1 -1
  44. package/lib/utils/NitroManeuver.js +1 -3
  45. package/lib/utils/NitroOptionsPanel.d.ts +103 -0
  46. package/lib/utils/NitroOptionsPanel.js +63 -0
  47. package/lib/utils/NitroSection.d.ts +89 -2
  48. package/lib/utils/NitroSection.js +49 -2
  49. package/lib-cjs/AutoPlayHeadlessJsTask.js +16 -0
  50. package/lib-cjs/Constants.js +9 -0
  51. package/lib-cjs/components/MapTemplateContext.js +10 -0
  52. package/lib-cjs/components/SafeAreaInsetsContext.js +21 -0
  53. package/lib-cjs/components/SafeAreaView.js +22 -0
  54. package/lib-cjs/components/WindowInformationWrapper.js +20 -0
  55. package/lib-cjs/hooks/useAndroidAutoTelemetry.js +115 -0
  56. package/lib-cjs/hooks/useFocusedEffect.js +35 -0
  57. package/lib-cjs/hooks/useMapTemplate.js +13 -0
  58. package/lib-cjs/hooks/useSafeAreaInsets.js +9 -0
  59. package/lib-cjs/hooks/useVoiceInput.js +42 -0
  60. package/lib-cjs/hybrid/HybridAndroidAutoTelemetry.js +4 -0
  61. package/lib-cjs/hybrid/HybridAndroidWindowInformation.js +4 -0
  62. package/lib-cjs/hybrid/HybridAutoPlay.js +5 -0
  63. package/lib-cjs/hybrid/HybridVoice.js +61 -0
  64. package/lib-cjs/index.js +76 -0
  65. package/lib-cjs/index.web.js +98 -0
  66. package/lib-cjs/scenes/AutoPlayCluster.js +140 -0
  67. package/lib-cjs/scenes/CarPlayDashboardScene.js +100 -0
  68. package/lib-cjs/specs/AndroidAutoTelemetry.nitro.js +2 -0
  69. package/lib-cjs/specs/AndroidAutomotive.nitro.js +16 -0
  70. package/lib-cjs/specs/AndroidWindowInformation.nitro.js +2 -0
  71. package/lib-cjs/specs/AutoPlay.nitro.js +2 -0
  72. package/lib-cjs/specs/CarPlayDashboard.nitro.js +2 -0
  73. package/lib-cjs/specs/Cluster.nitro.js +2 -0
  74. package/lib-cjs/specs/GridTemplate.nitro.js +2 -0
  75. package/lib-cjs/specs/InformationTemplate.nitro.js +2 -0
  76. package/lib-cjs/specs/ListTemplate.nitro.js +2 -0
  77. package/lib-cjs/specs/MapTemplate.nitro.js +2 -0
  78. package/lib-cjs/specs/MessageTemplate.nitro.js +2 -0
  79. package/lib-cjs/specs/SearchTemplate.nitro.js +2 -0
  80. package/lib-cjs/specs/SignInTemplate.nitro.js +2 -0
  81. package/lib-cjs/specs/Voice.nitro.js +2 -0
  82. package/lib-cjs/templates/GridTemplate.js +41 -0
  83. package/lib-cjs/templates/InformationTemplate.js +49 -0
  84. package/lib-cjs/templates/ListTemplate.js +33 -0
  85. package/lib-cjs/templates/MapTemplate.js +168 -0
  86. package/lib-cjs/templates/MessageTemplate.js +50 -0
  87. package/lib-cjs/templates/SearchTemplate.js +32 -0
  88. package/lib-cjs/templates/SignInTemplate.js +55 -0
  89. package/lib-cjs/templates/Template.js +40 -0
  90. package/lib-cjs/types/Button.js +12 -0
  91. package/lib-cjs/types/Event.js +2 -0
  92. package/lib-cjs/types/Image.js +2 -0
  93. package/lib-cjs/types/Maneuver.js +77 -0
  94. package/lib-cjs/types/RootComponent.js +2 -0
  95. package/lib-cjs/types/SignInMethod.js +22 -0
  96. package/lib-cjs/types/Telemetry.js +24 -0
  97. package/lib-cjs/types/Text.js +8 -0
  98. package/lib-cjs/types/Trip.js +2 -0
  99. package/lib-cjs/types/Voice.js +2 -0
  100. package/lib-cjs/utils/ErrorUtil.js +34 -0
  101. package/lib-cjs/utils/NitroAction.js +129 -0
  102. package/lib-cjs/utils/NitroAlert.js +19 -0
  103. package/lib-cjs/utils/NitroAttributedString.js +14 -0
  104. package/lib-cjs/utils/NitroColor.js +32 -0
  105. package/lib-cjs/utils/NitroGrid.js +12 -0
  106. package/lib-cjs/utils/NitroImage.js +97 -0
  107. package/lib-cjs/utils/NitroManeuver.js +79 -0
  108. package/lib-cjs/utils/NitroMapButton.js +33 -0
  109. package/lib-cjs/utils/NitroOptionsPanel.js +66 -0
  110. package/lib-cjs/utils/NitroSection.js +112 -0
  111. package/nitrogen/generated/android/ReactNativeAutoPlay+autolinking.cmake +1 -0
  112. package/nitrogen/generated/android/c++/JChargingConnector.hpp +79 -0
  113. package/nitrogen/generated/android/c++/JGridImageSize.hpp +64 -0
  114. package/nitrogen/generated/android/c++/JGridTemplateConfig.hpp +7 -1
  115. package/nitrogen/generated/android/c++/JHybridGridTemplateSpec.cpp +4 -0
  116. package/nitrogen/generated/android/c++/JHybridInformationTemplateSpec.cpp +12 -0
  117. package/nitrogen/generated/android/c++/JHybridListTemplateSpec.cpp +12 -0
  118. package/nitrogen/generated/android/c++/JHybridMapTemplateSpec.cpp +78 -3
  119. package/nitrogen/generated/android/c++/JHybridMapTemplateSpec.hpp +2 -1
  120. package/nitrogen/generated/android/c++/JHybridSearchTemplateSpec.cpp +12 -0
  121. package/nitrogen/generated/android/c++/JInformationTemplateConfig.hpp +6 -0
  122. package/nitrogen/generated/android/c++/JListImageType.hpp +67 -0
  123. package/nitrogen/generated/android/c++/JListTemplateConfig.hpp +6 -0
  124. package/nitrogen/generated/android/c++/JNitroChargerLocation.hpp +115 -0
  125. package/nitrogen/generated/android/c++/JNitroChargerOutlet.hpp +82 -0
  126. package/nitrogen/generated/android/c++/JNitroColor.hpp +8 -4
  127. package/nitrogen/generated/android/c++/JNitroOptionsPanelChargerSection.hpp +112 -0
  128. package/nitrogen/generated/android/c++/JNitroOptionsPanelConfig.hpp +157 -0
  129. package/nitrogen/generated/android/c++/JNitroOptionsPanelGridSection.hpp +102 -0
  130. package/nitrogen/generated/android/c++/JNitroOptionsPanelSection.cpp +30 -0
  131. package/nitrogen/generated/android/c++/JNitroOptionsPanelSection.hpp +129 -0
  132. package/nitrogen/generated/android/c++/JNitroRow.hpp +33 -3
  133. package/nitrogen/generated/android/c++/JNitroSection.hpp +6 -0
  134. package/nitrogen/generated/android/c++/JSearchTemplateConfig.hpp +6 -0
  135. package/nitrogen/generated/android/c++/JWaypointCoordinate.hpp +65 -0
  136. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ChargingConnector.kt +30 -0
  137. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GridImageSize.kt +25 -0
  138. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GridTemplateConfig.kt +9 -4
  139. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplateSpec.kt +5 -1
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ListImageType.kt +26 -0
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroChargerLocation.kt +90 -0
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroChargerOutlet.kt +70 -0
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroColor.kt +9 -4
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelChargerSection.kt +61 -0
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelConfig.kt +61 -0
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelGridSection.kt +56 -0
  147. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroOptionsPanelSection.kt +75 -0
  148. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroRow.kt +36 -6
  149. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/WaypointCoordinate.kt +61 -0
  150. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.hpp +174 -0
  151. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Umbrella.hpp +27 -0
  152. package/nitrogen/generated/ios/c++/HybridGridTemplateSpecSwift.hpp +3 -0
  153. package/nitrogen/generated/ios/c++/HybridInformationTemplateSpecSwift.hpp +9 -0
  154. package/nitrogen/generated/ios/c++/HybridListTemplateSpecSwift.hpp +9 -0
  155. package/nitrogen/generated/ios/c++/HybridMapTemplateSpecSwift.hpp +47 -1
  156. package/nitrogen/generated/ios/c++/HybridSearchTemplateSpecSwift.hpp +9 -0
  157. package/nitrogen/generated/ios/swift/ChargingConnector.swift +68 -0
  158. package/nitrogen/generated/ios/swift/GridImageSize.swift +48 -0
  159. package/nitrogen/generated/ios/swift/GridTemplateConfig.swift +12 -1
  160. package/nitrogen/generated/ios/swift/HybridMapTemplateSpec.swift +2 -1
  161. package/nitrogen/generated/ios/swift/HybridMapTemplateSpec_cxx.swift +31 -4
  162. package/nitrogen/generated/ios/swift/ListImageType.swift +52 -0
  163. package/nitrogen/generated/ios/swift/NitroChargerLocation.swift +161 -0
  164. package/nitrogen/generated/ios/swift/NitroChargerOutlet.swift +65 -0
  165. package/nitrogen/generated/ios/swift/NitroColor.swift +20 -2
  166. package/nitrogen/generated/ios/swift/NitroOptionsPanelChargerSection.swift +64 -0
  167. package/nitrogen/generated/ios/swift/NitroOptionsPanelConfig.swift +94 -0
  168. package/nitrogen/generated/ios/swift/NitroOptionsPanelGridSection.swift +53 -0
  169. package/nitrogen/generated/ios/swift/NitroOptionsPanelSection.swift +32 -0
  170. package/nitrogen/generated/ios/swift/NitroRow.swift +81 -1
  171. package/nitrogen/generated/ios/swift/WaypointCoordinate.swift +52 -0
  172. package/nitrogen/generated/shared/c++/ChargingConnector.hpp +104 -0
  173. package/nitrogen/generated/shared/c++/GridImageSize.hpp +84 -0
  174. package/nitrogen/generated/shared/c++/GridTemplateConfig.hpp +8 -1
  175. package/nitrogen/generated/shared/c++/HybridMapTemplateSpec.cpp +1 -0
  176. package/nitrogen/generated/shared/c++/HybridMapTemplateSpec.hpp +5 -1
  177. package/nitrogen/generated/shared/c++/ListImageType.hpp +88 -0
  178. package/nitrogen/generated/shared/c++/NitroChargerLocation.hpp +131 -0
  179. package/nitrogen/generated/shared/c++/NitroChargerOutlet.hpp +98 -0
  180. package/nitrogen/generated/shared/c++/NitroColor.hpp +7 -3
  181. package/nitrogen/generated/shared/c++/NitroOptionsPanelChargerSection.hpp +98 -0
  182. package/nitrogen/generated/shared/c++/NitroOptionsPanelConfig.hpp +107 -0
  183. package/nitrogen/generated/shared/c++/NitroOptionsPanelGridSection.hpp +91 -0
  184. package/nitrogen/generated/shared/c++/NitroRow.hpp +39 -2
  185. package/nitrogen/generated/shared/c++/WaypointCoordinate.hpp +91 -0
  186. package/package.json +7 -3
  187. package/src/Constants.ts +9 -0
  188. package/src/index.ts +1 -0
  189. package/src/index.web.ts +166 -0
  190. package/src/specs/MapTemplate.nitro.ts +3 -1
  191. package/src/templates/GridTemplate.ts +38 -3
  192. package/src/templates/InformationTemplate.ts +60 -29
  193. package/src/templates/ListTemplate.ts +27 -55
  194. package/src/templates/MapTemplate.ts +60 -2
  195. package/src/templates/MessageTemplate.ts +71 -24
  196. package/src/types/Image.ts +6 -1
  197. package/src/utils/NitroColor.ts +10 -1
  198. package/src/utils/NitroImage.ts +1 -5
  199. package/src/utils/NitroManeuver.ts +1 -4
  200. package/src/utils/NitroOptionsPanel.ts +218 -0
  201. package/src/utils/NitroSection.ts +160 -5
@@ -1,14 +1,19 @@
1
1
  package com.margelo.nitro.swe.iternio.reactnativeautoplay.template
2
2
 
3
3
  import androidx.car.app.CarContext
4
+ import androidx.car.app.annotations.ExperimentalCarApi
4
5
  import androidx.car.app.model.GridItem
6
+ import androidx.car.app.model.GridSection
5
7
  import androidx.car.app.model.GridTemplate
6
8
  import androidx.car.app.model.ItemList
9
+ import androidx.car.app.model.SectionedItemTemplate
7
10
  import androidx.car.app.model.Template
8
11
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.GridTemplateConfig
12
+ import com.margelo.nitro.swe.iternio.reactnativeautoplay.GridImageSize
9
13
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.NitroAction
10
14
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.NitroGridButton
11
15
 
16
+ @OptIn(ExperimentalCarApi::class)
12
17
  class GridTemplate(context: CarContext, config: GridTemplateConfig) :
13
18
  AndroidAutoTemplate<GridTemplateConfig>(context, config) {
14
19
 
@@ -18,7 +23,33 @@ class GridTemplate(context: CarContext, config: GridTemplateConfig) :
18
23
  override val autoDismissMs = config.autoDismissMs
19
24
 
20
25
  override fun parse(): Template {
21
- val template = GridTemplate.Builder().apply {
26
+ val imageSize = config.imageSize
27
+ val template = when {
28
+ // SectionedItemTemplate (needed for per-item imageSize) is not a valid content
29
+ // template for MapWithContentTemplate, so imageSize is ignored while mapConfig is set.
30
+ config.mapConfig != null -> createGridTemplate()
31
+ imageSize == null || imageSize == GridImageSize.UNSET -> createGridTemplate()
32
+ else -> createSizedGridTemplate(imageSize)
33
+ }
34
+
35
+ return Parser.parseMapWithContentConfig(context, config.mapConfig, template)
36
+ }
37
+
38
+ private fun createGridTemplate(): Template = GridTemplate.Builder().apply {
39
+ setHeader(Parser.parseHeader(context, config.title, config.headerActions))
40
+
41
+ if (config.buttons.isEmpty()) {
42
+ setLoading(true)
43
+ return@apply
44
+ }
45
+
46
+ setSingleList(ItemList.Builder().apply {
47
+ config.buttons.forEach { button -> addItem(createGridItem(button)) }
48
+ }.build())
49
+ }.build()
50
+
51
+ private fun createSizedGridTemplate(imageSize: GridImageSize): Template =
52
+ SectionedItemTemplate.Builder().apply {
22
53
  setHeader(Parser.parseHeader(context, config.title, config.headerActions))
23
54
 
24
55
  if (config.buttons.isEmpty()) {
@@ -26,20 +57,23 @@ class GridTemplate(context: CarContext, config: GridTemplateConfig) :
26
57
  return@apply
27
58
  }
28
59
 
29
- setSingleList(ItemList.Builder().apply {
30
- config.buttons.forEachIndexed { index, button ->
31
- addItem(GridItem.Builder().apply {
32
- setTitle(Parser.parseText(button.title))
33
- setOnClickListener(button.onPress)
34
- button.image.let { image ->
35
- setImage(Parser.parseImage(context, image))
36
- }
37
- }.build())
38
- }
60
+ addSection(GridSection.Builder().apply {
61
+ setItemSize(imageSize.toItemSize())
62
+ config.buttons.forEach { button -> addItem(createGridItem(button)) }
39
63
  }.build())
40
64
  }.build()
41
65
 
42
- return Parser.parseMapWithContentConfig(context, config.mapConfig, template)
66
+ private fun createGridItem(button: NitroGridButton): GridItem = GridItem.Builder().apply {
67
+ setTitle(Parser.parseText(button.title))
68
+ setOnClickListener(button.onPress)
69
+ setImage(Parser.parseImage(context, button.image))
70
+ }.build()
71
+
72
+ private fun GridImageSize.toItemSize(): Int = when (this) {
73
+ GridImageSize.LARGE -> GridSection.ITEM_SIZE_LARGE
74
+ GridImageSize.MEDIUM -> GridSection.ITEM_SIZE_MEDIUM
75
+ GridImageSize.SMALL -> GridSection.ITEM_SIZE_SMALL
76
+ GridImageSize.UNSET -> error("An unset grid image size has no item size")
43
77
  }
44
78
 
45
79
  override fun setTemplateHeaderActions(headerActions: Array<NitroAction>?) {
@@ -72,4 +106,4 @@ class GridTemplate(context: CarContext, config: GridTemplateConfig) :
72
106
  config = config.copy(buttons = buttons)
73
107
  super.applyConfigUpdate()
74
108
  }
75
- }
109
+ }
@@ -36,6 +36,7 @@ import androidx.car.app.navigation.model.TravelEstimate
36
36
  import androidx.core.graphics.createBitmap
37
37
  import androidx.core.graphics.drawable.IconCompat
38
38
  import androidx.core.graphics.drawable.toBitmap
39
+ import androidx.core.net.toUri
39
40
  import com.facebook.datasource.DataSources
40
41
  import com.facebook.drawee.backends.pipeline.Fresco
41
42
  import com.facebook.imagepipeline.image.CloseableBitmap
@@ -51,6 +52,7 @@ import com.margelo.nitro.swe.iternio.reactnativeautoplay.DurationWithTimeZone
51
52
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.ForkType
52
53
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.GlyphImage
53
54
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.KeepType
55
+ import com.margelo.nitro.swe.iternio.reactnativeautoplay.ListImageType
54
56
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.ListTemplateConfig
55
57
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.ManeuverType
56
58
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.NitroAction
@@ -81,9 +83,12 @@ import java.util.Calendar
81
83
  import java.util.Locale
82
84
  import java.util.TimeZone
83
85
  import kotlin.math.abs
84
- import androidx.core.net.toUri
85
86
 
86
87
  object Parser {
88
+ // IMAGE_TYPE_MEDIUM was added to androidx.car.app in 1.8.0. Keep the protocol value here
89
+ // while this library continues to depend on 1.7.0.
90
+ private const val ROW_IMAGE_TYPE_MEDIUM = 16
91
+
87
92
  const val TAG = "Parser"
88
93
 
89
94
  fun parseHeader(
@@ -177,7 +182,11 @@ object Parser {
177
182
  }.build()
178
183
  }
179
184
 
180
- fun parseAction(context: CarContext, action: NitroAction, useParkedOnlyClickListener: Boolean = false): Action {
185
+ fun parseAction(
186
+ context: CarContext,
187
+ action: NitroAction,
188
+ useParkedOnlyClickListener: Boolean = false
189
+ ): Action {
181
190
  if (action.type == NitroActionType.APPICON) {
182
191
  return Action.APP_ICON
183
192
  }
@@ -214,11 +223,21 @@ object Parser {
214
223
  }
215
224
 
216
225
  fun parseImage(context: CarContext, image: Variant_GlyphImage_AssetImage_RemoteImage): CarIcon {
217
- return parseImage(context, image.asFirstOrNull(), image.asSecondOrNull(), image.asThirdOrNull())
226
+ return parseImage(
227
+ context,
228
+ image.asFirstOrNull(),
229
+ image.asSecondOrNull(),
230
+ image.asThirdOrNull()
231
+ )
218
232
  }
219
233
 
220
234
  fun parseImage(context: CarContext, image: NitroImage): CarIcon {
221
- return parseImage(context, image.asFirstOrNull(), image.asSecondOrNull(), image.asThirdOrNull())
235
+ return parseImage(
236
+ context,
237
+ image.asFirstOrNull(),
238
+ image.asSecondOrNull(),
239
+ image.asThirdOrNull()
240
+ )
222
241
  }
223
242
 
224
243
  fun parseImage(
@@ -229,8 +248,19 @@ object Parser {
229
248
  ): CarIcon {
230
249
  val bitmap = parseImageToBitmap(context, glyphImage, assetImage, remoteImage)
231
250
 
251
+ // the tint recolors every opaque pixel, so it would also fill the background drawn in SymbolFont
252
+ val hasGlyphBackground =
253
+ glyphImage != null && (glyphImage.backgroundColor.get(context) ushr 24) != 0
254
+
255
+ val applyDefaultTint = !hasGlyphBackground && (glyphImage?.color?.isDefault
256
+ ?: assetImage?.color?.isDefault ?: remoteImage?.color?.isDefault ?: false)
257
+
232
258
  bitmap?.let {
233
- return CarIcon.Builder(IconCompat.createWithBitmap(it)).build()
259
+ return CarIcon.Builder(IconCompat.createWithBitmap(it)).apply {
260
+ if (applyDefaultTint) {
261
+ setTint(CarColor.DEFAULT)
262
+ }
263
+ }.build()
234
264
  }
235
265
 
236
266
  // remote images might fail to load so we provide some placeholder then
@@ -397,7 +427,13 @@ object Parser {
397
427
  addText(parseText(detailedText))
398
428
  }
399
429
  row.image?.let { image ->
400
- setImage(parseImage(context, image))
430
+ val parsedImage = parseImage(context, image)
431
+ val imageType = row.imageType
432
+ if (imageType == null) {
433
+ setImage(parsedImage)
434
+ } else {
435
+ setImage(parsedImage, imageType.toRowImageType())
436
+ }
401
437
  }
402
438
  row.browsable?.let { browsable ->
403
439
  setBrowsable(browsable)
@@ -426,6 +462,14 @@ object Parser {
426
462
  }.build()
427
463
  }
428
464
 
465
+ private fun ListImageType.toRowImageType(): Int = when (this) {
466
+ ListImageType.LARGE -> Row.IMAGE_TYPE_LARGE
467
+ ListImageType.MEDIUM -> ROW_IMAGE_TYPE_MEDIUM
468
+ ListImageType.SMALL -> Row.IMAGE_TYPE_SMALL
469
+ ListImageType.EXTRA_SMALL -> Row.IMAGE_TYPE_EXTRA_SMALL
470
+ ListImageType.ICON -> Row.IMAGE_TYPE_ICON
471
+ }
472
+
429
473
  fun formatToTimestamp(time: DurationWithTimeZone): String {
430
474
  val calendar = Calendar.getInstance().apply {
431
475
  add(Calendar.SECOND, time.seconds.toInt())
@@ -591,10 +635,14 @@ object Parser {
591
635
  private fun fetchSync(context: CarContext, imageRequest: ImageRequest): Bitmap? {
592
636
  val dataSource = try {
593
637
  Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context)
594
- } catch (_: Exception) { return null }
638
+ } catch (_: Exception) {
639
+ return null
640
+ }
595
641
  val result = try {
596
642
  DataSources.waitForFinalResult(dataSource)
597
- } catch (_: Exception) { dataSource.close(); return null }
643
+ } catch (_: Exception) {
644
+ dataSource.close(); return null
645
+ }
598
646
  val image = result?.get()
599
647
  try {
600
648
  if (image is CloseableBitmap) {
@@ -602,10 +650,14 @@ object Parser {
602
650
  // whose backing bitmap has already been recycled or failed to allocate;
603
651
  // copy() can also throw (e.g., OOM on very large remote images). Either
604
652
  // way we return null so the caller falls back to a placeholder icon.
605
- return image.underlyingBitmap?.copy(Bitmap.Config.ARGB_8888, false)
653
+ return image.underlyingBitmap.copy(Bitmap.Config.ARGB_8888, false)
606
654
  } else if (image is CloseableXml) {
607
655
  val drawable = image.buildDrawable()
608
- return drawable?.toBitmap(width = image.width, height = image.height, Bitmap.Config.ARGB_8888)
656
+ return drawable?.toBitmap(
657
+ width = image.width,
658
+ height = image.height,
659
+ Bitmap.Config.ARGB_8888
660
+ )
609
661
  }
610
662
  } catch (_: Exception) {
611
663
  // Any decode/copy failure (OOM, recycled bitmap, invalid config, …) should
@@ -740,10 +792,12 @@ object Parser {
740
792
  }
741
793
  nitroManeuver.angle?.let { roundaboutExitAngle ->
742
794
  if (nitroManeuver.trafficSide == TrafficSide.LEFT) {
743
- val angle = ((180 + roundaboutExitAngle) % 360).toInt().let { if (it == 0) 360 else it }
795
+ val angle = ((180 + roundaboutExitAngle) % 360).toInt()
796
+ .let { if (it == 0) 360 else it }
744
797
  setRoundaboutExitAngle(angle)
745
798
  } else {
746
- val angle = ((180 - roundaboutExitAngle) % 360).toInt().let { if (it == 0) 360 else it }
799
+ val angle = ((180 - roundaboutExitAngle) % 360).toInt()
800
+ .let { if (it == 0) 360 else it }
747
801
  setRoundaboutExitAngle(angle)
748
802
  }
749
803
  }
@@ -822,7 +876,7 @@ object Parser {
822
876
  mapConfig.mapButtons?.let { mapButtons ->
823
877
  setMapController(
824
878
  MapController.Builder().apply {
825
- setMapActionStrip(Parser.parseMapActions(context, mapButtons)).build()
879
+ setMapActionStrip(parseMapActions(context, mapButtons)).build()
826
880
  setPanModeListener { isInPanMode ->
827
881
  mapConfig.onDidChangePanningInterface?.let {
828
882
  it(isInPanMode)
@@ -832,8 +886,8 @@ object Parser {
832
886
  )
833
887
  }
834
888
  mapConfig.headerActions?.let { headerActions ->
835
- setActionStrip(Parser.parseMapHeaderActions(context, headerActions))
889
+ setActionStrip(parseMapHeaderActions(context, headerActions))
836
890
  }
837
891
  }.build()
838
892
  }
839
- }
893
+ }
package/ios/Types.swift CHANGED
@@ -20,4 +20,7 @@ enum AutoPlayError: LocalizedError {
20
20
  case noUiWindow(String)
21
21
  case initReactRootViewFailed(String)
22
22
  case voiceInputCancelled
23
+ case rootTemplateNotMapTemplate(String)
24
+ case templateIsMapPanel(String)
25
+ case mapTemplateNotVisible(String)
23
26
  }
@@ -10,9 +10,12 @@ import UIKit
10
10
  extension UIImage {
11
11
  static func makeToggleImage(
12
12
  enabled: Bool,
13
- maximumImageSize: CGSize
13
+ maximumImageSize: CGSize,
14
+ traitCollection: UITraitCollection
14
15
  ) -> UIImage {
15
- let renderer = UIGraphicsImageRenderer(size: maximumImageSize)
16
+ let format = UIGraphicsImageRendererFormat()
17
+ format.scale = traitCollection.displayScale
18
+ let renderer = UIGraphicsImageRenderer(size: maximumImageSize, format: format)
16
19
  return renderer.image { ctx in
17
20
  // Draw the track as a pill, centered vertically
18
21
  let trackHeight = maximumImageSize.height * 0.5
@@ -160,7 +160,7 @@ class HybridAutoPlay: HybridAutoPlaySpec {
160
160
  templateId: templateId
161
161
  )
162
162
 
163
- let carPlayTemplate = template.getTemplate()
163
+ let carPlayTemplate = try template.getTemplate()
164
164
 
165
165
  if carPlayTemplate is CPMapTemplate {
166
166
  try await MainActor.run {
@@ -192,23 +192,35 @@ class HybridAutoPlay: HybridAutoPlaySpec {
192
192
 
193
193
  await template.invalidate()
194
194
 
195
- let carPlayTemplate = template.getTemplate()
196
-
197
- if carPlayTemplate is CPAlertTemplate {
198
- let animated = try await !interfaceController.dismissTemplate(
199
- animated: false
200
- )
201
-
202
- let _ = try await interfaceController.presentTemplate(
203
- carPlayTemplate,
204
- animated: animated
195
+ if #available(iOS 27.0, *), let panel = template.getPanel() as? CPMapPanel {
196
+ /// since only the top most panel gets a panelDidHide call when pressing the close button
197
+ /// we hide it globaly to avoid orphaned panels on the navigation stack
198
+ panel.showsCloseButton = false
199
+
200
+ try await interfaceController.pushPanel(
201
+ panel,
202
+ templateId: templateId
205
203
  )
206
204
  }
207
205
  else {
208
- let _ = try await interfaceController.pushTemplate(
209
- carPlayTemplate,
210
- animated: true
211
- )
206
+ let carPlayTemplate = try template.getTemplate()
207
+
208
+ if carPlayTemplate is CPAlertTemplate {
209
+ let animated = try await !interfaceController.dismissTemplate(
210
+ animated: false
211
+ )
212
+
213
+ let _ = try await interfaceController.presentTemplate(
214
+ carPlayTemplate,
215
+ animated: animated
216
+ )
217
+ }
218
+ else {
219
+ let _ = try await interfaceController.pushTemplate(
220
+ carPlayTemplate,
221
+ animated: true
222
+ )
223
+ }
212
224
  }
213
225
 
214
226
  if let autoDismissMs = template.autoDismissMs {
@@ -217,7 +229,7 @@ class HybridAutoPlay: HybridAutoPlaySpec {
217
229
  nanoseconds: UInt64(autoDismissMs) * 1_000_000
218
230
  )
219
231
 
220
- if interfaceController.topTemplateId == templateId
232
+ if interfaceController.isTopEntry(templateId: templateId)
221
233
  || interfaceController.interfaceController
222
234
  .presentedTemplate?.id == templateId
223
235
  {
@@ -147,11 +147,15 @@ class HybridMapTemplate: HybridMapTemplateSpec {
147
147
  }
148
148
  }
149
149
 
150
- func startNavigation(templateId: String, trip: TripConfig) throws {
151
- try RootModule.withAutoPlayTemplate(templateId: templateId) {
152
- (template: MapTemplate) in
153
- let trip = Parser.parseTrip(tripConfig: trip)
154
- template.startNavigation(trip: trip)
150
+ func startNavigation(templateId: String, trip: TripConfig) throws -> Promise<Void> {
151
+ return Promise.async {
152
+ try await MainActor.run {
153
+ try RootModule.withAutoPlayTemplate(templateId: templateId) {
154
+ (template: MapTemplate) in
155
+ let trip = Parser.parseTrip(tripConfig: trip)
156
+ template.startNavigation(trip: trip)
157
+ }
158
+ }
155
159
  }
156
160
  }
157
161
 
@@ -168,4 +172,17 @@ class HybridMapTemplate: HybridMapTemplateSpec {
168
172
  template.setManeuverState(state: state)
169
173
  }
170
174
  }
175
+
176
+ func updateOptionsPanel(templateId: String, config: NitroOptionsPanelConfig?) throws
177
+ -> Promise<Void>
178
+ {
179
+ return Promise.async {
180
+ try await MainActor.run {
181
+ try RootModule.withAutoPlayTemplate(templateId: templateId) {
182
+ (template: MapTemplate) in
183
+ template.updateOptionsPanel(config: config)
184
+ }
185
+ }
186
+ }
187
+ }
171
188
  }