- Implemented a toggle for the 'Read Aloud' (TTS) feature in the general settings. - Refactored AppSettings and PlayerUIState to support TTS enable/disable. - Updated BookmarkDetailView, PadSidebarView, PhoneTabView, and GlobalPlayerContainerView to respect the TTS setting. - Added new RButton component for consistent button styling. - Improved LabelsView to support tag selection on iPad and iPhone. - Updated SettingsGeneralView and SettingsGeneralViewModel for new TTS logic and removed unused app info code. - Added app info section to SettingsContainerView. - Updated SettingsServerView to use English labels and messages. - Refactored SpeechPlayerViewModel to only initialize TTS when enabled. - Updated Core Data model to include enableTTS in SettingEntity. - Removed obsolete files (PersistenceController.swift, old PlayerUIState). - Various bugfixes, code cleanups, and UI improvements.
105 lines
3.0 KiB
Swift
105 lines
3.0 KiB
Swift
import Foundation
|
|
import Combine
|
|
|
|
class SpeechPlayerViewModel: ObservableObject {
|
|
private var ttsManager: TTSManager? = nil
|
|
private var speechQueue: SpeechQueue? = nil
|
|
private let loadSettingsUseCase: PLoadSettingsUseCase
|
|
private var cancellables = Set<AnyCancellable>()
|
|
|
|
@Published var isSpeaking: Bool = false
|
|
@Published var currentText: String = ""
|
|
@Published var queueCount: Int = 0
|
|
@Published var queueItems: [SpeechQueueItem] = []
|
|
@Published var hasItems: Bool = false
|
|
@Published var progress: Double = 0.0
|
|
@Published var currentUtteranceIndex: Int = 0
|
|
@Published var totalUtterances: Int = 0
|
|
@Published var articleProgress: Double = 0.0
|
|
@Published var volume: Float = 1.0
|
|
@Published var rate: Float = 0.5
|
|
|
|
init(_ factory: UseCaseFactory = DefaultUseCaseFactory.shared) {
|
|
loadSettingsUseCase = factory.makeLoadSettingsUseCase()
|
|
}
|
|
|
|
func setup() async {
|
|
let settings = try? await loadSettingsUseCase.execute()
|
|
if settings?.enableTTS == true {
|
|
self.ttsManager = .shared
|
|
self.speechQueue = .shared
|
|
setupBindings()
|
|
}
|
|
}
|
|
|
|
private func setupBindings() {
|
|
// TTSManager bindings
|
|
ttsManager?.$isSpeaking
|
|
.assign(to: \.isSpeaking, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
ttsManager?.$currentUtterance
|
|
.assign(to: \.currentText, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
// SpeechQueue bindings
|
|
speechQueue?.$queueItems
|
|
.assign(to: \.queueItems, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
speechQueue?.$queueItems
|
|
.map { $0.count }
|
|
.assign(to: \.queueCount, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
speechQueue?.$hasItems
|
|
.assign(to: \.hasItems, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
// TTS Progress bindings
|
|
ttsManager?.$progress
|
|
.assign(to: \.progress, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
ttsManager?.$currentUtteranceIndex
|
|
.assign(to: \.currentUtteranceIndex, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
ttsManager?.$totalUtterances
|
|
.assign(to: \.totalUtterances, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
ttsManager?.$articleProgress
|
|
.assign(to: \.articleProgress, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
ttsManager?.$volume
|
|
.assign(to: \.volume, on: self)
|
|
.store(in: &cancellables)
|
|
|
|
ttsManager?.$rate
|
|
.assign(to: \.rate, on: self)
|
|
.store(in: &cancellables)
|
|
}
|
|
|
|
func setVolume(_ newVolume: Float) {
|
|
ttsManager?.setVolume(newVolume)
|
|
}
|
|
|
|
func setRate(_ newRate: Float) {
|
|
ttsManager?.setRate(newRate)
|
|
}
|
|
|
|
func pause() {
|
|
ttsManager?.pause()
|
|
}
|
|
|
|
func resume() {
|
|
ttsManager?.resume()
|
|
}
|
|
|
|
func stop() {
|
|
ttsManager?.stop()
|
|
}
|
|
}
|