You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In my app I wanted to implement something similar to dictation button in Safari search:
User taps button
User speaks
When user is not speaking for about 2 seconds, dictation stops automatically
RPReplay_Final1698318345.MP4
This way user doesn't need to tap on a button again to stop dictation. There are built-in methods swiftSpeechRecordOnHold and swiftSpeechToggleRecordingOnTap, but both of them need additional interaction from user. Also there was a need for different button.
Here is how I solved this, maybe this will be helpful for somebody in the future. Will be happy to hear any comments on how this can be done better:
import SwiftUI
import SwiftSpeech
// Creating new extension with custom record button view
public extension SwiftSpeech {
struct RecordButtonCustom: View {
public var body: some View {
RecordButtonView()
}
}
}
// Define new EnvironmentKey for custom state
struct DictationState: EnvironmentKey {
static let defaultValue: SwiftSpeech.State = .pending
}
// Define new Environment Values for custom state
extension EnvironmentValues {
var dictationState: SwiftSpeech.State {
get {
self[DictationState.self]
}
set {
self[DictationState.self] = newValue
}
}
}
struct SwiftSpeechView: View {
@State private var text = "Tap to Speak"
@State private var timer: Timer?
@State var dictationState: SwiftSpeech.State = .pending
var body: some View {
VStack() {
Text(text)
SwiftSpeech
.RecordButtonCustom()
.swiftSpeechToggleRecordingOnTap(locale: Locale(identifier: "en_US"))
.onRecognizeLatest(
includePartialResults: true,
handleResult: { session, result in
text = result.bestTranscription.formattedString
timer?.invalidate()
// initiate timer to stop recording after 2 seconds of silence
timer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { timer in
session.stopRecording()
dictationState = .pending
}
},
handleError: { session, error in
text = "Error \((error as NSError).code)"
session.stopRecording()
dictationState = .pending
})
.onStartRecording { session in
dictationState = .recording
}
.onStopRecording { session in
dictationState = .pending
}
.onCancelRecording{ session in
dictationState = .cancelling
}
}
.onAppear {
SwiftSpeech.requestSpeechRecognitionAuthorization()
}
.environment(\.dictationState, dictationState)
}
}
#Preview {
SwiftSpeechView()
}
import SwiftUI
import SwiftSpeech
struct RecordButtonView: View {
@Environment(\.dictationState) var state: SwiftSpeech.State
public init() { }
var icon: String {
switch state {
case .pending:
return "mic"
case .recording:
return "mic.fill"
case .cancelling:
return "xmark"
}
}
public var body: some View {
Button("Dictate", systemImage: icon, action: {
print("Dictate")
})
.buttonStyle(.borderless)
.labelStyle(.iconOnly)
.help("Dictate")
}
}
#Preview {
RecordButtonView()
}
Hello ✌️ Thank you for such a wonderful library!
In my app I wanted to implement something similar to dictation button in Safari search:
RPReplay_Final1698318345.MP4
This way user doesn't need to tap on a button again to stop dictation. There are built-in methods
swiftSpeechRecordOnHoldandswiftSpeechToggleRecordingOnTap, but both of them need additional interaction from user. Also there was a need for different button.Here is how I solved this, maybe this will be helpful for somebody in the future. Will be happy to hear any comments on how this can be done better:
My stack:
Xcode 15.1 beta
visionOS 1.0