ThirdTabViewController.swift 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. //
  2. // ThirdTabViewController.swift
  3. // AppBuilder
  4. //
  5. // Created by Kevin Maulana on 30/03/22.
  6. //
  7. import UIKit
  8. import WebKit
  9. import NexilisLite
  10. import Speech
  11. class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, WKNavigationDelegate, WKScriptMessageHandler {
  12. @IBOutlet weak var webView: WKWebView!
  13. var address = ""
  14. private var lastContentOffset: CGFloat = 0
  15. var isAllowSpeech = false
  16. var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en"))
  17. var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
  18. var recognitionTask : SFSpeechRecognitionTask?
  19. let audioEngine = AVAudioEngine()
  20. var alertController = UIAlertController()
  21. var dateRefresh: Date?
  22. public static var forceRefresh = false
  23. override func viewDidLoad() {
  24. super.viewDidLoad()
  25. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
  26. tapGesture.cancelsTouchesInView = false
  27. tapGesture.delegate = self
  28. webView.scrollView.addGestureRecognizer(tapGesture)
  29. let refreshControl = UIRefreshControl()
  30. refreshControl.addTarget(self, action: #selector(reloadWebView(_:)), for: .valueChanged)
  31. webView.scrollView.addSubview(refreshControl)
  32. webView.scrollView.delegate = self
  33. webView.navigationDelegate = self
  34. webView.allowsBackForwardNavigationGestures = true
  35. let contentController = self.webView.configuration.userContentController
  36. contentController.add(self, name: "checkProfile")
  37. contentController.add(self, name: "setIsProductModalOpen")
  38. contentController.add(self, name: "toggleVoiceSearch")
  39. contentController.add(self, name: "blockUser")
  40. contentController.add(self, name: "showAlert")
  41. contentController.add(self, name: "closeProfile")
  42. contentController.add(self, name: "tabShowHide")
  43. let source: String = "var meta = document.createElement('meta');" +
  44. "meta.name = 'viewport';" +
  45. "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" +
  46. "var head = document.getElementsByTagName('head')[0];" +
  47. "head.appendChild(meta);" +
  48. "$('#header-layout').find('.col-8').removeClass('col-8').addClass('col');" +
  49. "$('#header-layout').find('.col-4').removeClass('col-4').addClass('col');"
  50. let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
  51. contentController.addUserScript(script)
  52. NotificationCenter.default.addObserver(self, selector: #selector(onShowAC(notification:)), name: NSNotification.Name(rawValue: "onShowAC"), object: nil)
  53. }
  54. override func viewWillAppear(_ animated: Bool) {
  55. let me = UserDefaults.standard.string(forKey: "me")
  56. var myURL : URL?
  57. let lang = UserDefaults.standard.string(forKey: "i18n_language")
  58. var intLang = 0
  59. if lang == "id" {
  60. speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "id"))
  61. intLang = 1
  62. }
  63. switch(ViewController.tab3){
  64. case "0":
  65. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
  66. myURL = URL(string: address)
  67. case "1":
  68. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
  69. myURL = URL(string: address)
  70. case "2":
  71. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)"
  72. myURL = URL(string: address)
  73. case "3":
  74. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)"
  75. myURL = URL(string: address)
  76. case "4":
  77. address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)"
  78. myURL = URL(string: address)
  79. default:
  80. if(!ViewController.tab3.isEmpty){
  81. if(ViewController.tab3.lowercased().contains("https://") || ViewController.sURL.lowercased().contains("http://")){
  82. address = ViewController.tab3
  83. myURL = URL(string: address)
  84. }
  85. else {
  86. address = "https://\(ViewController.tab3)"
  87. myURL = URL(string: address)
  88. }
  89. }
  90. }
  91. print(address)
  92. if let u = myURL{
  93. if dateRefresh == nil || Int(Date().timeIntervalSince(dateRefresh!)) >= 60 || ThirdTabViewController.forceRefresh {
  94. let myRequest = URLRequest(url: u)
  95. webView.load(myRequest)
  96. }
  97. dateRefresh = Date()
  98. ThirdTabViewController.forceRefresh = false
  99. self.webView.evaluateJavaScript("if(resumeAll){resumeAll();}")
  100. }
  101. self.navigationController?.navigationBar.topItem?.title = Bundle.main.displayName
  102. let cpaasMode = PrefsUtil.getCpaasMode()
  103. let isBurger = cpaasMode == PrefsUtil.CPAAS_MODE_BURGER
  104. // navigationController?.navigationBar.backgroundColor = .white
  105. navigationController?.setNavigationBarHidden(!isBurger, animated: false)
  106. }
  107. @objc func onShowAC(notification: NSNotification) {
  108. self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  109. view.endEditing(true)
  110. resignFirstResponder()
  111. }
  112. override func viewWillDisappear(_ animated: Bool) {
  113. self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  114. view.endEditing(true)
  115. resignFirstResponder()
  116. }
  117. func scrollViewDidScroll(_ scrollView: UIScrollView) {
  118. if (self.lastContentOffset > scrollView.contentOffset.y && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)) {
  119. showTabBar();
  120. }
  121. else if (self.lastContentOffset != 0 && self.lastContentOffset < scrollView.contentOffset.y && self.lastContentOffset >= 0) {
  122. hideTabBar();
  123. }
  124. self.lastContentOffset = scrollView.contentOffset.y
  125. self.collapseDocked()
  126. }
  127. @objc func collapseDocked() {
  128. if ViewController.isExpandButton {
  129. ViewController.expandButton()
  130. }
  131. }
  132. @objc func reloadWebView(_ sender: UIRefreshControl) {
  133. webView.reload()
  134. sender.endRefreshing()
  135. }
  136. func hideTabBar() {
  137. var viewController = UIApplication.shared.windows.first!.rootViewController
  138. if !(viewController is ViewController) {
  139. viewController = self.parent
  140. }
  141. if ViewController.middleButton.isDescendant(of: viewController!.view) {
  142. DispatchQueue.main.async {
  143. ViewController.hideDockedButton()
  144. if let viewController = viewController as? ViewController {
  145. viewController.tabBar.isHidden = true
  146. }
  147. ViewController.removeMiddleButton()
  148. }
  149. } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
  150. DispatchQueue.main.async {
  151. if let viewController = viewController as? ViewController {
  152. if !viewController.tabBar.isHidden {
  153. viewController.tabBar.isHidden = true
  154. }
  155. }
  156. }
  157. }
  158. }
  159. func showTabBar() {
  160. if(ViewController.alwaysHideButton){
  161. return
  162. }
  163. var viewController = UIApplication.shared.windows.first!.rootViewController
  164. if !(viewController is ViewController) {
  165. viewController = self.parent
  166. }
  167. if ViewController.middleButton.isHidden {
  168. ViewController.isExpandButton = false
  169. if let viewController = viewController as? ViewController {
  170. viewController.tabBar.isHidden = false
  171. ViewController.middleButton.isHidden = false
  172. }
  173. } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
  174. DispatchQueue.main.async {
  175. if let viewController = viewController as? ViewController {
  176. if viewController.tabBar.isHidden {
  177. viewController.tabBar.isHidden = false
  178. }
  179. }
  180. }
  181. }
  182. }
  183. func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
  184. scrollView.pinchGestureRecognizer?.isEnabled = false
  185. }
  186. func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
  187. if message.name == "checkProfile" {
  188. guard let dict = message.body as? [String: AnyObject],
  189. let param1 = dict["param1"] as? String,
  190. let param2 = dict["param2"] as? String else {
  191. return
  192. }
  193. if ViewController.checkIsChangePerson() {
  194. if param2 == "like" {
  195. self.webView.evaluateJavaScript("likeProduct('\(param1)',true);")
  196. } else if param2 == "comment" {
  197. self.webView.evaluateJavaScript("openComment('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
  198. } else if param2 == "report_user" {
  199. self.webView.evaluateJavaScript("reportUser('\(param1)',true);")
  200. } else if param2 == "report_content" {
  201. self.webView.evaluateJavaScript("reportContent('\(param1.split(separator: "|")[0])','\(param1.split(separator: "|")[1])',true);")
  202. } else if param2 == "block_user" {
  203. self.webView.evaluateJavaScript("blockUser('\(param1)',true);")
  204. } else if param2 == "follow_user" {
  205. self.webView.evaluateJavaScript("followUser('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
  206. } else if param2 == "homepage" || param2 == "gif" {
  207. self.webView.evaluateJavaScript("window.location.href = '\(param1)';")
  208. } else {
  209. self.webView.evaluateJavaScript("openNewPost(true);")
  210. }
  211. } else {
  212. self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
  213. }
  214. } else if message.name == "setIsProductModalOpen" {
  215. guard let dict = message.body as? [String: AnyObject],
  216. let param1 = dict["param1"] as? Bool else {
  217. return
  218. }
  219. if param1 {
  220. } else {
  221. }
  222. } else if message.name == "toggleVoiceSearch" {
  223. if !isAllowSpeech {
  224. setupSpeech()
  225. } else {
  226. runVoice()
  227. }
  228. } else if message.name == "blockUser" {
  229. guard let dict = message.body as? [String: AnyObject],
  230. let param1 = dict["param1"] as? String,
  231. let param2 = dict["param2"] as? Bool else {
  232. return
  233. }
  234. if param2 {
  235. DispatchQueue.global().async {
  236. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
  237. if response.isOk() {
  238. DispatchQueue.main.async {
  239. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  240. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
  241. "ex_block" : "1"
  242. ], _where: "f_pin = '\(param1)'")
  243. })
  244. }
  245. }
  246. }
  247. }
  248. } else {
  249. DispatchQueue.global().async {
  250. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
  251. if response.isOk() {
  252. DispatchQueue.main.async {
  253. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  254. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
  255. "ex_block" : "0"
  256. ], _where: "f_pin = '\(param1)'")
  257. })
  258. }
  259. }
  260. }
  261. }
  262. }
  263. } else if message.name == "showAlert" {
  264. guard let dict = message.body as? [String: AnyObject],
  265. let param1 = dict["param1"] as? String else {
  266. return
  267. }
  268. showToast(message: param1, controller: self.tabBarController!)
  269. } else if message.name == "blockUser" {
  270. guard let dict = message.body as? [String: AnyObject],
  271. let param1 = dict["param1"] as? String,
  272. let param2 = dict["param2"] as? Bool else {
  273. return
  274. }
  275. if param2 {
  276. DispatchQueue.global().async {
  277. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
  278. if response.isOk() {
  279. DispatchQueue.main.async {
  280. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  281. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
  282. "ex_block" : "1"
  283. ], _where: "f_pin = '\(param1)'")
  284. })
  285. }
  286. }
  287. }
  288. }
  289. } else {
  290. DispatchQueue.global().async {
  291. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
  292. if response.isOk() {
  293. DispatchQueue.main.async {
  294. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  295. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
  296. "ex_block" : "0"
  297. ], _where: "f_pin = '\(param1)'")
  298. })
  299. }
  300. }
  301. }
  302. }
  303. }
  304. } else if message.name == "tabShowHide" {
  305. guard let dict = message.body as? [String: AnyObject],
  306. let param1 = dict["param1"] as? Bool else {
  307. return
  308. }
  309. if param1 {
  310. ViewController.alwaysHideButton = false
  311. showTabBar()
  312. } else {
  313. ViewController.alwaysHideButton = true
  314. hideTabBar()
  315. }
  316. }
  317. }
  318. func setupSpeech() {
  319. self.speechRecognizer?.delegate = self
  320. SFSpeechRecognizer.requestAuthorization { (authStatus) in
  321. var isButtonEnabled = false
  322. switch authStatus {
  323. case .authorized:
  324. isButtonEnabled = true
  325. case .denied:
  326. isButtonEnabled = false
  327. print("User denied access to speech recognition")
  328. case .restricted:
  329. isButtonEnabled = false
  330. print("Speech recognition restricted on this device")
  331. case .notDetermined:
  332. isButtonEnabled = false
  333. print("Speech recognition not yet authorized")
  334. @unknown default:
  335. isButtonEnabled = false
  336. }
  337. OperationQueue.main.addOperation() {
  338. self.isAllowSpeech = isButtonEnabled
  339. if isButtonEnabled {
  340. UserDefaults.standard.set(isButtonEnabled, forKey: "allowSpeech")
  341. self.runVoice()
  342. }
  343. }
  344. }
  345. }
  346. func runVoice() {
  347. if !audioEngine.isRunning {
  348. alertController = UIAlertController(title: "Start Recording".localized(), message: "Say something, I'm listening!".localized(), preferredStyle: .alert)
  349. self.present(alertController, animated: true)
  350. self.webView.evaluateJavaScript("toggleVoiceButton(true)")
  351. self.startRecording()
  352. }
  353. }
  354. func startRecording() {
  355. // Clear all previous session data and cancel task
  356. if recognitionTask != nil {
  357. recognitionTask?.cancel()
  358. recognitionTask = nil
  359. }
  360. // Create instance of audio session to record voice
  361. let audioSession = AVAudioSession.sharedInstance()
  362. do {
  363. try audioSession.setCategory(AVAudioSession.Category.record, mode: .default, options: [])
  364. try audioSession.setMode(AVAudioSession.Mode.measurement)
  365. try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
  366. } catch {
  367. print("audioSession properties weren't set because of an error.")
  368. }
  369. self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
  370. let inputNode = audioEngine.inputNode
  371. guard let recognitionRequest = recognitionRequest else {
  372. fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
  373. }
  374. recognitionRequest.shouldReportPartialResults = true
  375. self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
  376. var isFinal = false
  377. var text = ""
  378. if result != nil {
  379. text = result?.bestTranscription.formattedString ?? ""
  380. isFinal = (result?.isFinal)!
  381. self.alertController.dismiss(animated: true)
  382. self.audioEngine.stop()
  383. self.recognitionRequest?.endAudio()
  384. } else {
  385. self.alertController.dismiss(animated: true)
  386. }
  387. if error != nil || isFinal {
  388. if error == nil {
  389. self.webView.evaluateJavaScript("toggleVoiceButton(false)")
  390. self.webView.evaluateJavaScript("submitVoiceSearch('\(text)')")
  391. } else {
  392. self.audioEngine.stop()
  393. self.recognitionRequest?.endAudio()
  394. }
  395. inputNode.removeTap(onBus: 0)
  396. self.recognitionRequest = nil
  397. self.recognitionTask = nil
  398. self.isAllowSpeech = true
  399. }
  400. })
  401. let recordingFormat = inputNode.outputFormat(forBus: 0)
  402. inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
  403. self.recognitionRequest?.append(buffer)
  404. }
  405. self.audioEngine.prepare()
  406. do {
  407. try self.audioEngine.start()
  408. } catch {
  409. print("audioEngine couldn't start because of an error.")
  410. }
  411. }
  412. }
  413. extension ThirdTabViewController: SFSpeechRecognizerDelegate {
  414. func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
  415. if available {
  416. self.isAllowSpeech = true
  417. } else {
  418. self.isAllowSpeech = false
  419. }
  420. }
  421. }
  422. extension ThirdTabViewController: WKUIDelegate {
  423. func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
  424. if let urlStr = navigationAction.request.url?.absoluteString {
  425. print("kacau \(urlStr)")
  426. collapseDocked()
  427. if urlStr.contains("nexilis/pages/tab1-main-only") || urlStr.contains("nexilis/pages/tab3-main-only") || urlStr.contains("nexilis/pages/tab1-main") || urlStr.contains("nexilis/pages/tab3-commerce") {
  428. ViewController.alwaysHideButton = false
  429. showTabBar()
  430. }
  431. }
  432. decisionHandler(.allow)
  433. }
  434. }