@iternio/react-native-auto-play 0.5.3 → 0.5.5

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 (32) hide show
  1. package/README.md +75 -16
  2. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AutoPlayError.kt +6 -1
  3. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoice.kt +9 -3
  4. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VoiceInputManager.kt +103 -45
  5. package/ios/Types.swift +2 -1
  6. package/ios/extensions/CarPlayTemplateExtensions.swift +7 -0
  7. package/ios/hybrid/HybridAutoPlay.swift +0 -1
  8. package/ios/hybrid/HybridVoice.swift +10 -2
  9. package/ios/templates/Parser.swift +95 -0
  10. package/ios/templates/VoiceInputTemplate.swift +33 -0
  11. package/ios/utils/VoiceInputManager.swift +224 -29
  12. package/lib/hybrid/HybridVoice.js +7 -2
  13. package/lib/specs/Voice.nitro.d.ts +2 -1
  14. package/lib/templates/Template.d.ts +1 -1
  15. package/lib/types/Image.d.ts +16 -0
  16. package/lib/types/Voice.d.ts +9 -0
  17. package/lib/utils/ErrorUtil.d.ts +1 -0
  18. package/lib/utils/ErrorUtil.js +15 -3
  19. package/nitrogen/generated/android/c++/JHybridVoiceSpec.cpp +21 -3
  20. package/nitrogen/generated/android/c++/JHybridVoiceSpec.hpp +1 -1
  21. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoiceSpec.kt +3 -3
  22. package/nitrogen/generated/ios/c++/HybridVoiceSpecSwift.hpp +15 -2
  23. package/nitrogen/generated/ios/swift/HybridVoiceSpec.swift +1 -1
  24. package/nitrogen/generated/ios/swift/HybridVoiceSpec_cxx.swift +44 -1
  25. package/nitrogen/generated/shared/c++/HybridVoiceSpec.hpp +11 -1
  26. package/package.json +1 -1
  27. package/src/hybrid/HybridVoice.ts +16 -1
  28. package/src/specs/Voice.nitro.ts +6 -1
  29. package/src/templates/Template.ts +1 -1
  30. package/src/types/Image.ts +19 -0
  31. package/src/types/Voice.ts +10 -0
  32. package/src/utils/ErrorUtil.ts +19 -3
@@ -156,7 +156,7 @@ open class HybridVoiceSpec_cxx {
156
156
  }
157
157
 
158
158
  @inline(__always)
