@iternio/react-native-auto-play 0.3.10 → 0.3.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.
Files changed (134) hide show
  1. package/README.md +60 -2
  2. package/android/src/automotive/AndroidManifest.xml +1 -0
  3. package/android/src/main/AndroidManifest.xml +1 -0
  4. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoSession.kt +1 -0
  5. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlay.kt +91 -0
  6. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VoiceInputManager.kt +214 -0
  7. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/MapTemplate.kt +8 -1
  8. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/Parser.kt +108 -38
  9. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/utils/BitmapCache.kt +14 -0
  10. package/ios/extensions/NitroImageExtensions.swift +10 -1
  11. package/ios/hybrid/HybridAutoPlay.swift +51 -4
  12. package/ios/hybrid/HybridMapTemplate.swift +2 -5
  13. package/ios/templates/GridTemplate.swift +7 -0
  14. package/ios/templates/MapTemplate.swift +55 -0
  15. package/ios/templates/Parser.swift +109 -11
  16. package/ios/utils/VoiceInputManager.swift +233 -0
  17. package/lib/specs/AutoPlay.nitro.d.ts +31 -1
  18. package/lib/templates/MapTemplate.d.ts +7 -1
  19. package/lib/templates/MapTemplate.js +10 -2
  20. package/lib/types/Image.d.ts +13 -0
  21. package/lib/types/Maneuver.d.ts +6 -0
  22. package/lib/utils/NitroImage.d.ts +6 -1
  23. package/lib/utils/NitroImage.js +7 -0
  24. package/lib/utils/NitroManeuver.d.ts +2 -0
  25. package/nitrogen/generated/android/ReactNativeAutoPlay+autolinking.cmake +1 -1
  26. package/nitrogen/generated/android/c++/JGridTemplateConfig.hpp +3 -1
  27. package/nitrogen/generated/android/c++/JHybridAutoPlaySpec.cpp +48 -1
  28. package/nitrogen/generated/android/c++/JHybridAutoPlaySpec.hpp +4 -0
  29. package/nitrogen/generated/android/c++/JHybridClusterSpec.cpp +4 -0
  30. package/nitrogen/generated/android/c++/JHybridGridTemplateSpec.cpp +5 -1
  31. package/nitrogen/generated/android/c++/JHybridInformationTemplateSpec.cpp +5 -1
  32. package/nitrogen/generated/android/c++/JHybridListTemplateSpec.cpp +5 -1
  33. package/nitrogen/generated/android/c++/JHybridMapTemplateSpec.cpp +5 -1
  34. package/nitrogen/generated/android/c++/JHybridMessageTemplateSpec.cpp +5 -1
  35. package/nitrogen/generated/android/c++/JHybridSearchTemplateSpec.cpp +5 -1
  36. package/nitrogen/generated/android/c++/JHybridSignInTemplateSpec.cpp +5 -1
  37. package/nitrogen/generated/android/c++/JImageLane.hpp +2 -0
  38. package/nitrogen/generated/android/c++/JInformationTemplateConfig.hpp +3 -1
  39. package/nitrogen/generated/android/c++/JLaneGuidance.hpp +2 -0
  40. package/nitrogen/generated/android/c++/JListTemplateConfig.hpp +3 -1
  41. package/nitrogen/generated/android/c++/JMapTemplateConfig.hpp +8 -2
  42. package/nitrogen/generated/android/c++/JMessageTemplateConfig.hpp +7 -5
  43. package/nitrogen/generated/android/c++/JNitroAction.hpp +7 -5
  44. package/nitrogen/generated/android/c++/JNitroAttributedString.hpp +2 -0
  45. package/nitrogen/generated/android/c++/JNitroAttributedStringImage.hpp +2 -0
  46. package/nitrogen/generated/android/c++/JNitroBaseMapTemplateConfig.hpp +3 -1
  47. package/nitrogen/generated/android/c++/JNitroGridButton.hpp +2 -0
  48. package/nitrogen/generated/android/c++/JNitroImage.cpp +6 -2
  49. package/nitrogen/generated/android/c++/JNitroImage.hpp +19 -2
  50. package/nitrogen/generated/android/c++/JNitroLoadingManeuver.hpp +15 -4
  51. package/nitrogen/generated/android/c++/JNitroManeuver.hpp +3 -1
  52. package/nitrogen/generated/android/c++/JNitroMapButton.hpp +2 -0
  53. package/nitrogen/generated/android/c++/JNitroMessageManeuver.hpp +7 -5
  54. package/nitrogen/generated/android/c++/JNitroNavigationAlert.hpp +7 -5
  55. package/nitrogen/generated/android/c++/JNitroRoutingManeuver.hpp +7 -5
  56. package/nitrogen/generated/android/c++/JNitroRow.hpp +7 -5
  57. package/nitrogen/generated/android/c++/JNitroSection.hpp +3 -1
  58. package/nitrogen/generated/android/c++/JPreferredImageLane.hpp +2 -0
  59. package/nitrogen/generated/android/c++/JRemoteImage.hpp +68 -0
  60. package/nitrogen/generated/android/c++/JSearchTemplateConfig.hpp +3 -1
  61. package/nitrogen/generated/android/c++/JSignInTemplateConfig.hpp +3 -1
  62. package/nitrogen/generated/android/c++/JVariant_GlyphImage_AssetImage_RemoteImage.cpp +30 -0
  63. package/nitrogen/generated/android/c++/JVariant_GlyphImage_AssetImage_RemoteImage.hpp +92 -0
  64. package/nitrogen/generated/android/c++/JVariant_PreferredImageLane_ImageLane.hpp +2 -0
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlaySpec.kt +17 -0
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/MapTemplateConfig.kt +7 -4
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/MessageTemplateConfig.kt +3 -3
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroAction.kt +3 -3
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroImage.kt +14 -2
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroLoadingManeuver.kt +9 -3
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroMessageManeuver.kt +2 -2
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroNavigationAlert.kt +3 -3
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroRoutingManeuver.kt +2 -2
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroRow.kt +3 -3
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/RemoteImage.kt +44 -0
  76. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/{Variant_GlyphImage_AssetImage.kt → Variant_GlyphImage_AssetImage_RemoteImage.kt} +20 -8
  77. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.cpp +16 -8
  78. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.hpp +156 -79
  79. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Umbrella.hpp +4 -0
  80. package/nitrogen/generated/ios/c++/HybridAutoPlaySpecSwift.hpp +37 -0
  81. package/nitrogen/generated/ios/c++/HybridCarPlayDashboardSpecSwift.hpp +3 -0
  82. package/nitrogen/generated/ios/c++/HybridClusterSpecSwift.hpp +3 -0
  83. package/nitrogen/generated/ios/c++/HybridGridTemplateSpecSwift.hpp +3 -0
  84. package/nitrogen/generated/ios/c++/HybridInformationTemplateSpecSwift.hpp +3 -0
  85. package/nitrogen/generated/ios/c++/HybridListTemplateSpecSwift.hpp +3 -0
  86. package/nitrogen/generated/ios/c++/HybridMapTemplateSpecSwift.hpp +3 -0
  87. package/nitrogen/generated/ios/c++/HybridMessageTemplateSpecSwift.hpp +3 -0
  88. package/nitrogen/generated/ios/c++/HybridSearchTemplateSpecSwift.hpp +3 -0
  89. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_ArrayBuffer_.swift +46 -0
  90. package/nitrogen/generated/ios/swift/HybridAutoPlaySpec.swift +4 -0
  91. package/nitrogen/generated/ios/swift/HybridAutoPlaySpec_cxx.swift +82 -0
  92. package/nitrogen/generated/ios/swift/ImageLane.swift +9 -4
  93. package/nitrogen/generated/ios/swift/MapTemplateConfig.swift +12 -1
  94. package/nitrogen/generated/ios/swift/MessageTemplateConfig.swift +16 -11
  95. package/nitrogen/generated/ios/swift/NitroAction.swift +16 -11
  96. package/nitrogen/generated/ios/swift/NitroAttributedStringImage.swift +9 -4
  97. package/nitrogen/generated/ios/swift/NitroCarPlayDashboardButton.swift +9 -4
  98. package/nitrogen/generated/ios/swift/NitroGridButton.swift +9 -4
  99. package/nitrogen/generated/ios/swift/NitroImage.swift +2 -1
  100. package/nitrogen/generated/ios/swift/NitroLoadingManeuver.swift +25 -2
  101. package/nitrogen/generated/ios/swift/NitroMapButton.swift +9 -4
  102. package/nitrogen/generated/ios/swift/NitroMessageManeuver.swift +16 -11
  103. package/nitrogen/generated/ios/swift/NitroNavigationAlert.swift +16 -11
  104. package/nitrogen/generated/ios/swift/NitroRoutingManeuver.swift +25 -15
  105. package/nitrogen/generated/ios/swift/NitroRow.swift +16 -11
  106. package/nitrogen/generated/ios/swift/PreferredImageLane.swift +9 -4
  107. package/nitrogen/generated/ios/swift/RemoteImage.swift +58 -0
  108. package/nitrogen/generated/ios/swift/{Variant_GlyphImage_AssetImage.swift → Variant_GlyphImage_AssetImage_RemoteImage.swift} +4 -3
  109. package/nitrogen/generated/shared/c++/HybridAutoPlaySpec.cpp +4 -0
  110. package/nitrogen/generated/shared/c++/HybridAutoPlaySpec.hpp +5 -0
  111. package/nitrogen/generated/shared/c++/ImageLane.hpp +8 -5
  112. package/nitrogen/generated/shared/c++/MapTemplateConfig.hpp +8 -1
  113. package/nitrogen/generated/shared/c++/MessageTemplateConfig.hpp +8 -5
  114. package/nitrogen/generated/shared/c++/NitroAction.hpp +8 -5
  115. package/nitrogen/generated/shared/c++/NitroAttributedStringImage.hpp +8 -5
  116. package/nitrogen/generated/shared/c++/NitroCarPlayDashboardButton.hpp +8 -5
  117. package/nitrogen/generated/shared/c++/NitroGridButton.hpp +8 -5
  118. package/nitrogen/generated/shared/c++/NitroLoadingManeuver.hpp +15 -4
  119. package/nitrogen/generated/shared/c++/NitroMapButton.hpp +8 -5
  120. package/nitrogen/generated/shared/c++/NitroMessageManeuver.hpp +8 -5
  121. package/nitrogen/generated/shared/c++/NitroNavigationAlert.hpp +8 -5
  122. package/nitrogen/generated/shared/c++/NitroRoutingManeuver.hpp +12 -9
  123. package/nitrogen/generated/shared/c++/NitroRow.hpp +8 -5
  124. package/nitrogen/generated/shared/c++/PreferredImageLane.hpp +8 -5
  125. package/nitrogen/generated/shared/c++/RemoteImage.hpp +94 -0
  126. package/package.json +1 -1
  127. package/src/specs/AutoPlay.nitro.ts +39 -1
  128. package/src/templates/MapTemplate.ts +23 -2
  129. package/src/types/Image.ts +14 -0
  130. package/src/types/Maneuver.ts +6 -0
  131. package/src/utils/NitroImage.ts +15 -1
  132. package/src/utils/NitroManeuver.ts +2 -0
  133. package/nitrogen/generated/android/c++/JVariant_GlyphImage_AssetImage.cpp +0 -26
  134. package/nitrogen/generated/android/c++/JVariant_GlyphImage_AssetImage.hpp +0 -75
