ReadKeep/readeck/Utils/SpeechQueue.swift
Ilyas Hallak 9b89e58115 Refactor TTS system with Combine and VoiceManager
- Replace @MainActor with Combine framework for TTS functionality
- Create VoiceManager class for voice selection and caching
- Add UserDefaults persistence for selected voice
- Optimize performance with voice caching and immediate UI updates
- Remove @MainActor from TTS-related Use Cases
- Add proper pause/resume delegate methods
- Improve reactive UI updates with @StateObject
- Clean up code and remove unnecessary comments
2025-07-09 23:15:23 +02:00

77 lines
2.1 KiB
Swift

import Foundation
import Combine
class SpeechQueue: ObservableObject {
private var queue: [String] = []
private var isProcessing = false
private let ttsManager: TTSManager
private let language: String
static let shared = SpeechQueue()
@Published var queueItems: [String] = []
@Published var currentText: String = ""
@Published var hasItems: Bool = false
var queueCount: Int {
return queueItems.count
}
var currentItem: String? {
return queueItems.first
}
private init(ttsManager: TTSManager = .shared, language: String = "de-DE") {
self.ttsManager = ttsManager
self.language = language
}
func enqueue(_ text: String) {
queue.append(text)
updatePublishedProperties()
processQueue()
}
func enqueue(contentsOf texts: [String]) {
queue.append(contentsOf: texts)
updatePublishedProperties()
processQueue()
}
func clear() {
queue.removeAll()
ttsManager.stop()
isProcessing = false
updatePublishedProperties()
}
private func updatePublishedProperties() {
queueItems = queue
currentText = queue.first ?? ""
hasItems = !queue.isEmpty || ttsManager.isCurrentlySpeaking()
}
private func processQueue() {
guard !isProcessing, !queue.isEmpty else { return }
isProcessing = true
let next = queue.removeFirst()
ttsManager.speak(text: next, language: language)
// Delegate/Notification für didFinish kann hier angebunden werden
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
self?.waitForSpeechToFinish()
}
}
private func waitForSpeechToFinish() {
if ttsManager.isCurrentlySpeaking() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.waitForSpeechToFinish()
}
} else {
self.isProcessing = false
self.updatePublishedProperties()
self.processQueue()
}
}
}