159
- public final func startVoiceInput(silenceThresholdMs: bridge.std__optional_double_, maxDurationMs: bridge.std__optional_double_, listeningText: bridge.std__optional_std__string_, preferSpeechToText: bridge.std__optional_bool_, onChunk: bridge.std__optional_std__function_void_const_VoiceInputChunk_____chunk______, language: bridge.std__optional_std__string_) -> bridge.Result_std__shared_ptr_Promise_VoiceInputResult___ {
159
+ public final func startVoiceInput(silenceThresholdMs: bridge.std__optional_double_, maxDurationMs: bridge.std__optional_double_, listeningText: bridge.std__optional_std__string_, listeningImage: bridge.std__optional_std__variant_GlyphImage__AssetImage__RemoteImage__, listeningImageRepeats: bridge.std__optional_bool_, preferSpeechToText: bridge.std__optional_bool_, onChunk: bridge.std__optional_std__function_void_const_VoiceInputChunk_____chunk______, language: bridge.std__optional_std__string_, startSoundUri: bridge.std__optional_std__string_, endSoundUri: bridge.std__optional_std__string_) -> bridge.Result_std__shared_ptr_Promise_VoiceInputResult___ {
160
160
  do {
161
161
  let __result = try self.__implementation.startVoiceInput(silenceThresholdMs: { () -> Double? in
162
162
  if bridge.has_value_std__optional_double_(silenceThresholdMs) {
@@ -179,6 +179,35 @@ open class HybridVoiceSpec_cxx {
179
179
  } else {
180
180
  return nil
181
181
  }
182
+ }(), listeningImage: { () -> Variant_GlyphImage_AssetImage_RemoteImage? in
183
+ if bridge.has_value_std__optional_std__variant_GlyphImage__AssetImage__RemoteImage__(listeningImage) {
184
+ let __unwrapped = bridge.get_std__optional_std__variant_GlyphImage__AssetImage__RemoteImage__(listeningImage)
185
+ return { () -> Variant_GlyphImage_AssetImage_RemoteImage in
186
+ let __variant = bridge.std__variant_GlyphImage__AssetImage__RemoteImage_(__unwrapped)
187
+ switch __variant.index() {
188
+ case 0:
189
+ let __actual = __variant.get_0()
190
+ return .first(__actual)
191
+ case 1:
192
+ let __actual = __variant.get_1()
193
+ return .second(__actual)
194
+ case 2:
195
+ let __actual = __variant.get_2()
196
+ return .third(__actual)
197
+ default:
198
+ fatalError("Variant can never have index \(__variant.index())!")
199
+ }
200
+ }()
201
+ } else {
202
+ return nil
203
+ }
204
+ }(), listeningImageRepeats: { () -> Bool? in
205
+ if bridge.has_value_std__optional_bool_(listeningImageRepeats) {
206
+ let __unwrapped = bridge.get_std__optional_bool_(listeningImageRepeats)
207
+ return __unwrapped
208
+ } else {
209
+ return nil
210
+ }
182
211
  }(), preferSpeechToText: { () -> Bool? in
183
212
  if bridge.has_value_std__optional_bool_(preferSpeechToText) {
184
213
  let __unwrapped = bridge.get_std__optional_bool_(preferSpeechToText)
@@ -205,6 +234,20 @@ open class HybridVoiceSpec_cxx {
205
234
  } else {
206
235
  return nil
207
236
  }
237
+ }(), startSoundUri: { () -> String? in
238
+ if bridge.has_value_std__optional_std__string_(startSoundUri) {
239
+ let __unwrapped = bridge.get_std__optional_std__string_(startSoundUri)
240
+ return String(__unwrapped)
241
+ } else {
242
+ return nil
243
+ }
244
+ }(), endSoundUri: { () -> String? in
245
+ if bridge.has_value_std__optional_std__string_(endSoundUri) {
246
+ let __unwrapped = bridge.get_std__optional_std__string_(endSoundUri)
247
+ return String(__unwrapped)
248
+ } else {
249
+ return nil
250
+ }
208
251
  }())
209
252
  let __resultCpp = { () -> bridge.std__shared_ptr_Promise_VoiceInputResult__ in
210
253
  let __promise = bridge.create_std__shared_ptr_Promise_VoiceInputResult__()
@@ -15,6 +15,12 @@
15
15
 
16
16
  // Forward declaration of `VoiceInputResult` to properly resolve imports.
17
17
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct VoiceInputResult; }
18
+ // Forward declaration of `GlyphImage` to properly resolve imports.
19
+ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct GlyphImage; }
20
+ // Forward declaration of `AssetImage` to properly resolve imports.
21
+ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct AssetImage; }
22
+ // Forward declaration of `RemoteImage` to properly resolve imports.
23
+ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct RemoteImage; }
18
24
  // Forward declaration of `VoiceInputChunk` to properly resolve imports.
19
25
  namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct VoiceInputChunk; }
20
26
 
@@ -22,6 +28,10 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay { struct VoiceInputC
22
28
  #include "VoiceInputResult.hpp"
23
29
  #include <optional>
24
30
  #include <string>
31
+ #include "GlyphImage.hpp"
32
+ #include "AssetImage.hpp"
33
+ #include "RemoteImage.hpp"
34
+ #include <variant>
25
35
  #include "VoiceInputChunk.hpp"
26
36
  #include <functional>
27
37
 
@@ -58,7 +68,7 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay {
58
68
  // Methods
59
69
  virtual bool hasVoiceInputPermission() = 0;
60
70
  virtual std::shared_ptr<Promise<bool>> requestVoiceInputPermission() = 0;
61
- virtual std::shared_ptr<Promise<VoiceInputResult>> startVoiceInput(std::optional<double> silenceThresholdMs, std::optional<double> maxDurationMs, const std::optional<std::string>& listeningText, std::optional<bool> preferSpeechToText, const std::optional<std::function<void(const VoiceInputChunk& /* chunk */)>>& onChunk, const std::optional<std::string>& language) = 0;
71
+ virtual std::shared_ptr<Promise<VoiceInputResult>> startVoiceInput(std::optional<double> silenceThresholdMs, std::optional<double> maxDurationMs, const std::optional<std::string>& listeningText, const std::optional<std::variant<GlyphImage, AssetImage, RemoteImage>>& listeningImage, std::optional<bool> listeningImageRepeats, std::optional<bool> preferSpeechToText, const std::optional<std::function<void(const VoiceInputChunk& /* chunk */)>>& onChunk, const std::optional<std::string>& language, const std::optional<std::string>& startSoundUri, const std::optional<std::string>& endSoundUri) = 0;
62
72
  virtual void stopVoiceInput() = 0;
63
73
 
64
74
  protected:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iternio/react-native-auto-play",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "Android Auto and Apple CarPlay for react-native",
5
5
  "main": "lib/index",
6
6
  "module": "lib/index",
@@ -1,6 +1,8 @@
1
+ import { Image } from 'react-native';
1
2
  import { NitroModules } from 'react-native-nitro-modules';
2
3
  import type { Voice } from '../specs/Voice.nitro';
3
4
  import type { VoiceInputOptions, VoiceInputResult } from '../types/Voice';
5
+ import { NitroImageUtil } from '../utils/NitroImage';
4
6
 
5
7
  const _native = NitroModules.createHybridObject<Voice>('Voice');
6
8
 
@@ -17,17 +19,30 @@ const startVoiceInput: StartVoiceInput = async (options?: VoiceInputOptions) =>
17
19
  silenceThresholdMs,
18
20
  maxDurationMs,
19
21
  listeningText,
22
+ listeningImage,
20
23
  preferSpeechToText,
21
24
  language,
25
+ startSound,
26
+ endSound,
22
27
  } = options ?? {};
23
28
 
29
+ const listeningImageRepeats =
30
+ listeningImage?.type === 'asset' ? listeningImage.repeats : undefined;
31
+
32
+ const startSoundUri = startSound != null ? Image.resolveAssetSource(startSound).uri : undefined;
33
+ const endSoundUri = endSound != null ? Image.resolveAssetSource(endSound).uri : undefined;
34
+
24
35
  return await _native.startVoiceInput(
25
36
  silenceThresholdMs,
26
37
  maxDurationMs,
27
38
  listeningText,
39
+ NitroImageUtil.convert(listeningImage),
40
+ listeningImageRepeats,
28
41
  preferSpeechToText,
29
42
  onChunk,
30
- language
43
+ language,
44
+ startSoundUri,
45
+ endSoundUri
31
46
  );
32
47
  };
33
48
 
@@ -1,5 +1,6 @@
1
1
  import type { HybridObject } from 'react-native-nitro-modules';
2
2
  import type { VoiceInputChunk, VoiceInputResult } from '../types/Voice';
3
+ import type { NitroImage } from '../utils/NitroImage';
3
4
 
4
5
  export interface Voice extends HybridObject<{ android: 'kotlin'; ios: 'swift' }> {
5
6
  hasVoiceInputPermission(): boolean;
@@ -8,9 +9,13 @@ export interface Voice extends HybridObject<{ android: 'kotlin'; ios: 'swift' }>
8
9
  silenceThresholdMs?: number,
9
10
  maxDurationMs?: number,
10
11
  listeningText?: string,
12
+ listeningImage?: NitroImage,
13
+ listeningImageRepeats?: boolean,
11
14
  preferSpeechToText?: boolean,
12
15
  onChunk?: (chunk: VoiceInputChunk) => void,
13
- language?: string
16
+ language?: string,
17
+ startSoundUri?: string,
18
+ endSoundUri?: string
14
19
  ): Promise<VoiceInputResult>;
15
20
  stopVoiceInput(): void;
16
21
  }