@@ -0,0 +1,233 @@
1
+ import AVFoundation
2
+ import CarPlay
3
+
4
+ /// Captures audio from the car microphone and buffers raw 16 kHz / 16-bit / mono PCM.
5
+ /// Recording stops automatically when silence is detected or the max duration is reached.
6
+ class VoiceInputManager {
7
+ private var audioEngine: AVAudioEngine?
8
+ private var voiceControlTemplate: CPVoiceControlTemplate?
9
+ private var continuation: CheckedContinuation<[Int16], Error>?
10
+ private var samples: [Int16] = []
11
+ private var isStopping = false
12
+ private let stopLock = NSLock()
13
+
14
+ // Timing
15
+ private var recordingStart: Date?
16
+ private var silenceStart: Date?
17
+
18
+ private static let sampleRate: Double = 16_000
19
+ private static let tapBufferSize: AVAudioFrameCount = 4_096
20
+ private static let silenceAmplitudeThreshold = 500
21
+ private static let warmupMs: Double = 500
22
+
23
+ private static let targetFormat = AVAudioFormat(
24
+ commonFormat: .pcmFormatInt16,
25
+ sampleRate: sampleRate,
26
+ channels: 1,
27
+ interleaved: true
28
+ )!
29
+
30
+ // MARK: - Public
31
+
32
+ func start(
33
+ interfaceController: AutoPlayInterfaceController?,
34
+ silenceThresholdMs: Double,
35
+ maxDurationMs: Double,
36
+ listeningText: String
37
+ ) async throws -> Data {
38
+ let samples = try await withCheckedThrowingContinuation {
39
+ (cont: CheckedContinuation<[Int16], Error>) in
40
+ self.continuation = cont
41
+ self.samples = []
42
+ self.isStopping = false
43
+
44
+ do {
45
+ try self.startCapture(
46
+ interfaceController: interfaceController,
47
+ silenceThresholdMs: silenceThresholdMs,
48
+ maxDurationMs: maxDurationMs,
49
+ listeningText: listeningText
50
+ )
51
+ }
52
+ catch {
53
+ self.stopCapture(interfaceController: interfaceController)
54
+ self.continuation = nil
55
+ cont.resume(throwing: error)
56
+ }
57
+ }
58
+
59
+ return samplesAsData(samples)
60
+ }
61
+
62
+ func stop(interfaceController: AutoPlayInterfaceController? = nil) {
63
+ stopLock.lock()
64
+ guard !isStopping else {
65
+ stopLock.unlock()
66
+ return
67
+ }
68
+ isStopping = true
69
+ let capturedContinuation = continuation
70
+ let capturedSamples = samples
71
+ continuation = nil
72
+ samples = []
73
+ stopLock.unlock()
74
+
75
+ stopCapture(interfaceController: interfaceController)
76
+ capturedContinuation?.resume(returning: capturedSamples)
77
+ }
78
+
79
+ // MARK: - Private
80
+
81
+ private func startCapture(
82
+ interfaceController: AutoPlayInterfaceController?,
83
+ silenceThresholdMs: Double,
84
+ maxDurationMs: Double,
85
+ listeningText: String
86
+ ) throws {
87
+ guard AVAudioSession.sharedInstance().recordPermission == .granted else {
88
+ throw VoiceInputError.microphonePermissionDenied
89
+ }
90
+
91
+ // Activate the session first so inputNode reports the correct hardware format
92
+ let session = AVAudioSession.sharedInstance()
93
+ try session.setCategory(.playAndRecord, mode: .measurement, options: [.mixWithOthers])
94
+ try session.setActive(true)
95
+
96
+ if let interfaceController {
97
+ presentVoiceTemplate(interfaceController: interfaceController, listeningText: listeningText)
98
+ }
99
+
100
+ let engine = AVAudioEngine()
101
+ let inputNode = engine.inputNode
102
+ let nativeFormat = inputNode.outputFormat(forBus: 0)
103
+
104
+ let targetFormat = VoiceInputManager.targetFormat
105
+ guard let converter = AVAudioConverter(from: nativeFormat, to: targetFormat) else {
106
+ throw VoiceInputError.converterUnavailable
107
+ }
108
+
109
+ recordingStart = Date()
110
+ silenceStart = nil
111
+
112
+ inputNode.installTap(
113
+ onBus: 0,
114
+ bufferSize: VoiceInputManager.tapBufferSize,
115
+ format: nativeFormat
116
+ ) { [weak self] buffer, _ in
117
+ guard let self, !self.isStopping else { return }
118
+
119
+ let outputFrameCapacity = AVAudioFrameCount(
120
+ Double(buffer.frameLength)
121
+ * VoiceInputManager.sampleRate
122
+ / nativeFormat.sampleRate
123
+ )
124
+
125
+ guard
126
+ let outputBuffer = AVAudioPCMBuffer(
127
+ pcmFormat: targetFormat,
128
+ frameCapacity: outputFrameCapacity
129
+ )
130
+ else { return }
131
+
132
+ var conversionError: NSError?
133
+ let status = converter.convert(to: outputBuffer, error: &conversionError) {
134
+ _,
135
+ outStatus in
136
+ outStatus.pointee = .haveData
137
+ return buffer
138
+ }
139
+
140
+ guard status != .error, let int16Data = outputBuffer.int16ChannelData else { return }
141
+
142
+ let frameCount = Int(outputBuffer.frameLength)
143
+ let newSamples = Array(UnsafeBufferPointer(start: int16Data[0], count: frameCount))
144
+ self.samples.append(contentsOf: newSamples)
145
+
146
+ let now = Date()
147
+
148
+ // Max duration check
149
+ if let start = self.recordingStart,
150
+ now.timeIntervalSince(start) * 1000 >= maxDurationMs
151
+ {
152
+ self.triggerAutoStop(interfaceController: interfaceController)
153
+ return
154
+ }
155
+
156
+ // Silence detection — skip during warm-up so the pipeline has time
157
+ // to stabilise before we start measuring amplitude
158
+ if let start = self.recordingStart,
159
+ now.timeIntervalSince(start) * 1000 >= VoiceInputManager.warmupMs
160
+ {
161
+ let peak = newSamples.reduce(0) { max($0, abs(Int($1))) }
162
+ if peak < VoiceInputManager.silenceAmplitudeThreshold {
163
+ if self.silenceStart == nil { self.silenceStart = now }
164
+ if let silenceBegin = self.silenceStart,
165
+ now.timeIntervalSince(silenceBegin) * 1000 >= silenceThresholdMs
166
+ {
167
+ self.triggerAutoStop(interfaceController: interfaceController)
168
+ }
169
+ }
170
+ else {
171
+ self.silenceStart = nil
172
+ }
173
+ }
174
+ }
175
+
176
+ try engine.start()
177
+ audioEngine = engine
178
+ }
179
+
180
+ private func triggerAutoStop(interfaceController: AutoPlayInterfaceController?) {
181
+ DispatchQueue.global(qos: .userInitiated).async {
182
+ self.stop(interfaceController: interfaceController)
183
+ }
184
+ }
185
+
186
+ private func stopCapture(interfaceController: AutoPlayInterfaceController?) {
187
+ audioEngine?.inputNode.removeTap(onBus: 0)
188
+ audioEngine?.stop()
189
+ audioEngine = nil
190
+ recordingStart = nil
191
+ silenceStart = nil
192
+ try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
193
+ if let interfaceController {
194
+ dismissVoiceTemplate(interfaceController: interfaceController)
195
+ }
196
+ }
197
+
198
+ private func presentVoiceTemplate(interfaceController: AutoPlayInterfaceController, listeningText: String) {
199
+ let listeningState = CPVoiceControlState(
200
+ identifier: "listening",
201
+ titleVariants: [listeningText],
202
+ image: nil,
203
+ repeats: true
204
+ )
205
+ let template = CPVoiceControlTemplate(voiceControlStates: [listeningState])
206
+ initTemplate(template: template, id: "voice-input")
207
+ voiceControlTemplate = template
208
+
209
+ Task { @MainActor in
210
+ try? await interfaceController.presentTemplate(template, animated: true)
211
+ template.activateVoiceControlState(withIdentifier: "listening")
212
+ }
213
+ }
214
+
215
+ private func dismissVoiceTemplate(interfaceController: AutoPlayInterfaceController) {
216
+ Task { @MainActor in
217
+ try? await interfaceController.dismissTemplate(animated: true)
218
+ }
219
+ voiceControlTemplate = nil
220
+ }
221
+
222
+ private func samplesAsData(_ samples: [Int16]) -> Data {
223
+ samples.withUnsafeBufferPointer { ptr in
224
+ Data(buffer: ptr)
225
+ }
226
+ }
227
+ }
228
+
229
+ enum VoiceInputError: Error {
230
+ case microphonePermissionDenied
231
+ case converterUnavailable
232
+ case noActiveSession
233
+ }
@@ -24,12 +24,42 @@ export interface AutoPlay extends HybridObject<{
24
24
  */
25
25
  addListenerRenderState(moduleName: string, callback: (payload: VisibilityState) => void): CleanupCallback;
26
26
  /**
27
- * Adds a listener for voice input events. Not implemented on iOS.
27
+ * Adds a listener for voice input events fired by the OS (Android Auto only).
28
+ * On iOS this is a no-op — use startVoiceInput instead.
28
29
  * @param callback the callback to receive the voice input
29
30
  * @returns callback to remove the listener
30
31
  * @namespace Android
31
32
  */
32
33
  addListenerVoiceInput(callback: (coordinates: Location | undefined, query: string | undefined) => void): CleanupCallback;
34
+ /**
35
+ * Returns true if microphone permission has already been granted.
36
+ */
37
+ hasVoiceInputPermission(): boolean;
38
+ /**
39
+ * Request microphone permission from the user.
40
+ * On Android: uses the car context when Android Auto is connected, otherwise
41
+ * falls back to the React Native application context.
42
+ * On iOS: uses AVAudioApplication (iOS 17+) or AVAudioSession (iOS 15–16).
43
+ * Returns true if permission was granted, false if denied.
44
+ */
45
+ requestVoiceInputPermission(): Promise<boolean>;
46
+ /**
47
+ * Start an in-app voice recording session.
48
+ * On Android: acquires audio focus and captures via CarAudioRecord when
49
+ * Android Auto is connected, otherwise uses standard AudioRecord.
50
+ * On iOS: presents CPVoiceControlTemplate (when a car is connected) and
51
+ * captures audio via AVAudioEngine.
52
+ * Resolves with the complete raw PCM buffer (16 kHz, 16-bit, mono) when
53
+ * silence is detected, the max duration is reached, or stopVoiceInput() is called.
54
+ * Rejects if microphone permission has not been granted or recording fails to start.
55
+ */
56
+ startVoiceInput(silenceThresholdMs?: number, maxDurationMs?: number, listeningText?: string): Promise<ArrayBuffer>;
57
+ /**
58
+ * Stop the active voice recording session early. Causes the Promise returned
59
+ * by startVoiceInput() to resolve with the audio captured so far.
60
+ * No-op if no recording is in progress.
61
+ */
62
+ stopVoiceInput(): void;
33
63
  /**
34
64
  * sets the specified template as root template, initializes a new stack
35
65
  * Promise might contain an error message in case setting root template failed
@@ -6,6 +6,7 @@ import type { ColorScheme, RootComponentInitialProps } from '../types/RootCompon
6
6
  import type { TripConfig, TripPoint, TripPreviewTextConfiguration, TripsConfig } from '../types/Trip';
7
7
  import { type NitroAction } from '../utils/NitroAction';
8
8
  import { type NavigationAlert } from '../utils/NitroAlert';
9
+ import { type NitroColor, type ThemedColor } from '../utils/NitroColor';
9
10
  import { NitroMapButton } from '../utils/NitroMapButton';
10
11
  import { type HeaderActionsIos, type NitroBaseMapTemplateConfig, Template, type TemplateConfig } from './Template';
11
12
  export type Point = {
@@ -53,6 +54,7 @@ export interface NitroMapTemplateConfig extends TemplateConfig, NitroBaseMapTemp
53
54
  onAutoDriveEnabled?: () => void;
54
55
  mapButtons?: Array<NitroMapButton>;
55
56
  headerActions?: Array<NitroAction>;
57
+ defaultGuidanceBackgroundColor?: NitroColor;
56
58
  /**
57
59
  * specify the percentage of screen height/width the pan button should scroll
58
60
  * @namespace iOS
@@ -78,7 +80,7 @@ export type BaseMapTemplateConfig<T> = {
78
80
  */
79
81
  headerActions?: MapHeaderActions<T>;
80
82
  };
