FirstTabViewController.swift 24 KB

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