Skip to content

Commit 177dcff

Browse files
committed
feat(SwiftDependencies): add a swift-dependencies library wrapper
* TTS is now usable out of the box with Point-Free `Dependencies` library.
1 parent e74d559 commit 177dcff

File tree

4 files changed

+136
-1
lines changed

4 files changed

+136
-1
lines changed

Package.resolved

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,19 @@ let package = Package(
1111
],
1212
products: [
1313
.library(name: "SwiftTTS", targets: ["SwiftTTS"]),
14+
.library(name: "SwiftTTSDependency", targets: ["SwiftTTSDependency"]),
1415
.library(name: "SwiftTTSCombine", targets: ["SwiftTTSCombine"]),
1516
],
16-
dependencies: [],
17+
dependencies: [
18+
.package(url: "https://github.com/pointfreeco/swift-dependencies", from: "0.2.0"),
19+
],
1720
targets: [
1821
.target(name: "SwiftTTS", dependencies: []),
1922
.testTarget(name: "SwiftTTSTests", dependencies: ["SwiftTTS"]),
23+
.target(name: "SwiftTTSDependency", dependencies: [
24+
.product(name: "Dependencies", package: "swift-dependencies"),
25+
"SwiftTTS",
26+
]),
2027
.target(name: "SwiftTTSCombine", dependencies: []),
2128
]
2229
)

Sources/SwiftTTS/SwiftTTS.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,24 @@ public struct SwiftTTS {
88
public var speak: (String) -> Void
99
public var isSpeaking: () -> AsyncStream<Bool>
1010
public var speakingProgress: () -> AsyncStream<Double>
11+
12+
public init(
13+
rateRatio: @escaping () -> Float,
14+
setRateRatio: @escaping (Float) -> Void,
15+
voice: @escaping () -> AVSpeechSynthesisVoice?,
16+
setVoice: @escaping (AVSpeechSynthesisVoice) -> Void,
17+
speak: @escaping (String) -> Void,
18+
isSpeaking: @escaping () -> AsyncStream<Bool>,
19+
speakingProgress: @escaping () -> AsyncStream<Double>
20+
) {
21+
self.rateRatio = rateRatio
22+
self.setRateRatio = setRateRatio
23+
self.voice = voice
24+
self.setVoice = setVoice
25+
self.speak = speak
26+
self.isSpeaking = isSpeaking
27+
self.speakingProgress = speakingProgress
28+
}
1129
}
1230

1331
private final class Engine: NSObject, AVSpeechSynthesizerDelegate {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import AVFoundation
2+
import Dependencies
3+
import SwiftTTS
4+
import XCTestDynamicOverlay
5+
6+
extension SwiftTTS {
7+
static let test = Self(
8+
rateRatio: unimplemented("SwiftTTS.rateRatio"),
9+
setRateRatio: unimplemented("SwiftTTS.setRateRatio"),
10+
voice: unimplemented("SwiftTTS.voice"),
11+
setVoice: unimplemented("SwiftTTS.setVoice"),
12+
speak: unimplemented("SwiftTTS.speak"),
13+
isSpeaking: unimplemented("SwiftTTS.isSpeaking"),
14+
speakingProgress: unimplemented("SwiftTTS.speakingProgress")
15+
)
16+
static let preview = {
17+
var speakingCallbacks: [() -> Void] = []
18+
let speak: (String) -> Void = {
19+
print("Spoken utterance: \($0)")
20+
for callback in speakingCallbacks {
21+
callback()
22+
}
23+
}
24+
25+
let isSpeaking = AsyncStream { continuation in
26+
speakingCallbacks.append {
27+
continuation.yield(true)
28+
Task {
29+
try await Task.sleep(nanoseconds: 2_000_000_000)
30+
continuation.yield(false)
31+
}
32+
}
33+
}
34+
35+
let speakingProgress = AsyncStream { continuation in
36+
speakingCallbacks.append {
37+
Task {
38+
for seconds in 0...4 {
39+
continuation.yield(Double(seconds) / 4)
40+
try await Task.sleep(nanoseconds: 500_000_000)
41+
}
42+
}
43+
}
44+
}
45+
46+
return Self(
47+
rateRatio: { 1.0 },
48+
setRateRatio: { _ in },
49+
voice: { AVSpeechSynthesisVoice(language: "en-GB") },
50+
setVoice: { _ in },
51+
speak: speak,
52+
isSpeaking: { isSpeaking },
53+
speakingProgress: { speakingProgress }
54+
)
55+
}()
56+
}
57+
58+
private enum SwiftTTSDependencyKey: DependencyKey {
59+
static let liveValue = SwiftTTS.live
60+
static let testValue = SwiftTTS.test
61+
static let previewValue = SwiftTTS.preview
62+
}
63+
64+
public extension DependencyValues {
65+
var tts: SwiftTTS {
66+
get { self[SwiftTTSDependencyKey.self] }
67+
set { self[SwiftTTSDependencyKey.self] = newValue }
68+
}
69+
}

0 commit comments

Comments
 (0)