Files
ReadViewSDK/Sources/RDPDFReaderView/Speech/RDPDFSpeechSession.swift
T
2026-07-27 21:43:13 +08:00

60 lines
2.2 KiB
Swift

import Foundation
import RDSpeechReaderView
/// A ready-to-use PDF speech session. It owns the controller delegate so page
/// navigation and temporary sentence highlighting stay synchronized.
@MainActor
public final class RDPDFSpeechSession: NSObject, RDSpeechReaderControllerDelegate {
public let controller: RDSpeechReaderController
public let contentProvider: RDPDFSpeechContentProvider
public var onStateChange: ((RDSpeechReaderState) -> Void)?
private weak var reader: RDPDFReaderViewController?
init(reader: RDPDFReaderViewController, configuration: RDSpeechReaderConfiguration) {
self.reader = reader
contentProvider = reader.makeSpeechContentProvider()
controller = RDSpeechReaderController(contentProvider: contentProvider, configuration: configuration)
super.init()
controller.delegate = self
}
public func start(from pageIndex: Int = 0) async throws {
let location = RDSpeechLocation(
bookIdentifier: contentProvider.speechBookDescriptor().identifier,
resourceIdentifier: String(max(0, pageIndex))
)
try await controller.start(from: location)
}
public func pause() { controller.pause() }
public func resume() { controller.resume() }
public func stop() {
controller.stop()
reader?.clearSpeechHighlight()
}
public func speechReaderController(_ controller: RDSpeechReaderController, didChange state: RDSpeechReaderState) {
if case .finished = state { reader?.clearSpeechHighlight() }
if case .idle = state { reader?.clearSpeechHighlight() }
onStateChange?(state)
}
public func speechReaderController(_ controller: RDSpeechReaderController, willSpeak range: RDSpeechSpokenRange) {
guard let pageIndex = Int(range.unit.location.resourceIdentifier) else { return }
reader?.showSpeechHighlight(
pageIndex: pageIndex,
normalizedRects: contentProvider.normalizedRects(for: range)
)
}
}
public extension RDPDFReaderViewController {
func makeSpeechSession(
configuration: RDSpeechReaderConfiguration = .default
) -> RDPDFSpeechSession {
RDPDFSpeechSession(reader: self, configuration: configuration)
}
}