81
- export type MapTemplateConfig = Omit<NitroMapTemplateConfig, 'mapButtons' | 'headerActions' | 'onStopNavigation' | 'onAutoDriveEnabled'> & BaseMapTemplateConfig<MapTemplate> & {
83
+ export type MapTemplateConfig = Omit<NitroMapTemplateConfig, 'mapButtons' | 'headerActions' | 'onStopNavigation' | 'onAutoDriveEnabled' | 'defaultGuidanceBackgroundColor'> & BaseMapTemplateConfig<MapTemplate> & {
82
84
  /**
83
85
  * react component that is rendered
84
86
  */
@@ -93,6 +95,10 @@ export type MapTemplateConfig = Omit<NitroMapTemplateConfig, 'mapButtons' | 'hea
93
95
  * @namespace Android
94
96
  */
95
97
  onAutoDriveEnabled?: (template: MapTemplate) => void;
98
+ /**
99
+ * Initial navigation maneuver background color. Mainly useful, when in CarPlay the default loading maneuver does not have the right color.
100
+ */
101
+ defaultGuidanceBackgroundColor?: ThemedColor | string;
96
102
  };
97
103
  export interface TripSelectorCallback {
98
104
  setSelectedTrip: (id: string) => void;
@@ -7,6 +7,7 @@ import { SafeAreaInsetsProvider } from '../components/SafeAreaInsetsContext';
7
7
  import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
8
8
  import { NitroActionUtil } from '../utils/NitroAction';
9
9
  import { NitroAlertUtil } from '../utils/NitroAlert';
10
+ import { NitroColorUtil } from '../utils/NitroColor';
10
11
  import { NitroManeuverUtil } from '../utils/NitroManeuver';
11
12
  import { NitroMapButton } from '../utils/NitroMapButton';
12
13
  import { Template, } from './Template';
@@ -16,7 +17,7 @@ export class MapTemplate extends Template {
16
17
  template = this;
17
18
  constructor(config) {
18
19
  super(config);
19
- const { component, mapButtons, headerActions, onStopNavigation, onAutoDriveEnabled, ...baseConfig } = config;
20
+ const { component, mapButtons, headerActions, onStopNavigation, onAutoDriveEnabled, defaultGuidanceBackgroundColor, ...baseConfig } = config;
20
21
  AppRegistry.registerComponent(this.id, () => (props) => React.createElement(MapTemplateProvider, {
21
22
  mapTemplate: this.template,
22
23
  // biome-ignore lint/correctness/noChildrenProp: there is no other way in a ts file
@@ -37,6 +38,9 @@ export class MapTemplate extends Template {
37
38
  mapButtons: NitroMapButton.convert(this.template, mapButtons),
38
39
  onStopNavigation: () => onStopNavigation(this.template),
39
40
  onAutoDriveEnabled: onAutoDriveEnabled ? () => onAutoDriveEnabled(this.template) : undefined,
41
+ defaultGuidanceBackgroundColor: defaultGuidanceBackgroundColor != null
42
+ ? NitroColorUtil.convert(defaultGuidanceBackgroundColor)
43
+ : undefined,
40
44
  };
41
45
  HybridMapTemplate.createMapTemplate(nitroConfig);
42
46
  }
@@ -111,7 +115,11 @@ export class MapTemplate extends Template {
111
115
  return;
112
116
  }
113
117
  if (maneuvers.type === 'loading') {
114
- HybridMapTemplate.updateManeuvers(this.id, { isLoading: true });
118
+ HybridMapTemplate.updateManeuvers(this.id, {
119
+ isLoading: true,
120
+ cardBackgroundColor: NitroColorUtil.convert(maneuvers.cardBackgroundColor),
121
+ text: maneuvers.text != null ? maneuvers.text : undefined,
122
+ });
115
123
  return;
116
124
  }
117
125
  const messageManeuver = NitroManeuverUtil.convert(maneuvers);
@@ -24,4 +24,17 @@ export type AutoImage = {
24
24
  */
25
25
  color?: ThemedColor | string;
26
26
  type: 'asset';
27
+ } | {
28
+ /** HTTPS URL to a remote image. HTTP is not supported (blocked by App Transport Security). */
29
+ uri: string;
30
+ /**
31
+ * if specified the image gets tinted, if not it will just use the original image
32
+ */
33
+ color?: ThemedColor | string;
34
+ /**
35
+ * Network timeout in milliseconds before the remote fetch is abandoned and `null` is returned.
36
+ * Defaults to 500ms when not specified.
37
+ */
38
+ timeoutMs?: number;
39
+ type: 'remote';
27
40
  };
@@ -210,6 +210,12 @@ export type MessageManeuver = {
210
210
  };
211
211
  export type LoadingManeuver = {
212
212
  type: 'loading';
213
+ cardBackgroundColor: ThemedColor | string;
214
+ /**
215
+ * @namespace iOS CarPlay — shows text on the loading maneuver card
216
+ * @namespace Android Auto — not supported
217
+ */
218
+ text?: string;
213
219
  };
214
220
  export type AutoManeuver = (Array<RoutingManeuver> & {
215
221
  length: 0 | 1 | 2;
@@ -11,11 +11,16 @@ interface GlyphImage {
11
11
  backgroundColor: NitroColor;
12
12
  fontScale?: number;
13
13
  }
14
+ interface RemoteImage {
15
+ uri: string;
16
+ color?: NitroColor;
17
+ timeoutMs?: number;
18
+ }
14
19
  /**
15
20
  * we need to map the ButtonImage.name from GlyphName to
16
21
  * the actual numeric value so we need a nitro specific type
17
22
  */
18
- export type NitroImage = GlyphImage | AssetImage;
23
+ export type NitroImage = GlyphImage | AssetImage | RemoteImage;
19
24
  declare function convert(image: AutoImage): NitroImage;
20
25
  declare function convert(image?: AutoImage): NitroImage | undefined;
21
26
  export declare const NitroImageUtil: {
@@ -14,6 +14,13 @@ function convert(image) {
14
14
  fontScale,
15
15
  };
16
16
  }
17
+ if (image.type === 'remote') {
18
+ return {
19
+ uri: image.uri,
20
+ color: NitroColorUtil.convert(image.color),
21
+ timeoutMs: image.timeoutMs,
22
+ };
23
+ }
17
24
  // Image.resolveAssetSource is pretty terrible, it will simply return whatever object you pass it is not a number [require(...)]
18
25
  // so the input allows all optional parameters which are returned as is even though
19
26
  // the return type claims to not have any optional parameters...
@@ -35,6 +35,8 @@ export interface NitroMessageManeuver {
35
35
  }
36
36
  interface NitroLoadingManeuver {
37
37
  isLoading: true;
38
+ cardBackgroundColor: NitroColor;
39
+ text?: string;
38
40
  }
39
41
  export type NitroManeuver = Array<NitroRoutingManeuver> | NitroMessageManeuver | NitroLoadingManeuver;
40
42
  declare function convert(autoManeuver: MessageManeuver): NitroMessageManeuver;
@@ -49,7 +49,7 @@ target_sources(
49
49
  ../nitrogen/generated/android/c++/JHybridAndroidAutomotiveSpec.cpp
50
50
  ../nitrogen/generated/android/c++/JHybridAndroidAutoTelemetrySpec.cpp
51
51
  ../nitrogen/generated/android/c++/JHybridAutoPlaySpec.cpp
52
- ../nitrogen/generated/android/c++/JVariant_GlyphImage_AssetImage.cpp
52
+ ../nitrogen/generated/android/c++/JVariant_GlyphImage_AssetImage_RemoteImage.cpp
53
53
  ../nitrogen/generated/android/c++/JHybridClusterSpec.cpp
54
54
  ../nitrogen/generated/android/c++/JNitroImage.cpp
55
55
  ../nitrogen/generated/android/c++/JHybridGridTemplateSpec.cpp
@@ -33,7 +33,8 @@
33
33
  #include "JNitroImage.hpp"
34
34
  #include "JNitroMapButton.hpp"
35
35
  #include "JNitroMapButtonType.hpp"
36
- #include "JVariant_GlyphImage_AssetImage.hpp"
36
+ #include "JRemoteImage.hpp"
37
+ #include "JVariant_GlyphImage_AssetImage_RemoteImage.hpp"
37
38
  #include "NitroAction.hpp"
38
39
  #include "NitroActionType.hpp"
39
40
  #include "NitroAlignment.hpp"
@@ -43,6 +44,7 @@
43
44
  #include "NitroGridButton.hpp"
44
45
  #include "NitroMapButton.hpp"
45
46
  #include "NitroMapButtonType.hpp"
47
+ #include "RemoteImage.hpp"
46
48
  #include <NitroModules/JNICallable.hpp>
47
49
  #include <functional>
48
50
  #include <optional>
@@ -21,6 +21,8 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroAction
21
21
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct GlyphImage; }
22
22
  // Forward declaration of `AssetImage` to properly resolve imports.
23
23
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct AssetImage; }
24
+ // Forward declaration of `RemoteImage` to properly resolve imports.
25
+ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct RemoteImage; }
24
26
  // Forward declaration of `NitroColor` to properly resolve imports.
25
27
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroColor; }
26
28
  // Forward declaration of `NitroActionType` to properly resolve imports.
@@ -35,6 +37,8 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { enum class NitroBu
35
37
  #include <NitroModules/JNICallable.hpp>
36
38
  #include <NitroModules/Promise.hpp>
37
39
  #include <NitroModules/JPromise.hpp>
40
+ #include <NitroModules/ArrayBuffer.hpp>
41
+ #include <NitroModules/JArrayBuffer.hpp>
38
42
  #include <NitroModules/JUnit.hpp>
39
43
  #include "EventName.hpp"
40
44
  #include "JEventName.hpp"
@@ -54,12 +58,14 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { enum class NitroBu
54
58
  #include "JNitroAction.hpp"
55
59
  #include "GlyphImage.hpp"
56
60
  #include "AssetImage.hpp"
61
+ #include "RemoteImage.hpp"
57
62
  #include <variant>
58
- #include "JVariant_GlyphImage_AssetImage.hpp"
63
+ #include "JVariant_GlyphImage_AssetImage_RemoteImage.hpp"
59
64
  #include "JGlyphImage.hpp"
60
65
  #include "NitroColor.hpp"
61
66
  #include "JNitroColor.hpp"
62
67
  #include "JAssetImage.hpp"
68
+ #include "JRemoteImage.hpp"
63
69
  #include "NitroActionType.hpp"
64
70
  #include "JNitroActionType.hpp"
65
71
  #include "NitroAlignment.hpp"
@@ -139,6 +145,47 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay {
139
145
  }
140
146
  }();
141
147
  }
148
+ bool JHybridAutoPlaySpec::hasVoiceInputPermission() {
149
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jboolean()>("hasVoiceInputPermission");
150
+ auto __result = method(_javaPart);
151
+ return static_cast<bool>(__result);
152
+ }
153
+ std::shared_ptr<Promise<bool>> JHybridAutoPlaySpec::requestVoiceInputPermission() {
154
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("requestVoiceInputPermission");
155
+ auto __result = method(_javaPart);
156
+ return [&]() {
157
+ auto __promise = Promise<bool>::create();
158
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
159
+ auto __result = jni::static_ref_cast<jni::JBoolean>(__boxedResult);
160
+ __promise->resolve(static_cast<bool>(__result->value()));
161
+ });
162
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
163
+ jni::JniException __jniError(__throwable);
164
+ __promise->reject(std::make_exception_ptr(__jniError));
165
+ });
166
+ return __promise;
167
+ }();
168
+ }
169
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> JHybridAutoPlaySpec::startVoiceInput(std::optional<double> silenceThresholdMs, std::optional<double> maxDurationMs, const std::optional<std::string>& listeningText) {
170
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JDouble> /* silenceThresholdMs */, jni::alias_ref<jni::JDouble> /* maxDurationMs */, jni::alias_ref<jni::JString> /* listeningText */)>("startVoiceInput");
171
+ auto __result = method(_javaPart, silenceThresholdMs.has_value() ? jni::JDouble::valueOf(silenceThresholdMs.value()) : nullptr, maxDurationMs.has_value() ? jni::JDouble::valueOf(maxDurationMs.value()) : nullptr, listeningText.has_value() ? jni::make_jstring(listeningText.value()) : nullptr);
172
+ return [&]() {
173
+ auto __promise = Promise<std::shared_ptr<ArrayBuffer>>::create();
174
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
175
+ auto __result = jni::static_ref_cast<JArrayBuffer::javaobject>(__boxedResult);
176
+ __promise->resolve(__result->cthis()->getArrayBuffer());
177
+ });
178
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
179
+ jni::JniException __jniError(__throwable);
180
+ __promise->reject(std::make_exception_ptr(__jniError));
181
+ });
182
+ return __promise;
183
+ }();
184
+ }
185
+ void JHybridAutoPlaySpec::stopVoiceInput() {
186
+ static const auto method = _javaPart->javaClassStatic()->getMethod<void()>("stopVoiceInput");
187
+ method(_javaPart);
188
+ }
142
189
  std::shared_ptr<Promise<void>> JHybridAutoPlaySpec::setRootTemplate(const std::string& templateId) {
143
190
  static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JString> /* templateId */)>("setRootTemplate");
