I am working on a Christian app, all is going well, except for 1 thing: I can't solve how to get the label to update its text after my AVSpeechSynthesizer has finished speaking.
For example, after the prayer has finished being read, the text should update to "Play" again. It does this correctly in all other known scenarios (Pause works, Resume works, stop works, restart works, etc. as in the label updates accordingly).
Please see my code here:
import SwiftUI
import AVFoundation
class GlobalVarsModel: ObservableObject {
@Published var prayerAudioID: UUID?
@Published var uttPrayerAudio = ""
@Published var strAudioBtnImgStr = "play.fill"
@Published var strAudioBtnText = "Play Audio"
static let audioSession = AVAudioSession.sharedInstance()
static var synthesizer = CustomAVSpeechSynth()
}
class CustomAVSpeechSynth: AVSpeechSynthesizer, AVSpeechSynthesizerDelegate {
//NOT DESIRED OUTPUT LIST
//@Published
//@ObservedObject
//@State
@StateObject var gVars = GlobalVarsModel()
override init() {
super.init()
delegate = self
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didPause utterance: AVSpeechUtterance) {
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
print("Finished praying.")
print(gVars.strAudioBtnText)
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didContinue utterance: AVSpeechUtterance) {
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
}
}
struct TappedPrayerView: View {
public var tappedPrayer: Prayer
@StateObject public var gVars = GlobalVarsModel()
@Environment(\.scenePhase) var scenePhase
var body: some View {
ScrollView {
VStack {
Text(tappedPrayer.strTitle).font(.title2).padding()
HStack {
Spacer()
Button {
gVars.prayerAudioID = tappedPrayer.id
gVars.uttPrayerAudio = tappedPrayer.strText
if (gVars.strAudioBtnText == "Play Audio") {
gVars.strAudioBtnImgStr = "pause.fill"
gVars.strAudioBtnText = "Pause Audio"
if (GlobalVarsModel.synthesizer.isSpeaking || GlobalVarsModel.synthesizer.isPaused) {
GlobalVarsModel.synthesizer.stopSpeaking(at: .immediate)
GlobalVarsModel.synthesizer.speak(AVSpeechUtterance(string: gVars.uttPrayerAudio))
} else {
GlobalVarsModel.synthesizer.speak(AVSpeechUtterance(string: gVars.uttPrayerAudio))
}
} else if (gVars.strAudioBtnText == "Pause Audio") {
GlobalVarsModel.synthesizer.pauseSpeaking(at: .immediate)
gVars.strAudioBtnImgStr = "play.fill"
gVars.strAudioBtnText = "Continue Audio"
} else if (gVars.strAudioBtnText == "Continue Audio") {
if (GlobalVarsModel.synthesizer.isPaused) {
GlobalVarsModel.synthesizer.continueSpeaking()
gVars.strAudioBtnImgStr = "pause.fill"
gVars.strAudioBtnText = "Pause Audio"
}
}
} label: {
Label(gVars.strAudioBtnText, systemImage: gVars.strAudioBtnImgStr).font(.title3).padding()
}.onAppear {
if ((GlobalVarsModel.synthesizer.isSpeaking || GlobalVarsModel.synthesizer.isPaused) && tappedPrayer.id != gVars.prayerAudioID) {
gVars.strAudioBtnImgStr = "play.fill"
gVars.strAudioBtnText = "Play Audio"
}
}
Spacer()
Button {
if (GlobalVarsModel.synthesizer.isSpeaking || GlobalVarsModel.synthesizer.isPaused) {
GlobalVarsModel.synthesizer.stopSpeaking(at: .immediate)
gVars.strAudioBtnImgStr = "play.fill"
gVars.strAudioBtnText = "Play Audio"
gVars.prayerAudioID = UUID(uuidString: String(Int.random(in: 0..<7)) + (gVars.prayerAudioID?.uuidString ?? "777"))
}
} label: {
Label("Restart", systemImage: "restart.circle.fill").font(.title3).padding()
}
Spacer()
}
Spacer()
Text(tappedPrayer.strText).padding()
Spacer()
}
}.onAppear {
if (GlobalVarsModel.synthesizer.isPaused) {
if (tappedPrayer.id == gVars.prayerAudioID) {
gVars.strAudioBtnImgStr = "play.fill"
gVars.strAudioBtnText = "Continue Audio"
}
} else if (GlobalVarsModel.synthesizer.isSpeaking) {
if (tappedPrayer.id == gVars.prayerAudioID) {
gVars.strAudioBtnImgStr = "pause.fill"
gVars.strAudioBtnText = "Pause Audio"
}
} else {
gVars.strAudioBtnImgStr = "play.fill"
gVars.strAudioBtnText = "Play Audio"
}
}.onChange(of: scenePhase) { newPhase in
if (newPhase == .active) {
} else if (newPhase == .inactive) {
} else if (newPhase == .background) {
}
}
}
struct TappedPrayerView_Previews: PreviewProvider {
static var previews: some View {
let defaultPrayer = Prayer(strTitle: "Default title", strText: "Default text")
TappedPrayerView(tappedPrayer: defaultPrayer)
}
}
}