|
@@ -7,13 +7,24 @@
|
|
|
|
|
|
import UIKit
|
|
|
import WebKit
|
|
|
+import NexilisLite
|
|
|
+import Speech
|
|
|
|
|
|
-class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, WKNavigationDelegate {
|
|
|
+class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, WKNavigationDelegate, WKScriptMessageHandler {
|
|
|
|
|
|
@IBOutlet weak var webView: WKWebView!
|
|
|
var address = ""
|
|
|
private var lastContentOffset: CGFloat = 0
|
|
|
|
|
|
+ var isAllowSpeech = false
|
|
|
+
|
|
|
+ let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "id"))
|
|
|
+
|
|
|
+ var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
|
|
|
+ var recognitionTask : SFSpeechRecognitionTask?
|
|
|
+ let audioEngine = AVAudioEngine()
|
|
|
+ var alertController = UIAlertController()
|
|
|
+
|
|
|
override func viewDidLoad() {
|
|
|
super.viewDidLoad()
|
|
|
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
|
|
@@ -26,7 +37,24 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
|
|
|
webView.scrollView.delegate = self
|
|
|
webView.navigationDelegate = self
|
|
|
webView.allowsBackForwardNavigationGestures = true
|
|
|
- // Do any additional setup after loading the view.
|
|
|
+
|
|
|
+ let contentController = self.webView.configuration.userContentController
|
|
|
+ contentController.add(self, name: "checkProfile")
|
|
|
+ contentController.add(self, name: "setIsProductModalOpen")
|
|
|
+ contentController.add(self, name: "toggleVoiceSearch")
|
|
|
+ contentController.add(self, name: "blockUser")
|
|
|
+ contentController.add(self, name: "showAlert")
|
|
|
+ contentController.add(self, name: "closeProfile")
|
|
|
+
|
|
|
+ let source: String = "var meta = document.createElement('meta');" +
|
|
|
+ "meta.name = 'viewport';" +
|
|
|
+ "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" +
|
|
|
+ "var head = document.getElementsByTagName('head')[0];" +
|
|
|
+ "head.appendChild(meta);" +
|
|
|
+ "$('#header-layout').find('.col-8').removeClass('col-8').addClass('col');" +
|
|
|
+ "$('#header-layout').find('.col-4').removeClass('col-4').addClass('col');"
|
|
|
+ let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
|
|
|
+ contentController.addUserScript(script)
|
|
|
}
|
|
|
|
|
|
override func viewWillAppear(_ animated: Bool) {
|
|
@@ -60,6 +88,12 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
|
|
|
}
|
|
|
print(address)
|
|
|
if let u = myURL{
|
|
|
+ let lang = UserDefaults.standard.string(forKey: "i18n_language")
|
|
|
+ var intLang = 0
|
|
|
+ if lang == "id" {
|
|
|
+ intLang = 1
|
|
|
+ }
|
|
|
+ self.webView.evaluateJavaScript("{window.localStorage.lang = \(intLang)}")
|
|
|
let myRequest = URLRequest(url: u)
|
|
|
webView.load(myRequest)
|
|
|
}
|
|
@@ -130,14 +164,255 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
|
|
|
}
|
|
|
|
|
|
|
|
|
- /*
|
|
|
- // MARK: - Navigation
|
|
|
+ func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
|
|
+ print("KACAU \(message.name)")
|
|
|
+ if message.name == "checkProfile" {
|
|
|
+ guard let dict = message.body as? [String: AnyObject],
|
|
|
+ let param1 = dict["param1"] as? String,
|
|
|
+ let param2 = dict["param2"] as? String else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if ViewController.checkIsChangePerson() {
|
|
|
+ if param2 == "like" {
|
|
|
+ self.webView.evaluateJavaScript("likeProduct('\(param1)',true);")
|
|
|
+ } else if param2 == "comment" {
|
|
|
+ self.webView.evaluateJavaScript("openComment('\(param1)',true);")
|
|
|
+ } else if param2 == "report_user" {
|
|
|
+ self.webView.evaluateJavaScript("reportUser('\(param1)',true);")
|
|
|
+ } else if param2 == "report_content" {
|
|
|
+ self.webView.evaluateJavaScript("reportContent('\(param1.split(separator: "|")[0])','\(param1.split(separator: "|")[1])',true);")
|
|
|
+ } else if param2 == "block_user" {
|
|
|
+ self.webView.evaluateJavaScript("blockUser('\(param1)',true);")
|
|
|
+ } else if param2 == "follow_store" {
|
|
|
+ self.webView.evaluateJavaScript("follow(true);")
|
|
|
+ } else if param2 == "homepage" {
|
|
|
+ self.webView.evaluateJavaScript("window.location.href = '\(param1)';")
|
|
|
+ } else {
|
|
|
+ self.webView.evaluateJavaScript("openNewPost(true);")
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
|
|
|
+ }
|
|
|
+ } else if message.name == "setIsProductModalOpen" {
|
|
|
+ guard let dict = message.body as? [String: AnyObject],
|
|
|
+ let param1 = dict["param1"] as? Bool else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if param1 {
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ }
|
|
|
+ } else if message.name == "toggleVoiceSearch" {
|
|
|
+ if !isAllowSpeech {
|
|
|
+ setupSpeech()
|
|
|
+ } else {
|
|
|
+ runVoice()
|
|
|
+ }
|
|
|
+ } else if message.name == "blockUser" {
|
|
|
+ guard let dict = message.body as? [String: AnyObject],
|
|
|
+ let param1 = dict["param1"] as? String,
|
|
|
+ let param2 = dict["param2"] as? Bool else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if param2 {
|
|
|
+ DispatchQueue.global().async {
|
|
|
+ if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
|
|
|
+ if response.isOk() {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ Database.shared.database?.inTransaction({ (fmdb, rollback) in
|
|
|
+ _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
|
|
|
+ "ex_block" : "1"
|
|
|
+ ], _where: "f_pin = '\(param1)'")
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ DispatchQueue.global().async {
|
|
|
+ if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
|
|
|
+ if response.isOk() {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ Database.shared.database?.inTransaction({ (fmdb, rollback) in
|
|
|
+ _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
|
|
|
+ "ex_block" : "0"
|
|
|
+ ], _where: "f_pin = '\(param1)'")
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if message.name == "showAlert" {
|
|
|
+ guard let dict = message.body as? [String: AnyObject],
|
|
|
+ let param1 = dict["param1"] as? String else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ showToast(message: param1, controller: self.tabBarController!)
|
|
|
+ } else if message.name == "blockUser" {
|
|
|
+ guard let dict = message.body as? [String: AnyObject],
|
|
|
+ let param1 = dict["param1"] as? String,
|
|
|
+ let param2 = dict["param2"] as? Bool else {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if param2 {
|
|
|
+ DispatchQueue.global().async {
|
|
|
+ if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
|
|
|
+ if response.isOk() {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ Database.shared.database?.inTransaction({ (fmdb, rollback) in
|
|
|
+ _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
|
|
|
+ "ex_block" : "1"
|
|
|
+ ], _where: "f_pin = '\(param1)'")
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ DispatchQueue.global().async {
|
|
|
+ if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
|
|
|
+ if response.isOk() {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ Database.shared.database?.inTransaction({ (fmdb, rollback) in
|
|
|
+ _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
|
|
|
+ "ex_block" : "0"
|
|
|
+ ], _where: "f_pin = '\(param1)'")
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func setupSpeech() {
|
|
|
+
|
|
|
+ self.speechRecognizer?.delegate = self
|
|
|
+
|
|
|
+ SFSpeechRecognizer.requestAuthorization { (authStatus) in
|
|
|
+
|
|
|
+ var isButtonEnabled = false
|
|
|
+
|
|
|
+ switch authStatus {
|
|
|
+ case .authorized:
|
|
|
+ isButtonEnabled = true
|
|
|
+
|
|
|
+ case .denied:
|
|
|
+ isButtonEnabled = false
|
|
|
+ print("User denied access to speech recognition")
|
|
|
+
|
|
|
+ case .restricted:
|
|
|
+ isButtonEnabled = false
|
|
|
+ print("Speech recognition restricted on this device")
|
|
|
+
|
|
|
+ case .notDetermined:
|
|
|
+ isButtonEnabled = false
|
|
|
+ print("Speech recognition not yet authorized")
|
|
|
+ @unknown default:
|
|
|
+ isButtonEnabled = false
|
|
|
+ }
|
|
|
+
|
|
|
+ OperationQueue.main.addOperation() {
|
|
|
+ self.isAllowSpeech = isButtonEnabled
|
|
|
+ if isButtonEnabled {
|
|
|
+ UserDefaults.standard.set(isButtonEnabled, forKey: "allowSpeech")
|
|
|
+ self.runVoice()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func runVoice() {
|
|
|
+ if !audioEngine.isRunning {
|
|
|
+ alertController = UIAlertController(title: "Start Recording".localized(), message: "Say something, I'm listening!".localized(), preferredStyle: .alert)
|
|
|
+ self.present(alertController, animated: true)
|
|
|
+ self.webView.evaluateJavaScript("toggleVoiceButton(true)")
|
|
|
+ self.startRecording()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func startRecording() {
|
|
|
+
|
|
|
+ // Clear all previous session data and cancel task
|
|
|
+ if recognitionTask != nil {
|
|
|
+ recognitionTask?.cancel()
|
|
|
+ recognitionTask = nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create instance of audio session to record voice
|
|
|
+ let audioSession = AVAudioSession.sharedInstance()
|
|
|
+ do {
|
|
|
+ try audioSession.setCategory(AVAudioSession.Category.record, mode: .default, options: [])
|
|
|
+ try audioSession.setMode(AVAudioSession.Mode.measurement)
|
|
|
+ try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
|
|
|
+ } catch {
|
|
|
+ print("audioSession properties weren't set because of an error.")
|
|
|
+ }
|
|
|
+
|
|
|
+ self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
|
|
|
+
|
|
|
+ let inputNode = audioEngine.inputNode
|
|
|
+
|
|
|
+ guard let recognitionRequest = recognitionRequest else {
|
|
|
+ fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
|
|
|
+ }
|
|
|
+
|
|
|
+ recognitionRequest.shouldReportPartialResults = true
|
|
|
+
|
|
|
+ self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
|
|
|
|
|
|
- // In a storyboard-based application, you will often want to do a little preparation before navigation
|
|
|
- override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
|
|
- // Get the new view controller using segue.destination.
|
|
|
- // Pass the selected object to the new view controller.
|
|
|
+ var isFinal = false
|
|
|
+
|
|
|
+ if result != nil {
|
|
|
+ let text = result?.bestTranscription.formattedString
|
|
|
+ isFinal = (result?.isFinal)!
|
|
|
+ self.alertController.dismiss(animated: true)
|
|
|
+ self.audioEngine.stop()
|
|
|
+ self.recognitionRequest?.endAudio()
|
|
|
+ self.webView.evaluateJavaScript("toggleVoiceButton(false)")
|
|
|
+ self.webView.evaluateJavaScript("submitVoiceSearch('\(text ?? "")')")
|
|
|
+ } else {
|
|
|
+ self.alertController.dismiss(animated: true)
|
|
|
+ }
|
|
|
+
|
|
|
+ if error != nil || isFinal {
|
|
|
+
|
|
|
+ self.audioEngine.stop()
|
|
|
+ inputNode.removeTap(onBus: 0)
|
|
|
+
|
|
|
+ self.recognitionRequest = nil
|
|
|
+ self.recognitionTask = nil
|
|
|
+
|
|
|
+ self.isAllowSpeech = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ let recordingFormat = inputNode.outputFormat(forBus: 0)
|
|
|
+ inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
|
|
|
+ self.recognitionRequest?.append(buffer)
|
|
|
+ }
|
|
|
+
|
|
|
+ self.audioEngine.prepare()
|
|
|
+
|
|
|
+ do {
|
|
|
+ try self.audioEngine.start()
|
|
|
+ } catch {
|
|
|
+ print("audioEngine couldn't start because of an error.")
|
|
|
+ }
|
|
|
}
|
|
|
- */
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+extension ThirdTabViewController: SFSpeechRecognizerDelegate {
|
|
|
+
|
|
|
+ func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
|
|
|
+ if available {
|
|
|
+ self.isAllowSpeech = true
|
|
|
+ } else {
|
|
|
+ self.isAllowSpeech = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|