From fbdc3c4f99038de6694f414cfa04cf43935eff4f Mon Sep 17 00:00:00 2001 From: Jeremy Rand Date: Tue, 19 Oct 2021 00:48:37 -0400 Subject: [PATCH] Remove the application logic code from the view code. --- ListenerGS.xcodeproj/project.pbxproj | 4 + .../xcschemes/xcschememanagement.plist | 5 + ListenerGS/ContentView.swift | 222 +----------------- ListenerGS/Info.plist | 2 +- 4 files changed, 19 insertions(+), 214 deletions(-) diff --git a/ListenerGS.xcodeproj/project.pbxproj b/ListenerGS.xcodeproj/project.pbxproj index a6996ad..340bef2 100644 --- a/ListenerGS.xcodeproj/project.pbxproj +++ b/ListenerGS.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 9D51566526A36F6D0075EBC7 /* BinUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D51566426A36F6C0075EBC7 /* BinUtils.swift */; }; 9D51567326A36FEC0075EBC7 /* BinUtils.LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 9D51567226A36FEC0075EBC7 /* BinUtils.LICENSE */; }; 9D51567E26A370380075EBC7 /* SwiftSocket.LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 9D51567D26A370380075EBC7 /* SwiftSocket.LICENSE */; }; + 9D6ED23A271E6BD600D773CD /* SpeechForwarder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D6ED239271E6BD600D773CD /* SpeechForwarder.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -71,6 +72,7 @@ 9D51566426A36F6C0075EBC7 /* BinUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinUtils.swift; sourceTree = ""; }; 9D51567226A36FEC0075EBC7 /* BinUtils.LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BinUtils.LICENSE; sourceTree = ""; }; 9D51567D26A370380075EBC7 /* SwiftSocket.LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SwiftSocket.LICENSE; sourceTree = ""; }; + 9D6ED239271E6BD600D773CD /* SpeechForwarder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpeechForwarder.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -128,6 +130,7 @@ 9D0DC15826F2E47A007EB92D /* ListenerGS.entitlements */, 9D5155F226A1EF7B0075EBC7 /* ListenerGSApp.swift */, 9D5155F426A1EF7B0075EBC7 /* ContentView.swift */, + 9D6ED239271E6BD600D773CD /* SpeechForwarder.swift */, 9D51566326A36F530075EBC7 /* BinUtils */, 9D51563626A36AD60075EBC7 /* SwiftSocket */, 9D5155F626A1EF7C0075EBC7 /* Assets.xcassets */, @@ -356,6 +359,7 @@ 9D51565326A36B410075EBC7 /* yudpsocket.c in Sources */, 9D51565226A36B410075EBC7 /* Result.swift in Sources */, 9D5155F526A1EF7B0075EBC7 /* ContentView.swift in Sources */, + 9D6ED23A271E6BD600D773CD /* SpeechForwarder.swift in Sources */, 9D5155F326A1EF7B0075EBC7 /* ListenerGSApp.swift in Sources */, 9D51566526A36F6D0075EBC7 /* BinUtils.swift in Sources */, 9D51565426A36B410075EBC7 /* ytcpsocket.c in Sources */, diff --git a/ListenerGS.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/xcschememanagement.plist b/ListenerGS.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/xcschememanagement.plist index 0ec5871..0dbda45 100644 --- a/ListenerGS.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/ListenerGS.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,6 +9,11 @@ orderHint 0 + ListenerGS.xcscheme_^#shared#^_ + + orderHint + 0 + diff --git a/ListenerGS/ContentView.swift b/ListenerGS/ContentView.swift index 59f37f2..9f2b397 100644 --- a/ListenerGS/ContentView.swift +++ b/ListenerGS/ContentView.swift @@ -9,237 +9,33 @@ import SwiftUI import Speech struct ContentView: View { - @State private var listening = false - @State private var listenEnabled = false - @State private var textHeard = "" - @State private var log = "" - @State private var ipAddress = "" - @State private var isEditing = false - - let LISTEN_STATE_MSG = 1 - let LISTEN_TEXT_MSG = 2 - - let port = 19026 - @State private var client: TCPClient? - - private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))! - - @State private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest? - - @State private var recognitionTask: SFSpeechRecognitionTask? - - private let audioEngine = AVAudioEngine() + @StateObject private var speechForwarder = SpeechForwarder() var body: some View { VStack { - TextField("IP Address", text: $ipAddress) { isEditing in - self.isEditing = isEditing + TextField("IP Address", text: $speechForwarder.ipAddress) { isEditing in + speechForwarder.isEditing = isEditing } onCommit: { - validate(destination: ipAddress) + speechForwarder.validate(destination: speechForwarder.ipAddress) } .padding() ScrollView() { - Text(log) + Text(speechForwarder.log) .multilineTextAlignment(.leading) } Button("Listen") { - listen() + speechForwarder.listen() } .padding() - .background(listening ? Color.red : Color.clear) - .foregroundColor(listening ? .black : .blue) - .disabled(listenEnabled == false) + .background(speechForwarder.listening ? Color.red : Color.clear) + .foregroundColor(speechForwarder.listening ? .black : .blue) + .disabled(speechForwarder.listenEnabled == false) .frame(maxWidth: .infinity) .buttonStyle(PlainButtonStyle()) } } - - func logError(message: String) { - log.append("ERROR: " + message + "\n") - } - - func logEvent(message: String) { - log.append("EVENT: " + message + "\n") - } - - func validate(destination : String) { - logEvent(message: "Attempting to connect to " + destination) - client = TCPClient(address: destination, port: Int32(port)) - guard let client = client else { return } - switch client.connect(timeout: 10) { - case .success: - listenEnabled = true - logEvent(message: "Connected to " + destination) - case .failure(let error): - client.close() - self.client = nil - logError(message: String(describing: error)) - break - } - } - - func listen() { - self.listening.toggle() - if (self.listening) { - SFSpeechRecognizer.requestAuthorization { authStatus in - // The authorization status results in changes to the - // app’s interface, so process the results on the app’s - // main queue. - OperationQueue.main.addOperation { - switch authStatus { - case .authorized: - break - - case .denied: - self.listening = false - break - - case .restricted: - self.listening = false - break - - case .notDetermined: - self.listening = false - break - - default: - self.listening = false - break - } - } - } - } - - guard let client = client else { return } - if (self.listening) { - switch (client.send(data: isListening())) { - case .success: - break - case .failure(let error): - self.listening = false - logError(message: String(describing: error)) - } - } - - if (self.listening) { - do { - try startRecording() - logEvent(message: "Listening...") - } - catch { - self.listening = false - } - } - - if (!self.listening) { - logEvent(message: "Listening stopped") - audioEngine.stop() - recognitionRequest?.endAudio() - switch (client.send(data: isListening())) { - case .success: - break - case .failure(let error): - self.listening = false - logError(message: String(describing: error)) - } - } - } - - private func isListening() -> Data { - return pack(" 0) { - if (latestText.prefix(commonChars) == self.textHeard.prefix(commonChars)) { - break - } - commonChars -= 1 - } - var stringToSend = "" - if (commonChars < self.textHeard.count) { - stringToSend = String(repeating: "\u{7f}", count: self.textHeard.count - commonChars) - } - stringToSend.append(contentsOf: latestText.suffix(latestText.count - commonChars).replacingOccurrences(of: "\n", with: "\r")) - - if (stringToSend.count > 0) { - // TODO - Handle strings to send that are longer than 64K (doubt that would happen though) - // TODO - Try to convert encoding from utf8 to something the GS can understand. - switch (client.send(data: pack("CFBundleShortVersionString 1.0 CFBundleVersion - 100 + 122 LSApplicationCategoryType public.app-category.utilities LSRequiresIPhoneOS