@@ -8,7 +8,7 @@ export type ActionButton<T> = ActionButtonAndroid<T> | ActionButtonIos<T>;
8
8
 
9
9
  export type HeaderActionsIos<T> = {
10
10
  /**
11
- * @platform iOS - the back button can not be hidden or disabled, if you don't define it iOS will provide a default back button popping the template
11
+ * @namespace iOS - the back button can not be hidden or disabled, if you don't define it iOS will provide a default back button popping the template
12
12
  */
13
13
  backButton?: BackButton<T>;
14
14
  leadingNavigationBarButtons?: [ActionButtonIos<T>, ActionButtonIos<T>] | [ActionButtonIos<T>];
@@ -79,3 +79,22 @@ export type AutoImage =
79
79
  timeoutMs?: number;
80
80
  type: 'remote';
81
81
  };
82
+
83
+ /**
84
+ * Image for the CarPlay voice control overlay. Animated GIF, APNG, and WebP all animate.
85
+ * `color` is ignored for animated assets — frames cannot be tinted individually. Static
86
+ * assets and glyphs are resized/capped to fit within 150×150pt (`fontScale` controls a
87
+ * glyph's relative size). CarPlay enforces a 0.3s–5s animation cycle duration: shorter
88
+ * source animations are stretched to 0.3s by the system, longer ones are capped to 5s.
89
+ * @namespace ios
90
+ */
91
+ export type VoiceInputImage =
92
+ | AutoGlyph
93
+ | {
94
+ type: 'asset';
95
+ image: ImageSourcePropType;
96
+ /** Tints the image. Ignored for animated assets — frames cannot be tinted individually. */
97
+ color?: ThemedColor | string;
98
+ /** Whether the animation loops. Defaults to `true` for animated images, `false` for static. */
99
+ repeats?: boolean;
100
+ };
@@ -1,3 +1,5 @@
1
+ import type { VoiceInputImage } from './Image';
2
+
1
3
  export interface VoiceInputChunk {
2
4
  partial?: string;
3
5
  audio?: ArrayBuffer;
@@ -12,7 +14,15 @@ export interface VoiceInputOptions {
12
14
  silenceThresholdMs?: number;
13
15
  maxDurationMs?: number;
14
16
  listeningText?: string;
17
+ /** Image displayed in the CarPlay voice control overlay. See {@link VoiceInputImage}.
18
+ * @namespace ios
19
+ */
20
+ listeningImage?: VoiceInputImage;
15
21
  preferSpeechToText?: boolean;
16
22
  onChunk?: (chunk: VoiceInputChunk) => void;
17
23
  language?: string;
24
+ /** Sound played just before recording starts. Pass a Metro asset: `require('./beep_start.wav')`. */
25
+ startSound?: number;
26
+ /** Sound played just after recording stops. Pass a Metro asset: `require('./beep_end.wav')`. */
27
+ endSound?: number;
18
28
  }
@@ -1,4 +1,4 @@
1
- const isTemplateNotFoundError = (error: unknown): error is Error => {
1
+ const isError = (error: unknown): error is { message: string } => {
2
2
  if (error == null) {
3
3
  return false;
4
4
  }
@@ -19,7 +19,23 @@ const isTemplateNotFoundError = (error: unknown): error is Error => {
19
19
  return false;
20
20
  }
21
21
 
22
- return error.message.startsWith('templateNotFound');
22
+ return true;
23
+ };
24
+
25
+ const isTemplateNotFoundError = (error: unknown): error is Error => {
26
+ if (isError(error)) {
27
+ return error.message.startsWith('templateNotFound');
28
+ }
29
+
30
+ return false;
31
+ };
32
+
33
+ const isVoiceInputCanceledError = (error: unknown): error is Error => {
34
+ if (isError(error)) {
35
+ return error.message.startsWith('voiceInputCancelled');
36
+ }
37
+
38
+ return false;
23
39
  };
24
40
 
25
- export const ErrorUtil = { isTemplateNotFoundError };
41
+ export const ErrorUtil = { isTemplateNotFoundError, isVoiceInputCanceledError };