@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.
- package/README.md +75 -16
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AutoPlayError.kt +6 -1
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoice.kt +9 -3
- package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VoiceInputManager.kt +103 -45
- package/ios/Types.swift +2 -1
- package/ios/extensions/CarPlayTemplateExtensions.swift +7 -0
- package/ios/hybrid/HybridAutoPlay.swift +0 -1
- package/ios/hybrid/HybridVoice.swift +10 -2
- package/ios/templates/Parser.swift +95 -0
- package/ios/templates/VoiceInputTemplate.swift +33 -0
- package/ios/utils/VoiceInputManager.swift +224 -29
- package/lib/hybrid/HybridVoice.js +7 -2
- package/lib/specs/Voice.nitro.d.ts +2 -1
- package/lib/templates/Template.d.ts +1 -1
- package/lib/types/Image.d.ts +16 -0
- package/lib/types/Voice.d.ts +9 -0
- package/lib/utils/ErrorUtil.d.ts +1 -0
- package/lib/utils/ErrorUtil.js +15 -3
- package/nitrogen/generated/android/c++/JHybridVoiceSpec.cpp +21 -3
- package/nitrogen/generated/android/c++/JHybridVoiceSpec.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoiceSpec.kt +3 -3
- package/nitrogen/generated/ios/c++/HybridVoiceSpecSwift.hpp +15 -2
- package/nitrogen/generated/ios/swift/HybridVoiceSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridVoiceSpec_cxx.swift +44 -1
- package/nitrogen/generated/shared/c++/HybridVoiceSpec.hpp +11 -1
- package/package.json +1 -1
- package/src/hybrid/HybridVoice.ts +16 -1
- package/src/specs/Voice.nitro.ts +6 -1
- package/src/templates/Template.ts +1 -1
- package/src/types/Image.ts +19 -0
- package/src/types/Voice.ts +10 -0
- 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,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
|
|
package/src/specs/Voice.nitro.ts
CHANGED
|
@@ -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
|
-
* @
|
|
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>];
|
package/src/types/Image.ts
CHANGED
|
@@ -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
|
+
};
|
package/src/types/Voice.ts
CHANGED
|
@@ -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
|
}
|
package/src/utils/ErrorUtil.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
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
|
|
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 };
|