144
191
  auto __result = method(_javaPart, jni::make_jstring(templateId));
@@ -57,6 +57,10 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay {
57
57
  std::function<void()> addListener(EventName eventType, const std::function<void()>& callback) override;
58
58
  std::function<void()> addListenerRenderState(const std::string& moduleName, const std::function<void(VisibilityState /* payload */)>& callback) override;
59
59
  std::function<void()> addListenerVoiceInput(const std::function<void(const std::optional<Location>& /* coordinates */, const std::optional<std::string>& /* query */)>& callback) override;
60
+ bool hasVoiceInputPermission() override;
61
+ std::shared_ptr<Promise<bool>> requestVoiceInputPermission() override;
62
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> startVoiceInput(std::optional<double> silenceThresholdMs, std::optional<double> maxDurationMs, const std::optional<std::string>& listeningText) override;
63
+ void stopVoiceInput() override;
60
64
  std::shared_ptr<Promise<void>> setRootTemplate(const std::string& templateId) override;
61
65
  std::shared_ptr<Promise<void>> pushTemplate(const std::string& templateId) override;
62
66
  std::shared_ptr<Promise<void>> popTemplate(std::optional<bool> animate) override;
@@ -17,6 +17,8 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroAttrib
17
17
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct GlyphImage; }
18
18
  // Forward declaration of `AssetImage` to properly resolve imports.
19
19
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct AssetImage; }
20
+ // Forward declaration of `RemoteImage` to properly resolve imports.
21
+ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct RemoteImage; }
20
22
  // Forward declaration of `NitroColor` to properly resolve imports.
21
23
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroColor; }
22
24
  // Forward declaration of `ColorScheme` to properly resolve imports.
@@ -42,12 +44,14 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { enum class ZoomEve
42
44
  #include "JNitroAttributedStringImage.hpp"
43
45
  #include "GlyphImage.hpp"
44
46
  #include "AssetImage.hpp"
47
+ #include "RemoteImage.hpp"
45
48
  #include <variant>
46
49
  #include "JNitroImage.hpp"
47
50
  #include "JGlyphImage.hpp"
48
51
  #include "NitroColor.hpp"
49
52
  #include "JNitroColor.hpp"
50
53
  #include "JAssetImage.hpp"
54
+ #include "JRemoteImage.hpp"
51
55
  #include "ColorScheme.hpp"
52
56
  #include "JFunc_void_std__string_ColorScheme.hpp"
53
57
  #include "JColorScheme.hpp"
@@ -15,6 +15,8 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroAction
15
15
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct GlyphImage; }
16
16
  // Forward declaration of `AssetImage` to properly resolve imports.
17
17
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct AssetImage; }
18
+ // Forward declaration of `RemoteImage` to properly resolve imports.
19
+ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct RemoteImage; }
18
20
  // Forward declaration of `NitroColor` to properly resolve imports.
19
21
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroColor; }
20
22
  // Forward declaration of `NitroActionType` to properly resolve imports.
@@ -54,12 +56,14 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { enum class NitroMa
54
56
  #include "JNitroAction.hpp"
55
57
  #include "GlyphImage.hpp"
56
58
  #include "AssetImage.hpp"
59
+ #include "RemoteImage.hpp"
57
60
  #include <variant>
58
- #include "JVariant_GlyphImage_AssetImage.hpp"
61
+ #include "JVariant_GlyphImage_AssetImage_RemoteImage.hpp"
59
62
  #include "JGlyphImage.hpp"
60
63
  #include "NitroColor.hpp"
61
64
  #include "JNitroColor.hpp"
62
65
  #include "JAssetImage.hpp"
66
+ #include "JRemoteImage.hpp"
63
67
  #include "NitroActionType.hpp"
64
68
  #include "JNitroActionType.hpp"
65
69
  #include "NitroAlignment.hpp"
@@ -15,6 +15,8 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroAction
15
15
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct GlyphImage; }
16
16
  // Forward declaration of `AssetImage` to properly resolve imports.
17
17
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct AssetImage; }
18
+ // Forward declaration of `RemoteImage` to properly resolve imports.
19
+ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct RemoteImage; }
18
20
  // Forward declaration of `NitroColor` to properly resolve imports.
19
21
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroColor; }
20
22
  // Forward declaration of `NitroActionType` to properly resolve imports.
@@ -58,12 +60,14 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { enum class NitroMa
58
60
  #include "JNitroAction.hpp"
59
61
  #include "GlyphImage.hpp"
60
62
  #include "AssetImage.hpp"
63
+ #include "RemoteImage.hpp"
61
64
  #include <variant>
62
- #include "JVariant_GlyphImage_AssetImage.hpp"
65
+ #include "JVariant_GlyphImage_AssetImage_RemoteImage.hpp"
63
66
  #include "JGlyphImage.hpp"
64
67
  #include "NitroColor.hpp"
65
68
  #include "JNitroColor.hpp"
66
69
  #include "JAssetImage.hpp"
70
+ #include "JRemoteImage.hpp"
67
71
  #include "NitroActionType.hpp"
68
72
  #include "JNitroActionType.hpp"
69
73
  #include "NitroAlignment.hpp"
@@ -15,6 +15,8 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroAction
15
15
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct GlyphImage; }
16
16
  // Forward declaration of `AssetImage` to properly resolve imports.
17
17
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct AssetImage; }
18
+ // Forward declaration of `RemoteImage` to properly resolve imports.
19
+ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct RemoteImage; }
18
20
  // Forward declaration of `NitroColor` to properly resolve imports.
19
21
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct NitroColor; }
20
22
  // Forward declaration of `NitroActionType` to properly resolve imports.
@@ -58,12 +60,14 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { enum class NitroMa
58
60
  #include "JNitroAction.hpp"
59
61
  #include "GlyphImage.hpp"
60
62
  #include "AssetImage.hpp"
63
+ #include "RemoteImage.hpp"
61
64
  #include <variant>
62
- #include "JVariant_GlyphImage_AssetImage.hpp"
65
+ #include "JVariant_GlyphImage_AssetImage_RemoteImage.hpp"
63
66
  #include "JGlyphImage.hpp"
64
67
  #include "NitroColor.hpp"
65
68
  #include "JNitroColor.hpp"
66
69
  #include "JAssetImage.hpp"
70
+ #include "JRemoteImage.hpp"
67
71
  #include "NitroActionType.hpp"
68
72
  #include "JNitroActionType.hpp"
69
73
  #include "NitroAlignment.hpp"